blob: 99aafcc33a0be30f58ea88d0d54269c2e005c6d3 [file] [log] [blame]
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001/*
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>
Thomas Faber17f1bbc2012-01-18 13:45:44 +000027#include <linux/interrupt.h>
Po-Yu Chuang69785b72011-06-08 23:32:48 +000028#include <linux/io.h>
29#include <linux/module.h>
30#include <linux/netdevice.h>
Mark Brown3af887c2017-03-30 17:00:12 +010031#include <linux/of.h>
Po-Yu Chuang69785b72011-06-08 23:32:48 +000032#include <linux/phy.h>
33#include <linux/platform_device.h>
Mark Brown3af887c2017-03-30 17:00:12 +010034#include <linux/property.h>
Po-Yu Chuang69785b72011-06-08 23:32:48 +000035#include <net/ip.h>
Gavin Shanbd466c32016-07-19 11:54:23 +100036#include <net/ncsi.h>
Po-Yu Chuang69785b72011-06-08 23:32:48 +000037
38#include "ftgmac100.h"
39
40#define DRV_NAME "ftgmac100"
41#define DRV_VERSION "0.7"
42
43#define RX_QUEUE_ENTRIES 256 /* must be power of 2 */
44#define TX_QUEUE_ENTRIES 512 /* must be power of 2 */
45
46#define MAX_PKT_SIZE 1518
47#define RX_BUF_SIZE PAGE_SIZE /* must be smaller than 0x3fff */
48
Po-Yu Chuang69785b72011-06-08 23:32:48 +000049struct ftgmac100_descs {
50 struct ftgmac100_rxdes rxdes[RX_QUEUE_ENTRIES];
51 struct ftgmac100_txdes txdes[TX_QUEUE_ENTRIES];
52};
53
54struct ftgmac100 {
55 struct resource *res;
56 void __iomem *base;
Po-Yu Chuang69785b72011-06-08 23:32:48 +000057
58 struct ftgmac100_descs *descs;
59 dma_addr_t descs_dma_addr;
60
Andrew Jefferyada66b52016-09-22 08:34:58 +093061 struct page *rx_pages[RX_QUEUE_ENTRIES];
62
Po-Yu Chuang69785b72011-06-08 23:32:48 +000063 unsigned int rx_pointer;
64 unsigned int tx_clean_pointer;
65 unsigned int tx_pointer;
66 unsigned int tx_pending;
67
68 spinlock_t tx_lock;
69
70 struct net_device *netdev;
71 struct device *dev;
Gavin Shanbd466c32016-07-19 11:54:23 +100072 struct ncsi_dev *ndev;
Po-Yu Chuang69785b72011-06-08 23:32:48 +000073 struct napi_struct napi;
74
75 struct mii_bus *mii_bus;
Po-Yu Chuang69785b72011-06-08 23:32:48 +000076 int old_speed;
Gavin Shanfc6061c2016-07-19 11:54:25 +100077 int int_mask_all;
Gavin Shanbd466c32016-07-19 11:54:23 +100078 bool use_ncsi;
79 bool enabled;
Andrew Jeffery7906a4d2016-09-22 08:34:59 +093080
81 u32 rxdes0_edorr_mask;
82 u32 txdes0_edotr_mask;
Po-Yu Chuang69785b72011-06-08 23:32:48 +000083};
84
85static int ftgmac100_alloc_rx_page(struct ftgmac100 *priv,
86 struct ftgmac100_rxdes *rxdes, gfp_t gfp);
87
Po-Yu Chuang69785b72011-06-08 23:32:48 +000088static void ftgmac100_set_rx_ring_base(struct ftgmac100 *priv, dma_addr_t addr)
89{
90 iowrite32(addr, priv->base + FTGMAC100_OFFSET_RXR_BADR);
91}
92
93static void ftgmac100_set_rx_buffer_size(struct ftgmac100 *priv,
94 unsigned int size)
95{
96 size = FTGMAC100_RBSR_SIZE(size);
97 iowrite32(size, priv->base + FTGMAC100_OFFSET_RBSR);
98}
99
100static void ftgmac100_set_normal_prio_tx_ring_base(struct ftgmac100 *priv,
101 dma_addr_t addr)
102{
103 iowrite32(addr, priv->base + FTGMAC100_OFFSET_NPTXR_BADR);
104}
105
106static void ftgmac100_txdma_normal_prio_start_polling(struct ftgmac100 *priv)
107{
108 iowrite32(1, priv->base + FTGMAC100_OFFSET_NPTXPD);
109}
110
111static int ftgmac100_reset_hw(struct ftgmac100 *priv)
112{
113 struct net_device *netdev = priv->netdev;
114 int i;
115
116 /* NOTE: reset clears all registers */
117 iowrite32(FTGMAC100_MACCR_SW_RST, priv->base + FTGMAC100_OFFSET_MACCR);
118 for (i = 0; i < 5; i++) {
119 unsigned int maccr;
120
121 maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR);
122 if (!(maccr & FTGMAC100_MACCR_SW_RST))
123 return 0;
124
125 udelay(1000);
126 }
127
128 netdev_err(netdev, "software reset failed\n");
129 return -EIO;
130}
131
132static void ftgmac100_set_mac(struct ftgmac100 *priv, const unsigned char *mac)
133{
134 unsigned int maddr = mac[0] << 8 | mac[1];
135 unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
136
137 iowrite32(maddr, priv->base + FTGMAC100_OFFSET_MAC_MADR);
138 iowrite32(laddr, priv->base + FTGMAC100_OFFSET_MAC_LADR);
139}
140
Gavin Shan113ce102016-07-19 11:54:22 +1000141static void ftgmac100_setup_mac(struct ftgmac100 *priv)
142{
143 u8 mac[ETH_ALEN];
144 unsigned int m;
145 unsigned int l;
146 void *addr;
147
148 addr = device_get_mac_address(priv->dev, mac, ETH_ALEN);
149 if (addr) {
150 ether_addr_copy(priv->netdev->dev_addr, mac);
151 dev_info(priv->dev, "Read MAC address %pM from device tree\n",
152 mac);
153 return;
154 }
155
156 m = ioread32(priv->base + FTGMAC100_OFFSET_MAC_MADR);
157 l = ioread32(priv->base + FTGMAC100_OFFSET_MAC_LADR);
158
159 mac[0] = (m >> 8) & 0xff;
160 mac[1] = m & 0xff;
161 mac[2] = (l >> 24) & 0xff;
162 mac[3] = (l >> 16) & 0xff;
163 mac[4] = (l >> 8) & 0xff;
164 mac[5] = l & 0xff;
165
Gavin Shan113ce102016-07-19 11:54:22 +1000166 if (is_valid_ether_addr(mac)) {
167 ether_addr_copy(priv->netdev->dev_addr, mac);
168 dev_info(priv->dev, "Read MAC address %pM from chip\n", mac);
169 } else {
170 eth_hw_addr_random(priv->netdev);
171 dev_info(priv->dev, "Generated random MAC address %pM\n",
172 priv->netdev->dev_addr);
173 }
174}
175
176static int ftgmac100_set_mac_addr(struct net_device *dev, void *p)
177{
178 int ret;
179
180 ret = eth_prepare_mac_addr_change(dev, p);
181 if (ret < 0)
182 return ret;
183
184 eth_commit_mac_addr_change(dev, p);
185 ftgmac100_set_mac(netdev_priv(dev), dev->dev_addr);
186
187 return 0;
188}
189
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000190static void ftgmac100_init_hw(struct ftgmac100 *priv)
191{
192 /* setup ring buffer base registers */
193 ftgmac100_set_rx_ring_base(priv,
194 priv->descs_dma_addr +
195 offsetof(struct ftgmac100_descs, rxdes));
196 ftgmac100_set_normal_prio_tx_ring_base(priv,
197 priv->descs_dma_addr +
198 offsetof(struct ftgmac100_descs, txdes));
199
200 ftgmac100_set_rx_buffer_size(priv, RX_BUF_SIZE);
201
202 iowrite32(FTGMAC100_APTC_RXPOLL_CNT(1), priv->base + FTGMAC100_OFFSET_APTC);
203
204 ftgmac100_set_mac(priv, priv->netdev->dev_addr);
205}
206
207#define MACCR_ENABLE_ALL (FTGMAC100_MACCR_TXDMA_EN | \
208 FTGMAC100_MACCR_RXDMA_EN | \
209 FTGMAC100_MACCR_TXMAC_EN | \
210 FTGMAC100_MACCR_RXMAC_EN | \
211 FTGMAC100_MACCR_FULLDUP | \
212 FTGMAC100_MACCR_CRC_APD | \
213 FTGMAC100_MACCR_RX_RUNT | \
214 FTGMAC100_MACCR_RX_BROADPKT)
215
216static void ftgmac100_start_hw(struct ftgmac100 *priv, int speed)
217{
218 int maccr = MACCR_ENABLE_ALL;
219
220 switch (speed) {
221 default:
222 case 10:
223 break;
224
225 case 100:
226 maccr |= FTGMAC100_MACCR_FAST_MODE;
227 break;
228
229 case 1000:
230 maccr |= FTGMAC100_MACCR_GIGA_MODE;
231 break;
232 }
233
234 iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR);
235}
236
237static void ftgmac100_stop_hw(struct ftgmac100 *priv)
238{
239 iowrite32(0, priv->base + FTGMAC100_OFFSET_MACCR);
240}
241
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000242static bool ftgmac100_rxdes_first_segment(struct ftgmac100_rxdes *rxdes)
243{
244 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_FRS);
245}
246
247static bool ftgmac100_rxdes_last_segment(struct ftgmac100_rxdes *rxdes)
248{
249 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_LRS);
250}
251
252static bool ftgmac100_rxdes_packet_ready(struct ftgmac100_rxdes *rxdes)
253{
254 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RXPKT_RDY);
255}
256
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930257static void ftgmac100_rxdes_set_dma_own(const struct ftgmac100 *priv,
258 struct ftgmac100_rxdes *rxdes)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000259{
260 /* clear status bits */
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930261 rxdes->rxdes0 &= cpu_to_le32(priv->rxdes0_edorr_mask);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000262}
263
264static bool ftgmac100_rxdes_rx_error(struct ftgmac100_rxdes *rxdes)
265{
266 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RX_ERR);
267}
268
269static bool ftgmac100_rxdes_crc_error(struct ftgmac100_rxdes *rxdes)
270{
271 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_CRC_ERR);
272}
273
274static bool ftgmac100_rxdes_frame_too_long(struct ftgmac100_rxdes *rxdes)
275{
276 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_FTL);
277}
278
279static bool ftgmac100_rxdes_runt(struct ftgmac100_rxdes *rxdes)
280{
281 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RUNT);
282}
283
284static bool ftgmac100_rxdes_odd_nibble(struct ftgmac100_rxdes *rxdes)
285{
286 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RX_ODD_NB);
287}
288
289static unsigned int ftgmac100_rxdes_data_length(struct ftgmac100_rxdes *rxdes)
290{
291 return le32_to_cpu(rxdes->rxdes0) & FTGMAC100_RXDES0_VDBC;
292}
293
294static bool ftgmac100_rxdes_multicast(struct ftgmac100_rxdes *rxdes)
295{
296 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_MULTICAST);
297}
298
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930299static void ftgmac100_rxdes_set_end_of_ring(const struct ftgmac100 *priv,
300 struct ftgmac100_rxdes *rxdes)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000301{
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930302 rxdes->rxdes0 |= cpu_to_le32(priv->rxdes0_edorr_mask);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000303}
304
305static void ftgmac100_rxdes_set_dma_addr(struct ftgmac100_rxdes *rxdes,
306 dma_addr_t addr)
307{
308 rxdes->rxdes3 = cpu_to_le32(addr);
309}
310
311static dma_addr_t ftgmac100_rxdes_get_dma_addr(struct ftgmac100_rxdes *rxdes)
312{
313 return le32_to_cpu(rxdes->rxdes3);
314}
315
316static bool ftgmac100_rxdes_is_tcp(struct ftgmac100_rxdes *rxdes)
317{
318 return (rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_PROT_MASK)) ==
319 cpu_to_le32(FTGMAC100_RXDES1_PROT_TCPIP);
320}
321
322static bool ftgmac100_rxdes_is_udp(struct ftgmac100_rxdes *rxdes)
323{
324 return (rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_PROT_MASK)) ==
325 cpu_to_le32(FTGMAC100_RXDES1_PROT_UDPIP);
326}
327
328static bool ftgmac100_rxdes_tcpcs_err(struct ftgmac100_rxdes *rxdes)
329{
330 return rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_TCP_CHKSUM_ERR);
331}
332
333static bool ftgmac100_rxdes_udpcs_err(struct ftgmac100_rxdes *rxdes)
334{
335 return rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_UDP_CHKSUM_ERR);
336}
337
338static bool ftgmac100_rxdes_ipcs_err(struct ftgmac100_rxdes *rxdes)
339{
340 return rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_IP_CHKSUM_ERR);
341}
342
Andrew Jefferyada66b52016-09-22 08:34:58 +0930343static inline struct page **ftgmac100_rxdes_page_slot(struct ftgmac100 *priv,
344 struct ftgmac100_rxdes *rxdes)
345{
346 return &priv->rx_pages[rxdes - priv->descs->rxdes];
347}
348
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000349/*
350 * rxdes2 is not used by hardware. We use it to keep track of page.
351 * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu().
352 */
Andrew Jefferyada66b52016-09-22 08:34:58 +0930353static void ftgmac100_rxdes_set_page(struct ftgmac100 *priv,
354 struct ftgmac100_rxdes *rxdes,
355 struct page *page)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000356{
Andrew Jefferyada66b52016-09-22 08:34:58 +0930357 *ftgmac100_rxdes_page_slot(priv, rxdes) = page;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000358}
359
Andrew Jefferyada66b52016-09-22 08:34:58 +0930360static struct page *ftgmac100_rxdes_get_page(struct ftgmac100 *priv,
361 struct ftgmac100_rxdes *rxdes)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000362{
Andrew Jefferyada66b52016-09-22 08:34:58 +0930363 return *ftgmac100_rxdes_page_slot(priv, rxdes);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000364}
365
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000366static int ftgmac100_next_rx_pointer(int pointer)
367{
368 return (pointer + 1) & (RX_QUEUE_ENTRIES - 1);
369}
370
371static void ftgmac100_rx_pointer_advance(struct ftgmac100 *priv)
372{
373 priv->rx_pointer = ftgmac100_next_rx_pointer(priv->rx_pointer);
374}
375
376static struct ftgmac100_rxdes *ftgmac100_current_rxdes(struct ftgmac100 *priv)
377{
378 return &priv->descs->rxdes[priv->rx_pointer];
379}
380
381static struct ftgmac100_rxdes *
382ftgmac100_rx_locate_first_segment(struct ftgmac100 *priv)
383{
384 struct ftgmac100_rxdes *rxdes = ftgmac100_current_rxdes(priv);
385
386 while (ftgmac100_rxdes_packet_ready(rxdes)) {
387 if (ftgmac100_rxdes_first_segment(rxdes))
388 return rxdes;
389
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930390 ftgmac100_rxdes_set_dma_own(priv, rxdes);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000391 ftgmac100_rx_pointer_advance(priv);
392 rxdes = ftgmac100_current_rxdes(priv);
393 }
394
395 return NULL;
396}
397
398static bool ftgmac100_rx_packet_error(struct ftgmac100 *priv,
399 struct ftgmac100_rxdes *rxdes)
400{
401 struct net_device *netdev = priv->netdev;
402 bool error = false;
403
404 if (unlikely(ftgmac100_rxdes_rx_error(rxdes))) {
405 if (net_ratelimit())
406 netdev_info(netdev, "rx err\n");
407
408 netdev->stats.rx_errors++;
409 error = true;
410 }
411
412 if (unlikely(ftgmac100_rxdes_crc_error(rxdes))) {
413 if (net_ratelimit())
414 netdev_info(netdev, "rx crc err\n");
415
416 netdev->stats.rx_crc_errors++;
417 error = true;
418 } else if (unlikely(ftgmac100_rxdes_ipcs_err(rxdes))) {
419 if (net_ratelimit())
420 netdev_info(netdev, "rx IP checksum err\n");
421
422 error = true;
423 }
424
425 if (unlikely(ftgmac100_rxdes_frame_too_long(rxdes))) {
426 if (net_ratelimit())
427 netdev_info(netdev, "rx frame too long\n");
428
429 netdev->stats.rx_length_errors++;
430 error = true;
431 } else if (unlikely(ftgmac100_rxdes_runt(rxdes))) {
432 if (net_ratelimit())
433 netdev_info(netdev, "rx runt\n");
434
435 netdev->stats.rx_length_errors++;
436 error = true;
437 } else if (unlikely(ftgmac100_rxdes_odd_nibble(rxdes))) {
438 if (net_ratelimit())
439 netdev_info(netdev, "rx odd nibble\n");
440
441 netdev->stats.rx_length_errors++;
442 error = true;
443 }
444
445 return error;
446}
447
448static void ftgmac100_rx_drop_packet(struct ftgmac100 *priv)
449{
450 struct net_device *netdev = priv->netdev;
451 struct ftgmac100_rxdes *rxdes = ftgmac100_current_rxdes(priv);
452 bool done = false;
453
454 if (net_ratelimit())
455 netdev_dbg(netdev, "drop packet %p\n", rxdes);
456
457 do {
458 if (ftgmac100_rxdes_last_segment(rxdes))
459 done = true;
460
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930461 ftgmac100_rxdes_set_dma_own(priv, rxdes);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000462 ftgmac100_rx_pointer_advance(priv);
463 rxdes = ftgmac100_current_rxdes(priv);
464 } while (!done && ftgmac100_rxdes_packet_ready(rxdes));
465
466 netdev->stats.rx_dropped++;
467}
468
469static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
470{
471 struct net_device *netdev = priv->netdev;
472 struct ftgmac100_rxdes *rxdes;
473 struct sk_buff *skb;
474 bool done = false;
475
476 rxdes = ftgmac100_rx_locate_first_segment(priv);
477 if (!rxdes)
478 return false;
479
480 if (unlikely(ftgmac100_rx_packet_error(priv, rxdes))) {
481 ftgmac100_rx_drop_packet(priv);
482 return true;
483 }
484
485 /* start processing */
486 skb = netdev_alloc_skb_ip_align(netdev, 128);
487 if (unlikely(!skb)) {
488 if (net_ratelimit())
489 netdev_err(netdev, "rx skb alloc failed\n");
490
491 ftgmac100_rx_drop_packet(priv);
492 return true;
493 }
494
495 if (unlikely(ftgmac100_rxdes_multicast(rxdes)))
496 netdev->stats.multicast++;
497
498 /*
499 * It seems that HW does checksum incorrectly with fragmented packets,
500 * so we are conservative here - if HW checksum error, let software do
501 * the checksum again.
502 */
503 if ((ftgmac100_rxdes_is_tcp(rxdes) && !ftgmac100_rxdes_tcpcs_err(rxdes)) ||
504 (ftgmac100_rxdes_is_udp(rxdes) && !ftgmac100_rxdes_udpcs_err(rxdes)))
505 skb->ip_summed = CHECKSUM_UNNECESSARY;
506
507 do {
508 dma_addr_t map = ftgmac100_rxdes_get_dma_addr(rxdes);
Andrew Jefferyada66b52016-09-22 08:34:58 +0930509 struct page *page = ftgmac100_rxdes_get_page(priv, rxdes);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000510 unsigned int size;
511
512 dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
513
514 size = ftgmac100_rxdes_data_length(rxdes);
515 skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page, 0, size);
516
517 skb->len += size;
518 skb->data_len += size;
Eric Dumazet5935f812011-10-13 11:30:52 +0000519 skb->truesize += PAGE_SIZE;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000520
521 if (ftgmac100_rxdes_last_segment(rxdes))
522 done = true;
523
524 ftgmac100_alloc_rx_page(priv, rxdes, GFP_ATOMIC);
525
526 ftgmac100_rx_pointer_advance(priv);
527 rxdes = ftgmac100_current_rxdes(priv);
528 } while (!done);
529
Eric Dumazet6ecd09d2012-07-12 04:19:38 +0000530 /* Small frames are copied into linear part of skb to free one page */
531 if (skb->len <= 128) {
Eric Dumazet5935f812011-10-13 11:30:52 +0000532 skb->truesize -= PAGE_SIZE;
Eric Dumazet6ecd09d2012-07-12 04:19:38 +0000533 __pskb_pull_tail(skb, skb->len);
534 } else {
535 /* We pull the minimum amount into linear part */
536 __pskb_pull_tail(skb, ETH_HLEN);
537 }
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000538 skb->protocol = eth_type_trans(skb, netdev);
539
540 netdev->stats.rx_packets++;
541 netdev->stats.rx_bytes += skb->len;
542
543 /* push packet to protocol stack */
544 napi_gro_receive(&priv->napi, skb);
545
546 (*processed)++;
547 return true;
548}
549
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930550static void ftgmac100_txdes_reset(const struct ftgmac100 *priv,
551 struct ftgmac100_txdes *txdes)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000552{
553 /* clear all except end of ring bit */
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930554 txdes->txdes0 &= cpu_to_le32(priv->txdes0_edotr_mask);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000555 txdes->txdes1 = 0;
556 txdes->txdes2 = 0;
557 txdes->txdes3 = 0;
558}
559
560static bool ftgmac100_txdes_owned_by_dma(struct ftgmac100_txdes *txdes)
561{
562 return txdes->txdes0 & cpu_to_le32(FTGMAC100_TXDES0_TXDMA_OWN);
563}
564
565static void ftgmac100_txdes_set_dma_own(struct ftgmac100_txdes *txdes)
566{
567 /*
568 * Make sure dma own bit will not be set before any other
569 * descriptor fields.
570 */
571 wmb();
572 txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_TXDMA_OWN);
573}
574
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930575static void ftgmac100_txdes_set_end_of_ring(const struct ftgmac100 *priv,
576 struct ftgmac100_txdes *txdes)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000577{
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930578 txdes->txdes0 |= cpu_to_le32(priv->txdes0_edotr_mask);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000579}
580
581static void ftgmac100_txdes_set_first_segment(struct ftgmac100_txdes *txdes)
582{
583 txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_FTS);
584}
585
586static void ftgmac100_txdes_set_last_segment(struct ftgmac100_txdes *txdes)
587{
588 txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_LTS);
589}
590
591static void ftgmac100_txdes_set_buffer_size(struct ftgmac100_txdes *txdes,
592 unsigned int len)
593{
594 txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_TXBUF_SIZE(len));
595}
596
597static void ftgmac100_txdes_set_txint(struct ftgmac100_txdes *txdes)
598{
599 txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_TXIC);
600}
601
602static void ftgmac100_txdes_set_tcpcs(struct ftgmac100_txdes *txdes)
603{
604 txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_TCP_CHKSUM);
605}
606
607static void ftgmac100_txdes_set_udpcs(struct ftgmac100_txdes *txdes)
608{
609 txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_UDP_CHKSUM);
610}
611
612static void ftgmac100_txdes_set_ipcs(struct ftgmac100_txdes *txdes)
613{
614 txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_IP_CHKSUM);
615}
616
617static void ftgmac100_txdes_set_dma_addr(struct ftgmac100_txdes *txdes,
618 dma_addr_t addr)
619{
620 txdes->txdes3 = cpu_to_le32(addr);
621}
622
623static dma_addr_t ftgmac100_txdes_get_dma_addr(struct ftgmac100_txdes *txdes)
624{
625 return le32_to_cpu(txdes->txdes3);
626}
627
628/*
629 * txdes2 is not used by hardware. We use it to keep track of socket buffer.
630 * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu().
631 */
632static void ftgmac100_txdes_set_skb(struct ftgmac100_txdes *txdes,
633 struct sk_buff *skb)
634{
635 txdes->txdes2 = (unsigned int)skb;
636}
637
638static struct sk_buff *ftgmac100_txdes_get_skb(struct ftgmac100_txdes *txdes)
639{
640 return (struct sk_buff *)txdes->txdes2;
641}
642
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000643static int ftgmac100_next_tx_pointer(int pointer)
644{
645 return (pointer + 1) & (TX_QUEUE_ENTRIES - 1);
646}
647
648static void ftgmac100_tx_pointer_advance(struct ftgmac100 *priv)
649{
650 priv->tx_pointer = ftgmac100_next_tx_pointer(priv->tx_pointer);
651}
652
653static void ftgmac100_tx_clean_pointer_advance(struct ftgmac100 *priv)
654{
655 priv->tx_clean_pointer = ftgmac100_next_tx_pointer(priv->tx_clean_pointer);
656}
657
658static struct ftgmac100_txdes *ftgmac100_current_txdes(struct ftgmac100 *priv)
659{
660 return &priv->descs->txdes[priv->tx_pointer];
661}
662
663static struct ftgmac100_txdes *
664ftgmac100_current_clean_txdes(struct ftgmac100 *priv)
665{
666 return &priv->descs->txdes[priv->tx_clean_pointer];
667}
668
669static bool ftgmac100_tx_complete_packet(struct ftgmac100 *priv)
670{
671 struct net_device *netdev = priv->netdev;
672 struct ftgmac100_txdes *txdes;
673 struct sk_buff *skb;
674 dma_addr_t map;
675
676 if (priv->tx_pending == 0)
677 return false;
678
679 txdes = ftgmac100_current_clean_txdes(priv);
680
681 if (ftgmac100_txdes_owned_by_dma(txdes))
682 return false;
683
684 skb = ftgmac100_txdes_get_skb(txdes);
685 map = ftgmac100_txdes_get_dma_addr(txdes);
686
687 netdev->stats.tx_packets++;
688 netdev->stats.tx_bytes += skb->len;
689
690 dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
691
692 dev_kfree_skb(skb);
693
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930694 ftgmac100_txdes_reset(priv, txdes);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000695
696 ftgmac100_tx_clean_pointer_advance(priv);
697
698 spin_lock(&priv->tx_lock);
699 priv->tx_pending--;
700 spin_unlock(&priv->tx_lock);
701 netif_wake_queue(netdev);
702
703 return true;
704}
705
706static void ftgmac100_tx_complete(struct ftgmac100 *priv)
707{
708 while (ftgmac100_tx_complete_packet(priv))
709 ;
710}
711
712static int ftgmac100_xmit(struct ftgmac100 *priv, struct sk_buff *skb,
713 dma_addr_t map)
714{
715 struct net_device *netdev = priv->netdev;
716 struct ftgmac100_txdes *txdes;
717 unsigned int len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
718
719 txdes = ftgmac100_current_txdes(priv);
720 ftgmac100_tx_pointer_advance(priv);
721
722 /* setup TX descriptor */
723 ftgmac100_txdes_set_skb(txdes, skb);
724 ftgmac100_txdes_set_dma_addr(txdes, map);
725 ftgmac100_txdes_set_buffer_size(txdes, len);
726
727 ftgmac100_txdes_set_first_segment(txdes);
728 ftgmac100_txdes_set_last_segment(txdes);
729 ftgmac100_txdes_set_txint(txdes);
730 if (skb->ip_summed == CHECKSUM_PARTIAL) {
731 __be16 protocol = skb->protocol;
732
733 if (protocol == cpu_to_be16(ETH_P_IP)) {
734 u8 ip_proto = ip_hdr(skb)->protocol;
735
736 ftgmac100_txdes_set_ipcs(txdes);
737 if (ip_proto == IPPROTO_TCP)
738 ftgmac100_txdes_set_tcpcs(txdes);
739 else if (ip_proto == IPPROTO_UDP)
740 ftgmac100_txdes_set_udpcs(txdes);
741 }
742 }
743
744 spin_lock(&priv->tx_lock);
745 priv->tx_pending++;
746 if (priv->tx_pending == TX_QUEUE_ENTRIES)
747 netif_stop_queue(netdev);
748
749 /* start transmit */
750 ftgmac100_txdes_set_dma_own(txdes);
751 spin_unlock(&priv->tx_lock);
752
753 ftgmac100_txdma_normal_prio_start_polling(priv);
754
755 return NETDEV_TX_OK;
756}
757
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000758static int ftgmac100_alloc_rx_page(struct ftgmac100 *priv,
759 struct ftgmac100_rxdes *rxdes, gfp_t gfp)
760{
761 struct net_device *netdev = priv->netdev;
762 struct page *page;
763 dma_addr_t map;
764
765 page = alloc_page(gfp);
766 if (!page) {
767 if (net_ratelimit())
768 netdev_err(netdev, "failed to allocate rx page\n");
769 return -ENOMEM;
770 }
771
772 map = dma_map_page(priv->dev, page, 0, RX_BUF_SIZE, DMA_FROM_DEVICE);
773 if (unlikely(dma_mapping_error(priv->dev, map))) {
774 if (net_ratelimit())
775 netdev_err(netdev, "failed to map rx page\n");
776 __free_page(page);
777 return -ENOMEM;
778 }
779
Andrew Jefferyada66b52016-09-22 08:34:58 +0930780 ftgmac100_rxdes_set_page(priv, rxdes, page);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000781 ftgmac100_rxdes_set_dma_addr(rxdes, map);
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930782 ftgmac100_rxdes_set_dma_own(priv, rxdes);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000783 return 0;
784}
785
786static void ftgmac100_free_buffers(struct ftgmac100 *priv)
787{
788 int i;
789
790 for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
791 struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[i];
Andrew Jefferyada66b52016-09-22 08:34:58 +0930792 struct page *page = ftgmac100_rxdes_get_page(priv, rxdes);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000793 dma_addr_t map = ftgmac100_rxdes_get_dma_addr(rxdes);
794
795 if (!page)
796 continue;
797
798 dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
799 __free_page(page);
800 }
801
802 for (i = 0; i < TX_QUEUE_ENTRIES; i++) {
803 struct ftgmac100_txdes *txdes = &priv->descs->txdes[i];
804 struct sk_buff *skb = ftgmac100_txdes_get_skb(txdes);
805 dma_addr_t map = ftgmac100_txdes_get_dma_addr(txdes);
806
807 if (!skb)
808 continue;
809
810 dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
Eric Dumazet0113e342014-01-16 23:38:24 -0800811 kfree_skb(skb);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000812 }
813
814 dma_free_coherent(priv->dev, sizeof(struct ftgmac100_descs),
815 priv->descs, priv->descs_dma_addr);
816}
817
818static int ftgmac100_alloc_buffers(struct ftgmac100 *priv)
819{
820 int i;
821
Joe Perchesede23fa82013-08-26 22:45:23 -0700822 priv->descs = dma_zalloc_coherent(priv->dev,
823 sizeof(struct ftgmac100_descs),
824 &priv->descs_dma_addr, GFP_KERNEL);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000825 if (!priv->descs)
826 return -ENOMEM;
827
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000828 /* initialize RX ring */
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930829 ftgmac100_rxdes_set_end_of_ring(priv,
830 &priv->descs->rxdes[RX_QUEUE_ENTRIES - 1]);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000831
832 for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
833 struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[i];
834
835 if (ftgmac100_alloc_rx_page(priv, rxdes, GFP_KERNEL))
836 goto err;
837 }
838
839 /* initialize TX ring */
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930840 ftgmac100_txdes_set_end_of_ring(priv,
841 &priv->descs->txdes[TX_QUEUE_ENTRIES - 1]);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000842 return 0;
843
844err:
845 ftgmac100_free_buffers(priv);
846 return -ENOMEM;
847}
848
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000849static void ftgmac100_adjust_link(struct net_device *netdev)
850{
851 struct ftgmac100 *priv = netdev_priv(netdev);
Philippe Reynesb3c40ad2016-05-16 01:35:13 +0200852 struct phy_device *phydev = netdev->phydev;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000853 int ier;
854
855 if (phydev->speed == priv->old_speed)
856 return;
857
858 priv->old_speed = phydev->speed;
859
860 ier = ioread32(priv->base + FTGMAC100_OFFSET_IER);
861
862 /* disable all interrupts */
863 iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
864
865 netif_stop_queue(netdev);
866 ftgmac100_stop_hw(priv);
867
868 netif_start_queue(netdev);
869 ftgmac100_init_hw(priv);
870 ftgmac100_start_hw(priv, phydev->speed);
871
872 /* re-enable interrupts */
873 iowrite32(ier, priv->base + FTGMAC100_OFFSET_IER);
874}
875
876static int ftgmac100_mii_probe(struct ftgmac100 *priv)
877{
878 struct net_device *netdev = priv->netdev;
Guenter Roecke574f392016-01-10 12:04:32 -0800879 struct phy_device *phydev;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000880
Guenter Roecke574f392016-01-10 12:04:32 -0800881 phydev = phy_find_first(priv->mii_bus);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000882 if (!phydev) {
883 netdev_info(netdev, "%s: no PHY found\n", netdev->name);
884 return -ENODEV;
885 }
886
Andrew Lunn84eff6d2016-01-06 20:11:10 +0100887 phydev = phy_connect(netdev, phydev_name(phydev),
Florian Fainellif9a8f832013-01-14 00:52:52 +0000888 &ftgmac100_adjust_link, PHY_INTERFACE_MODE_GMII);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000889
890 if (IS_ERR(phydev)) {
891 netdev_err(netdev, "%s: Could not attach to PHY\n", netdev->name);
892 return PTR_ERR(phydev);
893 }
894
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000895 return 0;
896}
897
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000898static int ftgmac100_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
899{
900 struct net_device *netdev = bus->priv;
901 struct ftgmac100 *priv = netdev_priv(netdev);
902 unsigned int phycr;
903 int i;
904
905 phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
906
907 /* preserve MDC cycle threshold */
908 phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
909
910 phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr) |
911 FTGMAC100_PHYCR_REGAD(regnum) |
912 FTGMAC100_PHYCR_MIIRD;
913
914 iowrite32(phycr, priv->base + FTGMAC100_OFFSET_PHYCR);
915
916 for (i = 0; i < 10; i++) {
917 phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
918
919 if ((phycr & FTGMAC100_PHYCR_MIIRD) == 0) {
920 int data;
921
922 data = ioread32(priv->base + FTGMAC100_OFFSET_PHYDATA);
923 return FTGMAC100_PHYDATA_MIIRDATA(data);
924 }
925
926 udelay(100);
927 }
928
929 netdev_err(netdev, "mdio read timed out\n");
930 return -EIO;
931}
932
933static int ftgmac100_mdiobus_write(struct mii_bus *bus, int phy_addr,
934 int regnum, u16 value)
935{
936 struct net_device *netdev = bus->priv;
937 struct ftgmac100 *priv = netdev_priv(netdev);
938 unsigned int phycr;
939 int data;
940 int i;
941
942 phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
943
944 /* preserve MDC cycle threshold */
945 phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
946
947 phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr) |
948 FTGMAC100_PHYCR_REGAD(regnum) |
949 FTGMAC100_PHYCR_MIIWR;
950
951 data = FTGMAC100_PHYDATA_MIIWDATA(value);
952
953 iowrite32(data, priv->base + FTGMAC100_OFFSET_PHYDATA);
954 iowrite32(phycr, priv->base + FTGMAC100_OFFSET_PHYCR);
955
956 for (i = 0; i < 10; i++) {
957 phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
958
959 if ((phycr & FTGMAC100_PHYCR_MIIWR) == 0)
960 return 0;
961
962 udelay(100);
963 }
964
965 netdev_err(netdev, "mdio write timed out\n");
966 return -EIO;
967}
968
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000969static void ftgmac100_get_drvinfo(struct net_device *netdev,
970 struct ethtool_drvinfo *info)
971{
Jiri Pirko7826d432013-01-06 00:44:26 +0000972 strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
973 strlcpy(info->version, DRV_VERSION, sizeof(info->version));
974 strlcpy(info->bus_info, dev_name(&netdev->dev), sizeof(info->bus_info));
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000975}
976
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000977static const struct ethtool_ops ftgmac100_ethtool_ops = {
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000978 .get_drvinfo = ftgmac100_get_drvinfo,
979 .get_link = ethtool_op_get_link,
Philippe Reynesfd24d722016-05-16 01:35:14 +0200980 .get_link_ksettings = phy_ethtool_get_link_ksettings,
981 .set_link_ksettings = phy_ethtool_set_link_ksettings,
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000982};
983
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000984static irqreturn_t ftgmac100_interrupt(int irq, void *dev_id)
985{
986 struct net_device *netdev = dev_id;
987 struct ftgmac100 *priv = netdev_priv(netdev);
988
Gavin Shanbd466c32016-07-19 11:54:23 +1000989 /* When running in NCSI mode, the interface should be ready for
990 * receiving or transmitting NCSI packets before it's opened.
991 */
992 if (likely(priv->use_ncsi || netif_running(netdev))) {
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000993 /* Disable interrupts for polling */
994 iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
995 napi_schedule(&priv->napi);
996 }
997
998 return IRQ_HANDLED;
999}
1000
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001001static int ftgmac100_poll(struct napi_struct *napi, int budget)
1002{
1003 struct ftgmac100 *priv = container_of(napi, struct ftgmac100, napi);
1004 struct net_device *netdev = priv->netdev;
1005 unsigned int status;
1006 bool completed = true;
1007 int rx = 0;
1008
1009 status = ioread32(priv->base + FTGMAC100_OFFSET_ISR);
1010 iowrite32(status, priv->base + FTGMAC100_OFFSET_ISR);
1011
1012 if (status & (FTGMAC100_INT_RPKT_BUF | FTGMAC100_INT_NO_RXBUF)) {
1013 /*
1014 * FTGMAC100_INT_RPKT_BUF:
1015 * RX DMA has received packets into RX buffer successfully
1016 *
1017 * FTGMAC100_INT_NO_RXBUF:
1018 * RX buffer unavailable
1019 */
1020 bool retry;
1021
1022 do {
1023 retry = ftgmac100_rx_packet(priv, &rx);
1024 } while (retry && rx < budget);
1025
1026 if (retry && rx == budget)
1027 completed = false;
1028 }
1029
1030 if (status & (FTGMAC100_INT_XPKT_ETH | FTGMAC100_INT_XPKT_LOST)) {
1031 /*
1032 * FTGMAC100_INT_XPKT_ETH:
1033 * packet transmitted to ethernet successfully
1034 *
1035 * FTGMAC100_INT_XPKT_LOST:
1036 * packet transmitted to ethernet lost due to late
1037 * collision or excessive collision
1038 */
1039 ftgmac100_tx_complete(priv);
1040 }
1041
Gavin Shanfc6061c2016-07-19 11:54:25 +10001042 if (status & priv->int_mask_all & (FTGMAC100_INT_NO_RXBUF |
Joel Stanleyedcd6922016-09-22 08:35:03 +09301043 FTGMAC100_INT_RPKT_LOST | FTGMAC100_INT_AHB_ERR)) {
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001044 if (net_ratelimit())
Joel Stanleyedcd6922016-09-22 08:35:03 +09301045 netdev_info(netdev, "[ISR] = 0x%x: %s%s%s\n", status,
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001046 status & FTGMAC100_INT_NO_RXBUF ? "NO_RXBUF " : "",
1047 status & FTGMAC100_INT_RPKT_LOST ? "RPKT_LOST " : "",
Joel Stanleyedcd6922016-09-22 08:35:03 +09301048 status & FTGMAC100_INT_AHB_ERR ? "AHB_ERR " : "");
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001049
1050 if (status & FTGMAC100_INT_NO_RXBUF) {
1051 /* RX buffer unavailable */
1052 netdev->stats.rx_over_errors++;
1053 }
1054
1055 if (status & FTGMAC100_INT_RPKT_LOST) {
1056 /* received packet lost due to RX FIFO full */
1057 netdev->stats.rx_fifo_errors++;
1058 }
1059 }
1060
1061 if (completed) {
1062 napi_complete(napi);
1063
1064 /* enable all interrupts */
Gavin Shanfc6061c2016-07-19 11:54:25 +10001065 iowrite32(priv->int_mask_all,
1066 priv->base + FTGMAC100_OFFSET_IER);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001067 }
1068
1069 return rx;
1070}
1071
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001072static int ftgmac100_open(struct net_device *netdev)
1073{
1074 struct ftgmac100 *priv = netdev_priv(netdev);
Gavin Shan08c9c122016-09-22 08:35:01 +09301075 unsigned int status;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001076 int err;
1077
1078 err = ftgmac100_alloc_buffers(priv);
1079 if (err) {
1080 netdev_err(netdev, "failed to allocate buffers\n");
1081 goto err_alloc;
1082 }
1083
Benjamin Herrenschmidt60b28a12017-04-05 12:28:41 +10001084 err = request_irq(netdev->irq, ftgmac100_interrupt, 0, netdev->name, netdev);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001085 if (err) {
Benjamin Herrenschmidt60b28a12017-04-05 12:28:41 +10001086 netdev_err(netdev, "failed to request irq %d\n", netdev->irq);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001087 goto err_irq;
1088 }
1089
1090 priv->rx_pointer = 0;
1091 priv->tx_clean_pointer = 0;
1092 priv->tx_pointer = 0;
1093 priv->tx_pending = 0;
1094
1095 err = ftgmac100_reset_hw(priv);
1096 if (err)
1097 goto err_hw;
1098
1099 ftgmac100_init_hw(priv);
Gavin Shanbd466c32016-07-19 11:54:23 +10001100 ftgmac100_start_hw(priv, priv->use_ncsi ? 100 : 10);
Gavin Shan08c9c122016-09-22 08:35:01 +09301101
1102 /* Clear stale interrupts */
1103 status = ioread32(priv->base + FTGMAC100_OFFSET_ISR);
1104 iowrite32(status, priv->base + FTGMAC100_OFFSET_ISR);
1105
Gavin Shanbd466c32016-07-19 11:54:23 +10001106 if (netdev->phydev)
1107 phy_start(netdev->phydev);
1108 else if (priv->use_ncsi)
1109 netif_carrier_on(netdev);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001110
1111 napi_enable(&priv->napi);
1112 netif_start_queue(netdev);
1113
1114 /* enable all interrupts */
Gavin Shanfc6061c2016-07-19 11:54:25 +10001115 iowrite32(priv->int_mask_all, priv->base + FTGMAC100_OFFSET_IER);
Gavin Shanbd466c32016-07-19 11:54:23 +10001116
1117 /* Start the NCSI device */
1118 if (priv->use_ncsi) {
1119 err = ncsi_start_dev(priv->ndev);
1120 if (err)
1121 goto err_ncsi;
1122 }
1123
1124 priv->enabled = true;
1125
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001126 return 0;
1127
Gavin Shanbd466c32016-07-19 11:54:23 +10001128err_ncsi:
1129 napi_disable(&priv->napi);
1130 netif_stop_queue(netdev);
1131 iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001132err_hw:
Benjamin Herrenschmidt60b28a12017-04-05 12:28:41 +10001133 free_irq(netdev->irq, netdev);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001134err_irq:
1135 ftgmac100_free_buffers(priv);
1136err_alloc:
1137 return err;
1138}
1139
1140static int ftgmac100_stop(struct net_device *netdev)
1141{
1142 struct ftgmac100 *priv = netdev_priv(netdev);
1143
Gavin Shanbd466c32016-07-19 11:54:23 +10001144 if (!priv->enabled)
1145 return 0;
1146
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001147 /* disable all interrupts */
Gavin Shanbd466c32016-07-19 11:54:23 +10001148 priv->enabled = false;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001149 iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
1150
1151 netif_stop_queue(netdev);
1152 napi_disable(&priv->napi);
Gavin Shanbd466c32016-07-19 11:54:23 +10001153 if (netdev->phydev)
1154 phy_stop(netdev->phydev);
Gavin Shan2c15f252016-10-04 11:25:54 +11001155 else if (priv->use_ncsi)
1156 ncsi_stop_dev(priv->ndev);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001157
1158 ftgmac100_stop_hw(priv);
Benjamin Herrenschmidt60b28a12017-04-05 12:28:41 +10001159 free_irq(netdev->irq, netdev);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001160 ftgmac100_free_buffers(priv);
1161
1162 return 0;
1163}
1164
1165static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
1166 struct net_device *netdev)
1167{
1168 struct ftgmac100 *priv = netdev_priv(netdev);
1169 dma_addr_t map;
1170
1171 if (unlikely(skb->len > MAX_PKT_SIZE)) {
1172 if (net_ratelimit())
1173 netdev_dbg(netdev, "tx packet too big\n");
1174
1175 netdev->stats.tx_dropped++;
Eric Dumazet0113e342014-01-16 23:38:24 -08001176 kfree_skb(skb);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001177 return NETDEV_TX_OK;
1178 }
1179
1180 map = dma_map_single(priv->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
1181 if (unlikely(dma_mapping_error(priv->dev, map))) {
1182 /* drop packet */
1183 if (net_ratelimit())
1184 netdev_err(netdev, "map socket buffer failed\n");
1185
1186 netdev->stats.tx_dropped++;
Eric Dumazet0113e342014-01-16 23:38:24 -08001187 kfree_skb(skb);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001188 return NETDEV_TX_OK;
1189 }
1190
1191 return ftgmac100_xmit(priv, skb, map);
1192}
1193
1194/* optional */
1195static int ftgmac100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
1196{
Gavin Shanbd466c32016-07-19 11:54:23 +10001197 if (!netdev->phydev)
1198 return -ENXIO;
1199
Philippe Reynesb3c40ad2016-05-16 01:35:13 +02001200 return phy_mii_ioctl(netdev->phydev, ifr, cmd);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001201}
1202
1203static const struct net_device_ops ftgmac100_netdev_ops = {
1204 .ndo_open = ftgmac100_open,
1205 .ndo_stop = ftgmac100_stop,
1206 .ndo_start_xmit = ftgmac100_hard_start_xmit,
Gavin Shan113ce102016-07-19 11:54:22 +10001207 .ndo_set_mac_address = ftgmac100_set_mac_addr,
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001208 .ndo_validate_addr = eth_validate_addr,
1209 .ndo_do_ioctl = ftgmac100_do_ioctl,
1210};
1211
Gavin Shaneb418182016-07-19 11:54:21 +10001212static int ftgmac100_setup_mdio(struct net_device *netdev)
1213{
1214 struct ftgmac100 *priv = netdev_priv(netdev);
1215 struct platform_device *pdev = to_platform_device(priv->dev);
1216 int i, err = 0;
Joel Stanleye07dc632016-09-22 08:35:02 +09301217 u32 reg;
Gavin Shaneb418182016-07-19 11:54:21 +10001218
1219 /* initialize mdio bus */
1220 priv->mii_bus = mdiobus_alloc();
1221 if (!priv->mii_bus)
1222 return -EIO;
1223
Joel Stanleye07dc632016-09-22 08:35:02 +09301224 if (of_machine_is_compatible("aspeed,ast2400") ||
1225 of_machine_is_compatible("aspeed,ast2500")) {
1226 /* This driver supports the old MDIO interface */
1227 reg = ioread32(priv->base + FTGMAC100_OFFSET_REVR);
1228 reg &= ~FTGMAC100_REVR_NEW_MDIO_INTERFACE;
1229 iowrite32(reg, priv->base + FTGMAC100_OFFSET_REVR);
1230 };
1231
Gavin Shaneb418182016-07-19 11:54:21 +10001232 priv->mii_bus->name = "ftgmac100_mdio";
1233 snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%d",
1234 pdev->name, pdev->id);
1235 priv->mii_bus->priv = priv->netdev;
1236 priv->mii_bus->read = ftgmac100_mdiobus_read;
1237 priv->mii_bus->write = ftgmac100_mdiobus_write;
1238
1239 for (i = 0; i < PHY_MAX_ADDR; i++)
1240 priv->mii_bus->irq[i] = PHY_POLL;
1241
1242 err = mdiobus_register(priv->mii_bus);
1243 if (err) {
1244 dev_err(priv->dev, "Cannot register MDIO bus!\n");
1245 goto err_register_mdiobus;
1246 }
1247
1248 err = ftgmac100_mii_probe(priv);
1249 if (err) {
1250 dev_err(priv->dev, "MII Probe failed!\n");
1251 goto err_mii_probe;
1252 }
1253
1254 return 0;
1255
1256err_mii_probe:
1257 mdiobus_unregister(priv->mii_bus);
1258err_register_mdiobus:
1259 mdiobus_free(priv->mii_bus);
1260 return err;
1261}
1262
1263static void ftgmac100_destroy_mdio(struct net_device *netdev)
1264{
1265 struct ftgmac100 *priv = netdev_priv(netdev);
1266
1267 if (!netdev->phydev)
1268 return;
1269
1270 phy_disconnect(netdev->phydev);
1271 mdiobus_unregister(priv->mii_bus);
1272 mdiobus_free(priv->mii_bus);
1273}
1274
Gavin Shanbd466c32016-07-19 11:54:23 +10001275static void ftgmac100_ncsi_handler(struct ncsi_dev *nd)
1276{
1277 if (unlikely(nd->state != ncsi_dev_state_functional))
1278 return;
1279
1280 netdev_info(nd->dev, "NCSI interface %s\n",
1281 nd->link_up ? "up" : "down");
1282}
1283
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001284static int ftgmac100_probe(struct platform_device *pdev)
1285{
1286 struct resource *res;
1287 int irq;
1288 struct net_device *netdev;
1289 struct ftgmac100 *priv;
Gavin Shanbd466c32016-07-19 11:54:23 +10001290 int err = 0;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001291
1292 if (!pdev)
1293 return -ENODEV;
1294
1295 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1296 if (!res)
1297 return -ENXIO;
1298
1299 irq = platform_get_irq(pdev, 0);
1300 if (irq < 0)
1301 return irq;
1302
1303 /* setup net_device */
1304 netdev = alloc_etherdev(sizeof(*priv));
1305 if (!netdev) {
1306 err = -ENOMEM;
1307 goto err_alloc_etherdev;
1308 }
1309
1310 SET_NETDEV_DEV(netdev, &pdev->dev);
1311
Wilfried Klaebe7ad24ea2014-05-11 00:12:32 +00001312 netdev->ethtool_ops = &ftgmac100_ethtool_ops;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001313 netdev->netdev_ops = &ftgmac100_netdev_ops;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001314
1315 platform_set_drvdata(pdev, netdev);
1316
1317 /* setup private data */
1318 priv = netdev_priv(netdev);
1319 priv->netdev = netdev;
1320 priv->dev = &pdev->dev;
1321
1322 spin_lock_init(&priv->tx_lock);
1323
1324 /* initialize NAPI */
1325 netif_napi_add(netdev, &priv->napi, ftgmac100_poll, 64);
1326
1327 /* map io memory */
1328 priv->res = request_mem_region(res->start, resource_size(res),
1329 dev_name(&pdev->dev));
1330 if (!priv->res) {
1331 dev_err(&pdev->dev, "Could not reserve memory region\n");
1332 err = -ENOMEM;
1333 goto err_req_mem;
1334 }
1335
1336 priv->base = ioremap(res->start, resource_size(res));
1337 if (!priv->base) {
1338 dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
1339 err = -EIO;
1340 goto err_ioremap;
1341 }
1342
Benjamin Herrenschmidt60b28a12017-04-05 12:28:41 +10001343 netdev->irq = irq;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001344
Gavin Shan113ce102016-07-19 11:54:22 +10001345 /* MAC address from chip or random one */
1346 ftgmac100_setup_mac(priv);
1347
Gavin Shanfc6061c2016-07-19 11:54:25 +10001348 priv->int_mask_all = (FTGMAC100_INT_RPKT_LOST |
1349 FTGMAC100_INT_XPKT_ETH |
1350 FTGMAC100_INT_XPKT_LOST |
1351 FTGMAC100_INT_AHB_ERR |
Gavin Shanfc6061c2016-07-19 11:54:25 +10001352 FTGMAC100_INT_RPKT_BUF |
1353 FTGMAC100_INT_NO_RXBUF);
Joel Stanley2a0ab8eb2016-09-22 08:35:00 +09301354
1355 if (of_machine_is_compatible("aspeed,ast2400") ||
1356 of_machine_is_compatible("aspeed,ast2500")) {
1357 priv->rxdes0_edorr_mask = BIT(30);
1358 priv->txdes0_edotr_mask = BIT(30);
1359 } else {
1360 priv->rxdes0_edorr_mask = BIT(15);
1361 priv->txdes0_edotr_mask = BIT(15);
1362 }
1363
Gavin Shanbd466c32016-07-19 11:54:23 +10001364 if (pdev->dev.of_node &&
1365 of_get_property(pdev->dev.of_node, "use-ncsi", NULL)) {
1366 if (!IS_ENABLED(CONFIG_NET_NCSI)) {
1367 dev_err(&pdev->dev, "NCSI stack not enabled\n");
1368 goto err_ncsi_dev;
1369 }
1370
1371 dev_info(&pdev->dev, "Using NCSI interface\n");
1372 priv->use_ncsi = true;
1373 priv->ndev = ncsi_register_dev(netdev, ftgmac100_ncsi_handler);
1374 if (!priv->ndev)
1375 goto err_ncsi_dev;
1376 } else {
1377 priv->use_ncsi = false;
1378 err = ftgmac100_setup_mdio(netdev);
1379 if (err)
1380 goto err_setup_mdio;
1381 }
1382
1383 /* We have to disable on-chip IP checksum functionality
1384 * when NCSI is enabled on the interface. It doesn't work
1385 * in that case.
1386 */
1387 netdev->features = NETIF_F_IP_CSUM | NETIF_F_GRO;
1388 if (priv->use_ncsi &&
1389 of_get_property(pdev->dev.of_node, "no-hw-checksum", NULL))
1390 netdev->features &= ~NETIF_F_IP_CSUM;
1391
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001392
1393 /* register network device */
1394 err = register_netdev(netdev);
1395 if (err) {
1396 dev_err(&pdev->dev, "Failed to register netdev\n");
1397 goto err_register_netdev;
1398 }
1399
Benjamin Herrenschmidt60b28a12017-04-05 12:28:41 +10001400 netdev_info(netdev, "irq %d, mapped at %p\n", netdev->irq, priv->base);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001401
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001402 return 0;
1403
Gavin Shanbd466c32016-07-19 11:54:23 +10001404err_ncsi_dev:
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001405err_register_netdev:
Gavin Shaneb418182016-07-19 11:54:21 +10001406 ftgmac100_destroy_mdio(netdev);
1407err_setup_mdio:
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001408 iounmap(priv->base);
1409err_ioremap:
1410 release_resource(priv->res);
1411err_req_mem:
1412 netif_napi_del(&priv->napi);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001413 free_netdev(netdev);
1414err_alloc_etherdev:
1415 return err;
1416}
1417
Dmitry Torokhovbe125022017-03-01 17:24:47 -08001418static int ftgmac100_remove(struct platform_device *pdev)
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001419{
1420 struct net_device *netdev;
1421 struct ftgmac100 *priv;
1422
1423 netdev = platform_get_drvdata(pdev);
1424 priv = netdev_priv(netdev);
1425
1426 unregister_netdev(netdev);
Gavin Shaneb418182016-07-19 11:54:21 +10001427 ftgmac100_destroy_mdio(netdev);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001428
1429 iounmap(priv->base);
1430 release_resource(priv->res);
1431
1432 netif_napi_del(&priv->napi);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001433 free_netdev(netdev);
1434 return 0;
1435}
1436
Gavin Shanbb168e22016-07-19 11:54:24 +10001437static const struct of_device_id ftgmac100_of_match[] = {
1438 { .compatible = "faraday,ftgmac100" },
1439 { }
1440};
1441MODULE_DEVICE_TABLE(of, ftgmac100_of_match);
1442
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001443static struct platform_driver ftgmac100_driver = {
Gavin Shanbb168e22016-07-19 11:54:24 +10001444 .probe = ftgmac100_probe,
Dmitry Torokhovbe125022017-03-01 17:24:47 -08001445 .remove = ftgmac100_remove,
Gavin Shanbb168e22016-07-19 11:54:24 +10001446 .driver = {
1447 .name = DRV_NAME,
1448 .of_match_table = ftgmac100_of_match,
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001449 },
1450};
Sachin Kamat14f645d2013-03-18 01:50:48 +00001451module_platform_driver(ftgmac100_driver);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001452
1453MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
1454MODULE_DESCRIPTION("FTGMAC100 driver");
1455MODULE_LICENSE("GPL");