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/interrupt.h>
30 #include <linux/phy.h>
31 #include <linux/ratelimit.h>
34 #include <asm/octeon/octeon.h>
36 #include "ethernet-defines.h"
37 #include "octeon-ethernet.h"
38 #include "ethernet-util.h"
39 #include "ethernet-mdio.h"
41 #include <asm/octeon/cvmx-helper.h>
43 #include <asm/octeon/cvmx-ipd-defs.h>
44 #include <asm/octeon/cvmx-npi-defs.h>
45 #include <asm/octeon/cvmx-gmxx-defs.h>
47 static DEFINE_SPINLOCK(global_register_lock
);
49 static int number_rgmii_ports
;
51 static void cvm_oct_set_hw_preamble(struct octeon_ethernet
*priv
, bool enable
)
53 union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl
;
54 union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs
;
55 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg
;
56 int interface
= INTERFACE(priv
->port
);
57 int index
= INDEX(priv
->port
);
59 /* Set preamble checking. */
60 gmxx_rxx_frm_ctl
.u64
= cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index
,
62 gmxx_rxx_frm_ctl
.s
.pre_chk
= enable
;
63 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index
, interface
),
64 gmxx_rxx_frm_ctl
.u64
);
66 /* Set FCS stripping. */
67 ipd_sub_port_fcs
.u64
= cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS
);
69 ipd_sub_port_fcs
.s
.port_bit
|= 1ull << priv
->port
;
71 ipd_sub_port_fcs
.s
.port_bit
&=
72 0xffffffffull
^ (1ull << priv
->port
);
73 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS
, ipd_sub_port_fcs
.u64
);
75 /* Clear any error bits. */
76 gmxx_rxx_int_reg
.u64
= cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index
,
78 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index
, interface
),
79 gmxx_rxx_int_reg
.u64
);
82 static void cvm_oct_rgmii_poll(struct net_device
*dev
)
84 struct octeon_ethernet
*priv
= netdev_priv(dev
);
85 unsigned long flags
= 0;
86 cvmx_helper_link_info_t link_info
;
87 int use_global_register_lock
= (priv
->phydev
== NULL
);
89 BUG_ON(in_interrupt());
90 if (use_global_register_lock
) {
92 * Take the global register lock since we are going to
93 * touch registers that affect more than one port.
95 spin_lock_irqsave(&global_register_lock
, flags
);
97 mutex_lock(&priv
->phydev
->bus
->mdio_lock
);
100 link_info
= cvmx_helper_link_get(priv
->port
);
101 if (link_info
.u64
== priv
->link_info
) {
104 * If the 10Mbps preamble workaround is supported and we're
105 * at 10Mbps we may need to do some special checking.
107 if (USE_10MBPS_PREAMBLE_WORKAROUND
&&
108 (link_info
.s
.speed
== 10)) {
111 * Read the GMXX_RXX_INT_REG[PCTERR] bit and
112 * see if we are getting preamble errors.
114 int interface
= INTERFACE(priv
->port
);
115 int index
= INDEX(priv
->port
);
116 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg
;
118 gmxx_rxx_int_reg
.u64
=
119 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
121 if (gmxx_rxx_int_reg
.s
.pcterr
) {
123 * We are getting preamble errors at
124 * 10Mbps. Most likely the PHY is
125 * giving us packets with mis aligned
126 * preambles. In order to get these
127 * packets we need to disable preamble
128 * checking and do it in software.
130 cvm_oct_set_hw_preamble(priv
, false);
131 printk_ratelimited("%s: Using 10Mbps with software preamble removal\n",
136 if (use_global_register_lock
)
137 spin_unlock_irqrestore(&global_register_lock
, flags
);
139 mutex_unlock(&priv
->phydev
->bus
->mdio_lock
);
143 /* If the 10Mbps preamble workaround is allowed we need to on
144 preamble checking, FCS stripping, and clear error bits on
145 every speed change. If errors occur during 10Mbps operation
146 the above code will change this stuff */
147 if (USE_10MBPS_PREAMBLE_WORKAROUND
)
148 cvm_oct_set_hw_preamble(priv
, true);
150 if (priv
->phydev
== NULL
) {
151 link_info
= cvmx_helper_link_autoconf(priv
->port
);
152 priv
->link_info
= link_info
.u64
;
155 if (use_global_register_lock
)
156 spin_unlock_irqrestore(&global_register_lock
, flags
);
158 mutex_unlock(&priv
->phydev
->bus
->mdio_lock
);
160 if (priv
->phydev
== NULL
) {
162 if (link_info
.s
.link_up
) {
163 if (!netif_carrier_ok(dev
))
164 netif_carrier_on(dev
);
165 } else if (netif_carrier_ok(dev
)) {
166 netif_carrier_off(dev
);
168 cvm_oct_note_carrier(priv
, link_info
);
172 static int cmv_oct_rgmii_gmx_interrupt(int interface
)
177 /* Loop through every port of this interface */
179 index
< cvmx_helper_ports_on_interface(interface
);
181 union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg
;
183 /* Read the GMX interrupt status bits */
184 gmx_rx_int_reg
.u64
= cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
186 gmx_rx_int_reg
.u64
&= cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
189 /* Poll the port if inband status changed */
190 if (gmx_rx_int_reg
.s
.phy_dupx
|| gmx_rx_int_reg
.s
.phy_link
||
191 gmx_rx_int_reg
.s
.phy_spd
) {
192 struct net_device
*dev
=
193 cvm_oct_device
[cvmx_helper_get_ipd_port
195 struct octeon_ethernet
*priv
= netdev_priv(dev
);
197 if (dev
&& !atomic_read(&cvm_oct_poll_queue_stopping
))
198 queue_work(cvm_oct_poll_queue
,
201 gmx_rx_int_reg
.u64
= 0;
202 gmx_rx_int_reg
.s
.phy_dupx
= 1;
203 gmx_rx_int_reg
.s
.phy_link
= 1;
204 gmx_rx_int_reg
.s
.phy_spd
= 1;
205 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index
, interface
),
213 static irqreturn_t
cvm_oct_rgmii_rml_interrupt(int cpl
, void *dev_id
)
215 union cvmx_npi_rsl_int_blocks rsl_int_blocks
;
218 rsl_int_blocks
.u64
= cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS
);
220 /* Check and see if this interrupt was caused by the GMX0 block */
221 if (rsl_int_blocks
.s
.gmx0
)
222 count
+= cmv_oct_rgmii_gmx_interrupt(0);
224 /* Check and see if this interrupt was caused by the GMX1 block */
225 if (rsl_int_blocks
.s
.gmx1
)
226 count
+= cmv_oct_rgmii_gmx_interrupt(1);
228 return count
? IRQ_HANDLED
: IRQ_NONE
;
231 int cvm_oct_rgmii_open(struct net_device
*dev
)
233 return cvm_oct_common_open(dev
, cvm_oct_rgmii_poll
, false);
236 static void cvm_oct_rgmii_immediate_poll(struct work_struct
*work
)
238 struct octeon_ethernet
*priv
=
239 container_of(work
, struct octeon_ethernet
, port_work
);
240 cvm_oct_rgmii_poll(cvm_oct_device
[priv
->port
]);
243 int cvm_oct_rgmii_init(struct net_device
*dev
)
245 struct octeon_ethernet
*priv
= netdev_priv(dev
);
248 cvm_oct_common_init(dev
);
249 INIT_WORK(&priv
->port_work
, cvm_oct_rgmii_immediate_poll
);
251 * Due to GMX errata in CN3XXX series chips, it is necessary
252 * to take the link down immediately when the PHY changes
253 * state. In order to do this we call the poll function every
254 * time the RGMII inband status changes. This may cause
255 * problems if the PHY doesn't implement inband status
258 if (number_rgmii_ports
== 0) {
259 r
= request_irq(OCTEON_IRQ_RML
, cvm_oct_rgmii_rml_interrupt
,
260 IRQF_SHARED
, "RGMII", &number_rgmii_ports
);
264 number_rgmii_ports
++;
267 * Only true RGMII ports need to be polled. In GMII mode, port
268 * 0 is really a RGMII port.
270 if (((priv
->imode
== CVMX_HELPER_INTERFACE_MODE_GMII
)
271 && (priv
->port
== 0))
272 || (priv
->imode
== CVMX_HELPER_INTERFACE_MODE_RGMII
)) {
274 if (!octeon_is_simulation()) {
276 union cvmx_gmxx_rxx_int_en gmx_rx_int_en
;
277 int interface
= INTERFACE(priv
->port
);
278 int index
= INDEX(priv
->port
);
281 * Enable interrupts on inband status changes
284 gmx_rx_int_en
.u64
= 0;
285 gmx_rx_int_en
.s
.phy_dupx
= 1;
286 gmx_rx_int_en
.s
.phy_link
= 1;
287 gmx_rx_int_en
.s
.phy_spd
= 1;
288 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index
, interface
),
296 void cvm_oct_rgmii_uninit(struct net_device
*dev
)
298 struct octeon_ethernet
*priv
= netdev_priv(dev
);
300 cvm_oct_common_uninit(dev
);
303 * Only true RGMII ports need to be polled. In GMII mode, port
304 * 0 is really a RGMII port.
306 if (((priv
->imode
== CVMX_HELPER_INTERFACE_MODE_GMII
)
307 && (priv
->port
== 0))
308 || (priv
->imode
== CVMX_HELPER_INTERFACE_MODE_RGMII
)) {
310 if (!octeon_is_simulation()) {
312 union cvmx_gmxx_rxx_int_en gmx_rx_int_en
;
313 int interface
= INTERFACE(priv
->port
);
314 int index
= INDEX(priv
->port
);
317 * Disable interrupts on inband status changes
321 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
323 gmx_rx_int_en
.s
.phy_dupx
= 0;
324 gmx_rx_int_en
.s
.phy_link
= 0;
325 gmx_rx_int_en
.s
.phy_spd
= 0;
326 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index
, interface
),
331 /* Remove the interrupt handler when the last port is removed. */
332 number_rgmii_ports
--;
333 if (number_rgmii_ports
== 0)
334 free_irq(OCTEON_IRQ_RML
, &number_rgmii_ports
);
335 cancel_work_sync(&priv
->port_work
);