Back to home page

OSCL-LXR

 
 

    


0001 /***********************license start***************
0002  * Author: Cavium Networks
0003  *
0004  * Contact: support@caviumnetworks.com
0005  * This file is part of the OCTEON SDK
0006  *
0007  * Copyright (c) 2003-2008 Cavium Networks
0008  *
0009  * This file is free software; you can redistribute it and/or modify
0010  * it under the terms of the GNU General Public License, Version 2, as
0011  * published by the Free Software Foundation.
0012  *
0013  * This file is distributed in the hope that it will be useful, but
0014  * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
0015  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
0016  * NONINFRINGEMENT.  See the GNU General Public License for more
0017  * details.
0018  *
0019  * You should have received a copy of the GNU General Public License
0020  * along with this file; if not, write to the Free Software
0021  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
0022  * or visit http://www.gnu.org/licenses/.
0023  *
0024  * This file may also be available under a different license from Cavium.
0025  * Contact Cavium Networks for more information
0026  ***********************license end**************************************/
0027 
0028 /*
0029  * Small helper utilities.
0030  */
0031 #include <linux/kernel.h>
0032 
0033 #include <asm/octeon/octeon.h>
0034 
0035 #include <asm/octeon/cvmx-config.h>
0036 
0037 #include <asm/octeon/cvmx-fpa.h>
0038 #include <asm/octeon/cvmx-pip.h>
0039 #include <asm/octeon/cvmx-pko.h>
0040 #include <asm/octeon/cvmx-ipd.h>
0041 #include <asm/octeon/cvmx-spi.h>
0042 
0043 #include <asm/octeon/cvmx-helper.h>
0044 #include <asm/octeon/cvmx-helper-util.h>
0045 
0046 #include <asm/octeon/cvmx-ipd-defs.h>
0047 
0048 /**
0049  * Convert a interface mode into a human readable string
0050  *
0051  * @mode:   Mode to convert
0052  *
0053  * Returns String
0054  */
0055 const char *cvmx_helper_interface_mode_to_string(cvmx_helper_interface_mode_t
0056                          mode)
0057 {
0058     switch (mode) {
0059     case CVMX_HELPER_INTERFACE_MODE_DISABLED:
0060         return "DISABLED";
0061     case CVMX_HELPER_INTERFACE_MODE_RGMII:
0062         return "RGMII";
0063     case CVMX_HELPER_INTERFACE_MODE_GMII:
0064         return "GMII";
0065     case CVMX_HELPER_INTERFACE_MODE_SPI:
0066         return "SPI";
0067     case CVMX_HELPER_INTERFACE_MODE_PCIE:
0068         return "PCIE";
0069     case CVMX_HELPER_INTERFACE_MODE_XAUI:
0070         return "XAUI";
0071     case CVMX_HELPER_INTERFACE_MODE_SGMII:
0072         return "SGMII";
0073     case CVMX_HELPER_INTERFACE_MODE_PICMG:
0074         return "PICMG";
0075     case CVMX_HELPER_INTERFACE_MODE_NPI:
0076         return "NPI";
0077     case CVMX_HELPER_INTERFACE_MODE_LOOP:
0078         return "LOOP";
0079     }
0080     return "UNKNOWN";
0081 }
0082 
0083 /**
0084  * Setup Random Early Drop on a specific input queue
0085  *
0086  * @queue:  Input queue to setup RED on (0-7)
0087  * @pass_thresh:
0088  *       Packets will begin slowly dropping when there are less than
0089  *       this many packet buffers free in FPA 0.
0090  * @drop_thresh:
0091  *       All incoming packets will be dropped when there are less
0092  *       than this many free packet buffers in FPA 0.
0093  * Returns Zero on success. Negative on failure
0094  */
0095 static int cvmx_helper_setup_red_queue(int queue, int pass_thresh,
0096                        int drop_thresh)
0097 {
0098     union cvmx_ipd_qosx_red_marks red_marks;
0099     union cvmx_ipd_red_quex_param red_param;
0100 
0101     /* Set RED to begin dropping packets when there are pass_thresh buffers
0102        left. It will linearly drop more packets until reaching drop_thresh
0103        buffers */
0104     red_marks.u64 = 0;
0105     red_marks.s.drop = drop_thresh;
0106     red_marks.s.pass = pass_thresh;
0107     cvmx_write_csr(CVMX_IPD_QOSX_RED_MARKS(queue), red_marks.u64);
0108 
0109     /* Use the actual queue 0 counter, not the average */
0110     red_param.u64 = 0;
0111     red_param.s.prb_con =
0112         (255ul << 24) / (red_marks.s.pass - red_marks.s.drop);
0113     red_param.s.avg_con = 1;
0114     red_param.s.new_con = 255;
0115     red_param.s.use_pcnt = 1;
0116     cvmx_write_csr(CVMX_IPD_RED_QUEX_PARAM(queue), red_param.u64);
0117     return 0;
0118 }
0119 
0120 /**
0121  * Setup Random Early Drop to automatically begin dropping packets.
0122  *
0123  * @pass_thresh:
0124  *       Packets will begin slowly dropping when there are less than
0125  *       this many packet buffers free in FPA 0.
0126  * @drop_thresh:
0127  *       All incoming packets will be dropped when there are less
0128  *       than this many free packet buffers in FPA 0.
0129  * Returns Zero on success. Negative on failure
0130  */
0131 int cvmx_helper_setup_red(int pass_thresh, int drop_thresh)
0132 {
0133     union cvmx_ipd_portx_bp_page_cnt page_cnt;
0134     union cvmx_ipd_bp_prt_red_end ipd_bp_prt_red_end;
0135     union cvmx_ipd_red_port_enable red_port_enable;
0136     int queue;
0137     int interface;
0138     int port;
0139 
0140     /* Disable backpressure based on queued buffers. It needs SW support */
0141     page_cnt.u64 = 0;
0142     page_cnt.s.bp_enb = 0;
0143     page_cnt.s.page_cnt = 100;
0144     for (interface = 0; interface < 2; interface++) {
0145         for (port = cvmx_helper_get_first_ipd_port(interface);
0146              port < cvmx_helper_get_last_ipd_port(interface); port++)
0147             cvmx_write_csr(CVMX_IPD_PORTX_BP_PAGE_CNT(port),
0148                        page_cnt.u64);
0149     }
0150 
0151     for (queue = 0; queue < 8; queue++)
0152         cvmx_helper_setup_red_queue(queue, pass_thresh, drop_thresh);
0153 
0154     /* Shutoff the dropping based on the per port page count. SW isn't
0155        decrementing it right now */
0156     ipd_bp_prt_red_end.u64 = 0;
0157     ipd_bp_prt_red_end.s.prt_enb = 0;
0158     cvmx_write_csr(CVMX_IPD_BP_PRT_RED_END, ipd_bp_prt_red_end.u64);
0159 
0160     red_port_enable.u64 = 0;
0161     red_port_enable.s.prt_enb = 0xfffffffffull;
0162     red_port_enable.s.avg_dly = 10000;
0163     red_port_enable.s.prb_dly = 10000;
0164     cvmx_write_csr(CVMX_IPD_RED_PORT_ENABLE, red_port_enable.u64);
0165 
0166     return 0;
0167 }
0168 EXPORT_SYMBOL_GPL(cvmx_helper_setup_red);
0169 
0170 /**
0171  * Setup the common GMX settings that determine the number of
0172  * ports. These setting apply to almost all configurations of all
0173  * chips.
0174  *
0175  * @interface: Interface to configure
0176  * @num_ports: Number of ports on the interface
0177  *
0178  * Returns Zero on success, negative on failure
0179  */
0180 int __cvmx_helper_setup_gmx(int interface, int num_ports)
0181 {
0182     union cvmx_gmxx_tx_prts gmx_tx_prts;
0183     union cvmx_gmxx_rx_prts gmx_rx_prts;
0184     union cvmx_pko_reg_gmx_port_mode pko_mode;
0185     union cvmx_gmxx_txx_thresh gmx_tx_thresh;
0186     int index;
0187 
0188     /* Tell GMX the number of TX ports on this interface */
0189     gmx_tx_prts.u64 = cvmx_read_csr(CVMX_GMXX_TX_PRTS(interface));
0190     gmx_tx_prts.s.prts = num_ports;
0191     cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), gmx_tx_prts.u64);
0192 
0193     /* Tell GMX the number of RX ports on this interface.  This only
0194      ** applies to *GMII and XAUI ports */
0195     if (cvmx_helper_interface_get_mode(interface) ==
0196         CVMX_HELPER_INTERFACE_MODE_RGMII
0197         || cvmx_helper_interface_get_mode(interface) ==
0198         CVMX_HELPER_INTERFACE_MODE_SGMII
0199         || cvmx_helper_interface_get_mode(interface) ==
0200         CVMX_HELPER_INTERFACE_MODE_GMII
0201         || cvmx_helper_interface_get_mode(interface) ==
0202         CVMX_HELPER_INTERFACE_MODE_XAUI) {
0203         if (num_ports > 4) {
0204             cvmx_dprintf("__cvmx_helper_setup_gmx: Illegal "
0205                      "num_ports\n");
0206             return -1;
0207         }
0208 
0209         gmx_rx_prts.u64 = cvmx_read_csr(CVMX_GMXX_RX_PRTS(interface));
0210         gmx_rx_prts.s.prts = num_ports;
0211         cvmx_write_csr(CVMX_GMXX_RX_PRTS(interface), gmx_rx_prts.u64);
0212     }
0213 
0214     /* Skip setting CVMX_PKO_REG_GMX_PORT_MODE on 30XX, 31XX, and 50XX */
0215     if (!OCTEON_IS_MODEL(OCTEON_CN30XX) && !OCTEON_IS_MODEL(OCTEON_CN31XX)
0216         && !OCTEON_IS_MODEL(OCTEON_CN50XX)) {
0217         /* Tell PKO the number of ports on this interface */
0218         pko_mode.u64 = cvmx_read_csr(CVMX_PKO_REG_GMX_PORT_MODE);
0219         if (interface == 0) {
0220             if (num_ports == 1)
0221                 pko_mode.s.mode0 = 4;
0222             else if (num_ports == 2)
0223                 pko_mode.s.mode0 = 3;
0224             else if (num_ports <= 4)
0225                 pko_mode.s.mode0 = 2;
0226             else if (num_ports <= 8)
0227                 pko_mode.s.mode0 = 1;
0228             else
0229                 pko_mode.s.mode0 = 0;
0230         } else {
0231             if (num_ports == 1)
0232                 pko_mode.s.mode1 = 4;
0233             else if (num_ports == 2)
0234                 pko_mode.s.mode1 = 3;
0235             else if (num_ports <= 4)
0236                 pko_mode.s.mode1 = 2;
0237             else if (num_ports <= 8)
0238                 pko_mode.s.mode1 = 1;
0239             else
0240                 pko_mode.s.mode1 = 0;
0241         }
0242         cvmx_write_csr(CVMX_PKO_REG_GMX_PORT_MODE, pko_mode.u64);
0243     }
0244 
0245     /*
0246      * Set GMX to buffer as much data as possible before starting
0247      * transmit.  This reduces the chances that we have a TX under
0248      * run due to memory contention. Any packet that fits entirely
0249      * in the GMX FIFO can never have an under run regardless of
0250      * memory load.
0251      */
0252     gmx_tx_thresh.u64 = cvmx_read_csr(CVMX_GMXX_TXX_THRESH(0, interface));
0253     if (OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN31XX)
0254         || OCTEON_IS_MODEL(OCTEON_CN50XX)) {
0255         /* These chips have a fixed max threshold of 0x40 */
0256         gmx_tx_thresh.s.cnt = 0x40;
0257     } else {
0258         /* Choose the max value for the number of ports */
0259         if (num_ports <= 1)
0260             gmx_tx_thresh.s.cnt = 0x100 / 1;
0261         else if (num_ports == 2)
0262             gmx_tx_thresh.s.cnt = 0x100 / 2;
0263         else
0264             gmx_tx_thresh.s.cnt = 0x100 / 4;
0265     }
0266     /*
0267      * SPI and XAUI can have lots of ports but the GMX hardware
0268      * only ever has a max of 4.
0269      */
0270     if (num_ports > 4)
0271         num_ports = 4;
0272     for (index = 0; index < num_ports; index++)
0273         cvmx_write_csr(CVMX_GMXX_TXX_THRESH(index, interface),
0274                    gmx_tx_thresh.u64);
0275 
0276     return 0;
0277 }
0278 
0279 /**
0280  * Returns the IPD/PKO port number for a port on the given
0281  * interface.
0282  *
0283  * @interface: Interface to use
0284  * @port:      Port on the interface
0285  *
0286  * Returns IPD/PKO port number
0287  */
0288 int cvmx_helper_get_ipd_port(int interface, int port)
0289 {
0290     switch (interface) {
0291     case 0:
0292         return port;
0293     case 1:
0294         return port + 16;
0295     case 2:
0296         return port + 32;
0297     case 3:
0298         return port + 36;
0299     case 4:
0300         return port + 40;
0301     case 5:
0302         return port + 44;
0303     }
0304     return -1;
0305 }
0306 EXPORT_SYMBOL_GPL(cvmx_helper_get_ipd_port);
0307 
0308 /**
0309  * Returns the interface number for an IPD/PKO port number.
0310  *
0311  * @ipd_port: IPD/PKO port number
0312  *
0313  * Returns Interface number
0314  */
0315 int cvmx_helper_get_interface_num(int ipd_port)
0316 {
0317     if (ipd_port < 16)
0318         return 0;
0319     else if (ipd_port < 32)
0320         return 1;
0321     else if (ipd_port < 36)
0322         return 2;
0323     else if (ipd_port < 40)
0324         return 3;
0325     else if (ipd_port < 44)
0326         return 4;
0327     else if (ipd_port < 48)
0328         return 5;
0329     else
0330         cvmx_dprintf("cvmx_helper_get_interface_num: Illegal IPD "
0331                  "port number\n");
0332 
0333     return -1;
0334 }
0335 EXPORT_SYMBOL_GPL(cvmx_helper_get_interface_num);
0336 
0337 /**
0338  * Returns the interface index number for an IPD/PKO port
0339  * number.
0340  *
0341  * @ipd_port: IPD/PKO port number
0342  *
0343  * Returns Interface index number
0344  */
0345 int cvmx_helper_get_interface_index_num(int ipd_port)
0346 {
0347     if (ipd_port < 32)
0348         return ipd_port & 15;
0349     else if (ipd_port < 36)
0350         return ipd_port & 3;
0351     else if (ipd_port < 40)
0352         return ipd_port & 3;
0353     else if (ipd_port < 44)
0354         return ipd_port & 3;
0355     else if (ipd_port < 48)
0356         return ipd_port & 3;
0357     else
0358         cvmx_dprintf("cvmx_helper_get_interface_index_num: "
0359                  "Illegal IPD port number\n");
0360 
0361     return -1;
0362 }
0363 EXPORT_SYMBOL_GPL(cvmx_helper_get_interface_index_num);