cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cvmx-helper-util.c (10341B)


      1/***********************license start***************
      2 * Author: Cavium Networks
      3 *
      4 * Contact: support@caviumnetworks.com
      5 * This file is part of the OCTEON SDK
      6 *
      7 * Copyright (c) 2003-2008 Cavium Networks
      8 *
      9 * This file is free software; you can redistribute it and/or modify
     10 * it under the terms of the GNU General Public License, Version 2, as
     11 * published by the Free Software Foundation.
     12 *
     13 * This file is distributed in the hope that it will be useful, but
     14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
     15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
     16 * NONINFRINGEMENT.  See the GNU General Public License for more
     17 * details.
     18 *
     19 * You should have received a copy of the GNU General Public License
     20 * along with this file; if not, write to the Free Software
     21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
     22 * or visit http://www.gnu.org/licenses/.
     23 *
     24 * This file may also be available under a different license from Cavium.
     25 * Contact Cavium Networks for more information
     26 ***********************license end**************************************/
     27
     28/*
     29 * Small helper utilities.
     30 */
     31#include <linux/kernel.h>
     32
     33#include <asm/octeon/octeon.h>
     34
     35#include <asm/octeon/cvmx-config.h>
     36
     37#include <asm/octeon/cvmx-fpa.h>
     38#include <asm/octeon/cvmx-pip.h>
     39#include <asm/octeon/cvmx-pko.h>
     40#include <asm/octeon/cvmx-ipd.h>
     41#include <asm/octeon/cvmx-spi.h>
     42
     43#include <asm/octeon/cvmx-helper.h>
     44#include <asm/octeon/cvmx-helper-util.h>
     45
     46#include <asm/octeon/cvmx-ipd-defs.h>
     47
     48/**
     49 * Convert a interface mode into a human readable string
     50 *
     51 * @mode:   Mode to convert
     52 *
     53 * Returns String
     54 */
     55const char *cvmx_helper_interface_mode_to_string(cvmx_helper_interface_mode_t
     56						 mode)
     57{
     58	switch (mode) {
     59	case CVMX_HELPER_INTERFACE_MODE_DISABLED:
     60		return "DISABLED";
     61	case CVMX_HELPER_INTERFACE_MODE_RGMII:
     62		return "RGMII";
     63	case CVMX_HELPER_INTERFACE_MODE_GMII:
     64		return "GMII";
     65	case CVMX_HELPER_INTERFACE_MODE_SPI:
     66		return "SPI";
     67	case CVMX_HELPER_INTERFACE_MODE_PCIE:
     68		return "PCIE";
     69	case CVMX_HELPER_INTERFACE_MODE_XAUI:
     70		return "XAUI";
     71	case CVMX_HELPER_INTERFACE_MODE_SGMII:
     72		return "SGMII";
     73	case CVMX_HELPER_INTERFACE_MODE_PICMG:
     74		return "PICMG";
     75	case CVMX_HELPER_INTERFACE_MODE_NPI:
     76		return "NPI";
     77	case CVMX_HELPER_INTERFACE_MODE_LOOP:
     78		return "LOOP";
     79	}
     80	return "UNKNOWN";
     81}
     82
     83/**
     84 * Setup Random Early Drop on a specific input queue
     85 *
     86 * @queue:  Input queue to setup RED on (0-7)
     87 * @pass_thresh:
     88 *		 Packets will begin slowly dropping when there are less than
     89 *		 this many packet buffers free in FPA 0.
     90 * @drop_thresh:
     91 *		 All incoming packets will be dropped when there are less
     92 *		 than this many free packet buffers in FPA 0.
     93 * Returns Zero on success. Negative on failure
     94 */
     95static int cvmx_helper_setup_red_queue(int queue, int pass_thresh,
     96				       int drop_thresh)
     97{
     98	union cvmx_ipd_qosx_red_marks red_marks;
     99	union cvmx_ipd_red_quex_param red_param;
    100
    101	/* Set RED to begin dropping packets when there are pass_thresh buffers
    102	   left. It will linearly drop more packets until reaching drop_thresh
    103	   buffers */
    104	red_marks.u64 = 0;
    105	red_marks.s.drop = drop_thresh;
    106	red_marks.s.pass = pass_thresh;
    107	cvmx_write_csr(CVMX_IPD_QOSX_RED_MARKS(queue), red_marks.u64);
    108
    109	/* Use the actual queue 0 counter, not the average */
    110	red_param.u64 = 0;
    111	red_param.s.prb_con =
    112	    (255ul << 24) / (red_marks.s.pass - red_marks.s.drop);
    113	red_param.s.avg_con = 1;
    114	red_param.s.new_con = 255;
    115	red_param.s.use_pcnt = 1;
    116	cvmx_write_csr(CVMX_IPD_RED_QUEX_PARAM(queue), red_param.u64);
    117	return 0;
    118}
    119
    120/**
    121 * Setup Random Early Drop to automatically begin dropping packets.
    122 *
    123 * @pass_thresh:
    124 *		 Packets will begin slowly dropping when there are less than
    125 *		 this many packet buffers free in FPA 0.
    126 * @drop_thresh:
    127 *		 All incoming packets will be dropped when there are less
    128 *		 than this many free packet buffers in FPA 0.
    129 * Returns Zero on success. Negative on failure
    130 */
    131int cvmx_helper_setup_red(int pass_thresh, int drop_thresh)
    132{
    133	union cvmx_ipd_portx_bp_page_cnt page_cnt;
    134	union cvmx_ipd_bp_prt_red_end ipd_bp_prt_red_end;
    135	union cvmx_ipd_red_port_enable red_port_enable;
    136	int queue;
    137	int interface;
    138	int port;
    139
    140	/* Disable backpressure based on queued buffers. It needs SW support */
    141	page_cnt.u64 = 0;
    142	page_cnt.s.bp_enb = 0;
    143	page_cnt.s.page_cnt = 100;
    144	for (interface = 0; interface < 2; interface++) {
    145		for (port = cvmx_helper_get_first_ipd_port(interface);
    146		     port < cvmx_helper_get_last_ipd_port(interface); port++)
    147			cvmx_write_csr(CVMX_IPD_PORTX_BP_PAGE_CNT(port),
    148				       page_cnt.u64);
    149	}
    150
    151	for (queue = 0; queue < 8; queue++)
    152		cvmx_helper_setup_red_queue(queue, pass_thresh, drop_thresh);
    153
    154	/* Shutoff the dropping based on the per port page count. SW isn't
    155	   decrementing it right now */
    156	ipd_bp_prt_red_end.u64 = 0;
    157	ipd_bp_prt_red_end.s.prt_enb = 0;
    158	cvmx_write_csr(CVMX_IPD_BP_PRT_RED_END, ipd_bp_prt_red_end.u64);
    159
    160	red_port_enable.u64 = 0;
    161	red_port_enable.s.prt_enb = 0xfffffffffull;
    162	red_port_enable.s.avg_dly = 10000;
    163	red_port_enable.s.prb_dly = 10000;
    164	cvmx_write_csr(CVMX_IPD_RED_PORT_ENABLE, red_port_enable.u64);
    165
    166	return 0;
    167}
    168EXPORT_SYMBOL_GPL(cvmx_helper_setup_red);
    169
    170/**
    171 * Setup the common GMX settings that determine the number of
    172 * ports. These setting apply to almost all configurations of all
    173 * chips.
    174 *
    175 * @interface: Interface to configure
    176 * @num_ports: Number of ports on the interface
    177 *
    178 * Returns Zero on success, negative on failure
    179 */
    180int __cvmx_helper_setup_gmx(int interface, int num_ports)
    181{
    182	union cvmx_gmxx_tx_prts gmx_tx_prts;
    183	union cvmx_gmxx_rx_prts gmx_rx_prts;
    184	union cvmx_pko_reg_gmx_port_mode pko_mode;
    185	union cvmx_gmxx_txx_thresh gmx_tx_thresh;
    186	int index;
    187
    188	/* Tell GMX the number of TX ports on this interface */
    189	gmx_tx_prts.u64 = cvmx_read_csr(CVMX_GMXX_TX_PRTS(interface));
    190	gmx_tx_prts.s.prts = num_ports;
    191	cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), gmx_tx_prts.u64);
    192
    193	/* Tell GMX the number of RX ports on this interface.  This only
    194	 ** applies to *GMII and XAUI ports */
    195	if (cvmx_helper_interface_get_mode(interface) ==
    196	    CVMX_HELPER_INTERFACE_MODE_RGMII
    197	    || cvmx_helper_interface_get_mode(interface) ==
    198	    CVMX_HELPER_INTERFACE_MODE_SGMII
    199	    || cvmx_helper_interface_get_mode(interface) ==
    200	    CVMX_HELPER_INTERFACE_MODE_GMII
    201	    || cvmx_helper_interface_get_mode(interface) ==
    202	    CVMX_HELPER_INTERFACE_MODE_XAUI) {
    203		if (num_ports > 4) {
    204			cvmx_dprintf("__cvmx_helper_setup_gmx: Illegal "
    205				     "num_ports\n");
    206			return -1;
    207		}
    208
    209		gmx_rx_prts.u64 = cvmx_read_csr(CVMX_GMXX_RX_PRTS(interface));
    210		gmx_rx_prts.s.prts = num_ports;
    211		cvmx_write_csr(CVMX_GMXX_RX_PRTS(interface), gmx_rx_prts.u64);
    212	}
    213
    214	/* Skip setting CVMX_PKO_REG_GMX_PORT_MODE on 30XX, 31XX, and 50XX */
    215	if (!OCTEON_IS_MODEL(OCTEON_CN30XX) && !OCTEON_IS_MODEL(OCTEON_CN31XX)
    216	    && !OCTEON_IS_MODEL(OCTEON_CN50XX)) {
    217		/* Tell PKO the number of ports on this interface */
    218		pko_mode.u64 = cvmx_read_csr(CVMX_PKO_REG_GMX_PORT_MODE);
    219		if (interface == 0) {
    220			if (num_ports == 1)
    221				pko_mode.s.mode0 = 4;
    222			else if (num_ports == 2)
    223				pko_mode.s.mode0 = 3;
    224			else if (num_ports <= 4)
    225				pko_mode.s.mode0 = 2;
    226			else if (num_ports <= 8)
    227				pko_mode.s.mode0 = 1;
    228			else
    229				pko_mode.s.mode0 = 0;
    230		} else {
    231			if (num_ports == 1)
    232				pko_mode.s.mode1 = 4;
    233			else if (num_ports == 2)
    234				pko_mode.s.mode1 = 3;
    235			else if (num_ports <= 4)
    236				pko_mode.s.mode1 = 2;
    237			else if (num_ports <= 8)
    238				pko_mode.s.mode1 = 1;
    239			else
    240				pko_mode.s.mode1 = 0;
    241		}
    242		cvmx_write_csr(CVMX_PKO_REG_GMX_PORT_MODE, pko_mode.u64);
    243	}
    244
    245	/*
    246	 * Set GMX to buffer as much data as possible before starting
    247	 * transmit.  This reduces the chances that we have a TX under
    248	 * run due to memory contention. Any packet that fits entirely
    249	 * in the GMX FIFO can never have an under run regardless of
    250	 * memory load.
    251	 */
    252	gmx_tx_thresh.u64 = cvmx_read_csr(CVMX_GMXX_TXX_THRESH(0, interface));
    253	if (OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN31XX)
    254	    || OCTEON_IS_MODEL(OCTEON_CN50XX)) {
    255		/* These chips have a fixed max threshold of 0x40 */
    256		gmx_tx_thresh.s.cnt = 0x40;
    257	} else {
    258		/* Choose the max value for the number of ports */
    259		if (num_ports <= 1)
    260			gmx_tx_thresh.s.cnt = 0x100 / 1;
    261		else if (num_ports == 2)
    262			gmx_tx_thresh.s.cnt = 0x100 / 2;
    263		else
    264			gmx_tx_thresh.s.cnt = 0x100 / 4;
    265	}
    266	/*
    267	 * SPI and XAUI can have lots of ports but the GMX hardware
    268	 * only ever has a max of 4.
    269	 */
    270	if (num_ports > 4)
    271		num_ports = 4;
    272	for (index = 0; index < num_ports; index++)
    273		cvmx_write_csr(CVMX_GMXX_TXX_THRESH(index, interface),
    274			       gmx_tx_thresh.u64);
    275
    276	return 0;
    277}
    278
    279/**
    280 * Returns the IPD/PKO port number for a port on the given
    281 * interface.
    282 *
    283 * @interface: Interface to use
    284 * @port:      Port on the interface
    285 *
    286 * Returns IPD/PKO port number
    287 */
    288int cvmx_helper_get_ipd_port(int interface, int port)
    289{
    290	switch (interface) {
    291	case 0:
    292		return port;
    293	case 1:
    294		return port + 16;
    295	case 2:
    296		return port + 32;
    297	case 3:
    298		return port + 36;
    299	case 4:
    300		return port + 40;
    301	case 5:
    302		return port + 44;
    303	}
    304	return -1;
    305}
    306EXPORT_SYMBOL_GPL(cvmx_helper_get_ipd_port);
    307
    308/**
    309 * Returns the interface number for an IPD/PKO port number.
    310 *
    311 * @ipd_port: IPD/PKO port number
    312 *
    313 * Returns Interface number
    314 */
    315int cvmx_helper_get_interface_num(int ipd_port)
    316{
    317	if (ipd_port < 16)
    318		return 0;
    319	else if (ipd_port < 32)
    320		return 1;
    321	else if (ipd_port < 36)
    322		return 2;
    323	else if (ipd_port < 40)
    324		return 3;
    325	else if (ipd_port < 44)
    326		return 4;
    327	else if (ipd_port < 48)
    328		return 5;
    329	else
    330		cvmx_dprintf("cvmx_helper_get_interface_num: Illegal IPD "
    331			     "port number\n");
    332
    333	return -1;
    334}
    335EXPORT_SYMBOL_GPL(cvmx_helper_get_interface_num);
    336
    337/**
    338 * Returns the interface index number for an IPD/PKO port
    339 * number.
    340 *
    341 * @ipd_port: IPD/PKO port number
    342 *
    343 * Returns Interface index number
    344 */
    345int cvmx_helper_get_interface_index_num(int ipd_port)
    346{
    347	if (ipd_port < 32)
    348		return ipd_port & 15;
    349	else if (ipd_port < 36)
    350		return ipd_port & 3;
    351	else if (ipd_port < 40)
    352		return ipd_port & 3;
    353	else if (ipd_port < 44)
    354		return ipd_port & 3;
    355	else if (ipd_port < 48)
    356		return ipd_port & 3;
    357	else
    358		cvmx_dprintf("cvmx_helper_get_interface_index_num: "
    359			     "Illegal IPD port number\n");
    360
    361	return -1;
    362}
    363EXPORT_SYMBOL_GPL(cvmx_helper_get_interface_index_num);