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-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
);
52 cvmx_helper_link_info_t link_info
;
55 * Take the global register lock since we are going to touch
56 * registers that affect more than one port.
58 spin_lock_irqsave(&global_register_lock
, flags
);
60 link_info
= cvmx_helper_link_get(priv
->port
);
61 if (link_info
.u64
== priv
->link_info
) {
64 * If the 10Mbps preamble workaround is supported and we're
65 * at 10Mbps we may need to do some special checking.
67 if (USE_10MBPS_PREAMBLE_WORKAROUND
&& (link_info
.s
.speed
== 10)) {
70 * Read the GMXX_RXX_INT_REG[PCTERR] bit and
71 * see if we are getting preamble errors.
73 int interface
= INTERFACE(priv
->port
);
74 int index
= INDEX(priv
->port
);
75 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg
;
76 gmxx_rxx_int_reg
.u64
=
77 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
79 if (gmxx_rxx_int_reg
.s
.pcterr
) {
82 * We are getting preamble errors at
83 * 10Mbps. Most likely the PHY is
84 * giving us packets with mis aligned
85 * preambles. In order to get these
86 * packets we need to disable preamble
87 * checking and do it in software.
89 union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl
;
90 union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs
;
92 /* Disable preamble checking */
93 gmxx_rxx_frm_ctl
.u64
=
94 cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL
96 gmxx_rxx_frm_ctl
.s
.pre_chk
= 0;
97 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL
99 gmxx_rxx_frm_ctl
.u64
);
101 /* Disable FCS stripping */
102 ipd_sub_port_fcs
.u64
=
103 cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS
);
104 ipd_sub_port_fcs
.s
.port_bit
&=
105 0xffffffffull
^ (1ull << priv
->port
);
106 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS
,
107 ipd_sub_port_fcs
.u64
);
109 /* Clear any error bits */
110 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
112 gmxx_rxx_int_reg
.u64
);
113 DEBUGPRINT("%s: Using 10Mbps with software "
114 "preamble removal\n",
118 spin_unlock_irqrestore(&global_register_lock
, flags
);
122 /* If the 10Mbps preamble workaround is allowed we need to on
123 preamble checking, FCS stripping, and clear error bits on
124 every speed change. If errors occur during 10Mbps operation
125 the above code will change this stuff */
126 if (USE_10MBPS_PREAMBLE_WORKAROUND
) {
128 union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl
;
129 union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs
;
130 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg
;
131 int interface
= INTERFACE(priv
->port
);
132 int index
= INDEX(priv
->port
);
134 /* Enable preamble checking */
135 gmxx_rxx_frm_ctl
.u64
=
136 cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index
, interface
));
137 gmxx_rxx_frm_ctl
.s
.pre_chk
= 1;
138 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index
, interface
),
139 gmxx_rxx_frm_ctl
.u64
);
140 /* Enable FCS stripping */
141 ipd_sub_port_fcs
.u64
= cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS
);
142 ipd_sub_port_fcs
.s
.port_bit
|= 1ull << priv
->port
;
143 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS
, ipd_sub_port_fcs
.u64
);
144 /* Clear any error bits */
145 gmxx_rxx_int_reg
.u64
=
146 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index
, interface
));
147 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index
, interface
),
148 gmxx_rxx_int_reg
.u64
);
151 link_info
= cvmx_helper_link_autoconf(priv
->port
);
152 priv
->link_info
= link_info
.u64
;
153 spin_unlock_irqrestore(&global_register_lock
, flags
);
156 if (link_info
.s
.link_up
) {
158 if (!netif_carrier_ok(dev
))
159 netif_carrier_on(dev
);
160 if (priv
->queue
!= -1)
162 ("%s: %u Mbps %s duplex, port %2d, queue %2d\n",
163 dev
->name
, link_info
.s
.speed
,
164 (link_info
.s
.full_duplex
) ? "Full" : "Half",
165 priv
->port
, priv
->queue
);
167 DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, POW\n",
168 dev
->name
, link_info
.s
.speed
,
169 (link_info
.s
.full_duplex
) ? "Full" : "Half",
173 if (netif_carrier_ok(dev
))
174 netif_carrier_off(dev
);
175 DEBUGPRINT("%s: Link down\n", dev
->name
);
179 static irqreturn_t
cvm_oct_rgmii_rml_interrupt(int cpl
, void *dev_id
)
181 union cvmx_npi_rsl_int_blocks rsl_int_blocks
;
183 irqreturn_t return_status
= IRQ_NONE
;
185 rsl_int_blocks
.u64
= cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS
);
187 /* Check and see if this interrupt was caused by the GMX0 block */
188 if (rsl_int_blocks
.s
.gmx0
) {
191 /* Loop through every port of this interface */
193 index
< cvmx_helper_ports_on_interface(interface
);
196 /* Read the GMX interrupt status bits */
197 union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg
;
199 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
201 gmx_rx_int_reg
.u64
&=
202 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
204 /* Poll the port if inband status changed */
205 if (gmx_rx_int_reg
.s
.phy_dupx
206 || gmx_rx_int_reg
.s
.phy_link
207 || gmx_rx_int_reg
.s
.phy_spd
) {
209 struct net_device
*dev
=
210 cvm_oct_device
[cvmx_helper_get_ipd_port
213 cvm_oct_rgmii_poll(dev
);
214 gmx_rx_int_reg
.u64
= 0;
215 gmx_rx_int_reg
.s
.phy_dupx
= 1;
216 gmx_rx_int_reg
.s
.phy_link
= 1;
217 gmx_rx_int_reg
.s
.phy_spd
= 1;
218 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
221 return_status
= IRQ_HANDLED
;
226 /* Check and see if this interrupt was caused by the GMX1 block */
227 if (rsl_int_blocks
.s
.gmx1
) {
230 /* Loop through every port of this interface */
232 index
< cvmx_helper_ports_on_interface(interface
);
235 /* Read the GMX interrupt status bits */
236 union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg
;
238 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
240 gmx_rx_int_reg
.u64
&=
241 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
243 /* Poll the port if inband status changed */
244 if (gmx_rx_int_reg
.s
.phy_dupx
245 || gmx_rx_int_reg
.s
.phy_link
246 || gmx_rx_int_reg
.s
.phy_spd
) {
248 struct net_device
*dev
=
249 cvm_oct_device
[cvmx_helper_get_ipd_port
252 cvm_oct_rgmii_poll(dev
);
253 gmx_rx_int_reg
.u64
= 0;
254 gmx_rx_int_reg
.s
.phy_dupx
= 1;
255 gmx_rx_int_reg
.s
.phy_link
= 1;
256 gmx_rx_int_reg
.s
.phy_spd
= 1;
257 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
260 return_status
= IRQ_HANDLED
;
264 return return_status
;
267 int cvm_oct_rgmii_open(struct net_device
*dev
)
269 union cvmx_gmxx_prtx_cfg gmx_cfg
;
270 struct octeon_ethernet
*priv
= netdev_priv(dev
);
271 int interface
= INTERFACE(priv
->port
);
272 int index
= INDEX(priv
->port
);
273 cvmx_helper_link_info_t link_info
;
275 gmx_cfg
.u64
= cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index
, interface
));
277 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index
, interface
), gmx_cfg
.u64
);
279 if (!octeon_is_simulation()) {
280 link_info
= cvmx_helper_link_get(priv
->port
);
281 if (!link_info
.s
.link_up
)
282 netif_carrier_off(dev
);
288 int cvm_oct_rgmii_stop(struct net_device
*dev
)
290 union cvmx_gmxx_prtx_cfg gmx_cfg
;
291 struct octeon_ethernet
*priv
= netdev_priv(dev
);
292 int interface
= INTERFACE(priv
->port
);
293 int index
= INDEX(priv
->port
);
295 gmx_cfg
.u64
= cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index
, interface
));
297 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index
, interface
), gmx_cfg
.u64
);
301 int cvm_oct_rgmii_init(struct net_device
*dev
)
303 struct octeon_ethernet
*priv
= netdev_priv(dev
);
306 cvm_oct_common_init(dev
);
307 dev
->netdev_ops
->ndo_stop(dev
);
310 * Due to GMX errata in CN3XXX series chips, it is necessary
311 * to take the link down immediately when the PHY changes
312 * state. In order to do this we call the poll function every
313 * time the RGMII inband status changes. This may cause
314 * problems if the PHY doesn't implement inband status
317 if (number_rgmii_ports
== 0) {
318 r
= request_irq(OCTEON_IRQ_RML
, cvm_oct_rgmii_rml_interrupt
,
319 IRQF_SHARED
, "RGMII", &number_rgmii_ports
);
323 number_rgmii_ports
++;
326 * Only true RGMII ports need to be polled. In GMII mode, port
327 * 0 is really a RGMII port.
329 if (((priv
->imode
== CVMX_HELPER_INTERFACE_MODE_GMII
)
330 && (priv
->port
== 0))
331 || (priv
->imode
== CVMX_HELPER_INTERFACE_MODE_RGMII
)) {
333 if (!octeon_is_simulation()) {
335 union cvmx_gmxx_rxx_int_en gmx_rx_int_en
;
336 int interface
= INTERFACE(priv
->port
);
337 int index
= INDEX(priv
->port
);
340 * Enable interrupts on inband status changes
344 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
346 gmx_rx_int_en
.s
.phy_dupx
= 1;
347 gmx_rx_int_en
.s
.phy_link
= 1;
348 gmx_rx_int_en
.s
.phy_spd
= 1;
349 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index
, interface
),
351 priv
->poll
= cvm_oct_rgmii_poll
;
358 void cvm_oct_rgmii_uninit(struct net_device
*dev
)
360 struct octeon_ethernet
*priv
= netdev_priv(dev
);
361 cvm_oct_common_uninit(dev
);
364 * Only true RGMII ports need to be polled. In GMII mode, port
365 * 0 is really a RGMII port.
367 if (((priv
->imode
== CVMX_HELPER_INTERFACE_MODE_GMII
)
368 && (priv
->port
== 0))
369 || (priv
->imode
== CVMX_HELPER_INTERFACE_MODE_RGMII
)) {
371 if (!octeon_is_simulation()) {
373 union cvmx_gmxx_rxx_int_en gmx_rx_int_en
;
374 int interface
= INTERFACE(priv
->port
);
375 int index
= INDEX(priv
->port
);
378 * Disable interrupts on inband status changes
382 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
384 gmx_rx_int_en
.s
.phy_dupx
= 0;
385 gmx_rx_int_en
.s
.phy_link
= 0;
386 gmx_rx_int_en
.s
.phy_spd
= 0;
387 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index
, interface
),
392 /* Remove the interrupt handler when the last port is removed. */
393 number_rgmii_ports
--;
394 if (number_rgmii_ports
== 0)
395 free_irq(OCTEON_IRQ_RML
, &number_rgmii_ports
);