linux/arch/mips/cavium-octeon/executive/cvmx-helper-util.c
<<
>>
Prefs
   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);
 364