blob: 7f46d9c18f11266045f8009dc67a86c08bf5edc8 [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 {
Benjamin Herrenschmidt831fb332017-04-05 12:28:43 +100055 /* Registers */
Po-Yu Chuang69785b72011-06-08 23:32:48 +000056 struct resource *res;
57 void __iomem *base;
Po-Yu Chuang69785b72011-06-08 23:32:48 +000058
59 struct ftgmac100_descs *descs;
60 dma_addr_t descs_dma_addr;
61
Benjamin Herrenschmidt831fb332017-04-05 12:28:43 +100062 /* Rx ring */
Andrew Jefferyada66b52016-09-22 08:34:58 +093063 struct page *rx_pages[RX_QUEUE_ENTRIES];
Po-Yu Chuang69785b72011-06-08 23:32:48 +000064 unsigned int rx_pointer;
Benjamin Herrenschmidt831fb332017-04-05 12:28:43 +100065 u32 rxdes0_edorr_mask;
66
67 /* Tx ring */
Po-Yu Chuang69785b72011-06-08 23:32:48 +000068 unsigned int tx_clean_pointer;
69 unsigned int tx_pointer;
70 unsigned int tx_pending;
Benjamin Herrenschmidt831fb332017-04-05 12:28:43 +100071 u32 txdes0_edotr_mask;
Po-Yu Chuang69785b72011-06-08 23:32:48 +000072 spinlock_t tx_lock;
73
Benjamin Herrenschmidt831fb332017-04-05 12:28:43 +100074 /* Component structures */
Po-Yu Chuang69785b72011-06-08 23:32:48 +000075 struct net_device *netdev;
76 struct device *dev;
Gavin Shanbd466c32016-07-19 11:54:23 +100077 struct ncsi_dev *ndev;
Po-Yu Chuang69785b72011-06-08 23:32:48 +000078 struct napi_struct napi;
Po-Yu Chuang69785b72011-06-08 23:32:48 +000079 struct mii_bus *mii_bus;
Andrew Jeffery7906a4d2016-09-22 08:34:59 +093080
Benjamin Herrenschmidt831fb332017-04-05 12:28:43 +100081 /* Link management */
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +100082 int cur_speed;
83 int cur_duplex;
Benjamin Herrenschmidt831fb332017-04-05 12:28:43 +100084 bool use_ncsi;
85
86 /* Misc */
87 int int_mask_all;
Po-Yu Chuang69785b72011-06-08 23:32:48 +000088};
89
90static int ftgmac100_alloc_rx_page(struct ftgmac100 *priv,
91 struct ftgmac100_rxdes *rxdes, gfp_t gfp);
92
Po-Yu Chuang69785b72011-06-08 23:32:48 +000093static void ftgmac100_set_rx_ring_base(struct ftgmac100 *priv, dma_addr_t addr)
94{
95 iowrite32(addr, priv->base + FTGMAC100_OFFSET_RXR_BADR);
96}
97
98static void ftgmac100_set_rx_buffer_size(struct ftgmac100 *priv,
99 unsigned int size)
100{
101 size = FTGMAC100_RBSR_SIZE(size);
102 iowrite32(size, priv->base + FTGMAC100_OFFSET_RBSR);
103}
104
105static void ftgmac100_set_normal_prio_tx_ring_base(struct ftgmac100 *priv,
106 dma_addr_t addr)
107{
108 iowrite32(addr, priv->base + FTGMAC100_OFFSET_NPTXR_BADR);
109}
110
111static void ftgmac100_txdma_normal_prio_start_polling(struct ftgmac100 *priv)
112{
113 iowrite32(1, priv->base + FTGMAC100_OFFSET_NPTXPD);
114}
115
116static int ftgmac100_reset_hw(struct ftgmac100 *priv)
117{
118 struct net_device *netdev = priv->netdev;
119 int i;
120
121 /* NOTE: reset clears all registers */
122 iowrite32(FTGMAC100_MACCR_SW_RST, priv->base + FTGMAC100_OFFSET_MACCR);
123 for (i = 0; i < 5; i++) {
124 unsigned int maccr;
125
126 maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR);
127 if (!(maccr & FTGMAC100_MACCR_SW_RST))
128 return 0;
129
130 udelay(1000);
131 }
132
133 netdev_err(netdev, "software reset failed\n");
134 return -EIO;
135}
136
137static void ftgmac100_set_mac(struct ftgmac100 *priv, const unsigned char *mac)
138{
139 unsigned int maddr = mac[0] << 8 | mac[1];
140 unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
141
142 iowrite32(maddr, priv->base + FTGMAC100_OFFSET_MAC_MADR);
143 iowrite32(laddr, priv->base + FTGMAC100_OFFSET_MAC_LADR);
144}
145
Gavin Shan113ce102016-07-19 11:54:22 +1000146static void ftgmac100_setup_mac(struct ftgmac100 *priv)
147{
148 u8 mac[ETH_ALEN];
149 unsigned int m;
150 unsigned int l;
151 void *addr;
152
153 addr = device_get_mac_address(priv->dev, mac, ETH_ALEN);
154 if (addr) {
155 ether_addr_copy(priv->netdev->dev_addr, mac);
156 dev_info(priv->dev, "Read MAC address %pM from device tree\n",
157 mac);
158 return;
159 }
160
161 m = ioread32(priv->base + FTGMAC100_OFFSET_MAC_MADR);
162 l = ioread32(priv->base + FTGMAC100_OFFSET_MAC_LADR);
163
164 mac[0] = (m >> 8) & 0xff;
165 mac[1] = m & 0xff;
166 mac[2] = (l >> 24) & 0xff;
167 mac[3] = (l >> 16) & 0xff;
168 mac[4] = (l >> 8) & 0xff;
169 mac[5] = l & 0xff;
170
Gavin Shan113ce102016-07-19 11:54:22 +1000171 if (is_valid_ether_addr(mac)) {
172 ether_addr_copy(priv->netdev->dev_addr, mac);
173 dev_info(priv->dev, "Read MAC address %pM from chip\n", mac);
174 } else {
175 eth_hw_addr_random(priv->netdev);
176 dev_info(priv->dev, "Generated random MAC address %pM\n",
177 priv->netdev->dev_addr);
178 }
179}
180
181static int ftgmac100_set_mac_addr(struct net_device *dev, void *p)
182{
183 int ret;
184
185 ret = eth_prepare_mac_addr_change(dev, p);
186 if (ret < 0)
187 return ret;
188
189 eth_commit_mac_addr_change(dev, p);
190 ftgmac100_set_mac(netdev_priv(dev), dev->dev_addr);
191
192 return 0;
193}
194
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000195static void ftgmac100_init_hw(struct ftgmac100 *priv)
196{
197 /* setup ring buffer base registers */
198 ftgmac100_set_rx_ring_base(priv,
199 priv->descs_dma_addr +
200 offsetof(struct ftgmac100_descs, rxdes));
201 ftgmac100_set_normal_prio_tx_ring_base(priv,
202 priv->descs_dma_addr +
203 offsetof(struct ftgmac100_descs, txdes));
204
205 ftgmac100_set_rx_buffer_size(priv, RX_BUF_SIZE);
206
207 iowrite32(FTGMAC100_APTC_RXPOLL_CNT(1), priv->base + FTGMAC100_OFFSET_APTC);
208
209 ftgmac100_set_mac(priv, priv->netdev->dev_addr);
210}
211
212#define MACCR_ENABLE_ALL (FTGMAC100_MACCR_TXDMA_EN | \
213 FTGMAC100_MACCR_RXDMA_EN | \
214 FTGMAC100_MACCR_TXMAC_EN | \
215 FTGMAC100_MACCR_RXMAC_EN | \
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000216 FTGMAC100_MACCR_CRC_APD | \
217 FTGMAC100_MACCR_RX_RUNT | \
218 FTGMAC100_MACCR_RX_BROADPKT)
219
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +1000220static void ftgmac100_start_hw(struct ftgmac100 *priv)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000221{
222 int maccr = MACCR_ENABLE_ALL;
223
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +1000224 switch (priv->cur_speed) {
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000225 default:
226 case 10:
227 break;
228
229 case 100:
230 maccr |= FTGMAC100_MACCR_FAST_MODE;
231 break;
232
233 case 1000:
234 maccr |= FTGMAC100_MACCR_GIGA_MODE;
235 break;
236 }
237
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +1000238 if (priv->cur_duplex == DUPLEX_FULL)
239 maccr |= FTGMAC100_MACCR_FULLDUP;
240
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000241 iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR);
242}
243
244static void ftgmac100_stop_hw(struct ftgmac100 *priv)
245{
246 iowrite32(0, priv->base + FTGMAC100_OFFSET_MACCR);
247}
248
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000249static bool ftgmac100_rxdes_first_segment(struct ftgmac100_rxdes *rxdes)
250{
251 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_FRS);
252}
253
254static bool ftgmac100_rxdes_last_segment(struct ftgmac100_rxdes *rxdes)
255{
256 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_LRS);
257}
258
259static bool ftgmac100_rxdes_packet_ready(struct ftgmac100_rxdes *rxdes)
260{
261 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RXPKT_RDY);
262}
263
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930264static void ftgmac100_rxdes_set_dma_own(const struct ftgmac100 *priv,
265 struct ftgmac100_rxdes *rxdes)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000266{
267 /* clear status bits */
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930268 rxdes->rxdes0 &= cpu_to_le32(priv->rxdes0_edorr_mask);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000269}
270
271static bool ftgmac100_rxdes_rx_error(struct ftgmac100_rxdes *rxdes)
272{
273 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RX_ERR);
274}
275
276static bool ftgmac100_rxdes_crc_error(struct ftgmac100_rxdes *rxdes)
277{
278 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_CRC_ERR);
279}
280
281static bool ftgmac100_rxdes_frame_too_long(struct ftgmac100_rxdes *rxdes)
282{
283 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_FTL);
284}
285
286static bool ftgmac100_rxdes_runt(struct ftgmac100_rxdes *rxdes)
287{
288 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RUNT);
289}
290
291static bool ftgmac100_rxdes_odd_nibble(struct ftgmac100_rxdes *rxdes)
292{
293 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RX_ODD_NB);
294}
295
296static unsigned int ftgmac100_rxdes_data_length(struct ftgmac100_rxdes *rxdes)
297{
298 return le32_to_cpu(rxdes->rxdes0) & FTGMAC100_RXDES0_VDBC;
299}
300
301static bool ftgmac100_rxdes_multicast(struct ftgmac100_rxdes *rxdes)
302{
303 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_MULTICAST);
304}
305
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930306static void ftgmac100_rxdes_set_end_of_ring(const struct ftgmac100 *priv,
307 struct ftgmac100_rxdes *rxdes)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000308{
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930309 rxdes->rxdes0 |= cpu_to_le32(priv->rxdes0_edorr_mask);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000310}
311
312static void ftgmac100_rxdes_set_dma_addr(struct ftgmac100_rxdes *rxdes,
313 dma_addr_t addr)
314{
315 rxdes->rxdes3 = cpu_to_le32(addr);
316}
317
318static dma_addr_t ftgmac100_rxdes_get_dma_addr(struct ftgmac100_rxdes *rxdes)
319{
320 return le32_to_cpu(rxdes->rxdes3);
321}
322
323static bool ftgmac100_rxdes_is_tcp(struct ftgmac100_rxdes *rxdes)
324{
325 return (rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_PROT_MASK)) ==
326 cpu_to_le32(FTGMAC100_RXDES1_PROT_TCPIP);
327}
328
329static bool ftgmac100_rxdes_is_udp(struct ftgmac100_rxdes *rxdes)
330{
331 return (rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_PROT_MASK)) ==
332 cpu_to_le32(FTGMAC100_RXDES1_PROT_UDPIP);
333}
334
335static bool ftgmac100_rxdes_tcpcs_err(struct ftgmac100_rxdes *rxdes)
336{
337 return rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_TCP_CHKSUM_ERR);
338}
339
340static bool ftgmac100_rxdes_udpcs_err(struct ftgmac100_rxdes *rxdes)
341{
342 return rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_UDP_CHKSUM_ERR);
343}
344
345static bool ftgmac100_rxdes_ipcs_err(struct ftgmac100_rxdes *rxdes)
346{
347 return rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_IP_CHKSUM_ERR);
348}
349
Andrew Jefferyada66b52016-09-22 08:34:58 +0930350static inline struct page **ftgmac100_rxdes_page_slot(struct ftgmac100 *priv,
351 struct ftgmac100_rxdes *rxdes)
352{
353 return &priv->rx_pages[rxdes - priv->descs->rxdes];
354}
355
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000356/*
357 * rxdes2 is not used by hardware. We use it to keep track of page.
358 * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu().
359 */
Andrew Jefferyada66b52016-09-22 08:34:58 +0930360static void ftgmac100_rxdes_set_page(struct ftgmac100 *priv,
361 struct ftgmac100_rxdes *rxdes,
362 struct page *page)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000363{
Andrew Jefferyada66b52016-09-22 08:34:58 +0930364 *ftgmac100_rxdes_page_slot(priv, rxdes) = page;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000365}
366
Andrew Jefferyada66b52016-09-22 08:34:58 +0930367static struct page *ftgmac100_rxdes_get_page(struct ftgmac100 *priv,
368 struct ftgmac100_rxdes *rxdes)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000369{
Andrew Jefferyada66b52016-09-22 08:34:58 +0930370 return *ftgmac100_rxdes_page_slot(priv, rxdes);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000371}
372
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000373static int ftgmac100_next_rx_pointer(int pointer)
374{
375 return (pointer + 1) & (RX_QUEUE_ENTRIES - 1);
376}
377
378static void ftgmac100_rx_pointer_advance(struct ftgmac100 *priv)
379{
380 priv->rx_pointer = ftgmac100_next_rx_pointer(priv->rx_pointer);
381}
382
383static struct ftgmac100_rxdes *ftgmac100_current_rxdes(struct ftgmac100 *priv)
384{
385 return &priv->descs->rxdes[priv->rx_pointer];
386}
387
388static struct ftgmac100_rxdes *
389ftgmac100_rx_locate_first_segment(struct ftgmac100 *priv)
390{
391 struct ftgmac100_rxdes *rxdes = ftgmac100_current_rxdes(priv);
392
393 while (ftgmac100_rxdes_packet_ready(rxdes)) {
394 if (ftgmac100_rxdes_first_segment(rxdes))
395 return rxdes;
396
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930397 ftgmac100_rxdes_set_dma_own(priv, rxdes);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000398 ftgmac100_rx_pointer_advance(priv);
399 rxdes = ftgmac100_current_rxdes(priv);
400 }
401
402 return NULL;
403}
404
405static bool ftgmac100_rx_packet_error(struct ftgmac100 *priv,
406 struct ftgmac100_rxdes *rxdes)
407{
408 struct net_device *netdev = priv->netdev;
409 bool error = false;
410
411 if (unlikely(ftgmac100_rxdes_rx_error(rxdes))) {
412 if (net_ratelimit())
413 netdev_info(netdev, "rx err\n");
414
415 netdev->stats.rx_errors++;
416 error = true;
417 }
418
419 if (unlikely(ftgmac100_rxdes_crc_error(rxdes))) {
420 if (net_ratelimit())
421 netdev_info(netdev, "rx crc err\n");
422
423 netdev->stats.rx_crc_errors++;
424 error = true;
425 } else if (unlikely(ftgmac100_rxdes_ipcs_err(rxdes))) {
426 if (net_ratelimit())
427 netdev_info(netdev, "rx IP checksum err\n");
428
429 error = true;
430 }
431
432 if (unlikely(ftgmac100_rxdes_frame_too_long(rxdes))) {
433 if (net_ratelimit())
434 netdev_info(netdev, "rx frame too long\n");
435
436 netdev->stats.rx_length_errors++;
437 error = true;
438 } else if (unlikely(ftgmac100_rxdes_runt(rxdes))) {
439 if (net_ratelimit())
440 netdev_info(netdev, "rx runt\n");
441
442 netdev->stats.rx_length_errors++;
443 error = true;
444 } else if (unlikely(ftgmac100_rxdes_odd_nibble(rxdes))) {
445 if (net_ratelimit())
446 netdev_info(netdev, "rx odd nibble\n");
447
448 netdev->stats.rx_length_errors++;
449 error = true;
450 }
451
452 return error;
453}
454
455static void ftgmac100_rx_drop_packet(struct ftgmac100 *priv)
456{
457 struct net_device *netdev = priv->netdev;
458 struct ftgmac100_rxdes *rxdes = ftgmac100_current_rxdes(priv);
459 bool done = false;
460
461 if (net_ratelimit())
462 netdev_dbg(netdev, "drop packet %p\n", rxdes);
463
464 do {
465 if (ftgmac100_rxdes_last_segment(rxdes))
466 done = true;
467
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930468 ftgmac100_rxdes_set_dma_own(priv, rxdes);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000469 ftgmac100_rx_pointer_advance(priv);
470 rxdes = ftgmac100_current_rxdes(priv);
471 } while (!done && ftgmac100_rxdes_packet_ready(rxdes));
472
473 netdev->stats.rx_dropped++;
474}
475
476static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
477{
478 struct net_device *netdev = priv->netdev;
479 struct ftgmac100_rxdes *rxdes;
480 struct sk_buff *skb;
481 bool done = false;
482
483 rxdes = ftgmac100_rx_locate_first_segment(priv);
484 if (!rxdes)
485 return false;
486
487 if (unlikely(ftgmac100_rx_packet_error(priv, rxdes))) {
488 ftgmac100_rx_drop_packet(priv);
489 return true;
490 }
491
492 /* start processing */
493 skb = netdev_alloc_skb_ip_align(netdev, 128);
494 if (unlikely(!skb)) {
495 if (net_ratelimit())
496 netdev_err(netdev, "rx skb alloc failed\n");
497
498 ftgmac100_rx_drop_packet(priv);
499 return true;
500 }
501
502 if (unlikely(ftgmac100_rxdes_multicast(rxdes)))
503 netdev->stats.multicast++;
504
505 /*
506 * It seems that HW does checksum incorrectly with fragmented packets,
507 * so we are conservative here - if HW checksum error, let software do
508 * the checksum again.
509 */
510 if ((ftgmac100_rxdes_is_tcp(rxdes) && !ftgmac100_rxdes_tcpcs_err(rxdes)) ||
511 (ftgmac100_rxdes_is_udp(rxdes) && !ftgmac100_rxdes_udpcs_err(rxdes)))
512 skb->ip_summed = CHECKSUM_UNNECESSARY;
513
514 do {
515 dma_addr_t map = ftgmac100_rxdes_get_dma_addr(rxdes);
Andrew Jefferyada66b52016-09-22 08:34:58 +0930516 struct page *page = ftgmac100_rxdes_get_page(priv, rxdes);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000517 unsigned int size;
518
519 dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
520
521 size = ftgmac100_rxdes_data_length(rxdes);
522 skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page, 0, size);
523
524 skb->len += size;
525 skb->data_len += size;
Eric Dumazet5935f812011-10-13 11:30:52 +0000526 skb->truesize += PAGE_SIZE;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000527
528 if (ftgmac100_rxdes_last_segment(rxdes))
529 done = true;
530
531 ftgmac100_alloc_rx_page(priv, rxdes, GFP_ATOMIC);
532
533 ftgmac100_rx_pointer_advance(priv);
534 rxdes = ftgmac100_current_rxdes(priv);
535 } while (!done);
536
Eric Dumazet6ecd09d2012-07-12 04:19:38 +0000537 /* Small frames are copied into linear part of skb to free one page */
538 if (skb->len <= 128) {
Eric Dumazet5935f812011-10-13 11:30:52 +0000539 skb->truesize -= PAGE_SIZE;
Eric Dumazet6ecd09d2012-07-12 04:19:38 +0000540 __pskb_pull_tail(skb, skb->len);
541 } else {
542 /* We pull the minimum amount into linear part */
543 __pskb_pull_tail(skb, ETH_HLEN);
544 }
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000545 skb->protocol = eth_type_trans(skb, netdev);
546
547 netdev->stats.rx_packets++;
548 netdev->stats.rx_bytes += skb->len;
549
550 /* push packet to protocol stack */
551 napi_gro_receive(&priv->napi, skb);
552
553 (*processed)++;
554 return true;
555}
556
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930557static void ftgmac100_txdes_reset(const struct ftgmac100 *priv,
558 struct ftgmac100_txdes *txdes)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000559{
560 /* clear all except end of ring bit */
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930561 txdes->txdes0 &= cpu_to_le32(priv->txdes0_edotr_mask);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000562 txdes->txdes1 = 0;
563 txdes->txdes2 = 0;
564 txdes->txdes3 = 0;
565}
566
567static bool ftgmac100_txdes_owned_by_dma(struct ftgmac100_txdes *txdes)
568{
569 return txdes->txdes0 & cpu_to_le32(FTGMAC100_TXDES0_TXDMA_OWN);
570}
571
572static void ftgmac100_txdes_set_dma_own(struct ftgmac100_txdes *txdes)
573{
574 /*
575 * Make sure dma own bit will not be set before any other
576 * descriptor fields.
577 */
578 wmb();
579 txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_TXDMA_OWN);
580}
581
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930582static void ftgmac100_txdes_set_end_of_ring(const struct ftgmac100 *priv,
583 struct ftgmac100_txdes *txdes)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000584{
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930585 txdes->txdes0 |= cpu_to_le32(priv->txdes0_edotr_mask);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000586}
587
588static void ftgmac100_txdes_set_first_segment(struct ftgmac100_txdes *txdes)
589{
590 txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_FTS);
591}
592
593static void ftgmac100_txdes_set_last_segment(struct ftgmac100_txdes *txdes)
594{
595 txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_LTS);
596}
597
598static void ftgmac100_txdes_set_buffer_size(struct ftgmac100_txdes *txdes,
599 unsigned int len)
600{
601 txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_TXBUF_SIZE(len));
602}
603
604static void ftgmac100_txdes_set_txint(struct ftgmac100_txdes *txdes)
605{
606 txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_TXIC);
607}
608
609static void ftgmac100_txdes_set_tcpcs(struct ftgmac100_txdes *txdes)
610{
611 txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_TCP_CHKSUM);
612}
613
614static void ftgmac100_txdes_set_udpcs(struct ftgmac100_txdes *txdes)
615{
616 txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_UDP_CHKSUM);
617}
618
619static void ftgmac100_txdes_set_ipcs(struct ftgmac100_txdes *txdes)
620{
621 txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_IP_CHKSUM);
622}
623
624static void ftgmac100_txdes_set_dma_addr(struct ftgmac100_txdes *txdes,
625 dma_addr_t addr)
626{
627 txdes->txdes3 = cpu_to_le32(addr);
628}
629
630static dma_addr_t ftgmac100_txdes_get_dma_addr(struct ftgmac100_txdes *txdes)
631{
632 return le32_to_cpu(txdes->txdes3);
633}
634
635/*
636 * txdes2 is not used by hardware. We use it to keep track of socket buffer.
637 * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu().
638 */
639static void ftgmac100_txdes_set_skb(struct ftgmac100_txdes *txdes,
640 struct sk_buff *skb)
641{
642 txdes->txdes2 = (unsigned int)skb;
643}
644
645static struct sk_buff *ftgmac100_txdes_get_skb(struct ftgmac100_txdes *txdes)
646{
647 return (struct sk_buff *)txdes->txdes2;
648}
649
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000650static int ftgmac100_next_tx_pointer(int pointer)
651{
652 return (pointer + 1) & (TX_QUEUE_ENTRIES - 1);
653}
654
655static void ftgmac100_tx_pointer_advance(struct ftgmac100 *priv)
656{
657 priv->tx_pointer = ftgmac100_next_tx_pointer(priv->tx_pointer);
658}
659
660static void ftgmac100_tx_clean_pointer_advance(struct ftgmac100 *priv)
661{
662 priv->tx_clean_pointer = ftgmac100_next_tx_pointer(priv->tx_clean_pointer);
663}
664
665static struct ftgmac100_txdes *ftgmac100_current_txdes(struct ftgmac100 *priv)
666{
667 return &priv->descs->txdes[priv->tx_pointer];
668}
669
670static struct ftgmac100_txdes *
671ftgmac100_current_clean_txdes(struct ftgmac100 *priv)
672{
673 return &priv->descs->txdes[priv->tx_clean_pointer];
674}
675
676static bool ftgmac100_tx_complete_packet(struct ftgmac100 *priv)
677{
678 struct net_device *netdev = priv->netdev;
679 struct ftgmac100_txdes *txdes;
680 struct sk_buff *skb;
681 dma_addr_t map;
682
683 if (priv->tx_pending == 0)
684 return false;
685
686 txdes = ftgmac100_current_clean_txdes(priv);
687
688 if (ftgmac100_txdes_owned_by_dma(txdes))
689 return false;
690
691 skb = ftgmac100_txdes_get_skb(txdes);
692 map = ftgmac100_txdes_get_dma_addr(txdes);
693
694 netdev->stats.tx_packets++;
695 netdev->stats.tx_bytes += skb->len;
696
697 dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
698
699 dev_kfree_skb(skb);
700
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930701 ftgmac100_txdes_reset(priv, txdes);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000702
703 ftgmac100_tx_clean_pointer_advance(priv);
704
705 spin_lock(&priv->tx_lock);
706 priv->tx_pending--;
707 spin_unlock(&priv->tx_lock);
708 netif_wake_queue(netdev);
709
710 return true;
711}
712
713static void ftgmac100_tx_complete(struct ftgmac100 *priv)
714{
715 while (ftgmac100_tx_complete_packet(priv))
716 ;
717}
718
719static int ftgmac100_xmit(struct ftgmac100 *priv, struct sk_buff *skb,
720 dma_addr_t map)
721{
722 struct net_device *netdev = priv->netdev;
723 struct ftgmac100_txdes *txdes;
724 unsigned int len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
725
726 txdes = ftgmac100_current_txdes(priv);
727 ftgmac100_tx_pointer_advance(priv);
728
729 /* setup TX descriptor */
730 ftgmac100_txdes_set_skb(txdes, skb);
731 ftgmac100_txdes_set_dma_addr(txdes, map);
732 ftgmac100_txdes_set_buffer_size(txdes, len);
733
734 ftgmac100_txdes_set_first_segment(txdes);
735 ftgmac100_txdes_set_last_segment(txdes);
736 ftgmac100_txdes_set_txint(txdes);
737 if (skb->ip_summed == CHECKSUM_PARTIAL) {
738 __be16 protocol = skb->protocol;
739
740 if (protocol == cpu_to_be16(ETH_P_IP)) {
741 u8 ip_proto = ip_hdr(skb)->protocol;
742
743 ftgmac100_txdes_set_ipcs(txdes);
744 if (ip_proto == IPPROTO_TCP)
745 ftgmac100_txdes_set_tcpcs(txdes);
746 else if (ip_proto == IPPROTO_UDP)
747 ftgmac100_txdes_set_udpcs(txdes);
748 }
749 }
750
751 spin_lock(&priv->tx_lock);
752 priv->tx_pending++;
753 if (priv->tx_pending == TX_QUEUE_ENTRIES)
754 netif_stop_queue(netdev);
755
756 /* start transmit */
757 ftgmac100_txdes_set_dma_own(txdes);
758 spin_unlock(&priv->tx_lock);
759
760 ftgmac100_txdma_normal_prio_start_polling(priv);
761
762 return NETDEV_TX_OK;
763}
764
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000765static int ftgmac100_alloc_rx_page(struct ftgmac100 *priv,
766 struct ftgmac100_rxdes *rxdes, gfp_t gfp)
767{
768 struct net_device *netdev = priv->netdev;
769 struct page *page;
770 dma_addr_t map;
771
772 page = alloc_page(gfp);
773 if (!page) {
774 if (net_ratelimit())
775 netdev_err(netdev, "failed to allocate rx page\n");
776 return -ENOMEM;
777 }
778
779 map = dma_map_page(priv->dev, page, 0, RX_BUF_SIZE, DMA_FROM_DEVICE);
780 if (unlikely(dma_mapping_error(priv->dev, map))) {
781 if (net_ratelimit())
782 netdev_err(netdev, "failed to map rx page\n");
783 __free_page(page);
784 return -ENOMEM;
785 }
786
Andrew Jefferyada66b52016-09-22 08:34:58 +0930787 ftgmac100_rxdes_set_page(priv, rxdes, page);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000788 ftgmac100_rxdes_set_dma_addr(rxdes, map);
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930789 ftgmac100_rxdes_set_dma_own(priv, rxdes);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000790 return 0;
791}
792
793static void ftgmac100_free_buffers(struct ftgmac100 *priv)
794{
795 int i;
796
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000797 /* Free all RX buffers */
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000798 for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
799 struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[i];
Andrew Jefferyada66b52016-09-22 08:34:58 +0930800 struct page *page = ftgmac100_rxdes_get_page(priv, rxdes);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000801 dma_addr_t map = ftgmac100_rxdes_get_dma_addr(rxdes);
802
803 if (!page)
804 continue;
805
806 dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
807 __free_page(page);
808 }
809
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000810 /* Free all TX buffers */
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000811 for (i = 0; i < TX_QUEUE_ENTRIES; i++) {
812 struct ftgmac100_txdes *txdes = &priv->descs->txdes[i];
813 struct sk_buff *skb = ftgmac100_txdes_get_skb(txdes);
814 dma_addr_t map = ftgmac100_txdes_get_dma_addr(txdes);
815
816 if (!skb)
817 continue;
818
819 dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
Eric Dumazet0113e342014-01-16 23:38:24 -0800820 kfree_skb(skb);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000821 }
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000822}
823
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000824static void ftgmac100_free_rings(struct ftgmac100 *priv)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000825{
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000826 /* Free descriptors */
827 if (priv->descs)
828 dma_free_coherent(priv->dev, sizeof(struct ftgmac100_descs),
829 priv->descs, priv->descs_dma_addr);
830}
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000831
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000832static int ftgmac100_alloc_rings(struct ftgmac100 *priv)
833{
834 /* Allocate descriptors */
Joe Perchesede23fa82013-08-26 22:45:23 -0700835 priv->descs = dma_zalloc_coherent(priv->dev,
836 sizeof(struct ftgmac100_descs),
837 &priv->descs_dma_addr, GFP_KERNEL);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000838 if (!priv->descs)
839 return -ENOMEM;
840
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000841 return 0;
842}
843
844static void ftgmac100_init_rings(struct ftgmac100 *priv)
845{
846 int i;
847
848 /* Initialize RX ring */
849 for (i = 0; i < RX_QUEUE_ENTRIES; i++)
850 priv->descs->rxdes[i].rxdes0 = 0;
851 ftgmac100_rxdes_set_end_of_ring(priv, &priv->descs->rxdes[i - 1]);
852
853 /* Initialize TX ring */
854 for (i = 0; i < TX_QUEUE_ENTRIES; i++)
855 priv->descs->txdes[i].txdes0 = 0;
856 ftgmac100_txdes_set_end_of_ring(priv, &priv->descs->txdes[i -1]);
857}
858
859static int ftgmac100_alloc_rx_buffers(struct ftgmac100 *priv)
860{
861 int i;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000862
863 for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
864 struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[i];
865
866 if (ftgmac100_alloc_rx_page(priv, rxdes, GFP_KERNEL))
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000867 return -ENOMEM;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000868 }
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000869 return 0;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000870}
871
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000872static void ftgmac100_adjust_link(struct net_device *netdev)
873{
874 struct ftgmac100 *priv = netdev_priv(netdev);
Philippe Reynesb3c40ad2016-05-16 01:35:13 +0200875 struct phy_device *phydev = netdev->phydev;
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +1000876 int new_speed;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000877 int ier;
878
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +1000879 /* We store "no link" as speed 0 */
880 if (!phydev->link)
881 new_speed = 0;
882 else
883 new_speed = phydev->speed;
884
885 if (phydev->speed == priv->cur_speed &&
886 phydev->duplex == priv->cur_duplex)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000887 return;
888
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +1000889 /* Print status if we have a link or we had one and just lost it,
890 * don't print otherwise.
891 */
892 if (new_speed || priv->cur_speed)
893 phy_print_status(phydev);
894
895 priv->cur_speed = new_speed;
896 priv->cur_duplex = phydev->duplex;
897
898 /* Link is down, do nothing else */
899 if (!new_speed)
900 return;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000901
902 ier = ioread32(priv->base + FTGMAC100_OFFSET_IER);
903
904 /* disable all interrupts */
905 iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
906
907 netif_stop_queue(netdev);
908 ftgmac100_stop_hw(priv);
909
910 netif_start_queue(netdev);
911 ftgmac100_init_hw(priv);
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +1000912 ftgmac100_start_hw(priv);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000913
914 /* re-enable interrupts */
915 iowrite32(ier, priv->base + FTGMAC100_OFFSET_IER);
916}
917
918static int ftgmac100_mii_probe(struct ftgmac100 *priv)
919{
920 struct net_device *netdev = priv->netdev;
Guenter Roecke574f392016-01-10 12:04:32 -0800921 struct phy_device *phydev;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000922
Guenter Roecke574f392016-01-10 12:04:32 -0800923 phydev = phy_find_first(priv->mii_bus);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000924 if (!phydev) {
925 netdev_info(netdev, "%s: no PHY found\n", netdev->name);
926 return -ENODEV;
927 }
928
Andrew Lunn84eff6d2016-01-06 20:11:10 +0100929 phydev = phy_connect(netdev, phydev_name(phydev),
Florian Fainellif9a8f832013-01-14 00:52:52 +0000930 &ftgmac100_adjust_link, PHY_INTERFACE_MODE_GMII);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000931
932 if (IS_ERR(phydev)) {
933 netdev_err(netdev, "%s: Could not attach to PHY\n", netdev->name);
934 return PTR_ERR(phydev);
935 }
936
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000937 return 0;
938}
939
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000940static int ftgmac100_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
941{
942 struct net_device *netdev = bus->priv;
943 struct ftgmac100 *priv = netdev_priv(netdev);
944 unsigned int phycr;
945 int i;
946
947 phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
948
949 /* preserve MDC cycle threshold */
950 phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
951
952 phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr) |
953 FTGMAC100_PHYCR_REGAD(regnum) |
954 FTGMAC100_PHYCR_MIIRD;
955
956 iowrite32(phycr, priv->base + FTGMAC100_OFFSET_PHYCR);
957
958 for (i = 0; i < 10; i++) {
959 phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
960
961 if ((phycr & FTGMAC100_PHYCR_MIIRD) == 0) {
962 int data;
963
964 data = ioread32(priv->base + FTGMAC100_OFFSET_PHYDATA);
965 return FTGMAC100_PHYDATA_MIIRDATA(data);
966 }
967
968 udelay(100);
969 }
970
971 netdev_err(netdev, "mdio read timed out\n");
972 return -EIO;
973}
974
975static int ftgmac100_mdiobus_write(struct mii_bus *bus, int phy_addr,
976 int regnum, u16 value)
977{
978 struct net_device *netdev = bus->priv;
979 struct ftgmac100 *priv = netdev_priv(netdev);
980 unsigned int phycr;
981 int data;
982 int i;
983
984 phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
985
986 /* preserve MDC cycle threshold */
987 phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
988
989 phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr) |
990 FTGMAC100_PHYCR_REGAD(regnum) |
991 FTGMAC100_PHYCR_MIIWR;
992
993 data = FTGMAC100_PHYDATA_MIIWDATA(value);
994
995 iowrite32(data, priv->base + FTGMAC100_OFFSET_PHYDATA);
996 iowrite32(phycr, priv->base + FTGMAC100_OFFSET_PHYCR);
997
998 for (i = 0; i < 10; i++) {
999 phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
1000
1001 if ((phycr & FTGMAC100_PHYCR_MIIWR) == 0)
1002 return 0;
1003
1004 udelay(100);
1005 }
1006
1007 netdev_err(netdev, "mdio write timed out\n");
1008 return -EIO;
1009}
1010
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001011static void ftgmac100_get_drvinfo(struct net_device *netdev,
1012 struct ethtool_drvinfo *info)
1013{
Jiri Pirko7826d432013-01-06 00:44:26 +00001014 strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
1015 strlcpy(info->version, DRV_VERSION, sizeof(info->version));
1016 strlcpy(info->bus_info, dev_name(&netdev->dev), sizeof(info->bus_info));
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001017}
1018
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001019static const struct ethtool_ops ftgmac100_ethtool_ops = {
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001020 .get_drvinfo = ftgmac100_get_drvinfo,
1021 .get_link = ethtool_op_get_link,
Philippe Reynesfd24d722016-05-16 01:35:14 +02001022 .get_link_ksettings = phy_ethtool_get_link_ksettings,
1023 .set_link_ksettings = phy_ethtool_set_link_ksettings,
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001024};
1025
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001026static irqreturn_t ftgmac100_interrupt(int irq, void *dev_id)
1027{
1028 struct net_device *netdev = dev_id;
1029 struct ftgmac100 *priv = netdev_priv(netdev);
1030
Gavin Shanbd466c32016-07-19 11:54:23 +10001031 /* When running in NCSI mode, the interface should be ready for
1032 * receiving or transmitting NCSI packets before it's opened.
1033 */
1034 if (likely(priv->use_ncsi || netif_running(netdev))) {
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001035 /* Disable interrupts for polling */
1036 iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
1037 napi_schedule(&priv->napi);
1038 }
1039
1040 return IRQ_HANDLED;
1041}
1042
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001043static int ftgmac100_poll(struct napi_struct *napi, int budget)
1044{
1045 struct ftgmac100 *priv = container_of(napi, struct ftgmac100, napi);
1046 struct net_device *netdev = priv->netdev;
1047 unsigned int status;
1048 bool completed = true;
1049 int rx = 0;
1050
1051 status = ioread32(priv->base + FTGMAC100_OFFSET_ISR);
1052 iowrite32(status, priv->base + FTGMAC100_OFFSET_ISR);
1053
1054 if (status & (FTGMAC100_INT_RPKT_BUF | FTGMAC100_INT_NO_RXBUF)) {
1055 /*
1056 * FTGMAC100_INT_RPKT_BUF:
1057 * RX DMA has received packets into RX buffer successfully
1058 *
1059 * FTGMAC100_INT_NO_RXBUF:
1060 * RX buffer unavailable
1061 */
1062 bool retry;
1063
1064 do {
1065 retry = ftgmac100_rx_packet(priv, &rx);
1066 } while (retry && rx < budget);
1067
1068 if (retry && rx == budget)
1069 completed = false;
1070 }
1071
1072 if (status & (FTGMAC100_INT_XPKT_ETH | FTGMAC100_INT_XPKT_LOST)) {
1073 /*
1074 * FTGMAC100_INT_XPKT_ETH:
1075 * packet transmitted to ethernet successfully
1076 *
1077 * FTGMAC100_INT_XPKT_LOST:
1078 * packet transmitted to ethernet lost due to late
1079 * collision or excessive collision
1080 */
1081 ftgmac100_tx_complete(priv);
1082 }
1083
Gavin Shanfc6061c2016-07-19 11:54:25 +10001084 if (status & priv->int_mask_all & (FTGMAC100_INT_NO_RXBUF |
Joel Stanleyedcd6922016-09-22 08:35:03 +09301085 FTGMAC100_INT_RPKT_LOST | FTGMAC100_INT_AHB_ERR)) {
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001086 if (net_ratelimit())
Joel Stanleyedcd6922016-09-22 08:35:03 +09301087 netdev_info(netdev, "[ISR] = 0x%x: %s%s%s\n", status,
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001088 status & FTGMAC100_INT_NO_RXBUF ? "NO_RXBUF " : "",
1089 status & FTGMAC100_INT_RPKT_LOST ? "RPKT_LOST " : "",
Joel Stanleyedcd6922016-09-22 08:35:03 +09301090 status & FTGMAC100_INT_AHB_ERR ? "AHB_ERR " : "");
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001091
1092 if (status & FTGMAC100_INT_NO_RXBUF) {
1093 /* RX buffer unavailable */
1094 netdev->stats.rx_over_errors++;
1095 }
1096
1097 if (status & FTGMAC100_INT_RPKT_LOST) {
1098 /* received packet lost due to RX FIFO full */
1099 netdev->stats.rx_fifo_errors++;
1100 }
1101 }
1102
1103 if (completed) {
1104 napi_complete(napi);
1105
1106 /* enable all interrupts */
Gavin Shanfc6061c2016-07-19 11:54:25 +10001107 iowrite32(priv->int_mask_all,
1108 priv->base + FTGMAC100_OFFSET_IER);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001109 }
1110
1111 return rx;
1112}
1113
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001114static int ftgmac100_init_all(struct ftgmac100 *priv, bool ignore_alloc_err)
1115{
1116 int err = 0;
1117
1118 /* Re-init descriptors (adjust queue sizes) */
1119 ftgmac100_init_rings(priv);
1120
1121 /* Realloc rx descriptors */
1122 err = ftgmac100_alloc_rx_buffers(priv);
1123 if (err && !ignore_alloc_err)
1124 return err;
1125
1126 /* Reinit and restart HW */
1127 ftgmac100_init_hw(priv);
1128 ftgmac100_start_hw(priv);
1129
1130 /* Re-enable the device */
1131 napi_enable(&priv->napi);
1132 netif_start_queue(priv->netdev);
1133
1134 /* Enable all interrupts */
1135 iowrite32(priv->int_mask_all, priv->base + FTGMAC100_OFFSET_IER);
1136
1137 return err;
1138}
1139
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001140static int ftgmac100_open(struct net_device *netdev)
1141{
1142 struct ftgmac100 *priv = netdev_priv(netdev);
1143 int err;
1144
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +10001145 /* Allocate ring buffers */
1146 err = ftgmac100_alloc_rings(priv);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001147 if (err) {
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +10001148 netdev_err(netdev, "Failed to allocate descriptors\n");
1149 return err;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001150 }
1151
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +10001152 /* When using NC-SI we force the speed to 100Mbit/s full duplex,
1153 *
1154 * Otherwise we leave it set to 0 (no link), the link
1155 * message from the PHY layer will handle setting it up to
1156 * something else if needed.
1157 */
1158 if (priv->use_ncsi) {
1159 priv->cur_duplex = DUPLEX_FULL;
1160 priv->cur_speed = SPEED_100;
1161 } else {
1162 priv->cur_duplex = 0;
1163 priv->cur_speed = 0;
1164 }
1165
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001166 priv->rx_pointer = 0;
1167 priv->tx_clean_pointer = 0;
1168 priv->tx_pointer = 0;
1169 priv->tx_pending = 0;
1170
1171 err = ftgmac100_reset_hw(priv);
1172 if (err)
1173 goto err_hw;
1174
Benjamin Herrenschmidtb8dbecf2017-04-05 12:28:47 +10001175 /* Initialize NAPI */
1176 netif_napi_add(netdev, &priv->napi, ftgmac100_poll, 64);
1177
Benjamin Herrenschmidt81f1eca2017-04-05 12:28:48 +10001178 /* Grab our interrupt */
1179 err = request_irq(netdev->irq, ftgmac100_interrupt, 0, netdev->name, netdev);
1180 if (err) {
1181 netdev_err(netdev, "failed to request irq %d\n", netdev->irq);
1182 goto err_irq;
1183 }
1184
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001185 /* Start things up */
1186 err = ftgmac100_init_all(priv, false);
1187 if (err) {
1188 netdev_err(netdev, "Failed to allocate packet buffers\n");
1189 goto err_alloc;
1190 }
Gavin Shan08c9c122016-09-22 08:35:01 +09301191
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001192 if (netdev->phydev) {
1193 /* If we have a PHY, start polling */
Gavin Shanbd466c32016-07-19 11:54:23 +10001194 phy_start(netdev->phydev);
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001195 } else if (priv->use_ncsi) {
1196 /* If using NC-SI, set our carrier on and start the stack */
Gavin Shanbd466c32016-07-19 11:54:23 +10001197 netif_carrier_on(netdev);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001198
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001199 /* Start the NCSI device */
Gavin Shanbd466c32016-07-19 11:54:23 +10001200 err = ncsi_start_dev(priv->ndev);
1201 if (err)
1202 goto err_ncsi;
1203 }
1204
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001205 return 0;
1206
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001207 err_ncsi:
Gavin Shanbd466c32016-07-19 11:54:23 +10001208 napi_disable(&priv->napi);
1209 netif_stop_queue(netdev);
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001210 err_alloc:
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +10001211 ftgmac100_free_buffers(priv);
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001212 free_irq(netdev->irq, netdev);
1213 err_irq:
1214 netif_napi_del(&priv->napi);
1215 err_hw:
1216 iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +10001217 ftgmac100_free_rings(priv);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001218 return err;
1219}
1220
1221static int ftgmac100_stop(struct net_device *netdev)
1222{
1223 struct ftgmac100 *priv = netdev_priv(netdev);
1224
1225 /* disable all interrupts */
1226 iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
1227
1228 netif_stop_queue(netdev);
1229 napi_disable(&priv->napi);
Benjamin Herrenschmidtb8dbecf2017-04-05 12:28:47 +10001230 netif_napi_del(&priv->napi);
Gavin Shanbd466c32016-07-19 11:54:23 +10001231 if (netdev->phydev)
1232 phy_stop(netdev->phydev);
Gavin Shan2c15f252016-10-04 11:25:54 +11001233 else if (priv->use_ncsi)
1234 ncsi_stop_dev(priv->ndev);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001235
1236 ftgmac100_stop_hw(priv);
Benjamin Herrenschmidt60b28a12017-04-05 12:28:41 +10001237 free_irq(netdev->irq, netdev);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001238 ftgmac100_free_buffers(priv);
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +10001239 ftgmac100_free_rings(priv);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001240
1241 return 0;
1242}
1243
1244static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
1245 struct net_device *netdev)
1246{
1247 struct ftgmac100 *priv = netdev_priv(netdev);
1248 dma_addr_t map;
1249
1250 if (unlikely(skb->len > MAX_PKT_SIZE)) {
1251 if (net_ratelimit())
1252 netdev_dbg(netdev, "tx packet too big\n");
1253
1254 netdev->stats.tx_dropped++;
Eric Dumazet0113e342014-01-16 23:38:24 -08001255 kfree_skb(skb);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001256 return NETDEV_TX_OK;
1257 }
1258
1259 map = dma_map_single(priv->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
1260 if (unlikely(dma_mapping_error(priv->dev, map))) {
1261 /* drop packet */
1262 if (net_ratelimit())
1263 netdev_err(netdev, "map socket buffer failed\n");
1264
1265 netdev->stats.tx_dropped++;
Eric Dumazet0113e342014-01-16 23:38:24 -08001266 kfree_skb(skb);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001267 return NETDEV_TX_OK;
1268 }
1269
1270 return ftgmac100_xmit(priv, skb, map);
1271}
1272
1273/* optional */
1274static int ftgmac100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
1275{
Gavin Shanbd466c32016-07-19 11:54:23 +10001276 if (!netdev->phydev)
1277 return -ENXIO;
1278
Philippe Reynesb3c40ad2016-05-16 01:35:13 +02001279 return phy_mii_ioctl(netdev->phydev, ifr, cmd);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001280}
1281
1282static const struct net_device_ops ftgmac100_netdev_ops = {
1283 .ndo_open = ftgmac100_open,
1284 .ndo_stop = ftgmac100_stop,
1285 .ndo_start_xmit = ftgmac100_hard_start_xmit,
Gavin Shan113ce102016-07-19 11:54:22 +10001286 .ndo_set_mac_address = ftgmac100_set_mac_addr,
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001287 .ndo_validate_addr = eth_validate_addr,
1288 .ndo_do_ioctl = ftgmac100_do_ioctl,
1289};
1290
Gavin Shaneb418182016-07-19 11:54:21 +10001291static int ftgmac100_setup_mdio(struct net_device *netdev)
1292{
1293 struct ftgmac100 *priv = netdev_priv(netdev);
1294 struct platform_device *pdev = to_platform_device(priv->dev);
1295 int i, err = 0;
Joel Stanleye07dc632016-09-22 08:35:02 +09301296 u32 reg;
Gavin Shaneb418182016-07-19 11:54:21 +10001297
1298 /* initialize mdio bus */
1299 priv->mii_bus = mdiobus_alloc();
1300 if (!priv->mii_bus)
1301 return -EIO;
1302
Joel Stanleye07dc632016-09-22 08:35:02 +09301303 if (of_machine_is_compatible("aspeed,ast2400") ||
1304 of_machine_is_compatible("aspeed,ast2500")) {
1305 /* This driver supports the old MDIO interface */
1306 reg = ioread32(priv->base + FTGMAC100_OFFSET_REVR);
1307 reg &= ~FTGMAC100_REVR_NEW_MDIO_INTERFACE;
1308 iowrite32(reg, priv->base + FTGMAC100_OFFSET_REVR);
1309 };
1310
Gavin Shaneb418182016-07-19 11:54:21 +10001311 priv->mii_bus->name = "ftgmac100_mdio";
1312 snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%d",
1313 pdev->name, pdev->id);
1314 priv->mii_bus->priv = priv->netdev;
1315 priv->mii_bus->read = ftgmac100_mdiobus_read;
1316 priv->mii_bus->write = ftgmac100_mdiobus_write;
1317
1318 for (i = 0; i < PHY_MAX_ADDR; i++)
1319 priv->mii_bus->irq[i] = PHY_POLL;
1320
1321 err = mdiobus_register(priv->mii_bus);
1322 if (err) {
1323 dev_err(priv->dev, "Cannot register MDIO bus!\n");
1324 goto err_register_mdiobus;
1325 }
1326
1327 err = ftgmac100_mii_probe(priv);
1328 if (err) {
1329 dev_err(priv->dev, "MII Probe failed!\n");
1330 goto err_mii_probe;
1331 }
1332
1333 return 0;
1334
1335err_mii_probe:
1336 mdiobus_unregister(priv->mii_bus);
1337err_register_mdiobus:
1338 mdiobus_free(priv->mii_bus);
1339 return err;
1340}
1341
1342static void ftgmac100_destroy_mdio(struct net_device *netdev)
1343{
1344 struct ftgmac100 *priv = netdev_priv(netdev);
1345
1346 if (!netdev->phydev)
1347 return;
1348
1349 phy_disconnect(netdev->phydev);
1350 mdiobus_unregister(priv->mii_bus);
1351 mdiobus_free(priv->mii_bus);
1352}
1353
Gavin Shanbd466c32016-07-19 11:54:23 +10001354static void ftgmac100_ncsi_handler(struct ncsi_dev *nd)
1355{
1356 if (unlikely(nd->state != ncsi_dev_state_functional))
1357 return;
1358
1359 netdev_info(nd->dev, "NCSI interface %s\n",
1360 nd->link_up ? "up" : "down");
1361}
1362
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001363static int ftgmac100_probe(struct platform_device *pdev)
1364{
1365 struct resource *res;
1366 int irq;
1367 struct net_device *netdev;
1368 struct ftgmac100 *priv;
Gavin Shanbd466c32016-07-19 11:54:23 +10001369 int err = 0;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001370
1371 if (!pdev)
1372 return -ENODEV;
1373
1374 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1375 if (!res)
1376 return -ENXIO;
1377
1378 irq = platform_get_irq(pdev, 0);
1379 if (irq < 0)
1380 return irq;
1381
1382 /* setup net_device */
1383 netdev = alloc_etherdev(sizeof(*priv));
1384 if (!netdev) {
1385 err = -ENOMEM;
1386 goto err_alloc_etherdev;
1387 }
1388
1389 SET_NETDEV_DEV(netdev, &pdev->dev);
1390
Wilfried Klaebe7ad24ea2014-05-11 00:12:32 +00001391 netdev->ethtool_ops = &ftgmac100_ethtool_ops;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001392 netdev->netdev_ops = &ftgmac100_netdev_ops;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001393
1394 platform_set_drvdata(pdev, netdev);
1395
1396 /* setup private data */
1397 priv = netdev_priv(netdev);
1398 priv->netdev = netdev;
1399 priv->dev = &pdev->dev;
1400
1401 spin_lock_init(&priv->tx_lock);
1402
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001403 /* map io memory */
1404 priv->res = request_mem_region(res->start, resource_size(res),
1405 dev_name(&pdev->dev));
1406 if (!priv->res) {
1407 dev_err(&pdev->dev, "Could not reserve memory region\n");
1408 err = -ENOMEM;
1409 goto err_req_mem;
1410 }
1411
1412 priv->base = ioremap(res->start, resource_size(res));
1413 if (!priv->base) {
1414 dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
1415 err = -EIO;
1416 goto err_ioremap;
1417 }
1418
Benjamin Herrenschmidt60b28a12017-04-05 12:28:41 +10001419 netdev->irq = irq;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001420
Gavin Shan113ce102016-07-19 11:54:22 +10001421 /* MAC address from chip or random one */
1422 ftgmac100_setup_mac(priv);
1423
Gavin Shanfc6061c2016-07-19 11:54:25 +10001424 priv->int_mask_all = (FTGMAC100_INT_RPKT_LOST |
1425 FTGMAC100_INT_XPKT_ETH |
1426 FTGMAC100_INT_XPKT_LOST |
1427 FTGMAC100_INT_AHB_ERR |
Gavin Shanfc6061c2016-07-19 11:54:25 +10001428 FTGMAC100_INT_RPKT_BUF |
1429 FTGMAC100_INT_NO_RXBUF);
Joel Stanley2a0ab8eb2016-09-22 08:35:00 +09301430
1431 if (of_machine_is_compatible("aspeed,ast2400") ||
1432 of_machine_is_compatible("aspeed,ast2500")) {
1433 priv->rxdes0_edorr_mask = BIT(30);
1434 priv->txdes0_edotr_mask = BIT(30);
1435 } else {
1436 priv->rxdes0_edorr_mask = BIT(15);
1437 priv->txdes0_edotr_mask = BIT(15);
1438 }
1439
Gavin Shanbd466c32016-07-19 11:54:23 +10001440 if (pdev->dev.of_node &&
1441 of_get_property(pdev->dev.of_node, "use-ncsi", NULL)) {
1442 if (!IS_ENABLED(CONFIG_NET_NCSI)) {
1443 dev_err(&pdev->dev, "NCSI stack not enabled\n");
1444 goto err_ncsi_dev;
1445 }
1446
1447 dev_info(&pdev->dev, "Using NCSI interface\n");
1448 priv->use_ncsi = true;
1449 priv->ndev = ncsi_register_dev(netdev, ftgmac100_ncsi_handler);
1450 if (!priv->ndev)
1451 goto err_ncsi_dev;
1452 } else {
1453 priv->use_ncsi = false;
1454 err = ftgmac100_setup_mdio(netdev);
1455 if (err)
1456 goto err_setup_mdio;
1457 }
1458
1459 /* We have to disable on-chip IP checksum functionality
1460 * when NCSI is enabled on the interface. It doesn't work
1461 * in that case.
1462 */
1463 netdev->features = NETIF_F_IP_CSUM | NETIF_F_GRO;
1464 if (priv->use_ncsi &&
1465 of_get_property(pdev->dev.of_node, "no-hw-checksum", NULL))
1466 netdev->features &= ~NETIF_F_IP_CSUM;
1467
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001468
1469 /* register network device */
1470 err = register_netdev(netdev);
1471 if (err) {
1472 dev_err(&pdev->dev, "Failed to register netdev\n");
1473 goto err_register_netdev;
1474 }
1475
Benjamin Herrenschmidt60b28a12017-04-05 12:28:41 +10001476 netdev_info(netdev, "irq %d, mapped at %p\n", netdev->irq, priv->base);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001477
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001478 return 0;
1479
Gavin Shanbd466c32016-07-19 11:54:23 +10001480err_ncsi_dev:
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001481err_register_netdev:
Gavin Shaneb418182016-07-19 11:54:21 +10001482 ftgmac100_destroy_mdio(netdev);
1483err_setup_mdio:
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001484 iounmap(priv->base);
1485err_ioremap:
1486 release_resource(priv->res);
1487err_req_mem:
1488 netif_napi_del(&priv->napi);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001489 free_netdev(netdev);
1490err_alloc_etherdev:
1491 return err;
1492}
1493
Dmitry Torokhovbe125022017-03-01 17:24:47 -08001494static int ftgmac100_remove(struct platform_device *pdev)
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001495{
1496 struct net_device *netdev;
1497 struct ftgmac100 *priv;
1498
1499 netdev = platform_get_drvdata(pdev);
1500 priv = netdev_priv(netdev);
1501
1502 unregister_netdev(netdev);
Gavin Shaneb418182016-07-19 11:54:21 +10001503 ftgmac100_destroy_mdio(netdev);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001504
1505 iounmap(priv->base);
1506 release_resource(priv->res);
1507
1508 netif_napi_del(&priv->napi);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001509 free_netdev(netdev);
1510 return 0;
1511}
1512
Gavin Shanbb168e22016-07-19 11:54:24 +10001513static const struct of_device_id ftgmac100_of_match[] = {
1514 { .compatible = "faraday,ftgmac100" },
1515 { }
1516};
1517MODULE_DEVICE_TABLE(of, ftgmac100_of_match);
1518
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001519static struct platform_driver ftgmac100_driver = {
Gavin Shanbb168e22016-07-19 11:54:24 +10001520 .probe = ftgmac100_probe,
Dmitry Torokhovbe125022017-03-01 17:24:47 -08001521 .remove = ftgmac100_remove,
Gavin Shanbb168e22016-07-19 11:54:24 +10001522 .driver = {
1523 .name = DRV_NAME,
1524 .of_match_table = ftgmac100_of_match,
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001525 },
1526};
Sachin Kamat14f645d2013-03-18 01:50:48 +00001527module_platform_driver(ftgmac100_driver);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001528
1529MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
1530MODULE_DESCRIPTION("FTGMAC100 driver");
1531MODULE_LICENSE("GPL");