1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * EP93xx ethernet network device driver |
4 | * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> |
5 | * Dedicated to Marija Kulikova. |
6 | */ |
7 | |
8 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ |
9 | |
10 | #include <linux/dma-mapping.h> |
11 | #include <linux/module.h> |
12 | #include <linux/kernel.h> |
13 | #include <linux/netdevice.h> |
14 | #include <linux/mii.h> |
15 | #include <linux/etherdevice.h> |
16 | #include <linux/ethtool.h> |
17 | #include <linux/interrupt.h> |
18 | #include <linux/moduleparam.h> |
19 | #include <linux/platform_device.h> |
20 | #include <linux/delay.h> |
21 | #include <linux/io.h> |
22 | #include <linux/slab.h> |
23 | |
24 | #include <linux/platform_data/eth-ep93xx.h> |
25 | |
26 | #define DRV_MODULE_NAME "ep93xx-eth" |
27 | |
28 | #define RX_QUEUE_ENTRIES 64 |
29 | #define TX_QUEUE_ENTRIES 8 |
30 | |
31 | #define MAX_PKT_SIZE 2044 |
32 | #define PKT_BUF_SIZE 2048 |
33 | |
34 | #define REG_RXCTL 0x0000 |
35 | #define REG_RXCTL_DEFAULT 0x00073800 |
36 | #define REG_TXCTL 0x0004 |
37 | #define REG_TXCTL_ENABLE 0x00000001 |
38 | #define REG_MIICMD 0x0010 |
39 | #define REG_MIICMD_READ 0x00008000 |
40 | #define REG_MIICMD_WRITE 0x00004000 |
41 | #define REG_MIIDATA 0x0014 |
42 | #define REG_MIISTS 0x0018 |
43 | #define REG_MIISTS_BUSY 0x00000001 |
44 | #define REG_SELFCTL 0x0020 |
45 | #define REG_SELFCTL_RESET 0x00000001 |
46 | #define REG_INTEN 0x0024 |
47 | #define REG_INTEN_TX 0x00000008 |
48 | #define REG_INTEN_RX 0x00000007 |
49 | #define REG_INTSTSP 0x0028 |
50 | #define REG_INTSTS_TX 0x00000008 |
51 | #define REG_INTSTS_RX 0x00000004 |
52 | #define REG_INTSTSC 0x002c |
53 | #define REG_AFP 0x004c |
54 | #define REG_INDAD0 0x0050 |
55 | #define REG_INDAD1 0x0051 |
56 | #define REG_INDAD2 0x0052 |
57 | #define REG_INDAD3 0x0053 |
58 | #define REG_INDAD4 0x0054 |
59 | #define REG_INDAD5 0x0055 |
60 | #define REG_GIINTMSK 0x0064 |
61 | #define REG_GIINTMSK_ENABLE 0x00008000 |
62 | #define REG_BMCTL 0x0080 |
63 | #define REG_BMCTL_ENABLE_TX 0x00000100 |
64 | #define REG_BMCTL_ENABLE_RX 0x00000001 |
65 | #define REG_BMSTS 0x0084 |
66 | #define REG_BMSTS_RX_ACTIVE 0x00000008 |
67 | #define REG_RXDQBADD 0x0090 |
68 | #define REG_RXDQBLEN 0x0094 |
69 | #define REG_RXDCURADD 0x0098 |
70 | #define REG_RXDENQ 0x009c |
71 | #define REG_RXSTSQBADD 0x00a0 |
72 | #define REG_RXSTSQBLEN 0x00a4 |
73 | #define REG_RXSTSQCURADD 0x00a8 |
74 | #define REG_RXSTSENQ 0x00ac |
75 | #define REG_TXDQBADD 0x00b0 |
76 | #define REG_TXDQBLEN 0x00b4 |
77 | #define REG_TXDQCURADD 0x00b8 |
78 | #define REG_TXDENQ 0x00bc |
79 | #define REG_TXSTSQBADD 0x00c0 |
80 | #define REG_TXSTSQBLEN 0x00c4 |
81 | #define REG_TXSTSQCURADD 0x00c8 |
82 | #define REG_MAXFRMLEN 0x00e8 |
83 | |
84 | struct ep93xx_rdesc |
85 | { |
86 | u32 buf_addr; |
87 | u32 rdesc1; |
88 | }; |
89 | |
90 | #define RDESC1_NSOF 0x80000000 |
91 | #define RDESC1_BUFFER_INDEX 0x7fff0000 |
92 | #define RDESC1_BUFFER_LENGTH 0x0000ffff |
93 | |
94 | struct ep93xx_rstat |
95 | { |
96 | u32 rstat0; |
97 | u32 rstat1; |
98 | }; |
99 | |
100 | #define RSTAT0_RFP 0x80000000 |
101 | #define RSTAT0_RWE 0x40000000 |
102 | #define RSTAT0_EOF 0x20000000 |
103 | #define RSTAT0_EOB 0x10000000 |
104 | #define RSTAT0_AM 0x00c00000 |
105 | #define RSTAT0_RX_ERR 0x00200000 |
106 | #define RSTAT0_OE 0x00100000 |
107 | #define RSTAT0_FE 0x00080000 |
108 | #define RSTAT0_RUNT 0x00040000 |
109 | #define RSTAT0_EDATA 0x00020000 |
110 | #define RSTAT0_CRCE 0x00010000 |
111 | #define RSTAT0_CRCI 0x00008000 |
112 | #define RSTAT0_HTI 0x00003f00 |
113 | #define RSTAT1_RFP 0x80000000 |
114 | #define RSTAT1_BUFFER_INDEX 0x7fff0000 |
115 | #define RSTAT1_FRAME_LENGTH 0x0000ffff |
116 | |
117 | struct ep93xx_tdesc |
118 | { |
119 | u32 buf_addr; |
120 | u32 tdesc1; |
121 | }; |
122 | |
123 | #define TDESC1_EOF 0x80000000 |
124 | #define TDESC1_BUFFER_INDEX 0x7fff0000 |
125 | #define TDESC1_BUFFER_ABORT 0x00008000 |
126 | #define TDESC1_BUFFER_LENGTH 0x00000fff |
127 | |
128 | struct ep93xx_tstat |
129 | { |
130 | u32 tstat0; |
131 | }; |
132 | |
133 | #define TSTAT0_TXFP 0x80000000 |
134 | #define TSTAT0_TXWE 0x40000000 |
135 | #define TSTAT0_FA 0x20000000 |
136 | #define TSTAT0_LCRS 0x10000000 |
137 | #define TSTAT0_OW 0x04000000 |
138 | #define TSTAT0_TXU 0x02000000 |
139 | #define TSTAT0_ECOLL 0x01000000 |
140 | #define TSTAT0_NCOLL 0x001f0000 |
141 | #define TSTAT0_BUFFER_INDEX 0x00007fff |
142 | |
143 | struct ep93xx_descs |
144 | { |
145 | struct ep93xx_rdesc rdesc[RX_QUEUE_ENTRIES]; |
146 | struct ep93xx_tdesc tdesc[TX_QUEUE_ENTRIES]; |
147 | struct ep93xx_rstat rstat[RX_QUEUE_ENTRIES]; |
148 | struct ep93xx_tstat tstat[TX_QUEUE_ENTRIES]; |
149 | }; |
150 | |
151 | struct ep93xx_priv |
152 | { |
153 | struct resource *res; |
154 | void __iomem *base_addr; |
155 | int irq; |
156 | |
157 | struct ep93xx_descs *descs; |
158 | dma_addr_t descs_dma_addr; |
159 | |
160 | void *rx_buf[RX_QUEUE_ENTRIES]; |
161 | void *tx_buf[TX_QUEUE_ENTRIES]; |
162 | |
163 | spinlock_t rx_lock; |
164 | unsigned int rx_pointer; |
165 | unsigned int tx_clean_pointer; |
166 | unsigned int tx_pointer; |
167 | spinlock_t tx_pending_lock; |
168 | unsigned int tx_pending; |
169 | |
170 | struct net_device *dev; |
171 | struct napi_struct napi; |
172 | |
173 | struct mii_if_info mii; |
174 | u8 mdc_divisor; |
175 | }; |
176 | |
177 | #define rdb(ep, off) __raw_readb((ep)->base_addr + (off)) |
178 | #define rdw(ep, off) __raw_readw((ep)->base_addr + (off)) |
179 | #define rdl(ep, off) __raw_readl((ep)->base_addr + (off)) |
180 | #define wrb(ep, off, val) __raw_writeb((val), (ep)->base_addr + (off)) |
181 | #define wrw(ep, off, val) __raw_writew((val), (ep)->base_addr + (off)) |
182 | #define wrl(ep, off, val) __raw_writel((val), (ep)->base_addr + (off)) |
183 | |
184 | static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg) |
185 | { |
186 | struct ep93xx_priv *ep = netdev_priv(dev); |
187 | int data; |
188 | int i; |
189 | |
190 | wrl(ep, REG_MIICMD, REG_MIICMD_READ | (phy_id << 5) | reg); |
191 | |
192 | for (i = 0; i < 10; i++) { |
193 | if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0) |
194 | break; |
195 | msleep(msecs: 1); |
196 | } |
197 | |
198 | if (i == 10) { |
199 | pr_info("mdio read timed out\n" ); |
200 | data = 0xffff; |
201 | } else { |
202 | data = rdl(ep, REG_MIIDATA); |
203 | } |
204 | |
205 | return data; |
206 | } |
207 | |
208 | static void ep93xx_mdio_write(struct net_device *dev, int phy_id, int reg, int data) |
209 | { |
210 | struct ep93xx_priv *ep = netdev_priv(dev); |
211 | int i; |
212 | |
213 | wrl(ep, REG_MIIDATA, data); |
214 | wrl(ep, REG_MIICMD, REG_MIICMD_WRITE | (phy_id << 5) | reg); |
215 | |
216 | for (i = 0; i < 10; i++) { |
217 | if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0) |
218 | break; |
219 | msleep(msecs: 1); |
220 | } |
221 | |
222 | if (i == 10) |
223 | pr_info("mdio write timed out\n" ); |
224 | } |
225 | |
226 | static int ep93xx_rx(struct net_device *dev, int budget) |
227 | { |
228 | struct ep93xx_priv *ep = netdev_priv(dev); |
229 | int processed = 0; |
230 | |
231 | while (processed < budget) { |
232 | int entry; |
233 | struct ep93xx_rstat *rstat; |
234 | u32 rstat0; |
235 | u32 rstat1; |
236 | int length; |
237 | struct sk_buff *skb; |
238 | |
239 | entry = ep->rx_pointer; |
240 | rstat = ep->descs->rstat + entry; |
241 | |
242 | rstat0 = rstat->rstat0; |
243 | rstat1 = rstat->rstat1; |
244 | if (!(rstat0 & RSTAT0_RFP) || !(rstat1 & RSTAT1_RFP)) |
245 | break; |
246 | |
247 | rstat->rstat0 = 0; |
248 | rstat->rstat1 = 0; |
249 | |
250 | if (!(rstat0 & RSTAT0_EOF)) |
251 | pr_crit("not end-of-frame %.8x %.8x\n" , rstat0, rstat1); |
252 | if (!(rstat0 & RSTAT0_EOB)) |
253 | pr_crit("not end-of-buffer %.8x %.8x\n" , rstat0, rstat1); |
254 | if ((rstat1 & RSTAT1_BUFFER_INDEX) >> 16 != entry) |
255 | pr_crit("entry mismatch %.8x %.8x\n" , rstat0, rstat1); |
256 | |
257 | if (!(rstat0 & RSTAT0_RWE)) { |
258 | dev->stats.rx_errors++; |
259 | if (rstat0 & RSTAT0_OE) |
260 | dev->stats.rx_fifo_errors++; |
261 | if (rstat0 & RSTAT0_FE) |
262 | dev->stats.rx_frame_errors++; |
263 | if (rstat0 & (RSTAT0_RUNT | RSTAT0_EDATA)) |
264 | dev->stats.rx_length_errors++; |
265 | if (rstat0 & RSTAT0_CRCE) |
266 | dev->stats.rx_crc_errors++; |
267 | goto err; |
268 | } |
269 | |
270 | length = rstat1 & RSTAT1_FRAME_LENGTH; |
271 | if (length > MAX_PKT_SIZE) { |
272 | pr_notice("invalid length %.8x %.8x\n" , rstat0, rstat1); |
273 | goto err; |
274 | } |
275 | |
276 | /* Strip FCS. */ |
277 | if (rstat0 & RSTAT0_CRCI) |
278 | length -= 4; |
279 | |
280 | skb = netdev_alloc_skb(dev, length: length + 2); |
281 | if (likely(skb != NULL)) { |
282 | struct ep93xx_rdesc *rxd = &ep->descs->rdesc[entry]; |
283 | skb_reserve(skb, len: 2); |
284 | dma_sync_single_for_cpu(dev: dev->dev.parent, addr: rxd->buf_addr, |
285 | size: length, dir: DMA_FROM_DEVICE); |
286 | skb_copy_to_linear_data(skb, from: ep->rx_buf[entry], len: length); |
287 | dma_sync_single_for_device(dev: dev->dev.parent, |
288 | addr: rxd->buf_addr, size: length, |
289 | dir: DMA_FROM_DEVICE); |
290 | skb_put(skb, len: length); |
291 | skb->protocol = eth_type_trans(skb, dev); |
292 | |
293 | napi_gro_receive(napi: &ep->napi, skb); |
294 | |
295 | dev->stats.rx_packets++; |
296 | dev->stats.rx_bytes += length; |
297 | } else { |
298 | dev->stats.rx_dropped++; |
299 | } |
300 | |
301 | err: |
302 | ep->rx_pointer = (entry + 1) & (RX_QUEUE_ENTRIES - 1); |
303 | processed++; |
304 | } |
305 | |
306 | return processed; |
307 | } |
308 | |
309 | static int ep93xx_poll(struct napi_struct *napi, int budget) |
310 | { |
311 | struct ep93xx_priv *ep = container_of(napi, struct ep93xx_priv, napi); |
312 | struct net_device *dev = ep->dev; |
313 | int rx; |
314 | |
315 | rx = ep93xx_rx(dev, budget); |
316 | if (rx < budget && napi_complete_done(n: napi, work_done: rx)) { |
317 | spin_lock_irq(lock: &ep->rx_lock); |
318 | wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX); |
319 | spin_unlock_irq(lock: &ep->rx_lock); |
320 | } |
321 | |
322 | if (rx) { |
323 | wrw(ep, REG_RXDENQ, rx); |
324 | wrw(ep, REG_RXSTSENQ, rx); |
325 | } |
326 | |
327 | return rx; |
328 | } |
329 | |
330 | static netdev_tx_t ep93xx_xmit(struct sk_buff *skb, struct net_device *dev) |
331 | { |
332 | struct ep93xx_priv *ep = netdev_priv(dev); |
333 | struct ep93xx_tdesc *txd; |
334 | int entry; |
335 | |
336 | if (unlikely(skb->len > MAX_PKT_SIZE)) { |
337 | dev->stats.tx_dropped++; |
338 | dev_kfree_skb(skb); |
339 | return NETDEV_TX_OK; |
340 | } |
341 | |
342 | entry = ep->tx_pointer; |
343 | ep->tx_pointer = (ep->tx_pointer + 1) & (TX_QUEUE_ENTRIES - 1); |
344 | |
345 | txd = &ep->descs->tdesc[entry]; |
346 | |
347 | txd->tdesc1 = TDESC1_EOF | (entry << 16) | (skb->len & 0xfff); |
348 | dma_sync_single_for_cpu(dev: dev->dev.parent, addr: txd->buf_addr, size: skb->len, |
349 | dir: DMA_TO_DEVICE); |
350 | skb_copy_and_csum_dev(skb, to: ep->tx_buf[entry]); |
351 | dma_sync_single_for_device(dev: dev->dev.parent, addr: txd->buf_addr, size: skb->len, |
352 | dir: DMA_TO_DEVICE); |
353 | dev_kfree_skb(skb); |
354 | |
355 | spin_lock_irq(lock: &ep->tx_pending_lock); |
356 | ep->tx_pending++; |
357 | if (ep->tx_pending == TX_QUEUE_ENTRIES) |
358 | netif_stop_queue(dev); |
359 | spin_unlock_irq(lock: &ep->tx_pending_lock); |
360 | |
361 | wrl(ep, REG_TXDENQ, 1); |
362 | |
363 | return NETDEV_TX_OK; |
364 | } |
365 | |
366 | static void ep93xx_tx_complete(struct net_device *dev) |
367 | { |
368 | struct ep93xx_priv *ep = netdev_priv(dev); |
369 | int wake; |
370 | |
371 | wake = 0; |
372 | |
373 | spin_lock(lock: &ep->tx_pending_lock); |
374 | while (1) { |
375 | int entry; |
376 | struct ep93xx_tstat *tstat; |
377 | u32 tstat0; |
378 | |
379 | entry = ep->tx_clean_pointer; |
380 | tstat = ep->descs->tstat + entry; |
381 | |
382 | tstat0 = tstat->tstat0; |
383 | if (!(tstat0 & TSTAT0_TXFP)) |
384 | break; |
385 | |
386 | tstat->tstat0 = 0; |
387 | |
388 | if (tstat0 & TSTAT0_FA) |
389 | pr_crit("frame aborted %.8x\n" , tstat0); |
390 | if ((tstat0 & TSTAT0_BUFFER_INDEX) != entry) |
391 | pr_crit("entry mismatch %.8x\n" , tstat0); |
392 | |
393 | if (tstat0 & TSTAT0_TXWE) { |
394 | int length = ep->descs->tdesc[entry].tdesc1 & 0xfff; |
395 | |
396 | dev->stats.tx_packets++; |
397 | dev->stats.tx_bytes += length; |
398 | } else { |
399 | dev->stats.tx_errors++; |
400 | } |
401 | |
402 | if (tstat0 & TSTAT0_OW) |
403 | dev->stats.tx_window_errors++; |
404 | if (tstat0 & TSTAT0_TXU) |
405 | dev->stats.tx_fifo_errors++; |
406 | dev->stats.collisions += (tstat0 >> 16) & 0x1f; |
407 | |
408 | ep->tx_clean_pointer = (entry + 1) & (TX_QUEUE_ENTRIES - 1); |
409 | if (ep->tx_pending == TX_QUEUE_ENTRIES) |
410 | wake = 1; |
411 | ep->tx_pending--; |
412 | } |
413 | spin_unlock(lock: &ep->tx_pending_lock); |
414 | |
415 | if (wake) |
416 | netif_wake_queue(dev); |
417 | } |
418 | |
419 | static irqreturn_t ep93xx_irq(int irq, void *dev_id) |
420 | { |
421 | struct net_device *dev = dev_id; |
422 | struct ep93xx_priv *ep = netdev_priv(dev); |
423 | u32 status; |
424 | |
425 | status = rdl(ep, REG_INTSTSC); |
426 | if (status == 0) |
427 | return IRQ_NONE; |
428 | |
429 | if (status & REG_INTSTS_RX) { |
430 | spin_lock(lock: &ep->rx_lock); |
431 | if (likely(napi_schedule_prep(&ep->napi))) { |
432 | wrl(ep, REG_INTEN, REG_INTEN_TX); |
433 | __napi_schedule(n: &ep->napi); |
434 | } |
435 | spin_unlock(lock: &ep->rx_lock); |
436 | } |
437 | |
438 | if (status & REG_INTSTS_TX) |
439 | ep93xx_tx_complete(dev); |
440 | |
441 | return IRQ_HANDLED; |
442 | } |
443 | |
444 | static void ep93xx_free_buffers(struct ep93xx_priv *ep) |
445 | { |
446 | struct device *dev = ep->dev->dev.parent; |
447 | int i; |
448 | |
449 | if (!ep->descs) |
450 | return; |
451 | |
452 | for (i = 0; i < RX_QUEUE_ENTRIES; i++) { |
453 | dma_addr_t d; |
454 | |
455 | d = ep->descs->rdesc[i].buf_addr; |
456 | if (d) |
457 | dma_unmap_single(dev, d, PKT_BUF_SIZE, DMA_FROM_DEVICE); |
458 | |
459 | kfree(objp: ep->rx_buf[i]); |
460 | } |
461 | |
462 | for (i = 0; i < TX_QUEUE_ENTRIES; i++) { |
463 | dma_addr_t d; |
464 | |
465 | d = ep->descs->tdesc[i].buf_addr; |
466 | if (d) |
467 | dma_unmap_single(dev, d, PKT_BUF_SIZE, DMA_TO_DEVICE); |
468 | |
469 | kfree(objp: ep->tx_buf[i]); |
470 | } |
471 | |
472 | dma_free_coherent(dev, size: sizeof(struct ep93xx_descs), cpu_addr: ep->descs, |
473 | dma_handle: ep->descs_dma_addr); |
474 | ep->descs = NULL; |
475 | } |
476 | |
477 | static int ep93xx_alloc_buffers(struct ep93xx_priv *ep) |
478 | { |
479 | struct device *dev = ep->dev->dev.parent; |
480 | int i; |
481 | |
482 | ep->descs = dma_alloc_coherent(dev, size: sizeof(struct ep93xx_descs), |
483 | dma_handle: &ep->descs_dma_addr, GFP_KERNEL); |
484 | if (ep->descs == NULL) |
485 | return 1; |
486 | |
487 | for (i = 0; i < RX_QUEUE_ENTRIES; i++) { |
488 | void *buf; |
489 | dma_addr_t d; |
490 | |
491 | buf = kmalloc(PKT_BUF_SIZE, GFP_KERNEL); |
492 | if (buf == NULL) |
493 | goto err; |
494 | |
495 | d = dma_map_single(dev, buf, PKT_BUF_SIZE, DMA_FROM_DEVICE); |
496 | if (dma_mapping_error(dev, dma_addr: d)) { |
497 | kfree(objp: buf); |
498 | goto err; |
499 | } |
500 | |
501 | ep->rx_buf[i] = buf; |
502 | ep->descs->rdesc[i].buf_addr = d; |
503 | ep->descs->rdesc[i].rdesc1 = (i << 16) | PKT_BUF_SIZE; |
504 | } |
505 | |
506 | for (i = 0; i < TX_QUEUE_ENTRIES; i++) { |
507 | void *buf; |
508 | dma_addr_t d; |
509 | |
510 | buf = kmalloc(PKT_BUF_SIZE, GFP_KERNEL); |
511 | if (buf == NULL) |
512 | goto err; |
513 | |
514 | d = dma_map_single(dev, buf, PKT_BUF_SIZE, DMA_TO_DEVICE); |
515 | if (dma_mapping_error(dev, dma_addr: d)) { |
516 | kfree(objp: buf); |
517 | goto err; |
518 | } |
519 | |
520 | ep->tx_buf[i] = buf; |
521 | ep->descs->tdesc[i].buf_addr = d; |
522 | } |
523 | |
524 | return 0; |
525 | |
526 | err: |
527 | ep93xx_free_buffers(ep); |
528 | return 1; |
529 | } |
530 | |
531 | static int ep93xx_start_hw(struct net_device *dev) |
532 | { |
533 | struct ep93xx_priv *ep = netdev_priv(dev); |
534 | unsigned long addr; |
535 | int i; |
536 | |
537 | wrl(ep, REG_SELFCTL, REG_SELFCTL_RESET); |
538 | for (i = 0; i < 10; i++) { |
539 | if ((rdl(ep, REG_SELFCTL) & REG_SELFCTL_RESET) == 0) |
540 | break; |
541 | msleep(msecs: 1); |
542 | } |
543 | |
544 | if (i == 10) { |
545 | pr_crit("hw failed to reset\n" ); |
546 | return 1; |
547 | } |
548 | |
549 | wrl(ep, REG_SELFCTL, ((ep->mdc_divisor - 1) << 9)); |
550 | |
551 | /* Does the PHY support preamble suppress? */ |
552 | if ((ep93xx_mdio_read(dev, phy_id: ep->mii.phy_id, MII_BMSR) & 0x0040) != 0) |
553 | wrl(ep, REG_SELFCTL, ((ep->mdc_divisor - 1) << 9) | (1 << 8)); |
554 | |
555 | /* Receive descriptor ring. */ |
556 | addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, rdesc); |
557 | wrl(ep, REG_RXDQBADD, addr); |
558 | wrl(ep, REG_RXDCURADD, addr); |
559 | wrw(ep, REG_RXDQBLEN, RX_QUEUE_ENTRIES * sizeof(struct ep93xx_rdesc)); |
560 | |
561 | /* Receive status ring. */ |
562 | addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, rstat); |
563 | wrl(ep, REG_RXSTSQBADD, addr); |
564 | wrl(ep, REG_RXSTSQCURADD, addr); |
565 | wrw(ep, REG_RXSTSQBLEN, RX_QUEUE_ENTRIES * sizeof(struct ep93xx_rstat)); |
566 | |
567 | /* Transmit descriptor ring. */ |
568 | addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, tdesc); |
569 | wrl(ep, REG_TXDQBADD, addr); |
570 | wrl(ep, REG_TXDQCURADD, addr); |
571 | wrw(ep, REG_TXDQBLEN, TX_QUEUE_ENTRIES * sizeof(struct ep93xx_tdesc)); |
572 | |
573 | /* Transmit status ring. */ |
574 | addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, tstat); |
575 | wrl(ep, REG_TXSTSQBADD, addr); |
576 | wrl(ep, REG_TXSTSQCURADD, addr); |
577 | wrw(ep, REG_TXSTSQBLEN, TX_QUEUE_ENTRIES * sizeof(struct ep93xx_tstat)); |
578 | |
579 | wrl(ep, REG_BMCTL, REG_BMCTL_ENABLE_TX | REG_BMCTL_ENABLE_RX); |
580 | wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX); |
581 | wrl(ep, REG_GIINTMSK, 0); |
582 | |
583 | for (i = 0; i < 10; i++) { |
584 | if ((rdl(ep, REG_BMSTS) & REG_BMSTS_RX_ACTIVE) != 0) |
585 | break; |
586 | msleep(msecs: 1); |
587 | } |
588 | |
589 | if (i == 10) { |
590 | pr_crit("hw failed to start\n" ); |
591 | return 1; |
592 | } |
593 | |
594 | wrl(ep, REG_RXDENQ, RX_QUEUE_ENTRIES); |
595 | wrl(ep, REG_RXSTSENQ, RX_QUEUE_ENTRIES); |
596 | |
597 | wrb(ep, REG_INDAD0, dev->dev_addr[0]); |
598 | wrb(ep, REG_INDAD1, dev->dev_addr[1]); |
599 | wrb(ep, REG_INDAD2, dev->dev_addr[2]); |
600 | wrb(ep, REG_INDAD3, dev->dev_addr[3]); |
601 | wrb(ep, REG_INDAD4, dev->dev_addr[4]); |
602 | wrb(ep, REG_INDAD5, dev->dev_addr[5]); |
603 | wrl(ep, REG_AFP, 0); |
604 | |
605 | wrl(ep, REG_MAXFRMLEN, (MAX_PKT_SIZE << 16) | MAX_PKT_SIZE); |
606 | |
607 | wrl(ep, REG_RXCTL, REG_RXCTL_DEFAULT); |
608 | wrl(ep, REG_TXCTL, REG_TXCTL_ENABLE); |
609 | |
610 | return 0; |
611 | } |
612 | |
613 | static void ep93xx_stop_hw(struct net_device *dev) |
614 | { |
615 | struct ep93xx_priv *ep = netdev_priv(dev); |
616 | int i; |
617 | |
618 | wrl(ep, REG_SELFCTL, REG_SELFCTL_RESET); |
619 | for (i = 0; i < 10; i++) { |
620 | if ((rdl(ep, REG_SELFCTL) & REG_SELFCTL_RESET) == 0) |
621 | break; |
622 | msleep(msecs: 1); |
623 | } |
624 | |
625 | if (i == 10) |
626 | pr_crit("hw failed to reset\n" ); |
627 | } |
628 | |
629 | static int ep93xx_open(struct net_device *dev) |
630 | { |
631 | struct ep93xx_priv *ep = netdev_priv(dev); |
632 | int err; |
633 | |
634 | if (ep93xx_alloc_buffers(ep)) |
635 | return -ENOMEM; |
636 | |
637 | napi_enable(n: &ep->napi); |
638 | |
639 | if (ep93xx_start_hw(dev)) { |
640 | napi_disable(n: &ep->napi); |
641 | ep93xx_free_buffers(ep); |
642 | return -EIO; |
643 | } |
644 | |
645 | spin_lock_init(&ep->rx_lock); |
646 | ep->rx_pointer = 0; |
647 | ep->tx_clean_pointer = 0; |
648 | ep->tx_pointer = 0; |
649 | spin_lock_init(&ep->tx_pending_lock); |
650 | ep->tx_pending = 0; |
651 | |
652 | err = request_irq(irq: ep->irq, handler: ep93xx_irq, IRQF_SHARED, name: dev->name, dev); |
653 | if (err) { |
654 | napi_disable(n: &ep->napi); |
655 | ep93xx_stop_hw(dev); |
656 | ep93xx_free_buffers(ep); |
657 | return err; |
658 | } |
659 | |
660 | wrl(ep, REG_GIINTMSK, REG_GIINTMSK_ENABLE); |
661 | |
662 | netif_start_queue(dev); |
663 | |
664 | return 0; |
665 | } |
666 | |
667 | static int ep93xx_close(struct net_device *dev) |
668 | { |
669 | struct ep93xx_priv *ep = netdev_priv(dev); |
670 | |
671 | napi_disable(n: &ep->napi); |
672 | netif_stop_queue(dev); |
673 | |
674 | wrl(ep, REG_GIINTMSK, 0); |
675 | free_irq(ep->irq, dev); |
676 | ep93xx_stop_hw(dev); |
677 | ep93xx_free_buffers(ep); |
678 | |
679 | return 0; |
680 | } |
681 | |
682 | static int ep93xx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
683 | { |
684 | struct ep93xx_priv *ep = netdev_priv(dev); |
685 | struct mii_ioctl_data *data = if_mii(rq: ifr); |
686 | |
687 | return generic_mii_ioctl(mii_if: &ep->mii, mii_data: data, cmd, NULL); |
688 | } |
689 | |
690 | static void ep93xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) |
691 | { |
692 | strscpy(p: info->driver, DRV_MODULE_NAME, size: sizeof(info->driver)); |
693 | } |
694 | |
695 | static int ep93xx_get_link_ksettings(struct net_device *dev, |
696 | struct ethtool_link_ksettings *cmd) |
697 | { |
698 | struct ep93xx_priv *ep = netdev_priv(dev); |
699 | |
700 | mii_ethtool_get_link_ksettings(mii: &ep->mii, cmd); |
701 | |
702 | return 0; |
703 | } |
704 | |
705 | static int ep93xx_set_link_ksettings(struct net_device *dev, |
706 | const struct ethtool_link_ksettings *cmd) |
707 | { |
708 | struct ep93xx_priv *ep = netdev_priv(dev); |
709 | return mii_ethtool_set_link_ksettings(mii: &ep->mii, cmd); |
710 | } |
711 | |
712 | static int ep93xx_nway_reset(struct net_device *dev) |
713 | { |
714 | struct ep93xx_priv *ep = netdev_priv(dev); |
715 | return mii_nway_restart(mii: &ep->mii); |
716 | } |
717 | |
718 | static u32 ep93xx_get_link(struct net_device *dev) |
719 | { |
720 | struct ep93xx_priv *ep = netdev_priv(dev); |
721 | return mii_link_ok(mii: &ep->mii); |
722 | } |
723 | |
724 | static const struct ethtool_ops ep93xx_ethtool_ops = { |
725 | .get_drvinfo = ep93xx_get_drvinfo, |
726 | .nway_reset = ep93xx_nway_reset, |
727 | .get_link = ep93xx_get_link, |
728 | .get_link_ksettings = ep93xx_get_link_ksettings, |
729 | .set_link_ksettings = ep93xx_set_link_ksettings, |
730 | }; |
731 | |
732 | static const struct net_device_ops ep93xx_netdev_ops = { |
733 | .ndo_open = ep93xx_open, |
734 | .ndo_stop = ep93xx_close, |
735 | .ndo_start_xmit = ep93xx_xmit, |
736 | .ndo_eth_ioctl = ep93xx_ioctl, |
737 | .ndo_validate_addr = eth_validate_addr, |
738 | .ndo_set_mac_address = eth_mac_addr, |
739 | }; |
740 | |
741 | static struct net_device *ep93xx_dev_alloc(struct ep93xx_eth_data *data) |
742 | { |
743 | struct net_device *dev; |
744 | |
745 | dev = alloc_etherdev(sizeof(struct ep93xx_priv)); |
746 | if (dev == NULL) |
747 | return NULL; |
748 | |
749 | eth_hw_addr_set(dev, addr: data->dev_addr); |
750 | |
751 | dev->ethtool_ops = &ep93xx_ethtool_ops; |
752 | dev->netdev_ops = &ep93xx_netdev_ops; |
753 | |
754 | dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; |
755 | |
756 | return dev; |
757 | } |
758 | |
759 | |
760 | static void ep93xx_eth_remove(struct platform_device *pdev) |
761 | { |
762 | struct net_device *dev; |
763 | struct ep93xx_priv *ep; |
764 | struct resource *mem; |
765 | |
766 | dev = platform_get_drvdata(pdev); |
767 | if (dev == NULL) |
768 | return; |
769 | |
770 | ep = netdev_priv(dev); |
771 | |
772 | /* @@@ Force down. */ |
773 | unregister_netdev(dev); |
774 | ep93xx_free_buffers(ep); |
775 | |
776 | if (ep->base_addr != NULL) |
777 | iounmap(addr: ep->base_addr); |
778 | |
779 | if (ep->res != NULL) { |
780 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
781 | release_mem_region(mem->start, resource_size(mem)); |
782 | } |
783 | |
784 | free_netdev(dev); |
785 | } |
786 | |
787 | static int ep93xx_eth_probe(struct platform_device *pdev) |
788 | { |
789 | struct ep93xx_eth_data *data; |
790 | struct net_device *dev; |
791 | struct ep93xx_priv *ep; |
792 | struct resource *mem; |
793 | int irq; |
794 | int err; |
795 | |
796 | if (pdev == NULL) |
797 | return -ENODEV; |
798 | data = dev_get_platdata(dev: &pdev->dev); |
799 | |
800 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
801 | irq = platform_get_irq(pdev, 0); |
802 | if (!mem || irq < 0) |
803 | return -ENXIO; |
804 | |
805 | dev = ep93xx_dev_alloc(data); |
806 | if (dev == NULL) { |
807 | err = -ENOMEM; |
808 | goto err_out; |
809 | } |
810 | ep = netdev_priv(dev); |
811 | ep->dev = dev; |
812 | SET_NETDEV_DEV(dev, &pdev->dev); |
813 | netif_napi_add(dev, napi: &ep->napi, poll: ep93xx_poll); |
814 | |
815 | platform_set_drvdata(pdev, data: dev); |
816 | |
817 | ep->res = request_mem_region(mem->start, resource_size(mem), |
818 | dev_name(&pdev->dev)); |
819 | if (ep->res == NULL) { |
820 | dev_err(&pdev->dev, "Could not reserve memory region\n" ); |
821 | err = -ENOMEM; |
822 | goto err_out; |
823 | } |
824 | |
825 | ep->base_addr = ioremap(offset: mem->start, size: resource_size(res: mem)); |
826 | if (ep->base_addr == NULL) { |
827 | dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n" ); |
828 | err = -EIO; |
829 | goto err_out; |
830 | } |
831 | ep->irq = irq; |
832 | |
833 | ep->mii.phy_id = data->phy_id; |
834 | ep->mii.phy_id_mask = 0x1f; |
835 | ep->mii.reg_num_mask = 0x1f; |
836 | ep->mii.dev = dev; |
837 | ep->mii.mdio_read = ep93xx_mdio_read; |
838 | ep->mii.mdio_write = ep93xx_mdio_write; |
839 | ep->mdc_divisor = 40; /* Max HCLK 100 MHz, min MDIO clk 2.5 MHz. */ |
840 | |
841 | if (is_zero_ether_addr(addr: dev->dev_addr)) |
842 | eth_hw_addr_random(dev); |
843 | |
844 | err = register_netdev(dev); |
845 | if (err) { |
846 | dev_err(&pdev->dev, "Failed to register netdev\n" ); |
847 | goto err_out; |
848 | } |
849 | |
850 | printk(KERN_INFO "%s: ep93xx on-chip ethernet, IRQ %d, %pM\n" , |
851 | dev->name, ep->irq, dev->dev_addr); |
852 | |
853 | return 0; |
854 | |
855 | err_out: |
856 | ep93xx_eth_remove(pdev); |
857 | return err; |
858 | } |
859 | |
860 | |
861 | static struct platform_driver ep93xx_eth_driver = { |
862 | .probe = ep93xx_eth_probe, |
863 | .remove_new = ep93xx_eth_remove, |
864 | .driver = { |
865 | .name = "ep93xx-eth" , |
866 | }, |
867 | }; |
868 | |
869 | module_platform_driver(ep93xx_eth_driver); |
870 | |
871 | MODULE_LICENSE("GPL" ); |
872 | MODULE_ALIAS("platform:ep93xx-eth" ); |
873 | |