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/phy.h>
32 #include <asm/octeon/octeon.h>
34 #include "ethernet-defines.h"
35 #include "octeon-ethernet.h"
36 #include "ethernet-util.h"
38 #include "cvmx-helper.h"
40 #include <asm/octeon/cvmx-ipd-defs.h>
41 #include <asm/octeon/cvmx-npi-defs.h>
42 #include "cvmx-gmxx-defs.h"
44 DEFINE_SPINLOCK(global_register_lock
);
46 static int number_rgmii_ports
;
48 static void cvm_oct_rgmii_poll(struct net_device
*dev
)
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
);
55 BUG_ON(in_interrupt());
56 if (use_global_register_lock
) {
58 * Take the global register lock since we are going to
59 * touch registers that affect more than one port.
61 spin_lock_irqsave(&global_register_lock
, flags
);
63 mutex_lock(&priv
->phydev
->bus
->mdio_lock
);
66 link_info
= cvmx_helper_link_get(priv
->port
);
67 if (link_info
.u64
== priv
->link_info
) {
70 * If the 10Mbps preamble workaround is supported and we're
71 * at 10Mbps we may need to do some special checking.
73 if (USE_10MBPS_PREAMBLE_WORKAROUND
&& (link_info
.s
.speed
== 10)) {
76 * Read the GMXX_RXX_INT_REG[PCTERR] bit and
77 * see if we are getting preamble errors.
79 int interface
= INTERFACE(priv
->port
);
80 int index
= INDEX(priv
->port
);
81 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg
;
82 gmxx_rxx_int_reg
.u64
=
83 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
85 if (gmxx_rxx_int_reg
.s
.pcterr
) {
88 * We are getting preamble errors at
89 * 10Mbps. Most likely the PHY is
90 * giving us packets with mis aligned
91 * preambles. In order to get these
92 * packets we need to disable preamble
93 * checking and do it in software.
95 union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl
;
96 union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs
;
98 /* Disable preamble checking */
99 gmxx_rxx_frm_ctl
.u64
=
100 cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL
102 gmxx_rxx_frm_ctl
.s
.pre_chk
= 0;
103 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL
105 gmxx_rxx_frm_ctl
.u64
);
107 /* Disable FCS stripping */
108 ipd_sub_port_fcs
.u64
=
109 cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS
);
110 ipd_sub_port_fcs
.s
.port_bit
&=
111 0xffffffffull
^ (1ull << priv
->port
);
112 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS
,
113 ipd_sub_port_fcs
.u64
);
115 /* Clear any error bits */
116 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
118 gmxx_rxx_int_reg
.u64
);
119 DEBUGPRINT("%s: Using 10Mbps with software "
120 "preamble removal\n",
125 if (use_global_register_lock
)
126 spin_unlock_irqrestore(&global_register_lock
, flags
);
128 mutex_unlock(&priv
->phydev
->bus
->mdio_lock
);
132 /* If the 10Mbps preamble workaround is allowed we need to on
133 preamble checking, FCS stripping, and clear error bits on
134 every speed change. If errors occur during 10Mbps operation
135 the above code will change this stuff */
136 if (USE_10MBPS_PREAMBLE_WORKAROUND
) {
138 union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl
;
139 union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs
;
140 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg
;
141 int interface
= INTERFACE(priv
->port
);
142 int index
= INDEX(priv
->port
);
144 /* Enable preamble checking */
145 gmxx_rxx_frm_ctl
.u64
=
146 cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index
, interface
));
147 gmxx_rxx_frm_ctl
.s
.pre_chk
= 1;
148 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index
, interface
),
149 gmxx_rxx_frm_ctl
.u64
);
150 /* Enable FCS stripping */
151 ipd_sub_port_fcs
.u64
= cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS
);
152 ipd_sub_port_fcs
.s
.port_bit
|= 1ull << priv
->port
;
153 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS
, ipd_sub_port_fcs
.u64
);
154 /* Clear any error bits */
155 gmxx_rxx_int_reg
.u64
=
156 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index
, interface
));
157 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index
, interface
),
158 gmxx_rxx_int_reg
.u64
);
160 if (priv
->phydev
== NULL
) {
161 link_info
= cvmx_helper_link_autoconf(priv
->port
);
162 priv
->link_info
= link_info
.u64
;
165 if (use_global_register_lock
)
166 spin_unlock_irqrestore(&global_register_lock
, flags
);
168 mutex_unlock(&priv
->phydev
->bus
->mdio_lock
);
171 if (priv
->phydev
== NULL
) {
173 if (link_info
.s
.link_up
) {
174 if (!netif_carrier_ok(dev
))
175 netif_carrier_on(dev
);
176 if (priv
->queue
!= -1)
177 DEBUGPRINT("%s: %u Mbps %s duplex, "
178 "port %2d, queue %2d\n",
179 dev
->name
, link_info
.s
.speed
,
180 (link_info
.s
.full_duplex
) ?
182 priv
->port
, priv
->queue
);
184 DEBUGPRINT("%s: %u Mbps %s duplex, "
186 dev
->name
, link_info
.s
.speed
,
187 (link_info
.s
.full_duplex
) ?
191 if (netif_carrier_ok(dev
))
192 netif_carrier_off(dev
);
193 DEBUGPRINT("%s: Link down\n", dev
->name
);
198 static irqreturn_t
cvm_oct_rgmii_rml_interrupt(int cpl
, void *dev_id
)
200 union cvmx_npi_rsl_int_blocks rsl_int_blocks
;
202 irqreturn_t return_status
= IRQ_NONE
;
204 rsl_int_blocks
.u64
= cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS
);
206 /* Check and see if this interrupt was caused by the GMX0 block */
207 if (rsl_int_blocks
.s
.gmx0
) {
210 /* Loop through every port of this interface */
212 index
< cvmx_helper_ports_on_interface(interface
);
215 /* Read the GMX interrupt status bits */
216 union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg
;
218 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
220 gmx_rx_int_reg
.u64
&=
221 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
223 /* Poll the port if inband status changed */
224 if (gmx_rx_int_reg
.s
.phy_dupx
225 || gmx_rx_int_reg
.s
.phy_link
226 || gmx_rx_int_reg
.s
.phy_spd
) {
228 struct net_device
*dev
=
229 cvm_oct_device
[cvmx_helper_get_ipd_port
231 struct octeon_ethernet
*priv
= netdev_priv(dev
);
233 if (dev
&& !atomic_read(&cvm_oct_poll_queue_stopping
))
234 queue_work(cvm_oct_poll_queue
, &priv
->port_work
);
236 gmx_rx_int_reg
.u64
= 0;
237 gmx_rx_int_reg
.s
.phy_dupx
= 1;
238 gmx_rx_int_reg
.s
.phy_link
= 1;
239 gmx_rx_int_reg
.s
.phy_spd
= 1;
240 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
243 return_status
= IRQ_HANDLED
;
248 /* Check and see if this interrupt was caused by the GMX1 block */
249 if (rsl_int_blocks
.s
.gmx1
) {
252 /* Loop through every port of this interface */
254 index
< cvmx_helper_ports_on_interface(interface
);
257 /* Read the GMX interrupt status bits */
258 union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg
;
260 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
262 gmx_rx_int_reg
.u64
&=
263 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
265 /* Poll the port if inband status changed */
266 if (gmx_rx_int_reg
.s
.phy_dupx
267 || gmx_rx_int_reg
.s
.phy_link
268 || gmx_rx_int_reg
.s
.phy_spd
) {
270 struct net_device
*dev
=
271 cvm_oct_device
[cvmx_helper_get_ipd_port
273 struct octeon_ethernet
*priv
= netdev_priv(dev
);
275 if (dev
&& !atomic_read(&cvm_oct_poll_queue_stopping
))
276 queue_work(cvm_oct_poll_queue
, &priv
->port_work
);
278 gmx_rx_int_reg
.u64
= 0;
279 gmx_rx_int_reg
.s
.phy_dupx
= 1;
280 gmx_rx_int_reg
.s
.phy_link
= 1;
281 gmx_rx_int_reg
.s
.phy_spd
= 1;
282 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
285 return_status
= IRQ_HANDLED
;
289 return return_status
;
292 int cvm_oct_rgmii_open(struct net_device
*dev
)
294 union cvmx_gmxx_prtx_cfg gmx_cfg
;
295 struct octeon_ethernet
*priv
= netdev_priv(dev
);
296 int interface
= INTERFACE(priv
->port
);
297 int index
= INDEX(priv
->port
);
298 cvmx_helper_link_info_t link_info
;
300 gmx_cfg
.u64
= cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index
, interface
));
302 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index
, interface
), gmx_cfg
.u64
);
304 if (!octeon_is_simulation()) {
305 link_info
= cvmx_helper_link_get(priv
->port
);
306 if (!link_info
.s
.link_up
)
307 netif_carrier_off(dev
);
313 int cvm_oct_rgmii_stop(struct net_device
*dev
)
315 union cvmx_gmxx_prtx_cfg gmx_cfg
;
316 struct octeon_ethernet
*priv
= netdev_priv(dev
);
317 int interface
= INTERFACE(priv
->port
);
318 int index
= INDEX(priv
->port
);
320 gmx_cfg
.u64
= cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index
, interface
));
322 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index
, interface
), gmx_cfg
.u64
);
326 static void cvm_oct_rgmii_immediate_poll(struct work_struct
*work
)
328 struct octeon_ethernet
*priv
= container_of(work
, struct octeon_ethernet
, port_work
);
329 cvm_oct_rgmii_poll(cvm_oct_device
[priv
->port
]);
332 int cvm_oct_rgmii_init(struct net_device
*dev
)
334 struct octeon_ethernet
*priv
= netdev_priv(dev
);
337 cvm_oct_common_init(dev
);
338 dev
->netdev_ops
->ndo_stop(dev
);
339 INIT_WORK(&priv
->port_work
, cvm_oct_rgmii_immediate_poll
);
341 * Due to GMX errata in CN3XXX series chips, it is necessary
342 * to take the link down immediately when the PHY changes
343 * state. In order to do this we call the poll function every
344 * time the RGMII inband status changes. This may cause
345 * problems if the PHY doesn't implement inband status
348 if (number_rgmii_ports
== 0) {
349 r
= request_irq(OCTEON_IRQ_RML
, cvm_oct_rgmii_rml_interrupt
,
350 IRQF_SHARED
, "RGMII", &number_rgmii_ports
);
354 number_rgmii_ports
++;
357 * Only true RGMII ports need to be polled. In GMII mode, port
358 * 0 is really a RGMII port.
360 if (((priv
->imode
== CVMX_HELPER_INTERFACE_MODE_GMII
)
361 && (priv
->port
== 0))
362 || (priv
->imode
== CVMX_HELPER_INTERFACE_MODE_RGMII
)) {
364 if (!octeon_is_simulation()) {
366 union cvmx_gmxx_rxx_int_en gmx_rx_int_en
;
367 int interface
= INTERFACE(priv
->port
);
368 int index
= INDEX(priv
->port
);
371 * Enable interrupts on inband status changes
375 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
377 gmx_rx_int_en
.s
.phy_dupx
= 1;
378 gmx_rx_int_en
.s
.phy_link
= 1;
379 gmx_rx_int_en
.s
.phy_spd
= 1;
380 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index
, interface
),
382 priv
->poll
= cvm_oct_rgmii_poll
;
389 void cvm_oct_rgmii_uninit(struct net_device
*dev
)
391 struct octeon_ethernet
*priv
= netdev_priv(dev
);
392 cvm_oct_common_uninit(dev
);
395 * Only true RGMII ports need to be polled. In GMII mode, port
396 * 0 is really a RGMII port.
398 if (((priv
->imode
== CVMX_HELPER_INTERFACE_MODE_GMII
)
399 && (priv
->port
== 0))
400 || (priv
->imode
== CVMX_HELPER_INTERFACE_MODE_RGMII
)) {
402 if (!octeon_is_simulation()) {
404 union cvmx_gmxx_rxx_int_en gmx_rx_int_en
;
405 int interface
= INTERFACE(priv
->port
);
406 int index
= INDEX(priv
->port
);
409 * Disable interrupts on inband status changes
413 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
415 gmx_rx_int_en
.s
.phy_dupx
= 0;
416 gmx_rx_int_en
.s
.phy_link
= 0;
417 gmx_rx_int_en
.s
.phy_spd
= 0;
418 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index
, interface
),
423 /* Remove the interrupt handler when the last port is removed. */
424 number_rgmii_ports
--;
425 if (number_rgmii_ports
== 0)
426 free_irq(OCTEON_IRQ_RML
, &number_rgmii_ports
);
427 cancel_work_sync(&priv
->port_work
);