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-2018 Cavium, Inc.
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  * Functions for XAUI initialization, configuration,
0030  * and monitoring.
0031  *
0032  */
0033 
0034 #include <asm/octeon/octeon.h>
0035 
0036 #include <asm/octeon/cvmx-config.h>
0037 
0038 #include <asm/octeon/cvmx-helper.h>
0039 
0040 #include <asm/octeon/cvmx-pko-defs.h>
0041 #include <asm/octeon/cvmx-gmxx-defs.h>
0042 #include <asm/octeon/cvmx-pcsx-defs.h>
0043 #include <asm/octeon/cvmx-pcsxx-defs.h>
0044 
0045 int __cvmx_helper_xaui_enumerate(int interface)
0046 {
0047     union cvmx_gmxx_hg2_control gmx_hg2_control;
0048 
0049     /* If HiGig2 is enabled return 16 ports, otherwise return 1 port */
0050     gmx_hg2_control.u64 = cvmx_read_csr(CVMX_GMXX_HG2_CONTROL(interface));
0051     if (gmx_hg2_control.s.hg2tx_en)
0052         return 16;
0053     else
0054         return 1;
0055 }
0056 
0057 /*
0058  * Probe a XAUI interface and determine the number of ports
0059  * connected to it. The XAUI interface should still be down
0060  * after this call.
0061  *
0062  * @interface: Interface to probe
0063  *
0064  * Returns Number of ports on the interface. Zero to disable.
0065  */
0066 int __cvmx_helper_xaui_probe(int interface)
0067 {
0068     int i;
0069     union cvmx_gmxx_inf_mode mode;
0070 
0071     /*
0072      * Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the
0073      * interface needs to be enabled before IPD otherwise per port
0074      * backpressure may not work properly.
0075      */
0076     mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
0077     mode.s.en = 1;
0078     cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64);
0079 
0080     __cvmx_helper_setup_gmx(interface, 1);
0081 
0082     /*
0083      * Setup PKO to support 16 ports for HiGig2 virtual
0084      * ports. We're pointing all of the PKO packet ports for this
0085      * interface to the XAUI. This allows us to use HiGig2
0086      * backpressure per port.
0087      */
0088     for (i = 0; i < 16; i++) {
0089         union cvmx_pko_mem_port_ptrs pko_mem_port_ptrs;
0090         pko_mem_port_ptrs.u64 = 0;
0091         /*
0092          * We set each PKO port to have equal priority in a
0093          * round robin fashion.
0094          */
0095         pko_mem_port_ptrs.s.static_p = 0;
0096         pko_mem_port_ptrs.s.qos_mask = 0xff;
0097         /* All PKO ports map to the same XAUI hardware port */
0098         pko_mem_port_ptrs.s.eid = interface * 4;
0099         pko_mem_port_ptrs.s.pid = interface * 16 + i;
0100         cvmx_write_csr(CVMX_PKO_MEM_PORT_PTRS, pko_mem_port_ptrs.u64);
0101     }
0102     return __cvmx_helper_xaui_enumerate(interface);
0103 }
0104 
0105 /*
0106  * Bringup and enable a XAUI interface. After this call packet
0107  * I/O should be fully functional. This is called with IPD
0108  * enabled but PKO disabled.
0109  *
0110  * @interface: Interface to bring up
0111  *
0112  * Returns Zero on success, negative on failure
0113  */
0114 int __cvmx_helper_xaui_enable(int interface)
0115 {
0116     union cvmx_gmxx_prtx_cfg gmx_cfg;
0117     union cvmx_pcsxx_control1_reg xauiCtl;
0118     union cvmx_pcsxx_misc_ctl_reg xauiMiscCtl;
0119     union cvmx_gmxx_tx_xaui_ctl gmxXauiTxCtl;
0120     union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
0121     union cvmx_gmxx_tx_int_en gmx_tx_int_en;
0122     union cvmx_pcsxx_int_en_reg pcsx_int_en_reg;
0123 
0124     /* Setup PKND */
0125     if (octeon_has_feature(OCTEON_FEATURE_PKND)) {
0126         gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
0127         gmx_cfg.s.pknd = cvmx_helper_get_ipd_port(interface, 0);
0128         cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
0129     }
0130 
0131     /* (1) Interface has already been enabled. */
0132 
0133     /* (2) Disable GMX. */
0134     xauiMiscCtl.u64 = cvmx_read_csr(CVMX_PCSXX_MISC_CTL_REG(interface));
0135     xauiMiscCtl.s.gmxeno = 1;
0136     cvmx_write_csr(CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64);
0137 
0138     /* (3) Disable GMX and PCSX interrupts. */
0139     gmx_rx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_EN(0, interface));
0140     cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), 0x0);
0141     gmx_tx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_TX_INT_EN(interface));
0142     cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0);
0143     pcsx_int_en_reg.u64 = cvmx_read_csr(CVMX_PCSXX_INT_EN_REG(interface));
0144     cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0);
0145 
0146     /* (4) Bring up the PCSX and GMX reconciliation layer. */
0147     /* (4)a Set polarity and lane swapping. */
0148     /* (4)b */
0149     gmxXauiTxCtl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
0150     /* Enable better IFG packing and improves performance */
0151     gmxXauiTxCtl.s.dic_en = 1;
0152     gmxXauiTxCtl.s.uni_en = 0;
0153     cvmx_write_csr(CVMX_GMXX_TX_XAUI_CTL(interface), gmxXauiTxCtl.u64);
0154 
0155     /* (4)c Aply reset sequence */
0156     xauiCtl.u64 = cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface));
0157     xauiCtl.s.lo_pwr = 0;
0158 
0159     /* Issuing a reset here seems to hang some CN66XX/CN68XX chips. */
0160     if (!OCTEON_IS_MODEL(OCTEON_CN66XX) &&
0161         !OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1_X) &&
0162         !OCTEON_IS_MODEL(OCTEON_CN68XX_PASS2_X))
0163         xauiCtl.s.reset = 1;
0164 
0165     cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), xauiCtl.u64);
0166 
0167     /* Wait for PCS to come out of reset */
0168     if (CVMX_WAIT_FOR_FIELD64
0169         (CVMX_PCSXX_CONTROL1_REG(interface), union cvmx_pcsxx_control1_reg,
0170          reset, ==, 0, 10000))
0171         return -1;
0172     /* Wait for PCS to be aligned */
0173     if (CVMX_WAIT_FOR_FIELD64
0174         (CVMX_PCSXX_10GBX_STATUS_REG(interface),
0175          union cvmx_pcsxx_10gbx_status_reg, alignd, ==, 1, 10000))
0176         return -1;
0177     /* Wait for RX to be ready */
0178     if (CVMX_WAIT_FOR_FIELD64
0179         (CVMX_GMXX_RX_XAUI_CTL(interface), union cvmx_gmxx_rx_xaui_ctl,
0180             status, ==, 0, 10000))
0181         return -1;
0182 
0183     /* (6) Configure GMX */
0184     gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
0185     gmx_cfg.s.en = 0;
0186     cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
0187 
0188     /* Wait for GMX RX to be idle */
0189     if (CVMX_WAIT_FOR_FIELD64
0190         (CVMX_GMXX_PRTX_CFG(0, interface), union cvmx_gmxx_prtx_cfg,
0191             rx_idle, ==, 1, 10000))
0192         return -1;
0193     /* Wait for GMX TX to be idle */
0194     if (CVMX_WAIT_FOR_FIELD64
0195         (CVMX_GMXX_PRTX_CFG(0, interface), union cvmx_gmxx_prtx_cfg,
0196             tx_idle, ==, 1, 10000))
0197         return -1;
0198 
0199     /* GMX configure */
0200     gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
0201     gmx_cfg.s.speed = 1;
0202     gmx_cfg.s.speed_msb = 0;
0203     gmx_cfg.s.slottime = 1;
0204     cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), 1);
0205     cvmx_write_csr(CVMX_GMXX_TXX_SLOT(0, interface), 512);
0206     cvmx_write_csr(CVMX_GMXX_TXX_BURST(0, interface), 8192);
0207     cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
0208 
0209     /* (7) Clear out any error state */
0210     cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(0, interface),
0211                cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(0, interface)));
0212     cvmx_write_csr(CVMX_GMXX_TX_INT_REG(interface),
0213                cvmx_read_csr(CVMX_GMXX_TX_INT_REG(interface)));
0214     cvmx_write_csr(CVMX_PCSXX_INT_REG(interface),
0215                cvmx_read_csr(CVMX_PCSXX_INT_REG(interface)));
0216 
0217     /* Wait for receive link */
0218     if (CVMX_WAIT_FOR_FIELD64
0219         (CVMX_PCSXX_STATUS1_REG(interface), union cvmx_pcsxx_status1_reg,
0220          rcv_lnk, ==, 1, 10000))
0221         return -1;
0222     if (CVMX_WAIT_FOR_FIELD64
0223         (CVMX_PCSXX_STATUS2_REG(interface), union cvmx_pcsxx_status2_reg,
0224          xmtflt, ==, 0, 10000))
0225         return -1;
0226     if (CVMX_WAIT_FOR_FIELD64
0227         (CVMX_PCSXX_STATUS2_REG(interface), union cvmx_pcsxx_status2_reg,
0228          rcvflt, ==, 0, 10000))
0229         return -1;
0230 
0231     cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), gmx_rx_int_en.u64);
0232     cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), gmx_tx_int_en.u64);
0233     cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), pcsx_int_en_reg.u64);
0234 
0235     /* (8) Enable packet reception */
0236     xauiMiscCtl.s.gmxeno = 0;
0237     cvmx_write_csr(CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64);
0238 
0239     gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
0240     gmx_cfg.s.en = 1;
0241     cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
0242 
0243     __cvmx_interrupt_pcsx_intx_en_reg_enable(0, interface);
0244     __cvmx_interrupt_pcsx_intx_en_reg_enable(1, interface);
0245     __cvmx_interrupt_pcsx_intx_en_reg_enable(2, interface);
0246     __cvmx_interrupt_pcsx_intx_en_reg_enable(3, interface);
0247     __cvmx_interrupt_pcsxx_int_en_reg_enable(interface);
0248     __cvmx_interrupt_gmxx_enable(interface);
0249 
0250     return 0;
0251 }
0252 
0253 /*
0254  * Return the link state of an IPD/PKO port as returned by
0255  * auto negotiation. The result of this function may not match
0256  * Octeon's link config if auto negotiation has changed since
0257  * the last call to cvmx_helper_link_set().
0258  *
0259  * @ipd_port: IPD/PKO port to query
0260  *
0261  * Returns Link state
0262  */
0263 union cvmx_helper_link_info __cvmx_helper_xaui_link_get(int ipd_port)
0264 {
0265     int interface = cvmx_helper_get_interface_num(ipd_port);
0266     union cvmx_gmxx_tx_xaui_ctl gmxx_tx_xaui_ctl;
0267     union cvmx_gmxx_rx_xaui_ctl gmxx_rx_xaui_ctl;
0268     union cvmx_pcsxx_status1_reg pcsxx_status1_reg;
0269     union cvmx_helper_link_info result;
0270 
0271     gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
0272     gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface));
0273     pcsxx_status1_reg.u64 =
0274         cvmx_read_csr(CVMX_PCSXX_STATUS1_REG(interface));
0275     result.u64 = 0;
0276 
0277     /* Only return a link if both RX and TX are happy */
0278     if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0) &&
0279         (pcsxx_status1_reg.s.rcv_lnk == 1)) {
0280         result.s.link_up = 1;
0281         result.s.full_duplex = 1;
0282         result.s.speed = 10000;
0283     } else {
0284         /* Disable GMX and PCSX interrupts. */
0285         cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), 0x0);
0286         cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0);
0287         cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0);
0288     }
0289     return result;
0290 }
0291 
0292 /*
0293  * Configure an IPD/PKO port for the specified link state. This
0294  * function does not influence auto negotiation at the PHY level.
0295  * The passed link state must always match the link state returned
0296  * by cvmx_helper_link_get().
0297  *
0298  * @ipd_port:  IPD/PKO port to configure
0299  * @link_info: The new link state
0300  *
0301  * Returns Zero on success, negative on failure
0302  */
0303 int __cvmx_helper_xaui_link_set(int ipd_port, union cvmx_helper_link_info link_info)
0304 {
0305     int interface = cvmx_helper_get_interface_num(ipd_port);
0306     union cvmx_gmxx_tx_xaui_ctl gmxx_tx_xaui_ctl;
0307     union cvmx_gmxx_rx_xaui_ctl gmxx_rx_xaui_ctl;
0308 
0309     gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
0310     gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface));
0311 
0312     /* If the link shouldn't be up, then just return */
0313     if (!link_info.s.link_up)
0314         return 0;
0315 
0316     /* Do nothing if both RX and TX are happy */
0317     if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0))
0318         return 0;
0319 
0320     /* Bring the link up */
0321     return __cvmx_helper_xaui_enable(interface);
0322 }