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

Cache object: d32a44ac1403be4c33f3c21b5193aad7


[ 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.