blob: 51dcb611702f1fd1f274e989a57dd14fda85982e [file] [log] [blame]
Aaro Koskinen67620982015-04-04 22:51:21 +03001/*
2 * This file is based on code from OCTEON SDK by Cavium Networks.
David Daney80ff0fd2009-05-05 17:35:21 -07003 *
4 * Copyright (c) 2003-2007 Cavium Networks
5 *
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.
Aaro Koskinen67620982015-04-04 22:51:21 +03009 */
10
David Daney80ff0fd2009-05-05 17:35:21 -070011#include <linux/kernel.h>
12#include <linux/netdevice.h>
David Daney048316b2011-08-16 10:10:56 -070013#include <linux/interrupt.h>
David Daneyf8c26482010-02-15 12:13:17 -080014#include <linux/phy.h>
Christian Dietrich7a2eaf92011-06-04 17:35:58 +020015#include <linux/ratelimit.h>
David Daney80ff0fd2009-05-05 17:35:21 -070016#include <net/dst.h>
17
18#include <asm/octeon/octeon.h>
19
20#include "ethernet-defines.h"
21#include "octeon-ethernet.h"
David Daney80ff0fd2009-05-05 17:35:21 -070022#include "ethernet-util.h"
David Daneyec3a2202014-05-29 11:10:02 +010023#include "ethernet-mdio.h"
David Daney80ff0fd2009-05-05 17:35:21 -070024
David Daneyaf866492011-11-22 14:47:00 +000025#include <asm/octeon/cvmx-helper.h>
David Daney80ff0fd2009-05-05 17:35:21 -070026
27#include <asm/octeon/cvmx-ipd-defs.h>
28#include <asm/octeon/cvmx-npi-defs.h>
David Daneyaf866492011-11-22 14:47:00 +000029#include <asm/octeon/cvmx-gmxx-defs.h>
David Daney80ff0fd2009-05-05 17:35:21 -070030
Aaro Koskinen54bf9172014-03-02 00:09:08 +020031static DEFINE_SPINLOCK(global_register_lock);
David Daney80ff0fd2009-05-05 17:35:21 -070032
33static int number_rgmii_ports;
34
Aaro Koskinen01d30072015-04-04 22:51:10 +030035static void cvm_oct_set_hw_preamble(struct octeon_ethernet *priv, bool enable)
36{
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);
42
43 /* Set preamble checking. */
44 gmxx_rxx_frm_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index,
45 interface));
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);
49
50 /* Set FCS stripping. */
51 ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
52 if (enable)
53 ipd_sub_port_fcs.s.port_bit |= 1ull << priv->port;
54 else
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);
58
59 /* Clear any error bits. */
60 gmxx_rxx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index,
61 interface));
62 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
63 gmxx_rxx_int_reg.u64);
64}
65
David Daney80ff0fd2009-05-05 17:35:21 -070066static void cvm_oct_rgmii_poll(struct net_device *dev)
67{
68 struct octeon_ethernet *priv = netdev_priv(dev);
David Daneyf8c26482010-02-15 12:13:17 -080069 unsigned long flags = 0;
David Daney80ff0fd2009-05-05 17:35:21 -070070 cvmx_helper_link_info_t link_info;
David Daneyf8c26482010-02-15 12:13:17 -080071 int use_global_register_lock = (priv->phydev == NULL);
David Daney80ff0fd2009-05-05 17:35:21 -070072
David Daneyf8c26482010-02-15 12:13:17 -080073 BUG_ON(in_interrupt());
74 if (use_global_register_lock) {
75 /*
76 * Take the global register lock since we are going to
77 * touch registers that affect more than one port.
78 */
79 spin_lock_irqsave(&global_register_lock, flags);
80 } else {
81 mutex_lock(&priv->phydev->bus->mdio_lock);
82 }
David Daney80ff0fd2009-05-05 17:35:21 -070083
84 link_info = cvmx_helper_link_get(priv->port);
85 if (link_info.u64 == priv->link_info) {
Aaro Koskinen25efe082015-04-04 22:51:15 +030086 if (link_info.s.speed == 10) {
David Daney80ff0fd2009-05-05 17:35:21 -070087 /*
88 * Read the GMXX_RXX_INT_REG[PCTERR] bit and
89 * see if we are getting preamble errors.
90 */
91 int interface = INTERFACE(priv->port);
92 int index = INDEX(priv->port);
93 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
Melike Yurtoglu5a2da4a2014-09-28 15:53:21 +030094
David Daney80ff0fd2009-05-05 17:35:21 -070095 gmxx_rxx_int_reg.u64 =
96 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
97 (index, interface));
98 if (gmxx_rxx_int_reg.s.pcterr) {
David Daney80ff0fd2009-05-05 17:35:21 -070099 /*
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.
106 */
Aaro Koskinen01d30072015-04-04 22:51:10 +0300107 cvm_oct_set_hw_preamble(priv, false);
Gulsah Kose42e0e192014-09-30 22:12:22 +0300108 printk_ratelimited("%s: Using 10Mbps with software preamble removal\n",
Christian Dietrich7a2eaf92011-06-04 17:35:58 +0200109 dev->name);
David Daney80ff0fd2009-05-05 17:35:21 -0700110 }
111 }
David Daneyf8c26482010-02-15 12:13:17 -0800112
113 if (use_global_register_lock)
114 spin_unlock_irqrestore(&global_register_lock, flags);
115 else
116 mutex_unlock(&priv->phydev->bus->mdio_lock);
David Daney80ff0fd2009-05-05 17:35:21 -0700117 return;
118 }
119
Aaro Koskinen25efe082015-04-04 22:51:15 +0300120 /* Since the 10Mbps preamble workaround is allowed we need to enable
Okash Khawajae2622fb2015-08-05 21:13:52 +0100121 * 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
124 */
Aaro Koskinen25efe082015-04-04 22:51:15 +0300125 cvm_oct_set_hw_preamble(priv, true);
David Daney80ff0fd2009-05-05 17:35:21 -0700126
David Daneyf6ed1b32009-10-14 12:04:42 -0700127 if (priv->phydev == NULL) {
128 link_info = cvmx_helper_link_autoconf(priv->port);
129 priv->link_info = link_info.u64;
130 }
David Daneyf8c26482010-02-15 12:13:17 -0800131
132 if (use_global_register_lock)
133 spin_unlock_irqrestore(&global_register_lock, flags);
bahar sahin4504b1b2014-03-03 03:56:03 +0200134 else
David Daneyf8c26482010-02-15 12:13:17 -0800135 mutex_unlock(&priv->phydev->bus->mdio_lock);
David Daney80ff0fd2009-05-05 17:35:21 -0700136
David Daneyf6ed1b32009-10-14 12:04:42 -0700137 if (priv->phydev == NULL) {
138 /* Tell core. */
139 if (link_info.s.link_up) {
140 if (!netif_carrier_ok(dev))
141 netif_carrier_on(dev);
Aaro Koskinen2638f712015-04-04 22:51:07 +0300142 } else if (netif_carrier_ok(dev)) {
143 netif_carrier_off(dev);
David Daneyf6ed1b32009-10-14 12:04:42 -0700144 }
Aaro Koskinen2638f712015-04-04 22:51:07 +0300145 cvm_oct_note_carrier(priv, link_info);
David Daney80ff0fd2009-05-05 17:35:21 -0700146 }
147}
148
Aaro Koskinen67d2ee22015-04-04 22:51:09 +0300149static int cmv_oct_rgmii_gmx_interrupt(int interface)
150{
151 int index;
152 int count = 0;
153
154 /* Loop through every port of this interface */
155 for (index = 0;
156 index < cvmx_helper_ports_on_interface(interface);
157 index++) {
158 union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
159
160 /* Read the GMX interrupt status bits */
161 gmx_rx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
162 (index, interface));
163 gmx_rx_int_reg.u64 &= cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
164 (index, interface));
165
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
171 (interface, index)];
172 struct octeon_ethernet *priv = netdev_priv(dev);
173
174 if (dev && !atomic_read(&cvm_oct_poll_queue_stopping))
175 queue_work(cvm_oct_poll_queue,
176 &priv->port_work);
177
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),
183 gmx_rx_int_reg.u64);
184 count++;
185 }
186 }
187 return count;
188}
189
David Daney80ff0fd2009-05-05 17:35:21 -0700190static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id)
191{
192 union cvmx_npi_rsl_int_blocks rsl_int_blocks;
Aaro Koskinen67d2ee22015-04-04 22:51:09 +0300193 int count = 0;
David Daney80ff0fd2009-05-05 17:35:21 -0700194
195 rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
196
197 /* Check and see if this interrupt was caused by the GMX0 block */
Aaro Koskinen67d2ee22015-04-04 22:51:09 +0300198 if (rsl_int_blocks.s.gmx0)
199 count += cmv_oct_rgmii_gmx_interrupt(0);
David Daney80ff0fd2009-05-05 17:35:21 -0700200
201 /* Check and see if this interrupt was caused by the GMX1 block */
Aaro Koskinen67d2ee22015-04-04 22:51:09 +0300202 if (rsl_int_blocks.s.gmx1)
203 count += cmv_oct_rgmii_gmx_interrupt(1);
David Daney80ff0fd2009-05-05 17:35:21 -0700204
Aaro Koskinen67d2ee22015-04-04 22:51:09 +0300205 return count ? IRQ_HANDLED : IRQ_NONE;
David Daney80ff0fd2009-05-05 17:35:21 -0700206}
207
David Daneyf696a102009-06-23 11:34:08 -0700208int cvm_oct_rgmii_open(struct net_device *dev)
David Daney80ff0fd2009-05-05 17:35:21 -0700209{
Aaro Koskinen9e3ae4f2015-04-04 22:51:02 +0300210 return cvm_oct_common_open(dev, cvm_oct_rgmii_poll, false);
David Daney80ff0fd2009-05-05 17:35:21 -0700211}
212
David Daneyf8c26482010-02-15 12:13:17 -0800213static void cvm_oct_rgmii_immediate_poll(struct work_struct *work)
214{
Aybuke Ozdemirf09d1442014-03-18 21:13:29 +0200215 struct octeon_ethernet *priv =
216 container_of(work, struct octeon_ethernet, port_work);
David Daneyf8c26482010-02-15 12:13:17 -0800217 cvm_oct_rgmii_poll(cvm_oct_device[priv->port]);
218}
219
David Daney80ff0fd2009-05-05 17:35:21 -0700220int cvm_oct_rgmii_init(struct net_device *dev)
221{
222 struct octeon_ethernet *priv = netdev_priv(dev);
223 int r;
224
225 cvm_oct_common_init(dev);
David Daneyf8c26482010-02-15 12:13:17 -0800226 INIT_WORK(&priv->port_work, cvm_oct_rgmii_immediate_poll);
David Daney80ff0fd2009-05-05 17:35:21 -0700227 /*
228 * Due to GMX errata in CN3XXX series chips, it is necessary
Roel Kluin82c7c112009-09-18 12:59:22 -0700229 * to take the link down immediately when the PHY changes
David Daney80ff0fd2009-05-05 17:35:21 -0700230 * 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
233 * properly.
234 */
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);
Roel Kluin82c7c112009-09-18 12:59:22 -0700238 if (r != 0)
239 return r;
David Daney80ff0fd2009-05-05 17:35:21 -0700240 }
241 number_rgmii_ports++;
242
243 /*
244 * Only true RGMII ports need to be polled. In GMII mode, port
245 * 0 is really a RGMII port.
246 */
247 if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
248 && (priv->port == 0))
249 || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
250
251 if (!octeon_is_simulation()) {
252
253 union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
254 int interface = INTERFACE(priv->port);
255 int index = INDEX(priv->port);
256
257 /*
258 * Enable interrupts on inband status changes
259 * for this port.
260 */
Aaro Koskinen7cc4fa12013-09-05 21:44:01 +0300261 gmx_rx_int_en.u64 = 0;
David Daney80ff0fd2009-05-05 17:35:21 -0700262 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),
266 gmx_rx_int_en.u64);
David Daney80ff0fd2009-05-05 17:35:21 -0700267 }
268 }
269
270 return 0;
271}
272
273void cvm_oct_rgmii_uninit(struct net_device *dev)
274{
275 struct octeon_ethernet *priv = netdev_priv(dev);
Melike Yurtoglu5a2da4a2014-09-28 15:53:21 +0300276
David Daney80ff0fd2009-05-05 17:35:21 -0700277 cvm_oct_common_uninit(dev);
278
279 /*
280 * Only true RGMII ports need to be polled. In GMII mode, port
281 * 0 is really a RGMII port.
282 */
283 if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
284 && (priv->port == 0))
285 || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
286
287 if (!octeon_is_simulation()) {
288
289 union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
290 int interface = INTERFACE(priv->port);
291 int index = INDEX(priv->port);
292
293 /*
294 * Disable interrupts on inband status changes
295 * for this port.
296 */
297 gmx_rx_int_en.u64 =
298 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
299 (index, interface));
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),
304 gmx_rx_int_en.u64);
305 }
306 }
307
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);
David Daneyf8c26482010-02-15 12:13:17 -0800312 cancel_work_sync(&priv->port_work);
David Daney80ff0fd2009-05-05 17:35:21 -0700313}