Path: blob/master/arch/mips/cavium-octeon/executive/cvmx-helper-util.c
26481 views
/***********************license start***************1* Author: Cavium Networks2*3* Contact: [email protected]4* This file is part of the OCTEON SDK5*6* Copyright (c) 2003-2008 Cavium Networks7*8* This file is free software; you can redistribute it and/or modify9* it under the terms of the GNU General Public License, Version 2, as10* published by the Free Software Foundation.11*12* This file is distributed in the hope that it will be useful, but13* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty14* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or15* NONINFRINGEMENT. See the GNU General Public License for more16* details.17*18* You should have received a copy of the GNU General Public License19* along with this file; if not, write to the Free Software20* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA21* or visit http://www.gnu.org/licenses/.22*23* This file may also be available under a different license from Cavium.24* Contact Cavium Networks for more information25***********************license end**************************************/2627/*28* Small helper utilities.29*/30#include <linux/kernel.h>3132#include <asm/octeon/octeon.h>3334#include <asm/octeon/cvmx-config.h>3536#include <asm/octeon/cvmx-fpa.h>37#include <asm/octeon/cvmx-pip.h>38#include <asm/octeon/cvmx-pko.h>39#include <asm/octeon/cvmx-ipd.h>40#include <asm/octeon/cvmx-spi.h>4142#include <asm/octeon/cvmx-helper.h>43#include <asm/octeon/cvmx-helper-util.h>4445#include <asm/octeon/cvmx-ipd-defs.h>4647/**48* Convert a interface mode into a human readable string49*50* @mode: Mode to convert51*52* Returns String53*/54const char *cvmx_helper_interface_mode_to_string(cvmx_helper_interface_mode_t55mode)56{57switch (mode) {58case CVMX_HELPER_INTERFACE_MODE_DISABLED:59return "DISABLED";60case CVMX_HELPER_INTERFACE_MODE_RGMII:61return "RGMII";62case CVMX_HELPER_INTERFACE_MODE_GMII:63return "GMII";64case CVMX_HELPER_INTERFACE_MODE_SPI:65return "SPI";66case CVMX_HELPER_INTERFACE_MODE_PCIE:67return "PCIE";68case CVMX_HELPER_INTERFACE_MODE_XAUI:69return "XAUI";70case CVMX_HELPER_INTERFACE_MODE_SGMII:71return "SGMII";72case CVMX_HELPER_INTERFACE_MODE_PICMG:73return "PICMG";74case CVMX_HELPER_INTERFACE_MODE_NPI:75return "NPI";76case CVMX_HELPER_INTERFACE_MODE_LOOP:77return "LOOP";78}79return "UNKNOWN";80}8182/**83* Setup Random Early Drop on a specific input queue84*85* @queue: Input queue to setup RED on (0-7)86* @pass_thresh:87* Packets will begin slowly dropping when there are less than88* this many packet buffers free in FPA 0.89* @drop_thresh:90* All incoming packets will be dropped when there are less91* than this many free packet buffers in FPA 0.92* Returns Zero on success. Negative on failure93*/94static int cvmx_helper_setup_red_queue(int queue, int pass_thresh,95int drop_thresh)96{97union cvmx_ipd_qosx_red_marks red_marks;98union cvmx_ipd_red_quex_param red_param;99100/* Set RED to begin dropping packets when there are pass_thresh buffers101left. It will linearly drop more packets until reaching drop_thresh102buffers */103red_marks.u64 = 0;104red_marks.s.drop = drop_thresh;105red_marks.s.pass = pass_thresh;106cvmx_write_csr(CVMX_IPD_QOSX_RED_MARKS(queue), red_marks.u64);107108/* Use the actual queue 0 counter, not the average */109red_param.u64 = 0;110red_param.s.prb_con =111(255ul << 24) / (red_marks.s.pass - red_marks.s.drop);112red_param.s.avg_con = 1;113red_param.s.new_con = 255;114red_param.s.use_pcnt = 1;115cvmx_write_csr(CVMX_IPD_RED_QUEX_PARAM(queue), red_param.u64);116return 0;117}118119/**120* Setup Random Early Drop to automatically begin dropping packets.121*122* @pass_thresh:123* Packets will begin slowly dropping when there are less than124* this many packet buffers free in FPA 0.125* @drop_thresh:126* All incoming packets will be dropped when there are less127* than this many free packet buffers in FPA 0.128* Returns Zero on success. Negative on failure129*/130int cvmx_helper_setup_red(int pass_thresh, int drop_thresh)131{132union cvmx_ipd_portx_bp_page_cnt page_cnt;133union cvmx_ipd_bp_prt_red_end ipd_bp_prt_red_end;134union cvmx_ipd_red_port_enable red_port_enable;135int queue;136int interface;137int port;138139/* Disable backpressure based on queued buffers. It needs SW support */140page_cnt.u64 = 0;141page_cnt.s.bp_enb = 0;142page_cnt.s.page_cnt = 100;143for (interface = 0; interface < 2; interface++) {144for (port = cvmx_helper_get_first_ipd_port(interface);145port < cvmx_helper_get_last_ipd_port(interface); port++)146cvmx_write_csr(CVMX_IPD_PORTX_BP_PAGE_CNT(port),147page_cnt.u64);148}149150for (queue = 0; queue < 8; queue++)151cvmx_helper_setup_red_queue(queue, pass_thresh, drop_thresh);152153/* Shutoff the dropping based on the per port page count. SW isn't154decrementing it right now */155ipd_bp_prt_red_end.u64 = 0;156ipd_bp_prt_red_end.s.prt_enb = 0;157cvmx_write_csr(CVMX_IPD_BP_PRT_RED_END, ipd_bp_prt_red_end.u64);158159red_port_enable.u64 = 0;160red_port_enable.s.prt_enb = 0xfffffffffull;161red_port_enable.s.avg_dly = 10000;162red_port_enable.s.prb_dly = 10000;163cvmx_write_csr(CVMX_IPD_RED_PORT_ENABLE, red_port_enable.u64);164165return 0;166}167EXPORT_SYMBOL_GPL(cvmx_helper_setup_red);168169/**170* Setup the common GMX settings that determine the number of171* ports. These setting apply to almost all configurations of all172* chips.173*174* @interface: Interface to configure175* @num_ports: Number of ports on the interface176*177* Returns Zero on success, negative on failure178*/179int __cvmx_helper_setup_gmx(int interface, int num_ports)180{181union cvmx_gmxx_tx_prts gmx_tx_prts;182union cvmx_gmxx_rx_prts gmx_rx_prts;183union cvmx_pko_reg_gmx_port_mode pko_mode;184union cvmx_gmxx_txx_thresh gmx_tx_thresh;185int index;186187/* Tell GMX the number of TX ports on this interface */188gmx_tx_prts.u64 = cvmx_read_csr(CVMX_GMXX_TX_PRTS(interface));189gmx_tx_prts.s.prts = num_ports;190cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), gmx_tx_prts.u64);191192/* Tell GMX the number of RX ports on this interface. This only193** applies to *GMII and XAUI ports */194if (cvmx_helper_interface_get_mode(interface) ==195CVMX_HELPER_INTERFACE_MODE_RGMII196|| cvmx_helper_interface_get_mode(interface) ==197CVMX_HELPER_INTERFACE_MODE_SGMII198|| cvmx_helper_interface_get_mode(interface) ==199CVMX_HELPER_INTERFACE_MODE_GMII200|| cvmx_helper_interface_get_mode(interface) ==201CVMX_HELPER_INTERFACE_MODE_XAUI) {202if (num_ports > 4) {203cvmx_dprintf("__cvmx_helper_setup_gmx: Illegal "204"num_ports\n");205return -1;206}207208gmx_rx_prts.u64 = cvmx_read_csr(CVMX_GMXX_RX_PRTS(interface));209gmx_rx_prts.s.prts = num_ports;210cvmx_write_csr(CVMX_GMXX_RX_PRTS(interface), gmx_rx_prts.u64);211}212213/* Skip setting CVMX_PKO_REG_GMX_PORT_MODE on 30XX, 31XX, and 50XX */214if (!OCTEON_IS_MODEL(OCTEON_CN30XX) && !OCTEON_IS_MODEL(OCTEON_CN31XX)215&& !OCTEON_IS_MODEL(OCTEON_CN50XX)) {216/* Tell PKO the number of ports on this interface */217pko_mode.u64 = cvmx_read_csr(CVMX_PKO_REG_GMX_PORT_MODE);218if (interface == 0) {219if (num_ports == 1)220pko_mode.s.mode0 = 4;221else if (num_ports == 2)222pko_mode.s.mode0 = 3;223else if (num_ports <= 4)224pko_mode.s.mode0 = 2;225else if (num_ports <= 8)226pko_mode.s.mode0 = 1;227else228pko_mode.s.mode0 = 0;229} else {230if (num_ports == 1)231pko_mode.s.mode1 = 4;232else if (num_ports == 2)233pko_mode.s.mode1 = 3;234else if (num_ports <= 4)235pko_mode.s.mode1 = 2;236else if (num_ports <= 8)237pko_mode.s.mode1 = 1;238else239pko_mode.s.mode1 = 0;240}241cvmx_write_csr(CVMX_PKO_REG_GMX_PORT_MODE, pko_mode.u64);242}243244/*245* Set GMX to buffer as much data as possible before starting246* transmit. This reduces the chances that we have a TX under247* run due to memory contention. Any packet that fits entirely248* in the GMX FIFO can never have an under run regardless of249* memory load.250*/251gmx_tx_thresh.u64 = cvmx_read_csr(CVMX_GMXX_TXX_THRESH(0, interface));252if (OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN31XX)253|| OCTEON_IS_MODEL(OCTEON_CN50XX)) {254/* These chips have a fixed max threshold of 0x40 */255gmx_tx_thresh.s.cnt = 0x40;256} else {257/* Choose the max value for the number of ports */258if (num_ports <= 1)259gmx_tx_thresh.s.cnt = 0x100 / 1;260else if (num_ports == 2)261gmx_tx_thresh.s.cnt = 0x100 / 2;262else263gmx_tx_thresh.s.cnt = 0x100 / 4;264}265/*266* SPI and XAUI can have lots of ports but the GMX hardware267* only ever has a max of 4.268*/269if (num_ports > 4)270num_ports = 4;271for (index = 0; index < num_ports; index++)272cvmx_write_csr(CVMX_GMXX_TXX_THRESH(index, interface),273gmx_tx_thresh.u64);274275return 0;276}277278/**279* Returns the IPD/PKO port number for a port on the given280* interface.281*282* @interface: Interface to use283* @port: Port on the interface284*285* Returns IPD/PKO port number286*/287int cvmx_helper_get_ipd_port(int interface, int port)288{289switch (interface) {290case 0:291return port;292case 1:293return port + 16;294case 2:295return port + 32;296case 3:297return port + 36;298case 4:299return port + 40;300case 5:301return port + 44;302}303return -1;304}305EXPORT_SYMBOL_GPL(cvmx_helper_get_ipd_port);306307/**308* Returns the interface number for an IPD/PKO port number.309*310* @ipd_port: IPD/PKO port number311*312* Returns Interface number313*/314int cvmx_helper_get_interface_num(int ipd_port)315{316if (ipd_port < 16)317return 0;318else if (ipd_port < 32)319return 1;320else if (ipd_port < 36)321return 2;322else if (ipd_port < 40)323return 3;324else if (ipd_port < 44)325return 4;326else if (ipd_port < 48)327return 5;328else329cvmx_dprintf("cvmx_helper_get_interface_num: Illegal IPD "330"port number\n");331332return -1;333}334EXPORT_SYMBOL_GPL(cvmx_helper_get_interface_num);335336/**337* Returns the interface index number for an IPD/PKO port338* number.339*340* @ipd_port: IPD/PKO port number341*342* Returns Interface index number343*/344int cvmx_helper_get_interface_index_num(int ipd_port)345{346if (ipd_port < 32)347return ipd_port & 15;348else if (ipd_port < 36)349return ipd_port & 3;350else if (ipd_port < 40)351return ipd_port & 3;352else if (ipd_port < 44)353return ipd_port & 3;354else if (ipd_port < 48)355return ipd_port & 3;356else357cvmx_dprintf("cvmx_helper_get_interface_index_num: "358"Illegal IPD port number\n");359360return -1;361}362EXPORT_SYMBOL_GPL(cvmx_helper_get_interface_index_num);363364365