2 * This file is based on code from OCTEON SDK by Cavium Networks.
4 * Copyright (c) 2003-2007 Cavium Networks
6 * This file is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, Version 2, as
8 * published by the Free Software Foundation.
11 #include <linux/kernel.h>
12 #include <linux/netdevice.h>
13 #include <linux/interrupt.h>
14 #include <linux/phy.h>
15 #include <linux/ratelimit.h>
18 #include <asm/octeon/octeon.h>
20 #include "ethernet-defines.h"
21 #include "octeon-ethernet.h"
22 #include "ethernet-util.h"
23 #include "ethernet-mdio.h"
25 #include <asm/octeon/cvmx-helper.h>
27 #include <asm/octeon/cvmx-ipd-defs.h>
28 #include <asm/octeon/cvmx-npi-defs.h>
29 #include <asm/octeon/cvmx-gmxx-defs.h>
31 static DEFINE_SPINLOCK(global_register_lock
);
33 static int number_rgmii_ports
;
35 static void cvm_oct_set_hw_preamble(struct octeon_ethernet
*priv
, bool enable
)
37 union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl
;
38 union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs
;
39 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg
;
40 int interface
= INTERFACE(priv
->port
);
41 int index
= INDEX(priv
->port
);
43 /* Set preamble checking. */
44 gmxx_rxx_frm_ctl
.u64
= cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index
,
46 gmxx_rxx_frm_ctl
.s
.pre_chk
= enable
;
47 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index
, interface
),
48 gmxx_rxx_frm_ctl
.u64
);
50 /* Set FCS stripping. */
51 ipd_sub_port_fcs
.u64
= cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS
);
53 ipd_sub_port_fcs
.s
.port_bit
|= 1ull << priv
->port
;
55 ipd_sub_port_fcs
.s
.port_bit
&=
56 0xffffffffull
^ (1ull << priv
->port
);
57 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS
, ipd_sub_port_fcs
.u64
);
59 /* Clear any error bits. */
60 gmxx_rxx_int_reg
.u64
= cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index
,
62 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index
, interface
),
63 gmxx_rxx_int_reg
.u64
);
66 static void cvm_oct_rgmii_poll(struct net_device
*dev
)
68 struct octeon_ethernet
*priv
= netdev_priv(dev
);
69 unsigned long flags
= 0;
70 cvmx_helper_link_info_t link_info
;
71 int use_global_register_lock
= (priv
->phydev
== NULL
);
73 BUG_ON(in_interrupt());
74 if (use_global_register_lock
) {
76 * Take the global register lock since we are going to
77 * touch registers that affect more than one port.
79 spin_lock_irqsave(&global_register_lock
, flags
);
81 mutex_lock(&priv
->phydev
->bus
->mdio_lock
);
84 link_info
= cvmx_helper_link_get(priv
->port
);
85 if (link_info
.u64
== priv
->link_info
) {
86 if (link_info
.s
.speed
== 10) {
88 * Read the GMXX_RXX_INT_REG[PCTERR] bit and
89 * see if we are getting preamble errors.
91 int interface
= INTERFACE(priv
->port
);
92 int index
= INDEX(priv
->port
);
93 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg
;
95 gmxx_rxx_int_reg
.u64
=
96 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
98 if (gmxx_rxx_int_reg
.s
.pcterr
) {
100 * We are getting preamble errors at
101 * 10Mbps. Most likely the PHY is
102 * giving us packets with mis aligned
103 * preambles. In order to get these
104 * packets we need to disable preamble
105 * checking and do it in software.
107 cvm_oct_set_hw_preamble(priv
, false);
108 printk_ratelimited("%s: Using 10Mbps with software preamble removal\n",
113 if (use_global_register_lock
)
114 spin_unlock_irqrestore(&global_register_lock
, flags
);
116 mutex_unlock(&priv
->phydev
->bus
->mdio_lock
);
120 /* Since the 10Mbps preamble workaround is allowed we need to enable
121 * preamble checking, FCS stripping, and clear error bits on
122 * every speed change. If errors occur during 10Mbps operation
123 * the above code will change this stuff
125 cvm_oct_set_hw_preamble(priv
, true);
127 if (priv
->phydev
== NULL
) {
128 link_info
= cvmx_helper_link_autoconf(priv
->port
);
129 priv
->link_info
= link_info
.u64
;
132 if (use_global_register_lock
)
133 spin_unlock_irqrestore(&global_register_lock
, flags
);
135 mutex_unlock(&priv
->phydev
->bus
->mdio_lock
);
137 if (priv
->phydev
== NULL
) {
139 if (link_info
.s
.link_up
) {
140 if (!netif_carrier_ok(dev
))
141 netif_carrier_on(dev
);
142 } else if (netif_carrier_ok(dev
)) {
143 netif_carrier_off(dev
);
145 cvm_oct_note_carrier(priv
, link_info
);
149 static int cmv_oct_rgmii_gmx_interrupt(int interface
)
154 /* Loop through every port of this interface */
156 index
< cvmx_helper_ports_on_interface(interface
);
158 union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg
;
160 /* Read the GMX interrupt status bits */
161 gmx_rx_int_reg
.u64
= cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
163 gmx_rx_int_reg
.u64
&= cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
166 /* Poll the port if inband status changed */
167 if (gmx_rx_int_reg
.s
.phy_dupx
|| gmx_rx_int_reg
.s
.phy_link
||
168 gmx_rx_int_reg
.s
.phy_spd
) {
169 struct net_device
*dev
=
170 cvm_oct_device
[cvmx_helper_get_ipd_port
172 struct octeon_ethernet
*priv
= netdev_priv(dev
);
174 if (dev
&& !atomic_read(&cvm_oct_poll_queue_stopping
))
175 queue_work(cvm_oct_poll_queue
,
178 gmx_rx_int_reg
.u64
= 0;
179 gmx_rx_int_reg
.s
.phy_dupx
= 1;
180 gmx_rx_int_reg
.s
.phy_link
= 1;
181 gmx_rx_int_reg
.s
.phy_spd
= 1;
182 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index
, interface
),
190 static irqreturn_t
cvm_oct_rgmii_rml_interrupt(int cpl
, void *dev_id
)
192 union cvmx_npi_rsl_int_blocks rsl_int_blocks
;
195 rsl_int_blocks
.u64
= cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS
);
197 /* Check and see if this interrupt was caused by the GMX0 block */
198 if (rsl_int_blocks
.s
.gmx0
)
199 count
+= cmv_oct_rgmii_gmx_interrupt(0);
201 /* Check and see if this interrupt was caused by the GMX1 block */
202 if (rsl_int_blocks
.s
.gmx1
)
203 count
+= cmv_oct_rgmii_gmx_interrupt(1);
205 return count
? IRQ_HANDLED
: IRQ_NONE
;
208 int cvm_oct_rgmii_open(struct net_device
*dev
)
210 return cvm_oct_common_open(dev
, cvm_oct_rgmii_poll
);
213 static void cvm_oct_rgmii_immediate_poll(struct work_struct
*work
)
215 struct octeon_ethernet
*priv
=
216 container_of(work
, struct octeon_ethernet
, port_work
);
217 cvm_oct_rgmii_poll(cvm_oct_device
[priv
->port
]);
220 int cvm_oct_rgmii_init(struct net_device
*dev
)
222 struct octeon_ethernet
*priv
= netdev_priv(dev
);
225 cvm_oct_common_init(dev
);
226 INIT_WORK(&priv
->port_work
, cvm_oct_rgmii_immediate_poll
);
228 * Due to GMX errata in CN3XXX series chips, it is necessary
229 * to take the link down immediately when the PHY changes
230 * state. In order to do this we call the poll function every
231 * time the RGMII inband status changes. This may cause
232 * problems if the PHY doesn't implement inband status
235 if (number_rgmii_ports
== 0) {
236 r
= request_irq(OCTEON_IRQ_RML
, cvm_oct_rgmii_rml_interrupt
,
237 IRQF_SHARED
, "RGMII", &number_rgmii_ports
);
241 number_rgmii_ports
++;
244 * Only true RGMII ports need to be polled. In GMII mode, port
245 * 0 is really a RGMII port.
247 if (((priv
->imode
== CVMX_HELPER_INTERFACE_MODE_GMII
)
248 && (priv
->port
== 0))
249 || (priv
->imode
== CVMX_HELPER_INTERFACE_MODE_RGMII
)) {
251 if (!octeon_is_simulation()) {
253 union cvmx_gmxx_rxx_int_en gmx_rx_int_en
;
254 int interface
= INTERFACE(priv
->port
);
255 int index
= INDEX(priv
->port
);
258 * Enable interrupts on inband status changes
261 gmx_rx_int_en
.u64
= 0;
262 gmx_rx_int_en
.s
.phy_dupx
= 1;
263 gmx_rx_int_en
.s
.phy_link
= 1;
264 gmx_rx_int_en
.s
.phy_spd
= 1;
265 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index
, interface
),
273 void cvm_oct_rgmii_uninit(struct net_device
*dev
)
275 struct octeon_ethernet
*priv
= netdev_priv(dev
);
277 cvm_oct_common_uninit(dev
);
280 * Only true RGMII ports need to be polled. In GMII mode, port
281 * 0 is really a RGMII port.
283 if (((priv
->imode
== CVMX_HELPER_INTERFACE_MODE_GMII
)
284 && (priv
->port
== 0))
285 || (priv
->imode
== CVMX_HELPER_INTERFACE_MODE_RGMII
)) {
287 if (!octeon_is_simulation()) {
289 union cvmx_gmxx_rxx_int_en gmx_rx_int_en
;
290 int interface
= INTERFACE(priv
->port
);
291 int index
= INDEX(priv
->port
);
294 * Disable interrupts on inband status changes
298 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
300 gmx_rx_int_en
.s
.phy_dupx
= 0;
301 gmx_rx_int_en
.s
.phy_link
= 0;
302 gmx_rx_int_en
.s
.phy_spd
= 0;
303 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index
, interface
),
308 /* Remove the interrupt handler when the last port is removed. */
309 number_rgmii_ports
--;
310 if (number_rgmii_ports
== 0)
311 free_irq(OCTEON_IRQ_RML
, &number_rgmii_ports
);
312 cancel_work_sync(&priv
->port_work
);