1/********************************************************************* 2 * Author: Cavium Networks 3 * 4 * Contact: support@caviumnetworks.com 5 * This file is part of the OCTEON SDK 6 * 7 * Copyright (c) 2003-2007 Cavium Networks 8 * 9 * This file is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License, Version 2, as 11 * published by the Free Software Foundation. 12 * 13 * This file is distributed in the hope that it will be useful, but 14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty 15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or 16 * NONINFRINGEMENT. See the GNU General Public License for more 17 * details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this file; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 * or visit http://www.gnu.org/licenses/. 23 * 24 * This file may also be available under a different license from Cavium. 25 * Contact Cavium Networks for more information 26**********************************************************************/ 27#include <linux/kernel.h> 28#include <linux/netdevice.h> 29#include <linux/phy.h> 30#include <net/dst.h> 31 32#include <asm/octeon/octeon.h> 33 34#include "ethernet-defines.h" 35#include "octeon-ethernet.h" 36#include "ethernet-util.h" 37 38#include "cvmx-helper.h" 39 40#include <asm/octeon/cvmx-ipd-defs.h> 41#include <asm/octeon/cvmx-npi-defs.h> 42#include "cvmx-gmxx-defs.h" 43 44DEFINE_SPINLOCK(global_register_lock); 45 46static int number_rgmii_ports; 47 48static void cvm_oct_rgmii_poll(struct net_device *dev) 49{ 50 struct octeon_ethernet *priv = netdev_priv(dev); 51 unsigned long flags = 0; 52 cvmx_helper_link_info_t link_info; 53 int use_global_register_lock = (priv->phydev == NULL); 54 55 BUG_ON(in_interrupt()); 56 if (use_global_register_lock) { 57 /* 58 * Take the global register lock since we are going to 59 * touch registers that affect more than one port. 60 */ 61 spin_lock_irqsave(&global_register_lock, flags); 62 } else { 63 mutex_lock(&priv->phydev->bus->mdio_lock); 64 } 65 66 link_info = cvmx_helper_link_get(priv->port); 67 if (link_info.u64 == priv->link_info) { 68 69 if (USE_10MBPS_PREAMBLE_WORKAROUND && (link_info.s.speed == 10)) { 70 71 /* 72 * Read the GMXX_RXX_INT_REG[PCTERR] bit and 73 * see if we are getting preamble errors. 74 */ 75 int interface = INTERFACE(priv->port); 76 int index = INDEX(priv->port); 77 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg; 78 gmxx_rxx_int_reg.u64 = 79 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG 80 (index, interface)); 81 if (gmxx_rxx_int_reg.s.pcterr) { 82 83 /* 84 * We are getting preamble errors at 85 * 10Mbps. Most likely the PHY is 86 * giving us packets with mis aligned 87 * preambles. In order to get these 88 * packets we need to disable preamble 89 * checking and do it in software. 90 */ 91 union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl; 92 union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs; 93 94 /* Disable preamble checking */ 95 gmxx_rxx_frm_ctl.u64 = 96 cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL 97 (index, interface)); 98 gmxx_rxx_frm_ctl.s.pre_chk = 0; 99 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL 100 (index, interface), 101 gmxx_rxx_frm_ctl.u64); 102 103 /* Disable FCS stripping */ 104 ipd_sub_port_fcs.u64 = 105 cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS); 106 ipd_sub_port_fcs.s.port_bit &= 107 0xffffffffull ^ (1ull << priv->port); 108 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, 109 ipd_sub_port_fcs.u64); 110 111 /* Clear any error bits */ 112 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG 113 (index, interface), 114 gmxx_rxx_int_reg.u64); 115 DEBUGPRINT("%s: Using 10Mbps with software " 116 "preamble removal\n", 117 dev->name); 118 } 119 } 120 121 if (use_global_register_lock) 122 spin_unlock_irqrestore(&global_register_lock, flags); 123 else 124 mutex_unlock(&priv->phydev->bus->mdio_lock); 125 return; 126 } 127 128 if (USE_10MBPS_PREAMBLE_WORKAROUND) { 129 130 union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl; 131 union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs; 132 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg; 133 int interface = INTERFACE(priv->port); 134 int index = INDEX(priv->port); 135 136 /* Enable preamble checking */ 137 gmxx_rxx_frm_ctl.u64 = 138 cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface)); 139 gmxx_rxx_frm_ctl.s.pre_chk = 1; 140 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface), 141 gmxx_rxx_frm_ctl.u64); 142 /* Enable FCS stripping */ 143 ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS); 144 ipd_sub_port_fcs.s.port_bit |= 1ull << priv->port; 145 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64); 146 /* Clear any error bits */ 147 gmxx_rxx_int_reg.u64 = 148 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index, interface)); 149 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface), 150 gmxx_rxx_int_reg.u64); 151 } 152 if (priv->phydev == NULL) { 153 link_info = cvmx_helper_link_autoconf(priv->port); 154 priv->link_info = link_info.u64; 155 } 156 157 if (use_global_register_lock) 158 spin_unlock_irqrestore(&global_register_lock, flags); 159 else { 160 mutex_unlock(&priv->phydev->bus->mdio_lock); 161 } 162 163 if (priv->phydev == NULL) { 164 /* Tell core. */ 165 if (link_info.s.link_up) { 166 if (!netif_carrier_ok(dev)) 167 netif_carrier_on(dev); 168 if (priv->queue != -1) 169 DEBUGPRINT("%s: %u Mbps %s duplex, " 170 "port %2d, queue %2d\n", 171 dev->name, link_info.s.speed, 172 (link_info.s.full_duplex) ? 173 "Full" : "Half", 174 priv->port, priv->queue); 175 else 176 DEBUGPRINT("%s: %u Mbps %s duplex, " 177 "port %2d, POW\n", 178 dev->name, link_info.s.speed, 179 (link_info.s.full_duplex) ? 180 "Full" : "Half", 181 priv->port); 182 } else { 183 if (netif_carrier_ok(dev)) 184 netif_carrier_off(dev); 185 DEBUGPRINT("%s: Link down\n", dev->name); 186 } 187 } 188} 189 190static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id) 191{ 192 union cvmx_npi_rsl_int_blocks rsl_int_blocks; 193 int index; 194 irqreturn_t return_status = IRQ_NONE; 195 196 rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS); 197 198 /* Check and see if this interrupt was caused by the GMX0 block */ 199 if (rsl_int_blocks.s.gmx0) { 200 201 int interface = 0; 202 /* Loop through every port of this interface */ 203 for (index = 0; 204 index < cvmx_helper_ports_on_interface(interface); 205 index++) { 206 207 /* Read the GMX interrupt status bits */ 208 union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg; 209 gmx_rx_int_reg.u64 = 210 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG 211 (index, interface)); 212 gmx_rx_int_reg.u64 &= 213 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN 214 (index, interface)); 215 /* Poll the port if inband status changed */ 216 if (gmx_rx_int_reg.s.phy_dupx 217 || gmx_rx_int_reg.s.phy_link 218 || gmx_rx_int_reg.s.phy_spd) { 219 220 struct net_device *dev = 221 cvm_oct_device[cvmx_helper_get_ipd_port 222 (interface, index)]; 223 struct octeon_ethernet *priv = netdev_priv(dev); 224 225 if (dev && !atomic_read(&cvm_oct_poll_queue_stopping)) 226 queue_work(cvm_oct_poll_queue, &priv->port_work); 227 228 gmx_rx_int_reg.u64 = 0; 229 gmx_rx_int_reg.s.phy_dupx = 1; 230 gmx_rx_int_reg.s.phy_link = 1; 231 gmx_rx_int_reg.s.phy_spd = 1; 232 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG 233 (index, interface), 234 gmx_rx_int_reg.u64); 235 return_status = IRQ_HANDLED; 236 } 237 } 238 } 239 240 /* Check and see if this interrupt was caused by the GMX1 block */ 241 if (rsl_int_blocks.s.gmx1) { 242 243 int interface = 1; 244 /* Loop through every port of this interface */ 245 for (index = 0; 246 index < cvmx_helper_ports_on_interface(interface); 247 index++) { 248 249 /* Read the GMX interrupt status bits */ 250 union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg; 251 gmx_rx_int_reg.u64 = 252 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG 253 (index, interface)); 254 gmx_rx_int_reg.u64 &= 255 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN 256 (index, interface)); 257 /* Poll the port if inband status changed */ 258 if (gmx_rx_int_reg.s.phy_dupx 259 || gmx_rx_int_reg.s.phy_link 260 || gmx_rx_int_reg.s.phy_spd) { 261 262 struct net_device *dev = 263 cvm_oct_device[cvmx_helper_get_ipd_port 264 (interface, index)]; 265 struct octeon_ethernet *priv = netdev_priv(dev); 266 267 if (dev && !atomic_read(&cvm_oct_poll_queue_stopping)) 268 queue_work(cvm_oct_poll_queue, &priv->port_work); 269 270 gmx_rx_int_reg.u64 = 0; 271 gmx_rx_int_reg.s.phy_dupx = 1; 272 gmx_rx_int_reg.s.phy_link = 1; 273 gmx_rx_int_reg.s.phy_spd = 1; 274 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG 275 (index, interface), 276 gmx_rx_int_reg.u64); 277 return_status = IRQ_HANDLED; 278 } 279 } 280 } 281 return return_status; 282} 283 284int cvm_oct_rgmii_open(struct net_device *dev) 285{ 286 union cvmx_gmxx_prtx_cfg gmx_cfg; 287 struct octeon_ethernet *priv = netdev_priv(dev); 288 int interface = INTERFACE(priv->port); 289 int index = INDEX(priv->port); 290 cvmx_helper_link_info_t link_info; 291 292 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 293 gmx_cfg.s.en = 1; 294 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 295 296 if (!octeon_is_simulation()) { 297 link_info = cvmx_helper_link_get(priv->port); 298 if (!link_info.s.link_up) 299 netif_carrier_off(dev); 300 } 301 302 return 0; 303} 304 305int cvm_oct_rgmii_stop(struct net_device *dev) 306{ 307 union cvmx_gmxx_prtx_cfg gmx_cfg; 308 struct octeon_ethernet *priv = netdev_priv(dev); 309 int interface = INTERFACE(priv->port); 310 int index = INDEX(priv->port); 311 312 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 313 gmx_cfg.s.en = 0; 314 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 315 return 0; 316} 317 318static void cvm_oct_rgmii_immediate_poll(struct work_struct *work) 319{ 320 struct octeon_ethernet *priv = container_of(work, struct octeon_ethernet, port_work); 321 cvm_oct_rgmii_poll(cvm_oct_device[priv->port]); 322} 323 324int cvm_oct_rgmii_init(struct net_device *dev) 325{ 326 struct octeon_ethernet *priv = netdev_priv(dev); 327 int r; 328 329 cvm_oct_common_init(dev); 330 dev->netdev_ops->ndo_stop(dev); 331 INIT_WORK(&priv->port_work, cvm_oct_rgmii_immediate_poll); 332 /* 333 * Due to GMX errata in CN3XXX series chips, it is necessary 334 * to take the link down immediately when the PHY changes 335 * state. In order to do this we call the poll function every 336 * time the RGMII inband status changes. This may cause 337 * problems if the PHY doesn't implement inband status 338 * properly. 339 */ 340 if (number_rgmii_ports == 0) { 341 r = request_irq(OCTEON_IRQ_RML, cvm_oct_rgmii_rml_interrupt, 342 IRQF_SHARED, "RGMII", &number_rgmii_ports); 343 if (r != 0) 344 return r; 345 } 346 number_rgmii_ports++; 347 348 /* 349 * Only true RGMII ports need to be polled. In GMII mode, port 350 * 0 is really a RGMII port. 351 */ 352 if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII) 353 && (priv->port == 0)) 354 || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) { 355 356 if (!octeon_is_simulation()) { 357 358 union cvmx_gmxx_rxx_int_en gmx_rx_int_en; 359 int interface = INTERFACE(priv->port); 360 int index = INDEX(priv->port); 361 362 /* 363 * Enable interrupts on inband status changes 364 * for this port. 365 */ 366 gmx_rx_int_en.u64 = 367 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN 368 (index, interface)); 369 gmx_rx_int_en.s.phy_dupx = 1; 370 gmx_rx_int_en.s.phy_link = 1; 371 gmx_rx_int_en.s.phy_spd = 1; 372 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface), 373 gmx_rx_int_en.u64); 374 priv->poll = cvm_oct_rgmii_poll; 375 } 376 } 377 378 return 0; 379} 380 381void cvm_oct_rgmii_uninit(struct net_device *dev) 382{ 383 struct octeon_ethernet *priv = netdev_priv(dev); 384 cvm_oct_common_uninit(dev); 385 386 /* 387 * Only true RGMII ports need to be polled. In GMII mode, port 388 * 0 is really a RGMII port. 389 */ 390 if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII) 391 && (priv->port == 0)) 392 || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) { 393 394 if (!octeon_is_simulation()) { 395 396 union cvmx_gmxx_rxx_int_en gmx_rx_int_en; 397 int interface = INTERFACE(priv->port); 398 int index = INDEX(priv->port); 399 400 /* 401 * Disable interrupts on inband status changes 402 * for this port. 403 */ 404 gmx_rx_int_en.u64 = 405 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN 406 (index, interface)); 407 gmx_rx_int_en.s.phy_dupx = 0; 408 gmx_rx_int_en.s.phy_link = 0; 409 gmx_rx_int_en.s.phy_spd = 0; 410 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface), 411 gmx_rx_int_en.u64); 412 } 413 } 414 415 /* Remove the interrupt handler when the last port is removed. */ 416 number_rgmii_ports--; 417 if (number_rgmii_ports == 0) 418 free_irq(OCTEON_IRQ_RML, &number_rgmii_ports); 419 cancel_work_sync(&priv->port_work); 420} 421