1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Faraday FTMAC100 10/100 Ethernet |
4 | * |
5 | * (C) Copyright 2009-2011 Faraday Technology |
6 | * Po-Yu Chuang <ratbert@faraday-tech.com> |
7 | */ |
8 | |
9 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
10 | |
11 | #include <linux/dma-mapping.h> |
12 | #include <linux/etherdevice.h> |
13 | #include <linux/ethtool.h> |
14 | #include <linux/if_ether.h> |
15 | #include <linux/if_vlan.h> |
16 | #include <linux/init.h> |
17 | #include <linux/interrupt.h> |
18 | #include <linux/io.h> |
19 | #include <linux/mii.h> |
20 | #include <linux/module.h> |
21 | #include <linux/mod_devicetable.h> |
22 | #include <linux/netdevice.h> |
23 | #include <linux/platform_device.h> |
24 | |
25 | #include "ftmac100.h" |
26 | |
27 | #define DRV_NAME "ftmac100" |
28 | |
29 | #define RX_QUEUE_ENTRIES 128 /* must be power of 2 */ |
30 | #define TX_QUEUE_ENTRIES 16 /* must be power of 2 */ |
31 | |
32 | #define RX_BUF_SIZE 2044 /* must be smaller than 0x7ff */ |
33 | #define MAX_PKT_SIZE RX_BUF_SIZE /* multi-segment not supported */ |
34 | |
35 | #if MAX_PKT_SIZE > 0x7ff |
36 | #error invalid MAX_PKT_SIZE |
37 | #endif |
38 | |
39 | #if RX_BUF_SIZE > 0x7ff || RX_BUF_SIZE > PAGE_SIZE |
40 | #error invalid RX_BUF_SIZE |
41 | #endif |
42 | |
43 | /****************************************************************************** |
44 | * private data |
45 | *****************************************************************************/ |
46 | struct ftmac100_descs { |
47 | struct ftmac100_rxdes rxdes[RX_QUEUE_ENTRIES]; |
48 | struct ftmac100_txdes txdes[TX_QUEUE_ENTRIES]; |
49 | }; |
50 | |
51 | struct ftmac100 { |
52 | struct resource *res; |
53 | void __iomem *base; |
54 | int irq; |
55 | |
56 | struct ftmac100_descs *descs; |
57 | dma_addr_t descs_dma_addr; |
58 | |
59 | unsigned int rx_pointer; |
60 | unsigned int tx_clean_pointer; |
61 | unsigned int tx_pointer; |
62 | unsigned int tx_pending; |
63 | |
64 | spinlock_t tx_lock; |
65 | |
66 | struct net_device *netdev; |
67 | struct device *dev; |
68 | struct napi_struct napi; |
69 | |
70 | struct mii_if_info mii; |
71 | }; |
72 | |
73 | static int ftmac100_alloc_rx_page(struct ftmac100 *priv, |
74 | struct ftmac100_rxdes *rxdes, gfp_t gfp); |
75 | |
76 | /****************************************************************************** |
77 | * internal functions (hardware register access) |
78 | *****************************************************************************/ |
79 | #define INT_MASK_ALL_ENABLED (FTMAC100_INT_RPKT_FINISH | \ |
80 | FTMAC100_INT_NORXBUF | \ |
81 | FTMAC100_INT_XPKT_OK | \ |
82 | FTMAC100_INT_XPKT_LOST | \ |
83 | FTMAC100_INT_RPKT_LOST | \ |
84 | FTMAC100_INT_AHB_ERR | \ |
85 | FTMAC100_INT_PHYSTS_CHG) |
86 | |
87 | #define INT_MASK_ALL_DISABLED 0 |
88 | |
89 | static void ftmac100_enable_all_int(struct ftmac100 *priv) |
90 | { |
91 | iowrite32(INT_MASK_ALL_ENABLED, priv->base + FTMAC100_OFFSET_IMR); |
92 | } |
93 | |
94 | static void ftmac100_disable_all_int(struct ftmac100 *priv) |
95 | { |
96 | iowrite32(INT_MASK_ALL_DISABLED, priv->base + FTMAC100_OFFSET_IMR); |
97 | } |
98 | |
99 | static void ftmac100_set_rx_ring_base(struct ftmac100 *priv, dma_addr_t addr) |
100 | { |
101 | iowrite32(addr, priv->base + FTMAC100_OFFSET_RXR_BADR); |
102 | } |
103 | |
104 | static void ftmac100_set_tx_ring_base(struct ftmac100 *priv, dma_addr_t addr) |
105 | { |
106 | iowrite32(addr, priv->base + FTMAC100_OFFSET_TXR_BADR); |
107 | } |
108 | |
109 | static void ftmac100_txdma_start_polling(struct ftmac100 *priv) |
110 | { |
111 | iowrite32(1, priv->base + FTMAC100_OFFSET_TXPD); |
112 | } |
113 | |
114 | static int ftmac100_reset(struct ftmac100 *priv) |
115 | { |
116 | struct net_device *netdev = priv->netdev; |
117 | int i; |
118 | |
119 | /* NOTE: reset clears all registers */ |
120 | iowrite32(FTMAC100_MACCR_SW_RST, priv->base + FTMAC100_OFFSET_MACCR); |
121 | |
122 | for (i = 0; i < 5; i++) { |
123 | unsigned int maccr; |
124 | |
125 | maccr = ioread32(priv->base + FTMAC100_OFFSET_MACCR); |
126 | if (!(maccr & FTMAC100_MACCR_SW_RST)) { |
127 | /* |
128 | * FTMAC100_MACCR_SW_RST cleared does not indicate |
129 | * that hardware reset completed (what the f*ck). |
130 | * We still need to wait for a while. |
131 | */ |
132 | udelay(500); |
133 | return 0; |
134 | } |
135 | |
136 | udelay(1000); |
137 | } |
138 | |
139 | netdev_err(dev: netdev, format: "software reset failed\n" ); |
140 | return -EIO; |
141 | } |
142 | |
143 | static void ftmac100_set_mac(struct ftmac100 *priv, const unsigned char *mac) |
144 | { |
145 | unsigned int maddr = mac[0] << 8 | mac[1]; |
146 | unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5]; |
147 | |
148 | iowrite32(maddr, priv->base + FTMAC100_OFFSET_MAC_MADR); |
149 | iowrite32(laddr, priv->base + FTMAC100_OFFSET_MAC_LADR); |
150 | } |
151 | |
152 | static void ftmac100_setup_mc_ht(struct ftmac100 *priv) |
153 | { |
154 | struct netdev_hw_addr *ha; |
155 | u64 maht = 0; /* Multicast Address Hash Table */ |
156 | |
157 | netdev_for_each_mc_addr(ha, priv->netdev) { |
158 | u32 hash = ether_crc(ETH_ALEN, ha->addr) >> 26; |
159 | |
160 | maht |= BIT_ULL(hash); |
161 | } |
162 | |
163 | iowrite32(lower_32_bits(maht), priv->base + FTMAC100_OFFSET_MAHT0); |
164 | iowrite32(upper_32_bits(maht), priv->base + FTMAC100_OFFSET_MAHT1); |
165 | } |
166 | |
167 | static void ftmac100_set_rx_bits(struct ftmac100 *priv, unsigned int *maccr) |
168 | { |
169 | struct net_device *netdev = priv->netdev; |
170 | |
171 | /* Clear all */ |
172 | *maccr &= ~(FTMAC100_MACCR_RCV_ALL | FTMAC100_MACCR_RX_MULTIPKT | |
173 | FTMAC100_MACCR_HT_MULTI_EN); |
174 | |
175 | /* Set the requested bits */ |
176 | if (netdev->flags & IFF_PROMISC) |
177 | *maccr |= FTMAC100_MACCR_RCV_ALL; |
178 | if (netdev->flags & IFF_ALLMULTI) |
179 | *maccr |= FTMAC100_MACCR_RX_MULTIPKT; |
180 | else if (netdev_mc_count(netdev)) { |
181 | *maccr |= FTMAC100_MACCR_HT_MULTI_EN; |
182 | ftmac100_setup_mc_ht(priv); |
183 | } |
184 | } |
185 | |
186 | #define MACCR_ENABLE_ALL (FTMAC100_MACCR_XMT_EN | \ |
187 | FTMAC100_MACCR_RCV_EN | \ |
188 | FTMAC100_MACCR_XDMA_EN | \ |
189 | FTMAC100_MACCR_RDMA_EN | \ |
190 | FTMAC100_MACCR_CRC_APD | \ |
191 | FTMAC100_MACCR_FULLDUP | \ |
192 | FTMAC100_MACCR_RX_RUNT | \ |
193 | FTMAC100_MACCR_RX_BROADPKT) |
194 | |
195 | static int ftmac100_start_hw(struct ftmac100 *priv) |
196 | { |
197 | struct net_device *netdev = priv->netdev; |
198 | unsigned int maccr = MACCR_ENABLE_ALL; |
199 | |
200 | if (ftmac100_reset(priv)) |
201 | return -EIO; |
202 | |
203 | /* setup ring buffer base registers */ |
204 | ftmac100_set_rx_ring_base(priv, |
205 | addr: priv->descs_dma_addr + |
206 | offsetof(struct ftmac100_descs, rxdes)); |
207 | ftmac100_set_tx_ring_base(priv, |
208 | addr: priv->descs_dma_addr + |
209 | offsetof(struct ftmac100_descs, txdes)); |
210 | |
211 | iowrite32(FTMAC100_APTC_RXPOLL_CNT(1), priv->base + FTMAC100_OFFSET_APTC); |
212 | |
213 | ftmac100_set_mac(priv, mac: netdev->dev_addr); |
214 | |
215 | /* See ftmac100_change_mtu() */ |
216 | if (netdev->mtu > ETH_DATA_LEN) |
217 | maccr |= FTMAC100_MACCR_RX_FTL; |
218 | |
219 | ftmac100_set_rx_bits(priv, maccr: &maccr); |
220 | |
221 | iowrite32(maccr, priv->base + FTMAC100_OFFSET_MACCR); |
222 | return 0; |
223 | } |
224 | |
225 | static void ftmac100_stop_hw(struct ftmac100 *priv) |
226 | { |
227 | iowrite32(0, priv->base + FTMAC100_OFFSET_MACCR); |
228 | } |
229 | |
230 | /****************************************************************************** |
231 | * internal functions (receive descriptor) |
232 | *****************************************************************************/ |
233 | static bool ftmac100_rxdes_first_segment(struct ftmac100_rxdes *rxdes) |
234 | { |
235 | return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_FRS); |
236 | } |
237 | |
238 | static bool ftmac100_rxdes_last_segment(struct ftmac100_rxdes *rxdes) |
239 | { |
240 | return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_LRS); |
241 | } |
242 | |
243 | static bool ftmac100_rxdes_owned_by_dma(struct ftmac100_rxdes *rxdes) |
244 | { |
245 | return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RXDMA_OWN); |
246 | } |
247 | |
248 | static void ftmac100_rxdes_set_dma_own(struct ftmac100_rxdes *rxdes) |
249 | { |
250 | /* clear status bits */ |
251 | rxdes->rxdes0 = cpu_to_le32(FTMAC100_RXDES0_RXDMA_OWN); |
252 | } |
253 | |
254 | static bool ftmac100_rxdes_rx_error(struct ftmac100_rxdes *rxdes) |
255 | { |
256 | return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RX_ERR); |
257 | } |
258 | |
259 | static bool ftmac100_rxdes_crc_error(struct ftmac100_rxdes *rxdes) |
260 | { |
261 | return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_CRC_ERR); |
262 | } |
263 | |
264 | static bool ftmac100_rxdes_runt(struct ftmac100_rxdes *rxdes) |
265 | { |
266 | return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RUNT); |
267 | } |
268 | |
269 | static bool ftmac100_rxdes_odd_nibble(struct ftmac100_rxdes *rxdes) |
270 | { |
271 | return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RX_ODD_NB); |
272 | } |
273 | |
274 | static unsigned int ftmac100_rxdes_frame_length(struct ftmac100_rxdes *rxdes) |
275 | { |
276 | return le32_to_cpu(rxdes->rxdes0) & FTMAC100_RXDES0_RFL; |
277 | } |
278 | |
279 | static bool ftmac100_rxdes_multicast(struct ftmac100_rxdes *rxdes) |
280 | { |
281 | return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_MULTICAST); |
282 | } |
283 | |
284 | static void ftmac100_rxdes_set_buffer_size(struct ftmac100_rxdes *rxdes, |
285 | unsigned int size) |
286 | { |
287 | rxdes->rxdes1 &= cpu_to_le32(FTMAC100_RXDES1_EDORR); |
288 | rxdes->rxdes1 |= cpu_to_le32(FTMAC100_RXDES1_RXBUF_SIZE(size)); |
289 | } |
290 | |
291 | static void ftmac100_rxdes_set_end_of_ring(struct ftmac100_rxdes *rxdes) |
292 | { |
293 | rxdes->rxdes1 |= cpu_to_le32(FTMAC100_RXDES1_EDORR); |
294 | } |
295 | |
296 | static void ftmac100_rxdes_set_dma_addr(struct ftmac100_rxdes *rxdes, |
297 | dma_addr_t addr) |
298 | { |
299 | rxdes->rxdes2 = cpu_to_le32(addr); |
300 | } |
301 | |
302 | static dma_addr_t ftmac100_rxdes_get_dma_addr(struct ftmac100_rxdes *rxdes) |
303 | { |
304 | return le32_to_cpu(rxdes->rxdes2); |
305 | } |
306 | |
307 | /* |
308 | * rxdes3 is not used by hardware. We use it to keep track of page. |
309 | * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu(). |
310 | */ |
311 | static void ftmac100_rxdes_set_page(struct ftmac100_rxdes *rxdes, struct page *page) |
312 | { |
313 | rxdes->rxdes3 = (unsigned int)page; |
314 | } |
315 | |
316 | static struct page *ftmac100_rxdes_get_page(struct ftmac100_rxdes *rxdes) |
317 | { |
318 | return (struct page *)rxdes->rxdes3; |
319 | } |
320 | |
321 | /****************************************************************************** |
322 | * internal functions (receive) |
323 | *****************************************************************************/ |
324 | static int ftmac100_next_rx_pointer(int pointer) |
325 | { |
326 | return (pointer + 1) & (RX_QUEUE_ENTRIES - 1); |
327 | } |
328 | |
329 | static void ftmac100_rx_pointer_advance(struct ftmac100 *priv) |
330 | { |
331 | priv->rx_pointer = ftmac100_next_rx_pointer(pointer: priv->rx_pointer); |
332 | } |
333 | |
334 | static struct ftmac100_rxdes *ftmac100_current_rxdes(struct ftmac100 *priv) |
335 | { |
336 | return &priv->descs->rxdes[priv->rx_pointer]; |
337 | } |
338 | |
339 | static struct ftmac100_rxdes * |
340 | ftmac100_rx_locate_first_segment(struct ftmac100 *priv) |
341 | { |
342 | struct ftmac100_rxdes *rxdes = ftmac100_current_rxdes(priv); |
343 | |
344 | while (!ftmac100_rxdes_owned_by_dma(rxdes)) { |
345 | if (ftmac100_rxdes_first_segment(rxdes)) |
346 | return rxdes; |
347 | |
348 | ftmac100_rxdes_set_dma_own(rxdes); |
349 | ftmac100_rx_pointer_advance(priv); |
350 | rxdes = ftmac100_current_rxdes(priv); |
351 | } |
352 | |
353 | return NULL; |
354 | } |
355 | |
356 | static bool ftmac100_rx_packet_error(struct ftmac100 *priv, |
357 | struct ftmac100_rxdes *rxdes) |
358 | { |
359 | struct net_device *netdev = priv->netdev; |
360 | bool error = false; |
361 | |
362 | if (unlikely(ftmac100_rxdes_rx_error(rxdes))) { |
363 | if (net_ratelimit()) |
364 | netdev_info(dev: netdev, format: "rx err\n" ); |
365 | |
366 | netdev->stats.rx_errors++; |
367 | error = true; |
368 | } |
369 | |
370 | if (unlikely(ftmac100_rxdes_crc_error(rxdes))) { |
371 | if (net_ratelimit()) |
372 | netdev_info(dev: netdev, format: "rx crc err\n" ); |
373 | |
374 | netdev->stats.rx_crc_errors++; |
375 | error = true; |
376 | } |
377 | |
378 | if (unlikely(ftmac100_rxdes_runt(rxdes))) { |
379 | if (net_ratelimit()) |
380 | netdev_info(dev: netdev, format: "rx runt\n" ); |
381 | |
382 | netdev->stats.rx_length_errors++; |
383 | error = true; |
384 | } else if (unlikely(ftmac100_rxdes_odd_nibble(rxdes))) { |
385 | if (net_ratelimit()) |
386 | netdev_info(dev: netdev, format: "rx odd nibble\n" ); |
387 | |
388 | netdev->stats.rx_length_errors++; |
389 | error = true; |
390 | } |
391 | /* |
392 | * FTMAC100_RXDES0_FTL is not an error, it just indicates that the |
393 | * frame is longer than 1518 octets. Receiving these is possible when |
394 | * we told the hardware not to drop them, via FTMAC100_MACCR_RX_FTL. |
395 | */ |
396 | |
397 | return error; |
398 | } |
399 | |
400 | static void ftmac100_rx_drop_packet(struct ftmac100 *priv) |
401 | { |
402 | struct net_device *netdev = priv->netdev; |
403 | struct ftmac100_rxdes *rxdes = ftmac100_current_rxdes(priv); |
404 | bool done = false; |
405 | |
406 | if (net_ratelimit()) |
407 | netdev_dbg(netdev, "drop packet %p\n" , rxdes); |
408 | |
409 | do { |
410 | if (ftmac100_rxdes_last_segment(rxdes)) |
411 | done = true; |
412 | |
413 | ftmac100_rxdes_set_dma_own(rxdes); |
414 | ftmac100_rx_pointer_advance(priv); |
415 | rxdes = ftmac100_current_rxdes(priv); |
416 | } while (!done && !ftmac100_rxdes_owned_by_dma(rxdes)); |
417 | |
418 | netdev->stats.rx_dropped++; |
419 | } |
420 | |
421 | static bool ftmac100_rx_packet(struct ftmac100 *priv, int *processed) |
422 | { |
423 | struct net_device *netdev = priv->netdev; |
424 | struct ftmac100_rxdes *rxdes; |
425 | struct sk_buff *skb; |
426 | struct page *page; |
427 | dma_addr_t map; |
428 | int length; |
429 | bool ret; |
430 | |
431 | rxdes = ftmac100_rx_locate_first_segment(priv); |
432 | if (!rxdes) |
433 | return false; |
434 | |
435 | if (unlikely(ftmac100_rx_packet_error(priv, rxdes))) { |
436 | ftmac100_rx_drop_packet(priv); |
437 | return true; |
438 | } |
439 | |
440 | /* We don't support multi-segment packets for now, so drop them. */ |
441 | ret = ftmac100_rxdes_last_segment(rxdes); |
442 | if (unlikely(!ret)) { |
443 | netdev->stats.rx_length_errors++; |
444 | ftmac100_rx_drop_packet(priv); |
445 | return true; |
446 | } |
447 | |
448 | /* start processing */ |
449 | skb = netdev_alloc_skb_ip_align(dev: netdev, length: 128); |
450 | if (unlikely(!skb)) { |
451 | if (net_ratelimit()) |
452 | netdev_err(dev: netdev, format: "rx skb alloc failed\n" ); |
453 | |
454 | ftmac100_rx_drop_packet(priv); |
455 | return true; |
456 | } |
457 | |
458 | if (unlikely(ftmac100_rxdes_multicast(rxdes))) |
459 | netdev->stats.multicast++; |
460 | |
461 | map = ftmac100_rxdes_get_dma_addr(rxdes); |
462 | dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE); |
463 | |
464 | length = ftmac100_rxdes_frame_length(rxdes); |
465 | page = ftmac100_rxdes_get_page(rxdes); |
466 | skb_fill_page_desc(skb, i: 0, page, off: 0, size: length); |
467 | skb->len += length; |
468 | skb->data_len += length; |
469 | |
470 | if (length > 128) { |
471 | skb->truesize += PAGE_SIZE; |
472 | /* We pull the minimum amount into linear part */ |
473 | __pskb_pull_tail(skb, ETH_HLEN); |
474 | } else { |
475 | /* Small frames are copied into linear part to free one page */ |
476 | __pskb_pull_tail(skb, delta: length); |
477 | } |
478 | ftmac100_alloc_rx_page(priv, rxdes, GFP_ATOMIC); |
479 | |
480 | ftmac100_rx_pointer_advance(priv); |
481 | |
482 | skb->protocol = eth_type_trans(skb, dev: netdev); |
483 | |
484 | netdev->stats.rx_packets++; |
485 | netdev->stats.rx_bytes += skb->len; |
486 | |
487 | /* push packet to protocol stack */ |
488 | netif_receive_skb(skb); |
489 | |
490 | (*processed)++; |
491 | return true; |
492 | } |
493 | |
494 | /****************************************************************************** |
495 | * internal functions (transmit descriptor) |
496 | *****************************************************************************/ |
497 | static void ftmac100_txdes_reset(struct ftmac100_txdes *txdes) |
498 | { |
499 | /* clear all except end of ring bit */ |
500 | txdes->txdes0 = 0; |
501 | txdes->txdes1 &= cpu_to_le32(FTMAC100_TXDES1_EDOTR); |
502 | txdes->txdes2 = 0; |
503 | txdes->txdes3 = 0; |
504 | } |
505 | |
506 | static bool ftmac100_txdes_owned_by_dma(struct ftmac100_txdes *txdes) |
507 | { |
508 | return txdes->txdes0 & cpu_to_le32(FTMAC100_TXDES0_TXDMA_OWN); |
509 | } |
510 | |
511 | static void ftmac100_txdes_set_dma_own(struct ftmac100_txdes *txdes) |
512 | { |
513 | /* |
514 | * Make sure dma own bit will not be set before any other |
515 | * descriptor fields. |
516 | */ |
517 | wmb(); |
518 | txdes->txdes0 |= cpu_to_le32(FTMAC100_TXDES0_TXDMA_OWN); |
519 | } |
520 | |
521 | static bool ftmac100_txdes_excessive_collision(struct ftmac100_txdes *txdes) |
522 | { |
523 | return txdes->txdes0 & cpu_to_le32(FTMAC100_TXDES0_TXPKT_EXSCOL); |
524 | } |
525 | |
526 | static bool ftmac100_txdes_late_collision(struct ftmac100_txdes *txdes) |
527 | { |
528 | return txdes->txdes0 & cpu_to_le32(FTMAC100_TXDES0_TXPKT_LATECOL); |
529 | } |
530 | |
531 | static void ftmac100_txdes_set_end_of_ring(struct ftmac100_txdes *txdes) |
532 | { |
533 | txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_EDOTR); |
534 | } |
535 | |
536 | static void ftmac100_txdes_set_first_segment(struct ftmac100_txdes *txdes) |
537 | { |
538 | txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_FTS); |
539 | } |
540 | |
541 | static void ftmac100_txdes_set_last_segment(struct ftmac100_txdes *txdes) |
542 | { |
543 | txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_LTS); |
544 | } |
545 | |
546 | static void ftmac100_txdes_set_txint(struct ftmac100_txdes *txdes) |
547 | { |
548 | txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_TXIC); |
549 | } |
550 | |
551 | static void ftmac100_txdes_set_buffer_size(struct ftmac100_txdes *txdes, |
552 | unsigned int len) |
553 | { |
554 | txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_TXBUF_SIZE(len)); |
555 | } |
556 | |
557 | static void ftmac100_txdes_set_dma_addr(struct ftmac100_txdes *txdes, |
558 | dma_addr_t addr) |
559 | { |
560 | txdes->txdes2 = cpu_to_le32(addr); |
561 | } |
562 | |
563 | static dma_addr_t ftmac100_txdes_get_dma_addr(struct ftmac100_txdes *txdes) |
564 | { |
565 | return le32_to_cpu(txdes->txdes2); |
566 | } |
567 | |
568 | /* |
569 | * txdes3 is not used by hardware. We use it to keep track of socket buffer. |
570 | * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu(). |
571 | */ |
572 | static void ftmac100_txdes_set_skb(struct ftmac100_txdes *txdes, struct sk_buff *skb) |
573 | { |
574 | txdes->txdes3 = (unsigned int)skb; |
575 | } |
576 | |
577 | static struct sk_buff *ftmac100_txdes_get_skb(struct ftmac100_txdes *txdes) |
578 | { |
579 | return (struct sk_buff *)txdes->txdes3; |
580 | } |
581 | |
582 | /****************************************************************************** |
583 | * internal functions (transmit) |
584 | *****************************************************************************/ |
585 | static int ftmac100_next_tx_pointer(int pointer) |
586 | { |
587 | return (pointer + 1) & (TX_QUEUE_ENTRIES - 1); |
588 | } |
589 | |
590 | static void ftmac100_tx_pointer_advance(struct ftmac100 *priv) |
591 | { |
592 | priv->tx_pointer = ftmac100_next_tx_pointer(pointer: priv->tx_pointer); |
593 | } |
594 | |
595 | static void ftmac100_tx_clean_pointer_advance(struct ftmac100 *priv) |
596 | { |
597 | priv->tx_clean_pointer = ftmac100_next_tx_pointer(pointer: priv->tx_clean_pointer); |
598 | } |
599 | |
600 | static struct ftmac100_txdes *ftmac100_current_txdes(struct ftmac100 *priv) |
601 | { |
602 | return &priv->descs->txdes[priv->tx_pointer]; |
603 | } |
604 | |
605 | static struct ftmac100_txdes *ftmac100_current_clean_txdes(struct ftmac100 *priv) |
606 | { |
607 | return &priv->descs->txdes[priv->tx_clean_pointer]; |
608 | } |
609 | |
610 | static bool ftmac100_tx_complete_packet(struct ftmac100 *priv) |
611 | { |
612 | struct net_device *netdev = priv->netdev; |
613 | struct ftmac100_txdes *txdes; |
614 | struct sk_buff *skb; |
615 | dma_addr_t map; |
616 | |
617 | if (priv->tx_pending == 0) |
618 | return false; |
619 | |
620 | txdes = ftmac100_current_clean_txdes(priv); |
621 | |
622 | if (ftmac100_txdes_owned_by_dma(txdes)) |
623 | return false; |
624 | |
625 | skb = ftmac100_txdes_get_skb(txdes); |
626 | map = ftmac100_txdes_get_dma_addr(txdes); |
627 | |
628 | if (unlikely(ftmac100_txdes_excessive_collision(txdes) || |
629 | ftmac100_txdes_late_collision(txdes))) { |
630 | /* |
631 | * packet transmitted to ethernet lost due to late collision |
632 | * or excessive collision |
633 | */ |
634 | netdev->stats.tx_aborted_errors++; |
635 | } else { |
636 | netdev->stats.tx_packets++; |
637 | netdev->stats.tx_bytes += skb->len; |
638 | } |
639 | |
640 | dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE); |
641 | dev_kfree_skb(skb); |
642 | |
643 | ftmac100_txdes_reset(txdes); |
644 | |
645 | ftmac100_tx_clean_pointer_advance(priv); |
646 | |
647 | spin_lock(lock: &priv->tx_lock); |
648 | priv->tx_pending--; |
649 | spin_unlock(lock: &priv->tx_lock); |
650 | netif_wake_queue(dev: netdev); |
651 | |
652 | return true; |
653 | } |
654 | |
655 | static void ftmac100_tx_complete(struct ftmac100 *priv) |
656 | { |
657 | while (ftmac100_tx_complete_packet(priv)) |
658 | ; |
659 | } |
660 | |
661 | static netdev_tx_t ftmac100_xmit(struct ftmac100 *priv, struct sk_buff *skb, |
662 | dma_addr_t map) |
663 | { |
664 | struct net_device *netdev = priv->netdev; |
665 | struct ftmac100_txdes *txdes; |
666 | unsigned int len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; |
667 | |
668 | txdes = ftmac100_current_txdes(priv); |
669 | ftmac100_tx_pointer_advance(priv); |
670 | |
671 | /* setup TX descriptor */ |
672 | ftmac100_txdes_set_skb(txdes, skb); |
673 | ftmac100_txdes_set_dma_addr(txdes, addr: map); |
674 | |
675 | ftmac100_txdes_set_first_segment(txdes); |
676 | ftmac100_txdes_set_last_segment(txdes); |
677 | ftmac100_txdes_set_txint(txdes); |
678 | ftmac100_txdes_set_buffer_size(txdes, len); |
679 | |
680 | spin_lock(lock: &priv->tx_lock); |
681 | priv->tx_pending++; |
682 | if (priv->tx_pending == TX_QUEUE_ENTRIES) |
683 | netif_stop_queue(dev: netdev); |
684 | |
685 | /* start transmit */ |
686 | ftmac100_txdes_set_dma_own(txdes); |
687 | spin_unlock(lock: &priv->tx_lock); |
688 | |
689 | ftmac100_txdma_start_polling(priv); |
690 | return NETDEV_TX_OK; |
691 | } |
692 | |
693 | /****************************************************************************** |
694 | * internal functions (buffer) |
695 | *****************************************************************************/ |
696 | static int ftmac100_alloc_rx_page(struct ftmac100 *priv, |
697 | struct ftmac100_rxdes *rxdes, gfp_t gfp) |
698 | { |
699 | struct net_device *netdev = priv->netdev; |
700 | struct page *page; |
701 | dma_addr_t map; |
702 | |
703 | page = alloc_page(gfp); |
704 | if (!page) { |
705 | if (net_ratelimit()) |
706 | netdev_err(dev: netdev, format: "failed to allocate rx page\n" ); |
707 | return -ENOMEM; |
708 | } |
709 | |
710 | map = dma_map_page(priv->dev, page, 0, RX_BUF_SIZE, DMA_FROM_DEVICE); |
711 | if (unlikely(dma_mapping_error(priv->dev, map))) { |
712 | if (net_ratelimit()) |
713 | netdev_err(dev: netdev, format: "failed to map rx page\n" ); |
714 | __free_page(page); |
715 | return -ENOMEM; |
716 | } |
717 | |
718 | ftmac100_rxdes_set_page(rxdes, page); |
719 | ftmac100_rxdes_set_dma_addr(rxdes, addr: map); |
720 | ftmac100_rxdes_set_buffer_size(rxdes, RX_BUF_SIZE); |
721 | ftmac100_rxdes_set_dma_own(rxdes); |
722 | return 0; |
723 | } |
724 | |
725 | static void ftmac100_free_buffers(struct ftmac100 *priv) |
726 | { |
727 | int i; |
728 | |
729 | for (i = 0; i < RX_QUEUE_ENTRIES; i++) { |
730 | struct ftmac100_rxdes *rxdes = &priv->descs->rxdes[i]; |
731 | struct page *page = ftmac100_rxdes_get_page(rxdes); |
732 | dma_addr_t map = ftmac100_rxdes_get_dma_addr(rxdes); |
733 | |
734 | if (!page) |
735 | continue; |
736 | |
737 | dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE); |
738 | __free_page(page); |
739 | } |
740 | |
741 | for (i = 0; i < TX_QUEUE_ENTRIES; i++) { |
742 | struct ftmac100_txdes *txdes = &priv->descs->txdes[i]; |
743 | struct sk_buff *skb = ftmac100_txdes_get_skb(txdes); |
744 | dma_addr_t map = ftmac100_txdes_get_dma_addr(txdes); |
745 | |
746 | if (!skb) |
747 | continue; |
748 | |
749 | dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE); |
750 | dev_kfree_skb(skb); |
751 | } |
752 | |
753 | dma_free_coherent(dev: priv->dev, size: sizeof(struct ftmac100_descs), |
754 | cpu_addr: priv->descs, dma_handle: priv->descs_dma_addr); |
755 | } |
756 | |
757 | static int ftmac100_alloc_buffers(struct ftmac100 *priv) |
758 | { |
759 | int i; |
760 | |
761 | priv->descs = dma_alloc_coherent(dev: priv->dev, |
762 | size: sizeof(struct ftmac100_descs), |
763 | dma_handle: &priv->descs_dma_addr, GFP_KERNEL); |
764 | if (!priv->descs) |
765 | return -ENOMEM; |
766 | |
767 | /* initialize RX ring */ |
768 | ftmac100_rxdes_set_end_of_ring(rxdes: &priv->descs->rxdes[RX_QUEUE_ENTRIES - 1]); |
769 | |
770 | for (i = 0; i < RX_QUEUE_ENTRIES; i++) { |
771 | struct ftmac100_rxdes *rxdes = &priv->descs->rxdes[i]; |
772 | |
773 | if (ftmac100_alloc_rx_page(priv, rxdes, GFP_KERNEL)) |
774 | goto err; |
775 | } |
776 | |
777 | /* initialize TX ring */ |
778 | ftmac100_txdes_set_end_of_ring(txdes: &priv->descs->txdes[TX_QUEUE_ENTRIES - 1]); |
779 | return 0; |
780 | |
781 | err: |
782 | ftmac100_free_buffers(priv); |
783 | return -ENOMEM; |
784 | } |
785 | |
786 | /****************************************************************************** |
787 | * struct mii_if_info functions |
788 | *****************************************************************************/ |
789 | static int ftmac100_mdio_read(struct net_device *netdev, int phy_id, int reg) |
790 | { |
791 | struct ftmac100 *priv = netdev_priv(dev: netdev); |
792 | unsigned int phycr; |
793 | int i; |
794 | |
795 | phycr = FTMAC100_PHYCR_PHYAD(phy_id) | |
796 | FTMAC100_PHYCR_REGAD(reg) | |
797 | FTMAC100_PHYCR_MIIRD; |
798 | |
799 | iowrite32(phycr, priv->base + FTMAC100_OFFSET_PHYCR); |
800 | |
801 | for (i = 0; i < 10; i++) { |
802 | phycr = ioread32(priv->base + FTMAC100_OFFSET_PHYCR); |
803 | |
804 | if ((phycr & FTMAC100_PHYCR_MIIRD) == 0) |
805 | return phycr & FTMAC100_PHYCR_MIIRDATA; |
806 | |
807 | udelay(100); |
808 | } |
809 | |
810 | netdev_err(dev: netdev, format: "mdio read timed out\n" ); |
811 | return 0; |
812 | } |
813 | |
814 | static void ftmac100_mdio_write(struct net_device *netdev, int phy_id, int reg, |
815 | int data) |
816 | { |
817 | struct ftmac100 *priv = netdev_priv(dev: netdev); |
818 | unsigned int phycr; |
819 | int i; |
820 | |
821 | phycr = FTMAC100_PHYCR_PHYAD(phy_id) | |
822 | FTMAC100_PHYCR_REGAD(reg) | |
823 | FTMAC100_PHYCR_MIIWR; |
824 | |
825 | data = FTMAC100_PHYWDATA_MIIWDATA(data); |
826 | |
827 | iowrite32(data, priv->base + FTMAC100_OFFSET_PHYWDATA); |
828 | iowrite32(phycr, priv->base + FTMAC100_OFFSET_PHYCR); |
829 | |
830 | for (i = 0; i < 10; i++) { |
831 | phycr = ioread32(priv->base + FTMAC100_OFFSET_PHYCR); |
832 | |
833 | if ((phycr & FTMAC100_PHYCR_MIIWR) == 0) |
834 | return; |
835 | |
836 | udelay(100); |
837 | } |
838 | |
839 | netdev_err(dev: netdev, format: "mdio write timed out\n" ); |
840 | } |
841 | |
842 | /****************************************************************************** |
843 | * struct ethtool_ops functions |
844 | *****************************************************************************/ |
845 | static void ftmac100_get_drvinfo(struct net_device *netdev, |
846 | struct ethtool_drvinfo *info) |
847 | { |
848 | strscpy(p: info->driver, DRV_NAME, size: sizeof(info->driver)); |
849 | strscpy(p: info->bus_info, q: dev_name(dev: &netdev->dev), size: sizeof(info->bus_info)); |
850 | } |
851 | |
852 | static int ftmac100_get_link_ksettings(struct net_device *netdev, |
853 | struct ethtool_link_ksettings *cmd) |
854 | { |
855 | struct ftmac100 *priv = netdev_priv(dev: netdev); |
856 | |
857 | mii_ethtool_get_link_ksettings(mii: &priv->mii, cmd); |
858 | |
859 | return 0; |
860 | } |
861 | |
862 | static int ftmac100_set_link_ksettings(struct net_device *netdev, |
863 | const struct ethtool_link_ksettings *cmd) |
864 | { |
865 | struct ftmac100 *priv = netdev_priv(dev: netdev); |
866 | return mii_ethtool_set_link_ksettings(mii: &priv->mii, cmd); |
867 | } |
868 | |
869 | static int ftmac100_nway_reset(struct net_device *netdev) |
870 | { |
871 | struct ftmac100 *priv = netdev_priv(dev: netdev); |
872 | return mii_nway_restart(mii: &priv->mii); |
873 | } |
874 | |
875 | static u32 ftmac100_get_link(struct net_device *netdev) |
876 | { |
877 | struct ftmac100 *priv = netdev_priv(dev: netdev); |
878 | return mii_link_ok(mii: &priv->mii); |
879 | } |
880 | |
881 | static const struct ethtool_ops ftmac100_ethtool_ops = { |
882 | .get_drvinfo = ftmac100_get_drvinfo, |
883 | .nway_reset = ftmac100_nway_reset, |
884 | .get_link = ftmac100_get_link, |
885 | .get_link_ksettings = ftmac100_get_link_ksettings, |
886 | .set_link_ksettings = ftmac100_set_link_ksettings, |
887 | }; |
888 | |
889 | /****************************************************************************** |
890 | * interrupt handler |
891 | *****************************************************************************/ |
892 | static irqreturn_t ftmac100_interrupt(int irq, void *dev_id) |
893 | { |
894 | struct net_device *netdev = dev_id; |
895 | struct ftmac100 *priv = netdev_priv(dev: netdev); |
896 | |
897 | /* Disable interrupts for polling */ |
898 | ftmac100_disable_all_int(priv); |
899 | if (likely(netif_running(netdev))) |
900 | napi_schedule(n: &priv->napi); |
901 | |
902 | return IRQ_HANDLED; |
903 | } |
904 | |
905 | /****************************************************************************** |
906 | * struct napi_struct functions |
907 | *****************************************************************************/ |
908 | static int ftmac100_poll(struct napi_struct *napi, int budget) |
909 | { |
910 | struct ftmac100 *priv = container_of(napi, struct ftmac100, napi); |
911 | struct net_device *netdev = priv->netdev; |
912 | unsigned int status; |
913 | bool completed = true; |
914 | int rx = 0; |
915 | |
916 | status = ioread32(priv->base + FTMAC100_OFFSET_ISR); |
917 | |
918 | if (status & (FTMAC100_INT_RPKT_FINISH | FTMAC100_INT_NORXBUF)) { |
919 | /* |
920 | * FTMAC100_INT_RPKT_FINISH: |
921 | * RX DMA has received packets into RX buffer successfully |
922 | * |
923 | * FTMAC100_INT_NORXBUF: |
924 | * RX buffer unavailable |
925 | */ |
926 | bool retry; |
927 | |
928 | do { |
929 | retry = ftmac100_rx_packet(priv, processed: &rx); |
930 | } while (retry && rx < budget); |
931 | |
932 | if (retry && rx == budget) |
933 | completed = false; |
934 | } |
935 | |
936 | if (status & (FTMAC100_INT_XPKT_OK | FTMAC100_INT_XPKT_LOST)) { |
937 | /* |
938 | * FTMAC100_INT_XPKT_OK: |
939 | * packet transmitted to ethernet successfully |
940 | * |
941 | * FTMAC100_INT_XPKT_LOST: |
942 | * packet transmitted to ethernet lost due to late |
943 | * collision or excessive collision |
944 | */ |
945 | ftmac100_tx_complete(priv); |
946 | } |
947 | |
948 | if (status & (FTMAC100_INT_NORXBUF | FTMAC100_INT_RPKT_LOST | |
949 | FTMAC100_INT_AHB_ERR | FTMAC100_INT_PHYSTS_CHG)) { |
950 | if (net_ratelimit()) |
951 | netdev_info(dev: netdev, format: "[ISR] = 0x%x: %s%s%s%s\n" , status, |
952 | status & FTMAC100_INT_NORXBUF ? "NORXBUF " : "" , |
953 | status & FTMAC100_INT_RPKT_LOST ? "RPKT_LOST " : "" , |
954 | status & FTMAC100_INT_AHB_ERR ? "AHB_ERR " : "" , |
955 | status & FTMAC100_INT_PHYSTS_CHG ? "PHYSTS_CHG" : "" ); |
956 | |
957 | if (status & FTMAC100_INT_NORXBUF) { |
958 | /* RX buffer unavailable */ |
959 | netdev->stats.rx_over_errors++; |
960 | } |
961 | |
962 | if (status & FTMAC100_INT_RPKT_LOST) { |
963 | /* received packet lost due to RX FIFO full */ |
964 | netdev->stats.rx_fifo_errors++; |
965 | } |
966 | |
967 | if (status & FTMAC100_INT_PHYSTS_CHG) { |
968 | /* PHY link status change */ |
969 | mii_check_link(mii: &priv->mii); |
970 | } |
971 | } |
972 | |
973 | if (completed) { |
974 | /* stop polling */ |
975 | napi_complete(n: napi); |
976 | ftmac100_enable_all_int(priv); |
977 | } |
978 | |
979 | return rx; |
980 | } |
981 | |
982 | /****************************************************************************** |
983 | * struct net_device_ops functions |
984 | *****************************************************************************/ |
985 | static int ftmac100_open(struct net_device *netdev) |
986 | { |
987 | struct ftmac100 *priv = netdev_priv(dev: netdev); |
988 | int err; |
989 | |
990 | err = ftmac100_alloc_buffers(priv); |
991 | if (err) { |
992 | netdev_err(dev: netdev, format: "failed to allocate buffers\n" ); |
993 | goto err_alloc; |
994 | } |
995 | |
996 | err = request_irq(irq: priv->irq, handler: ftmac100_interrupt, flags: 0, name: netdev->name, dev: netdev); |
997 | if (err) { |
998 | netdev_err(dev: netdev, format: "failed to request irq %d\n" , priv->irq); |
999 | goto err_irq; |
1000 | } |
1001 | |
1002 | priv->rx_pointer = 0; |
1003 | priv->tx_clean_pointer = 0; |
1004 | priv->tx_pointer = 0; |
1005 | priv->tx_pending = 0; |
1006 | |
1007 | err = ftmac100_start_hw(priv); |
1008 | if (err) |
1009 | goto err_hw; |
1010 | |
1011 | napi_enable(n: &priv->napi); |
1012 | netif_start_queue(dev: netdev); |
1013 | |
1014 | ftmac100_enable_all_int(priv); |
1015 | |
1016 | return 0; |
1017 | |
1018 | err_hw: |
1019 | free_irq(priv->irq, netdev); |
1020 | err_irq: |
1021 | ftmac100_free_buffers(priv); |
1022 | err_alloc: |
1023 | return err; |
1024 | } |
1025 | |
1026 | static int ftmac100_stop(struct net_device *netdev) |
1027 | { |
1028 | struct ftmac100 *priv = netdev_priv(dev: netdev); |
1029 | |
1030 | ftmac100_disable_all_int(priv); |
1031 | netif_stop_queue(dev: netdev); |
1032 | napi_disable(n: &priv->napi); |
1033 | ftmac100_stop_hw(priv); |
1034 | free_irq(priv->irq, netdev); |
1035 | ftmac100_free_buffers(priv); |
1036 | |
1037 | return 0; |
1038 | } |
1039 | |
1040 | static netdev_tx_t |
1041 | ftmac100_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) |
1042 | { |
1043 | struct ftmac100 *priv = netdev_priv(dev: netdev); |
1044 | dma_addr_t map; |
1045 | |
1046 | if (unlikely(skb->len > MAX_PKT_SIZE)) { |
1047 | if (net_ratelimit()) |
1048 | netdev_dbg(netdev, "tx packet too big\n" ); |
1049 | |
1050 | netdev->stats.tx_dropped++; |
1051 | dev_kfree_skb(skb); |
1052 | return NETDEV_TX_OK; |
1053 | } |
1054 | |
1055 | map = dma_map_single(priv->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); |
1056 | if (unlikely(dma_mapping_error(priv->dev, map))) { |
1057 | /* drop packet */ |
1058 | if (net_ratelimit()) |
1059 | netdev_err(dev: netdev, format: "map socket buffer failed\n" ); |
1060 | |
1061 | netdev->stats.tx_dropped++; |
1062 | dev_kfree_skb(skb); |
1063 | return NETDEV_TX_OK; |
1064 | } |
1065 | |
1066 | return ftmac100_xmit(priv, skb, map); |
1067 | } |
1068 | |
1069 | /* optional */ |
1070 | static int ftmac100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) |
1071 | { |
1072 | struct ftmac100 *priv = netdev_priv(dev: netdev); |
1073 | struct mii_ioctl_data *data = if_mii(rq: ifr); |
1074 | |
1075 | return generic_mii_ioctl(mii_if: &priv->mii, mii_data: data, cmd, NULL); |
1076 | } |
1077 | |
1078 | static int ftmac100_change_mtu(struct net_device *netdev, int mtu) |
1079 | { |
1080 | struct ftmac100 *priv = netdev_priv(dev: netdev); |
1081 | unsigned int maccr; |
1082 | |
1083 | maccr = ioread32(priv->base + FTMAC100_OFFSET_MACCR); |
1084 | if (mtu > ETH_DATA_LEN) { |
1085 | /* process long packets in the driver */ |
1086 | maccr |= FTMAC100_MACCR_RX_FTL; |
1087 | } else { |
1088 | /* Let the controller drop incoming packets greater |
1089 | * than 1518 (that is 1500 + 14 Ethernet + 4 FCS). |
1090 | */ |
1091 | maccr &= ~FTMAC100_MACCR_RX_FTL; |
1092 | } |
1093 | iowrite32(maccr, priv->base + FTMAC100_OFFSET_MACCR); |
1094 | |
1095 | netdev->mtu = mtu; |
1096 | |
1097 | return 0; |
1098 | } |
1099 | |
1100 | static void ftmac100_set_rx_mode(struct net_device *netdev) |
1101 | { |
1102 | struct ftmac100 *priv = netdev_priv(dev: netdev); |
1103 | unsigned int maccr = ioread32(priv->base + FTMAC100_OFFSET_MACCR); |
1104 | |
1105 | ftmac100_set_rx_bits(priv, maccr: &maccr); |
1106 | iowrite32(maccr, priv->base + FTMAC100_OFFSET_MACCR); |
1107 | } |
1108 | |
1109 | static const struct net_device_ops ftmac100_netdev_ops = { |
1110 | .ndo_open = ftmac100_open, |
1111 | .ndo_stop = ftmac100_stop, |
1112 | .ndo_start_xmit = ftmac100_hard_start_xmit, |
1113 | .ndo_set_mac_address = eth_mac_addr, |
1114 | .ndo_validate_addr = eth_validate_addr, |
1115 | .ndo_eth_ioctl = ftmac100_do_ioctl, |
1116 | .ndo_change_mtu = ftmac100_change_mtu, |
1117 | .ndo_set_rx_mode = ftmac100_set_rx_mode, |
1118 | }; |
1119 | |
1120 | /****************************************************************************** |
1121 | * struct platform_driver functions |
1122 | *****************************************************************************/ |
1123 | static int ftmac100_probe(struct platform_device *pdev) |
1124 | { |
1125 | struct resource *res; |
1126 | int irq; |
1127 | struct net_device *netdev; |
1128 | struct ftmac100 *priv; |
1129 | int err; |
1130 | |
1131 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1132 | if (!res) |
1133 | return -ENXIO; |
1134 | |
1135 | irq = platform_get_irq(pdev, 0); |
1136 | if (irq < 0) |
1137 | return irq; |
1138 | |
1139 | /* setup net_device */ |
1140 | netdev = alloc_etherdev(sizeof(*priv)); |
1141 | if (!netdev) { |
1142 | err = -ENOMEM; |
1143 | goto err_alloc_etherdev; |
1144 | } |
1145 | |
1146 | SET_NETDEV_DEV(netdev, &pdev->dev); |
1147 | netdev->ethtool_ops = &ftmac100_ethtool_ops; |
1148 | netdev->netdev_ops = &ftmac100_netdev_ops; |
1149 | netdev->max_mtu = MAX_PKT_SIZE - VLAN_ETH_HLEN; |
1150 | |
1151 | err = platform_get_ethdev_address(dev: &pdev->dev, netdev); |
1152 | if (err == -EPROBE_DEFER) |
1153 | goto defer_get_mac; |
1154 | |
1155 | platform_set_drvdata(pdev, data: netdev); |
1156 | |
1157 | /* setup private data */ |
1158 | priv = netdev_priv(dev: netdev); |
1159 | priv->netdev = netdev; |
1160 | priv->dev = &pdev->dev; |
1161 | |
1162 | spin_lock_init(&priv->tx_lock); |
1163 | |
1164 | /* initialize NAPI */ |
1165 | netif_napi_add(dev: netdev, napi: &priv->napi, poll: ftmac100_poll); |
1166 | |
1167 | /* map io memory */ |
1168 | priv->res = request_mem_region(res->start, resource_size(res), |
1169 | dev_name(&pdev->dev)); |
1170 | if (!priv->res) { |
1171 | dev_err(&pdev->dev, "Could not reserve memory region\n" ); |
1172 | err = -ENOMEM; |
1173 | goto err_req_mem; |
1174 | } |
1175 | |
1176 | priv->base = ioremap(offset: res->start, size: resource_size(res)); |
1177 | if (!priv->base) { |
1178 | dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n" ); |
1179 | err = -EIO; |
1180 | goto err_ioremap; |
1181 | } |
1182 | |
1183 | priv->irq = irq; |
1184 | |
1185 | /* initialize struct mii_if_info */ |
1186 | priv->mii.phy_id = 0; |
1187 | priv->mii.phy_id_mask = 0x1f; |
1188 | priv->mii.reg_num_mask = 0x1f; |
1189 | priv->mii.dev = netdev; |
1190 | priv->mii.mdio_read = ftmac100_mdio_read; |
1191 | priv->mii.mdio_write = ftmac100_mdio_write; |
1192 | |
1193 | /* register network device */ |
1194 | err = register_netdev(dev: netdev); |
1195 | if (err) { |
1196 | dev_err(&pdev->dev, "Failed to register netdev\n" ); |
1197 | goto err_register_netdev; |
1198 | } |
1199 | |
1200 | netdev_info(dev: netdev, format: "irq %d, mapped at %p\n" , priv->irq, priv->base); |
1201 | |
1202 | if (!is_valid_ether_addr(addr: netdev->dev_addr)) { |
1203 | eth_hw_addr_random(dev: netdev); |
1204 | netdev_info(dev: netdev, format: "generated random MAC address %pM\n" , |
1205 | netdev->dev_addr); |
1206 | } |
1207 | |
1208 | return 0; |
1209 | |
1210 | err_register_netdev: |
1211 | iounmap(addr: priv->base); |
1212 | err_ioremap: |
1213 | release_resource(new: priv->res); |
1214 | err_req_mem: |
1215 | netif_napi_del(napi: &priv->napi); |
1216 | defer_get_mac: |
1217 | free_netdev(dev: netdev); |
1218 | err_alloc_etherdev: |
1219 | return err; |
1220 | } |
1221 | |
1222 | static void ftmac100_remove(struct platform_device *pdev) |
1223 | { |
1224 | struct net_device *netdev; |
1225 | struct ftmac100 *priv; |
1226 | |
1227 | netdev = platform_get_drvdata(pdev); |
1228 | priv = netdev_priv(dev: netdev); |
1229 | |
1230 | unregister_netdev(dev: netdev); |
1231 | |
1232 | iounmap(addr: priv->base); |
1233 | release_resource(new: priv->res); |
1234 | |
1235 | netif_napi_del(napi: &priv->napi); |
1236 | free_netdev(dev: netdev); |
1237 | } |
1238 | |
1239 | static const struct of_device_id ftmac100_of_ids[] = { |
1240 | { .compatible = "andestech,atmac100" }, |
1241 | { } |
1242 | }; |
1243 | |
1244 | static struct platform_driver ftmac100_driver = { |
1245 | .probe = ftmac100_probe, |
1246 | .remove_new = ftmac100_remove, |
1247 | .driver = { |
1248 | .name = DRV_NAME, |
1249 | .of_match_table = ftmac100_of_ids |
1250 | }, |
1251 | }; |
1252 | |
1253 | /****************************************************************************** |
1254 | * initialization / finalization |
1255 | *****************************************************************************/ |
1256 | module_platform_driver(ftmac100_driver); |
1257 | |
1258 | MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>" ); |
1259 | MODULE_DESCRIPTION("FTMAC100 driver" ); |
1260 | MODULE_LICENSE("GPL" ); |
1261 | MODULE_DEVICE_TABLE(of, ftmac100_of_ids); |
1262 | |