blob: e36f9bc695430bf89fefd00b9feba9fe37bcc698 [file] [log] [blame]
David Daney80ff0fd2009-05-05 17:35:21 -07001/*********************************************************************
2 * Author: Cavium Networks
3 *
4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK
6 *
7 * Copyright (c) 2003-2007 Cavium Networks
8 *
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.
12 *
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
17 * details.
18 *
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/.
23 *
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>
David Daney048316b2011-08-16 10:10:56 -070029#include <linux/interrupt.h>
David Daneyf8c26482010-02-15 12:13:17 -080030#include <linux/phy.h>
Christian Dietrich7a2eaf92011-06-04 17:35:58 +020031#include <linux/ratelimit.h>
David Daney80ff0fd2009-05-05 17:35:21 -070032#include <net/dst.h>
33
34#include <asm/octeon/octeon.h>
35
36#include "ethernet-defines.h"
37#include "octeon-ethernet.h"
David Daney80ff0fd2009-05-05 17:35:21 -070038#include "ethernet-util.h"
David Daneyec3a2202014-05-29 11:10:02 +010039#include "ethernet-mdio.h"
David Daney80ff0fd2009-05-05 17:35:21 -070040
David Daneyaf866492011-11-22 14:47:00 +000041#include <asm/octeon/cvmx-helper.h>
David Daney80ff0fd2009-05-05 17:35:21 -070042
43#include <asm/octeon/cvmx-ipd-defs.h>
44#include <asm/octeon/cvmx-npi-defs.h>
David Daneyaf866492011-11-22 14:47:00 +000045#include <asm/octeon/cvmx-gmxx-defs.h>
David Daney80ff0fd2009-05-05 17:35:21 -070046
Aaro Koskinen54bf9172014-03-02 00:09:08 +020047static DEFINE_SPINLOCK(global_register_lock);
David Daney80ff0fd2009-05-05 17:35:21 -070048
49static int number_rgmii_ports;
50
51static void cvm_oct_rgmii_poll(struct net_device *dev)
52{
53 struct octeon_ethernet *priv = netdev_priv(dev);
David Daneyf8c26482010-02-15 12:13:17 -080054 unsigned long flags = 0;
David Daney80ff0fd2009-05-05 17:35:21 -070055 cvmx_helper_link_info_t link_info;
David Daneyf8c26482010-02-15 12:13:17 -080056 int use_global_register_lock = (priv->phydev == NULL);
David Daney80ff0fd2009-05-05 17:35:21 -070057
David Daneyf8c26482010-02-15 12:13:17 -080058 BUG_ON(in_interrupt());
59 if (use_global_register_lock) {
60 /*
61 * Take the global register lock since we are going to
62 * touch registers that affect more than one port.
63 */
64 spin_lock_irqsave(&global_register_lock, flags);
65 } else {
66 mutex_lock(&priv->phydev->bus->mdio_lock);
67 }
David Daney80ff0fd2009-05-05 17:35:21 -070068
69 link_info = cvmx_helper_link_get(priv->port);
70 if (link_info.u64 == priv->link_info) {
71
72 /*
73 * If the 10Mbps preamble workaround is supported and we're
74 * at 10Mbps we may need to do some special checking.
75 */
Aybuke Ozdemirf09d1442014-03-18 21:13:29 +020076 if (USE_10MBPS_PREAMBLE_WORKAROUND &&
77 (link_info.s.speed == 10)) {
David Daney80ff0fd2009-05-05 17:35:21 -070078
79 /*
80 * Read the GMXX_RXX_INT_REG[PCTERR] bit and
81 * see if we are getting preamble errors.
82 */
83 int interface = INTERFACE(priv->port);
84 int index = INDEX(priv->port);
85 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
Melike Yurtoglu5a2da4a2014-09-28 15:53:21 +030086
David Daney80ff0fd2009-05-05 17:35:21 -070087 gmxx_rxx_int_reg.u64 =
88 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
89 (index, interface));
90 if (gmxx_rxx_int_reg.s.pcterr) {
91
92 /*
93 * We are getting preamble errors at
94 * 10Mbps. Most likely the PHY is
95 * giving us packets with mis aligned
96 * preambles. In order to get these
97 * packets we need to disable preamble
98 * checking and do it in software.
99 */
100 union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
101 union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
102
103 /* Disable preamble checking */
104 gmxx_rxx_frm_ctl.u64 =
105 cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL
106 (index, interface));
107 gmxx_rxx_frm_ctl.s.pre_chk = 0;
108 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL
109 (index, interface),
110 gmxx_rxx_frm_ctl.u64);
111
112 /* Disable FCS stripping */
113 ipd_sub_port_fcs.u64 =
114 cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
115 ipd_sub_port_fcs.s.port_bit &=
116 0xffffffffull ^ (1ull << priv->port);
117 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS,
118 ipd_sub_port_fcs.u64);
119
120 /* Clear any error bits */
121 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
122 (index, interface),
123 gmxx_rxx_int_reg.u64);
Gulsah Kose42e0e192014-09-30 22:12:22 +0300124 printk_ratelimited("%s: Using 10Mbps with software preamble removal\n",
Christian Dietrich7a2eaf92011-06-04 17:35:58 +0200125 dev->name);
David Daney80ff0fd2009-05-05 17:35:21 -0700126 }
127 }
David Daneyf8c26482010-02-15 12:13:17 -0800128
129 if (use_global_register_lock)
130 spin_unlock_irqrestore(&global_register_lock, flags);
131 else
132 mutex_unlock(&priv->phydev->bus->mdio_lock);
David Daney80ff0fd2009-05-05 17:35:21 -0700133 return;
134 }
135
136 /* If the 10Mbps preamble workaround is allowed we need to on
137 preamble checking, FCS stripping, and clear error bits on
138 every speed change. If errors occur during 10Mbps operation
139 the above code will change this stuff */
140 if (USE_10MBPS_PREAMBLE_WORKAROUND) {
141
142 union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
143 union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
144 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
145 int interface = INTERFACE(priv->port);
146 int index = INDEX(priv->port);
147
148 /* Enable preamble checking */
149 gmxx_rxx_frm_ctl.u64 =
150 cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface));
151 gmxx_rxx_frm_ctl.s.pre_chk = 1;
152 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface),
153 gmxx_rxx_frm_ctl.u64);
154 /* Enable FCS stripping */
155 ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
156 ipd_sub_port_fcs.s.port_bit |= 1ull << priv->port;
157 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
158 /* Clear any error bits */
159 gmxx_rxx_int_reg.u64 =
160 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index, interface));
161 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
162 gmxx_rxx_int_reg.u64);
163 }
David Daneyf6ed1b32009-10-14 12:04:42 -0700164 if (priv->phydev == NULL) {
165 link_info = cvmx_helper_link_autoconf(priv->port);
166 priv->link_info = link_info.u64;
167 }
David Daneyf8c26482010-02-15 12:13:17 -0800168
169 if (use_global_register_lock)
170 spin_unlock_irqrestore(&global_register_lock, flags);
bahar sahin4504b1b2014-03-03 03:56:03 +0200171 else
David Daneyf8c26482010-02-15 12:13:17 -0800172 mutex_unlock(&priv->phydev->bus->mdio_lock);
David Daney80ff0fd2009-05-05 17:35:21 -0700173
David Daneyf6ed1b32009-10-14 12:04:42 -0700174 if (priv->phydev == NULL) {
175 /* Tell core. */
176 if (link_info.s.link_up) {
177 if (!netif_carrier_ok(dev))
178 netif_carrier_on(dev);
179 if (priv->queue != -1)
Gulsah Kose42e0e192014-09-30 22:12:22 +0300180 printk_ratelimited("%s: %u Mbps %s duplex, port %2d, queue %2d\n",
Christian Dietrich7a2eaf92011-06-04 17:35:58 +0200181 dev->name, link_info.s.speed,
182 (link_info.s.full_duplex) ?
183 "Full" : "Half",
184 priv->port, priv->queue);
David Daneyf6ed1b32009-10-14 12:04:42 -0700185 else
Gulsah Kose42e0e192014-09-30 22:12:22 +0300186 printk_ratelimited("%s: %u Mbps %s duplex, port %2d, POW\n",
Christian Dietrich7a2eaf92011-06-04 17:35:58 +0200187 dev->name, link_info.s.speed,
188 (link_info.s.full_duplex) ?
189 "Full" : "Half",
190 priv->port);
David Daneyf6ed1b32009-10-14 12:04:42 -0700191 } else {
192 if (netif_carrier_ok(dev))
193 netif_carrier_off(dev);
Christian Dietrich7a2eaf92011-06-04 17:35:58 +0200194 printk_ratelimited("%s: Link down\n", dev->name);
David Daneyf6ed1b32009-10-14 12:04:42 -0700195 }
David Daney80ff0fd2009-05-05 17:35:21 -0700196 }
197}
198
199static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id)
200{
201 union cvmx_npi_rsl_int_blocks rsl_int_blocks;
202 int index;
203 irqreturn_t return_status = IRQ_NONE;
204
205 rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
206
207 /* Check and see if this interrupt was caused by the GMX0 block */
208 if (rsl_int_blocks.s.gmx0) {
209
210 int interface = 0;
211 /* Loop through every port of this interface */
212 for (index = 0;
213 index < cvmx_helper_ports_on_interface(interface);
214 index++) {
215
216 /* Read the GMX interrupt status bits */
217 union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
Melike Yurtoglu5a2da4a2014-09-28 15:53:21 +0300218
David Daney80ff0fd2009-05-05 17:35:21 -0700219 gmx_rx_int_reg.u64 =
220 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
221 (index, interface));
222 gmx_rx_int_reg.u64 &=
223 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
224 (index, interface));
225 /* Poll the port if inband status changed */
226 if (gmx_rx_int_reg.s.phy_dupx
227 || gmx_rx_int_reg.s.phy_link
228 || gmx_rx_int_reg.s.phy_spd) {
229
230 struct net_device *dev =
231 cvm_oct_device[cvmx_helper_get_ipd_port
232 (interface, index)];
David Daneyf8c26482010-02-15 12:13:17 -0800233 struct octeon_ethernet *priv = netdev_priv(dev);
234
Aybuke Ozdemirf09d1442014-03-18 21:13:29 +0200235 if (dev &&
236 !atomic_read(&cvm_oct_poll_queue_stopping))
237 queue_work(cvm_oct_poll_queue,
238 &priv->port_work);
David Daneyf8c26482010-02-15 12:13:17 -0800239
David Daney80ff0fd2009-05-05 17:35:21 -0700240 gmx_rx_int_reg.u64 = 0;
241 gmx_rx_int_reg.s.phy_dupx = 1;
242 gmx_rx_int_reg.s.phy_link = 1;
243 gmx_rx_int_reg.s.phy_spd = 1;
244 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
245 (index, interface),
246 gmx_rx_int_reg.u64);
247 return_status = IRQ_HANDLED;
248 }
249 }
250 }
251
252 /* Check and see if this interrupt was caused by the GMX1 block */
253 if (rsl_int_blocks.s.gmx1) {
254
255 int interface = 1;
256 /* Loop through every port of this interface */
257 for (index = 0;
258 index < cvmx_helper_ports_on_interface(interface);
259 index++) {
260
261 /* Read the GMX interrupt status bits */
262 union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
Melike Yurtoglu5a2da4a2014-09-28 15:53:21 +0300263
David Daney80ff0fd2009-05-05 17:35:21 -0700264 gmx_rx_int_reg.u64 =
265 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
266 (index, interface));
267 gmx_rx_int_reg.u64 &=
268 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
269 (index, interface));
270 /* Poll the port if inband status changed */
271 if (gmx_rx_int_reg.s.phy_dupx
272 || gmx_rx_int_reg.s.phy_link
273 || gmx_rx_int_reg.s.phy_spd) {
274
275 struct net_device *dev =
276 cvm_oct_device[cvmx_helper_get_ipd_port
277 (interface, index)];
David Daneyf8c26482010-02-15 12:13:17 -0800278 struct octeon_ethernet *priv = netdev_priv(dev);
279
Aybuke Ozdemirf09d1442014-03-18 21:13:29 +0200280 if (dev &&
281 !atomic_read(&cvm_oct_poll_queue_stopping))
282 queue_work(cvm_oct_poll_queue,
283 &priv->port_work);
David Daneyf8c26482010-02-15 12:13:17 -0800284
David Daney80ff0fd2009-05-05 17:35:21 -0700285 gmx_rx_int_reg.u64 = 0;
286 gmx_rx_int_reg.s.phy_dupx = 1;
287 gmx_rx_int_reg.s.phy_link = 1;
288 gmx_rx_int_reg.s.phy_spd = 1;
289 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
290 (index, interface),
291 gmx_rx_int_reg.u64);
292 return_status = IRQ_HANDLED;
293 }
294 }
295 }
296 return return_status;
297}
298
David Daneyf696a102009-06-23 11:34:08 -0700299int cvm_oct_rgmii_open(struct net_device *dev)
David Daney80ff0fd2009-05-05 17:35:21 -0700300{
301 union cvmx_gmxx_prtx_cfg gmx_cfg;
302 struct octeon_ethernet *priv = netdev_priv(dev);
303 int interface = INTERFACE(priv->port);
304 int index = INDEX(priv->port);
305 cvmx_helper_link_info_t link_info;
David Daneyec3a2202014-05-29 11:10:02 +0100306 int rv;
307
308 rv = cvm_oct_phy_setup_device(dev);
309 if (rv)
310 return rv;
David Daney80ff0fd2009-05-05 17:35:21 -0700311
312 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
313 gmx_cfg.s.en = 1;
314 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
315
316 if (!octeon_is_simulation()) {
David Daneyec3a2202014-05-29 11:10:02 +0100317 if (priv->phydev) {
318 int r = phy_read_status(priv->phydev);
Melike Yurtoglu5a2da4a2014-09-28 15:53:21 +0300319
David Daneyec3a2202014-05-29 11:10:02 +0100320 if (r == 0 && priv->phydev->link == 0)
321 netif_carrier_off(dev);
322 cvm_oct_adjust_link(dev);
323 } else {
324 link_info = cvmx_helper_link_get(priv->port);
325 if (!link_info.s.link_up)
326 netif_carrier_off(dev);
327 priv->poll = cvm_oct_rgmii_poll;
328 }
David Daney80ff0fd2009-05-05 17:35:21 -0700329 }
330
331 return 0;
332}
333
David Daneyf696a102009-06-23 11:34:08 -0700334int cvm_oct_rgmii_stop(struct net_device *dev)
David Daney80ff0fd2009-05-05 17:35:21 -0700335{
336 union cvmx_gmxx_prtx_cfg gmx_cfg;
337 struct octeon_ethernet *priv = netdev_priv(dev);
338 int interface = INTERFACE(priv->port);
339 int index = INDEX(priv->port);
340
341 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
342 gmx_cfg.s.en = 0;
343 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
David Daneyec3a2202014-05-29 11:10:02 +0100344 return cvm_oct_common_stop(dev);
David Daney80ff0fd2009-05-05 17:35:21 -0700345}
346
David Daneyf8c26482010-02-15 12:13:17 -0800347static void cvm_oct_rgmii_immediate_poll(struct work_struct *work)
348{
Aybuke Ozdemirf09d1442014-03-18 21:13:29 +0200349 struct octeon_ethernet *priv =
350 container_of(work, struct octeon_ethernet, port_work);
David Daneyf8c26482010-02-15 12:13:17 -0800351 cvm_oct_rgmii_poll(cvm_oct_device[priv->port]);
352}
353
David Daney80ff0fd2009-05-05 17:35:21 -0700354int cvm_oct_rgmii_init(struct net_device *dev)
355{
356 struct octeon_ethernet *priv = netdev_priv(dev);
357 int r;
358
359 cvm_oct_common_init(dev);
David Daneyf696a102009-06-23 11:34:08 -0700360 dev->netdev_ops->ndo_stop(dev);
David Daneyf8c26482010-02-15 12:13:17 -0800361 INIT_WORK(&priv->port_work, cvm_oct_rgmii_immediate_poll);
David Daney80ff0fd2009-05-05 17:35:21 -0700362 /*
363 * Due to GMX errata in CN3XXX series chips, it is necessary
Roel Kluin82c7c112009-09-18 12:59:22 -0700364 * to take the link down immediately when the PHY changes
David Daney80ff0fd2009-05-05 17:35:21 -0700365 * state. In order to do this we call the poll function every
366 * time the RGMII inband status changes. This may cause
367 * problems if the PHY doesn't implement inband status
368 * properly.
369 */
370 if (number_rgmii_ports == 0) {
371 r = request_irq(OCTEON_IRQ_RML, cvm_oct_rgmii_rml_interrupt,
372 IRQF_SHARED, "RGMII", &number_rgmii_ports);
Roel Kluin82c7c112009-09-18 12:59:22 -0700373 if (r != 0)
374 return r;
David Daney80ff0fd2009-05-05 17:35:21 -0700375 }
376 number_rgmii_ports++;
377
378 /*
379 * Only true RGMII ports need to be polled. In GMII mode, port
380 * 0 is really a RGMII port.
381 */
382 if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
383 && (priv->port == 0))
384 || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
385
386 if (!octeon_is_simulation()) {
387
388 union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
389 int interface = INTERFACE(priv->port);
390 int index = INDEX(priv->port);
391
392 /*
393 * Enable interrupts on inband status changes
394 * for this port.
395 */
Aaro Koskinen7cc4fa12013-09-05 21:44:01 +0300396 gmx_rx_int_en.u64 = 0;
David Daney80ff0fd2009-05-05 17:35:21 -0700397 gmx_rx_int_en.s.phy_dupx = 1;
398 gmx_rx_int_en.s.phy_link = 1;
399 gmx_rx_int_en.s.phy_spd = 1;
400 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
401 gmx_rx_int_en.u64);
David Daney80ff0fd2009-05-05 17:35:21 -0700402 }
403 }
404
405 return 0;
406}
407
408void cvm_oct_rgmii_uninit(struct net_device *dev)
409{
410 struct octeon_ethernet *priv = netdev_priv(dev);
Melike Yurtoglu5a2da4a2014-09-28 15:53:21 +0300411
David Daney80ff0fd2009-05-05 17:35:21 -0700412 cvm_oct_common_uninit(dev);
413
414 /*
415 * Only true RGMII ports need to be polled. In GMII mode, port
416 * 0 is really a RGMII port.
417 */
418 if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
419 && (priv->port == 0))
420 || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
421
422 if (!octeon_is_simulation()) {
423
424 union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
425 int interface = INTERFACE(priv->port);
426 int index = INDEX(priv->port);
427
428 /*
429 * Disable interrupts on inband status changes
430 * for this port.
431 */
432 gmx_rx_int_en.u64 =
433 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
434 (index, interface));
435 gmx_rx_int_en.s.phy_dupx = 0;
436 gmx_rx_int_en.s.phy_link = 0;
437 gmx_rx_int_en.s.phy_spd = 0;
438 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
439 gmx_rx_int_en.u64);
440 }
441 }
442
443 /* Remove the interrupt handler when the last port is removed. */
444 number_rgmii_ports--;
445 if (number_rgmii_ports == 0)
446 free_irq(OCTEON_IRQ_RML, &number_rgmii_ports);
David Daneyf8c26482010-02-15 12:13:17 -0800447 cancel_work_sync(&priv->port_work);
David Daney80ff0fd2009-05-05 17:35:21 -0700448}