Merge tag 'late-mvebu-rebased' of git://git.kernel.org/pub/scm/linux/kernel/git/arm...
[deliverable/linux.git] / drivers / staging / octeon / ethernet-rgmii.c
CommitLineData
80ff0fd3
DD
1/*********************************************************************
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>
048316be 29#include <linux/interrupt.h>
f8c26486 30#include <linux/phy.h>
7a2eaf93 31#include <linux/ratelimit.h>
80ff0fd3
DD
32#include <net/dst.h>
33
34#include <asm/octeon/octeon.h>
35
36#include "ethernet-defines.h"
37#include "octeon-ethernet.h"
80ff0fd3
DD
38#include "ethernet-util.h"
39
af866496 40#include <asm/octeon/cvmx-helper.h>
80ff0fd3
DD
41
42#include <asm/octeon/cvmx-ipd-defs.h>
43#include <asm/octeon/cvmx-npi-defs.h>
af866496 44#include <asm/octeon/cvmx-gmxx-defs.h>
80ff0fd3
DD
45
46DEFINE_SPINLOCK(global_register_lock);
47
48static int number_rgmii_ports;
49
50static void cvm_oct_rgmii_poll(struct net_device *dev)
51{
52 struct octeon_ethernet *priv = netdev_priv(dev);
f8c26486 53 unsigned long flags = 0;
80ff0fd3 54 cvmx_helper_link_info_t link_info;
f8c26486 55 int use_global_register_lock = (priv->phydev == NULL);
80ff0fd3 56
f8c26486
DD
57 BUG_ON(in_interrupt());
58 if (use_global_register_lock) {
59 /*
60 * Take the global register lock since we are going to
61 * touch registers that affect more than one port.
62 */
63 spin_lock_irqsave(&global_register_lock, flags);
64 } else {
65 mutex_lock(&priv->phydev->bus->mdio_lock);
66 }
80ff0fd3
DD
67
68 link_info = cvmx_helper_link_get(priv->port);
69 if (link_info.u64 == priv->link_info) {
70
71 /*
72 * If the 10Mbps preamble workaround is supported and we're
73 * at 10Mbps we may need to do some special checking.
74 */
75 if (USE_10MBPS_PREAMBLE_WORKAROUND && (link_info.s.speed == 10)) {
76
77 /*
78 * Read the GMXX_RXX_INT_REG[PCTERR] bit and
79 * see if we are getting preamble errors.
80 */
81 int interface = INTERFACE(priv->port);
82 int index = INDEX(priv->port);
83 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
84 gmxx_rxx_int_reg.u64 =
85 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
86 (index, interface));
87 if (gmxx_rxx_int_reg.s.pcterr) {
88
89 /*
90 * We are getting preamble errors at
91 * 10Mbps. Most likely the PHY is
92 * giving us packets with mis aligned
93 * preambles. In order to get these
94 * packets we need to disable preamble
95 * checking and do it in software.
96 */
97 union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
98 union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
99
100 /* Disable preamble checking */
101 gmxx_rxx_frm_ctl.u64 =
102 cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL
103 (index, interface));
104 gmxx_rxx_frm_ctl.s.pre_chk = 0;
105 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL
106 (index, interface),
107 gmxx_rxx_frm_ctl.u64);
108
109 /* Disable FCS stripping */
110 ipd_sub_port_fcs.u64 =
111 cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
112 ipd_sub_port_fcs.s.port_bit &=
113 0xffffffffull ^ (1ull << priv->port);
114 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS,
115 ipd_sub_port_fcs.u64);
116
117 /* Clear any error bits */
118 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
119 (index, interface),
120 gmxx_rxx_int_reg.u64);
7a2eaf93
CD
121 printk_ratelimited("%s: Using 10Mbps with software "
122 "preamble removal\n",
123 dev->name);
80ff0fd3
DD
124 }
125 }
f8c26486
DD
126
127 if (use_global_register_lock)
128 spin_unlock_irqrestore(&global_register_lock, flags);
129 else
130 mutex_unlock(&priv->phydev->bus->mdio_lock);
80ff0fd3
DD
131 return;
132 }
133
134 /* If the 10Mbps preamble workaround is allowed we need to on
135 preamble checking, FCS stripping, and clear error bits on
136 every speed change. If errors occur during 10Mbps operation
137 the above code will change this stuff */
138 if (USE_10MBPS_PREAMBLE_WORKAROUND) {
139
140 union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
141 union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
142 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
143 int interface = INTERFACE(priv->port);
144 int index = INDEX(priv->port);
145
146 /* Enable preamble checking */
147 gmxx_rxx_frm_ctl.u64 =
148 cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface));
149 gmxx_rxx_frm_ctl.s.pre_chk = 1;
150 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface),
151 gmxx_rxx_frm_ctl.u64);
152 /* Enable FCS stripping */
153 ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
154 ipd_sub_port_fcs.s.port_bit |= 1ull << priv->port;
155 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
156 /* Clear any error bits */
157 gmxx_rxx_int_reg.u64 =
158 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index, interface));
159 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
160 gmxx_rxx_int_reg.u64);
161 }
f6ed1b3b
DD
162 if (priv->phydev == NULL) {
163 link_info = cvmx_helper_link_autoconf(priv->port);
164 priv->link_info = link_info.u64;
165 }
f8c26486
DD
166
167 if (use_global_register_lock)
168 spin_unlock_irqrestore(&global_register_lock, flags);
169 else {
170 mutex_unlock(&priv->phydev->bus->mdio_lock);
171 }
80ff0fd3 172
f6ed1b3b
DD
173 if (priv->phydev == NULL) {
174 /* Tell core. */
175 if (link_info.s.link_up) {
176 if (!netif_carrier_ok(dev))
177 netif_carrier_on(dev);
178 if (priv->queue != -1)
7a2eaf93
CD
179 printk_ratelimited("%s: %u Mbps %s duplex, "
180 "port %2d, queue %2d\n",
181 dev->name, link_info.s.speed,
182 (link_info.s.full_duplex) ?
183 "Full" : "Half",
184 priv->port, priv->queue);
f6ed1b3b 185 else
7a2eaf93
CD
186 printk_ratelimited("%s: %u Mbps %s duplex, "
187 "port %2d, POW\n",
188 dev->name, link_info.s.speed,
189 (link_info.s.full_duplex) ?
190 "Full" : "Half",
191 priv->port);
f6ed1b3b
DD
192 } else {
193 if (netif_carrier_ok(dev))
194 netif_carrier_off(dev);
7a2eaf93 195 printk_ratelimited("%s: Link down\n", dev->name);
f6ed1b3b 196 }
80ff0fd3
DD
197 }
198}
199
200static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id)
201{
202 union cvmx_npi_rsl_int_blocks rsl_int_blocks;
203 int index;
204 irqreturn_t return_status = IRQ_NONE;
205
206 rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
207
208 /* Check and see if this interrupt was caused by the GMX0 block */
209 if (rsl_int_blocks.s.gmx0) {
210
211 int interface = 0;
212 /* Loop through every port of this interface */
213 for (index = 0;
214 index < cvmx_helper_ports_on_interface(interface);
215 index++) {
216
217 /* Read the GMX interrupt status bits */
218 union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
219 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)];
f8c26486
DD
233 struct octeon_ethernet *priv = netdev_priv(dev);
234
235 if (dev && !atomic_read(&cvm_oct_poll_queue_stopping))
236 queue_work(cvm_oct_poll_queue, &priv->port_work);
237
80ff0fd3
DD
238 gmx_rx_int_reg.u64 = 0;
239 gmx_rx_int_reg.s.phy_dupx = 1;
240 gmx_rx_int_reg.s.phy_link = 1;
241 gmx_rx_int_reg.s.phy_spd = 1;
242 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
243 (index, interface),
244 gmx_rx_int_reg.u64);
245 return_status = IRQ_HANDLED;
246 }
247 }
248 }
249
250 /* Check and see if this interrupt was caused by the GMX1 block */
251 if (rsl_int_blocks.s.gmx1) {
252
253 int interface = 1;
254 /* Loop through every port of this interface */
255 for (index = 0;
256 index < cvmx_helper_ports_on_interface(interface);
257 index++) {
258
259 /* Read the GMX interrupt status bits */
260 union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
261 gmx_rx_int_reg.u64 =
262 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
263 (index, interface));
264 gmx_rx_int_reg.u64 &=
265 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
266 (index, interface));
267 /* Poll the port if inband status changed */
268 if (gmx_rx_int_reg.s.phy_dupx
269 || gmx_rx_int_reg.s.phy_link
270 || gmx_rx_int_reg.s.phy_spd) {
271
272 struct net_device *dev =
273 cvm_oct_device[cvmx_helper_get_ipd_port
274 (interface, index)];
f8c26486
DD
275 struct octeon_ethernet *priv = netdev_priv(dev);
276
277 if (dev && !atomic_read(&cvm_oct_poll_queue_stopping))
278 queue_work(cvm_oct_poll_queue, &priv->port_work);
279
80ff0fd3
DD
280 gmx_rx_int_reg.u64 = 0;
281 gmx_rx_int_reg.s.phy_dupx = 1;
282 gmx_rx_int_reg.s.phy_link = 1;
283 gmx_rx_int_reg.s.phy_spd = 1;
284 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
285 (index, interface),
286 gmx_rx_int_reg.u64);
287 return_status = IRQ_HANDLED;
288 }
289 }
290 }
291 return return_status;
292}
293
f696a108 294int cvm_oct_rgmii_open(struct net_device *dev)
80ff0fd3
DD
295{
296 union cvmx_gmxx_prtx_cfg gmx_cfg;
297 struct octeon_ethernet *priv = netdev_priv(dev);
298 int interface = INTERFACE(priv->port);
299 int index = INDEX(priv->port);
300 cvmx_helper_link_info_t link_info;
301
302 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
303 gmx_cfg.s.en = 1;
304 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
305
306 if (!octeon_is_simulation()) {
307 link_info = cvmx_helper_link_get(priv->port);
308 if (!link_info.s.link_up)
309 netif_carrier_off(dev);
310 }
311
312 return 0;
313}
314
f696a108 315int cvm_oct_rgmii_stop(struct net_device *dev)
80ff0fd3
DD
316{
317 union cvmx_gmxx_prtx_cfg gmx_cfg;
318 struct octeon_ethernet *priv = netdev_priv(dev);
319 int interface = INTERFACE(priv->port);
320 int index = INDEX(priv->port);
321
322 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
323 gmx_cfg.s.en = 0;
324 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
325 return 0;
326}
327
f8c26486
DD
328static void cvm_oct_rgmii_immediate_poll(struct work_struct *work)
329{
330 struct octeon_ethernet *priv = container_of(work, struct octeon_ethernet, port_work);
331 cvm_oct_rgmii_poll(cvm_oct_device[priv->port]);
332}
333
80ff0fd3
DD
334int cvm_oct_rgmii_init(struct net_device *dev)
335{
336 struct octeon_ethernet *priv = netdev_priv(dev);
337 int r;
338
339 cvm_oct_common_init(dev);
f696a108 340 dev->netdev_ops->ndo_stop(dev);
f8c26486 341 INIT_WORK(&priv->port_work, cvm_oct_rgmii_immediate_poll);
80ff0fd3
DD
342 /*
343 * Due to GMX errata in CN3XXX series chips, it is necessary
82c7c11f 344 * to take the link down immediately when the PHY changes
80ff0fd3
DD
345 * state. In order to do this we call the poll function every
346 * time the RGMII inband status changes. This may cause
347 * problems if the PHY doesn't implement inband status
348 * properly.
349 */
350 if (number_rgmii_ports == 0) {
351 r = request_irq(OCTEON_IRQ_RML, cvm_oct_rgmii_rml_interrupt,
352 IRQF_SHARED, "RGMII", &number_rgmii_ports);
82c7c11f
RK
353 if (r != 0)
354 return r;
80ff0fd3
DD
355 }
356 number_rgmii_ports++;
357
358 /*
359 * Only true RGMII ports need to be polled. In GMII mode, port
360 * 0 is really a RGMII port.
361 */
362 if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
363 && (priv->port == 0))
364 || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
365
366 if (!octeon_is_simulation()) {
367
368 union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
369 int interface = INTERFACE(priv->port);
370 int index = INDEX(priv->port);
371
372 /*
373 * Enable interrupts on inband status changes
374 * for this port.
375 */
376 gmx_rx_int_en.u64 =
377 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
378 (index, interface));
379 gmx_rx_int_en.s.phy_dupx = 1;
380 gmx_rx_int_en.s.phy_link = 1;
381 gmx_rx_int_en.s.phy_spd = 1;
382 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
383 gmx_rx_int_en.u64);
384 priv->poll = cvm_oct_rgmii_poll;
385 }
386 }
387
388 return 0;
389}
390
391void cvm_oct_rgmii_uninit(struct net_device *dev)
392{
393 struct octeon_ethernet *priv = netdev_priv(dev);
394 cvm_oct_common_uninit(dev);
395
396 /*
397 * Only true RGMII ports need to be polled. In GMII mode, port
398 * 0 is really a RGMII port.
399 */
400 if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
401 && (priv->port == 0))
402 || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
403
404 if (!octeon_is_simulation()) {
405
406 union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
407 int interface = INTERFACE(priv->port);
408 int index = INDEX(priv->port);
409
410 /*
411 * Disable interrupts on inband status changes
412 * for this port.
413 */
414 gmx_rx_int_en.u64 =
415 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
416 (index, interface));
417 gmx_rx_int_en.s.phy_dupx = 0;
418 gmx_rx_int_en.s.phy_link = 0;
419 gmx_rx_int_en.s.phy_spd = 0;
420 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
421 gmx_rx_int_en.u64);
422 }
423 }
424
425 /* Remove the interrupt handler when the last port is removed. */
426 number_rgmii_ports--;
427 if (number_rgmii_ports == 0)
428 free_irq(OCTEON_IRQ_RML, &number_rgmii_ports);
f8c26486 429 cancel_work_sync(&priv->port_work);
80ff0fd3 430}
This page took 0.292804 seconds and 5 git commands to generate.