1 /*********************************************************************
2 * Author: Cavium Networks
4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK
7 * Copyright (c) 2003-2007 Cavium Networks
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.
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
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/.
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/mii.h>
32 #include <asm/octeon/octeon.h>
34 #include "ethernet-defines.h"
35 #include "octeon-ethernet.h"
36 #include "ethernet-common.h"
37 #include "ethernet-util.h"
39 #include "cvmx-helper.h"
41 #include <asm/octeon/cvmx-ipd-defs.h>
42 #include <asm/octeon/cvmx-npi-defs.h>
43 #include "cvmx-gmxx-defs.h"
45 DEFINE_SPINLOCK(global_register_lock);
47 static int number_rgmii_ports;
49 static void cvm_oct_rgmii_poll(struct net_device *dev)
51 struct octeon_ethernet *priv = netdev_priv(dev);
53 cvmx_helper_link_info_t link_info;
56 * Take the global register lock since we are going to touch
57 * registers that affect more than one port.
59 spin_lock_irqsave(&global_register_lock, flags);
61 link_info = cvmx_helper_link_get(priv->port);
62 if (link_info.u64 == priv->link_info) {
65 * If the 10Mbps preamble workaround is supported and we're
66 * at 10Mbps we may need to do some special checking.
68 if (USE_10MBPS_PREAMBLE_WORKAROUND && (link_info.s.speed == 10)) {
71 * Read the GMXX_RXX_INT_REG[PCTERR] bit and
72 * see if we are getting preamble errors.
74 int interface = INTERFACE(priv->port);
75 int index = INDEX(priv->port);
76 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
77 gmxx_rxx_int_reg.u64 =
78 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
80 if (gmxx_rxx_int_reg.s.pcterr) {
83 * We are getting preamble errors at
84 * 10Mbps. Most likely the PHY is
85 * giving us packets with mis aligned
86 * preambles. In order to get these
87 * packets we need to disable preamble
88 * checking and do it in software.
90 union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
91 union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
93 /* Disable preamble checking */
94 gmxx_rxx_frm_ctl.u64 =
95 cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL
97 gmxx_rxx_frm_ctl.s.pre_chk = 0;
98 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL
100 gmxx_rxx_frm_ctl.u64);
102 /* Disable FCS stripping */
103 ipd_sub_port_fcs.u64 =
104 cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
105 ipd_sub_port_fcs.s.port_bit &=
106 0xffffffffull ^ (1ull << priv->port);
107 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS,
108 ipd_sub_port_fcs.u64);
110 /* Clear any error bits */
111 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
113 gmxx_rxx_int_reg.u64);
114 DEBUGPRINT("%s: Using 10Mbps with software "
115 "preamble removal\n",
119 spin_unlock_irqrestore(&global_register_lock, flags);
123 /* If the 10Mbps preamble workaround is allowed we need to on
124 preamble checking, FCS stripping, and clear error bits on
125 every speed change. If errors occur during 10Mbps operation
126 the above code will change this stuff */
127 if (USE_10MBPS_PREAMBLE_WORKAROUND) {
129 union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
130 union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
131 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
132 int interface = INTERFACE(priv->port);
133 int index = INDEX(priv->port);
135 /* Enable preamble checking */
136 gmxx_rxx_frm_ctl.u64 =
137 cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface));
138 gmxx_rxx_frm_ctl.s.pre_chk = 1;
139 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface),
140 gmxx_rxx_frm_ctl.u64);
141 /* Enable FCS stripping */
142 ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
143 ipd_sub_port_fcs.s.port_bit |= 1ull << priv->port;
144 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
145 /* Clear any error bits */
146 gmxx_rxx_int_reg.u64 =
147 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index, interface));
148 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
149 gmxx_rxx_int_reg.u64);
152 link_info = cvmx_helper_link_autoconf(priv->port);
153 priv->link_info = link_info.u64;
154 spin_unlock_irqrestore(&global_register_lock, flags);
157 if (link_info.s.link_up) {
159 if (!netif_carrier_ok(dev))
160 netif_carrier_on(dev);
161 if (priv->queue != -1)
163 ("%s: %u Mbps %s duplex, port %2d, queue %2d\n",
164 dev->name, link_info.s.speed,
165 (link_info.s.full_duplex) ? "Full" : "Half",
166 priv->port, priv->queue);
168 DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, POW\n",
169 dev->name, link_info.s.speed,
170 (link_info.s.full_duplex) ? "Full" : "Half",
174 if (netif_carrier_ok(dev))
175 netif_carrier_off(dev);
176 DEBUGPRINT("%s: Link down\n", dev->name);
180 static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id)
182 union cvmx_npi_rsl_int_blocks rsl_int_blocks;
184 irqreturn_t return_status = IRQ_NONE;
186 rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
188 /* Check and see if this interrupt was caused by the GMX0 block */
189 if (rsl_int_blocks.s.gmx0) {
192 /* Loop through every port of this interface */
194 index < cvmx_helper_ports_on_interface(interface);
197 /* Read the GMX interrupt status bits */
198 union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
200 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
202 gmx_rx_int_reg.u64 &=
203 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
205 /* Poll the port if inband status changed */
206 if (gmx_rx_int_reg.s.phy_dupx
207 || gmx_rx_int_reg.s.phy_link
208 || gmx_rx_int_reg.s.phy_spd) {
210 struct net_device *dev =
211 cvm_oct_device[cvmx_helper_get_ipd_port
214 cvm_oct_rgmii_poll(dev);
215 gmx_rx_int_reg.u64 = 0;
216 gmx_rx_int_reg.s.phy_dupx = 1;
217 gmx_rx_int_reg.s.phy_link = 1;
218 gmx_rx_int_reg.s.phy_spd = 1;
219 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
222 return_status = IRQ_HANDLED;
227 /* Check and see if this interrupt was caused by the GMX1 block */
228 if (rsl_int_blocks.s.gmx1) {
231 /* Loop through every port of this interface */
233 index < cvmx_helper_ports_on_interface(interface);
236 /* Read the GMX interrupt status bits */
237 union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
239 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
241 gmx_rx_int_reg.u64 &=
242 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
244 /* Poll the port if inband status changed */
245 if (gmx_rx_int_reg.s.phy_dupx
246 || gmx_rx_int_reg.s.phy_link
247 || gmx_rx_int_reg.s.phy_spd) {
249 struct net_device *dev =
250 cvm_oct_device[cvmx_helper_get_ipd_port
253 cvm_oct_rgmii_poll(dev);
254 gmx_rx_int_reg.u64 = 0;
255 gmx_rx_int_reg.s.phy_dupx = 1;
256 gmx_rx_int_reg.s.phy_link = 1;
257 gmx_rx_int_reg.s.phy_spd = 1;
258 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
261 return_status = IRQ_HANDLED;
265 return return_status;
268 static int cvm_oct_rgmii_open(struct net_device *dev)
270 union cvmx_gmxx_prtx_cfg gmx_cfg;
271 struct octeon_ethernet *priv = netdev_priv(dev);
272 int interface = INTERFACE(priv->port);
273 int index = INDEX(priv->port);
274 cvmx_helper_link_info_t link_info;
276 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
278 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
280 if (!octeon_is_simulation()) {
281 link_info = cvmx_helper_link_get(priv->port);
282 if (!link_info.s.link_up)
283 netif_carrier_off(dev);
289 static int cvm_oct_rgmii_stop(struct net_device *dev)
291 union cvmx_gmxx_prtx_cfg gmx_cfg;
292 struct octeon_ethernet *priv = netdev_priv(dev);
293 int interface = INTERFACE(priv->port);
294 int index = INDEX(priv->port);
296 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
298 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
302 int cvm_oct_rgmii_init(struct net_device *dev)
304 struct octeon_ethernet *priv = netdev_priv(dev);
307 cvm_oct_common_init(dev);
308 dev->open = cvm_oct_rgmii_open;
309 dev->stop = cvm_oct_rgmii_stop;
313 * Due to GMX errata in CN3XXX series chips, it is necessary
314 * to take the link down immediately whne the PHY changes
315 * state. In order to do this we call the poll function every
316 * time the RGMII inband status changes. This may cause
317 * problems if the PHY doesn't implement inband status
320 if (number_rgmii_ports == 0) {
321 r = request_irq(OCTEON_IRQ_RML, cvm_oct_rgmii_rml_interrupt,
322 IRQF_SHARED, "RGMII", &number_rgmii_ports);
324 number_rgmii_ports++;
327 * Only true RGMII ports need to be polled. In GMII mode, port
328 * 0 is really a RGMII port.
330 if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
331 && (priv->port == 0))
332 || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
334 if (!octeon_is_simulation()) {
336 union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
337 int interface = INTERFACE(priv->port);
338 int index = INDEX(priv->port);
341 * Enable interrupts on inband status changes
345 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
347 gmx_rx_int_en.s.phy_dupx = 1;
348 gmx_rx_int_en.s.phy_link = 1;
349 gmx_rx_int_en.s.phy_spd = 1;
350 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
352 priv->poll = cvm_oct_rgmii_poll;
359 void cvm_oct_rgmii_uninit(struct net_device *dev)
361 struct octeon_ethernet *priv = netdev_priv(dev);
362 cvm_oct_common_uninit(dev);
365 * Only true RGMII ports need to be polled. In GMII mode, port
366 * 0 is really a RGMII port.
368 if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
369 && (priv->port == 0))
370 || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
372 if (!octeon_is_simulation()) {
374 union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
375 int interface = INTERFACE(priv->port);
376 int index = INDEX(priv->port);
379 * Disable interrupts on inband status changes
383 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
385 gmx_rx_int_en.s.phy_dupx = 0;
386 gmx_rx_int_en.s.phy_link = 0;
387 gmx_rx_int_en.s.phy_spd = 0;
388 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
393 /* Remove the interrupt handler when the last port is removed. */
394 number_rgmii_ports--;
395 if (number_rgmii_ports == 0)
396 free_irq(OCTEON_IRQ_RML, &number_rgmii_ports);