blob: 949b48c0eae67d480ced7e7feb63555f16f6af7b [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
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +100043/* Arbitrary values, I am not sure the HW has limits */
44#define MAX_RX_QUEUE_ENTRIES 1024
45#define MAX_TX_QUEUE_ENTRIES 1024
46#define MIN_RX_QUEUE_ENTRIES 32
47#define MIN_TX_QUEUE_ENTRIES 32
48
49/* Defaults */
Benjamin Herrenschmidtbd3e4fd2017-04-12 13:27:10 +100050#define DEF_RX_QUEUE_ENTRIES 128
51#define DEF_TX_QUEUE_ENTRIES 128
Po-Yu Chuang69785b72011-06-08 23:32:48 +000052
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +100053#define MAX_PKT_SIZE 1536
54#define RX_BUF_SIZE MAX_PKT_SIZE /* must be smaller than 0x3fff */
Po-Yu Chuang69785b72011-06-08 23:32:48 +000055
Benjamin Herrenschmidt6ad3d7e2017-04-10 11:15:21 +100056/* Min number of tx ring entries before stopping queue */
Benjamin Herrenschmidt6db74702017-04-10 11:15:25 +100057#define TX_THRESHOLD (MAX_SKB_FRAGS + 1)
Benjamin Herrenschmidt6ad3d7e2017-04-10 11:15:21 +100058
Po-Yu Chuang69785b72011-06-08 23:32:48 +000059struct ftgmac100 {
Benjamin Herrenschmidt831fb332017-04-05 12:28:43 +100060 /* Registers */
Po-Yu Chuang69785b72011-06-08 23:32:48 +000061 struct resource *res;
62 void __iomem *base;
Po-Yu Chuang69785b72011-06-08 23:32:48 +000063
Benjamin Herrenschmidt831fb332017-04-05 12:28:43 +100064 /* Rx ring */
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +100065 unsigned int rx_q_entries;
66 struct ftgmac100_rxdes *rxdes;
67 dma_addr_t rxdes_dma;
68 struct sk_buff **rx_skbs;
Po-Yu Chuang69785b72011-06-08 23:32:48 +000069 unsigned int rx_pointer;
Benjamin Herrenschmidt831fb332017-04-05 12:28:43 +100070 u32 rxdes0_edorr_mask;
71
72 /* Tx ring */
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +100073 unsigned int tx_q_entries;
74 struct ftgmac100_txdes *txdes;
75 dma_addr_t txdes_dma;
76 struct sk_buff **tx_skbs;
Po-Yu Chuang69785b72011-06-08 23:32:48 +000077 unsigned int tx_clean_pointer;
78 unsigned int tx_pointer;
Benjamin Herrenschmidt831fb332017-04-05 12:28:43 +100079 u32 txdes0_edotr_mask;
Po-Yu Chuang69785b72011-06-08 23:32:48 +000080
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +100081 /* Used to signal the reset task of ring change request */
82 unsigned int new_rx_q_entries;
83 unsigned int new_tx_q_entries;
84
Benjamin Herrenschmidtd72e01a2017-04-06 11:02:45 +100085 /* Scratch page to use when rx skb alloc fails */
86 void *rx_scratch;
87 dma_addr_t rx_scratch_dma;
88
Benjamin Herrenschmidt831fb332017-04-05 12:28:43 +100089 /* Component structures */
Po-Yu Chuang69785b72011-06-08 23:32:48 +000090 struct net_device *netdev;
91 struct device *dev;
Gavin Shanbd466c32016-07-19 11:54:23 +100092 struct ncsi_dev *ndev;
Po-Yu Chuang69785b72011-06-08 23:32:48 +000093 struct napi_struct napi;
Benjamin Herrenschmidt855944c2017-04-05 12:28:50 +100094 struct work_struct reset_task;
Po-Yu Chuang69785b72011-06-08 23:32:48 +000095 struct mii_bus *mii_bus;
Andrew Jeffery7906a4d2016-09-22 08:34:59 +093096
Benjamin Herrenschmidt831fb332017-04-05 12:28:43 +100097 /* Link management */
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +100098 int cur_speed;
99 int cur_duplex;
Benjamin Herrenschmidt831fb332017-04-05 12:28:43 +1000100 bool use_ncsi;
101
Benjamin Herrenschmidt7c8e5142017-04-18 08:36:59 +1000102 /* Flow control settings */
103 bool tx_pause;
104 bool rx_pause;
105 bool aneg_pause;
106
Benjamin Herrenschmidt831fb332017-04-05 12:28:43 +1000107 /* Misc */
Benjamin Herrenschmidt10cbd642017-04-05 12:28:53 +1000108 bool need_mac_restart;
Benjamin Herrenschmidt78d28542017-04-12 13:27:02 +1000109 bool is_aspeed;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000110};
111
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +1000112static int ftgmac100_reset_mac(struct ftgmac100 *priv, u32 maccr)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000113{
114 struct net_device *netdev = priv->netdev;
115 int i;
116
117 /* NOTE: reset clears all registers */
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +1000118 iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR);
119 iowrite32(maccr | FTGMAC100_MACCR_SW_RST,
120 priv->base + FTGMAC100_OFFSET_MACCR);
121 for (i = 0; i < 50; i++) {
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000122 unsigned int maccr;
123
124 maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR);
125 if (!(maccr & FTGMAC100_MACCR_SW_RST))
126 return 0;
127
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +1000128 udelay(1);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000129 }
130
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +1000131 netdev_err(netdev, "Hardware reset failed\n");
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000132 return -EIO;
133}
134
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +1000135static int ftgmac100_reset_and_config_mac(struct ftgmac100 *priv)
136{
137 u32 maccr = 0;
138
139 switch (priv->cur_speed) {
140 case SPEED_10:
141 case 0: /* no link */
142 break;
143
144 case SPEED_100:
145 maccr |= FTGMAC100_MACCR_FAST_MODE;
146 break;
147
148 case SPEED_1000:
149 maccr |= FTGMAC100_MACCR_GIGA_MODE;
150 break;
151 default:
152 netdev_err(priv->netdev, "Unknown speed %d !\n",
153 priv->cur_speed);
154 break;
155 }
156
157 /* (Re)initialize the queue pointers */
158 priv->rx_pointer = 0;
159 priv->tx_clean_pointer = 0;
160 priv->tx_pointer = 0;
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +1000161
162 /* The doc says reset twice with 10us interval */
163 if (ftgmac100_reset_mac(priv, maccr))
164 return -EIO;
165 usleep_range(10, 1000);
166 return ftgmac100_reset_mac(priv, maccr);
167}
168
Benjamin Herrenschmidtf39c71b2017-04-12 13:27:05 +1000169static void ftgmac100_write_mac_addr(struct ftgmac100 *priv, const u8 *mac)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000170{
171 unsigned int maddr = mac[0] << 8 | mac[1];
172 unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
173
174 iowrite32(maddr, priv->base + FTGMAC100_OFFSET_MAC_MADR);
175 iowrite32(laddr, priv->base + FTGMAC100_OFFSET_MAC_LADR);
176}
177
Benjamin Herrenschmidtba1b1232017-04-12 13:27:06 +1000178static void ftgmac100_initial_mac(struct ftgmac100 *priv)
Gavin Shan113ce102016-07-19 11:54:22 +1000179{
180 u8 mac[ETH_ALEN];
181 unsigned int m;
182 unsigned int l;
183 void *addr;
184
185 addr = device_get_mac_address(priv->dev, mac, ETH_ALEN);
186 if (addr) {
187 ether_addr_copy(priv->netdev->dev_addr, mac);
188 dev_info(priv->dev, "Read MAC address %pM from device tree\n",
189 mac);
190 return;
191 }
192
193 m = ioread32(priv->base + FTGMAC100_OFFSET_MAC_MADR);
194 l = ioread32(priv->base + FTGMAC100_OFFSET_MAC_LADR);
195
196 mac[0] = (m >> 8) & 0xff;
197 mac[1] = m & 0xff;
198 mac[2] = (l >> 24) & 0xff;
199 mac[3] = (l >> 16) & 0xff;
200 mac[4] = (l >> 8) & 0xff;
201 mac[5] = l & 0xff;
202
Gavin Shan113ce102016-07-19 11:54:22 +1000203 if (is_valid_ether_addr(mac)) {
204 ether_addr_copy(priv->netdev->dev_addr, mac);
205 dev_info(priv->dev, "Read MAC address %pM from chip\n", mac);
206 } else {
207 eth_hw_addr_random(priv->netdev);
208 dev_info(priv->dev, "Generated random MAC address %pM\n",
209 priv->netdev->dev_addr);
210 }
211}
212
213static int ftgmac100_set_mac_addr(struct net_device *dev, void *p)
214{
215 int ret;
216
217 ret = eth_prepare_mac_addr_change(dev, p);
218 if (ret < 0)
219 return ret;
220
221 eth_commit_mac_addr_change(dev, p);
Benjamin Herrenschmidtf39c71b2017-04-12 13:27:05 +1000222 ftgmac100_write_mac_addr(netdev_priv(dev), dev->dev_addr);
Gavin Shan113ce102016-07-19 11:54:22 +1000223
224 return 0;
225}
226
Benjamin Herrenschmidt7c8e5142017-04-18 08:36:59 +1000227static void ftgmac100_config_pause(struct ftgmac100 *priv)
228{
229 u32 fcr = FTGMAC100_FCR_PAUSE_TIME(16);
230
231 /* Throttle tx queue when receiving pause frames */
232 if (priv->rx_pause)
233 fcr |= FTGMAC100_FCR_FC_EN;
234
235 /* Enables sending pause frames when the RX queue is past a
236 * certain threshold.
237 */
238 if (priv->tx_pause)
239 fcr |= FTGMAC100_FCR_FCTHR_EN;
240
241 iowrite32(fcr, priv->base + FTGMAC100_OFFSET_FCR);
242}
243
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000244static void ftgmac100_init_hw(struct ftgmac100 *priv)
245{
Benjamin Herrenschmidt3833dc62017-04-12 13:27:08 +1000246 u32 reg, rfifo_sz, tfifo_sz;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000247
Benjamin Herrenschmidt3833dc62017-04-12 13:27:08 +1000248 /* Clear stale interrupts */
249 reg = ioread32(priv->base + FTGMAC100_OFFSET_ISR);
250 iowrite32(reg, priv->base + FTGMAC100_OFFSET_ISR);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000251
Benjamin Herrenschmidt8eecf7c2017-04-12 13:27:07 +1000252 /* Setup RX ring buffer base */
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000253 iowrite32(priv->rxdes_dma, priv->base + FTGMAC100_OFFSET_RXR_BADR);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000254
Benjamin Herrenschmidt8eecf7c2017-04-12 13:27:07 +1000255 /* Setup TX ring buffer base */
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000256 iowrite32(priv->txdes_dma, priv->base + FTGMAC100_OFFSET_NPTXR_BADR);
Benjamin Herrenschmidt8eecf7c2017-04-12 13:27:07 +1000257
258 /* Configure RX buffer size */
259 iowrite32(FTGMAC100_RBSR_SIZE(RX_BUF_SIZE),
260 priv->base + FTGMAC100_OFFSET_RBSR);
261
262 /* Set RX descriptor autopoll */
263 iowrite32(FTGMAC100_APTC_RXPOLL_CNT(1),
264 priv->base + FTGMAC100_OFFSET_APTC);
265
266 /* Write MAC address */
Benjamin Herrenschmidtf39c71b2017-04-12 13:27:05 +1000267 ftgmac100_write_mac_addr(priv, priv->netdev->dev_addr);
Benjamin Herrenschmidt3833dc62017-04-12 13:27:08 +1000268
269 /* Configure descriptor sizes and increase burst sizes according
270 * to values in Aspeed SDK. The FIFO arbitration is enabled and
271 * the thresholds set based on the recommended values in the
272 * AST2400 specification.
273 */
274 iowrite32(FTGMAC100_DBLAC_RXDES_SIZE(2) | /* 2*8 bytes RX descs */
275 FTGMAC100_DBLAC_TXDES_SIZE(2) | /* 2*8 bytes TX descs */
276 FTGMAC100_DBLAC_RXBURST_SIZE(3) | /* 512 bytes max RX bursts */
277 FTGMAC100_DBLAC_TXBURST_SIZE(3) | /* 512 bytes max TX bursts */
278 FTGMAC100_DBLAC_RX_THR_EN | /* Enable fifo threshold arb */
279 FTGMAC100_DBLAC_RXFIFO_HTHR(6) | /* 6/8 of FIFO high threshold */
280 FTGMAC100_DBLAC_RXFIFO_LTHR(2), /* 2/8 of FIFO low threshold */
281 priv->base + FTGMAC100_OFFSET_DBLAC);
282
283 /* Interrupt mitigation configured for 1 interrupt/packet. HW interrupt
284 * mitigation doesn't seem to provide any benefit with NAPI so leave
285 * it at that.
286 */
287 iowrite32(FTGMAC100_ITC_RXINT_THR(1) |
288 FTGMAC100_ITC_TXINT_THR(1),
289 priv->base + FTGMAC100_OFFSET_ITC);
290
291 /* Configure FIFO sizes in the TPAFCR register */
292 reg = ioread32(priv->base + FTGMAC100_OFFSET_FEAR);
293 rfifo_sz = reg & 0x00000007;
294 tfifo_sz = (reg >> 3) & 0x00000007;
295 reg = ioread32(priv->base + FTGMAC100_OFFSET_TPAFCR);
296 reg &= ~0x3f000000;
297 reg |= (tfifo_sz << 27);
298 reg |= (rfifo_sz << 24);
299 iowrite32(reg, priv->base + FTGMAC100_OFFSET_TPAFCR);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000300}
301
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +1000302static void ftgmac100_start_hw(struct ftgmac100 *priv)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000303{
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +1000304 u32 maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000305
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +1000306 /* Keep the original GMAC and FAST bits */
307 maccr &= (FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_GIGA_MODE);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000308
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +1000309 /* Add all the main enable bits */
310 maccr |= FTGMAC100_MACCR_TXDMA_EN |
311 FTGMAC100_MACCR_RXDMA_EN |
312 FTGMAC100_MACCR_TXMAC_EN |
313 FTGMAC100_MACCR_RXMAC_EN |
314 FTGMAC100_MACCR_CRC_APD |
315 FTGMAC100_MACCR_PHY_LINK_LEVEL |
316 FTGMAC100_MACCR_RX_RUNT |
317 FTGMAC100_MACCR_RX_BROADPKT;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000318
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +1000319 /* Add other bits as needed */
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +1000320 if (priv->cur_duplex == DUPLEX_FULL)
321 maccr |= FTGMAC100_MACCR_FULLDUP;
322
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +1000323 /* Hit the HW */
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000324 iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR);
325}
326
327static void ftgmac100_stop_hw(struct ftgmac100 *priv)
328{
329 iowrite32(0, priv->base + FTGMAC100_OFFSET_MACCR);
330}
331
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000332static int ftgmac100_alloc_rx_buf(struct ftgmac100 *priv, unsigned int entry,
333 struct ftgmac100_rxdes *rxdes, gfp_t gfp)
Benjamin Herrenschmidtc06f73f2017-04-06 11:02:43 +1000334{
335 struct net_device *netdev = priv->netdev;
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000336 struct sk_buff *skb;
Benjamin Herrenschmidtc06f73f2017-04-06 11:02:43 +1000337 dma_addr_t map;
Benjamin Herrenschmidtd72e01a2017-04-06 11:02:45 +1000338 int err;
Benjamin Herrenschmidtc06f73f2017-04-06 11:02:43 +1000339
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000340 skb = netdev_alloc_skb_ip_align(netdev, RX_BUF_SIZE);
341 if (unlikely(!skb)) {
Benjamin Herrenschmidtc06f73f2017-04-06 11:02:43 +1000342 if (net_ratelimit())
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000343 netdev_warn(netdev, "failed to allocate rx skb\n");
Benjamin Herrenschmidtd72e01a2017-04-06 11:02:45 +1000344 err = -ENOMEM;
345 map = priv->rx_scratch_dma;
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000346 } else {
347 map = dma_map_single(priv->dev, skb->data, RX_BUF_SIZE,
348 DMA_FROM_DEVICE);
349 if (unlikely(dma_mapping_error(priv->dev, map))) {
350 if (net_ratelimit())
351 netdev_err(netdev, "failed to map rx page\n");
352 dev_kfree_skb_any(skb);
353 map = priv->rx_scratch_dma;
354 skb = NULL;
355 err = -ENOMEM;
356 }
Benjamin Herrenschmidtc06f73f2017-04-06 11:02:43 +1000357 }
358
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000359 /* Store skb */
360 priv->rx_skbs[entry] = skb;
Benjamin Herrenschmidtc06f73f2017-04-06 11:02:43 +1000361
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000362 /* Store DMA address into RX desc */
Benjamin Herrenschmidt4ca24152017-04-06 11:02:51 +1000363 rxdes->rxdes3 = cpu_to_le32(map);
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000364
365 /* Ensure the above is ordered vs clearing the OWN bit */
366 dma_wmb();
367
Benjamin Herrenschmidt4ca24152017-04-06 11:02:51 +1000368 /* Clean status (which resets own bit) */
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000369 if (entry == (priv->rx_q_entries - 1))
Benjamin Herrenschmidt4ca24152017-04-06 11:02:51 +1000370 rxdes->rxdes0 = cpu_to_le32(priv->rxdes0_edorr_mask);
371 else
372 rxdes->rxdes0 = 0;
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000373
Benjamin Herrenschmidtc06f73f2017-04-06 11:02:43 +1000374 return 0;
375}
376
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000377static unsigned int ftgmac100_next_rx_pointer(struct ftgmac100 *priv,
378 unsigned int pointer)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000379{
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000380 return (pointer + 1) & (priv->rx_q_entries - 1);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000381}
382
Benjamin Herrenschmidt4ca24152017-04-06 11:02:51 +1000383static void ftgmac100_rx_packet_error(struct ftgmac100 *priv, u32 status)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000384{
385 struct net_device *netdev = priv->netdev;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000386
Benjamin Herrenschmidt4ca24152017-04-06 11:02:51 +1000387 if (status & FTGMAC100_RXDES0_RX_ERR)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000388 netdev->stats.rx_errors++;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000389
Benjamin Herrenschmidt4ca24152017-04-06 11:02:51 +1000390 if (status & FTGMAC100_RXDES0_CRC_ERR)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000391 netdev->stats.rx_crc_errors++;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000392
Benjamin Herrenschmidt4ca24152017-04-06 11:02:51 +1000393 if (status & (FTGMAC100_RXDES0_FTL |
394 FTGMAC100_RXDES0_RUNT |
395 FTGMAC100_RXDES0_RX_ODD_NB))
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000396 netdev->stats.rx_length_errors++;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000397}
398
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000399static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
400{
401 struct net_device *netdev = priv->netdev;
402 struct ftgmac100_rxdes *rxdes;
403 struct sk_buff *skb;
Benjamin Herrenschmidt01dd70b2017-04-06 11:02:48 +1000404 unsigned int pointer, size;
Benjamin Herrenschmidtd9306552017-04-06 11:02:52 +1000405 u32 status, csum_vlan;
Benjamin Herrenschmidtb1977bf2017-04-06 11:02:44 +1000406 dma_addr_t map;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000407
Benjamin Herrenschmidt01dd70b2017-04-06 11:02:48 +1000408 /* Grab next RX descriptor */
409 pointer = priv->rx_pointer;
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000410 rxdes = &priv->rxdes[pointer];
Benjamin Herrenschmidt01dd70b2017-04-06 11:02:48 +1000411
Benjamin Herrenschmidt4ca24152017-04-06 11:02:51 +1000412 /* Grab descriptor status */
413 status = le32_to_cpu(rxdes->rxdes0);
414
Benjamin Herrenschmidt01dd70b2017-04-06 11:02:48 +1000415 /* Do we have a packet ? */
Benjamin Herrenschmidt4ca24152017-04-06 11:02:51 +1000416 if (!(status & FTGMAC100_RXDES0_RXPKT_RDY))
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000417 return false;
418
Benjamin Herrenschmidt027f4262017-04-06 11:02:50 +1000419 /* Order subsequent reads with the test for the ready bit */
420 dma_rmb();
421
Benjamin Herrenschmidt01dd70b2017-04-06 11:02:48 +1000422 /* We don't cope with fragmented RX packets */
Benjamin Herrenschmidt4ca24152017-04-06 11:02:51 +1000423 if (unlikely(!(status & FTGMAC100_RXDES0_FRS) ||
424 !(status & FTGMAC100_RXDES0_LRS)))
Benjamin Herrenschmidt01dd70b2017-04-06 11:02:48 +1000425 goto drop;
426
Benjamin Herrenschmidtd9306552017-04-06 11:02:52 +1000427 /* Grab received size and csum vlan field in the descriptor */
428 size = status & FTGMAC100_RXDES0_VDBC;
429 csum_vlan = le32_to_cpu(rxdes->rxdes1);
430
Benjamin Herrenschmidt01dd70b2017-04-06 11:02:48 +1000431 /* Any error (other than csum offload) flagged ? */
Benjamin Herrenschmidt4ca24152017-04-06 11:02:51 +1000432 if (unlikely(status & RXDES0_ANY_ERROR)) {
Benjamin Herrenschmidtd9306552017-04-06 11:02:52 +1000433 /* Correct for incorrect flagging of runt packets
434 * with vlan tags... Just accept a runt packet that
435 * has been flagged as vlan and whose size is at
436 * least 60 bytes.
437 */
438 if ((status & FTGMAC100_RXDES0_RUNT) &&
439 (csum_vlan & FTGMAC100_RXDES1_VLANTAG_AVAIL) &&
440 (size >= 60))
441 status &= ~FTGMAC100_RXDES0_RUNT;
442
443 /* Any error still in there ? */
444 if (status & RXDES0_ANY_ERROR) {
445 ftgmac100_rx_packet_error(priv, status);
446 goto drop;
447 }
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000448 }
449
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000450 /* If the packet had no skb (failed to allocate earlier)
Benjamin Herrenschmidtd72e01a2017-04-06 11:02:45 +1000451 * then try to allocate one and skip
452 */
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000453 skb = priv->rx_skbs[pointer];
454 if (!unlikely(skb)) {
455 ftgmac100_alloc_rx_buf(priv, pointer, rxdes, GFP_ATOMIC);
Benjamin Herrenschmidt01dd70b2017-04-06 11:02:48 +1000456 goto drop;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000457 }
458
Benjamin Herrenschmidt4ca24152017-04-06 11:02:51 +1000459 if (unlikely(status & FTGMAC100_RXDES0_MULTICAST))
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000460 netdev->stats.multicast++;
461
Benjamin Herrenschmidt67202192017-04-06 11:02:46 +1000462 /* If the HW found checksum errors, bounce it to software.
463 *
464 * If we didn't, we need to see if the packet was recognized
465 * by HW as one of the supported checksummed protocols before
466 * we accept the HW test results.
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000467 */
Benjamin Herrenschmidt67202192017-04-06 11:02:46 +1000468 if (netdev->features & NETIF_F_RXCSUM) {
Benjamin Herrenschmidtd9306552017-04-06 11:02:52 +1000469 u32 err_bits = FTGMAC100_RXDES1_TCP_CHKSUM_ERR |
470 FTGMAC100_RXDES1_UDP_CHKSUM_ERR |
471 FTGMAC100_RXDES1_IP_CHKSUM_ERR;
Benjamin Herrenschmidt67202192017-04-06 11:02:46 +1000472 if ((csum_vlan & err_bits) ||
Benjamin Herrenschmidtd9306552017-04-06 11:02:52 +1000473 !(csum_vlan & FTGMAC100_RXDES1_PROT_MASK))
Benjamin Herrenschmidt67202192017-04-06 11:02:46 +1000474 skb->ip_summed = CHECKSUM_NONE;
475 else
476 skb->ip_summed = CHECKSUM_UNNECESSARY;
477 }
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000478
Benjamin Herrenschmidtd9306552017-04-06 11:02:52 +1000479 /* Transfer received size to skb */
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000480 skb_put(skb, size);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000481
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000482 /* Tear down DMA mapping, do necessary cache management */
Benjamin Herrenschmidt4ca24152017-04-06 11:02:51 +1000483 map = le32_to_cpu(rxdes->rxdes3);
484
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000485#if defined(CONFIG_ARM) && !defined(CONFIG_ARM_DMA_USE_IOMMU)
486 /* When we don't have an iommu, we can save cycles by not
487 * invalidating the cache for the part of the packet that
488 * wasn't received.
489 */
490 dma_unmap_single(priv->dev, map, size, DMA_FROM_DEVICE);
491#else
492 dma_unmap_single(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
493#endif
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000494
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000495
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000496 /* Resplenish rx ring */
497 ftgmac100_alloc_rx_buf(priv, pointer, rxdes, GFP_ATOMIC);
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000498 priv->rx_pointer = ftgmac100_next_rx_pointer(priv, pointer);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000499
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000500 skb->protocol = eth_type_trans(skb, netdev);
501
502 netdev->stats.rx_packets++;
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000503 netdev->stats.rx_bytes += size;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000504
505 /* push packet to protocol stack */
Benjamin Herrenschmidt67202192017-04-06 11:02:46 +1000506 if (skb->ip_summed == CHECKSUM_NONE)
507 netif_receive_skb(skb);
508 else
509 napi_gro_receive(&priv->napi, skb);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000510
511 (*processed)++;
512 return true;
Benjamin Herrenschmidt01dd70b2017-04-06 11:02:48 +1000513
514 drop:
515 /* Clean rxdes0 (which resets own bit) */
Benjamin Herrenschmidt4ca24152017-04-06 11:02:51 +1000516 rxdes->rxdes0 = cpu_to_le32(status & priv->rxdes0_edorr_mask);
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000517 priv->rx_pointer = ftgmac100_next_rx_pointer(priv, pointer);
Benjamin Herrenschmidt01dd70b2017-04-06 11:02:48 +1000518 netdev->stats.rx_dropped++;
519 return true;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000520}
521
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000522static u32 ftgmac100_base_tx_ctlstat(struct ftgmac100 *priv,
523 unsigned int index)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000524{
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000525 if (index == (priv->tx_q_entries - 1))
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000526 return priv->txdes0_edotr_mask;
527 else
528 return 0;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000529}
530
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000531static unsigned int ftgmac100_next_tx_pointer(struct ftgmac100 *priv,
532 unsigned int pointer)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000533{
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000534 return (pointer + 1) & (priv->tx_q_entries - 1);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000535}
536
Benjamin Herrenschmidt6ad3d7e2017-04-10 11:15:21 +1000537static u32 ftgmac100_tx_buf_avail(struct ftgmac100 *priv)
538{
539 /* Returns the number of available slots in the TX queue
540 *
541 * This always leaves one free slot so we don't have to
542 * worry about empty vs. full, and this simplifies the
543 * test for ftgmac100_tx_buf_cleanable() below
544 */
545 return (priv->tx_clean_pointer - priv->tx_pointer - 1) &
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000546 (priv->tx_q_entries - 1);
Benjamin Herrenschmidt6ad3d7e2017-04-10 11:15:21 +1000547}
548
549static bool ftgmac100_tx_buf_cleanable(struct ftgmac100 *priv)
550{
551 return priv->tx_pointer != priv->tx_clean_pointer;
552}
553
Benjamin Herrenschmidt42c2d192017-04-10 11:15:23 +1000554static void ftgmac100_free_tx_packet(struct ftgmac100 *priv,
555 unsigned int pointer,
556 struct sk_buff *skb,
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000557 struct ftgmac100_txdes *txdes,
558 u32 ctl_stat)
Benjamin Herrenschmidt42c2d192017-04-10 11:15:23 +1000559{
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000560 dma_addr_t map = le32_to_cpu(txdes->txdes3);
561 size_t len;
Benjamin Herrenschmidt42c2d192017-04-10 11:15:23 +1000562
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000563 if (ctl_stat & FTGMAC100_TXDES0_FTS) {
564 len = skb_headlen(skb);
565 dma_unmap_single(priv->dev, map, len, DMA_TO_DEVICE);
Benjamin Herrenschmidt6db74702017-04-10 11:15:25 +1000566 } else {
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000567 len = FTGMAC100_TXDES0_TXBUF_SIZE(ctl_stat);
568 dma_unmap_page(priv->dev, map, len, DMA_TO_DEVICE);
Benjamin Herrenschmidt6db74702017-04-10 11:15:25 +1000569 }
Benjamin Herrenschmidt42c2d192017-04-10 11:15:23 +1000570
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000571 /* Free SKB on last segment */
572 if (ctl_stat & FTGMAC100_TXDES0_LTS)
Benjamin Herrenschmidt6db74702017-04-10 11:15:25 +1000573 dev_kfree_skb(skb);
Benjamin Herrenschmidt42c2d192017-04-10 11:15:23 +1000574 priv->tx_skbs[pointer] = NULL;
Benjamin Herrenschmidt42c2d192017-04-10 11:15:23 +1000575}
576
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000577static bool ftgmac100_tx_complete_packet(struct ftgmac100 *priv)
578{
579 struct net_device *netdev = priv->netdev;
580 struct ftgmac100_txdes *txdes;
581 struct sk_buff *skb;
Benjamin Herrenschmidt42c2d192017-04-10 11:15:23 +1000582 unsigned int pointer;
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000583 u32 ctl_stat;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000584
Benjamin Herrenschmidt83617312017-04-10 11:15:20 +1000585 pointer = priv->tx_clean_pointer;
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000586 txdes = &priv->txdes[pointer];
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000587
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000588 ctl_stat = le32_to_cpu(txdes->txdes0);
589 if (ctl_stat & FTGMAC100_TXDES0_TXDMA_OWN)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000590 return false;
591
Benjamin Herrenschmidt83617312017-04-10 11:15:20 +1000592 skb = priv->tx_skbs[pointer];
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000593 netdev->stats.tx_packets++;
594 netdev->stats.tx_bytes += skb->len;
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000595 ftgmac100_free_tx_packet(priv, pointer, skb, txdes, ctl_stat);
596 txdes->txdes0 = cpu_to_le32(ctl_stat & priv->txdes0_edotr_mask);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000597
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000598 priv->tx_clean_pointer = ftgmac100_next_tx_pointer(priv, pointer);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000599
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000600 return true;
601}
602
603static void ftgmac100_tx_complete(struct ftgmac100 *priv)
604{
Benjamin Herrenschmidt6ad3d7e2017-04-10 11:15:21 +1000605 struct net_device *netdev = priv->netdev;
606
607 /* Process all completed packets */
608 while (ftgmac100_tx_buf_cleanable(priv) &&
609 ftgmac100_tx_complete_packet(priv))
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000610 ;
Benjamin Herrenschmidt6ad3d7e2017-04-10 11:15:21 +1000611
612 /* Restart queue if needed */
613 smp_mb();
614 if (unlikely(netif_queue_stopped(netdev) &&
615 ftgmac100_tx_buf_avail(priv) >= TX_THRESHOLD)) {
616 struct netdev_queue *txq;
617
618 txq = netdev_get_tx_queue(netdev, 0);
619 __netif_tx_lock(txq, smp_processor_id());
620 if (netif_queue_stopped(netdev) &&
621 ftgmac100_tx_buf_avail(priv) >= TX_THRESHOLD)
622 netif_wake_queue(netdev);
623 __netif_tx_unlock(txq);
624 }
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000625}
626
Benjamin Herrenschmidt05690d62017-04-12 13:27:01 +1000627static bool ftgmac100_prep_tx_csum(struct sk_buff *skb, u32 *csum_vlan)
628{
629 if (skb->protocol == cpu_to_be16(ETH_P_IP)) {
630 u8 ip_proto = ip_hdr(skb)->protocol;
631
632 *csum_vlan |= FTGMAC100_TXDES1_IP_CHKSUM;
633 switch(ip_proto) {
634 case IPPROTO_TCP:
635 *csum_vlan |= FTGMAC100_TXDES1_TCP_CHKSUM;
636 return true;
637 case IPPROTO_UDP:
638 *csum_vlan |= FTGMAC100_TXDES1_UDP_CHKSUM;
639 return true;
640 case IPPROTO_IP:
641 return true;
642 }
643 }
644 return skb_checksum_help(skb) == 0;
645}
646
Benjamin Herrenschmidt43b25ee2017-04-10 11:15:17 +1000647static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
648 struct net_device *netdev)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000649{
Benjamin Herrenschmidt43b25ee2017-04-10 11:15:17 +1000650 struct ftgmac100 *priv = netdev_priv(netdev);
Benjamin Herrenschmidt6db74702017-04-10 11:15:25 +1000651 struct ftgmac100_txdes *txdes, *first;
652 unsigned int pointer, nfrags, len, i, j;
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000653 u32 f_ctl_stat, ctl_stat, csum_vlan;
Benjamin Herrenschmidt43b25ee2017-04-10 11:15:17 +1000654 dma_addr_t map;
655
Benjamin Herrenschmidt9b0f7712017-04-10 11:15:19 +1000656 /* The HW doesn't pad small frames */
657 if (eth_skb_pad(skb)) {
658 netdev->stats.tx_dropped++;
659 return NETDEV_TX_OK;
660 }
661
662 /* Reject oversize packets */
Benjamin Herrenschmidt43b25ee2017-04-10 11:15:17 +1000663 if (unlikely(skb->len > MAX_PKT_SIZE)) {
664 if (net_ratelimit())
665 netdev_dbg(netdev, "tx packet too big\n");
Benjamin Herrenschmidt3e427a32017-04-10 11:15:18 +1000666 goto drop;
Benjamin Herrenschmidt43b25ee2017-04-10 11:15:17 +1000667 }
668
Benjamin Herrenschmidt6db74702017-04-10 11:15:25 +1000669 /* Do we have a limit on #fragments ? I yet have to get a reply
670 * from Aspeed. If there's one I haven't hit it.
671 */
672 nfrags = skb_shinfo(skb)->nr_frags;
673
674 /* Get header len */
675 len = skb_headlen(skb);
676
677 /* Map the packet head */
678 map = dma_map_single(priv->dev, skb->data, len, DMA_TO_DEVICE);
679 if (dma_mapping_error(priv->dev, map)) {
Benjamin Herrenschmidt43b25ee2017-04-10 11:15:17 +1000680 if (net_ratelimit())
Benjamin Herrenschmidt6db74702017-04-10 11:15:25 +1000681 netdev_err(netdev, "map tx packet head failed\n");
Benjamin Herrenschmidt3e427a32017-04-10 11:15:18 +1000682 goto drop;
Benjamin Herrenschmidt43b25ee2017-04-10 11:15:17 +1000683 }
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000684
Benjamin Herrenschmidt83617312017-04-10 11:15:20 +1000685 /* Grab the next free tx descriptor */
686 pointer = priv->tx_pointer;
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000687 txdes = first = &priv->txdes[pointer];
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000688
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000689 /* Setup it up with the packet head. Don't write the head to the
690 * ring just yet
691 */
Benjamin Herrenschmidt83617312017-04-10 11:15:20 +1000692 priv->tx_skbs[pointer] = skb;
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000693 f_ctl_stat = ftgmac100_base_tx_ctlstat(priv, pointer);
694 f_ctl_stat |= FTGMAC100_TXDES0_TXDMA_OWN;
695 f_ctl_stat |= FTGMAC100_TXDES0_TXBUF_SIZE(len);
696 f_ctl_stat |= FTGMAC100_TXDES0_FTS;
697 if (nfrags == 0)
698 f_ctl_stat |= FTGMAC100_TXDES0_LTS;
699 txdes->txdes3 = cpu_to_le32(map);
Benjamin Herrenschmidt6db74702017-04-10 11:15:25 +1000700
701 /* Setup HW checksumming */
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000702 csum_vlan = 0;
Benjamin Herrenschmidt05690d62017-04-12 13:27:01 +1000703 if (skb->ip_summed == CHECKSUM_PARTIAL &&
704 !ftgmac100_prep_tx_csum(skb, &csum_vlan))
705 goto drop;
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000706 txdes->txdes1 = cpu_to_le32(csum_vlan);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000707
Benjamin Herrenschmidt6db74702017-04-10 11:15:25 +1000708 /* Next descriptor */
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000709 pointer = ftgmac100_next_tx_pointer(priv, pointer);
Benjamin Herrenschmidt6db74702017-04-10 11:15:25 +1000710
711 /* Add the fragments */
712 for (i = 0; i < nfrags; i++) {
713 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
714
715 len = frag->size;
716
717 /* Map it */
718 map = skb_frag_dma_map(priv->dev, frag, 0, len,
719 DMA_TO_DEVICE);
720 if (dma_mapping_error(priv->dev, map))
721 goto dma_err;
722
723 /* Setup descriptor */
724 priv->tx_skbs[pointer] = skb;
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000725 txdes = &priv->txdes[pointer];
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000726 ctl_stat = ftgmac100_base_tx_ctlstat(priv, pointer);
727 ctl_stat |= FTGMAC100_TXDES0_TXDMA_OWN;
728 ctl_stat |= FTGMAC100_TXDES0_TXBUF_SIZE(len);
729 if (i == (nfrags - 1))
730 ctl_stat |= FTGMAC100_TXDES0_LTS;
731 txdes->txdes0 = cpu_to_le32(ctl_stat);
732 txdes->txdes1 = 0;
733 txdes->txdes3 = cpu_to_le32(map);
734
735 /* Next one */
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000736 pointer = ftgmac100_next_tx_pointer(priv, pointer);
Benjamin Herrenschmidt6db74702017-04-10 11:15:25 +1000737 }
738
Benjamin Herrenschmidt4a2712b2017-04-10 11:15:22 +1000739 /* Order the previous packet and descriptor udpates
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000740 * before setting the OWN bit on the first descriptor.
Benjamin Herrenschmidt4a2712b2017-04-10 11:15:22 +1000741 */
742 dma_wmb();
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000743 first->txdes0 = cpu_to_le32(f_ctl_stat);
Benjamin Herrenschmidt6ad3d7e2017-04-10 11:15:21 +1000744
Benjamin Herrenschmidt83617312017-04-10 11:15:20 +1000745 /* Update next TX pointer */
Benjamin Herrenschmidt6db74702017-04-10 11:15:25 +1000746 priv->tx_pointer = pointer;
Benjamin Herrenschmidt83617312017-04-10 11:15:20 +1000747
Benjamin Herrenschmidt6ad3d7e2017-04-10 11:15:21 +1000748 /* If there isn't enough room for all the fragments of a new packet
749 * in the TX ring, stop the queue. The sequence below is race free
750 * vs. a concurrent restart in ftgmac100_poll()
751 */
752 if (unlikely(ftgmac100_tx_buf_avail(priv) < TX_THRESHOLD)) {
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000753 netif_stop_queue(netdev);
Benjamin Herrenschmidt6ad3d7e2017-04-10 11:15:21 +1000754 /* Order the queue stop with the test below */
755 smp_mb();
756 if (ftgmac100_tx_buf_avail(priv) >= TX_THRESHOLD)
757 netif_wake_queue(netdev);
758 }
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000759
Benjamin Herrenschmidt8eecf7c2017-04-12 13:27:07 +1000760 /* Poke transmitter to read the updated TX descriptors */
761 iowrite32(1, priv->base + FTGMAC100_OFFSET_NPTXPD);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000762
763 return NETDEV_TX_OK;
Benjamin Herrenschmidt3e427a32017-04-10 11:15:18 +1000764
Benjamin Herrenschmidt6db74702017-04-10 11:15:25 +1000765 dma_err:
766 if (net_ratelimit())
767 netdev_err(netdev, "map tx fragment failed\n");
768
769 /* Free head */
770 pointer = priv->tx_pointer;
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000771 ftgmac100_free_tx_packet(priv, pointer, skb, first, f_ctl_stat);
772 first->txdes0 = cpu_to_le32(f_ctl_stat & priv->txdes0_edotr_mask);
Benjamin Herrenschmidt6db74702017-04-10 11:15:25 +1000773
774 /* Then all fragments */
775 for (j = 0; j < i; j++) {
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000776 pointer = ftgmac100_next_tx_pointer(priv, pointer);
777 txdes = &priv->txdes[pointer];
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000778 ctl_stat = le32_to_cpu(txdes->txdes0);
779 ftgmac100_free_tx_packet(priv, pointer, skb, txdes, ctl_stat);
780 txdes->txdes0 = cpu_to_le32(ctl_stat & priv->txdes0_edotr_mask);
Benjamin Herrenschmidt6db74702017-04-10 11:15:25 +1000781 }
782
783 /* This cannot be reached if we successfully mapped the
784 * last fragment, so we know ftgmac100_free_tx_packet()
785 * hasn't freed the skb yet.
786 */
Benjamin Herrenschmidt3e427a32017-04-10 11:15:18 +1000787 drop:
788 /* Drop the packet */
789 dev_kfree_skb_any(skb);
790 netdev->stats.tx_dropped++;
791
792 return NETDEV_TX_OK;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000793}
794
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000795static void ftgmac100_free_buffers(struct ftgmac100 *priv)
796{
797 int i;
798
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000799 /* Free all RX buffers */
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000800 for (i = 0; i < priv->rx_q_entries; i++) {
801 struct ftgmac100_rxdes *rxdes = &priv->rxdes[i];
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000802 struct sk_buff *skb = priv->rx_skbs[i];
Benjamin Herrenschmidt4ca24152017-04-06 11:02:51 +1000803 dma_addr_t map = le32_to_cpu(rxdes->rxdes3);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000804
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000805 if (!skb)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000806 continue;
807
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000808 priv->rx_skbs[i] = NULL;
809 dma_unmap_single(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
810 dev_kfree_skb_any(skb);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000811 }
812
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000813 /* Free all TX buffers */
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000814 for (i = 0; i < priv->tx_q_entries; i++) {
815 struct ftgmac100_txdes *txdes = &priv->txdes[i];
Benjamin Herrenschmidt83617312017-04-10 11:15:20 +1000816 struct sk_buff *skb = priv->tx_skbs[i];
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000817
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000818 if (!skb)
819 continue;
820 ftgmac100_free_tx_packet(priv, i, skb, txdes,
821 le32_to_cpu(txdes->txdes0));
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000822 }
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000823}
824
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000825static void ftgmac100_free_rings(struct ftgmac100 *priv)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000826{
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000827 /* Free skb arrays */
828 kfree(priv->rx_skbs);
829 kfree(priv->tx_skbs);
830
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000831 /* Free descriptors */
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000832 if (priv->rxdes)
833 dma_free_coherent(priv->dev, MAX_RX_QUEUE_ENTRIES *
834 sizeof(struct ftgmac100_rxdes),
835 priv->rxdes, priv->rxdes_dma);
836 priv->rxdes = NULL;
837
838 if (priv->txdes)
839 dma_free_coherent(priv->dev, MAX_TX_QUEUE_ENTRIES *
840 sizeof(struct ftgmac100_txdes),
841 priv->txdes, priv->txdes_dma);
842 priv->txdes = NULL;
Benjamin Herrenschmidtd72e01a2017-04-06 11:02:45 +1000843
844 /* Free scratch packet buffer */
845 if (priv->rx_scratch)
846 dma_free_coherent(priv->dev, RX_BUF_SIZE,
847 priv->rx_scratch, priv->rx_scratch_dma);
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000848}
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000849
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000850static int ftgmac100_alloc_rings(struct ftgmac100 *priv)
851{
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000852 /* Allocate skb arrays */
853 priv->rx_skbs = kcalloc(MAX_RX_QUEUE_ENTRIES, sizeof(void *),
854 GFP_KERNEL);
855 if (!priv->rx_skbs)
856 return -ENOMEM;
857 priv->tx_skbs = kcalloc(MAX_TX_QUEUE_ENTRIES, sizeof(void *),
858 GFP_KERNEL);
859 if (!priv->tx_skbs)
860 return -ENOMEM;
861
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000862 /* Allocate descriptors */
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000863 priv->rxdes = dma_zalloc_coherent(priv->dev,
864 MAX_RX_QUEUE_ENTRIES *
865 sizeof(struct ftgmac100_rxdes),
866 &priv->rxdes_dma, GFP_KERNEL);
867 if (!priv->rxdes)
868 return -ENOMEM;
869 priv->txdes = dma_zalloc_coherent(priv->dev,
870 MAX_TX_QUEUE_ENTRIES *
871 sizeof(struct ftgmac100_txdes),
872 &priv->txdes_dma, GFP_KERNEL);
873 if (!priv->txdes)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000874 return -ENOMEM;
875
Benjamin Herrenschmidtd72e01a2017-04-06 11:02:45 +1000876 /* Allocate scratch packet buffer */
877 priv->rx_scratch = dma_alloc_coherent(priv->dev,
878 RX_BUF_SIZE,
879 &priv->rx_scratch_dma,
880 GFP_KERNEL);
881 if (!priv->rx_scratch)
882 return -ENOMEM;
883
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000884 return 0;
885}
886
887static void ftgmac100_init_rings(struct ftgmac100 *priv)
888{
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000889 struct ftgmac100_rxdes *rxdes = NULL;
890 struct ftgmac100_txdes *txdes = NULL;
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000891 int i;
892
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000893 /* Update entries counts */
894 priv->rx_q_entries = priv->new_rx_q_entries;
895 priv->tx_q_entries = priv->new_tx_q_entries;
896
897 if (WARN_ON(priv->rx_q_entries < MIN_RX_QUEUE_ENTRIES))
898 return;
899
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000900 /* Initialize RX ring */
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000901 for (i = 0; i < priv->rx_q_entries; i++) {
902 rxdes = &priv->rxdes[i];
Benjamin Herrenschmidtd72e01a2017-04-06 11:02:45 +1000903 rxdes->rxdes0 = 0;
Benjamin Herrenschmidt4ca24152017-04-06 11:02:51 +1000904 rxdes->rxdes3 = cpu_to_le32(priv->rx_scratch_dma);
Benjamin Herrenschmidtd72e01a2017-04-06 11:02:45 +1000905 }
Benjamin Herrenschmidt4ca24152017-04-06 11:02:51 +1000906 /* Mark the end of the ring */
907 rxdes->rxdes0 |= cpu_to_le32(priv->rxdes0_edorr_mask);
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000908
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000909 if (WARN_ON(priv->tx_q_entries < MIN_RX_QUEUE_ENTRIES))
910 return;
911
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000912 /* Initialize TX ring */
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000913 for (i = 0; i < priv->tx_q_entries; i++) {
914 txdes = &priv->txdes[i];
Benjamin Herrenschmidt52c0cae2017-04-10 11:15:26 +1000915 txdes->txdes0 = 0;
916 }
917 txdes->txdes0 |= cpu_to_le32(priv->txdes0_edotr_mask);
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000918}
919
920static int ftgmac100_alloc_rx_buffers(struct ftgmac100 *priv)
921{
922 int i;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000923
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +1000924 for (i = 0; i < priv->rx_q_entries; i++) {
925 struct ftgmac100_rxdes *rxdes = &priv->rxdes[i];
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000926
Benjamin Herrenschmidt7b49cd12017-04-06 11:02:49 +1000927 if (ftgmac100_alloc_rx_buf(priv, i, rxdes, GFP_KERNEL))
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +1000928 return -ENOMEM;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000929 }
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000930 return 0;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000931}
932
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000933static void ftgmac100_adjust_link(struct net_device *netdev)
934{
935 struct ftgmac100 *priv = netdev_priv(netdev);
Philippe Reynesb3c40ad2016-05-16 01:35:13 +0200936 struct phy_device *phydev = netdev->phydev;
Benjamin Herrenschmidt7c8e5142017-04-18 08:36:59 +1000937 bool tx_pause, rx_pause;
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +1000938 int new_speed;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000939
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +1000940 /* We store "no link" as speed 0 */
941 if (!phydev->link)
942 new_speed = 0;
943 else
944 new_speed = phydev->speed;
945
Benjamin Herrenschmidt7c8e5142017-04-18 08:36:59 +1000946 /* Grab pause settings from PHY if configured to do so */
947 if (priv->aneg_pause) {
948 rx_pause = tx_pause = phydev->pause;
949 if (phydev->asym_pause)
950 tx_pause = !rx_pause;
951 } else {
952 rx_pause = priv->rx_pause;
953 tx_pause = priv->tx_pause;
954 }
955
956 /* Link hasn't changed, do nothing */
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +1000957 if (phydev->speed == priv->cur_speed &&
Benjamin Herrenschmidt7c8e5142017-04-18 08:36:59 +1000958 phydev->duplex == priv->cur_duplex &&
959 rx_pause == priv->rx_pause &&
960 tx_pause == priv->tx_pause)
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000961 return;
962
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +1000963 /* Print status if we have a link or we had one and just lost it,
964 * don't print otherwise.
965 */
966 if (new_speed || priv->cur_speed)
967 phy_print_status(phydev);
968
969 priv->cur_speed = new_speed;
970 priv->cur_duplex = phydev->duplex;
Benjamin Herrenschmidt7c8e5142017-04-18 08:36:59 +1000971 priv->rx_pause = rx_pause;
972 priv->tx_pause = tx_pause;
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +1000973
974 /* Link is down, do nothing else */
975 if (!new_speed)
976 return;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000977
Benjamin Herrenschmidt855944c2017-04-05 12:28:50 +1000978 /* Disable all interrupts */
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000979 iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
980
Benjamin Herrenschmidt855944c2017-04-05 12:28:50 +1000981 /* Reset the adapter asynchronously */
982 schedule_work(&priv->reset_task);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000983}
984
985static int ftgmac100_mii_probe(struct ftgmac100 *priv)
986{
987 struct net_device *netdev = priv->netdev;
Guenter Roecke574f392016-01-10 12:04:32 -0800988 struct phy_device *phydev;
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000989
Guenter Roecke574f392016-01-10 12:04:32 -0800990 phydev = phy_find_first(priv->mii_bus);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000991 if (!phydev) {
992 netdev_info(netdev, "%s: no PHY found\n", netdev->name);
993 return -ENODEV;
994 }
995
Andrew Lunn84eff6d2016-01-06 20:11:10 +0100996 phydev = phy_connect(netdev, phydev_name(phydev),
Florian Fainellif9a8f832013-01-14 00:52:52 +0000997 &ftgmac100_adjust_link, PHY_INTERFACE_MODE_GMII);
Po-Yu Chuang69785b72011-06-08 23:32:48 +0000998
999 if (IS_ERR(phydev)) {
1000 netdev_err(netdev, "%s: Could not attach to PHY\n", netdev->name);
1001 return PTR_ERR(phydev);
1002 }
1003
Benjamin Herrenschmidt7c8e5142017-04-18 08:36:59 +10001004 /* Indicate that we support PAUSE frames (see comment in
1005 * Documentation/networking/phy.txt)
1006 */
1007 phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
1008 phydev->advertising = phydev->supported;
1009
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001010 return 0;
1011}
1012
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001013static int ftgmac100_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
1014{
1015 struct net_device *netdev = bus->priv;
1016 struct ftgmac100 *priv = netdev_priv(netdev);
1017 unsigned int phycr;
1018 int i;
1019
1020 phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
1021
1022 /* preserve MDC cycle threshold */
1023 phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
1024
1025 phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr) |
1026 FTGMAC100_PHYCR_REGAD(regnum) |
1027 FTGMAC100_PHYCR_MIIRD;
1028
1029 iowrite32(phycr, priv->base + FTGMAC100_OFFSET_PHYCR);
1030
1031 for (i = 0; i < 10; i++) {
1032 phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
1033
1034 if ((phycr & FTGMAC100_PHYCR_MIIRD) == 0) {
1035 int data;
1036
1037 data = ioread32(priv->base + FTGMAC100_OFFSET_PHYDATA);
1038 return FTGMAC100_PHYDATA_MIIRDATA(data);
1039 }
1040
1041 udelay(100);
1042 }
1043
1044 netdev_err(netdev, "mdio read timed out\n");
1045 return -EIO;
1046}
1047
1048static int ftgmac100_mdiobus_write(struct mii_bus *bus, int phy_addr,
1049 int regnum, u16 value)
1050{
1051 struct net_device *netdev = bus->priv;
1052 struct ftgmac100 *priv = netdev_priv(netdev);
1053 unsigned int phycr;
1054 int data;
1055 int i;
1056
1057 phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
1058
1059 /* preserve MDC cycle threshold */
1060 phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
1061
1062 phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr) |
1063 FTGMAC100_PHYCR_REGAD(regnum) |
1064 FTGMAC100_PHYCR_MIIWR;
1065
1066 data = FTGMAC100_PHYDATA_MIIWDATA(value);
1067
1068 iowrite32(data, priv->base + FTGMAC100_OFFSET_PHYDATA);
1069 iowrite32(phycr, priv->base + FTGMAC100_OFFSET_PHYCR);
1070
1071 for (i = 0; i < 10; i++) {
1072 phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
1073
1074 if ((phycr & FTGMAC100_PHYCR_MIIWR) == 0)
1075 return 0;
1076
1077 udelay(100);
1078 }
1079
1080 netdev_err(netdev, "mdio write timed out\n");
1081 return -EIO;
1082}
1083
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001084static void ftgmac100_get_drvinfo(struct net_device *netdev,
1085 struct ethtool_drvinfo *info)
1086{
Jiri Pirko7826d432013-01-06 00:44:26 +00001087 strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
1088 strlcpy(info->version, DRV_VERSION, sizeof(info->version));
1089 strlcpy(info->bus_info, dev_name(&netdev->dev), sizeof(info->bus_info));
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001090}
1091
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +10001092static void ftgmac100_get_ringparam(struct net_device *netdev,
1093 struct ethtool_ringparam *ering)
1094{
1095 struct ftgmac100 *priv = netdev_priv(netdev);
1096
1097 memset(ering, 0, sizeof(*ering));
1098 ering->rx_max_pending = MAX_RX_QUEUE_ENTRIES;
1099 ering->tx_max_pending = MAX_TX_QUEUE_ENTRIES;
1100 ering->rx_pending = priv->rx_q_entries;
1101 ering->tx_pending = priv->tx_q_entries;
1102}
1103
1104static int ftgmac100_set_ringparam(struct net_device *netdev,
1105 struct ethtool_ringparam *ering)
1106{
1107 struct ftgmac100 *priv = netdev_priv(netdev);
1108
1109 if (ering->rx_pending > MAX_RX_QUEUE_ENTRIES ||
1110 ering->tx_pending > MAX_TX_QUEUE_ENTRIES ||
1111 ering->rx_pending < MIN_RX_QUEUE_ENTRIES ||
1112 ering->tx_pending < MIN_TX_QUEUE_ENTRIES ||
1113 !is_power_of_2(ering->rx_pending) ||
1114 !is_power_of_2(ering->tx_pending))
1115 return -EINVAL;
1116
1117 priv->new_rx_q_entries = ering->rx_pending;
1118 priv->new_tx_q_entries = ering->tx_pending;
1119 if (netif_running(netdev))
1120 schedule_work(&priv->reset_task);
1121
1122 return 0;
1123}
1124
Benjamin Herrenschmidt7c8e5142017-04-18 08:36:59 +10001125static void ftgmac100_get_pauseparam(struct net_device *netdev,
1126 struct ethtool_pauseparam *pause)
1127{
1128 struct ftgmac100 *priv = netdev_priv(netdev);
1129
1130 pause->autoneg = priv->aneg_pause;
1131 pause->tx_pause = priv->tx_pause;
1132 pause->rx_pause = priv->rx_pause;
1133}
1134
1135static int ftgmac100_set_pauseparam(struct net_device *netdev,
1136 struct ethtool_pauseparam *pause)
1137{
1138 struct ftgmac100 *priv = netdev_priv(netdev);
1139 struct phy_device *phydev = netdev->phydev;
1140
1141 priv->aneg_pause = pause->autoneg;
1142 priv->tx_pause = pause->tx_pause;
1143 priv->rx_pause = pause->rx_pause;
1144
1145 if (phydev) {
1146 phydev->advertising &= ~ADVERTISED_Pause;
1147 phydev->advertising &= ~ADVERTISED_Asym_Pause;
1148
1149 if (pause->rx_pause) {
1150 phydev->advertising |= ADVERTISED_Pause;
1151 phydev->advertising |= ADVERTISED_Asym_Pause;
1152 }
1153
1154 if (pause->tx_pause)
1155 phydev->advertising ^= ADVERTISED_Asym_Pause;
1156 }
1157 if (netif_running(netdev)) {
1158 if (phydev && priv->aneg_pause)
1159 phy_start_aneg(phydev);
1160 else
1161 ftgmac100_config_pause(priv);
1162 }
1163
1164 return 0;
1165}
1166
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001167static const struct ethtool_ops ftgmac100_ethtool_ops = {
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001168 .get_drvinfo = ftgmac100_get_drvinfo,
1169 .get_link = ethtool_op_get_link,
Philippe Reynesfd24d722016-05-16 01:35:14 +02001170 .get_link_ksettings = phy_ethtool_get_link_ksettings,
1171 .set_link_ksettings = phy_ethtool_set_link_ksettings,
Benjamin Herrenschmidte98233a2017-04-18 08:36:58 +10001172 .nway_reset = phy_ethtool_nway_reset,
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +10001173 .get_ringparam = ftgmac100_get_ringparam,
1174 .set_ringparam = ftgmac100_set_ringparam,
Benjamin Herrenschmidt7c8e5142017-04-18 08:36:59 +10001175 .get_pauseparam = ftgmac100_get_pauseparam,
1176 .set_pauseparam = ftgmac100_set_pauseparam,
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001177};
1178
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001179static irqreturn_t ftgmac100_interrupt(int irq, void *dev_id)
1180{
1181 struct net_device *netdev = dev_id;
1182 struct ftgmac100 *priv = netdev_priv(netdev);
Benjamin Herrenschmidt10cbd642017-04-05 12:28:53 +10001183 unsigned int status, new_mask = FTGMAC100_INT_BAD;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001184
Benjamin Herrenschmidt10cbd642017-04-05 12:28:53 +10001185 /* Fetch and clear interrupt bits, process abnormal ones */
1186 status = ioread32(priv->base + FTGMAC100_OFFSET_ISR);
1187 iowrite32(status, priv->base + FTGMAC100_OFFSET_ISR);
1188 if (unlikely(status & FTGMAC100_INT_BAD)) {
1189
1190 /* RX buffer unavailable */
1191 if (status & FTGMAC100_INT_NO_RXBUF)
1192 netdev->stats.rx_over_errors++;
1193
1194 /* received packet lost due to RX FIFO full */
1195 if (status & FTGMAC100_INT_RPKT_LOST)
1196 netdev->stats.rx_fifo_errors++;
1197
1198 /* sent packet lost due to excessive TX collision */
1199 if (status & FTGMAC100_INT_XPKT_LOST)
1200 netdev->stats.tx_fifo_errors++;
1201
1202 /* AHB error -> Reset the chip */
1203 if (status & FTGMAC100_INT_AHB_ERR) {
1204 if (net_ratelimit())
1205 netdev_warn(netdev,
1206 "AHB bus error ! Resetting chip.\n");
1207 iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
1208 schedule_work(&priv->reset_task);
1209 return IRQ_HANDLED;
1210 }
1211
1212 /* We may need to restart the MAC after such errors, delay
1213 * this until after we have freed some Rx buffers though
1214 */
1215 priv->need_mac_restart = true;
1216
1217 /* Disable those errors until we restart */
1218 new_mask &= ~status;
1219 }
1220
1221 /* Only enable "bad" interrupts while NAPI is on */
1222 iowrite32(new_mask, priv->base + FTGMAC100_OFFSET_IER);
1223
1224 /* Schedule NAPI bh */
1225 napi_schedule_irqoff(&priv->napi);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001226
1227 return IRQ_HANDLED;
1228}
1229
Benjamin Herrenschmidt4ca24152017-04-06 11:02:51 +10001230static bool ftgmac100_check_rx(struct ftgmac100 *priv)
1231{
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +10001232 struct ftgmac100_rxdes *rxdes = &priv->rxdes[priv->rx_pointer];
Benjamin Herrenschmidt4ca24152017-04-06 11:02:51 +10001233
1234 /* Do we have a packet ? */
1235 return !!(rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RXPKT_RDY));
1236}
1237
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001238static int ftgmac100_poll(struct napi_struct *napi, int budget)
1239{
1240 struct ftgmac100 *priv = container_of(napi, struct ftgmac100, napi);
Benjamin Herrenschmidt6ad3d7e2017-04-10 11:15:21 +10001241 int work_done = 0;
1242 bool more;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001243
Benjamin Herrenschmidt6ad3d7e2017-04-10 11:15:21 +10001244 /* Handle TX completions */
1245 if (ftgmac100_tx_buf_cleanable(priv))
1246 ftgmac100_tx_complete(priv);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001247
Benjamin Herrenschmidt6ad3d7e2017-04-10 11:15:21 +10001248 /* Handle RX packets */
Benjamin Herrenschmidt10cbd642017-04-05 12:28:53 +10001249 do {
Benjamin Herrenschmidt6ad3d7e2017-04-10 11:15:21 +10001250 more = ftgmac100_rx_packet(priv, &work_done);
1251 } while (more && work_done < budget);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001252
Benjamin Herrenschmidt10cbd642017-04-05 12:28:53 +10001253
1254 /* The interrupt is telling us to kick the MAC back to life
1255 * after an RX overflow
1256 */
1257 if (unlikely(priv->need_mac_restart)) {
1258 ftgmac100_start_hw(priv);
1259
1260 /* Re-enable "bad" interrupts */
1261 iowrite32(FTGMAC100_INT_BAD,
1262 priv->base + FTGMAC100_OFFSET_IER);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001263 }
1264
Benjamin Herrenschmidt6ad3d7e2017-04-10 11:15:21 +10001265 /* As long as we are waiting for transmit packets to be
1266 * completed we keep NAPI going
1267 */
1268 if (ftgmac100_tx_buf_cleanable(priv))
1269 work_done = budget;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001270
Benjamin Herrenschmidt6ad3d7e2017-04-10 11:15:21 +10001271 if (work_done < budget) {
Benjamin Herrenschmidt10cbd642017-04-05 12:28:53 +10001272 /* We are about to re-enable all interrupts. However
1273 * the HW has been latching RX/TX packet interrupts while
1274 * they were masked. So we clear them first, then we need
1275 * to re-check if there's something to process
1276 */
1277 iowrite32(FTGMAC100_INT_RXTX,
1278 priv->base + FTGMAC100_OFFSET_ISR);
Benjamin Herrenschmidt6ad3d7e2017-04-10 11:15:21 +10001279 if (ftgmac100_check_rx(priv) ||
1280 ftgmac100_tx_buf_cleanable(priv))
Benjamin Herrenschmidt10cbd642017-04-05 12:28:53 +10001281 return budget;
1282
1283 /* deschedule NAPI */
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001284 napi_complete(napi);
1285
1286 /* enable all interrupts */
Benjamin Herrenschmidt10cbd642017-04-05 12:28:53 +10001287 iowrite32(FTGMAC100_INT_ALL,
Gavin Shanfc6061c2016-07-19 11:54:25 +10001288 priv->base + FTGMAC100_OFFSET_IER);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001289 }
1290
Benjamin Herrenschmidt6ad3d7e2017-04-10 11:15:21 +10001291 return work_done;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001292}
1293
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001294static int ftgmac100_init_all(struct ftgmac100 *priv, bool ignore_alloc_err)
1295{
1296 int err = 0;
1297
1298 /* Re-init descriptors (adjust queue sizes) */
1299 ftgmac100_init_rings(priv);
1300
1301 /* Realloc rx descriptors */
1302 err = ftgmac100_alloc_rx_buffers(priv);
1303 if (err && !ignore_alloc_err)
1304 return err;
1305
1306 /* Reinit and restart HW */
1307 ftgmac100_init_hw(priv);
Benjamin Herrenschmidt7c8e5142017-04-18 08:36:59 +10001308 ftgmac100_config_pause(priv);
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001309 ftgmac100_start_hw(priv);
1310
1311 /* Re-enable the device */
1312 napi_enable(&priv->napi);
1313 netif_start_queue(priv->netdev);
1314
1315 /* Enable all interrupts */
Benjamin Herrenschmidt10cbd642017-04-05 12:28:53 +10001316 iowrite32(FTGMAC100_INT_ALL, priv->base + FTGMAC100_OFFSET_IER);
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001317
1318 return err;
1319}
1320
Benjamin Herrenschmidt855944c2017-04-05 12:28:50 +10001321static void ftgmac100_reset_task(struct work_struct *work)
1322{
1323 struct ftgmac100 *priv = container_of(work, struct ftgmac100,
1324 reset_task);
1325 struct net_device *netdev = priv->netdev;
1326 int err;
1327
1328 netdev_dbg(netdev, "Resetting NIC...\n");
1329
1330 /* Lock the world */
1331 rtnl_lock();
1332 if (netdev->phydev)
1333 mutex_lock(&netdev->phydev->lock);
1334 if (priv->mii_bus)
1335 mutex_lock(&priv->mii_bus->mdio_lock);
1336
1337
1338 /* Check if the interface is still up */
1339 if (!netif_running(netdev))
1340 goto bail;
1341
1342 /* Stop the network stack */
1343 netif_trans_update(netdev);
1344 napi_disable(&priv->napi);
1345 netif_tx_disable(netdev);
1346
1347 /* Stop and reset the MAC */
1348 ftgmac100_stop_hw(priv);
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +10001349 err = ftgmac100_reset_and_config_mac(priv);
Benjamin Herrenschmidt855944c2017-04-05 12:28:50 +10001350 if (err) {
1351 /* Not much we can do ... it might come back... */
1352 netdev_err(netdev, "attempting to continue...\n");
1353 }
1354
1355 /* Free all rx and tx buffers */
1356 ftgmac100_free_buffers(priv);
1357
Benjamin Herrenschmidt855944c2017-04-05 12:28:50 +10001358 /* Setup everything again and restart chip */
1359 ftgmac100_init_all(priv, true);
1360
1361 netdev_dbg(netdev, "Reset done !\n");
1362 bail:
1363 if (priv->mii_bus)
1364 mutex_unlock(&priv->mii_bus->mdio_lock);
1365 if (netdev->phydev)
1366 mutex_unlock(&netdev->phydev->lock);
1367 rtnl_unlock();
1368}
1369
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001370static int ftgmac100_open(struct net_device *netdev)
1371{
1372 struct ftgmac100 *priv = netdev_priv(netdev);
1373 int err;
1374
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +10001375 /* Allocate ring buffers */
1376 err = ftgmac100_alloc_rings(priv);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001377 if (err) {
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +10001378 netdev_err(netdev, "Failed to allocate descriptors\n");
1379 return err;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001380 }
1381
Benjamin Herrenschmidt51764772017-04-05 12:28:45 +10001382 /* When using NC-SI we force the speed to 100Mbit/s full duplex,
1383 *
1384 * Otherwise we leave it set to 0 (no link), the link
1385 * message from the PHY layer will handle setting it up to
1386 * something else if needed.
1387 */
1388 if (priv->use_ncsi) {
1389 priv->cur_duplex = DUPLEX_FULL;
1390 priv->cur_speed = SPEED_100;
1391 } else {
1392 priv->cur_duplex = 0;
1393 priv->cur_speed = 0;
1394 }
1395
Benjamin Herrenschmidt874b55b2017-04-05 12:28:51 +10001396 /* Reset the hardware */
1397 err = ftgmac100_reset_and_config_mac(priv);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001398 if (err)
1399 goto err_hw;
1400
Benjamin Herrenschmidtb8dbecf2017-04-05 12:28:47 +10001401 /* Initialize NAPI */
1402 netif_napi_add(netdev, &priv->napi, ftgmac100_poll, 64);
1403
Benjamin Herrenschmidt81f1eca2017-04-05 12:28:48 +10001404 /* Grab our interrupt */
1405 err = request_irq(netdev->irq, ftgmac100_interrupt, 0, netdev->name, netdev);
1406 if (err) {
1407 netdev_err(netdev, "failed to request irq %d\n", netdev->irq);
1408 goto err_irq;
1409 }
1410
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001411 /* Start things up */
1412 err = ftgmac100_init_all(priv, false);
1413 if (err) {
1414 netdev_err(netdev, "Failed to allocate packet buffers\n");
1415 goto err_alloc;
1416 }
Gavin Shan08c9c122016-09-22 08:35:01 +09301417
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001418 if (netdev->phydev) {
1419 /* If we have a PHY, start polling */
Gavin Shanbd466c32016-07-19 11:54:23 +10001420 phy_start(netdev->phydev);
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001421 } else if (priv->use_ncsi) {
1422 /* If using NC-SI, set our carrier on and start the stack */
Gavin Shanbd466c32016-07-19 11:54:23 +10001423 netif_carrier_on(netdev);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001424
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001425 /* Start the NCSI device */
Gavin Shanbd466c32016-07-19 11:54:23 +10001426 err = ncsi_start_dev(priv->ndev);
1427 if (err)
1428 goto err_ncsi;
1429 }
1430
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001431 return 0;
1432
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001433 err_ncsi:
Gavin Shanbd466c32016-07-19 11:54:23 +10001434 napi_disable(&priv->napi);
1435 netif_stop_queue(netdev);
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001436 err_alloc:
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +10001437 ftgmac100_free_buffers(priv);
Benjamin Herrenschmidtda40d9d2017-04-05 12:28:49 +10001438 free_irq(netdev->irq, netdev);
1439 err_irq:
1440 netif_napi_del(&priv->napi);
1441 err_hw:
1442 iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +10001443 ftgmac100_free_rings(priv);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001444 return err;
1445}
1446
1447static int ftgmac100_stop(struct net_device *netdev)
1448{
1449 struct ftgmac100 *priv = netdev_priv(netdev);
1450
Benjamin Herrenschmidt855944c2017-04-05 12:28:50 +10001451 /* Note about the reset task: We are called with the rtnl lock
1452 * held, so we are synchronized against the core of the reset
1453 * task. We must not try to synchronously cancel it otherwise
1454 * we can deadlock. But since it will test for netif_running()
1455 * which has already been cleared by the net core, we don't
1456 * anything special to do.
1457 */
1458
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001459 /* disable all interrupts */
1460 iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
1461
1462 netif_stop_queue(netdev);
1463 napi_disable(&priv->napi);
Benjamin Herrenschmidtb8dbecf2017-04-05 12:28:47 +10001464 netif_napi_del(&priv->napi);
Gavin Shanbd466c32016-07-19 11:54:23 +10001465 if (netdev->phydev)
1466 phy_stop(netdev->phydev);
Gavin Shan2c15f252016-10-04 11:25:54 +11001467 else if (priv->use_ncsi)
1468 ncsi_stop_dev(priv->ndev);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001469
1470 ftgmac100_stop_hw(priv);
Benjamin Herrenschmidt60b28a12017-04-05 12:28:41 +10001471 free_irq(netdev->irq, netdev);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001472 ftgmac100_free_buffers(priv);
Benjamin Herrenschmidt87d18752017-04-05 12:28:46 +10001473 ftgmac100_free_rings(priv);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001474
1475 return 0;
1476}
1477
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001478/* optional */
1479static int ftgmac100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
1480{
Gavin Shanbd466c32016-07-19 11:54:23 +10001481 if (!netdev->phydev)
1482 return -ENXIO;
1483
Philippe Reynesb3c40ad2016-05-16 01:35:13 +02001484 return phy_mii_ioctl(netdev->phydev, ifr, cmd);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001485}
1486
Benjamin Herrenschmidtd3ca8fb2017-04-10 11:15:15 +10001487static void ftgmac100_tx_timeout(struct net_device *netdev)
1488{
1489 struct ftgmac100 *priv = netdev_priv(netdev);
1490
1491 /* Disable all interrupts */
1492 iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
1493
1494 /* Do the reset outside of interrupt context */
1495 schedule_work(&priv->reset_task);
1496}
1497
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001498static const struct net_device_ops ftgmac100_netdev_ops = {
1499 .ndo_open = ftgmac100_open,
1500 .ndo_stop = ftgmac100_stop,
1501 .ndo_start_xmit = ftgmac100_hard_start_xmit,
Gavin Shan113ce102016-07-19 11:54:22 +10001502 .ndo_set_mac_address = ftgmac100_set_mac_addr,
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001503 .ndo_validate_addr = eth_validate_addr,
1504 .ndo_do_ioctl = ftgmac100_do_ioctl,
Benjamin Herrenschmidtd3ca8fb2017-04-10 11:15:15 +10001505 .ndo_tx_timeout = ftgmac100_tx_timeout,
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001506};
1507
Gavin Shaneb418182016-07-19 11:54:21 +10001508static int ftgmac100_setup_mdio(struct net_device *netdev)
1509{
1510 struct ftgmac100 *priv = netdev_priv(netdev);
1511 struct platform_device *pdev = to_platform_device(priv->dev);
1512 int i, err = 0;
Joel Stanleye07dc632016-09-22 08:35:02 +09301513 u32 reg;
Gavin Shaneb418182016-07-19 11:54:21 +10001514
1515 /* initialize mdio bus */
1516 priv->mii_bus = mdiobus_alloc();
1517 if (!priv->mii_bus)
1518 return -EIO;
1519
Benjamin Herrenschmidt78d28542017-04-12 13:27:02 +10001520 if (priv->is_aspeed) {
Joel Stanleye07dc632016-09-22 08:35:02 +09301521 /* This driver supports the old MDIO interface */
1522 reg = ioread32(priv->base + FTGMAC100_OFFSET_REVR);
1523 reg &= ~FTGMAC100_REVR_NEW_MDIO_INTERFACE;
1524 iowrite32(reg, priv->base + FTGMAC100_OFFSET_REVR);
1525 };
1526
Gavin Shaneb418182016-07-19 11:54:21 +10001527 priv->mii_bus->name = "ftgmac100_mdio";
1528 snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%d",
1529 pdev->name, pdev->id);
1530 priv->mii_bus->priv = priv->netdev;
1531 priv->mii_bus->read = ftgmac100_mdiobus_read;
1532 priv->mii_bus->write = ftgmac100_mdiobus_write;
1533
1534 for (i = 0; i < PHY_MAX_ADDR; i++)
1535 priv->mii_bus->irq[i] = PHY_POLL;
1536
1537 err = mdiobus_register(priv->mii_bus);
1538 if (err) {
1539 dev_err(priv->dev, "Cannot register MDIO bus!\n");
1540 goto err_register_mdiobus;
1541 }
1542
1543 err = ftgmac100_mii_probe(priv);
1544 if (err) {
1545 dev_err(priv->dev, "MII Probe failed!\n");
1546 goto err_mii_probe;
1547 }
1548
1549 return 0;
1550
1551err_mii_probe:
1552 mdiobus_unregister(priv->mii_bus);
1553err_register_mdiobus:
1554 mdiobus_free(priv->mii_bus);
1555 return err;
1556}
1557
1558static void ftgmac100_destroy_mdio(struct net_device *netdev)
1559{
1560 struct ftgmac100 *priv = netdev_priv(netdev);
1561
1562 if (!netdev->phydev)
1563 return;
1564
1565 phy_disconnect(netdev->phydev);
1566 mdiobus_unregister(priv->mii_bus);
1567 mdiobus_free(priv->mii_bus);
1568}
1569
Gavin Shanbd466c32016-07-19 11:54:23 +10001570static void ftgmac100_ncsi_handler(struct ncsi_dev *nd)
1571{
1572 if (unlikely(nd->state != ncsi_dev_state_functional))
1573 return;
1574
1575 netdev_info(nd->dev, "NCSI interface %s\n",
1576 nd->link_up ? "up" : "down");
1577}
1578
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001579static int ftgmac100_probe(struct platform_device *pdev)
1580{
1581 struct resource *res;
1582 int irq;
1583 struct net_device *netdev;
1584 struct ftgmac100 *priv;
Benjamin Herrenschmidt78d28542017-04-12 13:27:02 +10001585 struct device_node *np;
Gavin Shanbd466c32016-07-19 11:54:23 +10001586 int err = 0;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001587
1588 if (!pdev)
1589 return -ENODEV;
1590
1591 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1592 if (!res)
1593 return -ENXIO;
1594
1595 irq = platform_get_irq(pdev, 0);
1596 if (irq < 0)
1597 return irq;
1598
1599 /* setup net_device */
1600 netdev = alloc_etherdev(sizeof(*priv));
1601 if (!netdev) {
1602 err = -ENOMEM;
1603 goto err_alloc_etherdev;
1604 }
1605
1606 SET_NETDEV_DEV(netdev, &pdev->dev);
1607
Wilfried Klaebe7ad24ea2014-05-11 00:12:32 +00001608 netdev->ethtool_ops = &ftgmac100_ethtool_ops;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001609 netdev->netdev_ops = &ftgmac100_netdev_ops;
Benjamin Herrenschmidtd3ca8fb2017-04-10 11:15:15 +10001610 netdev->watchdog_timeo = 5 * HZ;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001611
1612 platform_set_drvdata(pdev, netdev);
1613
1614 /* setup private data */
1615 priv = netdev_priv(netdev);
1616 priv->netdev = netdev;
1617 priv->dev = &pdev->dev;
Benjamin Herrenschmidt855944c2017-04-05 12:28:50 +10001618 INIT_WORK(&priv->reset_task, ftgmac100_reset_task);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001619
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001620 /* map io memory */
1621 priv->res = request_mem_region(res->start, resource_size(res),
1622 dev_name(&pdev->dev));
1623 if (!priv->res) {
1624 dev_err(&pdev->dev, "Could not reserve memory region\n");
1625 err = -ENOMEM;
1626 goto err_req_mem;
1627 }
1628
1629 priv->base = ioremap(res->start, resource_size(res));
1630 if (!priv->base) {
1631 dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
1632 err = -EIO;
1633 goto err_ioremap;
1634 }
1635
Benjamin Herrenschmidt60b28a12017-04-05 12:28:41 +10001636 netdev->irq = irq;
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001637
Benjamin Herrenschmidt7c8e5142017-04-18 08:36:59 +10001638 /* Enable pause */
1639 priv->tx_pause = true;
1640 priv->rx_pause = true;
1641 priv->aneg_pause = true;
1642
Gavin Shan113ce102016-07-19 11:54:22 +10001643 /* MAC address from chip or random one */
Benjamin Herrenschmidtba1b1232017-04-12 13:27:06 +10001644 ftgmac100_initial_mac(priv);
Gavin Shan113ce102016-07-19 11:54:22 +10001645
Benjamin Herrenschmidt78d28542017-04-12 13:27:02 +10001646 np = pdev->dev.of_node;
1647 if (np && (of_device_is_compatible(np, "aspeed,ast2400-mac") ||
1648 of_device_is_compatible(np, "aspeed,ast2500-mac"))) {
Joel Stanley2a0ab8eb2016-09-22 08:35:00 +09301649 priv->rxdes0_edorr_mask = BIT(30);
1650 priv->txdes0_edotr_mask = BIT(30);
Benjamin Herrenschmidt78d28542017-04-12 13:27:02 +10001651 priv->is_aspeed = true;
Joel Stanley2a0ab8eb2016-09-22 08:35:00 +09301652 } else {
1653 priv->rxdes0_edorr_mask = BIT(15);
1654 priv->txdes0_edotr_mask = BIT(15);
1655 }
1656
Benjamin Herrenschmidt78d28542017-04-12 13:27:02 +10001657 if (np && of_get_property(np, "use-ncsi", NULL)) {
Gavin Shanbd466c32016-07-19 11:54:23 +10001658 if (!IS_ENABLED(CONFIG_NET_NCSI)) {
1659 dev_err(&pdev->dev, "NCSI stack not enabled\n");
1660 goto err_ncsi_dev;
1661 }
1662
1663 dev_info(&pdev->dev, "Using NCSI interface\n");
1664 priv->use_ncsi = true;
1665 priv->ndev = ncsi_register_dev(netdev, ftgmac100_ncsi_handler);
1666 if (!priv->ndev)
1667 goto err_ncsi_dev;
1668 } else {
1669 priv->use_ncsi = false;
1670 err = ftgmac100_setup_mdio(netdev);
1671 if (err)
1672 goto err_setup_mdio;
1673 }
1674
Benjamin Herrenschmidt52d91382017-04-12 13:27:09 +10001675 /* Default ring sizes */
1676 priv->rx_q_entries = priv->new_rx_q_entries = DEF_RX_QUEUE_ENTRIES;
1677 priv->tx_q_entries = priv->new_tx_q_entries = DEF_TX_QUEUE_ENTRIES;
1678
Benjamin Herrenschmidt6aff0bf2017-04-12 13:27:03 +10001679 /* Base feature set */
Benjamin Herrenschmidt8c3ed132017-04-12 13:27:04 +10001680 netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_HW_CSUM |
Benjamin Herrenschmidt6db74702017-04-10 11:15:25 +10001681 NETIF_F_GRO | NETIF_F_SG;
Benjamin Herrenschmidt6aff0bf2017-04-12 13:27:03 +10001682
1683 /* AST2400 doesn't have working HW checksum generation */
1684 if (np && (of_device_is_compatible(np, "aspeed,ast2400-mac")))
Benjamin Herrenschmidt8c3ed132017-04-12 13:27:04 +10001685 netdev->hw_features &= ~NETIF_F_HW_CSUM;
Benjamin Herrenschmidt6aff0bf2017-04-12 13:27:03 +10001686 if (np && of_get_property(np, "no-hw-checksum", NULL))
Benjamin Herrenschmidt8c3ed132017-04-12 13:27:04 +10001687 netdev->hw_features &= ~(NETIF_F_HW_CSUM | NETIF_F_RXCSUM);
1688 netdev->features |= netdev->hw_features;
Gavin Shanbd466c32016-07-19 11:54:23 +10001689
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001690 /* register network device */
1691 err = register_netdev(netdev);
1692 if (err) {
1693 dev_err(&pdev->dev, "Failed to register netdev\n");
1694 goto err_register_netdev;
1695 }
1696
Benjamin Herrenschmidt60b28a12017-04-05 12:28:41 +10001697 netdev_info(netdev, "irq %d, mapped at %p\n", netdev->irq, priv->base);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001698
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001699 return 0;
1700
Gavin Shanbd466c32016-07-19 11:54:23 +10001701err_ncsi_dev:
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001702err_register_netdev:
Gavin Shaneb418182016-07-19 11:54:21 +10001703 ftgmac100_destroy_mdio(netdev);
1704err_setup_mdio:
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001705 iounmap(priv->base);
1706err_ioremap:
1707 release_resource(priv->res);
1708err_req_mem:
1709 netif_napi_del(&priv->napi);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001710 free_netdev(netdev);
1711err_alloc_etherdev:
1712 return err;
1713}
1714
Dmitry Torokhovbe125022017-03-01 17:24:47 -08001715static int ftgmac100_remove(struct platform_device *pdev)
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001716{
1717 struct net_device *netdev;
1718 struct ftgmac100 *priv;
1719
1720 netdev = platform_get_drvdata(pdev);
1721 priv = netdev_priv(netdev);
1722
1723 unregister_netdev(netdev);
Benjamin Herrenschmidt855944c2017-04-05 12:28:50 +10001724
1725 /* There's a small chance the reset task will have been re-queued,
1726 * during stop, make sure it's gone before we free the structure.
1727 */
1728 cancel_work_sync(&priv->reset_task);
1729
Gavin Shaneb418182016-07-19 11:54:21 +10001730 ftgmac100_destroy_mdio(netdev);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001731
1732 iounmap(priv->base);
1733 release_resource(priv->res);
1734
1735 netif_napi_del(&priv->napi);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001736 free_netdev(netdev);
1737 return 0;
1738}
1739
Gavin Shanbb168e22016-07-19 11:54:24 +10001740static const struct of_device_id ftgmac100_of_match[] = {
1741 { .compatible = "faraday,ftgmac100" },
1742 { }
1743};
1744MODULE_DEVICE_TABLE(of, ftgmac100_of_match);
1745
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001746static struct platform_driver ftgmac100_driver = {
Gavin Shanbb168e22016-07-19 11:54:24 +10001747 .probe = ftgmac100_probe,
Dmitry Torokhovbe125022017-03-01 17:24:47 -08001748 .remove = ftgmac100_remove,
Gavin Shanbb168e22016-07-19 11:54:24 +10001749 .driver = {
1750 .name = DRV_NAME,
1751 .of_match_table = ftgmac100_of_match,
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001752 },
1753};
Sachin Kamat14f645d2013-03-18 01:50:48 +00001754module_platform_driver(ftgmac100_driver);
Po-Yu Chuang69785b72011-06-08 23:32:48 +00001755
1756MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
1757MODULE_DESCRIPTION("FTGMAC100 driver");
1758MODULE_LICENSE("GPL");