1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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>
32#include <net/dst.h>
33
34#include <asm/octeon/octeon.h>
35
36#include "ethernet-defines.h"
37#include "octeon-ethernet.h"
38#include "ethernet-util.h"
39
40#include <asm/octeon/cvmx-helper.h>
41
42#include <asm/octeon/cvmx-ipd-defs.h>
43#include <asm/octeon/cvmx-npi-defs.h>
44#include <asm/octeon/cvmx-gmxx-defs.h>
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);
53 unsigned long flags = 0;
54 cvmx_helper_link_info_t link_info;
55 int use_global_register_lock = (priv->phydev == NULL);
56
57 BUG_ON(in_interrupt());
58 if (use_global_register_lock) {
59
60
61
62
63 spin_lock_irqsave(&global_register_lock, flags);
64 } else {
65 mutex_lock(&priv->phydev->bus->mdio_lock);
66 }
67
68 link_info = cvmx_helper_link_get(priv->port);
69 if (link_info.u64 == priv->link_info) {
70
71
72
73
74
75 if (USE_10MBPS_PREAMBLE_WORKAROUND && (link_info.s.speed == 10)) {
76
77
78
79
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
91
92
93
94
95
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
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
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
118 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
119 (index, interface),
120 gmxx_rxx_int_reg.u64);
121 printk_ratelimited("%s: Using 10Mbps with software "
122 "preamble removal\n",
123 dev->name);
124 }
125 }
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);
131 return;
132 }
133
134
135
136
137
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
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
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
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 }
162 if (priv->phydev == NULL) {
163 link_info = cvmx_helper_link_autoconf(priv->port);
164 priv->link_info = link_info.u64;
165 }
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 }
172
173 if (priv->phydev == NULL) {
174
175 if (link_info.s.link_up) {
176 if (!netif_carrier_ok(dev))
177 netif_carrier_on(dev);
178 if (priv->queue != -1)
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);
185 else
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);
192 } else {
193 if (netif_carrier_ok(dev))
194 netif_carrier_off(dev);
195 printk_ratelimited("%s: Link down\n", dev->name);
196 }
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
209 if (rsl_int_blocks.s.gmx0) {
210
211 int interface = 0;
212
213 for (index = 0;
214 index < cvmx_helper_ports_on_interface(interface);
215 index++) {
216
217
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
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)];
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
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
251 if (rsl_int_blocks.s.gmx1) {
252
253 int interface = 1;
254
255 for (index = 0;
256 index < cvmx_helper_ports_on_interface(interface);
257 index++) {
258
259
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
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)];
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
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
294int cvm_oct_rgmii_open(struct net_device *dev)
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
315int cvm_oct_rgmii_stop(struct net_device *dev)
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
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
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);
340 dev->netdev_ops->ndo_stop(dev);
341 INIT_WORK(&priv->port_work, cvm_oct_rgmii_immediate_poll);
342
343
344
345
346
347
348
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);
353 if (r != 0)
354 return r;
355 }
356 number_rgmii_ports++;
357
358
359
360
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
374
375
376 gmx_rx_int_en.u64 = 0;
377 gmx_rx_int_en.s.phy_dupx = 1;
378 gmx_rx_int_en.s.phy_link = 1;
379 gmx_rx_int_en.s.phy_spd = 1;
380 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
381 gmx_rx_int_en.u64);
382 priv->poll = cvm_oct_rgmii_poll;
383 }
384 }
385
386 return 0;
387}
388
389void cvm_oct_rgmii_uninit(struct net_device *dev)
390{
391 struct octeon_ethernet *priv = netdev_priv(dev);
392 cvm_oct_common_uninit(dev);
393
394
395
396
397
398 if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
399 && (priv->port == 0))
400 || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
401
402 if (!octeon_is_simulation()) {
403
404 union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
405 int interface = INTERFACE(priv->port);
406 int index = INDEX(priv->port);
407
408
409
410
411
412 gmx_rx_int_en.u64 =
413 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
414 (index, interface));
415 gmx_rx_int_en.s.phy_dupx = 0;
416 gmx_rx_int_en.s.phy_link = 0;
417 gmx_rx_int_en.s.phy_spd = 0;
418 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
419 gmx_rx_int_en.u64);
420 }
421 }
422
423
424 number_rgmii_ports--;
425 if (number_rgmii_ports == 0)
426 free_irq(OCTEON_IRQ_RML, &number_rgmii_ports);
427 cancel_work_sync(&priv->port_work);
428}
429