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