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

Cache object: 788748867de14e32cae7208822cfd794


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