blob: 5cd854e740a9c057e819682b330aacd5c706243c [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
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +100046#define MAX_PKT_SIZE 1536
47#define RX_BUF_SIZE MAX_PKT_SIZE /* must be smaller than 0x3fff */
Po-Yu Chuang69785b72011-06-08 23:32:48 +000048
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 */
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +100063 struct sk_buff *rx_skbs[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 Herrenschmidtd72e01a2017-04-06 11:02:45 +100074 /* Scratch page to use when rx skb alloc fails */
75 void *rx_scratch;
76 dma_addr_t rx_scratch_dma;
77
Benjamin Herrenschmidt831fb332017-04-05 12:28:43 +100078 /* Component structures */
Po-Yu Chuang69785b72011-06-08 23:32:48 +000079 struct net_device *netdev;
80 struct device *dev;
Gavin Shanbd466c32016-07-19 11:54:23 +100081 struct ncsi_dev *ndev;
Po-Yu Chuang69785b72011-06-08 23:32:48 +000082 struct napi_struct napi;
Benjamin Herrenschmidt855944c2017-04-05 12:28:50 +100083 struct work_struct reset_task;
Po-Yu Chuang69785b72011-06-08 23:32:48 +000084 struct mii_bus *mii_bus;
Andrew Jeffery7906a4d2016-09-22 08:34:59 +093085
Benjamin Herrenschmidt831fb332017-04-05 12:28:43 +100086 /* Link management */
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +100087 int cur_speed;
88 int cur_duplex;
Benjamin Herrenschmidt831fb332017-04-05 12:28:43 +100089 bool use_ncsi;
90
91 /* Misc */
Benjamin Herrenschmidt10cbd642017-04-05 12:28:53 +100092 bool need_mac_restart;
Po-Yu Chuang69785b72011-06-08 23:32:48 +000093};
94
Po-Yu Chuang69785b72011-06-08 23:32:48 +000095static void ftgmac100_set_rx_ring_base(struct ftgmac100 *priv, dma_addr_t addr)
96{
97 iowrite32(addr, priv->base + FTGMAC100_OFFSET_RXR_BADR);
98}
99
100static void ftgmac100_set_rx_buffer_size(struct ftgmac100 *priv,
101 unsigned int size)
102{
103 size = FTGMAC100_RBSR_SIZE(size);
104 iowrite32(size, priv->base + FTGMAC100_OFFSET_RBSR);
105}
106
107static void ftgmac100_set_normal_prio_tx_ring_base(struct ftgmac100 *priv,
108 dma_addr_t addr)
109{
110 iowrite32(addr, priv->base + FTGMAC100_OFFSET_NPTXR_BADR);
111}
112
113static void ftgmac100_txdma_normal_prio_start_polling(struct ftgmac100 *priv)
114{
115 iowrite32(1, priv->base + FTGMAC100_OFFSET_NPTXPD);
116}
117
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +1000118static int ftgmac100_reset_mac(struct ftgmac100 *priv, u32 maccr)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000119{
120 struct net_device *netdev = priv->netdev;
121 int i;
122
123 /* NOTE: reset clears all registers */
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +1000124 iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR);
125 iowrite32(maccr | FTGMAC100_MACCR_SW_RST,
126 priv->base + FTGMAC100_OFFSET_MACCR);
127 for (i = 0; i < 50; i++) {
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000128 unsigned int maccr;
129
130 maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR);
131 if (!(maccr & FTGMAC100_MACCR_SW_RST))
132 return 0;
133
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +1000134 udelay(1);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000135 }
136
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +1000137 netdev_err(netdev, "Hardware reset failed\n");
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000138 return -EIO;
139}
140
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +1000141static int ftgmac100_reset_and_config_mac(struct ftgmac100 *priv)
142{
143 u32 maccr = 0;
144
145 switch (priv->cur_speed) {
146 case SPEED_10:
147 case 0: /* no link */
148 break;
149
150 case SPEED_100:
151 maccr |= FTGMAC100_MACCR_FAST_MODE;
152 break;
153
154 case SPEED_1000:
155 maccr |= FTGMAC100_MACCR_GIGA_MODE;
156 break;
157 default:
158 netdev_err(priv->netdev, "Unknown speed %d !\n",
159 priv->cur_speed);
160 break;
161 }
162
163 /* (Re)initialize the queue pointers */
164 priv->rx_pointer = 0;
165 priv->tx_clean_pointer = 0;
166 priv->tx_pointer = 0;
167 priv->tx_pending = 0;
168
169 /* The doc says reset twice with 10us interval */
170 if (ftgmac100_reset_mac(priv, maccr))
171 return -EIO;
172 usleep_range(10, 1000);
173 return ftgmac100_reset_mac(priv, maccr);
174}
175
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000176static void ftgmac100_set_mac(struct ftgmac100 *priv, const unsigned char *mac)
177{
178 unsigned int maddr = mac[0] << 8 | mac[1];
179 unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
180
181 iowrite32(maddr, priv->base + FTGMAC100_OFFSET_MAC_MADR);
182 iowrite32(laddr, priv->base + FTGMAC100_OFFSET_MAC_LADR);
183}
184
Gavin Shan113ce102016-07-19 11:54:22 +1000185static void ftgmac100_setup_mac(struct ftgmac100 *priv)
186{
187 u8 mac[ETH_ALEN];
188 unsigned int m;
189 unsigned int l;
190 void *addr;
191
192 addr = device_get_mac_address(priv->dev, mac, ETH_ALEN);
193 if (addr) {
194 ether_addr_copy(priv->netdev->dev_addr, mac);
195 dev_info(priv->dev, "Read MAC address %pM from device tree\n",
196 mac);
197 return;
198 }
199
200 m = ioread32(priv->base + FTGMAC100_OFFSET_MAC_MADR);
201 l = ioread32(priv->base + FTGMAC100_OFFSET_MAC_LADR);
202
203 mac[0] = (m >> 8) & 0xff;
204 mac[1] = m & 0xff;
205 mac[2] = (l >> 24) & 0xff;
206 mac[3] = (l >> 16) & 0xff;
207 mac[4] = (l >> 8) & 0xff;
208 mac[5] = l & 0xff;
209
Gavin Shan113ce102016-07-19 11:54:22 +1000210 if (is_valid_ether_addr(mac)) {
211 ether_addr_copy(priv->netdev->dev_addr, mac);
212 dev_info(priv->dev, "Read MAC address %pM from chip\n", mac);
213 } else {
214 eth_hw_addr_random(priv->netdev);
215 dev_info(priv->dev, "Generated random MAC address %pM\n",
216 priv->netdev->dev_addr);
217 }
218}
219
220static int ftgmac100_set_mac_addr(struct net_device *dev, void *p)
221{
222 int ret;
223
224 ret = eth_prepare_mac_addr_change(dev, p);
225 if (ret < 0)
226 return ret;
227
228 eth_commit_mac_addr_change(dev, p);
229 ftgmac100_set_mac(netdev_priv(dev), dev->dev_addr);
230
231 return 0;
232}
233
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000234static void ftgmac100_init_hw(struct ftgmac100 *priv)
235{
236 /* setup ring buffer base registers */
237 ftgmac100_set_rx_ring_base(priv,
238 priv->descs_dma_addr +
239 offsetof(struct ftgmac100_descs, rxdes));
240 ftgmac100_set_normal_prio_tx_ring_base(priv,
241 priv->descs_dma_addr +
242 offsetof(struct ftgmac100_descs, txdes));
243
244 ftgmac100_set_rx_buffer_size(priv, RX_BUF_SIZE);
245
246 iowrite32(FTGMAC100_APTC_RXPOLL_CNT(1), priv->base + FTGMAC100_OFFSET_APTC);
247
248 ftgmac100_set_mac(priv, priv->netdev->dev_addr);
249}
250
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +1000251static void ftgmac100_start_hw(struct ftgmac100 *priv)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000252{
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +1000253 u32 maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000254
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +1000255 /* Keep the original GMAC and FAST bits */
256 maccr &= (FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_GIGA_MODE);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000257
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +1000258 /* Add all the main enable bits */
259 maccr |= FTGMAC100_MACCR_TXDMA_EN |
260 FTGMAC100_MACCR_RXDMA_EN |
261 FTGMAC100_MACCR_TXMAC_EN |
262 FTGMAC100_MACCR_RXMAC_EN |
263 FTGMAC100_MACCR_CRC_APD |
264 FTGMAC100_MACCR_PHY_LINK_LEVEL |
265 FTGMAC100_MACCR_RX_RUNT |
266 FTGMAC100_MACCR_RX_BROADPKT;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000267
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +1000268 /* Add other bits as needed */
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +1000269 if (priv->cur_duplex == DUPLEX_FULL)
270 maccr |= FTGMAC100_MACCR_FULLDUP;
271
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +1000272 /* Hit the HW */
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000273 iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR);
274}
275
276static void ftgmac100_stop_hw(struct ftgmac100 *priv)
277{
278 iowrite32(0, priv->base + FTGMAC100_OFFSET_MACCR);
279}
280
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000281static bool ftgmac100_rxdes_first_segment(struct ftgmac100_rxdes *rxdes)
282{
283 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_FRS);
284}
285
286static bool ftgmac100_rxdes_last_segment(struct ftgmac100_rxdes *rxdes)
287{
288 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_LRS);
289}
290
291static bool ftgmac100_rxdes_packet_ready(struct ftgmac100_rxdes *rxdes)
292{
293 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RXPKT_RDY);
294}
295
Benjamin Herrenschmidteb50af22017-04-06 11:02:47 +1000296#define RXDES0_ANY_ERROR ( \
297 FTGMAC100_RXDES0_RX_ERR | \
298 FTGMAC100_RXDES0_CRC_ERR | \
299 FTGMAC100_RXDES0_FTL | \
300 FTGMAC100_RXDES0_RUNT | \
301 FTGMAC100_RXDES0_RX_ODD_NB)
302
303static inline bool ftgmac100_rxdes_any_error(struct ftgmac100_rxdes *rxdes)
304{
305 return rxdes->rxdes0 & cpu_to_le32(RXDES0_ANY_ERROR);
306}
307
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000308static bool ftgmac100_rxdes_rx_error(struct ftgmac100_rxdes *rxdes)
309{
310 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RX_ERR);
311}
312
313static bool ftgmac100_rxdes_crc_error(struct ftgmac100_rxdes *rxdes)
314{
315 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_CRC_ERR);
316}
317
318static bool ftgmac100_rxdes_frame_too_long(struct ftgmac100_rxdes *rxdes)
319{
320 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_FTL);
321}
322
323static bool ftgmac100_rxdes_runt(struct ftgmac100_rxdes *rxdes)
324{
325 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RUNT);
326}
327
328static bool ftgmac100_rxdes_odd_nibble(struct ftgmac100_rxdes *rxdes)
329{
330 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RX_ODD_NB);
331}
332
333static unsigned int ftgmac100_rxdes_data_length(struct ftgmac100_rxdes *rxdes)
334{
335 return le32_to_cpu(rxdes->rxdes0) & FTGMAC100_RXDES0_VDBC;
336}
337
338static bool ftgmac100_rxdes_multicast(struct ftgmac100_rxdes *rxdes)
339{
340 return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_MULTICAST);
341}
342
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930343static void ftgmac100_rxdes_set_end_of_ring(const struct ftgmac100 *priv,
344 struct ftgmac100_rxdes *rxdes)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000345{
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930346 rxdes->rxdes0 |= cpu_to_le32(priv->rxdes0_edorr_mask);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000347}
348
349static void ftgmac100_rxdes_set_dma_addr(struct ftgmac100_rxdes *rxdes,
350 dma_addr_t addr)
351{
352 rxdes->rxdes3 = cpu_to_le32(addr);
353}
354
355static dma_addr_t ftgmac100_rxdes_get_dma_addr(struct ftgmac100_rxdes *rxdes)
356{
357 return le32_to_cpu(rxdes->rxdes3);
358}
359
Benjamin Herrenschmidt67202192017-04-06 11:02:46 +1000360static inline bool ftgmac100_rxdes_csum_err(struct ftgmac100_rxdes *rxdes)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000361{
Benjamin Herrenschmidt67202192017-04-06 11:02:46 +1000362 return !!(rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_TCP_CHKSUM_ERR |
363 FTGMAC100_RXDES1_UDP_CHKSUM_ERR |
364 FTGMAC100_RXDES1_IP_CHKSUM_ERR));
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000365}
366
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000367static int ftgmac100_alloc_rx_buf(struct ftgmac100 *priv, unsigned int entry,
368 struct ftgmac100_rxdes *rxdes, gfp_t gfp)
Benjamin Herrenschmidtc06f73f2017-04-06 11:02:43 +1000369{
370 struct net_device *netdev = priv->netdev;
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000371 struct sk_buff *skb;
Benjamin Herrenschmidtc06f73f2017-04-06 11:02:43 +1000372 dma_addr_t map;
Benjamin Herrenschmidtd72e01a2017-04-06 11:02:45 +1000373 int err;
Benjamin Herrenschmidtc06f73f2017-04-06 11:02:43 +1000374
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000375 skb = netdev_alloc_skb_ip_align(netdev, RX_BUF_SIZE);
376 if (unlikely(!skb)) {
Benjamin Herrenschmidtc06f73f2017-04-06 11:02:43 +1000377 if (net_ratelimit())
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000378 netdev_warn(netdev, "failed to allocate rx skb\n");
Benjamin Herrenschmidtd72e01a2017-04-06 11:02:45 +1000379 err = -ENOMEM;
380 map = priv->rx_scratch_dma;
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000381 } else {
382 map = dma_map_single(priv->dev, skb->data, RX_BUF_SIZE,
383 DMA_FROM_DEVICE);
384 if (unlikely(dma_mapping_error(priv->dev, map))) {
385 if (net_ratelimit())
386 netdev_err(netdev, "failed to map rx page\n");
387 dev_kfree_skb_any(skb);
388 map = priv->rx_scratch_dma;
389 skb = NULL;
390 err = -ENOMEM;
391 }
Benjamin Herrenschmidtc06f73f2017-04-06 11:02:43 +1000392 }
393
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000394 /* Store skb */
395 priv->rx_skbs[entry] = skb;
Benjamin Herrenschmidtc06f73f2017-04-06 11:02:43 +1000396
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000397 /* Store DMA address into RX desc */
Benjamin Herrenschmidtc06f73f2017-04-06 11:02:43 +1000398 ftgmac100_rxdes_set_dma_addr(rxdes, map);
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000399
400 /* Ensure the above is ordered vs clearing the OWN bit */
401 dma_wmb();
402
403 /* Clean rxdes0 (which resets own bit) */
404 rxdes->rxdes0 &= cpu_to_le32(priv->rxdes0_edorr_mask);
405
Benjamin Herrenschmidtc06f73f2017-04-06 11:02:43 +1000406 return 0;
407}
408
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000409static int ftgmac100_next_rx_pointer(int pointer)
410{
411 return (pointer + 1) & (RX_QUEUE_ENTRIES - 1);
412}
413
Benjamin Herrenschmidteb50af22017-04-06 11:02:47 +1000414static void ftgmac100_rx_packet_error(struct ftgmac100 *priv,
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000415 struct ftgmac100_rxdes *rxdes)
416{
417 struct net_device *netdev = priv->netdev;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000418
Benjamin Herrenschmidteb50af22017-04-06 11:02:47 +1000419 if (ftgmac100_rxdes_rx_error(rxdes))
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000420 netdev->stats.rx_errors++;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000421
Benjamin Herrenschmidteb50af22017-04-06 11:02:47 +1000422 if (ftgmac100_rxdes_crc_error(rxdes))
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000423 netdev->stats.rx_crc_errors++;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000424
Benjamin Herrenschmidteb50af22017-04-06 11:02:47 +1000425 if (ftgmac100_rxdes_frame_too_long(rxdes) ||
426 ftgmac100_rxdes_runt(rxdes) ||
427 ftgmac100_rxdes_odd_nibble(rxdes))
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000428 netdev->stats.rx_length_errors++;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000429}
430
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000431static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
432{
433 struct net_device *netdev = priv->netdev;
434 struct ftgmac100_rxdes *rxdes;
435 struct sk_buff *skb;
Benjamin Herrenschmidt01dd70b2017-04-06 11:02:48 +1000436 unsigned int pointer, size;
Benjamin Herrenschmidtb1977bf2017-04-06 11:02:44 +1000437 dma_addr_t map;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000438
Benjamin Herrenschmidt01dd70b2017-04-06 11:02:48 +1000439 /* Grab next RX descriptor */
440 pointer = priv->rx_pointer;
441 rxdes = &priv->descs->rxdes[pointer];
442
443 /* Do we have a packet ? */
444 if (!ftgmac100_rxdes_packet_ready(rxdes))
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000445 return false;
446
Benjamin Herrenschmidt01dd70b2017-04-06 11:02:48 +1000447 /* We don't cope with fragmented RX packets */
448 if (unlikely(!ftgmac100_rxdes_first_segment(rxdes) ||
449 !ftgmac100_rxdes_last_segment(rxdes)))
450 goto drop;
451
452 /* Any error (other than csum offload) flagged ? */
Benjamin Herrenschmidteb50af22017-04-06 11:02:47 +1000453 if (unlikely(ftgmac100_rxdes_any_error(rxdes))) {
454 ftgmac100_rx_packet_error(priv, rxdes);
Benjamin Herrenschmidt01dd70b2017-04-06 11:02:48 +1000455 goto drop;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000456 }
457
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000458 /* If the packet had no skb (failed to allocate earlier)
Benjamin Herrenschmidtd72e01a2017-04-06 11:02:45 +1000459 * then try to allocate one and skip
460 */
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000461 skb = priv->rx_skbs[pointer];
462 if (!unlikely(skb)) {
463 ftgmac100_alloc_rx_buf(priv, pointer, rxdes, GFP_ATOMIC);
Benjamin Herrenschmidt01dd70b2017-04-06 11:02:48 +1000464 goto drop;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000465 }
466
467 if (unlikely(ftgmac100_rxdes_multicast(rxdes)))
468 netdev->stats.multicast++;
469
Benjamin Herrenschmidt67202192017-04-06 11:02:46 +1000470 /* If the HW found checksum errors, bounce it to software.
471 *
472 * If we didn't, we need to see if the packet was recognized
473 * by HW as one of the supported checksummed protocols before
474 * we accept the HW test results.
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000475 */
Benjamin Herrenschmidt67202192017-04-06 11:02:46 +1000476 if (netdev->features & NETIF_F_RXCSUM) {
477 __le32 csum_vlan = rxdes->rxdes1;
478 __le32 err_bits = cpu_to_le32(FTGMAC100_RXDES1_TCP_CHKSUM_ERR |
479 FTGMAC100_RXDES1_UDP_CHKSUM_ERR |
480 FTGMAC100_RXDES1_IP_CHKSUM_ERR);
481 if ((csum_vlan & err_bits) ||
482 !(csum_vlan & cpu_to_le32(FTGMAC100_RXDES1_PROT_MASK)))
483 skb->ip_summed = CHECKSUM_NONE;
484 else
485 skb->ip_summed = CHECKSUM_UNNECESSARY;
486 }
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000487
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000488 /* Grab received size annd transfer to skb */
Benjamin Herrenschmidtb1977bf2017-04-06 11:02:44 +1000489 size = ftgmac100_rxdes_data_length(rxdes);
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000490 skb_put(skb, size);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000491
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000492 /* Tear down DMA mapping, do necessary cache management */
493 map = ftgmac100_rxdes_get_dma_addr(rxdes);
494#if defined(CONFIG_ARM) && !defined(CONFIG_ARM_DMA_USE_IOMMU)
495 /* When we don't have an iommu, we can save cycles by not
496 * invalidating the cache for the part of the packet that
497 * wasn't received.
498 */
499 dma_unmap_single(priv->dev, map, size, DMA_FROM_DEVICE);
500#else
501 dma_unmap_single(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
502#endif
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000503
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000504
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000505 /* Resplenish rx ring */
506 ftgmac100_alloc_rx_buf(priv, pointer, rxdes, GFP_ATOMIC);
Benjamin Herrenschmidt01dd70b2017-04-06 11:02:48 +1000507 priv->rx_pointer = ftgmac100_next_rx_pointer(pointer);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000508
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000509 skb->protocol = eth_type_trans(skb, netdev);
510
511 netdev->stats.rx_packets++;
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000512 netdev->stats.rx_bytes += size;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000513
514 /* push packet to protocol stack */
Benjamin Herrenschmidt67202192017-04-06 11:02:46 +1000515 if (skb->ip_summed == CHECKSUM_NONE)
516 netif_receive_skb(skb);
517 else
518 napi_gro_receive(&priv->napi, skb);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000519
520 (*processed)++;
521 return true;
Benjamin Herrenschmidt01dd70b2017-04-06 11:02:48 +1000522
523 drop:
524 /* Clean rxdes0 (which resets own bit) */
525 rxdes->rxdes0 &= cpu_to_le32(priv->rxdes0_edorr_mask);
526 priv->rx_pointer = ftgmac100_next_rx_pointer(pointer);
527 netdev->stats.rx_dropped++;
528 return true;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000529}
530
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930531static void ftgmac100_txdes_reset(const struct ftgmac100 *priv,
532 struct ftgmac100_txdes *txdes)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000533{
534 /* clear all except end of ring bit */
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930535 txdes->txdes0 &= cpu_to_le32(priv->txdes0_edotr_mask);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000536 txdes->txdes1 = 0;
537 txdes->txdes2 = 0;
538 txdes->txdes3 = 0;
539}
540
541static bool ftgmac100_txdes_owned_by_dma(struct ftgmac100_txdes *txdes)
542{
543 return txdes->txdes0 & cpu_to_le32(FTGMAC100_TXDES0_TXDMA_OWN);
544}
545
546static void ftgmac100_txdes_set_dma_own(struct ftgmac100_txdes *txdes)
547{
548 /*
549 * Make sure dma own bit will not be set before any other
550 * descriptor fields.
551 */
552 wmb();
553 txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_TXDMA_OWN);
554}
555
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930556static void ftgmac100_txdes_set_end_of_ring(const struct ftgmac100 *priv,
557 struct ftgmac100_txdes *txdes)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000558{
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930559 txdes->txdes0 |= cpu_to_le32(priv->txdes0_edotr_mask);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000560}
561
562static void ftgmac100_txdes_set_first_segment(struct ftgmac100_txdes *txdes)
563{
564 txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_FTS);
565}
566
567static void ftgmac100_txdes_set_last_segment(struct ftgmac100_txdes *txdes)
568{
569 txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_LTS);
570}
571
572static void ftgmac100_txdes_set_buffer_size(struct ftgmac100_txdes *txdes,
573 unsigned int len)
574{
575 txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_TXBUF_SIZE(len));
576}
577
578static void ftgmac100_txdes_set_txint(struct ftgmac100_txdes *txdes)
579{
580 txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_TXIC);
581}
582
583static void ftgmac100_txdes_set_tcpcs(struct ftgmac100_txdes *txdes)
584{
585 txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_TCP_CHKSUM);
586}
587
588static void ftgmac100_txdes_set_udpcs(struct ftgmac100_txdes *txdes)
589{
590 txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_UDP_CHKSUM);
591}
592
593static void ftgmac100_txdes_set_ipcs(struct ftgmac100_txdes *txdes)
594{
595 txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_IP_CHKSUM);
596}
597
598static void ftgmac100_txdes_set_dma_addr(struct ftgmac100_txdes *txdes,
599 dma_addr_t addr)
600{
601 txdes->txdes3 = cpu_to_le32(addr);
602}
603
604static dma_addr_t ftgmac100_txdes_get_dma_addr(struct ftgmac100_txdes *txdes)
605{
606 return le32_to_cpu(txdes->txdes3);
607}
608
609/*
610 * txdes2 is not used by hardware. We use it to keep track of socket buffer.
611 * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu().
612 */
613static void ftgmac100_txdes_set_skb(struct ftgmac100_txdes *txdes,
614 struct sk_buff *skb)
615{
616 txdes->txdes2 = (unsigned int)skb;
617}
618
619static struct sk_buff *ftgmac100_txdes_get_skb(struct ftgmac100_txdes *txdes)
620{
621 return (struct sk_buff *)txdes->txdes2;
622}
623
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000624static int ftgmac100_next_tx_pointer(int pointer)
625{
626 return (pointer + 1) & (TX_QUEUE_ENTRIES - 1);
627}
628
629static void ftgmac100_tx_pointer_advance(struct ftgmac100 *priv)
630{
631 priv->tx_pointer = ftgmac100_next_tx_pointer(priv->tx_pointer);
632}
633
634static void ftgmac100_tx_clean_pointer_advance(struct ftgmac100 *priv)
635{
636 priv->tx_clean_pointer = ftgmac100_next_tx_pointer(priv->tx_clean_pointer);
637}
638
639static struct ftgmac100_txdes *ftgmac100_current_txdes(struct ftgmac100 *priv)
640{
641 return &priv->descs->txdes[priv->tx_pointer];
642}
643
644static struct ftgmac100_txdes *
645ftgmac100_current_clean_txdes(struct ftgmac100 *priv)
646{
647 return &priv->descs->txdes[priv->tx_clean_pointer];
648}
649
650static bool ftgmac100_tx_complete_packet(struct ftgmac100 *priv)
651{
652 struct net_device *netdev = priv->netdev;
653 struct ftgmac100_txdes *txdes;
654 struct sk_buff *skb;
655 dma_addr_t map;
656
657 if (priv->tx_pending == 0)
658 return false;
659
660 txdes = ftgmac100_current_clean_txdes(priv);
661
662 if (ftgmac100_txdes_owned_by_dma(txdes))
663 return false;
664
665 skb = ftgmac100_txdes_get_skb(txdes);
666 map = ftgmac100_txdes_get_dma_addr(txdes);
667
668 netdev->stats.tx_packets++;
669 netdev->stats.tx_bytes += skb->len;
670
671 dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
672
673 dev_kfree_skb(skb);
674
Andrew Jeffery7906a4d2016-09-22 08:34:59 +0930675 ftgmac100_txdes_reset(priv, txdes);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000676
677 ftgmac100_tx_clean_pointer_advance(priv);
678
679 spin_lock(&priv->tx_lock);
680 priv->tx_pending--;
681 spin_unlock(&priv->tx_lock);
682 netif_wake_queue(netdev);
683
684 return true;
685}
686
687static void ftgmac100_tx_complete(struct ftgmac100 *priv)
688{
689 while (ftgmac100_tx_complete_packet(priv))
690 ;
691}
692
693static int ftgmac100_xmit(struct ftgmac100 *priv, struct sk_buff *skb,
694 dma_addr_t map)
695{
696 struct net_device *netdev = priv->netdev;
697 struct ftgmac100_txdes *txdes;
698 unsigned int len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
699
700 txdes = ftgmac100_current_txdes(priv);
701 ftgmac100_tx_pointer_advance(priv);
702
703 /* setup TX descriptor */
704 ftgmac100_txdes_set_skb(txdes, skb);
705 ftgmac100_txdes_set_dma_addr(txdes, map);
706 ftgmac100_txdes_set_buffer_size(txdes, len);
707
708 ftgmac100_txdes_set_first_segment(txdes);
709 ftgmac100_txdes_set_last_segment(txdes);
710 ftgmac100_txdes_set_txint(txdes);
711 if (skb->ip_summed == CHECKSUM_PARTIAL) {
712 __be16 protocol = skb->protocol;
713
714 if (protocol == cpu_to_be16(ETH_P_IP)) {
715 u8 ip_proto = ip_hdr(skb)->protocol;
716
717 ftgmac100_txdes_set_ipcs(txdes);
718 if (ip_proto == IPPROTO_TCP)
719 ftgmac100_txdes_set_tcpcs(txdes);
720 else if (ip_proto == IPPROTO_UDP)
721 ftgmac100_txdes_set_udpcs(txdes);
722 }
723 }
724
725 spin_lock(&priv->tx_lock);
726 priv->tx_pending++;
727 if (priv->tx_pending == TX_QUEUE_ENTRIES)
728 netif_stop_queue(netdev);
729
730 /* start transmit */
731 ftgmac100_txdes_set_dma_own(txdes);
732 spin_unlock(&priv->tx_lock);
733
734 ftgmac100_txdma_normal_prio_start_polling(priv);
735
736 return NETDEV_TX_OK;
737}
738
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000739static void ftgmac100_free_buffers(struct ftgmac100 *priv)
740{
741 int i;
742
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000743 /* Free all RX buffers */
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000744 for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
745 struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[i];
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000746 struct sk_buff *skb = priv->rx_skbs[i];
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000747 dma_addr_t map = ftgmac100_rxdes_get_dma_addr(rxdes);
748
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000749 if (!skb)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000750 continue;
751
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000752 priv->rx_skbs[i] = NULL;
753 dma_unmap_single(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
754 dev_kfree_skb_any(skb);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000755 }
756
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000757 /* Free all TX buffers */
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000758 for (i = 0; i < TX_QUEUE_ENTRIES; i++) {
759 struct ftgmac100_txdes *txdes = &priv->descs->txdes[i];
760 struct sk_buff *skb = ftgmac100_txdes_get_skb(txdes);
761 dma_addr_t map = ftgmac100_txdes_get_dma_addr(txdes);
762
763 if (!skb)
764 continue;
765
766 dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
Eric Dumazet0113e342014-01-16 23:38:24 -0800767 kfree_skb(skb);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000768 }
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000769}
770
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000771static void ftgmac100_free_rings(struct ftgmac100 *priv)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000772{
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000773 /* Free descriptors */
774 if (priv->descs)
775 dma_free_coherent(priv->dev, sizeof(struct ftgmac100_descs),
776 priv->descs, priv->descs_dma_addr);
Benjamin Herrenschmidtd72e01a2017-04-06 11:02:45 +1000777
778 /* Free scratch packet buffer */
779 if (priv->rx_scratch)
780 dma_free_coherent(priv->dev, RX_BUF_SIZE,
781 priv->rx_scratch, priv->rx_scratch_dma);
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000782}
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000783
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000784static int ftgmac100_alloc_rings(struct ftgmac100 *priv)
785{
786 /* Allocate descriptors */
Joe Perchesede23fa82013-08-26 22:45:23 -0700787 priv->descs = dma_zalloc_coherent(priv->dev,
788 sizeof(struct ftgmac100_descs),
789 &priv->descs_dma_addr, GFP_KERNEL);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000790 if (!priv->descs)
791 return -ENOMEM;
792
Benjamin Herrenschmidtd72e01a2017-04-06 11:02:45 +1000793 /* Allocate scratch packet buffer */
794 priv->rx_scratch = dma_alloc_coherent(priv->dev,
795 RX_BUF_SIZE,
796 &priv->rx_scratch_dma,
797 GFP_KERNEL);
798 if (!priv->rx_scratch)
799 return -ENOMEM;
800
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000801 return 0;
802}
803
804static void ftgmac100_init_rings(struct ftgmac100 *priv)
805{
806 int i;
807
808 /* Initialize RX ring */
Benjamin Herrenschmidtd72e01a2017-04-06 11:02:45 +1000809 for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
810 struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[i];
811 ftgmac100_rxdes_set_dma_addr(rxdes, priv->rx_scratch_dma);
812 rxdes->rxdes0 = 0;
813 }
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000814 ftgmac100_rxdes_set_end_of_ring(priv, &priv->descs->rxdes[i - 1]);
815
816 /* Initialize TX ring */
817 for (i = 0; i < TX_QUEUE_ENTRIES; i++)
818 priv->descs->txdes[i].txdes0 = 0;
819 ftgmac100_txdes_set_end_of_ring(priv, &priv->descs->txdes[i -1]);
820}
821
822static int ftgmac100_alloc_rx_buffers(struct ftgmac100 *priv)
823{
824 int i;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000825
826 for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
827 struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[i];
828
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000829 if (ftgmac100_alloc_rx_buf(priv, i, rxdes, GFP_KERNEL))
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000830 return -ENOMEM;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000831 }
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000832 return 0;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000833}
834
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000835static void ftgmac100_adjust_link(struct net_device *netdev)
836{
837 struct ftgmac100 *priv = netdev_priv(netdev);
Philippe Reynesb3c40ad2016-05-16 01:35:13 +0200838 struct phy_device *phydev = netdev->phydev;
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +1000839 int new_speed;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000840
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +1000841 /* We store "no link" as speed 0 */
842 if (!phydev->link)
843 new_speed = 0;
844 else
845 new_speed = phydev->speed;
846
847 if (phydev->speed == priv->cur_speed &&
848 phydev->duplex == priv->cur_duplex)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000849 return;
850
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +1000851 /* Print status if we have a link or we had one and just lost it,
852 * don't print otherwise.
853 */
854 if (new_speed || priv->cur_speed)
855 phy_print_status(phydev);
856
857 priv->cur_speed = new_speed;
858 priv->cur_duplex = phydev->duplex;
859
860 /* Link is down, do nothing else */
861 if (!new_speed)
862 return;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000863
Benjamin Herrenschmidt855944c2017-04-05 12:28:50 +1000864 /* Disable all interrupts */
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000865 iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
866
Benjamin Herrenschmidt855944c2017-04-05 12:28:50 +1000867 /* Reset the adapter asynchronously */
868 schedule_work(&priv->reset_task);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000869}
870
871static int ftgmac100_mii_probe(struct ftgmac100 *priv)
872{
873 struct net_device *netdev = priv->netdev;
Guenter Roecke574f392016-01-10 12:04:32 -0800874 struct phy_device *phydev;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000875
Guenter Roecke574f392016-01-10 12:04:32 -0800876 phydev = phy_find_first(priv->mii_bus);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000877 if (!phydev) {
878 netdev_info(netdev, "%s: no PHY found\n", netdev->name);
879 return -ENODEV;
880 }
881
Andrew Lunn84eff6d2016-01-06 20:11:10 +0100882 phydev = phy_connect(netdev, phydev_name(phydev),
Florian Fainellif9a8f832013-01-14 00:52:52 +0000883 &ftgmac100_adjust_link, PHY_INTERFACE_MODE_GMII);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000884
885 if (IS_ERR(phydev)) {
886 netdev_err(netdev, "%s: Could not attach to PHY\n", netdev->name);
887 return PTR_ERR(phydev);
888 }
889
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000890 return 0;
891}
892
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000893static int ftgmac100_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
894{
895 struct net_device *netdev = bus->priv;
896 struct ftgmac100 *priv = netdev_priv(netdev);
897 unsigned int phycr;
898 int i;
899
900 phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
901
902 /* preserve MDC cycle threshold */
903 phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
904
905 phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr) |
906 FTGMAC100_PHYCR_REGAD(regnum) |
907 FTGMAC100_PHYCR_MIIRD;
908
909 iowrite32(phycr, priv->base + FTGMAC100_OFFSET_PHYCR);
910
911 for (i = 0; i < 10; i++) {
912 phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
913
914 if ((phycr & FTGMAC100_PHYCR_MIIRD) == 0) {
915 int data;
916
917 data = ioread32(priv->base + FTGMAC100_OFFSET_PHYDATA);
918 return FTGMAC100_PHYDATA_MIIRDATA(data);
919 }
920
921 udelay(100);
922 }
923
924 netdev_err(netdev, "mdio read timed out\n");
925 return -EIO;
926}
927
928static int ftgmac100_mdiobus_write(struct mii_bus *bus, int phy_addr,
929 int regnum, u16 value)
930{
931 struct net_device *netdev = bus->priv;
932 struct ftgmac100 *priv = netdev_priv(netdev);
933 unsigned int phycr;
934 int data;
935 int i;
936
937 phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
938
939 /* preserve MDC cycle threshold */
940 phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
941
942 phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr) |
943 FTGMAC100_PHYCR_REGAD(regnum) |
944 FTGMAC100_PHYCR_MIIWR;
945
946 data = FTGMAC100_PHYDATA_MIIWDATA(value);
947
948 iowrite32(data, priv->base + FTGMAC100_OFFSET_PHYDATA);
949 iowrite32(phycr, priv->base + FTGMAC100_OFFSET_PHYCR);
950
951 for (i = 0; i < 10; i++) {
952 phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
953
954 if ((phycr & FTGMAC100_PHYCR_MIIWR) == 0)
955 return 0;
956
957 udelay(100);
958 }
959
960 netdev_err(netdev, "mdio write timed out\n");
961 return -EIO;
962}
963
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000964static void ftgmac100_get_drvinfo(struct net_device *netdev,
965 struct ethtool_drvinfo *info)
966{
Jiri Pirko7826d432013-01-06 00:44:26 +0000967 strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
968 strlcpy(info->version, DRV_VERSION, sizeof(info->version));
969 strlcpy(info->bus_info, dev_name(&netdev->dev), sizeof(info->bus_info));
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000970}
971
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000972static const struct ethtool_ops ftgmac100_ethtool_ops = {
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000973 .get_drvinfo = ftgmac100_get_drvinfo,
974 .get_link = ethtool_op_get_link,
Philippe Reynesfd24d722016-05-16 01:35:14 +0200975 .get_link_ksettings = phy_ethtool_get_link_ksettings,
976 .set_link_ksettings = phy_ethtool_set_link_ksettings,
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000977};
978
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000979static irqreturn_t ftgmac100_interrupt(int irq, void *dev_id)
980{
981 struct net_device *netdev = dev_id;
982 struct ftgmac100 *priv = netdev_priv(netdev);
Benjamin Herrenschmidt10cbd642017-04-05 12:28:53 +1000983 unsigned int status, new_mask = FTGMAC100_INT_BAD;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000984
Benjamin Herrenschmidt10cbd642017-04-05 12:28:53 +1000985 /* Fetch and clear interrupt bits, process abnormal ones */
986 status = ioread32(priv->base + FTGMAC100_OFFSET_ISR);
987 iowrite32(status, priv->base + FTGMAC100_OFFSET_ISR);
988 if (unlikely(status & FTGMAC100_INT_BAD)) {
989
990 /* RX buffer unavailable */
991 if (status & FTGMAC100_INT_NO_RXBUF)
992 netdev->stats.rx_over_errors++;
993
994 /* received packet lost due to RX FIFO full */
995 if (status & FTGMAC100_INT_RPKT_LOST)
996 netdev->stats.rx_fifo_errors++;
997
998 /* sent packet lost due to excessive TX collision */
999 if (status & FTGMAC100_INT_XPKT_LOST)
1000 netdev->stats.tx_fifo_errors++;
1001
1002 /* AHB error -> Reset the chip */
1003 if (status & FTGMAC100_INT_AHB_ERR) {
1004 if (net_ratelimit())
1005 netdev_warn(netdev,
1006 "AHB bus error ! Resetting chip.\n");
1007 iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
1008 schedule_work(&priv->reset_task);
1009 return IRQ_HANDLED;
1010 }
1011
1012 /* We may need to restart the MAC after such errors, delay
1013 * this until after we have freed some Rx buffers though
1014 */
1015 priv->need_mac_restart = true;
1016
1017 /* Disable those errors until we restart */
1018 new_mask &= ~status;
1019 }
1020
1021 /* Only enable "bad" interrupts while NAPI is on */
1022 iowrite32(new_mask, priv->base + FTGMAC100_OFFSET_IER);
1023
1024 /* Schedule NAPI bh */
1025 napi_schedule_irqoff(&priv->napi);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001026
1027 return IRQ_HANDLED;
1028}
1029
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001030static int ftgmac100_poll(struct napi_struct *napi, int budget)
1031{
1032 struct ftgmac100 *priv = container_of(napi, struct ftgmac100, napi);
Benjamin Herrenschmidt10cbd642017-04-05 12:28:53 +10001033 bool more, completed = true;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001034 int rx = 0;
1035
Benjamin Herrenschmidt10cbd642017-04-05 12:28:53 +10001036 ftgmac100_tx_complete(priv);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001037
Benjamin Herrenschmidt10cbd642017-04-05 12:28:53 +10001038 do {
1039 more = ftgmac100_rx_packet(priv, &rx);
1040 } while (more && rx < budget);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001041
Benjamin Herrenschmidt10cbd642017-04-05 12:28:53 +10001042 if (more && rx == budget)
1043 completed = false;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001044
Benjamin Herrenschmidt10cbd642017-04-05 12:28:53 +10001045
1046 /* The interrupt is telling us to kick the MAC back to life
1047 * after an RX overflow
1048 */
1049 if (unlikely(priv->need_mac_restart)) {
1050 ftgmac100_start_hw(priv);
1051
1052 /* Re-enable "bad" interrupts */
1053 iowrite32(FTGMAC100_INT_BAD,
1054 priv->base + FTGMAC100_OFFSET_IER);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001055 }
1056
Benjamin Herrenschmidt10cbd642017-04-05 12:28:53 +10001057 /* Keep NAPI going if we have still packets to reclaim */
1058 if (priv->tx_pending)
1059 return budget;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001060
1061 if (completed) {
Benjamin Herrenschmidt10cbd642017-04-05 12:28:53 +10001062 /* We are about to re-enable all interrupts. However
1063 * the HW has been latching RX/TX packet interrupts while
1064 * they were masked. So we clear them first, then we need
1065 * to re-check if there's something to process
1066 */
1067 iowrite32(FTGMAC100_INT_RXTX,
1068 priv->base + FTGMAC100_OFFSET_ISR);
1069 if (ftgmac100_rxdes_packet_ready
1070 (ftgmac100_current_rxdes(priv)) || priv->tx_pending)
1071 return budget;
1072
1073 /* deschedule NAPI */
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001074 napi_complete(napi);
1075
1076 /* enable all interrupts */
Benjamin Herrenschmidt10cbd642017-04-05 12:28:53 +10001077 iowrite32(FTGMAC100_INT_ALL,
Gavin Shanfc6061c2016-07-19 11:54:25 +10001078 priv->base + FTGMAC100_OFFSET_IER);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001079 }
1080
1081 return rx;
1082}
1083
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001084static int ftgmac100_init_all(struct ftgmac100 *priv, bool ignore_alloc_err)
1085{
1086 int err = 0;
1087
1088 /* Re-init descriptors (adjust queue sizes) */
1089 ftgmac100_init_rings(priv);
1090
1091 /* Realloc rx descriptors */
1092 err = ftgmac100_alloc_rx_buffers(priv);
1093 if (err && !ignore_alloc_err)
1094 return err;
1095
1096 /* Reinit and restart HW */
1097 ftgmac100_init_hw(priv);
1098 ftgmac100_start_hw(priv);
1099
1100 /* Re-enable the device */
1101 napi_enable(&priv->napi);
1102 netif_start_queue(priv->netdev);
1103
1104 /* Enable all interrupts */
Benjamin Herrenschmidt10cbd642017-04-05 12:28:53 +10001105 iowrite32(FTGMAC100_INT_ALL, priv->base + FTGMAC100_OFFSET_IER);
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001106
1107 return err;
1108}
1109
Benjamin Herrenschmidt855944c2017-04-05 12:28:50 +10001110static void ftgmac100_reset_task(struct work_struct *work)
1111{
1112 struct ftgmac100 *priv = container_of(work, struct ftgmac100,
1113 reset_task);
1114 struct net_device *netdev = priv->netdev;
1115 int err;
1116
1117 netdev_dbg(netdev, "Resetting NIC...\n");
1118
1119 /* Lock the world */
1120 rtnl_lock();
1121 if (netdev->phydev)
1122 mutex_lock(&netdev->phydev->lock);
1123 if (priv->mii_bus)
1124 mutex_lock(&priv->mii_bus->mdio_lock);
1125
1126
1127 /* Check if the interface is still up */
1128 if (!netif_running(netdev))
1129 goto bail;
1130
1131 /* Stop the network stack */
1132 netif_trans_update(netdev);
1133 napi_disable(&priv->napi);
1134 netif_tx_disable(netdev);
1135
1136 /* Stop and reset the MAC */
1137 ftgmac100_stop_hw(priv);
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +10001138 err = ftgmac100_reset_and_config_mac(priv);
Benjamin Herrenschmidt855944c2017-04-05 12:28:50 +10001139 if (err) {
1140 /* Not much we can do ... it might come back... */
1141 netdev_err(netdev, "attempting to continue...\n");
1142 }
1143
1144 /* Free all rx and tx buffers */
1145 ftgmac100_free_buffers(priv);
1146
Benjamin Herrenschmidt855944c2017-04-05 12:28:50 +10001147 /* Setup everything again and restart chip */
1148 ftgmac100_init_all(priv, true);
1149
1150 netdev_dbg(netdev, "Reset done !\n");
1151 bail:
1152 if (priv->mii_bus)
1153 mutex_unlock(&priv->mii_bus->mdio_lock);
1154 if (netdev->phydev)
1155 mutex_unlock(&netdev->phydev->lock);
1156 rtnl_unlock();
1157}
1158
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001159static int ftgmac100_open(struct net_device *netdev)
1160{
1161 struct ftgmac100 *priv = netdev_priv(netdev);
1162 int err;
1163
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +10001164 /* Allocate ring buffers */
1165 err = ftgmac100_alloc_rings(priv);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001166 if (err) {
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +10001167 netdev_err(netdev, "Failed to allocate descriptors\n");
1168 return err;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001169 }
1170
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +10001171 /* When using NC-SI we force the speed to 100Mbit/s full duplex,
1172 *
1173 * Otherwise we leave it set to 0 (no link), the link
1174 * message from the PHY layer will handle setting it up to
1175 * something else if needed.
1176 */
1177 if (priv->use_ncsi) {
1178 priv->cur_duplex = DUPLEX_FULL;
1179 priv->cur_speed = SPEED_100;
1180 } else {
1181 priv->cur_duplex = 0;
1182 priv->cur_speed = 0;
1183 }
1184
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +10001185 /* Reset the hardware */
1186 err = ftgmac100_reset_and_config_mac(priv);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001187 if (err)
1188 goto err_hw;
1189
Benjamin Herrenschmidtb8dbecf2017-04-05 12:28:47 +10001190 /* Initialize NAPI */
1191 netif_napi_add(netdev, &priv->napi, ftgmac100_poll, 64);
1192
Benjamin Herrenschmidt81f1eca2017-04-05 12:28:48 +10001193 /* Grab our interrupt */
1194 err = request_irq(netdev->irq, ftgmac100_interrupt, 0, netdev->name, netdev);
1195 if (err) {
1196 netdev_err(netdev, "failed to request irq %d\n", netdev->irq);
1197 goto err_irq;
1198 }
1199
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001200 /* Start things up */
1201 err = ftgmac100_init_all(priv, false);
1202 if (err) {
1203 netdev_err(netdev, "Failed to allocate packet buffers\n");
1204 goto err_alloc;
1205 }
Gavin Shan08c9c122016-09-22 08:35:01 +09301206
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001207 if (netdev->phydev) {
1208 /* If we have a PHY, start polling */
Gavin Shanbd466c32016-07-19 11:54:23 +10001209 phy_start(netdev->phydev);
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001210 } else if (priv->use_ncsi) {
1211 /* If using NC-SI, set our carrier on and start the stack */
Gavin Shanbd466c32016-07-19 11:54:23 +10001212 netif_carrier_on(netdev);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001213
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001214 /* Start the NCSI device */
Gavin Shanbd466c32016-07-19 11:54:23 +10001215 err = ncsi_start_dev(priv->ndev);
1216 if (err)
1217 goto err_ncsi;
1218 }
1219
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001220 return 0;
1221
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001222 err_ncsi:
Gavin Shanbd466c32016-07-19 11:54:23 +10001223 napi_disable(&priv->napi);
1224 netif_stop_queue(netdev);
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001225 err_alloc:
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +10001226 ftgmac100_free_buffers(priv);
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001227 free_irq(netdev->irq, netdev);
1228 err_irq:
1229 netif_napi_del(&priv->napi);
1230 err_hw:
1231 iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +10001232 ftgmac100_free_rings(priv);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001233 return err;
1234}
1235
1236static int ftgmac100_stop(struct net_device *netdev)
1237{
1238 struct ftgmac100 *priv = netdev_priv(netdev);
1239
Benjamin Herrenschmidt855944c2017-04-05 12:28:50 +10001240 /* Note about the reset task: We are called with the rtnl lock
1241 * held, so we are synchronized against the core of the reset
1242 * task. We must not try to synchronously cancel it otherwise
1243 * we can deadlock. But since it will test for netif_running()
1244 * which has already been cleared by the net core, we don't
1245 * anything special to do.
1246 */
1247
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001248 /* disable all interrupts */
1249 iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
1250
1251 netif_stop_queue(netdev);
1252 napi_disable(&priv->napi);
Benjamin Herrenschmidtb8dbecf2017-04-05 12:28:47 +10001253 netif_napi_del(&priv->napi);
Gavin Shanbd466c32016-07-19 11:54:23 +10001254 if (netdev->phydev)
1255 phy_stop(netdev->phydev);
Gavin Shan2c15f252016-10-04 11:25:54 +11001256 else if (priv->use_ncsi)
1257 ncsi_stop_dev(priv->ndev);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001258
1259 ftgmac100_stop_hw(priv);
Benjamin Herrenschmidt60b28a12017-04-05 12:28:41 +10001260 free_irq(netdev->irq, netdev);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001261 ftgmac100_free_buffers(priv);
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +10001262 ftgmac100_free_rings(priv);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001263
1264 return 0;
1265}
1266
1267static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
1268 struct net_device *netdev)
1269{
1270 struct ftgmac100 *priv = netdev_priv(netdev);
1271 dma_addr_t map;
1272
1273 if (unlikely(skb->len > MAX_PKT_SIZE)) {
1274 if (net_ratelimit())
1275 netdev_dbg(netdev, "tx packet too big\n");
1276
1277 netdev->stats.tx_dropped++;
Eric Dumazet0113e342014-01-16 23:38:24 -08001278 kfree_skb(skb);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001279 return NETDEV_TX_OK;
1280 }
1281
1282 map = dma_map_single(priv->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
1283 if (unlikely(dma_mapping_error(priv->dev, map))) {
1284 /* drop packet */
1285 if (net_ratelimit())
1286 netdev_err(netdev, "map socket buffer failed\n");
1287
1288 netdev->stats.tx_dropped++;
Eric Dumazet0113e342014-01-16 23:38:24 -08001289 kfree_skb(skb);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001290 return NETDEV_TX_OK;
1291 }
1292
1293 return ftgmac100_xmit(priv, skb, map);
1294}
1295
1296/* optional */
1297static int ftgmac100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
1298{
Gavin Shanbd466c32016-07-19 11:54:23 +10001299 if (!netdev->phydev)
1300 return -ENXIO;
1301
Philippe Reynesb3c40ad2016-05-16 01:35:13 +02001302 return phy_mii_ioctl(netdev->phydev, ifr, cmd);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001303}
1304
1305static const struct net_device_ops ftgmac100_netdev_ops = {
1306 .ndo_open = ftgmac100_open,
1307 .ndo_stop = ftgmac100_stop,
1308 .ndo_start_xmit = ftgmac100_hard_start_xmit,
Gavin Shan113ce102016-07-19 11:54:22 +10001309 .ndo_set_mac_address = ftgmac100_set_mac_addr,
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001310 .ndo_validate_addr = eth_validate_addr,
1311 .ndo_do_ioctl = ftgmac100_do_ioctl,
1312};
1313
Gavin Shaneb418182016-07-19 11:54:21 +10001314static int ftgmac100_setup_mdio(struct net_device *netdev)
1315{
1316 struct ftgmac100 *priv = netdev_priv(netdev);
1317 struct platform_device *pdev = to_platform_device(priv->dev);
1318 int i, err = 0;
Joel Stanleye07dc632016-09-22 08:35:02 +09301319 u32 reg;
Gavin Shaneb418182016-07-19 11:54:21 +10001320
1321 /* initialize mdio bus */
1322 priv->mii_bus = mdiobus_alloc();
1323 if (!priv->mii_bus)
1324 return -EIO;
1325
Joel Stanleye07dc632016-09-22 08:35:02 +09301326 if (of_machine_is_compatible("aspeed,ast2400") ||
1327 of_machine_is_compatible("aspeed,ast2500")) {
1328 /* This driver supports the old MDIO interface */
1329 reg = ioread32(priv->base + FTGMAC100_OFFSET_REVR);
1330 reg &= ~FTGMAC100_REVR_NEW_MDIO_INTERFACE;
1331 iowrite32(reg, priv->base + FTGMAC100_OFFSET_REVR);
1332 };
1333
Gavin Shaneb418182016-07-19 11:54:21 +10001334 priv->mii_bus->name = "ftgmac100_mdio";
1335 snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%d",
1336 pdev->name, pdev->id);
1337 priv->mii_bus->priv = priv->netdev;
1338 priv->mii_bus->read = ftgmac100_mdiobus_read;
1339 priv->mii_bus->write = ftgmac100_mdiobus_write;
1340
1341 for (i = 0; i < PHY_MAX_ADDR; i++)
1342 priv->mii_bus->irq[i] = PHY_POLL;
1343
1344 err = mdiobus_register(priv->mii_bus);
1345 if (err) {
1346 dev_err(priv->dev, "Cannot register MDIO bus!\n");
1347 goto err_register_mdiobus;
1348 }
1349
1350 err = ftgmac100_mii_probe(priv);
1351 if (err) {
1352 dev_err(priv->dev, "MII Probe failed!\n");
1353 goto err_mii_probe;
1354 }
1355
1356 return 0;
1357
1358err_mii_probe:
1359 mdiobus_unregister(priv->mii_bus);
1360err_register_mdiobus:
1361 mdiobus_free(priv->mii_bus);
1362 return err;
1363}
1364
1365static void ftgmac100_destroy_mdio(struct net_device *netdev)
1366{
1367 struct ftgmac100 *priv = netdev_priv(netdev);
1368
1369 if (!netdev->phydev)
1370 return;
1371
1372 phy_disconnect(netdev->phydev);
1373 mdiobus_unregister(priv->mii_bus);
1374 mdiobus_free(priv->mii_bus);
1375}
1376
Gavin Shanbd466c32016-07-19 11:54:23 +10001377static void ftgmac100_ncsi_handler(struct ncsi_dev *nd)
1378{
1379 if (unlikely(nd->state != ncsi_dev_state_functional))
1380 return;
1381
1382 netdev_info(nd->dev, "NCSI interface %s\n",
1383 nd->link_up ? "up" : "down");
1384}
1385
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001386static int ftgmac100_probe(struct platform_device *pdev)
1387{
1388 struct resource *res;
1389 int irq;
1390 struct net_device *netdev;
1391 struct ftgmac100 *priv;
Gavin Shanbd466c32016-07-19 11:54:23 +10001392 int err = 0;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001393
1394 if (!pdev)
1395 return -ENODEV;
1396
1397 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1398 if (!res)
1399 return -ENXIO;
1400
1401 irq = platform_get_irq(pdev, 0);
1402 if (irq < 0)
1403 return irq;
1404
1405 /* setup net_device */
1406 netdev = alloc_etherdev(sizeof(*priv));
1407 if (!netdev) {
1408 err = -ENOMEM;
1409 goto err_alloc_etherdev;
1410 }
1411
1412 SET_NETDEV_DEV(netdev, &pdev->dev);
1413
Wilfried Klaebe7ad24ea2014-05-11 00:12:32 +00001414 netdev->ethtool_ops = &ftgmac100_ethtool_ops;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001415 netdev->netdev_ops = &ftgmac100_netdev_ops;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001416
1417 platform_set_drvdata(pdev, netdev);
1418
1419 /* setup private data */
1420 priv = netdev_priv(netdev);
1421 priv->netdev = netdev;
1422 priv->dev = &pdev->dev;
Benjamin Herrenschmidt855944c2017-04-05 12:28:50 +10001423 INIT_WORK(&priv->reset_task, ftgmac100_reset_task);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001424
1425 spin_lock_init(&priv->tx_lock);
1426
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001427 /* map io memory */
1428 priv->res = request_mem_region(res->start, resource_size(res),
1429 dev_name(&pdev->dev));
1430 if (!priv->res) {
1431 dev_err(&pdev->dev, "Could not reserve memory region\n");
1432 err = -ENOMEM;
1433 goto err_req_mem;
1434 }
1435
1436 priv->base = ioremap(res->start, resource_size(res));
1437 if (!priv->base) {
1438 dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
1439 err = -EIO;
1440 goto err_ioremap;
1441 }
1442
Benjamin Herrenschmidt60b28a12017-04-05 12:28:41 +10001443 netdev->irq = irq;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001444
Gavin Shan113ce102016-07-19 11:54:22 +10001445 /* MAC address from chip or random one */
1446 ftgmac100_setup_mac(priv);
1447
Joel Stanley2a0ab8eb2016-09-22 08:35:00 +09301448 if (of_machine_is_compatible("aspeed,ast2400") ||
1449 of_machine_is_compatible("aspeed,ast2500")) {
1450 priv->rxdes0_edorr_mask = BIT(30);
1451 priv->txdes0_edotr_mask = BIT(30);
1452 } else {
1453 priv->rxdes0_edorr_mask = BIT(15);
1454 priv->txdes0_edotr_mask = BIT(15);
1455 }
1456
Gavin Shanbd466c32016-07-19 11:54:23 +10001457 if (pdev->dev.of_node &&
1458 of_get_property(pdev->dev.of_node, "use-ncsi", NULL)) {
1459 if (!IS_ENABLED(CONFIG_NET_NCSI)) {
1460 dev_err(&pdev->dev, "NCSI stack not enabled\n");
1461 goto err_ncsi_dev;
1462 }
1463
1464 dev_info(&pdev->dev, "Using NCSI interface\n");
1465 priv->use_ncsi = true;
1466 priv->ndev = ncsi_register_dev(netdev, ftgmac100_ncsi_handler);
1467 if (!priv->ndev)
1468 goto err_ncsi_dev;
1469 } else {
1470 priv->use_ncsi = false;
1471 err = ftgmac100_setup_mdio(netdev);
1472 if (err)
1473 goto err_setup_mdio;
1474 }
1475
1476 /* We have to disable on-chip IP checksum functionality
1477 * when NCSI is enabled on the interface. It doesn't work
1478 * in that case.
1479 */
Benjamin Herrenschmidt67202192017-04-06 11:02:46 +10001480 netdev->features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_GRO;
Gavin Shanbd466c32016-07-19 11:54:23 +10001481 if (priv->use_ncsi &&
1482 of_get_property(pdev->dev.of_node, "no-hw-checksum", NULL))
1483 netdev->features &= ~NETIF_F_IP_CSUM;
1484
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001485
1486 /* register network device */
1487 err = register_netdev(netdev);
1488 if (err) {
1489 dev_err(&pdev->dev, "Failed to register netdev\n");
1490 goto err_register_netdev;
1491 }
1492
Benjamin Herrenschmidt60b28a12017-04-05 12:28:41 +10001493 netdev_info(netdev, "irq %d, mapped at %p\n", netdev->irq, priv->base);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001494
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001495 return 0;
1496
Gavin Shanbd466c32016-07-19 11:54:23 +10001497err_ncsi_dev:
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001498err_register_netdev:
Gavin Shaneb418182016-07-19 11:54:21 +10001499 ftgmac100_destroy_mdio(netdev);
1500err_setup_mdio:
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001501 iounmap(priv->base);
1502err_ioremap:
1503 release_resource(priv->res);
1504err_req_mem:
1505 netif_napi_del(&priv->napi);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001506 free_netdev(netdev);
1507err_alloc_etherdev:
1508 return err;
1509}
1510
Dmitry Torokhovbe125022017-03-01 17:24:47 -08001511static int ftgmac100_remove(struct platform_device *pdev)
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001512{
1513 struct net_device *netdev;
1514 struct ftgmac100 *priv;
1515
1516 netdev = platform_get_drvdata(pdev);
1517 priv = netdev_priv(netdev);
1518
1519 unregister_netdev(netdev);
Benjamin Herrenschmidt855944c2017-04-05 12:28:50 +10001520
1521 /* There's a small chance the reset task will have been re-queued,
1522 * during stop, make sure it's gone before we free the structure.
1523 */
1524 cancel_work_sync(&priv->reset_task);
1525
Gavin Shaneb418182016-07-19 11:54:21 +10001526 ftgmac100_destroy_mdio(netdev);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001527
1528 iounmap(priv->base);
1529 release_resource(priv->res);
1530
1531 netif_napi_del(&priv->napi);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001532 free_netdev(netdev);
1533 return 0;
1534}
1535
Gavin Shanbb168e22016-07-19 11:54:24 +10001536static const struct of_device_id ftgmac100_of_match[] = {
1537 { .compatible = "faraday,ftgmac100" },
1538 { }
1539};
1540MODULE_DEVICE_TABLE(of, ftgmac100_of_match);
1541
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001542static struct platform_driver ftgmac100_driver = {
Gavin Shanbb168e22016-07-19 11:54:24 +10001543 .probe = ftgmac100_probe,
Dmitry Torokhovbe125022017-03-01 17:24:47 -08001544 .remove = ftgmac100_remove,
Gavin Shanbb168e22016-07-19 11:54:24 +10001545 .driver = {
1546 .name = DRV_NAME,
1547 .of_match_table = ftgmac100_of_match,
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001548 },
1549};
Sachin Kamat14f645d2013-03-18 01:50:48 +00001550module_platform_driver(ftgmac100_driver);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001551
1552MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
1553MODULE_DESCRIPTION("FTGMAC100 driver");
1554MODULE_LICENSE("GPL");