]>
Commit | Line | Data |
---|---|---|
69785b79 PYC |
1 | /* |
2 | * Faraday FTGMAC100 Gigabit Ethernet | |
3 | * | |
4 | * (C) Copyright 2009-2011 Faraday Technology | |
5 | * Po-Yu Chuang <ratbert@faraday-tech.com> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program; if not, write to the Free Software | |
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
20 | */ | |
21 | ||
22 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
23 | ||
24 | #include <linux/dma-mapping.h> | |
25 | #include <linux/etherdevice.h> | |
26 | #include <linux/ethtool.h> | |
17f1bbca | 27 | #include <linux/interrupt.h> |
69785b79 PYC |
28 | #include <linux/io.h> |
29 | #include <linux/module.h> | |
30 | #include <linux/netdevice.h> | |
d39004ab | 31 | #include <linux/of.h> |
69785b79 PYC |
32 | #include <linux/phy.h> |
33 | #include <linux/platform_device.h> | |
34 | #include <net/ip.h> | |
bd466c3f | 35 | #include <net/ncsi.h> |
69785b79 PYC |
36 | |
37 | #include "ftgmac100.h" | |
38 | ||
39 | #define DRV_NAME "ftgmac100" | |
40 | #define DRV_VERSION "0.7" | |
41 | ||
42 | #define RX_QUEUE_ENTRIES 256 /* must be power of 2 */ | |
43 | #define TX_QUEUE_ENTRIES 512 /* must be power of 2 */ | |
44 | ||
45 | #define MAX_PKT_SIZE 1518 | |
46 | #define RX_BUF_SIZE PAGE_SIZE /* must be smaller than 0x3fff */ | |
47 | ||
48 | /****************************************************************************** | |
49 | * private data | |
50 | *****************************************************************************/ | |
51 | struct ftgmac100_descs { | |
52 | struct ftgmac100_rxdes rxdes[RX_QUEUE_ENTRIES]; | |
53 | struct ftgmac100_txdes txdes[TX_QUEUE_ENTRIES]; | |
54 | }; | |
55 | ||
56 | struct ftgmac100 { | |
57 | struct resource *res; | |
58 | void __iomem *base; | |
59 | int irq; | |
60 | ||
61 | struct ftgmac100_descs *descs; | |
62 | dma_addr_t descs_dma_addr; | |
63 | ||
ada66b54 AJ |
64 | struct page *rx_pages[RX_QUEUE_ENTRIES]; |
65 | ||
69785b79 PYC |
66 | unsigned int rx_pointer; |
67 | unsigned int tx_clean_pointer; | |
68 | unsigned int tx_pointer; | |
69 | unsigned int tx_pending; | |
70 | ||
71 | spinlock_t tx_lock; | |
72 | ||
73 | struct net_device *netdev; | |
74 | struct device *dev; | |
bd466c3f | 75 | struct ncsi_dev *ndev; |
69785b79 PYC |
76 | struct napi_struct napi; |
77 | ||
78 | struct mii_bus *mii_bus; | |
69785b79 | 79 | int old_speed; |
fc6061cf | 80 | int int_mask_all; |
bd466c3f GS |
81 | bool use_ncsi; |
82 | bool enabled; | |
7906a4da AJ |
83 | |
84 | u32 rxdes0_edorr_mask; | |
85 | u32 txdes0_edotr_mask; | |
69785b79 PYC |
86 | }; |
87 | ||
88 | static int ftgmac100_alloc_rx_page(struct ftgmac100 *priv, | |
89 | struct ftgmac100_rxdes *rxdes, gfp_t gfp); | |
90 | ||
91 | /****************************************************************************** | |
92 | * internal functions (hardware register access) | |
93 | *****************************************************************************/ | |
69785b79 PYC |
94 | static void ftgmac100_set_rx_ring_base(struct ftgmac100 *priv, dma_addr_t addr) |
95 | { | |
96 | iowrite32(addr, priv->base + FTGMAC100_OFFSET_RXR_BADR); | |
97 | } | |
98 | ||
99 | static void ftgmac100_set_rx_buffer_size(struct ftgmac100 *priv, | |
100 | unsigned int size) | |
101 | { | |
102 | size = FTGMAC100_RBSR_SIZE(size); | |
103 | iowrite32(size, priv->base + FTGMAC100_OFFSET_RBSR); | |
104 | } | |
105 | ||
106 | static void ftgmac100_set_normal_prio_tx_ring_base(struct ftgmac100 *priv, | |
107 | dma_addr_t addr) | |
108 | { | |
109 | iowrite32(addr, priv->base + FTGMAC100_OFFSET_NPTXR_BADR); | |
110 | } | |
111 | ||
112 | static void ftgmac100_txdma_normal_prio_start_polling(struct ftgmac100 *priv) | |
113 | { | |
114 | iowrite32(1, priv->base + FTGMAC100_OFFSET_NPTXPD); | |
115 | } | |
116 | ||
117 | static int ftgmac100_reset_hw(struct ftgmac100 *priv) | |
118 | { | |
119 | struct net_device *netdev = priv->netdev; | |
120 | int i; | |
121 | ||
122 | /* NOTE: reset clears all registers */ | |
123 | iowrite32(FTGMAC100_MACCR_SW_RST, priv->base + FTGMAC100_OFFSET_MACCR); | |
124 | for (i = 0; i < 5; i++) { | |
125 | unsigned int maccr; | |
126 | ||
127 | maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR); | |
128 | if (!(maccr & FTGMAC100_MACCR_SW_RST)) | |
129 | return 0; | |
130 | ||
131 | udelay(1000); | |
132 | } | |
133 | ||
134 | netdev_err(netdev, "software reset failed\n"); | |
135 | return -EIO; | |
136 | } | |
137 | ||
138 | static void ftgmac100_set_mac(struct ftgmac100 *priv, const unsigned char *mac) | |
139 | { | |
140 | unsigned int maddr = mac[0] << 8 | mac[1]; | |
141 | unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5]; | |
142 | ||
143 | iowrite32(maddr, priv->base + FTGMAC100_OFFSET_MAC_MADR); | |
144 | iowrite32(laddr, priv->base + FTGMAC100_OFFSET_MAC_LADR); | |
145 | } | |
146 | ||
113ce107 GS |
147 | static void ftgmac100_setup_mac(struct ftgmac100 *priv) |
148 | { | |
149 | u8 mac[ETH_ALEN]; | |
150 | unsigned int m; | |
151 | unsigned int l; | |
152 | void *addr; | |
153 | ||
154 | addr = device_get_mac_address(priv->dev, mac, ETH_ALEN); | |
155 | if (addr) { | |
156 | ether_addr_copy(priv->netdev->dev_addr, mac); | |
157 | dev_info(priv->dev, "Read MAC address %pM from device tree\n", | |
158 | mac); | |
159 | return; | |
160 | } | |
161 | ||
162 | m = ioread32(priv->base + FTGMAC100_OFFSET_MAC_MADR); | |
163 | l = ioread32(priv->base + FTGMAC100_OFFSET_MAC_LADR); | |
164 | ||
165 | mac[0] = (m >> 8) & 0xff; | |
166 | mac[1] = m & 0xff; | |
167 | mac[2] = (l >> 24) & 0xff; | |
168 | mac[3] = (l >> 16) & 0xff; | |
169 | mac[4] = (l >> 8) & 0xff; | |
170 | mac[5] = l & 0xff; | |
171 | ||
113ce107 GS |
172 | if (is_valid_ether_addr(mac)) { |
173 | ether_addr_copy(priv->netdev->dev_addr, mac); | |
174 | dev_info(priv->dev, "Read MAC address %pM from chip\n", mac); | |
175 | } else { | |
176 | eth_hw_addr_random(priv->netdev); | |
177 | dev_info(priv->dev, "Generated random MAC address %pM\n", | |
178 | priv->netdev->dev_addr); | |
179 | } | |
180 | } | |
181 | ||
182 | static int ftgmac100_set_mac_addr(struct net_device *dev, void *p) | |
183 | { | |
184 | int ret; | |
185 | ||
186 | ret = eth_prepare_mac_addr_change(dev, p); | |
187 | if (ret < 0) | |
188 | return ret; | |
189 | ||
190 | eth_commit_mac_addr_change(dev, p); | |
191 | ftgmac100_set_mac(netdev_priv(dev), dev->dev_addr); | |
192 | ||
193 | return 0; | |
194 | } | |
195 | ||
69785b79 PYC |
196 | static void ftgmac100_init_hw(struct ftgmac100 *priv) |
197 | { | |
198 | /* setup ring buffer base registers */ | |
199 | ftgmac100_set_rx_ring_base(priv, | |
200 | priv->descs_dma_addr + | |
201 | offsetof(struct ftgmac100_descs, rxdes)); | |
202 | ftgmac100_set_normal_prio_tx_ring_base(priv, | |
203 | priv->descs_dma_addr + | |
204 | offsetof(struct ftgmac100_descs, txdes)); | |
205 | ||
206 | ftgmac100_set_rx_buffer_size(priv, RX_BUF_SIZE); | |
207 | ||
208 | iowrite32(FTGMAC100_APTC_RXPOLL_CNT(1), priv->base + FTGMAC100_OFFSET_APTC); | |
209 | ||
210 | ftgmac100_set_mac(priv, priv->netdev->dev_addr); | |
211 | } | |
212 | ||
213 | #define MACCR_ENABLE_ALL (FTGMAC100_MACCR_TXDMA_EN | \ | |
214 | FTGMAC100_MACCR_RXDMA_EN | \ | |
215 | FTGMAC100_MACCR_TXMAC_EN | \ | |
216 | FTGMAC100_MACCR_RXMAC_EN | \ | |
217 | FTGMAC100_MACCR_FULLDUP | \ | |
218 | FTGMAC100_MACCR_CRC_APD | \ | |
219 | FTGMAC100_MACCR_RX_RUNT | \ | |
220 | FTGMAC100_MACCR_RX_BROADPKT) | |
221 | ||
222 | static void ftgmac100_start_hw(struct ftgmac100 *priv, int speed) | |
223 | { | |
224 | int maccr = MACCR_ENABLE_ALL; | |
225 | ||
226 | switch (speed) { | |
227 | default: | |
228 | case 10: | |
229 | break; | |
230 | ||
231 | case 100: | |
232 | maccr |= FTGMAC100_MACCR_FAST_MODE; | |
233 | break; | |
234 | ||
235 | case 1000: | |
236 | maccr |= FTGMAC100_MACCR_GIGA_MODE; | |
237 | break; | |
238 | } | |
239 | ||
240 | iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR); | |
241 | } | |
242 | ||
243 | static void ftgmac100_stop_hw(struct ftgmac100 *priv) | |
244 | { | |
245 | iowrite32(0, priv->base + FTGMAC100_OFFSET_MACCR); | |
246 | } | |
247 | ||
248 | /****************************************************************************** | |
249 | * internal functions (receive descriptor) | |
250 | *****************************************************************************/ | |
251 | static bool ftgmac100_rxdes_first_segment(struct ftgmac100_rxdes *rxdes) | |
252 | { | |
253 | return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_FRS); | |
254 | } | |
255 | ||
256 | static bool ftgmac100_rxdes_last_segment(struct ftgmac100_rxdes *rxdes) | |
257 | { | |
258 | return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_LRS); | |
259 | } | |
260 | ||
261 | static bool ftgmac100_rxdes_packet_ready(struct ftgmac100_rxdes *rxdes) | |
262 | { | |
263 | return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RXPKT_RDY); | |
264 | } | |
265 | ||
7906a4da AJ |
266 | static void ftgmac100_rxdes_set_dma_own(const struct ftgmac100 *priv, |
267 | struct ftgmac100_rxdes *rxdes) | |
69785b79 PYC |
268 | { |
269 | /* clear status bits */ | |
7906a4da | 270 | rxdes->rxdes0 &= cpu_to_le32(priv->rxdes0_edorr_mask); |
69785b79 PYC |
271 | } |
272 | ||
273 | static bool ftgmac100_rxdes_rx_error(struct ftgmac100_rxdes *rxdes) | |
274 | { | |
275 | return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RX_ERR); | |
276 | } | |
277 | ||
278 | static bool ftgmac100_rxdes_crc_error(struct ftgmac100_rxdes *rxdes) | |
279 | { | |
280 | return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_CRC_ERR); | |
281 | } | |
282 | ||
283 | static bool ftgmac100_rxdes_frame_too_long(struct ftgmac100_rxdes *rxdes) | |
284 | { | |
285 | return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_FTL); | |
286 | } | |
287 | ||
288 | static bool ftgmac100_rxdes_runt(struct ftgmac100_rxdes *rxdes) | |
289 | { | |
290 | return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RUNT); | |
291 | } | |
292 | ||
293 | static bool ftgmac100_rxdes_odd_nibble(struct ftgmac100_rxdes *rxdes) | |
294 | { | |
295 | return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RX_ODD_NB); | |
296 | } | |
297 | ||
298 | static unsigned int ftgmac100_rxdes_data_length(struct ftgmac100_rxdes *rxdes) | |
299 | { | |
300 | return le32_to_cpu(rxdes->rxdes0) & FTGMAC100_RXDES0_VDBC; | |
301 | } | |
302 | ||
303 | static bool ftgmac100_rxdes_multicast(struct ftgmac100_rxdes *rxdes) | |
304 | { | |
305 | return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_MULTICAST); | |
306 | } | |
307 | ||
7906a4da AJ |
308 | static void ftgmac100_rxdes_set_end_of_ring(const struct ftgmac100 *priv, |
309 | struct ftgmac100_rxdes *rxdes) | |
69785b79 | 310 | { |
7906a4da | 311 | rxdes->rxdes0 |= cpu_to_le32(priv->rxdes0_edorr_mask); |
69785b79 PYC |
312 | } |
313 | ||
314 | static void ftgmac100_rxdes_set_dma_addr(struct ftgmac100_rxdes *rxdes, | |
315 | dma_addr_t addr) | |
316 | { | |
317 | rxdes->rxdes3 = cpu_to_le32(addr); | |
318 | } | |
319 | ||
320 | static dma_addr_t ftgmac100_rxdes_get_dma_addr(struct ftgmac100_rxdes *rxdes) | |
321 | { | |
322 | return le32_to_cpu(rxdes->rxdes3); | |
323 | } | |
324 | ||
325 | static bool ftgmac100_rxdes_is_tcp(struct ftgmac100_rxdes *rxdes) | |
326 | { | |
327 | return (rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_PROT_MASK)) == | |
328 | cpu_to_le32(FTGMAC100_RXDES1_PROT_TCPIP); | |
329 | } | |
330 | ||
331 | static bool ftgmac100_rxdes_is_udp(struct ftgmac100_rxdes *rxdes) | |
332 | { | |
333 | return (rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_PROT_MASK)) == | |
334 | cpu_to_le32(FTGMAC100_RXDES1_PROT_UDPIP); | |
335 | } | |
336 | ||
337 | static bool ftgmac100_rxdes_tcpcs_err(struct ftgmac100_rxdes *rxdes) | |
338 | { | |
339 | return rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_TCP_CHKSUM_ERR); | |
340 | } | |
341 | ||
342 | static bool ftgmac100_rxdes_udpcs_err(struct ftgmac100_rxdes *rxdes) | |
343 | { | |
344 | return rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_UDP_CHKSUM_ERR); | |
345 | } | |
346 | ||
347 | static bool ftgmac100_rxdes_ipcs_err(struct ftgmac100_rxdes *rxdes) | |
348 | { | |
349 | return rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_IP_CHKSUM_ERR); | |
350 | } | |
351 | ||
ada66b54 AJ |
352 | static inline struct page **ftgmac100_rxdes_page_slot(struct ftgmac100 *priv, |
353 | struct ftgmac100_rxdes *rxdes) | |
354 | { | |
355 | return &priv->rx_pages[rxdes - priv->descs->rxdes]; | |
356 | } | |
357 | ||
69785b79 PYC |
358 | /* |
359 | * rxdes2 is not used by hardware. We use it to keep track of page. | |
360 | * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu(). | |
361 | */ | |
ada66b54 AJ |
362 | static void ftgmac100_rxdes_set_page(struct ftgmac100 *priv, |
363 | struct ftgmac100_rxdes *rxdes, | |
364 | struct page *page) | |
69785b79 | 365 | { |
ada66b54 | 366 | *ftgmac100_rxdes_page_slot(priv, rxdes) = page; |
69785b79 PYC |
367 | } |
368 | ||
ada66b54 AJ |
369 | static struct page *ftgmac100_rxdes_get_page(struct ftgmac100 *priv, |
370 | struct ftgmac100_rxdes *rxdes) | |
69785b79 | 371 | { |
ada66b54 | 372 | return *ftgmac100_rxdes_page_slot(priv, rxdes); |
69785b79 PYC |
373 | } |
374 | ||
375 | /****************************************************************************** | |
376 | * internal functions (receive) | |
377 | *****************************************************************************/ | |
378 | static int ftgmac100_next_rx_pointer(int pointer) | |
379 | { | |
380 | return (pointer + 1) & (RX_QUEUE_ENTRIES - 1); | |
381 | } | |
382 | ||
383 | static void ftgmac100_rx_pointer_advance(struct ftgmac100 *priv) | |
384 | { | |
385 | priv->rx_pointer = ftgmac100_next_rx_pointer(priv->rx_pointer); | |
386 | } | |
387 | ||
388 | static struct ftgmac100_rxdes *ftgmac100_current_rxdes(struct ftgmac100 *priv) | |
389 | { | |
390 | return &priv->descs->rxdes[priv->rx_pointer]; | |
391 | } | |
392 | ||
393 | static struct ftgmac100_rxdes * | |
394 | ftgmac100_rx_locate_first_segment(struct ftgmac100 *priv) | |
395 | { | |
396 | struct ftgmac100_rxdes *rxdes = ftgmac100_current_rxdes(priv); | |
397 | ||
398 | while (ftgmac100_rxdes_packet_ready(rxdes)) { | |
399 | if (ftgmac100_rxdes_first_segment(rxdes)) | |
400 | return rxdes; | |
401 | ||
7906a4da | 402 | ftgmac100_rxdes_set_dma_own(priv, rxdes); |
69785b79 PYC |
403 | ftgmac100_rx_pointer_advance(priv); |
404 | rxdes = ftgmac100_current_rxdes(priv); | |
405 | } | |
406 | ||
407 | return NULL; | |
408 | } | |
409 | ||
410 | static bool ftgmac100_rx_packet_error(struct ftgmac100 *priv, | |
411 | struct ftgmac100_rxdes *rxdes) | |
412 | { | |
413 | struct net_device *netdev = priv->netdev; | |
414 | bool error = false; | |
415 | ||
416 | if (unlikely(ftgmac100_rxdes_rx_error(rxdes))) { | |
417 | if (net_ratelimit()) | |
418 | netdev_info(netdev, "rx err\n"); | |
419 | ||
420 | netdev->stats.rx_errors++; | |
421 | error = true; | |
422 | } | |
423 | ||
424 | if (unlikely(ftgmac100_rxdes_crc_error(rxdes))) { | |
425 | if (net_ratelimit()) | |
426 | netdev_info(netdev, "rx crc err\n"); | |
427 | ||
428 | netdev->stats.rx_crc_errors++; | |
429 | error = true; | |
430 | } else if (unlikely(ftgmac100_rxdes_ipcs_err(rxdes))) { | |
431 | if (net_ratelimit()) | |
432 | netdev_info(netdev, "rx IP checksum err\n"); | |
433 | ||
434 | error = true; | |
435 | } | |
436 | ||
437 | if (unlikely(ftgmac100_rxdes_frame_too_long(rxdes))) { | |
438 | if (net_ratelimit()) | |
439 | netdev_info(netdev, "rx frame too long\n"); | |
440 | ||
441 | netdev->stats.rx_length_errors++; | |
442 | error = true; | |
443 | } else if (unlikely(ftgmac100_rxdes_runt(rxdes))) { | |
444 | if (net_ratelimit()) | |
445 | netdev_info(netdev, "rx runt\n"); | |
446 | ||
447 | netdev->stats.rx_length_errors++; | |
448 | error = true; | |
449 | } else if (unlikely(ftgmac100_rxdes_odd_nibble(rxdes))) { | |
450 | if (net_ratelimit()) | |
451 | netdev_info(netdev, "rx odd nibble\n"); | |
452 | ||
453 | netdev->stats.rx_length_errors++; | |
454 | error = true; | |
455 | } | |
456 | ||
457 | return error; | |
458 | } | |
459 | ||
460 | static void ftgmac100_rx_drop_packet(struct ftgmac100 *priv) | |
461 | { | |
462 | struct net_device *netdev = priv->netdev; | |
463 | struct ftgmac100_rxdes *rxdes = ftgmac100_current_rxdes(priv); | |
464 | bool done = false; | |
465 | ||
466 | if (net_ratelimit()) | |
467 | netdev_dbg(netdev, "drop packet %p\n", rxdes); | |
468 | ||
469 | do { | |
470 | if (ftgmac100_rxdes_last_segment(rxdes)) | |
471 | done = true; | |
472 | ||
7906a4da | 473 | ftgmac100_rxdes_set_dma_own(priv, rxdes); |
69785b79 PYC |
474 | ftgmac100_rx_pointer_advance(priv); |
475 | rxdes = ftgmac100_current_rxdes(priv); | |
476 | } while (!done && ftgmac100_rxdes_packet_ready(rxdes)); | |
477 | ||
478 | netdev->stats.rx_dropped++; | |
479 | } | |
480 | ||
481 | static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed) | |
482 | { | |
483 | struct net_device *netdev = priv->netdev; | |
484 | struct ftgmac100_rxdes *rxdes; | |
485 | struct sk_buff *skb; | |
486 | bool done = false; | |
487 | ||
488 | rxdes = ftgmac100_rx_locate_first_segment(priv); | |
489 | if (!rxdes) | |
490 | return false; | |
491 | ||
492 | if (unlikely(ftgmac100_rx_packet_error(priv, rxdes))) { | |
493 | ftgmac100_rx_drop_packet(priv); | |
494 | return true; | |
495 | } | |
496 | ||
497 | /* start processing */ | |
498 | skb = netdev_alloc_skb_ip_align(netdev, 128); | |
499 | if (unlikely(!skb)) { | |
500 | if (net_ratelimit()) | |
501 | netdev_err(netdev, "rx skb alloc failed\n"); | |
502 | ||
503 | ftgmac100_rx_drop_packet(priv); | |
504 | return true; | |
505 | } | |
506 | ||
507 | if (unlikely(ftgmac100_rxdes_multicast(rxdes))) | |
508 | netdev->stats.multicast++; | |
509 | ||
510 | /* | |
511 | * It seems that HW does checksum incorrectly with fragmented packets, | |
512 | * so we are conservative here - if HW checksum error, let software do | |
513 | * the checksum again. | |
514 | */ | |
515 | if ((ftgmac100_rxdes_is_tcp(rxdes) && !ftgmac100_rxdes_tcpcs_err(rxdes)) || | |
516 | (ftgmac100_rxdes_is_udp(rxdes) && !ftgmac100_rxdes_udpcs_err(rxdes))) | |
517 | skb->ip_summed = CHECKSUM_UNNECESSARY; | |
518 | ||
519 | do { | |
520 | dma_addr_t map = ftgmac100_rxdes_get_dma_addr(rxdes); | |
ada66b54 | 521 | struct page *page = ftgmac100_rxdes_get_page(priv, rxdes); |
69785b79 PYC |
522 | unsigned int size; |
523 | ||
524 | dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE); | |
525 | ||
526 | size = ftgmac100_rxdes_data_length(rxdes); | |
527 | skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page, 0, size); | |
528 | ||
529 | skb->len += size; | |
530 | skb->data_len += size; | |
5935f81c | 531 | skb->truesize += PAGE_SIZE; |
69785b79 PYC |
532 | |
533 | if (ftgmac100_rxdes_last_segment(rxdes)) | |
534 | done = true; | |
535 | ||
536 | ftgmac100_alloc_rx_page(priv, rxdes, GFP_ATOMIC); | |
537 | ||
538 | ftgmac100_rx_pointer_advance(priv); | |
539 | rxdes = ftgmac100_current_rxdes(priv); | |
540 | } while (!done); | |
541 | ||
6ecd09dd ED |
542 | /* Small frames are copied into linear part of skb to free one page */ |
543 | if (skb->len <= 128) { | |
5935f81c | 544 | skb->truesize -= PAGE_SIZE; |
6ecd09dd ED |
545 | __pskb_pull_tail(skb, skb->len); |
546 | } else { | |
547 | /* We pull the minimum amount into linear part */ | |
548 | __pskb_pull_tail(skb, ETH_HLEN); | |
549 | } | |
69785b79 PYC |
550 | skb->protocol = eth_type_trans(skb, netdev); |
551 | ||
552 | netdev->stats.rx_packets++; | |
553 | netdev->stats.rx_bytes += skb->len; | |
554 | ||
555 | /* push packet to protocol stack */ | |
556 | napi_gro_receive(&priv->napi, skb); | |
557 | ||
558 | (*processed)++; | |
559 | return true; | |
560 | } | |
561 | ||
562 | /****************************************************************************** | |
563 | * internal functions (transmit descriptor) | |
564 | *****************************************************************************/ | |
7906a4da AJ |
565 | static void ftgmac100_txdes_reset(const struct ftgmac100 *priv, |
566 | struct ftgmac100_txdes *txdes) | |
69785b79 PYC |
567 | { |
568 | /* clear all except end of ring bit */ | |
7906a4da | 569 | txdes->txdes0 &= cpu_to_le32(priv->txdes0_edotr_mask); |
69785b79 PYC |
570 | txdes->txdes1 = 0; |
571 | txdes->txdes2 = 0; | |
572 | txdes->txdes3 = 0; | |
573 | } | |
574 | ||
575 | static bool ftgmac100_txdes_owned_by_dma(struct ftgmac100_txdes *txdes) | |
576 | { | |
577 | return txdes->txdes0 & cpu_to_le32(FTGMAC100_TXDES0_TXDMA_OWN); | |
578 | } | |
579 | ||
580 | static void ftgmac100_txdes_set_dma_own(struct ftgmac100_txdes *txdes) | |
581 | { | |
582 | /* | |
583 | * Make sure dma own bit will not be set before any other | |
584 | * descriptor fields. | |
585 | */ | |
586 | wmb(); | |
587 | txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_TXDMA_OWN); | |
588 | } | |
589 | ||
7906a4da AJ |
590 | static void ftgmac100_txdes_set_end_of_ring(const struct ftgmac100 *priv, |
591 | struct ftgmac100_txdes *txdes) | |
69785b79 | 592 | { |
7906a4da | 593 | txdes->txdes0 |= cpu_to_le32(priv->txdes0_edotr_mask); |
69785b79 PYC |
594 | } |
595 | ||
596 | static void ftgmac100_txdes_set_first_segment(struct ftgmac100_txdes *txdes) | |
597 | { | |
598 | txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_FTS); | |
599 | } | |
600 | ||
601 | static void ftgmac100_txdes_set_last_segment(struct ftgmac100_txdes *txdes) | |
602 | { | |
603 | txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_LTS); | |
604 | } | |
605 | ||
606 | static void ftgmac100_txdes_set_buffer_size(struct ftgmac100_txdes *txdes, | |
607 | unsigned int len) | |
608 | { | |
609 | txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_TXBUF_SIZE(len)); | |
610 | } | |
611 | ||
612 | static void ftgmac100_txdes_set_txint(struct ftgmac100_txdes *txdes) | |
613 | { | |
614 | txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_TXIC); | |
615 | } | |
616 | ||
617 | static void ftgmac100_txdes_set_tcpcs(struct ftgmac100_txdes *txdes) | |
618 | { | |
619 | txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_TCP_CHKSUM); | |
620 | } | |
621 | ||
622 | static void ftgmac100_txdes_set_udpcs(struct ftgmac100_txdes *txdes) | |
623 | { | |
624 | txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_UDP_CHKSUM); | |
625 | } | |
626 | ||
627 | static void ftgmac100_txdes_set_ipcs(struct ftgmac100_txdes *txdes) | |
628 | { | |
629 | txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_IP_CHKSUM); | |
630 | } | |
631 | ||
632 | static void ftgmac100_txdes_set_dma_addr(struct ftgmac100_txdes *txdes, | |
633 | dma_addr_t addr) | |
634 | { | |
635 | txdes->txdes3 = cpu_to_le32(addr); | |
636 | } | |
637 | ||
638 | static dma_addr_t ftgmac100_txdes_get_dma_addr(struct ftgmac100_txdes *txdes) | |
639 | { | |
640 | return le32_to_cpu(txdes->txdes3); | |
641 | } | |
642 | ||
643 | /* | |
644 | * txdes2 is not used by hardware. We use it to keep track of socket buffer. | |
645 | * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu(). | |
646 | */ | |
647 | static void ftgmac100_txdes_set_skb(struct ftgmac100_txdes *txdes, | |
648 | struct sk_buff *skb) | |
649 | { | |
650 | txdes->txdes2 = (unsigned int)skb; | |
651 | } | |
652 | ||
653 | static struct sk_buff *ftgmac100_txdes_get_skb(struct ftgmac100_txdes *txdes) | |
654 | { | |
655 | return (struct sk_buff *)txdes->txdes2; | |
656 | } | |
657 | ||
658 | /****************************************************************************** | |
659 | * internal functions (transmit) | |
660 | *****************************************************************************/ | |
661 | static int ftgmac100_next_tx_pointer(int pointer) | |
662 | { | |
663 | return (pointer + 1) & (TX_QUEUE_ENTRIES - 1); | |
664 | } | |
665 | ||
666 | static void ftgmac100_tx_pointer_advance(struct ftgmac100 *priv) | |
667 | { | |
668 | priv->tx_pointer = ftgmac100_next_tx_pointer(priv->tx_pointer); | |
669 | } | |
670 | ||
671 | static void ftgmac100_tx_clean_pointer_advance(struct ftgmac100 *priv) | |
672 | { | |
673 | priv->tx_clean_pointer = ftgmac100_next_tx_pointer(priv->tx_clean_pointer); | |
674 | } | |
675 | ||
676 | static struct ftgmac100_txdes *ftgmac100_current_txdes(struct ftgmac100 *priv) | |
677 | { | |
678 | return &priv->descs->txdes[priv->tx_pointer]; | |
679 | } | |
680 | ||
681 | static struct ftgmac100_txdes * | |
682 | ftgmac100_current_clean_txdes(struct ftgmac100 *priv) | |
683 | { | |
684 | return &priv->descs->txdes[priv->tx_clean_pointer]; | |
685 | } | |
686 | ||
687 | static bool ftgmac100_tx_complete_packet(struct ftgmac100 *priv) | |
688 | { | |
689 | struct net_device *netdev = priv->netdev; | |
690 | struct ftgmac100_txdes *txdes; | |
691 | struct sk_buff *skb; | |
692 | dma_addr_t map; | |
693 | ||
694 | if (priv->tx_pending == 0) | |
695 | return false; | |
696 | ||
697 | txdes = ftgmac100_current_clean_txdes(priv); | |
698 | ||
699 | if (ftgmac100_txdes_owned_by_dma(txdes)) | |
700 | return false; | |
701 | ||
702 | skb = ftgmac100_txdes_get_skb(txdes); | |
703 | map = ftgmac100_txdes_get_dma_addr(txdes); | |
704 | ||
705 | netdev->stats.tx_packets++; | |
706 | netdev->stats.tx_bytes += skb->len; | |
707 | ||
708 | dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE); | |
709 | ||
710 | dev_kfree_skb(skb); | |
711 | ||
7906a4da | 712 | ftgmac100_txdes_reset(priv, txdes); |
69785b79 PYC |
713 | |
714 | ftgmac100_tx_clean_pointer_advance(priv); | |
715 | ||
716 | spin_lock(&priv->tx_lock); | |
717 | priv->tx_pending--; | |
718 | spin_unlock(&priv->tx_lock); | |
719 | netif_wake_queue(netdev); | |
720 | ||
721 | return true; | |
722 | } | |
723 | ||
724 | static void ftgmac100_tx_complete(struct ftgmac100 *priv) | |
725 | { | |
726 | while (ftgmac100_tx_complete_packet(priv)) | |
727 | ; | |
728 | } | |
729 | ||
730 | static int ftgmac100_xmit(struct ftgmac100 *priv, struct sk_buff *skb, | |
731 | dma_addr_t map) | |
732 | { | |
733 | struct net_device *netdev = priv->netdev; | |
734 | struct ftgmac100_txdes *txdes; | |
735 | unsigned int len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; | |
736 | ||
737 | txdes = ftgmac100_current_txdes(priv); | |
738 | ftgmac100_tx_pointer_advance(priv); | |
739 | ||
740 | /* setup TX descriptor */ | |
741 | ftgmac100_txdes_set_skb(txdes, skb); | |
742 | ftgmac100_txdes_set_dma_addr(txdes, map); | |
743 | ftgmac100_txdes_set_buffer_size(txdes, len); | |
744 | ||
745 | ftgmac100_txdes_set_first_segment(txdes); | |
746 | ftgmac100_txdes_set_last_segment(txdes); | |
747 | ftgmac100_txdes_set_txint(txdes); | |
748 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | |
749 | __be16 protocol = skb->protocol; | |
750 | ||
751 | if (protocol == cpu_to_be16(ETH_P_IP)) { | |
752 | u8 ip_proto = ip_hdr(skb)->protocol; | |
753 | ||
754 | ftgmac100_txdes_set_ipcs(txdes); | |
755 | if (ip_proto == IPPROTO_TCP) | |
756 | ftgmac100_txdes_set_tcpcs(txdes); | |
757 | else if (ip_proto == IPPROTO_UDP) | |
758 | ftgmac100_txdes_set_udpcs(txdes); | |
759 | } | |
760 | } | |
761 | ||
762 | spin_lock(&priv->tx_lock); | |
763 | priv->tx_pending++; | |
764 | if (priv->tx_pending == TX_QUEUE_ENTRIES) | |
765 | netif_stop_queue(netdev); | |
766 | ||
767 | /* start transmit */ | |
768 | ftgmac100_txdes_set_dma_own(txdes); | |
769 | spin_unlock(&priv->tx_lock); | |
770 | ||
771 | ftgmac100_txdma_normal_prio_start_polling(priv); | |
772 | ||
773 | return NETDEV_TX_OK; | |
774 | } | |
775 | ||
776 | /****************************************************************************** | |
777 | * internal functions (buffer) | |
778 | *****************************************************************************/ | |
779 | static int ftgmac100_alloc_rx_page(struct ftgmac100 *priv, | |
780 | struct ftgmac100_rxdes *rxdes, gfp_t gfp) | |
781 | { | |
782 | struct net_device *netdev = priv->netdev; | |
783 | struct page *page; | |
784 | dma_addr_t map; | |
785 | ||
786 | page = alloc_page(gfp); | |
787 | if (!page) { | |
788 | if (net_ratelimit()) | |
789 | netdev_err(netdev, "failed to allocate rx page\n"); | |
790 | return -ENOMEM; | |
791 | } | |
792 | ||
793 | map = dma_map_page(priv->dev, page, 0, RX_BUF_SIZE, DMA_FROM_DEVICE); | |
794 | if (unlikely(dma_mapping_error(priv->dev, map))) { | |
795 | if (net_ratelimit()) | |
796 | netdev_err(netdev, "failed to map rx page\n"); | |
797 | __free_page(page); | |
798 | return -ENOMEM; | |
799 | } | |
800 | ||
ada66b54 | 801 | ftgmac100_rxdes_set_page(priv, rxdes, page); |
69785b79 | 802 | ftgmac100_rxdes_set_dma_addr(rxdes, map); |
7906a4da | 803 | ftgmac100_rxdes_set_dma_own(priv, rxdes); |
69785b79 PYC |
804 | return 0; |
805 | } | |
806 | ||
807 | static void ftgmac100_free_buffers(struct ftgmac100 *priv) | |
808 | { | |
809 | int i; | |
810 | ||
811 | for (i = 0; i < RX_QUEUE_ENTRIES; i++) { | |
812 | struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[i]; | |
ada66b54 | 813 | struct page *page = ftgmac100_rxdes_get_page(priv, rxdes); |
69785b79 PYC |
814 | dma_addr_t map = ftgmac100_rxdes_get_dma_addr(rxdes); |
815 | ||
816 | if (!page) | |
817 | continue; | |
818 | ||
819 | dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE); | |
820 | __free_page(page); | |
821 | } | |
822 | ||
823 | for (i = 0; i < TX_QUEUE_ENTRIES; i++) { | |
824 | struct ftgmac100_txdes *txdes = &priv->descs->txdes[i]; | |
825 | struct sk_buff *skb = ftgmac100_txdes_get_skb(txdes); | |
826 | dma_addr_t map = ftgmac100_txdes_get_dma_addr(txdes); | |
827 | ||
828 | if (!skb) | |
829 | continue; | |
830 | ||
831 | dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE); | |
0113e34b | 832 | kfree_skb(skb); |
69785b79 PYC |
833 | } |
834 | ||
835 | dma_free_coherent(priv->dev, sizeof(struct ftgmac100_descs), | |
836 | priv->descs, priv->descs_dma_addr); | |
837 | } | |
838 | ||
839 | static int ftgmac100_alloc_buffers(struct ftgmac100 *priv) | |
840 | { | |
841 | int i; | |
842 | ||
ede23fa8 JP |
843 | priv->descs = dma_zalloc_coherent(priv->dev, |
844 | sizeof(struct ftgmac100_descs), | |
845 | &priv->descs_dma_addr, GFP_KERNEL); | |
69785b79 PYC |
846 | if (!priv->descs) |
847 | return -ENOMEM; | |
848 | ||
69785b79 | 849 | /* initialize RX ring */ |
7906a4da AJ |
850 | ftgmac100_rxdes_set_end_of_ring(priv, |
851 | &priv->descs->rxdes[RX_QUEUE_ENTRIES - 1]); | |
69785b79 PYC |
852 | |
853 | for (i = 0; i < RX_QUEUE_ENTRIES; i++) { | |
854 | struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[i]; | |
855 | ||
856 | if (ftgmac100_alloc_rx_page(priv, rxdes, GFP_KERNEL)) | |
857 | goto err; | |
858 | } | |
859 | ||
860 | /* initialize TX ring */ | |
7906a4da AJ |
861 | ftgmac100_txdes_set_end_of_ring(priv, |
862 | &priv->descs->txdes[TX_QUEUE_ENTRIES - 1]); | |
69785b79 PYC |
863 | return 0; |
864 | ||
865 | err: | |
866 | ftgmac100_free_buffers(priv); | |
867 | return -ENOMEM; | |
868 | } | |
869 | ||
870 | /****************************************************************************** | |
871 | * internal functions (mdio) | |
872 | *****************************************************************************/ | |
873 | static void ftgmac100_adjust_link(struct net_device *netdev) | |
874 | { | |
875 | struct ftgmac100 *priv = netdev_priv(netdev); | |
b3c40adc | 876 | struct phy_device *phydev = netdev->phydev; |
69785b79 PYC |
877 | int ier; |
878 | ||
879 | if (phydev->speed == priv->old_speed) | |
880 | return; | |
881 | ||
882 | priv->old_speed = phydev->speed; | |
883 | ||
884 | ier = ioread32(priv->base + FTGMAC100_OFFSET_IER); | |
885 | ||
886 | /* disable all interrupts */ | |
887 | iowrite32(0, priv->base + FTGMAC100_OFFSET_IER); | |
888 | ||
889 | netif_stop_queue(netdev); | |
890 | ftgmac100_stop_hw(priv); | |
891 | ||
892 | netif_start_queue(netdev); | |
893 | ftgmac100_init_hw(priv); | |
894 | ftgmac100_start_hw(priv, phydev->speed); | |
895 | ||
896 | /* re-enable interrupts */ | |
897 | iowrite32(ier, priv->base + FTGMAC100_OFFSET_IER); | |
898 | } | |
899 | ||
900 | static int ftgmac100_mii_probe(struct ftgmac100 *priv) | |
901 | { | |
902 | struct net_device *netdev = priv->netdev; | |
e574f398 | 903 | struct phy_device *phydev; |
69785b79 | 904 | |
e574f398 | 905 | phydev = phy_find_first(priv->mii_bus); |
69785b79 PYC |
906 | if (!phydev) { |
907 | netdev_info(netdev, "%s: no PHY found\n", netdev->name); | |
908 | return -ENODEV; | |
909 | } | |
910 | ||
84eff6d1 | 911 | phydev = phy_connect(netdev, phydev_name(phydev), |
f9a8f83b | 912 | &ftgmac100_adjust_link, PHY_INTERFACE_MODE_GMII); |
69785b79 PYC |
913 | |
914 | if (IS_ERR(phydev)) { | |
915 | netdev_err(netdev, "%s: Could not attach to PHY\n", netdev->name); | |
916 | return PTR_ERR(phydev); | |
917 | } | |
918 | ||
69785b79 PYC |
919 | return 0; |
920 | } | |
921 | ||
922 | /****************************************************************************** | |
923 | * struct mii_bus functions | |
924 | *****************************************************************************/ | |
925 | static int ftgmac100_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum) | |
926 | { | |
927 | struct net_device *netdev = bus->priv; | |
928 | struct ftgmac100 *priv = netdev_priv(netdev); | |
929 | unsigned int phycr; | |
930 | int i; | |
931 | ||
932 | phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR); | |
933 | ||
934 | /* preserve MDC cycle threshold */ | |
935 | phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK; | |
936 | ||
937 | phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr) | | |
938 | FTGMAC100_PHYCR_REGAD(regnum) | | |
939 | FTGMAC100_PHYCR_MIIRD; | |
940 | ||
941 | iowrite32(phycr, priv->base + FTGMAC100_OFFSET_PHYCR); | |
942 | ||
943 | for (i = 0; i < 10; i++) { | |
944 | phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR); | |
945 | ||
946 | if ((phycr & FTGMAC100_PHYCR_MIIRD) == 0) { | |
947 | int data; | |
948 | ||
949 | data = ioread32(priv->base + FTGMAC100_OFFSET_PHYDATA); | |
950 | return FTGMAC100_PHYDATA_MIIRDATA(data); | |
951 | } | |
952 | ||
953 | udelay(100); | |
954 | } | |
955 | ||
956 | netdev_err(netdev, "mdio read timed out\n"); | |
957 | return -EIO; | |
958 | } | |
959 | ||
960 | static int ftgmac100_mdiobus_write(struct mii_bus *bus, int phy_addr, | |
961 | int regnum, u16 value) | |
962 | { | |
963 | struct net_device *netdev = bus->priv; | |
964 | struct ftgmac100 *priv = netdev_priv(netdev); | |
965 | unsigned int phycr; | |
966 | int data; | |
967 | int i; | |
968 | ||
969 | phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR); | |
970 | ||
971 | /* preserve MDC cycle threshold */ | |
972 | phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK; | |
973 | ||
974 | phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr) | | |
975 | FTGMAC100_PHYCR_REGAD(regnum) | | |
976 | FTGMAC100_PHYCR_MIIWR; | |
977 | ||
978 | data = FTGMAC100_PHYDATA_MIIWDATA(value); | |
979 | ||
980 | iowrite32(data, priv->base + FTGMAC100_OFFSET_PHYDATA); | |
981 | iowrite32(phycr, priv->base + FTGMAC100_OFFSET_PHYCR); | |
982 | ||
983 | for (i = 0; i < 10; i++) { | |
984 | phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR); | |
985 | ||
986 | if ((phycr & FTGMAC100_PHYCR_MIIWR) == 0) | |
987 | return 0; | |
988 | ||
989 | udelay(100); | |
990 | } | |
991 | ||
992 | netdev_err(netdev, "mdio write timed out\n"); | |
993 | return -EIO; | |
994 | } | |
995 | ||
69785b79 PYC |
996 | /****************************************************************************** |
997 | * struct ethtool_ops functions | |
998 | *****************************************************************************/ | |
999 | static void ftgmac100_get_drvinfo(struct net_device *netdev, | |
1000 | struct ethtool_drvinfo *info) | |
1001 | { | |
7826d43f JP |
1002 | strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); |
1003 | strlcpy(info->version, DRV_VERSION, sizeof(info->version)); | |
1004 | strlcpy(info->bus_info, dev_name(&netdev->dev), sizeof(info->bus_info)); | |
69785b79 PYC |
1005 | } |
1006 | ||
69785b79 | 1007 | static const struct ethtool_ops ftgmac100_ethtool_ops = { |
69785b79 PYC |
1008 | .get_drvinfo = ftgmac100_get_drvinfo, |
1009 | .get_link = ethtool_op_get_link, | |
fd24d72c PR |
1010 | .get_link_ksettings = phy_ethtool_get_link_ksettings, |
1011 | .set_link_ksettings = phy_ethtool_set_link_ksettings, | |
69785b79 PYC |
1012 | }; |
1013 | ||
1014 | /****************************************************************************** | |
1015 | * interrupt handler | |
1016 | *****************************************************************************/ | |
1017 | static irqreturn_t ftgmac100_interrupt(int irq, void *dev_id) | |
1018 | { | |
1019 | struct net_device *netdev = dev_id; | |
1020 | struct ftgmac100 *priv = netdev_priv(netdev); | |
1021 | ||
bd466c3f GS |
1022 | /* When running in NCSI mode, the interface should be ready for |
1023 | * receiving or transmitting NCSI packets before it's opened. | |
1024 | */ | |
1025 | if (likely(priv->use_ncsi || netif_running(netdev))) { | |
69785b79 PYC |
1026 | /* Disable interrupts for polling */ |
1027 | iowrite32(0, priv->base + FTGMAC100_OFFSET_IER); | |
1028 | napi_schedule(&priv->napi); | |
1029 | } | |
1030 | ||
1031 | return IRQ_HANDLED; | |
1032 | } | |
1033 | ||
1034 | /****************************************************************************** | |
1035 | * struct napi_struct functions | |
1036 | *****************************************************************************/ | |
1037 | static int ftgmac100_poll(struct napi_struct *napi, int budget) | |
1038 | { | |
1039 | struct ftgmac100 *priv = container_of(napi, struct ftgmac100, napi); | |
1040 | struct net_device *netdev = priv->netdev; | |
1041 | unsigned int status; | |
1042 | bool completed = true; | |
1043 | int rx = 0; | |
1044 | ||
1045 | status = ioread32(priv->base + FTGMAC100_OFFSET_ISR); | |
1046 | iowrite32(status, priv->base + FTGMAC100_OFFSET_ISR); | |
1047 | ||
1048 | if (status & (FTGMAC100_INT_RPKT_BUF | FTGMAC100_INT_NO_RXBUF)) { | |
1049 | /* | |
1050 | * FTGMAC100_INT_RPKT_BUF: | |
1051 | * RX DMA has received packets into RX buffer successfully | |
1052 | * | |
1053 | * FTGMAC100_INT_NO_RXBUF: | |
1054 | * RX buffer unavailable | |
1055 | */ | |
1056 | bool retry; | |
1057 | ||
1058 | do { | |
1059 | retry = ftgmac100_rx_packet(priv, &rx); | |
1060 | } while (retry && rx < budget); | |
1061 | ||
1062 | if (retry && rx == budget) | |
1063 | completed = false; | |
1064 | } | |
1065 | ||
1066 | if (status & (FTGMAC100_INT_XPKT_ETH | FTGMAC100_INT_XPKT_LOST)) { | |
1067 | /* | |
1068 | * FTGMAC100_INT_XPKT_ETH: | |
1069 | * packet transmitted to ethernet successfully | |
1070 | * | |
1071 | * FTGMAC100_INT_XPKT_LOST: | |
1072 | * packet transmitted to ethernet lost due to late | |
1073 | * collision or excessive collision | |
1074 | */ | |
1075 | ftgmac100_tx_complete(priv); | |
1076 | } | |
1077 | ||
fc6061cf | 1078 | if (status & priv->int_mask_all & (FTGMAC100_INT_NO_RXBUF | |
edcd692f | 1079 | FTGMAC100_INT_RPKT_LOST | FTGMAC100_INT_AHB_ERR)) { |
69785b79 | 1080 | if (net_ratelimit()) |
edcd692f | 1081 | netdev_info(netdev, "[ISR] = 0x%x: %s%s%s\n", status, |
69785b79 PYC |
1082 | status & FTGMAC100_INT_NO_RXBUF ? "NO_RXBUF " : "", |
1083 | status & FTGMAC100_INT_RPKT_LOST ? "RPKT_LOST " : "", | |
edcd692f | 1084 | status & FTGMAC100_INT_AHB_ERR ? "AHB_ERR " : ""); |
69785b79 PYC |
1085 | |
1086 | if (status & FTGMAC100_INT_NO_RXBUF) { | |
1087 | /* RX buffer unavailable */ | |
1088 | netdev->stats.rx_over_errors++; | |
1089 | } | |
1090 | ||
1091 | if (status & FTGMAC100_INT_RPKT_LOST) { | |
1092 | /* received packet lost due to RX FIFO full */ | |
1093 | netdev->stats.rx_fifo_errors++; | |
1094 | } | |
1095 | } | |
1096 | ||
1097 | if (completed) { | |
1098 | napi_complete(napi); | |
1099 | ||
1100 | /* enable all interrupts */ | |
fc6061cf GS |
1101 | iowrite32(priv->int_mask_all, |
1102 | priv->base + FTGMAC100_OFFSET_IER); | |
69785b79 PYC |
1103 | } |
1104 | ||
1105 | return rx; | |
1106 | } | |
1107 | ||
1108 | /****************************************************************************** | |
1109 | * struct net_device_ops functions | |
1110 | *****************************************************************************/ | |
1111 | static int ftgmac100_open(struct net_device *netdev) | |
1112 | { | |
1113 | struct ftgmac100 *priv = netdev_priv(netdev); | |
08c9c126 | 1114 | unsigned int status; |
69785b79 PYC |
1115 | int err; |
1116 | ||
1117 | err = ftgmac100_alloc_buffers(priv); | |
1118 | if (err) { | |
1119 | netdev_err(netdev, "failed to allocate buffers\n"); | |
1120 | goto err_alloc; | |
1121 | } | |
1122 | ||
1123 | err = request_irq(priv->irq, ftgmac100_interrupt, 0, netdev->name, netdev); | |
1124 | if (err) { | |
1125 | netdev_err(netdev, "failed to request irq %d\n", priv->irq); | |
1126 | goto err_irq; | |
1127 | } | |
1128 | ||
1129 | priv->rx_pointer = 0; | |
1130 | priv->tx_clean_pointer = 0; | |
1131 | priv->tx_pointer = 0; | |
1132 | priv->tx_pending = 0; | |
1133 | ||
1134 | err = ftgmac100_reset_hw(priv); | |
1135 | if (err) | |
1136 | goto err_hw; | |
1137 | ||
1138 | ftgmac100_init_hw(priv); | |
bd466c3f | 1139 | ftgmac100_start_hw(priv, priv->use_ncsi ? 100 : 10); |
08c9c126 GS |
1140 | |
1141 | /* Clear stale interrupts */ | |
1142 | status = ioread32(priv->base + FTGMAC100_OFFSET_ISR); | |
1143 | iowrite32(status, priv->base + FTGMAC100_OFFSET_ISR); | |
1144 | ||
bd466c3f GS |
1145 | if (netdev->phydev) |
1146 | phy_start(netdev->phydev); | |
1147 | else if (priv->use_ncsi) | |
1148 | netif_carrier_on(netdev); | |
69785b79 PYC |
1149 | |
1150 | napi_enable(&priv->napi); | |
1151 | netif_start_queue(netdev); | |
1152 | ||
1153 | /* enable all interrupts */ | |
fc6061cf | 1154 | iowrite32(priv->int_mask_all, priv->base + FTGMAC100_OFFSET_IER); |
bd466c3f GS |
1155 | |
1156 | /* Start the NCSI device */ | |
1157 | if (priv->use_ncsi) { | |
1158 | err = ncsi_start_dev(priv->ndev); | |
1159 | if (err) | |
1160 | goto err_ncsi; | |
1161 | } | |
1162 | ||
1163 | priv->enabled = true; | |
1164 | ||
69785b79 PYC |
1165 | return 0; |
1166 | ||
bd466c3f GS |
1167 | err_ncsi: |
1168 | napi_disable(&priv->napi); | |
1169 | netif_stop_queue(netdev); | |
1170 | iowrite32(0, priv->base + FTGMAC100_OFFSET_IER); | |
69785b79 PYC |
1171 | err_hw: |
1172 | free_irq(priv->irq, netdev); | |
1173 | err_irq: | |
1174 | ftgmac100_free_buffers(priv); | |
1175 | err_alloc: | |
1176 | return err; | |
1177 | } | |
1178 | ||
1179 | static int ftgmac100_stop(struct net_device *netdev) | |
1180 | { | |
1181 | struct ftgmac100 *priv = netdev_priv(netdev); | |
1182 | ||
bd466c3f GS |
1183 | if (!priv->enabled) |
1184 | return 0; | |
1185 | ||
69785b79 | 1186 | /* disable all interrupts */ |
bd466c3f | 1187 | priv->enabled = false; |
69785b79 PYC |
1188 | iowrite32(0, priv->base + FTGMAC100_OFFSET_IER); |
1189 | ||
1190 | netif_stop_queue(netdev); | |
1191 | napi_disable(&priv->napi); | |
bd466c3f GS |
1192 | if (netdev->phydev) |
1193 | phy_stop(netdev->phydev); | |
2c15f25b GS |
1194 | else if (priv->use_ncsi) |
1195 | ncsi_stop_dev(priv->ndev); | |
69785b79 PYC |
1196 | |
1197 | ftgmac100_stop_hw(priv); | |
1198 | free_irq(priv->irq, netdev); | |
1199 | ftgmac100_free_buffers(priv); | |
1200 | ||
1201 | return 0; | |
1202 | } | |
1203 | ||
1204 | static int ftgmac100_hard_start_xmit(struct sk_buff *skb, | |
1205 | struct net_device *netdev) | |
1206 | { | |
1207 | struct ftgmac100 *priv = netdev_priv(netdev); | |
1208 | dma_addr_t map; | |
1209 | ||
1210 | if (unlikely(skb->len > MAX_PKT_SIZE)) { | |
1211 | if (net_ratelimit()) | |
1212 | netdev_dbg(netdev, "tx packet too big\n"); | |
1213 | ||
1214 | netdev->stats.tx_dropped++; | |
0113e34b | 1215 | kfree_skb(skb); |
69785b79 PYC |
1216 | return NETDEV_TX_OK; |
1217 | } | |
1218 | ||
1219 | map = dma_map_single(priv->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); | |
1220 | if (unlikely(dma_mapping_error(priv->dev, map))) { | |
1221 | /* drop packet */ | |
1222 | if (net_ratelimit()) | |
1223 | netdev_err(netdev, "map socket buffer failed\n"); | |
1224 | ||
1225 | netdev->stats.tx_dropped++; | |
0113e34b | 1226 | kfree_skb(skb); |
69785b79 PYC |
1227 | return NETDEV_TX_OK; |
1228 | } | |
1229 | ||
1230 | return ftgmac100_xmit(priv, skb, map); | |
1231 | } | |
1232 | ||
1233 | /* optional */ | |
1234 | static int ftgmac100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) | |
1235 | { | |
bd466c3f GS |
1236 | if (!netdev->phydev) |
1237 | return -ENXIO; | |
1238 | ||
b3c40adc | 1239 | return phy_mii_ioctl(netdev->phydev, ifr, cmd); |
69785b79 PYC |
1240 | } |
1241 | ||
1242 | static const struct net_device_ops ftgmac100_netdev_ops = { | |
1243 | .ndo_open = ftgmac100_open, | |
1244 | .ndo_stop = ftgmac100_stop, | |
1245 | .ndo_start_xmit = ftgmac100_hard_start_xmit, | |
113ce107 | 1246 | .ndo_set_mac_address = ftgmac100_set_mac_addr, |
69785b79 PYC |
1247 | .ndo_validate_addr = eth_validate_addr, |
1248 | .ndo_do_ioctl = ftgmac100_do_ioctl, | |
1249 | }; | |
1250 | ||
eb418184 GS |
1251 | static int ftgmac100_setup_mdio(struct net_device *netdev) |
1252 | { | |
1253 | struct ftgmac100 *priv = netdev_priv(netdev); | |
1254 | struct platform_device *pdev = to_platform_device(priv->dev); | |
1255 | int i, err = 0; | |
e07dc63b | 1256 | u32 reg; |
eb418184 GS |
1257 | |
1258 | /* initialize mdio bus */ | |
1259 | priv->mii_bus = mdiobus_alloc(); | |
1260 | if (!priv->mii_bus) | |
1261 | return -EIO; | |
1262 | ||
e07dc63b JS |
1263 | if (of_machine_is_compatible("aspeed,ast2400") || |
1264 | of_machine_is_compatible("aspeed,ast2500")) { | |
1265 | /* This driver supports the old MDIO interface */ | |
1266 | reg = ioread32(priv->base + FTGMAC100_OFFSET_REVR); | |
1267 | reg &= ~FTGMAC100_REVR_NEW_MDIO_INTERFACE; | |
1268 | iowrite32(reg, priv->base + FTGMAC100_OFFSET_REVR); | |
1269 | }; | |
1270 | ||
eb418184 GS |
1271 | priv->mii_bus->name = "ftgmac100_mdio"; |
1272 | snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%d", | |
1273 | pdev->name, pdev->id); | |
1274 | priv->mii_bus->priv = priv->netdev; | |
1275 | priv->mii_bus->read = ftgmac100_mdiobus_read; | |
1276 | priv->mii_bus->write = ftgmac100_mdiobus_write; | |
1277 | ||
1278 | for (i = 0; i < PHY_MAX_ADDR; i++) | |
1279 | priv->mii_bus->irq[i] = PHY_POLL; | |
1280 | ||
1281 | err = mdiobus_register(priv->mii_bus); | |
1282 | if (err) { | |
1283 | dev_err(priv->dev, "Cannot register MDIO bus!\n"); | |
1284 | goto err_register_mdiobus; | |
1285 | } | |
1286 | ||
1287 | err = ftgmac100_mii_probe(priv); | |
1288 | if (err) { | |
1289 | dev_err(priv->dev, "MII Probe failed!\n"); | |
1290 | goto err_mii_probe; | |
1291 | } | |
1292 | ||
1293 | return 0; | |
1294 | ||
1295 | err_mii_probe: | |
1296 | mdiobus_unregister(priv->mii_bus); | |
1297 | err_register_mdiobus: | |
1298 | mdiobus_free(priv->mii_bus); | |
1299 | return err; | |
1300 | } | |
1301 | ||
1302 | static void ftgmac100_destroy_mdio(struct net_device *netdev) | |
1303 | { | |
1304 | struct ftgmac100 *priv = netdev_priv(netdev); | |
1305 | ||
1306 | if (!netdev->phydev) | |
1307 | return; | |
1308 | ||
1309 | phy_disconnect(netdev->phydev); | |
1310 | mdiobus_unregister(priv->mii_bus); | |
1311 | mdiobus_free(priv->mii_bus); | |
1312 | } | |
1313 | ||
bd466c3f GS |
1314 | static void ftgmac100_ncsi_handler(struct ncsi_dev *nd) |
1315 | { | |
1316 | if (unlikely(nd->state != ncsi_dev_state_functional)) | |
1317 | return; | |
1318 | ||
1319 | netdev_info(nd->dev, "NCSI interface %s\n", | |
1320 | nd->link_up ? "up" : "down"); | |
1321 | } | |
1322 | ||
69785b79 PYC |
1323 | /****************************************************************************** |
1324 | * struct platform_driver functions | |
1325 | *****************************************************************************/ | |
1326 | static int ftgmac100_probe(struct platform_device *pdev) | |
1327 | { | |
1328 | struct resource *res; | |
1329 | int irq; | |
1330 | struct net_device *netdev; | |
1331 | struct ftgmac100 *priv; | |
bd466c3f | 1332 | int err = 0; |
69785b79 PYC |
1333 | |
1334 | if (!pdev) | |
1335 | return -ENODEV; | |
1336 | ||
1337 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
1338 | if (!res) | |
1339 | return -ENXIO; | |
1340 | ||
1341 | irq = platform_get_irq(pdev, 0); | |
1342 | if (irq < 0) | |
1343 | return irq; | |
1344 | ||
1345 | /* setup net_device */ | |
1346 | netdev = alloc_etherdev(sizeof(*priv)); | |
1347 | if (!netdev) { | |
1348 | err = -ENOMEM; | |
1349 | goto err_alloc_etherdev; | |
1350 | } | |
1351 | ||
1352 | SET_NETDEV_DEV(netdev, &pdev->dev); | |
1353 | ||
7ad24ea4 | 1354 | netdev->ethtool_ops = &ftgmac100_ethtool_ops; |
69785b79 | 1355 | netdev->netdev_ops = &ftgmac100_netdev_ops; |
69785b79 PYC |
1356 | |
1357 | platform_set_drvdata(pdev, netdev); | |
1358 | ||
1359 | /* setup private data */ | |
1360 | priv = netdev_priv(netdev); | |
1361 | priv->netdev = netdev; | |
1362 | priv->dev = &pdev->dev; | |
1363 | ||
1364 | spin_lock_init(&priv->tx_lock); | |
1365 | ||
1366 | /* initialize NAPI */ | |
1367 | netif_napi_add(netdev, &priv->napi, ftgmac100_poll, 64); | |
1368 | ||
1369 | /* map io memory */ | |
1370 | priv->res = request_mem_region(res->start, resource_size(res), | |
1371 | dev_name(&pdev->dev)); | |
1372 | if (!priv->res) { | |
1373 | dev_err(&pdev->dev, "Could not reserve memory region\n"); | |
1374 | err = -ENOMEM; | |
1375 | goto err_req_mem; | |
1376 | } | |
1377 | ||
1378 | priv->base = ioremap(res->start, resource_size(res)); | |
1379 | if (!priv->base) { | |
1380 | dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n"); | |
1381 | err = -EIO; | |
1382 | goto err_ioremap; | |
1383 | } | |
1384 | ||
1385 | priv->irq = irq; | |
1386 | ||
113ce107 GS |
1387 | /* MAC address from chip or random one */ |
1388 | ftgmac100_setup_mac(priv); | |
1389 | ||
fc6061cf GS |
1390 | priv->int_mask_all = (FTGMAC100_INT_RPKT_LOST | |
1391 | FTGMAC100_INT_XPKT_ETH | | |
1392 | FTGMAC100_INT_XPKT_LOST | | |
1393 | FTGMAC100_INT_AHB_ERR | | |
fc6061cf GS |
1394 | FTGMAC100_INT_RPKT_BUF | |
1395 | FTGMAC100_INT_NO_RXBUF); | |
2a0ab8eb JS |
1396 | |
1397 | if (of_machine_is_compatible("aspeed,ast2400") || | |
1398 | of_machine_is_compatible("aspeed,ast2500")) { | |
1399 | priv->rxdes0_edorr_mask = BIT(30); | |
1400 | priv->txdes0_edotr_mask = BIT(30); | |
1401 | } else { | |
1402 | priv->rxdes0_edorr_mask = BIT(15); | |
1403 | priv->txdes0_edotr_mask = BIT(15); | |
1404 | } | |
1405 | ||
bd466c3f GS |
1406 | if (pdev->dev.of_node && |
1407 | of_get_property(pdev->dev.of_node, "use-ncsi", NULL)) { | |
1408 | if (!IS_ENABLED(CONFIG_NET_NCSI)) { | |
1409 | dev_err(&pdev->dev, "NCSI stack not enabled\n"); | |
1410 | goto err_ncsi_dev; | |
1411 | } | |
1412 | ||
1413 | dev_info(&pdev->dev, "Using NCSI interface\n"); | |
1414 | priv->use_ncsi = true; | |
1415 | priv->ndev = ncsi_register_dev(netdev, ftgmac100_ncsi_handler); | |
1416 | if (!priv->ndev) | |
1417 | goto err_ncsi_dev; | |
1418 | } else { | |
1419 | priv->use_ncsi = false; | |
1420 | err = ftgmac100_setup_mdio(netdev); | |
1421 | if (err) | |
1422 | goto err_setup_mdio; | |
1423 | } | |
1424 | ||
1425 | /* We have to disable on-chip IP checksum functionality | |
1426 | * when NCSI is enabled on the interface. It doesn't work | |
1427 | * in that case. | |
1428 | */ | |
1429 | netdev->features = NETIF_F_IP_CSUM | NETIF_F_GRO; | |
1430 | if (priv->use_ncsi && | |
1431 | of_get_property(pdev->dev.of_node, "no-hw-checksum", NULL)) | |
1432 | netdev->features &= ~NETIF_F_IP_CSUM; | |
1433 | ||
69785b79 PYC |
1434 | |
1435 | /* register network device */ | |
1436 | err = register_netdev(netdev); | |
1437 | if (err) { | |
1438 | dev_err(&pdev->dev, "Failed to register netdev\n"); | |
1439 | goto err_register_netdev; | |
1440 | } | |
1441 | ||
1442 | netdev_info(netdev, "irq %d, mapped at %p\n", priv->irq, priv->base); | |
1443 | ||
69785b79 PYC |
1444 | return 0; |
1445 | ||
bd466c3f | 1446 | err_ncsi_dev: |
69785b79 | 1447 | err_register_netdev: |
eb418184 GS |
1448 | ftgmac100_destroy_mdio(netdev); |
1449 | err_setup_mdio: | |
69785b79 PYC |
1450 | iounmap(priv->base); |
1451 | err_ioremap: | |
1452 | release_resource(priv->res); | |
1453 | err_req_mem: | |
1454 | netif_napi_del(&priv->napi); | |
69785b79 PYC |
1455 | free_netdev(netdev); |
1456 | err_alloc_etherdev: | |
1457 | return err; | |
1458 | } | |
1459 | ||
be12502e | 1460 | static int ftgmac100_remove(struct platform_device *pdev) |
69785b79 PYC |
1461 | { |
1462 | struct net_device *netdev; | |
1463 | struct ftgmac100 *priv; | |
1464 | ||
1465 | netdev = platform_get_drvdata(pdev); | |
1466 | priv = netdev_priv(netdev); | |
1467 | ||
1468 | unregister_netdev(netdev); | |
eb418184 | 1469 | ftgmac100_destroy_mdio(netdev); |
69785b79 PYC |
1470 | |
1471 | iounmap(priv->base); | |
1472 | release_resource(priv->res); | |
1473 | ||
1474 | netif_napi_del(&priv->napi); | |
69785b79 PYC |
1475 | free_netdev(netdev); |
1476 | return 0; | |
1477 | } | |
1478 | ||
bb168e2e GS |
1479 | static const struct of_device_id ftgmac100_of_match[] = { |
1480 | { .compatible = "faraday,ftgmac100" }, | |
1481 | { } | |
1482 | }; | |
1483 | MODULE_DEVICE_TABLE(of, ftgmac100_of_match); | |
1484 | ||
69785b79 | 1485 | static struct platform_driver ftgmac100_driver = { |
bb168e2e | 1486 | .probe = ftgmac100_probe, |
be12502e | 1487 | .remove = ftgmac100_remove, |
bb168e2e GS |
1488 | .driver = { |
1489 | .name = DRV_NAME, | |
1490 | .of_match_table = ftgmac100_of_match, | |
69785b79 PYC |
1491 | }, |
1492 | }; | |
14f645d0 | 1493 | module_platform_driver(ftgmac100_driver); |
69785b79 PYC |
1494 | |
1495 | MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>"); | |
1496 | MODULE_DESCRIPTION("FTGMAC100 driver"); | |
1497 | MODULE_LICENSE("GPL"); |