174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2baf0fbfeSJeff Kirsher /*
3baf0fbfeSJeff Kirsher  * Faraday FTMAC100 10/100 Ethernet
4baf0fbfeSJeff Kirsher  *
5baf0fbfeSJeff Kirsher  * (C) Copyright 2009-2011 Faraday Technology
6baf0fbfeSJeff Kirsher  * Po-Yu Chuang <ratbert@faraday-tech.com>
7baf0fbfeSJeff Kirsher  */
8baf0fbfeSJeff Kirsher 
9baf0fbfeSJeff Kirsher #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
10baf0fbfeSJeff Kirsher 
11baf0fbfeSJeff Kirsher #include <linux/dma-mapping.h>
12baf0fbfeSJeff Kirsher #include <linux/etherdevice.h>
13baf0fbfeSJeff Kirsher #include <linux/ethtool.h>
1437c84890SSergei Antonov #include <linux/if_ether.h>
1530f837b7SVladimir Oltean #include <linux/if_vlan.h>
16baf0fbfeSJeff Kirsher #include <linux/init.h>
1717f1bbcaSThomas Faber #include <linux/interrupt.h>
18baf0fbfeSJeff Kirsher #include <linux/io.h>
19baf0fbfeSJeff Kirsher #include <linux/mii.h>
20baf0fbfeSJeff Kirsher #include <linux/module.h>
21ac316725SRandy Dunlap #include <linux/mod_devicetable.h>
22baf0fbfeSJeff Kirsher #include <linux/netdevice.h>
23baf0fbfeSJeff Kirsher #include <linux/platform_device.h>
24baf0fbfeSJeff Kirsher 
25baf0fbfeSJeff Kirsher #include "ftmac100.h"
26baf0fbfeSJeff Kirsher 
27baf0fbfeSJeff Kirsher #define DRV_NAME	"ftmac100"
28baf0fbfeSJeff Kirsher 
29baf0fbfeSJeff Kirsher #define RX_QUEUE_ENTRIES	128	/* must be power of 2 */
30baf0fbfeSJeff Kirsher #define TX_QUEUE_ENTRIES	16	/* must be power of 2 */
31baf0fbfeSJeff Kirsher 
32baf0fbfeSJeff Kirsher #define RX_BUF_SIZE		2044	/* must be smaller than 0x7ff */
3337c84890SSergei Antonov #define MAX_PKT_SIZE		RX_BUF_SIZE /* multi-segment not supported */
34baf0fbfeSJeff Kirsher 
35baf0fbfeSJeff Kirsher #if MAX_PKT_SIZE > 0x7ff
36baf0fbfeSJeff Kirsher #error invalid MAX_PKT_SIZE
37baf0fbfeSJeff Kirsher #endif
38baf0fbfeSJeff Kirsher 
39baf0fbfeSJeff Kirsher #if RX_BUF_SIZE > 0x7ff || RX_BUF_SIZE > PAGE_SIZE
40baf0fbfeSJeff Kirsher #error invalid RX_BUF_SIZE
41baf0fbfeSJeff Kirsher #endif
42baf0fbfeSJeff Kirsher 
43baf0fbfeSJeff Kirsher /******************************************************************************
44baf0fbfeSJeff Kirsher  * private data
45baf0fbfeSJeff Kirsher  *****************************************************************************/
46baf0fbfeSJeff Kirsher struct ftmac100_descs {
47baf0fbfeSJeff Kirsher 	struct ftmac100_rxdes rxdes[RX_QUEUE_ENTRIES];
48baf0fbfeSJeff Kirsher 	struct ftmac100_txdes txdes[TX_QUEUE_ENTRIES];
49baf0fbfeSJeff Kirsher };
50baf0fbfeSJeff Kirsher 
51baf0fbfeSJeff Kirsher struct ftmac100 {
52baf0fbfeSJeff Kirsher 	struct resource *res;
53baf0fbfeSJeff Kirsher 	void __iomem *base;
54baf0fbfeSJeff Kirsher 	int irq;
55baf0fbfeSJeff Kirsher 
56baf0fbfeSJeff Kirsher 	struct ftmac100_descs *descs;
57baf0fbfeSJeff Kirsher 	dma_addr_t descs_dma_addr;
58baf0fbfeSJeff Kirsher 
59baf0fbfeSJeff Kirsher 	unsigned int rx_pointer;
60baf0fbfeSJeff Kirsher 	unsigned int tx_clean_pointer;
61baf0fbfeSJeff Kirsher 	unsigned int tx_pointer;
62baf0fbfeSJeff Kirsher 	unsigned int tx_pending;
63baf0fbfeSJeff Kirsher 
64baf0fbfeSJeff Kirsher 	spinlock_t tx_lock;
65baf0fbfeSJeff Kirsher 
66baf0fbfeSJeff Kirsher 	struct net_device *netdev;
67baf0fbfeSJeff Kirsher 	struct device *dev;
68baf0fbfeSJeff Kirsher 	struct napi_struct napi;
69baf0fbfeSJeff Kirsher 
70baf0fbfeSJeff Kirsher 	struct mii_if_info mii;
71baf0fbfeSJeff Kirsher };
72baf0fbfeSJeff Kirsher 
73baf0fbfeSJeff Kirsher static int ftmac100_alloc_rx_page(struct ftmac100 *priv,
74baf0fbfeSJeff Kirsher 				  struct ftmac100_rxdes *rxdes, gfp_t gfp);
75baf0fbfeSJeff Kirsher 
76baf0fbfeSJeff Kirsher /******************************************************************************
77baf0fbfeSJeff Kirsher  * internal functions (hardware register access)
78baf0fbfeSJeff Kirsher  *****************************************************************************/
79baf0fbfeSJeff Kirsher #define INT_MASK_ALL_ENABLED	(FTMAC100_INT_RPKT_FINISH	| \
80baf0fbfeSJeff Kirsher 				 FTMAC100_INT_NORXBUF		| \
81baf0fbfeSJeff Kirsher 				 FTMAC100_INT_XPKT_OK		| \
82baf0fbfeSJeff Kirsher 				 FTMAC100_INT_XPKT_LOST		| \
83baf0fbfeSJeff Kirsher 				 FTMAC100_INT_RPKT_LOST		| \
84baf0fbfeSJeff Kirsher 				 FTMAC100_INT_AHB_ERR		| \
85baf0fbfeSJeff Kirsher 				 FTMAC100_INT_PHYSTS_CHG)
86baf0fbfeSJeff Kirsher 
87baf0fbfeSJeff Kirsher #define INT_MASK_ALL_DISABLED	0
88baf0fbfeSJeff Kirsher 
ftmac100_enable_all_int(struct ftmac100 * priv)89baf0fbfeSJeff Kirsher static void ftmac100_enable_all_int(struct ftmac100 *priv)
90baf0fbfeSJeff Kirsher {
91baf0fbfeSJeff Kirsher 	iowrite32(INT_MASK_ALL_ENABLED, priv->base + FTMAC100_OFFSET_IMR);
92baf0fbfeSJeff Kirsher }
93baf0fbfeSJeff Kirsher 
ftmac100_disable_all_int(struct ftmac100 * priv)94baf0fbfeSJeff Kirsher static void ftmac100_disable_all_int(struct ftmac100 *priv)
95baf0fbfeSJeff Kirsher {
96baf0fbfeSJeff Kirsher 	iowrite32(INT_MASK_ALL_DISABLED, priv->base + FTMAC100_OFFSET_IMR);
97baf0fbfeSJeff Kirsher }
98baf0fbfeSJeff Kirsher 
ftmac100_set_rx_ring_base(struct ftmac100 * priv,dma_addr_t addr)99baf0fbfeSJeff Kirsher static void ftmac100_set_rx_ring_base(struct ftmac100 *priv, dma_addr_t addr)
100baf0fbfeSJeff Kirsher {
101baf0fbfeSJeff Kirsher 	iowrite32(addr, priv->base + FTMAC100_OFFSET_RXR_BADR);
102baf0fbfeSJeff Kirsher }
103baf0fbfeSJeff Kirsher 
ftmac100_set_tx_ring_base(struct ftmac100 * priv,dma_addr_t addr)104baf0fbfeSJeff Kirsher static void ftmac100_set_tx_ring_base(struct ftmac100 *priv, dma_addr_t addr)
105baf0fbfeSJeff Kirsher {
106baf0fbfeSJeff Kirsher 	iowrite32(addr, priv->base + FTMAC100_OFFSET_TXR_BADR);
107baf0fbfeSJeff Kirsher }
108baf0fbfeSJeff Kirsher 
ftmac100_txdma_start_polling(struct ftmac100 * priv)109baf0fbfeSJeff Kirsher static void ftmac100_txdma_start_polling(struct ftmac100 *priv)
110baf0fbfeSJeff Kirsher {
111baf0fbfeSJeff Kirsher 	iowrite32(1, priv->base + FTMAC100_OFFSET_TXPD);
112baf0fbfeSJeff Kirsher }
113baf0fbfeSJeff Kirsher 
ftmac100_reset(struct ftmac100 * priv)114baf0fbfeSJeff Kirsher static int ftmac100_reset(struct ftmac100 *priv)
115baf0fbfeSJeff Kirsher {
116baf0fbfeSJeff Kirsher 	struct net_device *netdev = priv->netdev;
117baf0fbfeSJeff Kirsher 	int i;
118baf0fbfeSJeff Kirsher 
119baf0fbfeSJeff Kirsher 	/* NOTE: reset clears all registers */
120baf0fbfeSJeff Kirsher 	iowrite32(FTMAC100_MACCR_SW_RST, priv->base + FTMAC100_OFFSET_MACCR);
121baf0fbfeSJeff Kirsher 
122baf0fbfeSJeff Kirsher 	for (i = 0; i < 5; i++) {
123baf0fbfeSJeff Kirsher 		unsigned int maccr;
124baf0fbfeSJeff Kirsher 
125baf0fbfeSJeff Kirsher 		maccr = ioread32(priv->base + FTMAC100_OFFSET_MACCR);
126baf0fbfeSJeff Kirsher 		if (!(maccr & FTMAC100_MACCR_SW_RST)) {
127baf0fbfeSJeff Kirsher 			/*
128baf0fbfeSJeff Kirsher 			 * FTMAC100_MACCR_SW_RST cleared does not indicate
129baf0fbfeSJeff Kirsher 			 * that hardware reset completed (what the f*ck).
130baf0fbfeSJeff Kirsher 			 * We still need to wait for a while.
131baf0fbfeSJeff Kirsher 			 */
132baf0fbfeSJeff Kirsher 			udelay(500);
133baf0fbfeSJeff Kirsher 			return 0;
134baf0fbfeSJeff Kirsher 		}
135baf0fbfeSJeff Kirsher 
136baf0fbfeSJeff Kirsher 		udelay(1000);
137baf0fbfeSJeff Kirsher 	}
138baf0fbfeSJeff Kirsher 
139baf0fbfeSJeff Kirsher 	netdev_err(netdev, "software reset failed\n");
140baf0fbfeSJeff Kirsher 	return -EIO;
141baf0fbfeSJeff Kirsher }
142baf0fbfeSJeff Kirsher 
ftmac100_set_mac(struct ftmac100 * priv,const unsigned char * mac)143baf0fbfeSJeff Kirsher static void ftmac100_set_mac(struct ftmac100 *priv, const unsigned char *mac)
144baf0fbfeSJeff Kirsher {
145baf0fbfeSJeff Kirsher 	unsigned int maddr = mac[0] << 8 | mac[1];
146baf0fbfeSJeff Kirsher 	unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
147baf0fbfeSJeff Kirsher 
148baf0fbfeSJeff Kirsher 	iowrite32(maddr, priv->base + FTMAC100_OFFSET_MAC_MADR);
149baf0fbfeSJeff Kirsher 	iowrite32(laddr, priv->base + FTMAC100_OFFSET_MAC_LADR);
150baf0fbfeSJeff Kirsher }
151baf0fbfeSJeff Kirsher 
ftmac100_setup_mc_ht(struct ftmac100 * priv)152*7a1c3821SSergei Antonov static void ftmac100_setup_mc_ht(struct ftmac100 *priv)
153*7a1c3821SSergei Antonov {
154*7a1c3821SSergei Antonov 	struct netdev_hw_addr *ha;
155*7a1c3821SSergei Antonov 	u64 maht = 0; /* Multicast Address Hash Table */
156*7a1c3821SSergei Antonov 
157*7a1c3821SSergei Antonov 	netdev_for_each_mc_addr(ha, priv->netdev) {
158*7a1c3821SSergei Antonov 		u32 hash = ether_crc(ETH_ALEN, ha->addr) >> 26;
159*7a1c3821SSergei Antonov 
160*7a1c3821SSergei Antonov 		maht |= BIT_ULL(hash);
161*7a1c3821SSergei Antonov 	}
162*7a1c3821SSergei Antonov 
163*7a1c3821SSergei Antonov 	iowrite32(lower_32_bits(maht), priv->base + FTMAC100_OFFSET_MAHT0);
164*7a1c3821SSergei Antonov 	iowrite32(upper_32_bits(maht), priv->base + FTMAC100_OFFSET_MAHT1);
165*7a1c3821SSergei Antonov }
166*7a1c3821SSergei Antonov 
ftmac100_set_rx_bits(struct ftmac100 * priv,unsigned int * maccr)167*7a1c3821SSergei Antonov static void ftmac100_set_rx_bits(struct ftmac100 *priv, unsigned int *maccr)
168*7a1c3821SSergei Antonov {
169*7a1c3821SSergei Antonov 	struct net_device *netdev = priv->netdev;
170*7a1c3821SSergei Antonov 
171*7a1c3821SSergei Antonov 	/* Clear all */
172*7a1c3821SSergei Antonov 	*maccr &= ~(FTMAC100_MACCR_RCV_ALL | FTMAC100_MACCR_RX_MULTIPKT |
173*7a1c3821SSergei Antonov 		   FTMAC100_MACCR_HT_MULTI_EN);
174*7a1c3821SSergei Antonov 
175*7a1c3821SSergei Antonov 	/* Set the requested bits */
176*7a1c3821SSergei Antonov 	if (netdev->flags & IFF_PROMISC)
177*7a1c3821SSergei Antonov 		*maccr |= FTMAC100_MACCR_RCV_ALL;
178*7a1c3821SSergei Antonov 	if (netdev->flags & IFF_ALLMULTI)
179*7a1c3821SSergei Antonov 		*maccr |= FTMAC100_MACCR_RX_MULTIPKT;
180*7a1c3821SSergei Antonov 	else if (netdev_mc_count(netdev)) {
181*7a1c3821SSergei Antonov 		*maccr |= FTMAC100_MACCR_HT_MULTI_EN;
182*7a1c3821SSergei Antonov 		ftmac100_setup_mc_ht(priv);
183*7a1c3821SSergei Antonov 	}
184*7a1c3821SSergei Antonov }
185*7a1c3821SSergei Antonov 
186baf0fbfeSJeff Kirsher #define MACCR_ENABLE_ALL	(FTMAC100_MACCR_XMT_EN	| \
187baf0fbfeSJeff Kirsher 				 FTMAC100_MACCR_RCV_EN	| \
188baf0fbfeSJeff Kirsher 				 FTMAC100_MACCR_XDMA_EN	| \
189baf0fbfeSJeff Kirsher 				 FTMAC100_MACCR_RDMA_EN	| \
190baf0fbfeSJeff Kirsher 				 FTMAC100_MACCR_CRC_APD	| \
191baf0fbfeSJeff Kirsher 				 FTMAC100_MACCR_FULLDUP	| \
192baf0fbfeSJeff Kirsher 				 FTMAC100_MACCR_RX_RUNT	| \
193baf0fbfeSJeff Kirsher 				 FTMAC100_MACCR_RX_BROADPKT)
194baf0fbfeSJeff Kirsher 
ftmac100_start_hw(struct ftmac100 * priv)195baf0fbfeSJeff Kirsher static int ftmac100_start_hw(struct ftmac100 *priv)
196baf0fbfeSJeff Kirsher {
197baf0fbfeSJeff Kirsher 	struct net_device *netdev = priv->netdev;
19837c84890SSergei Antonov 	unsigned int maccr = MACCR_ENABLE_ALL;
199baf0fbfeSJeff Kirsher 
200baf0fbfeSJeff Kirsher 	if (ftmac100_reset(priv))
201baf0fbfeSJeff Kirsher 		return -EIO;
202baf0fbfeSJeff Kirsher 
203baf0fbfeSJeff Kirsher 	/* setup ring buffer base registers */
204baf0fbfeSJeff Kirsher 	ftmac100_set_rx_ring_base(priv,
205baf0fbfeSJeff Kirsher 				  priv->descs_dma_addr +
206baf0fbfeSJeff Kirsher 				  offsetof(struct ftmac100_descs, rxdes));
207baf0fbfeSJeff Kirsher 	ftmac100_set_tx_ring_base(priv,
208baf0fbfeSJeff Kirsher 				  priv->descs_dma_addr +
209baf0fbfeSJeff Kirsher 				  offsetof(struct ftmac100_descs, txdes));
210baf0fbfeSJeff Kirsher 
211baf0fbfeSJeff Kirsher 	iowrite32(FTMAC100_APTC_RXPOLL_CNT(1), priv->base + FTMAC100_OFFSET_APTC);
212baf0fbfeSJeff Kirsher 
213baf0fbfeSJeff Kirsher 	ftmac100_set_mac(priv, netdev->dev_addr);
214baf0fbfeSJeff Kirsher 
21537c84890SSergei Antonov 	 /* See ftmac100_change_mtu() */
21637c84890SSergei Antonov 	if (netdev->mtu > ETH_DATA_LEN)
21737c84890SSergei Antonov 		maccr |= FTMAC100_MACCR_RX_FTL;
21837c84890SSergei Antonov 
219*7a1c3821SSergei Antonov 	ftmac100_set_rx_bits(priv, &maccr);
22075943bc9SSergei Antonov 
22137c84890SSergei Antonov 	iowrite32(maccr, priv->base + FTMAC100_OFFSET_MACCR);
222baf0fbfeSJeff Kirsher 	return 0;
223baf0fbfeSJeff Kirsher }
224baf0fbfeSJeff Kirsher 
ftmac100_stop_hw(struct ftmac100 * priv)225baf0fbfeSJeff Kirsher static void ftmac100_stop_hw(struct ftmac100 *priv)
226baf0fbfeSJeff Kirsher {
227baf0fbfeSJeff Kirsher 	iowrite32(0, priv->base + FTMAC100_OFFSET_MACCR);
228baf0fbfeSJeff Kirsher }
229baf0fbfeSJeff Kirsher 
230baf0fbfeSJeff Kirsher /******************************************************************************
231baf0fbfeSJeff Kirsher  * internal functions (receive descriptor)
232baf0fbfeSJeff Kirsher  *****************************************************************************/
ftmac100_rxdes_first_segment(struct ftmac100_rxdes * rxdes)233baf0fbfeSJeff Kirsher static bool ftmac100_rxdes_first_segment(struct ftmac100_rxdes *rxdes)
234baf0fbfeSJeff Kirsher {
235baf0fbfeSJeff Kirsher 	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_FRS);
236baf0fbfeSJeff Kirsher }
237baf0fbfeSJeff Kirsher 
ftmac100_rxdes_last_segment(struct ftmac100_rxdes * rxdes)238baf0fbfeSJeff Kirsher static bool ftmac100_rxdes_last_segment(struct ftmac100_rxdes *rxdes)
239baf0fbfeSJeff Kirsher {
240baf0fbfeSJeff Kirsher 	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_LRS);
241baf0fbfeSJeff Kirsher }
242baf0fbfeSJeff Kirsher 
ftmac100_rxdes_owned_by_dma(struct ftmac100_rxdes * rxdes)243baf0fbfeSJeff Kirsher static bool ftmac100_rxdes_owned_by_dma(struct ftmac100_rxdes *rxdes)
244baf0fbfeSJeff Kirsher {
245baf0fbfeSJeff Kirsher 	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RXDMA_OWN);
246baf0fbfeSJeff Kirsher }
247baf0fbfeSJeff Kirsher 
ftmac100_rxdes_set_dma_own(struct ftmac100_rxdes * rxdes)248baf0fbfeSJeff Kirsher static void ftmac100_rxdes_set_dma_own(struct ftmac100_rxdes *rxdes)
249baf0fbfeSJeff Kirsher {
250baf0fbfeSJeff Kirsher 	/* clear status bits */
251baf0fbfeSJeff Kirsher 	rxdes->rxdes0 = cpu_to_le32(FTMAC100_RXDES0_RXDMA_OWN);
252baf0fbfeSJeff Kirsher }
253baf0fbfeSJeff Kirsher 
ftmac100_rxdes_rx_error(struct ftmac100_rxdes * rxdes)254baf0fbfeSJeff Kirsher static bool ftmac100_rxdes_rx_error(struct ftmac100_rxdes *rxdes)
255baf0fbfeSJeff Kirsher {
256baf0fbfeSJeff Kirsher 	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RX_ERR);
257baf0fbfeSJeff Kirsher }
258baf0fbfeSJeff Kirsher 
ftmac100_rxdes_crc_error(struct ftmac100_rxdes * rxdes)259baf0fbfeSJeff Kirsher static bool ftmac100_rxdes_crc_error(struct ftmac100_rxdes *rxdes)
260baf0fbfeSJeff Kirsher {
261baf0fbfeSJeff Kirsher 	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_CRC_ERR);
262baf0fbfeSJeff Kirsher }
263baf0fbfeSJeff Kirsher 
ftmac100_rxdes_runt(struct ftmac100_rxdes * rxdes)264baf0fbfeSJeff Kirsher static bool ftmac100_rxdes_runt(struct ftmac100_rxdes *rxdes)
265baf0fbfeSJeff Kirsher {
266baf0fbfeSJeff Kirsher 	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RUNT);
267baf0fbfeSJeff Kirsher }
268baf0fbfeSJeff Kirsher 
ftmac100_rxdes_odd_nibble(struct ftmac100_rxdes * rxdes)269baf0fbfeSJeff Kirsher static bool ftmac100_rxdes_odd_nibble(struct ftmac100_rxdes *rxdes)
270baf0fbfeSJeff Kirsher {
271baf0fbfeSJeff Kirsher 	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RX_ODD_NB);
272baf0fbfeSJeff Kirsher }
273baf0fbfeSJeff Kirsher 
ftmac100_rxdes_frame_length(struct ftmac100_rxdes * rxdes)274baf0fbfeSJeff Kirsher static unsigned int ftmac100_rxdes_frame_length(struct ftmac100_rxdes *rxdes)
275baf0fbfeSJeff Kirsher {
276baf0fbfeSJeff Kirsher 	return le32_to_cpu(rxdes->rxdes0) & FTMAC100_RXDES0_RFL;
277baf0fbfeSJeff Kirsher }
278baf0fbfeSJeff Kirsher 
ftmac100_rxdes_multicast(struct ftmac100_rxdes * rxdes)279baf0fbfeSJeff Kirsher static bool ftmac100_rxdes_multicast(struct ftmac100_rxdes *rxdes)
280baf0fbfeSJeff Kirsher {
281baf0fbfeSJeff Kirsher 	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_MULTICAST);
282baf0fbfeSJeff Kirsher }
283baf0fbfeSJeff Kirsher 
ftmac100_rxdes_set_buffer_size(struct ftmac100_rxdes * rxdes,unsigned int size)284baf0fbfeSJeff Kirsher static void ftmac100_rxdes_set_buffer_size(struct ftmac100_rxdes *rxdes,
285baf0fbfeSJeff Kirsher 					   unsigned int size)
286baf0fbfeSJeff Kirsher {
287baf0fbfeSJeff Kirsher 	rxdes->rxdes1 &= cpu_to_le32(FTMAC100_RXDES1_EDORR);
288baf0fbfeSJeff Kirsher 	rxdes->rxdes1 |= cpu_to_le32(FTMAC100_RXDES1_RXBUF_SIZE(size));
289baf0fbfeSJeff Kirsher }
290baf0fbfeSJeff Kirsher 
ftmac100_rxdes_set_end_of_ring(struct ftmac100_rxdes * rxdes)291baf0fbfeSJeff Kirsher static void ftmac100_rxdes_set_end_of_ring(struct ftmac100_rxdes *rxdes)
292baf0fbfeSJeff Kirsher {
293baf0fbfeSJeff Kirsher 	rxdes->rxdes1 |= cpu_to_le32(FTMAC100_RXDES1_EDORR);
294baf0fbfeSJeff Kirsher }
295baf0fbfeSJeff Kirsher 
ftmac100_rxdes_set_dma_addr(struct ftmac100_rxdes * rxdes,dma_addr_t addr)296baf0fbfeSJeff Kirsher static void ftmac100_rxdes_set_dma_addr(struct ftmac100_rxdes *rxdes,
297baf0fbfeSJeff Kirsher 					dma_addr_t addr)
298baf0fbfeSJeff Kirsher {
299baf0fbfeSJeff Kirsher 	rxdes->rxdes2 = cpu_to_le32(addr);
300baf0fbfeSJeff Kirsher }
301baf0fbfeSJeff Kirsher 
ftmac100_rxdes_get_dma_addr(struct ftmac100_rxdes * rxdes)302baf0fbfeSJeff Kirsher static dma_addr_t ftmac100_rxdes_get_dma_addr(struct ftmac100_rxdes *rxdes)
303baf0fbfeSJeff Kirsher {
304baf0fbfeSJeff Kirsher 	return le32_to_cpu(rxdes->rxdes2);
305baf0fbfeSJeff Kirsher }
306baf0fbfeSJeff Kirsher 
307baf0fbfeSJeff Kirsher /*
308baf0fbfeSJeff Kirsher  * rxdes3 is not used by hardware. We use it to keep track of page.
309baf0fbfeSJeff Kirsher  * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu().
310baf0fbfeSJeff Kirsher  */
ftmac100_rxdes_set_page(struct ftmac100_rxdes * rxdes,struct page * page)311baf0fbfeSJeff Kirsher static void ftmac100_rxdes_set_page(struct ftmac100_rxdes *rxdes, struct page *page)
312baf0fbfeSJeff Kirsher {
313baf0fbfeSJeff Kirsher 	rxdes->rxdes3 = (unsigned int)page;
314baf0fbfeSJeff Kirsher }
315baf0fbfeSJeff Kirsher 
ftmac100_rxdes_get_page(struct ftmac100_rxdes * rxdes)316baf0fbfeSJeff Kirsher static struct page *ftmac100_rxdes_get_page(struct ftmac100_rxdes *rxdes)
317baf0fbfeSJeff Kirsher {
318baf0fbfeSJeff Kirsher 	return (struct page *)rxdes->rxdes3;
319baf0fbfeSJeff Kirsher }
320baf0fbfeSJeff Kirsher 
321baf0fbfeSJeff Kirsher /******************************************************************************
322baf0fbfeSJeff Kirsher  * internal functions (receive)
323baf0fbfeSJeff Kirsher  *****************************************************************************/
ftmac100_next_rx_pointer(int pointer)324baf0fbfeSJeff Kirsher static int ftmac100_next_rx_pointer(int pointer)
325baf0fbfeSJeff Kirsher {
326baf0fbfeSJeff Kirsher 	return (pointer + 1) & (RX_QUEUE_ENTRIES - 1);
327baf0fbfeSJeff Kirsher }
328baf0fbfeSJeff Kirsher 
ftmac100_rx_pointer_advance(struct ftmac100 * priv)329baf0fbfeSJeff Kirsher static void ftmac100_rx_pointer_advance(struct ftmac100 *priv)
330baf0fbfeSJeff Kirsher {
331baf0fbfeSJeff Kirsher 	priv->rx_pointer = ftmac100_next_rx_pointer(priv->rx_pointer);
332baf0fbfeSJeff Kirsher }
333baf0fbfeSJeff Kirsher 
ftmac100_current_rxdes(struct ftmac100 * priv)334baf0fbfeSJeff Kirsher static struct ftmac100_rxdes *ftmac100_current_rxdes(struct ftmac100 *priv)
335baf0fbfeSJeff Kirsher {
336baf0fbfeSJeff Kirsher 	return &priv->descs->rxdes[priv->rx_pointer];
337baf0fbfeSJeff Kirsher }
338baf0fbfeSJeff Kirsher 
339baf0fbfeSJeff Kirsher static struct ftmac100_rxdes *
ftmac100_rx_locate_first_segment(struct ftmac100 * priv)340baf0fbfeSJeff Kirsher ftmac100_rx_locate_first_segment(struct ftmac100 *priv)
341baf0fbfeSJeff Kirsher {
342baf0fbfeSJeff Kirsher 	struct ftmac100_rxdes *rxdes = ftmac100_current_rxdes(priv);
343baf0fbfeSJeff Kirsher 
344baf0fbfeSJeff Kirsher 	while (!ftmac100_rxdes_owned_by_dma(rxdes)) {
345baf0fbfeSJeff Kirsher 		if (ftmac100_rxdes_first_segment(rxdes))
346baf0fbfeSJeff Kirsher 			return rxdes;
347baf0fbfeSJeff Kirsher 
348baf0fbfeSJeff Kirsher 		ftmac100_rxdes_set_dma_own(rxdes);
349baf0fbfeSJeff Kirsher 		ftmac100_rx_pointer_advance(priv);
350baf0fbfeSJeff Kirsher 		rxdes = ftmac100_current_rxdes(priv);
351baf0fbfeSJeff Kirsher 	}
352baf0fbfeSJeff Kirsher 
353baf0fbfeSJeff Kirsher 	return NULL;
354baf0fbfeSJeff Kirsher }
355baf0fbfeSJeff Kirsher 
ftmac100_rx_packet_error(struct ftmac100 * priv,struct ftmac100_rxdes * rxdes)356baf0fbfeSJeff Kirsher static bool ftmac100_rx_packet_error(struct ftmac100 *priv,
357baf0fbfeSJeff Kirsher 				     struct ftmac100_rxdes *rxdes)
358baf0fbfeSJeff Kirsher {
359baf0fbfeSJeff Kirsher 	struct net_device *netdev = priv->netdev;
360baf0fbfeSJeff Kirsher 	bool error = false;
361baf0fbfeSJeff Kirsher 
362baf0fbfeSJeff Kirsher 	if (unlikely(ftmac100_rxdes_rx_error(rxdes))) {
363baf0fbfeSJeff Kirsher 		if (net_ratelimit())
364baf0fbfeSJeff Kirsher 			netdev_info(netdev, "rx err\n");
365baf0fbfeSJeff Kirsher 
366baf0fbfeSJeff Kirsher 		netdev->stats.rx_errors++;
367baf0fbfeSJeff Kirsher 		error = true;
368baf0fbfeSJeff Kirsher 	}
369baf0fbfeSJeff Kirsher 
370baf0fbfeSJeff Kirsher 	if (unlikely(ftmac100_rxdes_crc_error(rxdes))) {
371baf0fbfeSJeff Kirsher 		if (net_ratelimit())
372baf0fbfeSJeff Kirsher 			netdev_info(netdev, "rx crc err\n");
373baf0fbfeSJeff Kirsher 
374baf0fbfeSJeff Kirsher 		netdev->stats.rx_crc_errors++;
375baf0fbfeSJeff Kirsher 		error = true;
376baf0fbfeSJeff Kirsher 	}
377baf0fbfeSJeff Kirsher 
37855f6f3dbSVladimir Oltean 	if (unlikely(ftmac100_rxdes_runt(rxdes))) {
379baf0fbfeSJeff Kirsher 		if (net_ratelimit())
380baf0fbfeSJeff Kirsher 			netdev_info(netdev, "rx runt\n");
381baf0fbfeSJeff Kirsher 
382baf0fbfeSJeff Kirsher 		netdev->stats.rx_length_errors++;
383baf0fbfeSJeff Kirsher 		error = true;
384baf0fbfeSJeff Kirsher 	} else if (unlikely(ftmac100_rxdes_odd_nibble(rxdes))) {
385baf0fbfeSJeff Kirsher 		if (net_ratelimit())
386baf0fbfeSJeff Kirsher 			netdev_info(netdev, "rx odd nibble\n");
387baf0fbfeSJeff Kirsher 
388baf0fbfeSJeff Kirsher 		netdev->stats.rx_length_errors++;
389baf0fbfeSJeff Kirsher 		error = true;
390baf0fbfeSJeff Kirsher 	}
39155f6f3dbSVladimir Oltean 	/*
39255f6f3dbSVladimir Oltean 	 * FTMAC100_RXDES0_FTL is not an error, it just indicates that the
39355f6f3dbSVladimir Oltean 	 * frame is longer than 1518 octets. Receiving these is possible when
39455f6f3dbSVladimir Oltean 	 * we told the hardware not to drop them, via FTMAC100_MACCR_RX_FTL.
39555f6f3dbSVladimir Oltean 	 */
396baf0fbfeSJeff Kirsher 
397baf0fbfeSJeff Kirsher 	return error;
398baf0fbfeSJeff Kirsher }
399baf0fbfeSJeff Kirsher 
ftmac100_rx_drop_packet(struct ftmac100 * priv)400baf0fbfeSJeff Kirsher static void ftmac100_rx_drop_packet(struct ftmac100 *priv)
401baf0fbfeSJeff Kirsher {
402baf0fbfeSJeff Kirsher 	struct net_device *netdev = priv->netdev;
403baf0fbfeSJeff Kirsher 	struct ftmac100_rxdes *rxdes = ftmac100_current_rxdes(priv);
404baf0fbfeSJeff Kirsher 	bool done = false;
405baf0fbfeSJeff Kirsher 
406baf0fbfeSJeff Kirsher 	if (net_ratelimit())
407baf0fbfeSJeff Kirsher 		netdev_dbg(netdev, "drop packet %p\n", rxdes);
408baf0fbfeSJeff Kirsher 
409baf0fbfeSJeff Kirsher 	do {
410baf0fbfeSJeff Kirsher 		if (ftmac100_rxdes_last_segment(rxdes))
411baf0fbfeSJeff Kirsher 			done = true;
412baf0fbfeSJeff Kirsher 
413baf0fbfeSJeff Kirsher 		ftmac100_rxdes_set_dma_own(rxdes);
414baf0fbfeSJeff Kirsher 		ftmac100_rx_pointer_advance(priv);
415baf0fbfeSJeff Kirsher 		rxdes = ftmac100_current_rxdes(priv);
416baf0fbfeSJeff Kirsher 	} while (!done && !ftmac100_rxdes_owned_by_dma(rxdes));
417baf0fbfeSJeff Kirsher 
418baf0fbfeSJeff Kirsher 	netdev->stats.rx_dropped++;
419baf0fbfeSJeff Kirsher }
420baf0fbfeSJeff Kirsher 
ftmac100_rx_packet(struct ftmac100 * priv,int * processed)421baf0fbfeSJeff Kirsher static bool ftmac100_rx_packet(struct ftmac100 *priv, int *processed)
422baf0fbfeSJeff Kirsher {
423baf0fbfeSJeff Kirsher 	struct net_device *netdev = priv->netdev;
424baf0fbfeSJeff Kirsher 	struct ftmac100_rxdes *rxdes;
425baf0fbfeSJeff Kirsher 	struct sk_buff *skb;
426baf0fbfeSJeff Kirsher 	struct page *page;
427baf0fbfeSJeff Kirsher 	dma_addr_t map;
428baf0fbfeSJeff Kirsher 	int length;
4295bca178eSGustavo A. R. Silva 	bool ret;
430baf0fbfeSJeff Kirsher 
431baf0fbfeSJeff Kirsher 	rxdes = ftmac100_rx_locate_first_segment(priv);
432baf0fbfeSJeff Kirsher 	if (!rxdes)
433baf0fbfeSJeff Kirsher 		return false;
434baf0fbfeSJeff Kirsher 
435baf0fbfeSJeff Kirsher 	if (unlikely(ftmac100_rx_packet_error(priv, rxdes))) {
436baf0fbfeSJeff Kirsher 		ftmac100_rx_drop_packet(priv);
437baf0fbfeSJeff Kirsher 		return true;
438baf0fbfeSJeff Kirsher 	}
439baf0fbfeSJeff Kirsher 
44055f6f3dbSVladimir Oltean 	/* We don't support multi-segment packets for now, so drop them. */
4415bca178eSGustavo A. R. Silva 	ret = ftmac100_rxdes_last_segment(rxdes);
44255f6f3dbSVladimir Oltean 	if (unlikely(!ret)) {
44355f6f3dbSVladimir Oltean 		netdev->stats.rx_length_errors++;
44455f6f3dbSVladimir Oltean 		ftmac100_rx_drop_packet(priv);
44555f6f3dbSVladimir Oltean 		return true;
44655f6f3dbSVladimir Oltean 	}
447baf0fbfeSJeff Kirsher 
448baf0fbfeSJeff Kirsher 	/* start processing */
449baf0fbfeSJeff Kirsher 	skb = netdev_alloc_skb_ip_align(netdev, 128);
450baf0fbfeSJeff Kirsher 	if (unlikely(!skb)) {
451baf0fbfeSJeff Kirsher 		if (net_ratelimit())
452baf0fbfeSJeff Kirsher 			netdev_err(netdev, "rx skb alloc failed\n");
453baf0fbfeSJeff Kirsher 
454baf0fbfeSJeff Kirsher 		ftmac100_rx_drop_packet(priv);
455baf0fbfeSJeff Kirsher 		return true;
456baf0fbfeSJeff Kirsher 	}
457baf0fbfeSJeff Kirsher 
458baf0fbfeSJeff Kirsher 	if (unlikely(ftmac100_rxdes_multicast(rxdes)))
459baf0fbfeSJeff Kirsher 		netdev->stats.multicast++;
460baf0fbfeSJeff Kirsher 
461baf0fbfeSJeff Kirsher 	map = ftmac100_rxdes_get_dma_addr(rxdes);
462baf0fbfeSJeff Kirsher 	dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
463baf0fbfeSJeff Kirsher 
464baf0fbfeSJeff Kirsher 	length = ftmac100_rxdes_frame_length(rxdes);
465baf0fbfeSJeff Kirsher 	page = ftmac100_rxdes_get_page(rxdes);
466baf0fbfeSJeff Kirsher 	skb_fill_page_desc(skb, 0, page, 0, length);
467baf0fbfeSJeff Kirsher 	skb->len += length;
468baf0fbfeSJeff Kirsher 	skb->data_len += length;
46996cd8951SEric Dumazet 
4706ecd09ddSEric Dumazet 	if (length > 128) {
47196cd8951SEric Dumazet 		skb->truesize += PAGE_SIZE;
4726ecd09ddSEric Dumazet 		/* We pull the minimum amount into linear part */
4736ecd09ddSEric Dumazet 		__pskb_pull_tail(skb, ETH_HLEN);
4746ecd09ddSEric Dumazet 	} else {
4756ecd09ddSEric Dumazet 		/* Small frames are copied into linear part to free one page */
4766ecd09ddSEric Dumazet 		__pskb_pull_tail(skb, length);
4776ecd09ddSEric Dumazet 	}
478baf0fbfeSJeff Kirsher 	ftmac100_alloc_rx_page(priv, rxdes, GFP_ATOMIC);
479baf0fbfeSJeff Kirsher 
480baf0fbfeSJeff Kirsher 	ftmac100_rx_pointer_advance(priv);
481baf0fbfeSJeff Kirsher 
482baf0fbfeSJeff Kirsher 	skb->protocol = eth_type_trans(skb, netdev);
483baf0fbfeSJeff Kirsher 
484baf0fbfeSJeff Kirsher 	netdev->stats.rx_packets++;
485baf0fbfeSJeff Kirsher 	netdev->stats.rx_bytes += skb->len;
486baf0fbfeSJeff Kirsher 
487baf0fbfeSJeff Kirsher 	/* push packet to protocol stack */
488baf0fbfeSJeff Kirsher 	netif_receive_skb(skb);
489baf0fbfeSJeff Kirsher 
490baf0fbfeSJeff Kirsher 	(*processed)++;
491baf0fbfeSJeff Kirsher 	return true;
492baf0fbfeSJeff Kirsher }
493baf0fbfeSJeff Kirsher 
494baf0fbfeSJeff Kirsher /******************************************************************************
495baf0fbfeSJeff Kirsher  * internal functions (transmit descriptor)
496baf0fbfeSJeff Kirsher  *****************************************************************************/
ftmac100_txdes_reset(struct ftmac100_txdes * txdes)497baf0fbfeSJeff Kirsher static void ftmac100_txdes_reset(struct ftmac100_txdes *txdes)
498baf0fbfeSJeff Kirsher {
499baf0fbfeSJeff Kirsher 	/* clear all except end of ring bit */
500baf0fbfeSJeff Kirsher 	txdes->txdes0 = 0;
501baf0fbfeSJeff Kirsher 	txdes->txdes1 &= cpu_to_le32(FTMAC100_TXDES1_EDOTR);
502baf0fbfeSJeff Kirsher 	txdes->txdes2 = 0;
503baf0fbfeSJeff Kirsher 	txdes->txdes3 = 0;
504baf0fbfeSJeff Kirsher }
505baf0fbfeSJeff Kirsher 
ftmac100_txdes_owned_by_dma(struct ftmac100_txdes * txdes)506baf0fbfeSJeff Kirsher static bool ftmac100_txdes_owned_by_dma(struct ftmac100_txdes *txdes)
507baf0fbfeSJeff Kirsher {
508baf0fbfeSJeff Kirsher 	return txdes->txdes0 & cpu_to_le32(FTMAC100_TXDES0_TXDMA_OWN);
509baf0fbfeSJeff Kirsher }
510baf0fbfeSJeff Kirsher 
ftmac100_txdes_set_dma_own(struct ftmac100_txdes * txdes)511baf0fbfeSJeff Kirsher static void ftmac100_txdes_set_dma_own(struct ftmac100_txdes *txdes)
512baf0fbfeSJeff Kirsher {
513baf0fbfeSJeff Kirsher 	/*
514baf0fbfeSJeff Kirsher 	 * Make sure dma own bit will not be set before any other
515baf0fbfeSJeff Kirsher 	 * descriptor fields.
516baf0fbfeSJeff Kirsher 	 */
517baf0fbfeSJeff Kirsher 	wmb();
518baf0fbfeSJeff Kirsher 	txdes->txdes0 |= cpu_to_le32(FTMAC100_TXDES0_TXDMA_OWN);
519baf0fbfeSJeff Kirsher }
520baf0fbfeSJeff Kirsher 
ftmac100_txdes_excessive_collision(struct ftmac100_txdes * txdes)521baf0fbfeSJeff Kirsher static bool ftmac100_txdes_excessive_collision(struct ftmac100_txdes *txdes)
522baf0fbfeSJeff Kirsher {
523baf0fbfeSJeff Kirsher 	return txdes->txdes0 & cpu_to_le32(FTMAC100_TXDES0_TXPKT_EXSCOL);
524baf0fbfeSJeff Kirsher }
525baf0fbfeSJeff Kirsher 
ftmac100_txdes_late_collision(struct ftmac100_txdes * txdes)526baf0fbfeSJeff Kirsher static bool ftmac100_txdes_late_collision(struct ftmac100_txdes *txdes)
527baf0fbfeSJeff Kirsher {
528baf0fbfeSJeff Kirsher 	return txdes->txdes0 & cpu_to_le32(FTMAC100_TXDES0_TXPKT_LATECOL);
529baf0fbfeSJeff Kirsher }
530baf0fbfeSJeff Kirsher 
ftmac100_txdes_set_end_of_ring(struct ftmac100_txdes * txdes)531baf0fbfeSJeff Kirsher static void ftmac100_txdes_set_end_of_ring(struct ftmac100_txdes *txdes)
532baf0fbfeSJeff Kirsher {
533baf0fbfeSJeff Kirsher 	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_EDOTR);
534baf0fbfeSJeff Kirsher }
535baf0fbfeSJeff Kirsher 
ftmac100_txdes_set_first_segment(struct ftmac100_txdes * txdes)536baf0fbfeSJeff Kirsher static void ftmac100_txdes_set_first_segment(struct ftmac100_txdes *txdes)
537baf0fbfeSJeff Kirsher {
538baf0fbfeSJeff Kirsher 	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_FTS);
539baf0fbfeSJeff Kirsher }
540baf0fbfeSJeff Kirsher 
ftmac100_txdes_set_last_segment(struct ftmac100_txdes * txdes)541baf0fbfeSJeff Kirsher static void ftmac100_txdes_set_last_segment(struct ftmac100_txdes *txdes)
542baf0fbfeSJeff Kirsher {
543baf0fbfeSJeff Kirsher 	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_LTS);
544baf0fbfeSJeff Kirsher }
545baf0fbfeSJeff Kirsher 
ftmac100_txdes_set_txint(struct ftmac100_txdes * txdes)546baf0fbfeSJeff Kirsher static void ftmac100_txdes_set_txint(struct ftmac100_txdes *txdes)
547baf0fbfeSJeff Kirsher {
548baf0fbfeSJeff Kirsher 	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_TXIC);
549baf0fbfeSJeff Kirsher }
550baf0fbfeSJeff Kirsher 
ftmac100_txdes_set_buffer_size(struct ftmac100_txdes * txdes,unsigned int len)551baf0fbfeSJeff Kirsher static void ftmac100_txdes_set_buffer_size(struct ftmac100_txdes *txdes,
552baf0fbfeSJeff Kirsher 					   unsigned int len)
553baf0fbfeSJeff Kirsher {
554baf0fbfeSJeff Kirsher 	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_TXBUF_SIZE(len));
555baf0fbfeSJeff Kirsher }
556baf0fbfeSJeff Kirsher 
ftmac100_txdes_set_dma_addr(struct ftmac100_txdes * txdes,dma_addr_t addr)557baf0fbfeSJeff Kirsher static void ftmac100_txdes_set_dma_addr(struct ftmac100_txdes *txdes,
558baf0fbfeSJeff Kirsher 					dma_addr_t addr)
559baf0fbfeSJeff Kirsher {
560baf0fbfeSJeff Kirsher 	txdes->txdes2 = cpu_to_le32(addr);
561baf0fbfeSJeff Kirsher }
562baf0fbfeSJeff Kirsher 
ftmac100_txdes_get_dma_addr(struct ftmac100_txdes * txdes)563baf0fbfeSJeff Kirsher static dma_addr_t ftmac100_txdes_get_dma_addr(struct ftmac100_txdes *txdes)
564baf0fbfeSJeff Kirsher {
565baf0fbfeSJeff Kirsher 	return le32_to_cpu(txdes->txdes2);
566baf0fbfeSJeff Kirsher }
567baf0fbfeSJeff Kirsher 
568baf0fbfeSJeff Kirsher /*
569baf0fbfeSJeff Kirsher  * txdes3 is not used by hardware. We use it to keep track of socket buffer.
570baf0fbfeSJeff Kirsher  * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu().
571baf0fbfeSJeff Kirsher  */
ftmac100_txdes_set_skb(struct ftmac100_txdes * txdes,struct sk_buff * skb)572baf0fbfeSJeff Kirsher static void ftmac100_txdes_set_skb(struct ftmac100_txdes *txdes, struct sk_buff *skb)
573baf0fbfeSJeff Kirsher {
574baf0fbfeSJeff Kirsher 	txdes->txdes3 = (unsigned int)skb;
575baf0fbfeSJeff Kirsher }
576baf0fbfeSJeff Kirsher 
ftmac100_txdes_get_skb(struct ftmac100_txdes * txdes)577baf0fbfeSJeff Kirsher static struct sk_buff *ftmac100_txdes_get_skb(struct ftmac100_txdes *txdes)
578baf0fbfeSJeff Kirsher {
579baf0fbfeSJeff Kirsher 	return (struct sk_buff *)txdes->txdes3;
580baf0fbfeSJeff Kirsher }
581baf0fbfeSJeff Kirsher 
582baf0fbfeSJeff Kirsher /******************************************************************************
583baf0fbfeSJeff Kirsher  * internal functions (transmit)
584baf0fbfeSJeff Kirsher  *****************************************************************************/
ftmac100_next_tx_pointer(int pointer)585baf0fbfeSJeff Kirsher static int ftmac100_next_tx_pointer(int pointer)
586baf0fbfeSJeff Kirsher {
587baf0fbfeSJeff Kirsher 	return (pointer + 1) & (TX_QUEUE_ENTRIES - 1);
588baf0fbfeSJeff Kirsher }
589baf0fbfeSJeff Kirsher 
ftmac100_tx_pointer_advance(struct ftmac100 * priv)590baf0fbfeSJeff Kirsher static void ftmac100_tx_pointer_advance(struct ftmac100 *priv)
591baf0fbfeSJeff Kirsher {
592baf0fbfeSJeff Kirsher 	priv->tx_pointer = ftmac100_next_tx_pointer(priv->tx_pointer);
593baf0fbfeSJeff Kirsher }
594baf0fbfeSJeff Kirsher 
ftmac100_tx_clean_pointer_advance(struct ftmac100 * priv)595baf0fbfeSJeff Kirsher static void ftmac100_tx_clean_pointer_advance(struct ftmac100 *priv)
596baf0fbfeSJeff Kirsher {
597baf0fbfeSJeff Kirsher 	priv->tx_clean_pointer = ftmac100_next_tx_pointer(priv->tx_clean_pointer);
598baf0fbfeSJeff Kirsher }
599baf0fbfeSJeff Kirsher 
ftmac100_current_txdes(struct ftmac100 * priv)600baf0fbfeSJeff Kirsher static struct ftmac100_txdes *ftmac100_current_txdes(struct ftmac100 *priv)
601baf0fbfeSJeff Kirsher {
602baf0fbfeSJeff Kirsher 	return &priv->descs->txdes[priv->tx_pointer];
603baf0fbfeSJeff Kirsher }
604baf0fbfeSJeff Kirsher 
ftmac100_current_clean_txdes(struct ftmac100 * priv)605baf0fbfeSJeff Kirsher static struct ftmac100_txdes *ftmac100_current_clean_txdes(struct ftmac100 *priv)
606baf0fbfeSJeff Kirsher {
607baf0fbfeSJeff Kirsher 	return &priv->descs->txdes[priv->tx_clean_pointer];
608baf0fbfeSJeff Kirsher }
609baf0fbfeSJeff Kirsher 
ftmac100_tx_complete_packet(struct ftmac100 * priv)610baf0fbfeSJeff Kirsher static bool ftmac100_tx_complete_packet(struct ftmac100 *priv)
611baf0fbfeSJeff Kirsher {
612baf0fbfeSJeff Kirsher 	struct net_device *netdev = priv->netdev;
613baf0fbfeSJeff Kirsher 	struct ftmac100_txdes *txdes;
614baf0fbfeSJeff Kirsher 	struct sk_buff *skb;
615baf0fbfeSJeff Kirsher 	dma_addr_t map;
616baf0fbfeSJeff Kirsher 
617baf0fbfeSJeff Kirsher 	if (priv->tx_pending == 0)
618baf0fbfeSJeff Kirsher 		return false;
619baf0fbfeSJeff Kirsher 
620baf0fbfeSJeff Kirsher 	txdes = ftmac100_current_clean_txdes(priv);
621baf0fbfeSJeff Kirsher 
622baf0fbfeSJeff Kirsher 	if (ftmac100_txdes_owned_by_dma(txdes))
623baf0fbfeSJeff Kirsher 		return false;
624baf0fbfeSJeff Kirsher 
625baf0fbfeSJeff Kirsher 	skb = ftmac100_txdes_get_skb(txdes);
626baf0fbfeSJeff Kirsher 	map = ftmac100_txdes_get_dma_addr(txdes);
627baf0fbfeSJeff Kirsher 
628baf0fbfeSJeff Kirsher 	if (unlikely(ftmac100_txdes_excessive_collision(txdes) ||
629baf0fbfeSJeff Kirsher 		     ftmac100_txdes_late_collision(txdes))) {
630baf0fbfeSJeff Kirsher 		/*
631baf0fbfeSJeff Kirsher 		 * packet transmitted to ethernet lost due to late collision
632baf0fbfeSJeff Kirsher 		 * or excessive collision
633baf0fbfeSJeff Kirsher 		 */
634baf0fbfeSJeff Kirsher 		netdev->stats.tx_aborted_errors++;
635baf0fbfeSJeff Kirsher 	} else {
636baf0fbfeSJeff Kirsher 		netdev->stats.tx_packets++;
637baf0fbfeSJeff Kirsher 		netdev->stats.tx_bytes += skb->len;
638baf0fbfeSJeff Kirsher 	}
639baf0fbfeSJeff Kirsher 
640baf0fbfeSJeff Kirsher 	dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
641baf0fbfeSJeff Kirsher 	dev_kfree_skb(skb);
642baf0fbfeSJeff Kirsher 
643baf0fbfeSJeff Kirsher 	ftmac100_txdes_reset(txdes);
644baf0fbfeSJeff Kirsher 
645baf0fbfeSJeff Kirsher 	ftmac100_tx_clean_pointer_advance(priv);
646baf0fbfeSJeff Kirsher 
647baf0fbfeSJeff Kirsher 	spin_lock(&priv->tx_lock);
648baf0fbfeSJeff Kirsher 	priv->tx_pending--;
649baf0fbfeSJeff Kirsher 	spin_unlock(&priv->tx_lock);
650baf0fbfeSJeff Kirsher 	netif_wake_queue(netdev);
651baf0fbfeSJeff Kirsher 
652baf0fbfeSJeff Kirsher 	return true;
653baf0fbfeSJeff Kirsher }
654baf0fbfeSJeff Kirsher 
ftmac100_tx_complete(struct ftmac100 * priv)655baf0fbfeSJeff Kirsher static void ftmac100_tx_complete(struct ftmac100 *priv)
656baf0fbfeSJeff Kirsher {
657baf0fbfeSJeff Kirsher 	while (ftmac100_tx_complete_packet(priv))
658baf0fbfeSJeff Kirsher 		;
659baf0fbfeSJeff Kirsher }
660baf0fbfeSJeff Kirsher 
ftmac100_xmit(struct ftmac100 * priv,struct sk_buff * skb,dma_addr_t map)6610a715156SYueHaibing static netdev_tx_t ftmac100_xmit(struct ftmac100 *priv, struct sk_buff *skb,
662baf0fbfeSJeff Kirsher 				 dma_addr_t map)
663baf0fbfeSJeff Kirsher {
664baf0fbfeSJeff Kirsher 	struct net_device *netdev = priv->netdev;
665baf0fbfeSJeff Kirsher 	struct ftmac100_txdes *txdes;
666baf0fbfeSJeff Kirsher 	unsigned int len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
667baf0fbfeSJeff Kirsher 
668baf0fbfeSJeff Kirsher 	txdes = ftmac100_current_txdes(priv);
669baf0fbfeSJeff Kirsher 	ftmac100_tx_pointer_advance(priv);
670baf0fbfeSJeff Kirsher 
671baf0fbfeSJeff Kirsher 	/* setup TX descriptor */
672baf0fbfeSJeff Kirsher 	ftmac100_txdes_set_skb(txdes, skb);
673baf0fbfeSJeff Kirsher 	ftmac100_txdes_set_dma_addr(txdes, map);
674baf0fbfeSJeff Kirsher 
675baf0fbfeSJeff Kirsher 	ftmac100_txdes_set_first_segment(txdes);
676baf0fbfeSJeff Kirsher 	ftmac100_txdes_set_last_segment(txdes);
677baf0fbfeSJeff Kirsher 	ftmac100_txdes_set_txint(txdes);
678baf0fbfeSJeff Kirsher 	ftmac100_txdes_set_buffer_size(txdes, len);
679baf0fbfeSJeff Kirsher 
680baf0fbfeSJeff Kirsher 	spin_lock(&priv->tx_lock);
681baf0fbfeSJeff Kirsher 	priv->tx_pending++;
682baf0fbfeSJeff Kirsher 	if (priv->tx_pending == TX_QUEUE_ENTRIES)
683baf0fbfeSJeff Kirsher 		netif_stop_queue(netdev);
684baf0fbfeSJeff Kirsher 
685baf0fbfeSJeff Kirsher 	/* start transmit */
686baf0fbfeSJeff Kirsher 	ftmac100_txdes_set_dma_own(txdes);
687baf0fbfeSJeff Kirsher 	spin_unlock(&priv->tx_lock);
688baf0fbfeSJeff Kirsher 
689baf0fbfeSJeff Kirsher 	ftmac100_txdma_start_polling(priv);
690baf0fbfeSJeff Kirsher 	return NETDEV_TX_OK;
691baf0fbfeSJeff Kirsher }
692baf0fbfeSJeff Kirsher 
693baf0fbfeSJeff Kirsher /******************************************************************************
694baf0fbfeSJeff Kirsher  * internal functions (buffer)
695baf0fbfeSJeff Kirsher  *****************************************************************************/
ftmac100_alloc_rx_page(struct ftmac100 * priv,struct ftmac100_rxdes * rxdes,gfp_t gfp)696baf0fbfeSJeff Kirsher static int ftmac100_alloc_rx_page(struct ftmac100 *priv,
697baf0fbfeSJeff Kirsher 				  struct ftmac100_rxdes *rxdes, gfp_t gfp)
698baf0fbfeSJeff Kirsher {
699baf0fbfeSJeff Kirsher 	struct net_device *netdev = priv->netdev;
700baf0fbfeSJeff Kirsher 	struct page *page;
701baf0fbfeSJeff Kirsher 	dma_addr_t map;
702baf0fbfeSJeff Kirsher 
703baf0fbfeSJeff Kirsher 	page = alloc_page(gfp);
704baf0fbfeSJeff Kirsher 	if (!page) {
705baf0fbfeSJeff Kirsher 		if (net_ratelimit())
706baf0fbfeSJeff Kirsher 			netdev_err(netdev, "failed to allocate rx page\n");
707baf0fbfeSJeff Kirsher 		return -ENOMEM;
708baf0fbfeSJeff Kirsher 	}
709baf0fbfeSJeff Kirsher 
710baf0fbfeSJeff Kirsher 	map = dma_map_page(priv->dev, page, 0, RX_BUF_SIZE, DMA_FROM_DEVICE);
711baf0fbfeSJeff Kirsher 	if (unlikely(dma_mapping_error(priv->dev, map))) {
712baf0fbfeSJeff Kirsher 		if (net_ratelimit())
713baf0fbfeSJeff Kirsher 			netdev_err(netdev, "failed to map rx page\n");
714baf0fbfeSJeff Kirsher 		__free_page(page);
715baf0fbfeSJeff Kirsher 		return -ENOMEM;
716baf0fbfeSJeff Kirsher 	}
717baf0fbfeSJeff Kirsher 
718baf0fbfeSJeff Kirsher 	ftmac100_rxdes_set_page(rxdes, page);
719baf0fbfeSJeff Kirsher 	ftmac100_rxdes_set_dma_addr(rxdes, map);
720baf0fbfeSJeff Kirsher 	ftmac100_rxdes_set_buffer_size(rxdes, RX_BUF_SIZE);
721baf0fbfeSJeff Kirsher 	ftmac100_rxdes_set_dma_own(rxdes);
722baf0fbfeSJeff Kirsher 	return 0;
723baf0fbfeSJeff Kirsher }
724baf0fbfeSJeff Kirsher 
ftmac100_free_buffers(struct ftmac100 * priv)725baf0fbfeSJeff Kirsher static void ftmac100_free_buffers(struct ftmac100 *priv)
726baf0fbfeSJeff Kirsher {
727baf0fbfeSJeff Kirsher 	int i;
728baf0fbfeSJeff Kirsher 
729baf0fbfeSJeff Kirsher 	for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
730baf0fbfeSJeff Kirsher 		struct ftmac100_rxdes *rxdes = &priv->descs->rxdes[i];
731baf0fbfeSJeff Kirsher 		struct page *page = ftmac100_rxdes_get_page(rxdes);
732baf0fbfeSJeff Kirsher 		dma_addr_t map = ftmac100_rxdes_get_dma_addr(rxdes);
733baf0fbfeSJeff Kirsher 
734baf0fbfeSJeff Kirsher 		if (!page)
735baf0fbfeSJeff Kirsher 			continue;
736baf0fbfeSJeff Kirsher 
737baf0fbfeSJeff Kirsher 		dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
738baf0fbfeSJeff Kirsher 		__free_page(page);
739baf0fbfeSJeff Kirsher 	}
740baf0fbfeSJeff Kirsher 
741baf0fbfeSJeff Kirsher 	for (i = 0; i < TX_QUEUE_ENTRIES; i++) {
742baf0fbfeSJeff Kirsher 		struct ftmac100_txdes *txdes = &priv->descs->txdes[i];
743baf0fbfeSJeff Kirsher 		struct sk_buff *skb = ftmac100_txdes_get_skb(txdes);
744baf0fbfeSJeff Kirsher 		dma_addr_t map = ftmac100_txdes_get_dma_addr(txdes);
745baf0fbfeSJeff Kirsher 
746baf0fbfeSJeff Kirsher 		if (!skb)
747baf0fbfeSJeff Kirsher 			continue;
748baf0fbfeSJeff Kirsher 
749baf0fbfeSJeff Kirsher 		dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
750baf0fbfeSJeff Kirsher 		dev_kfree_skb(skb);
751baf0fbfeSJeff Kirsher 	}
752baf0fbfeSJeff Kirsher 
753baf0fbfeSJeff Kirsher 	dma_free_coherent(priv->dev, sizeof(struct ftmac100_descs),
754baf0fbfeSJeff Kirsher 			  priv->descs, priv->descs_dma_addr);
755baf0fbfeSJeff Kirsher }
756baf0fbfeSJeff Kirsher 
ftmac100_alloc_buffers(struct ftmac100 * priv)757baf0fbfeSJeff Kirsher static int ftmac100_alloc_buffers(struct ftmac100 *priv)
758baf0fbfeSJeff Kirsher {
759baf0fbfeSJeff Kirsher 	int i;
760baf0fbfeSJeff Kirsher 
761750afb08SLuis Chamberlain 	priv->descs = dma_alloc_coherent(priv->dev,
7621f9061d2SJoe Perches 					 sizeof(struct ftmac100_descs),
763750afb08SLuis Chamberlain 					 &priv->descs_dma_addr, GFP_KERNEL);
764baf0fbfeSJeff Kirsher 	if (!priv->descs)
765baf0fbfeSJeff Kirsher 		return -ENOMEM;
766baf0fbfeSJeff Kirsher 
767baf0fbfeSJeff Kirsher 	/* initialize RX ring */
768baf0fbfeSJeff Kirsher 	ftmac100_rxdes_set_end_of_ring(&priv->descs->rxdes[RX_QUEUE_ENTRIES - 1]);
769baf0fbfeSJeff Kirsher 
770baf0fbfeSJeff Kirsher 	for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
771baf0fbfeSJeff Kirsher 		struct ftmac100_rxdes *rxdes = &priv->descs->rxdes[i];
772baf0fbfeSJeff Kirsher 
773baf0fbfeSJeff Kirsher 		if (ftmac100_alloc_rx_page(priv, rxdes, GFP_KERNEL))
774baf0fbfeSJeff Kirsher 			goto err;
775baf0fbfeSJeff Kirsher 	}
776baf0fbfeSJeff Kirsher 
777baf0fbfeSJeff Kirsher 	/* initialize TX ring */
778baf0fbfeSJeff Kirsher 	ftmac100_txdes_set_end_of_ring(&priv->descs->txdes[TX_QUEUE_ENTRIES - 1]);
779baf0fbfeSJeff Kirsher 	return 0;
780baf0fbfeSJeff Kirsher 
781baf0fbfeSJeff Kirsher err:
782baf0fbfeSJeff Kirsher 	ftmac100_free_buffers(priv);
783baf0fbfeSJeff Kirsher 	return -ENOMEM;
784baf0fbfeSJeff Kirsher }
785baf0fbfeSJeff Kirsher 
786baf0fbfeSJeff Kirsher /******************************************************************************
787baf0fbfeSJeff Kirsher  * struct mii_if_info functions
788baf0fbfeSJeff Kirsher  *****************************************************************************/
ftmac100_mdio_read(struct net_device * netdev,int phy_id,int reg)789baf0fbfeSJeff Kirsher static int ftmac100_mdio_read(struct net_device *netdev, int phy_id, int reg)
790baf0fbfeSJeff Kirsher {
791baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
792baf0fbfeSJeff Kirsher 	unsigned int phycr;
793baf0fbfeSJeff Kirsher 	int i;
794baf0fbfeSJeff Kirsher 
795baf0fbfeSJeff Kirsher 	phycr = FTMAC100_PHYCR_PHYAD(phy_id) |
796baf0fbfeSJeff Kirsher 		FTMAC100_PHYCR_REGAD(reg) |
797baf0fbfeSJeff Kirsher 		FTMAC100_PHYCR_MIIRD;
798baf0fbfeSJeff Kirsher 
799baf0fbfeSJeff Kirsher 	iowrite32(phycr, priv->base + FTMAC100_OFFSET_PHYCR);
800baf0fbfeSJeff Kirsher 
801baf0fbfeSJeff Kirsher 	for (i = 0; i < 10; i++) {
802baf0fbfeSJeff Kirsher 		phycr = ioread32(priv->base + FTMAC100_OFFSET_PHYCR);
803baf0fbfeSJeff Kirsher 
804baf0fbfeSJeff Kirsher 		if ((phycr & FTMAC100_PHYCR_MIIRD) == 0)
805baf0fbfeSJeff Kirsher 			return phycr & FTMAC100_PHYCR_MIIRDATA;
806baf0fbfeSJeff Kirsher 
807baf0fbfeSJeff Kirsher 		udelay(100);
808baf0fbfeSJeff Kirsher 	}
809baf0fbfeSJeff Kirsher 
810baf0fbfeSJeff Kirsher 	netdev_err(netdev, "mdio read timed out\n");
811baf0fbfeSJeff Kirsher 	return 0;
812baf0fbfeSJeff Kirsher }
813baf0fbfeSJeff Kirsher 
ftmac100_mdio_write(struct net_device * netdev,int phy_id,int reg,int data)814baf0fbfeSJeff Kirsher static void ftmac100_mdio_write(struct net_device *netdev, int phy_id, int reg,
815baf0fbfeSJeff Kirsher 				int data)
816baf0fbfeSJeff Kirsher {
817baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
818baf0fbfeSJeff Kirsher 	unsigned int phycr;
819baf0fbfeSJeff Kirsher 	int i;
820baf0fbfeSJeff Kirsher 
821baf0fbfeSJeff Kirsher 	phycr = FTMAC100_PHYCR_PHYAD(phy_id) |
822baf0fbfeSJeff Kirsher 		FTMAC100_PHYCR_REGAD(reg) |
823baf0fbfeSJeff Kirsher 		FTMAC100_PHYCR_MIIWR;
824baf0fbfeSJeff Kirsher 
825baf0fbfeSJeff Kirsher 	data = FTMAC100_PHYWDATA_MIIWDATA(data);
826baf0fbfeSJeff Kirsher 
827baf0fbfeSJeff Kirsher 	iowrite32(data, priv->base + FTMAC100_OFFSET_PHYWDATA);
828baf0fbfeSJeff Kirsher 	iowrite32(phycr, priv->base + FTMAC100_OFFSET_PHYCR);
829baf0fbfeSJeff Kirsher 
830baf0fbfeSJeff Kirsher 	for (i = 0; i < 10; i++) {
831baf0fbfeSJeff Kirsher 		phycr = ioread32(priv->base + FTMAC100_OFFSET_PHYCR);
832baf0fbfeSJeff Kirsher 
833baf0fbfeSJeff Kirsher 		if ((phycr & FTMAC100_PHYCR_MIIWR) == 0)
834baf0fbfeSJeff Kirsher 			return;
835baf0fbfeSJeff Kirsher 
836baf0fbfeSJeff Kirsher 		udelay(100);
837baf0fbfeSJeff Kirsher 	}
838baf0fbfeSJeff Kirsher 
839baf0fbfeSJeff Kirsher 	netdev_err(netdev, "mdio write timed out\n");
840baf0fbfeSJeff Kirsher }
841baf0fbfeSJeff Kirsher 
842baf0fbfeSJeff Kirsher /******************************************************************************
843baf0fbfeSJeff Kirsher  * struct ethtool_ops functions
844baf0fbfeSJeff Kirsher  *****************************************************************************/
ftmac100_get_drvinfo(struct net_device * netdev,struct ethtool_drvinfo * info)845baf0fbfeSJeff Kirsher static void ftmac100_get_drvinfo(struct net_device *netdev,
846baf0fbfeSJeff Kirsher 				 struct ethtool_drvinfo *info)
847baf0fbfeSJeff Kirsher {
848f029c781SWolfram Sang 	strscpy(info->driver, DRV_NAME, sizeof(info->driver));
849f029c781SWolfram Sang 	strscpy(info->bus_info, dev_name(&netdev->dev), sizeof(info->bus_info));
850baf0fbfeSJeff Kirsher }
851baf0fbfeSJeff Kirsher 
ftmac100_get_link_ksettings(struct net_device * netdev,struct ethtool_link_ksettings * cmd)8529da12b64SPhilippe Reynes static int ftmac100_get_link_ksettings(struct net_device *netdev,
8539da12b64SPhilippe Reynes 				       struct ethtool_link_ksettings *cmd)
854baf0fbfeSJeff Kirsher {
855baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
85682c01a84Syuval.shaia@oracle.com 
85782c01a84Syuval.shaia@oracle.com 	mii_ethtool_get_link_ksettings(&priv->mii, cmd);
85882c01a84Syuval.shaia@oracle.com 
85982c01a84Syuval.shaia@oracle.com 	return 0;
860baf0fbfeSJeff Kirsher }
861baf0fbfeSJeff Kirsher 
ftmac100_set_link_ksettings(struct net_device * netdev,const struct ethtool_link_ksettings * cmd)8629da12b64SPhilippe Reynes static int ftmac100_set_link_ksettings(struct net_device *netdev,
8639da12b64SPhilippe Reynes 				       const struct ethtool_link_ksettings *cmd)
864baf0fbfeSJeff Kirsher {
865baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
8669da12b64SPhilippe Reynes 	return mii_ethtool_set_link_ksettings(&priv->mii, cmd);
867baf0fbfeSJeff Kirsher }
868baf0fbfeSJeff Kirsher 
ftmac100_nway_reset(struct net_device * netdev)869baf0fbfeSJeff Kirsher static int ftmac100_nway_reset(struct net_device *netdev)
870baf0fbfeSJeff Kirsher {
871baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
872baf0fbfeSJeff Kirsher 	return mii_nway_restart(&priv->mii);
873baf0fbfeSJeff Kirsher }
874baf0fbfeSJeff Kirsher 
ftmac100_get_link(struct net_device * netdev)875baf0fbfeSJeff Kirsher static u32 ftmac100_get_link(struct net_device *netdev)
876baf0fbfeSJeff Kirsher {
877baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
878baf0fbfeSJeff Kirsher 	return mii_link_ok(&priv->mii);
879baf0fbfeSJeff Kirsher }
880baf0fbfeSJeff Kirsher 
881baf0fbfeSJeff Kirsher static const struct ethtool_ops ftmac100_ethtool_ops = {
882baf0fbfeSJeff Kirsher 	.get_drvinfo		= ftmac100_get_drvinfo,
883baf0fbfeSJeff Kirsher 	.nway_reset		= ftmac100_nway_reset,
884baf0fbfeSJeff Kirsher 	.get_link		= ftmac100_get_link,
8859da12b64SPhilippe Reynes 	.get_link_ksettings	= ftmac100_get_link_ksettings,
8869da12b64SPhilippe Reynes 	.set_link_ksettings	= ftmac100_set_link_ksettings,
887baf0fbfeSJeff Kirsher };
888baf0fbfeSJeff Kirsher 
889baf0fbfeSJeff Kirsher /******************************************************************************
890baf0fbfeSJeff Kirsher  * interrupt handler
891baf0fbfeSJeff Kirsher  *****************************************************************************/
ftmac100_interrupt(int irq,void * dev_id)892baf0fbfeSJeff Kirsher static irqreturn_t ftmac100_interrupt(int irq, void *dev_id)
893baf0fbfeSJeff Kirsher {
894baf0fbfeSJeff Kirsher 	struct net_device *netdev = dev_id;
895baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
896baf0fbfeSJeff Kirsher 
897baf0fbfeSJeff Kirsher 	/* Disable interrupts for polling */
898baf0fbfeSJeff Kirsher 	ftmac100_disable_all_int(priv);
899426a593eSVincent Chen 	if (likely(netif_running(netdev)))
900baf0fbfeSJeff Kirsher 		napi_schedule(&priv->napi);
901baf0fbfeSJeff Kirsher 
902baf0fbfeSJeff Kirsher 	return IRQ_HANDLED;
903baf0fbfeSJeff Kirsher }
904baf0fbfeSJeff Kirsher 
905baf0fbfeSJeff Kirsher /******************************************************************************
906baf0fbfeSJeff Kirsher  * struct napi_struct functions
907baf0fbfeSJeff Kirsher  *****************************************************************************/
ftmac100_poll(struct napi_struct * napi,int budget)908baf0fbfeSJeff Kirsher static int ftmac100_poll(struct napi_struct *napi, int budget)
909baf0fbfeSJeff Kirsher {
910baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = container_of(napi, struct ftmac100, napi);
911baf0fbfeSJeff Kirsher 	struct net_device *netdev = priv->netdev;
912baf0fbfeSJeff Kirsher 	unsigned int status;
913baf0fbfeSJeff Kirsher 	bool completed = true;
914baf0fbfeSJeff Kirsher 	int rx = 0;
915baf0fbfeSJeff Kirsher 
916baf0fbfeSJeff Kirsher 	status = ioread32(priv->base + FTMAC100_OFFSET_ISR);
917baf0fbfeSJeff Kirsher 
918baf0fbfeSJeff Kirsher 	if (status & (FTMAC100_INT_RPKT_FINISH | FTMAC100_INT_NORXBUF)) {
919baf0fbfeSJeff Kirsher 		/*
920baf0fbfeSJeff Kirsher 		 * FTMAC100_INT_RPKT_FINISH:
921baf0fbfeSJeff Kirsher 		 *	RX DMA has received packets into RX buffer successfully
922baf0fbfeSJeff Kirsher 		 *
923baf0fbfeSJeff Kirsher 		 * FTMAC100_INT_NORXBUF:
924baf0fbfeSJeff Kirsher 		 *	RX buffer unavailable
925baf0fbfeSJeff Kirsher 		 */
926baf0fbfeSJeff Kirsher 		bool retry;
927baf0fbfeSJeff Kirsher 
928baf0fbfeSJeff Kirsher 		do {
929baf0fbfeSJeff Kirsher 			retry = ftmac100_rx_packet(priv, &rx);
930baf0fbfeSJeff Kirsher 		} while (retry && rx < budget);
931baf0fbfeSJeff Kirsher 
932baf0fbfeSJeff Kirsher 		if (retry && rx == budget)
933baf0fbfeSJeff Kirsher 			completed = false;
934baf0fbfeSJeff Kirsher 	}
935baf0fbfeSJeff Kirsher 
936baf0fbfeSJeff Kirsher 	if (status & (FTMAC100_INT_XPKT_OK | FTMAC100_INT_XPKT_LOST)) {
937baf0fbfeSJeff Kirsher 		/*
938baf0fbfeSJeff Kirsher 		 * FTMAC100_INT_XPKT_OK:
939baf0fbfeSJeff Kirsher 		 *	packet transmitted to ethernet successfully
940baf0fbfeSJeff Kirsher 		 *
941baf0fbfeSJeff Kirsher 		 * FTMAC100_INT_XPKT_LOST:
942baf0fbfeSJeff Kirsher 		 *	packet transmitted to ethernet lost due to late
943baf0fbfeSJeff Kirsher 		 *	collision or excessive collision
944baf0fbfeSJeff Kirsher 		 */
945baf0fbfeSJeff Kirsher 		ftmac100_tx_complete(priv);
946baf0fbfeSJeff Kirsher 	}
947baf0fbfeSJeff Kirsher 
948baf0fbfeSJeff Kirsher 	if (status & (FTMAC100_INT_NORXBUF | FTMAC100_INT_RPKT_LOST |
949baf0fbfeSJeff Kirsher 		      FTMAC100_INT_AHB_ERR | FTMAC100_INT_PHYSTS_CHG)) {
950baf0fbfeSJeff Kirsher 		if (net_ratelimit())
951baf0fbfeSJeff Kirsher 			netdev_info(netdev, "[ISR] = 0x%x: %s%s%s%s\n", status,
952baf0fbfeSJeff Kirsher 				    status & FTMAC100_INT_NORXBUF ? "NORXBUF " : "",
953baf0fbfeSJeff Kirsher 				    status & FTMAC100_INT_RPKT_LOST ? "RPKT_LOST " : "",
954baf0fbfeSJeff Kirsher 				    status & FTMAC100_INT_AHB_ERR ? "AHB_ERR " : "",
955baf0fbfeSJeff Kirsher 				    status & FTMAC100_INT_PHYSTS_CHG ? "PHYSTS_CHG" : "");
956baf0fbfeSJeff Kirsher 
957baf0fbfeSJeff Kirsher 		if (status & FTMAC100_INT_NORXBUF) {
958baf0fbfeSJeff Kirsher 			/* RX buffer unavailable */
959baf0fbfeSJeff Kirsher 			netdev->stats.rx_over_errors++;
960baf0fbfeSJeff Kirsher 		}
961baf0fbfeSJeff Kirsher 
962baf0fbfeSJeff Kirsher 		if (status & FTMAC100_INT_RPKT_LOST) {
963baf0fbfeSJeff Kirsher 			/* received packet lost due to RX FIFO full */
964baf0fbfeSJeff Kirsher 			netdev->stats.rx_fifo_errors++;
965baf0fbfeSJeff Kirsher 		}
966baf0fbfeSJeff Kirsher 
967baf0fbfeSJeff Kirsher 		if (status & FTMAC100_INT_PHYSTS_CHG) {
968baf0fbfeSJeff Kirsher 			/* PHY link status change */
969baf0fbfeSJeff Kirsher 			mii_check_link(&priv->mii);
970baf0fbfeSJeff Kirsher 		}
971baf0fbfeSJeff Kirsher 	}
972baf0fbfeSJeff Kirsher 
973baf0fbfeSJeff Kirsher 	if (completed) {
974baf0fbfeSJeff Kirsher 		/* stop polling */
975baf0fbfeSJeff Kirsher 		napi_complete(napi);
976baf0fbfeSJeff Kirsher 		ftmac100_enable_all_int(priv);
977baf0fbfeSJeff Kirsher 	}
978baf0fbfeSJeff Kirsher 
979baf0fbfeSJeff Kirsher 	return rx;
980baf0fbfeSJeff Kirsher }
981baf0fbfeSJeff Kirsher 
982baf0fbfeSJeff Kirsher /******************************************************************************
983baf0fbfeSJeff Kirsher  * struct net_device_ops functions
984baf0fbfeSJeff Kirsher  *****************************************************************************/
ftmac100_open(struct net_device * netdev)985baf0fbfeSJeff Kirsher static int ftmac100_open(struct net_device *netdev)
986baf0fbfeSJeff Kirsher {
987baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
988baf0fbfeSJeff Kirsher 	int err;
989baf0fbfeSJeff Kirsher 
990baf0fbfeSJeff Kirsher 	err = ftmac100_alloc_buffers(priv);
991baf0fbfeSJeff Kirsher 	if (err) {
992baf0fbfeSJeff Kirsher 		netdev_err(netdev, "failed to allocate buffers\n");
993baf0fbfeSJeff Kirsher 		goto err_alloc;
994baf0fbfeSJeff Kirsher 	}
995baf0fbfeSJeff Kirsher 
996baf0fbfeSJeff Kirsher 	err = request_irq(priv->irq, ftmac100_interrupt, 0, netdev->name, netdev);
997baf0fbfeSJeff Kirsher 	if (err) {
998baf0fbfeSJeff Kirsher 		netdev_err(netdev, "failed to request irq %d\n", priv->irq);
999baf0fbfeSJeff Kirsher 		goto err_irq;
1000baf0fbfeSJeff Kirsher 	}
1001baf0fbfeSJeff Kirsher 
1002baf0fbfeSJeff Kirsher 	priv->rx_pointer = 0;
1003baf0fbfeSJeff Kirsher 	priv->tx_clean_pointer = 0;
1004baf0fbfeSJeff Kirsher 	priv->tx_pointer = 0;
1005baf0fbfeSJeff Kirsher 	priv->tx_pending = 0;
1006baf0fbfeSJeff Kirsher 
1007baf0fbfeSJeff Kirsher 	err = ftmac100_start_hw(priv);
1008baf0fbfeSJeff Kirsher 	if (err)
1009baf0fbfeSJeff Kirsher 		goto err_hw;
1010baf0fbfeSJeff Kirsher 
1011baf0fbfeSJeff Kirsher 	napi_enable(&priv->napi);
1012baf0fbfeSJeff Kirsher 	netif_start_queue(netdev);
1013baf0fbfeSJeff Kirsher 
1014baf0fbfeSJeff Kirsher 	ftmac100_enable_all_int(priv);
1015baf0fbfeSJeff Kirsher 
1016baf0fbfeSJeff Kirsher 	return 0;
1017baf0fbfeSJeff Kirsher 
1018baf0fbfeSJeff Kirsher err_hw:
1019baf0fbfeSJeff Kirsher 	free_irq(priv->irq, netdev);
1020baf0fbfeSJeff Kirsher err_irq:
1021baf0fbfeSJeff Kirsher 	ftmac100_free_buffers(priv);
1022baf0fbfeSJeff Kirsher err_alloc:
1023baf0fbfeSJeff Kirsher 	return err;
1024baf0fbfeSJeff Kirsher }
1025baf0fbfeSJeff Kirsher 
ftmac100_stop(struct net_device * netdev)1026baf0fbfeSJeff Kirsher static int ftmac100_stop(struct net_device *netdev)
1027baf0fbfeSJeff Kirsher {
1028baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
1029baf0fbfeSJeff Kirsher 
1030baf0fbfeSJeff Kirsher 	ftmac100_disable_all_int(priv);
1031baf0fbfeSJeff Kirsher 	netif_stop_queue(netdev);
1032baf0fbfeSJeff Kirsher 	napi_disable(&priv->napi);
1033baf0fbfeSJeff Kirsher 	ftmac100_stop_hw(priv);
1034baf0fbfeSJeff Kirsher 	free_irq(priv->irq, netdev);
1035baf0fbfeSJeff Kirsher 	ftmac100_free_buffers(priv);
1036baf0fbfeSJeff Kirsher 
1037baf0fbfeSJeff Kirsher 	return 0;
1038baf0fbfeSJeff Kirsher }
1039baf0fbfeSJeff Kirsher 
10400a715156SYueHaibing static netdev_tx_t
ftmac100_hard_start_xmit(struct sk_buff * skb,struct net_device * netdev)10410a715156SYueHaibing ftmac100_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
1042baf0fbfeSJeff Kirsher {
1043baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
1044baf0fbfeSJeff Kirsher 	dma_addr_t map;
1045baf0fbfeSJeff Kirsher 
1046baf0fbfeSJeff Kirsher 	if (unlikely(skb->len > MAX_PKT_SIZE)) {
1047baf0fbfeSJeff Kirsher 		if (net_ratelimit())
1048baf0fbfeSJeff Kirsher 			netdev_dbg(netdev, "tx packet too big\n");
1049baf0fbfeSJeff Kirsher 
1050baf0fbfeSJeff Kirsher 		netdev->stats.tx_dropped++;
1051baf0fbfeSJeff Kirsher 		dev_kfree_skb(skb);
1052baf0fbfeSJeff Kirsher 		return NETDEV_TX_OK;
1053baf0fbfeSJeff Kirsher 	}
1054baf0fbfeSJeff Kirsher 
1055baf0fbfeSJeff Kirsher 	map = dma_map_single(priv->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
1056baf0fbfeSJeff Kirsher 	if (unlikely(dma_mapping_error(priv->dev, map))) {
1057baf0fbfeSJeff Kirsher 		/* drop packet */
1058baf0fbfeSJeff Kirsher 		if (net_ratelimit())
1059baf0fbfeSJeff Kirsher 			netdev_err(netdev, "map socket buffer failed\n");
1060baf0fbfeSJeff Kirsher 
1061baf0fbfeSJeff Kirsher 		netdev->stats.tx_dropped++;
1062baf0fbfeSJeff Kirsher 		dev_kfree_skb(skb);
1063baf0fbfeSJeff Kirsher 		return NETDEV_TX_OK;
1064baf0fbfeSJeff Kirsher 	}
1065baf0fbfeSJeff Kirsher 
1066baf0fbfeSJeff Kirsher 	return ftmac100_xmit(priv, skb, map);
1067baf0fbfeSJeff Kirsher }
1068baf0fbfeSJeff Kirsher 
1069baf0fbfeSJeff Kirsher /* optional */
ftmac100_do_ioctl(struct net_device * netdev,struct ifreq * ifr,int cmd)1070baf0fbfeSJeff Kirsher static int ftmac100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
1071baf0fbfeSJeff Kirsher {
1072baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
1073baf0fbfeSJeff Kirsher 	struct mii_ioctl_data *data = if_mii(ifr);
1074baf0fbfeSJeff Kirsher 
1075baf0fbfeSJeff Kirsher 	return generic_mii_ioctl(&priv->mii, data, cmd, NULL);
1076baf0fbfeSJeff Kirsher }
1077baf0fbfeSJeff Kirsher 
ftmac100_change_mtu(struct net_device * netdev,int mtu)107837c84890SSergei Antonov static int ftmac100_change_mtu(struct net_device *netdev, int mtu)
107937c84890SSergei Antonov {
108037c84890SSergei Antonov 	struct ftmac100 *priv = netdev_priv(netdev);
108137c84890SSergei Antonov 	unsigned int maccr;
108237c84890SSergei Antonov 
108337c84890SSergei Antonov 	maccr = ioread32(priv->base + FTMAC100_OFFSET_MACCR);
108437c84890SSergei Antonov 	if (mtu > ETH_DATA_LEN) {
108537c84890SSergei Antonov 		/* process long packets in the driver */
108637c84890SSergei Antonov 		maccr |= FTMAC100_MACCR_RX_FTL;
108737c84890SSergei Antonov 	} else {
108837c84890SSergei Antonov 		/* Let the controller drop incoming packets greater
108937c84890SSergei Antonov 		 * than 1518 (that is 1500 + 14 Ethernet + 4 FCS).
109037c84890SSergei Antonov 		 */
109137c84890SSergei Antonov 		maccr &= ~FTMAC100_MACCR_RX_FTL;
109237c84890SSergei Antonov 	}
109337c84890SSergei Antonov 	iowrite32(maccr, priv->base + FTMAC100_OFFSET_MACCR);
109437c84890SSergei Antonov 
109537c84890SSergei Antonov 	netdev->mtu = mtu;
109637c84890SSergei Antonov 
109737c84890SSergei Antonov 	return 0;
109837c84890SSergei Antonov }
109937c84890SSergei Antonov 
ftmac100_set_rx_mode(struct net_device * netdev)1100*7a1c3821SSergei Antonov static void ftmac100_set_rx_mode(struct net_device *netdev)
1101*7a1c3821SSergei Antonov {
1102*7a1c3821SSergei Antonov 	struct ftmac100 *priv = netdev_priv(netdev);
1103*7a1c3821SSergei Antonov 	unsigned int maccr = ioread32(priv->base + FTMAC100_OFFSET_MACCR);
1104*7a1c3821SSergei Antonov 
1105*7a1c3821SSergei Antonov 	ftmac100_set_rx_bits(priv, &maccr);
1106*7a1c3821SSergei Antonov 	iowrite32(maccr, priv->base + FTMAC100_OFFSET_MACCR);
1107*7a1c3821SSergei Antonov }
1108*7a1c3821SSergei Antonov 
1109baf0fbfeSJeff Kirsher static const struct net_device_ops ftmac100_netdev_ops = {
1110baf0fbfeSJeff Kirsher 	.ndo_open		= ftmac100_open,
1111baf0fbfeSJeff Kirsher 	.ndo_stop		= ftmac100_stop,
1112baf0fbfeSJeff Kirsher 	.ndo_start_xmit		= ftmac100_hard_start_xmit,
1113baf0fbfeSJeff Kirsher 	.ndo_set_mac_address	= eth_mac_addr,
1114baf0fbfeSJeff Kirsher 	.ndo_validate_addr	= eth_validate_addr,
1115a7605370SArnd Bergmann 	.ndo_eth_ioctl		= ftmac100_do_ioctl,
111637c84890SSergei Antonov 	.ndo_change_mtu		= ftmac100_change_mtu,
1117*7a1c3821SSergei Antonov 	.ndo_set_rx_mode	= ftmac100_set_rx_mode,
1118baf0fbfeSJeff Kirsher };
1119baf0fbfeSJeff Kirsher 
1120baf0fbfeSJeff Kirsher /******************************************************************************
1121baf0fbfeSJeff Kirsher  * struct platform_driver functions
1122baf0fbfeSJeff Kirsher  *****************************************************************************/
ftmac100_probe(struct platform_device * pdev)1123baf0fbfeSJeff Kirsher static int ftmac100_probe(struct platform_device *pdev)
1124baf0fbfeSJeff Kirsher {
1125baf0fbfeSJeff Kirsher 	struct resource *res;
1126baf0fbfeSJeff Kirsher 	int irq;
1127baf0fbfeSJeff Kirsher 	struct net_device *netdev;
1128baf0fbfeSJeff Kirsher 	struct ftmac100 *priv;
1129baf0fbfeSJeff Kirsher 	int err;
1130baf0fbfeSJeff Kirsher 
1131baf0fbfeSJeff Kirsher 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1132baf0fbfeSJeff Kirsher 	if (!res)
1133baf0fbfeSJeff Kirsher 		return -ENXIO;
1134baf0fbfeSJeff Kirsher 
1135baf0fbfeSJeff Kirsher 	irq = platform_get_irq(pdev, 0);
1136baf0fbfeSJeff Kirsher 	if (irq < 0)
1137baf0fbfeSJeff Kirsher 		return irq;
1138baf0fbfeSJeff Kirsher 
1139baf0fbfeSJeff Kirsher 	/* setup net_device */
1140baf0fbfeSJeff Kirsher 	netdev = alloc_etherdev(sizeof(*priv));
1141baf0fbfeSJeff Kirsher 	if (!netdev) {
1142baf0fbfeSJeff Kirsher 		err = -ENOMEM;
1143baf0fbfeSJeff Kirsher 		goto err_alloc_etherdev;
1144baf0fbfeSJeff Kirsher 	}
1145baf0fbfeSJeff Kirsher 
1146baf0fbfeSJeff Kirsher 	SET_NETDEV_DEV(netdev, &pdev->dev);
11477ad24ea4SWilfried Klaebe 	netdev->ethtool_ops = &ftmac100_ethtool_ops;
1148baf0fbfeSJeff Kirsher 	netdev->netdev_ops = &ftmac100_netdev_ops;
114930f837b7SVladimir Oltean 	netdev->max_mtu = MAX_PKT_SIZE - VLAN_ETH_HLEN;
1150baf0fbfeSJeff Kirsher 
1151f7650d82SSergei Antonov 	err = platform_get_ethdev_address(&pdev->dev, netdev);
1152f7650d82SSergei Antonov 	if (err == -EPROBE_DEFER)
1153f7650d82SSergei Antonov 		goto defer_get_mac;
1154f7650d82SSergei Antonov 
1155baf0fbfeSJeff Kirsher 	platform_set_drvdata(pdev, netdev);
1156baf0fbfeSJeff Kirsher 
1157baf0fbfeSJeff Kirsher 	/* setup private data */
1158baf0fbfeSJeff Kirsher 	priv = netdev_priv(netdev);
1159baf0fbfeSJeff Kirsher 	priv->netdev = netdev;
1160baf0fbfeSJeff Kirsher 	priv->dev = &pdev->dev;
1161baf0fbfeSJeff Kirsher 
1162baf0fbfeSJeff Kirsher 	spin_lock_init(&priv->tx_lock);
1163baf0fbfeSJeff Kirsher 
1164baf0fbfeSJeff Kirsher 	/* initialize NAPI */
1165b48b89f9SJakub Kicinski 	netif_napi_add(netdev, &priv->napi, ftmac100_poll);
1166baf0fbfeSJeff Kirsher 
1167baf0fbfeSJeff Kirsher 	/* map io memory */
1168baf0fbfeSJeff Kirsher 	priv->res = request_mem_region(res->start, resource_size(res),
1169baf0fbfeSJeff Kirsher 				       dev_name(&pdev->dev));
1170baf0fbfeSJeff Kirsher 	if (!priv->res) {
1171baf0fbfeSJeff Kirsher 		dev_err(&pdev->dev, "Could not reserve memory region\n");
1172baf0fbfeSJeff Kirsher 		err = -ENOMEM;
1173baf0fbfeSJeff Kirsher 		goto err_req_mem;
1174baf0fbfeSJeff Kirsher 	}
1175baf0fbfeSJeff Kirsher 
1176baf0fbfeSJeff Kirsher 	priv->base = ioremap(res->start, resource_size(res));
1177baf0fbfeSJeff Kirsher 	if (!priv->base) {
1178baf0fbfeSJeff Kirsher 		dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
1179baf0fbfeSJeff Kirsher 		err = -EIO;
1180baf0fbfeSJeff Kirsher 		goto err_ioremap;
1181baf0fbfeSJeff Kirsher 	}
1182baf0fbfeSJeff Kirsher 
1183baf0fbfeSJeff Kirsher 	priv->irq = irq;
1184baf0fbfeSJeff Kirsher 
1185baf0fbfeSJeff Kirsher 	/* initialize struct mii_if_info */
1186baf0fbfeSJeff Kirsher 	priv->mii.phy_id	= 0;
1187baf0fbfeSJeff Kirsher 	priv->mii.phy_id_mask	= 0x1f;
1188baf0fbfeSJeff Kirsher 	priv->mii.reg_num_mask	= 0x1f;
1189baf0fbfeSJeff Kirsher 	priv->mii.dev		= netdev;
1190baf0fbfeSJeff Kirsher 	priv->mii.mdio_read	= ftmac100_mdio_read;
1191baf0fbfeSJeff Kirsher 	priv->mii.mdio_write	= ftmac100_mdio_write;
1192baf0fbfeSJeff Kirsher 
1193baf0fbfeSJeff Kirsher 	/* register network device */
1194baf0fbfeSJeff Kirsher 	err = register_netdev(netdev);
1195baf0fbfeSJeff Kirsher 	if (err) {
1196baf0fbfeSJeff Kirsher 		dev_err(&pdev->dev, "Failed to register netdev\n");
1197baf0fbfeSJeff Kirsher 		goto err_register_netdev;
1198baf0fbfeSJeff Kirsher 	}
1199baf0fbfeSJeff Kirsher 
1200baf0fbfeSJeff Kirsher 	netdev_info(netdev, "irq %d, mapped at %p\n", priv->irq, priv->base);
1201baf0fbfeSJeff Kirsher 
1202baf0fbfeSJeff Kirsher 	if (!is_valid_ether_addr(netdev->dev_addr)) {
1203f2cedb63SDanny Kukawka 		eth_hw_addr_random(netdev);
1204baf0fbfeSJeff Kirsher 		netdev_info(netdev, "generated random MAC address %pM\n",
1205baf0fbfeSJeff Kirsher 			    netdev->dev_addr);
1206baf0fbfeSJeff Kirsher 	}
1207baf0fbfeSJeff Kirsher 
1208baf0fbfeSJeff Kirsher 	return 0;
1209baf0fbfeSJeff Kirsher 
1210baf0fbfeSJeff Kirsher err_register_netdev:
1211baf0fbfeSJeff Kirsher 	iounmap(priv->base);
1212baf0fbfeSJeff Kirsher err_ioremap:
1213baf0fbfeSJeff Kirsher 	release_resource(priv->res);
1214baf0fbfeSJeff Kirsher err_req_mem:
1215baf0fbfeSJeff Kirsher 	netif_napi_del(&priv->napi);
1216f7650d82SSergei Antonov defer_get_mac:
1217baf0fbfeSJeff Kirsher 	free_netdev(netdev);
1218baf0fbfeSJeff Kirsher err_alloc_etherdev:
1219baf0fbfeSJeff Kirsher 	return err;
1220baf0fbfeSJeff Kirsher }
1221baf0fbfeSJeff Kirsher 
ftmac100_remove(struct platform_device * pdev)1222be12502eSDmitry Torokhov static int ftmac100_remove(struct platform_device *pdev)
1223baf0fbfeSJeff Kirsher {
1224baf0fbfeSJeff Kirsher 	struct net_device *netdev;
1225baf0fbfeSJeff Kirsher 	struct ftmac100 *priv;
1226baf0fbfeSJeff Kirsher 
1227baf0fbfeSJeff Kirsher 	netdev = platform_get_drvdata(pdev);
1228baf0fbfeSJeff Kirsher 	priv = netdev_priv(netdev);
1229baf0fbfeSJeff Kirsher 
1230baf0fbfeSJeff Kirsher 	unregister_netdev(netdev);
1231baf0fbfeSJeff Kirsher 
1232baf0fbfeSJeff Kirsher 	iounmap(priv->base);
1233baf0fbfeSJeff Kirsher 	release_resource(priv->res);
1234baf0fbfeSJeff Kirsher 
1235baf0fbfeSJeff Kirsher 	netif_napi_del(&priv->napi);
1236baf0fbfeSJeff Kirsher 	free_netdev(netdev);
1237baf0fbfeSJeff Kirsher 	return 0;
1238baf0fbfeSJeff Kirsher }
1239baf0fbfeSJeff Kirsher 
124047ab37a1SGreentime Hu static const struct of_device_id ftmac100_of_ids[] = {
124147ab37a1SGreentime Hu 	{ .compatible = "andestech,atmac100" },
124247ab37a1SGreentime Hu 	{ }
124347ab37a1SGreentime Hu };
124447ab37a1SGreentime Hu 
1245baf0fbfeSJeff Kirsher static struct platform_driver ftmac100_driver = {
1246baf0fbfeSJeff Kirsher 	.probe		= ftmac100_probe,
1247be12502eSDmitry Torokhov 	.remove		= ftmac100_remove,
1248baf0fbfeSJeff Kirsher 	.driver		= {
1249baf0fbfeSJeff Kirsher 		.name	= DRV_NAME,
125047ab37a1SGreentime Hu 		.of_match_table = ftmac100_of_ids
1251baf0fbfeSJeff Kirsher 	},
1252baf0fbfeSJeff Kirsher };
1253baf0fbfeSJeff Kirsher 
1254baf0fbfeSJeff Kirsher /******************************************************************************
1255baf0fbfeSJeff Kirsher  * initialization / finalization
1256baf0fbfeSJeff Kirsher  *****************************************************************************/
1257d280a2c2SZhichao Cai module_platform_driver(ftmac100_driver);
1258baf0fbfeSJeff Kirsher 
1259baf0fbfeSJeff Kirsher MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
1260baf0fbfeSJeff Kirsher MODULE_DESCRIPTION("FTMAC100 driver");
1261baf0fbfeSJeff Kirsher MODULE_LICENSE("GPL");
126247ab37a1SGreentime Hu MODULE_DEVICE_TABLE(of, ftmac100_of_ids);
1263