The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/mips/cavium/octe/ethernet-rgmii.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*************************************************************************
    2 SPDX-License-Identifier: BSD-3-Clause
    3 
    4 Copyright (c) 2003-2007  Cavium Networks (support@cavium.com). All rights
    5 reserved.
    6 
    7 Redistribution and use in source and binary forms, with or without
    8 modification, are permitted provided that the following conditions are
    9 met:
   10 
   11     * Redistributions of source code must retain the above copyright
   12       notice, this list of conditions and the following disclaimer.
   13 
   14     * Redistributions in binary form must reproduce the above
   15       copyright notice, this list of conditions and the following
   16       disclaimer in the documentation and/or other materials provided
   17       with the distribution.
   18 
   19     * Neither the name of Cavium Networks nor the names of
   20       its contributors may be used to endorse or promote products
   21       derived from this software without specific prior written
   22       permission.
   23 
   24 This Software, including technical data, may be subject to U.S. export  control laws, including the U.S. Export Administration Act and its  associated regulations, and may be subject to export or import  regulations in other countries.
   25 
   26 TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
   27 AND WITH ALL FAULTS AND CAVIUM  NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
   28 
   29 *************************************************************************/
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/bus.h>
   37 #include <sys/endian.h>
   38 #include <sys/kernel.h>
   39 #include <sys/mbuf.h>
   40 #include <sys/rman.h>
   41 #include <sys/socket.h>
   42 #include <sys/lock.h>
   43 #include <sys/mutex.h>
   44 
   45 #include <net/ethernet.h>
   46 #include <net/if.h>
   47 #include <net/if_var.h>
   48 
   49 #include "wrapper-cvmx-includes.h"
   50 #include "ethernet-headers.h"
   51 
   52 #include "octebusvar.h"
   53 
   54 extern struct ifnet *cvm_oct_device[];
   55 
   56 static struct mtx global_register_lock;
   57 MTX_SYSINIT(global_register_lock, &global_register_lock,
   58             "RGMII Global", MTX_SPIN);
   59 
   60 static int number_rgmii_ports;
   61 
   62 static void cvm_oct_rgmii_poll(struct ifnet *ifp)
   63 {
   64         cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
   65         cvmx_helper_link_info_t link_info;
   66 
   67         /* Take the global register lock since we are going to touch
   68            registers that affect more than one port */
   69         mtx_lock_spin(&global_register_lock);
   70 
   71         link_info = cvmx_helper_link_get(priv->port);
   72         if (link_info.u64 == priv->link_info) {
   73                 /* If the 10Mbps preamble workaround is supported and we're
   74                    at 10Mbps we may need to do some special checking */
   75                 if (USE_10MBPS_PREAMBLE_WORKAROUND && (link_info.s.speed == 10)) {
   76                         /* Read the GMXX_RXX_INT_REG[PCTERR] bit and
   77                            see if we are getting preamble errors */
   78                         int interface = INTERFACE(priv->port);
   79                         int index = INDEX(priv->port);
   80                         cvmx_gmxx_rxx_int_reg_t gmxx_rxx_int_reg;
   81                         gmxx_rxx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index, interface));
   82                         if (gmxx_rxx_int_reg.s.pcterr) {
   83                                 /* We are getting preamble errors at 10Mbps.
   84                                    Most likely the PHY is giving us packets
   85                                    with mis aligned preambles. In order to get
   86                                    these packets we need to disable preamble
   87                                    checking and do it in software */
   88                                 cvmx_gmxx_rxx_frm_ctl_t gmxx_rxx_frm_ctl;
   89                                 cvmx_ipd_sub_port_fcs_t ipd_sub_port_fcs;
   90 
   91                                 /* Disable preamble checking */
   92                                 gmxx_rxx_frm_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface));
   93                                 gmxx_rxx_frm_ctl.s.pre_chk = 0;
   94                                 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface), gmxx_rxx_frm_ctl.u64);
   95 
   96                                 /* Disable FCS stripping */
   97                                 ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
   98                                 ipd_sub_port_fcs.s.port_bit &= 0xffffffffull ^ (1ull<<priv->port);
   99                                 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
  100 
  101                                 /* Clear any error bits */
  102                                 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface), gmxx_rxx_int_reg.u64);
  103                                 DEBUGPRINT("%s: Using 10Mbps with software preamble removal\n", if_name(ifp));
  104                         }
  105                 }
  106                 mtx_unlock_spin(&global_register_lock);
  107                 return;
  108         }
  109 
  110         /* If the 10Mbps preamble workaround is allowed we need to on
  111            preamble checking, FCS stripping, and clear error bits on
  112            every speed change. If errors occur during 10Mbps operation
  113            the above code will change this stuff */
  114         if (USE_10MBPS_PREAMBLE_WORKAROUND) {
  115                 cvmx_gmxx_rxx_frm_ctl_t gmxx_rxx_frm_ctl;
  116                 cvmx_ipd_sub_port_fcs_t ipd_sub_port_fcs;
  117                 cvmx_gmxx_rxx_int_reg_t gmxx_rxx_int_reg;
  118                 int interface = INTERFACE(priv->port);
  119                 int index = INDEX(priv->port);
  120 
  121                 /* Enable preamble checking */
  122                 gmxx_rxx_frm_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface));
  123                 gmxx_rxx_frm_ctl.s.pre_chk = 1;
  124                 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface), gmxx_rxx_frm_ctl.u64);
  125                 /* Enable FCS stripping */
  126                 ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
  127                 ipd_sub_port_fcs.s.port_bit |= 1ull<<priv->port;
  128                 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
  129                 /* Clear any error bits */
  130                 gmxx_rxx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index, interface));
  131                 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface), gmxx_rxx_int_reg.u64);
  132         }
  133 
  134         if (priv->miibus == NULL) {
  135                 link_info = cvmx_helper_link_autoconf(priv->port);
  136                 priv->link_info = link_info.u64;
  137                 priv->need_link_update = 1;
  138         }
  139         mtx_unlock_spin(&global_register_lock);
  140 }
  141 
  142 static int cvm_oct_rgmii_rml_interrupt(void *dev_id)
  143 {
  144         cvmx_npi_rsl_int_blocks_t rsl_int_blocks;
  145         int index;
  146         int return_status = FILTER_STRAY;
  147 
  148         rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
  149 
  150         /* Check and see if this interrupt was caused by the GMX0 block */
  151         if (rsl_int_blocks.s.gmx0) {
  152                 int interface = 0;
  153                 /* Loop through every port of this interface */
  154                 for (index = 0; index < cvmx_helper_ports_on_interface(interface); index++) {
  155                         /* Read the GMX interrupt status bits */
  156                         cvmx_gmxx_rxx_int_reg_t gmx_rx_int_reg;
  157                         gmx_rx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index, interface));
  158                         gmx_rx_int_reg.u64 &= cvmx_read_csr(CVMX_GMXX_RXX_INT_EN(index, interface));
  159                         /* Poll the port if inband status changed */
  160                         if (gmx_rx_int_reg.s.phy_dupx || gmx_rx_int_reg.s.phy_link || gmx_rx_int_reg.s.phy_spd) {
  161                                 struct ifnet *ifp = cvm_oct_device[cvmx_helper_get_ipd_port(interface, index)];
  162                                 if (ifp)
  163                                         cvm_oct_rgmii_poll(ifp);
  164                                 gmx_rx_int_reg.u64 = 0;
  165                                 gmx_rx_int_reg.s.phy_dupx = 1;
  166                                 gmx_rx_int_reg.s.phy_link = 1;
  167                                 gmx_rx_int_reg.s.phy_spd = 1;
  168                                 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface), gmx_rx_int_reg.u64);
  169                                 return_status = FILTER_HANDLED;
  170                         }
  171                 }
  172         }
  173 
  174         /* Check and see if this interrupt was caused by the GMX1 block */
  175         if (rsl_int_blocks.s.gmx1) {
  176                 int interface = 1;
  177                 /* Loop through every port of this interface */
  178                 for (index = 0; index < cvmx_helper_ports_on_interface(interface); index++) {
  179                         /* Read the GMX interrupt status bits */
  180                         cvmx_gmxx_rxx_int_reg_t gmx_rx_int_reg;
  181                         gmx_rx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index, interface));
  182                         gmx_rx_int_reg.u64 &= cvmx_read_csr(CVMX_GMXX_RXX_INT_EN(index, interface));
  183                         /* Poll the port if inband status changed */
  184                         if (gmx_rx_int_reg.s.phy_dupx || gmx_rx_int_reg.s.phy_link || gmx_rx_int_reg.s.phy_spd) {
  185                                 struct ifnet *ifp = cvm_oct_device[cvmx_helper_get_ipd_port(interface, index)];
  186                                 if (ifp)
  187                                         cvm_oct_rgmii_poll(ifp);
  188                                 gmx_rx_int_reg.u64 = 0;
  189                                 gmx_rx_int_reg.s.phy_dupx = 1;
  190                                 gmx_rx_int_reg.s.phy_link = 1;
  191                                 gmx_rx_int_reg.s.phy_spd = 1;
  192                                 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface), gmx_rx_int_reg.u64);
  193                                 return_status = FILTER_HANDLED;
  194                         }
  195                 }
  196         }
  197         return return_status;
  198 }
  199 
  200 int cvm_oct_rgmii_init(struct ifnet *ifp)
  201 {
  202         struct octebus_softc *sc;
  203         cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
  204         int error;
  205         int rid;
  206 
  207         if (cvm_oct_common_init(ifp) != 0)
  208             return ENXIO;
  209 
  210         priv->open = cvm_oct_common_open;
  211         priv->stop = cvm_oct_common_stop;
  212         priv->stop(ifp);
  213 
  214         /* Due to GMX errata in CN3XXX series chips, it is necessary to take the
  215            link down immediately whne the PHY changes state. In order to do this
  216            we call the poll function every time the RGMII inband status changes.
  217            This may cause problems if the PHY doesn't implement inband status
  218            properly */
  219         if (number_rgmii_ports == 0) {
  220                 sc = device_get_softc(device_get_parent(priv->dev));
  221 
  222                 rid = 0;
  223                 sc->sc_rgmii_irq = bus_alloc_resource(sc->sc_dev, SYS_RES_IRQ,
  224                                                       &rid, OCTEON_IRQ_RML,
  225                                                       OCTEON_IRQ_RML, 1,
  226                                                       RF_ACTIVE);
  227                 if (sc->sc_rgmii_irq == NULL) {
  228                         device_printf(sc->sc_dev, "could not allocate RGMII irq");
  229                         return ENXIO;
  230                 }
  231 
  232                 error = bus_setup_intr(sc->sc_dev, sc->sc_rgmii_irq,
  233                                        INTR_TYPE_NET | INTR_MPSAFE,
  234                                        cvm_oct_rgmii_rml_interrupt, NULL,
  235                                        &number_rgmii_ports, NULL);
  236                 if (error != 0) {
  237                         device_printf(sc->sc_dev, "could not setup RGMII irq");
  238                         return error;
  239                 }
  240         }
  241         number_rgmii_ports++;
  242 
  243         /* Only true RGMII ports need to be polled. In GMII mode, port 0 is really
  244            a RGMII port */
  245         if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII) && (priv->port == 0)) ||
  246             (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
  247                 if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) {
  248                         cvmx_gmxx_rxx_int_en_t gmx_rx_int_en;
  249                         int interface = INTERFACE(priv->port);
  250                         int index = INDEX(priv->port);
  251 
  252                         /* Enable interrupts on inband status changes for this port */
  253                         gmx_rx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_EN(index, interface));
  254                         gmx_rx_int_en.s.phy_dupx = 1;
  255                         gmx_rx_int_en.s.phy_link = 1;
  256                         gmx_rx_int_en.s.phy_spd = 1;
  257                         cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface), gmx_rx_int_en.u64);
  258                         priv->poll = cvm_oct_rgmii_poll;
  259                 }
  260         }
  261 
  262         return 0;
  263 }
  264 
  265 void cvm_oct_rgmii_uninit(struct ifnet *ifp)
  266 {
  267         cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
  268         cvm_oct_common_uninit(ifp);
  269 
  270         /* Only true RGMII ports need to be polled. In GMII mode, port 0 is really
  271            a RGMII port */
  272         if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII) && (priv->port == 0)) ||
  273             (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
  274                 if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) {
  275                         cvmx_gmxx_rxx_int_en_t gmx_rx_int_en;
  276                         int interface = INTERFACE(priv->port);
  277                         int index = INDEX(priv->port);
  278 
  279                         /* Disable interrupts on inband status changes for this port */
  280                         gmx_rx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_EN(index, interface));
  281                         gmx_rx_int_en.s.phy_dupx = 0;
  282                         gmx_rx_int_en.s.phy_link = 0;
  283                         gmx_rx_int_en.s.phy_spd = 0;
  284                         cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface), gmx_rx_int_en.u64);
  285                 }
  286         }
  287 
  288         /* Remove the interrupt handler when the last port is removed */
  289         number_rgmii_ports--;
  290         if (number_rgmii_ports == 0)
  291                 panic("%s: need to implement IRQ release.", __func__);
  292 }

Cache object: 35283e3e82a9092764f177e0bf18823b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.