1baf0fbfeSJeff Kirsher /*
2baf0fbfeSJeff Kirsher  * Faraday FTMAC100 10/100 Ethernet
3baf0fbfeSJeff Kirsher  *
4baf0fbfeSJeff Kirsher  * (C) Copyright 2009-2011 Faraday Technology
5baf0fbfeSJeff Kirsher  * Po-Yu Chuang <ratbert@faraday-tech.com>
6baf0fbfeSJeff Kirsher  *
7baf0fbfeSJeff Kirsher  * This program is free software; you can redistribute it and/or modify
8baf0fbfeSJeff Kirsher  * it under the terms of the GNU General Public License as published by
9baf0fbfeSJeff Kirsher  * the Free Software Foundation; either version 2 of the License, or
10baf0fbfeSJeff Kirsher  * (at your option) any later version.
11baf0fbfeSJeff Kirsher  *
12baf0fbfeSJeff Kirsher  * This program is distributed in the hope that it will be useful,
13baf0fbfeSJeff Kirsher  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14baf0fbfeSJeff Kirsher  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15baf0fbfeSJeff Kirsher  * GNU General Public License for more details.
16baf0fbfeSJeff Kirsher  *
17baf0fbfeSJeff Kirsher  * You should have received a copy of the GNU General Public License
18baf0fbfeSJeff Kirsher  * along with this program; if not, write to the Free Software
19baf0fbfeSJeff Kirsher  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20baf0fbfeSJeff Kirsher  */
21baf0fbfeSJeff Kirsher 
22baf0fbfeSJeff Kirsher #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
23baf0fbfeSJeff Kirsher 
24baf0fbfeSJeff Kirsher #include <linux/dma-mapping.h>
25baf0fbfeSJeff Kirsher #include <linux/etherdevice.h>
26baf0fbfeSJeff Kirsher #include <linux/ethtool.h>
27baf0fbfeSJeff Kirsher #include <linux/init.h>
2817f1bbcaSThomas Faber #include <linux/interrupt.h>
29baf0fbfeSJeff Kirsher #include <linux/io.h>
30baf0fbfeSJeff Kirsher #include <linux/mii.h>
31baf0fbfeSJeff Kirsher #include <linux/module.h>
32baf0fbfeSJeff Kirsher #include <linux/netdevice.h>
33baf0fbfeSJeff Kirsher #include <linux/platform_device.h>
34baf0fbfeSJeff Kirsher 
35baf0fbfeSJeff Kirsher #include "ftmac100.h"
36baf0fbfeSJeff Kirsher 
37baf0fbfeSJeff Kirsher #define DRV_NAME	"ftmac100"
38baf0fbfeSJeff Kirsher #define DRV_VERSION	"0.2"
39baf0fbfeSJeff Kirsher 
40baf0fbfeSJeff Kirsher #define RX_QUEUE_ENTRIES	128	/* must be power of 2 */
41baf0fbfeSJeff Kirsher #define TX_QUEUE_ENTRIES	16	/* must be power of 2 */
42baf0fbfeSJeff Kirsher 
43baf0fbfeSJeff Kirsher #define MAX_PKT_SIZE		1518
44baf0fbfeSJeff Kirsher #define RX_BUF_SIZE		2044	/* must be smaller than 0x7ff */
45baf0fbfeSJeff Kirsher 
46baf0fbfeSJeff Kirsher #if MAX_PKT_SIZE > 0x7ff
47baf0fbfeSJeff Kirsher #error invalid MAX_PKT_SIZE
48baf0fbfeSJeff Kirsher #endif
49baf0fbfeSJeff Kirsher 
50baf0fbfeSJeff Kirsher #if RX_BUF_SIZE > 0x7ff || RX_BUF_SIZE > PAGE_SIZE
51baf0fbfeSJeff Kirsher #error invalid RX_BUF_SIZE
52baf0fbfeSJeff Kirsher #endif
53baf0fbfeSJeff Kirsher 
54baf0fbfeSJeff Kirsher /******************************************************************************
55baf0fbfeSJeff Kirsher  * private data
56baf0fbfeSJeff Kirsher  *****************************************************************************/
57baf0fbfeSJeff Kirsher struct ftmac100_descs {
58baf0fbfeSJeff Kirsher 	struct ftmac100_rxdes rxdes[RX_QUEUE_ENTRIES];
59baf0fbfeSJeff Kirsher 	struct ftmac100_txdes txdes[TX_QUEUE_ENTRIES];
60baf0fbfeSJeff Kirsher };
61baf0fbfeSJeff Kirsher 
62baf0fbfeSJeff Kirsher struct ftmac100 {
63baf0fbfeSJeff Kirsher 	struct resource *res;
64baf0fbfeSJeff Kirsher 	void __iomem *base;
65baf0fbfeSJeff Kirsher 	int irq;
66baf0fbfeSJeff Kirsher 
67baf0fbfeSJeff Kirsher 	struct ftmac100_descs *descs;
68baf0fbfeSJeff Kirsher 	dma_addr_t descs_dma_addr;
69baf0fbfeSJeff Kirsher 
70baf0fbfeSJeff Kirsher 	unsigned int rx_pointer;
71baf0fbfeSJeff Kirsher 	unsigned int tx_clean_pointer;
72baf0fbfeSJeff Kirsher 	unsigned int tx_pointer;
73baf0fbfeSJeff Kirsher 	unsigned int tx_pending;
74baf0fbfeSJeff Kirsher 
75baf0fbfeSJeff Kirsher 	spinlock_t tx_lock;
76baf0fbfeSJeff Kirsher 
77baf0fbfeSJeff Kirsher 	struct net_device *netdev;
78baf0fbfeSJeff Kirsher 	struct device *dev;
79baf0fbfeSJeff Kirsher 	struct napi_struct napi;
80baf0fbfeSJeff Kirsher 
81baf0fbfeSJeff Kirsher 	struct mii_if_info mii;
82baf0fbfeSJeff Kirsher };
83baf0fbfeSJeff Kirsher 
84baf0fbfeSJeff Kirsher static int ftmac100_alloc_rx_page(struct ftmac100 *priv,
85baf0fbfeSJeff Kirsher 				  struct ftmac100_rxdes *rxdes, gfp_t gfp);
86baf0fbfeSJeff Kirsher 
87baf0fbfeSJeff Kirsher /******************************************************************************
88baf0fbfeSJeff Kirsher  * internal functions (hardware register access)
89baf0fbfeSJeff Kirsher  *****************************************************************************/
90baf0fbfeSJeff Kirsher #define INT_MASK_ALL_ENABLED	(FTMAC100_INT_RPKT_FINISH	| \
91baf0fbfeSJeff Kirsher 				 FTMAC100_INT_NORXBUF		| \
92baf0fbfeSJeff Kirsher 				 FTMAC100_INT_XPKT_OK		| \
93baf0fbfeSJeff Kirsher 				 FTMAC100_INT_XPKT_LOST		| \
94baf0fbfeSJeff Kirsher 				 FTMAC100_INT_RPKT_LOST		| \
95baf0fbfeSJeff Kirsher 				 FTMAC100_INT_AHB_ERR		| \
96baf0fbfeSJeff Kirsher 				 FTMAC100_INT_PHYSTS_CHG)
97baf0fbfeSJeff Kirsher 
98baf0fbfeSJeff Kirsher #define INT_MASK_ALL_DISABLED	0
99baf0fbfeSJeff Kirsher 
100baf0fbfeSJeff Kirsher static void ftmac100_enable_all_int(struct ftmac100 *priv)
101baf0fbfeSJeff Kirsher {
102baf0fbfeSJeff Kirsher 	iowrite32(INT_MASK_ALL_ENABLED, priv->base + FTMAC100_OFFSET_IMR);
103baf0fbfeSJeff Kirsher }
104baf0fbfeSJeff Kirsher 
105baf0fbfeSJeff Kirsher static void ftmac100_disable_all_int(struct ftmac100 *priv)
106baf0fbfeSJeff Kirsher {
107baf0fbfeSJeff Kirsher 	iowrite32(INT_MASK_ALL_DISABLED, priv->base + FTMAC100_OFFSET_IMR);
108baf0fbfeSJeff Kirsher }
109baf0fbfeSJeff Kirsher 
110baf0fbfeSJeff Kirsher static void ftmac100_set_rx_ring_base(struct ftmac100 *priv, dma_addr_t addr)
111baf0fbfeSJeff Kirsher {
112baf0fbfeSJeff Kirsher 	iowrite32(addr, priv->base + FTMAC100_OFFSET_RXR_BADR);
113baf0fbfeSJeff Kirsher }
114baf0fbfeSJeff Kirsher 
115baf0fbfeSJeff Kirsher static void ftmac100_set_tx_ring_base(struct ftmac100 *priv, dma_addr_t addr)
116baf0fbfeSJeff Kirsher {
117baf0fbfeSJeff Kirsher 	iowrite32(addr, priv->base + FTMAC100_OFFSET_TXR_BADR);
118baf0fbfeSJeff Kirsher }
119baf0fbfeSJeff Kirsher 
120baf0fbfeSJeff Kirsher static void ftmac100_txdma_start_polling(struct ftmac100 *priv)
121baf0fbfeSJeff Kirsher {
122baf0fbfeSJeff Kirsher 	iowrite32(1, priv->base + FTMAC100_OFFSET_TXPD);
123baf0fbfeSJeff Kirsher }
124baf0fbfeSJeff Kirsher 
125baf0fbfeSJeff Kirsher static int ftmac100_reset(struct ftmac100 *priv)
126baf0fbfeSJeff Kirsher {
127baf0fbfeSJeff Kirsher 	struct net_device *netdev = priv->netdev;
128baf0fbfeSJeff Kirsher 	int i;
129baf0fbfeSJeff Kirsher 
130baf0fbfeSJeff Kirsher 	/* NOTE: reset clears all registers */
131baf0fbfeSJeff Kirsher 	iowrite32(FTMAC100_MACCR_SW_RST, priv->base + FTMAC100_OFFSET_MACCR);
132baf0fbfeSJeff Kirsher 
133baf0fbfeSJeff Kirsher 	for (i = 0; i < 5; i++) {
134baf0fbfeSJeff Kirsher 		unsigned int maccr;
135baf0fbfeSJeff Kirsher 
136baf0fbfeSJeff Kirsher 		maccr = ioread32(priv->base + FTMAC100_OFFSET_MACCR);
137baf0fbfeSJeff Kirsher 		if (!(maccr & FTMAC100_MACCR_SW_RST)) {
138baf0fbfeSJeff Kirsher 			/*
139baf0fbfeSJeff Kirsher 			 * FTMAC100_MACCR_SW_RST cleared does not indicate
140baf0fbfeSJeff Kirsher 			 * that hardware reset completed (what the f*ck).
141baf0fbfeSJeff Kirsher 			 * We still need to wait for a while.
142baf0fbfeSJeff Kirsher 			 */
143baf0fbfeSJeff Kirsher 			udelay(500);
144baf0fbfeSJeff Kirsher 			return 0;
145baf0fbfeSJeff Kirsher 		}
146baf0fbfeSJeff Kirsher 
147baf0fbfeSJeff Kirsher 		udelay(1000);
148baf0fbfeSJeff Kirsher 	}
149baf0fbfeSJeff Kirsher 
150baf0fbfeSJeff Kirsher 	netdev_err(netdev, "software reset failed\n");
151baf0fbfeSJeff Kirsher 	return -EIO;
152baf0fbfeSJeff Kirsher }
153baf0fbfeSJeff Kirsher 
154baf0fbfeSJeff Kirsher static void ftmac100_set_mac(struct ftmac100 *priv, const unsigned char *mac)
155baf0fbfeSJeff Kirsher {
156baf0fbfeSJeff Kirsher 	unsigned int maddr = mac[0] << 8 | mac[1];
157baf0fbfeSJeff Kirsher 	unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
158baf0fbfeSJeff Kirsher 
159baf0fbfeSJeff Kirsher 	iowrite32(maddr, priv->base + FTMAC100_OFFSET_MAC_MADR);
160baf0fbfeSJeff Kirsher 	iowrite32(laddr, priv->base + FTMAC100_OFFSET_MAC_LADR);
161baf0fbfeSJeff Kirsher }
162baf0fbfeSJeff Kirsher 
163baf0fbfeSJeff Kirsher #define MACCR_ENABLE_ALL	(FTMAC100_MACCR_XMT_EN	| \
164baf0fbfeSJeff Kirsher 				 FTMAC100_MACCR_RCV_EN	| \
165baf0fbfeSJeff Kirsher 				 FTMAC100_MACCR_XDMA_EN	| \
166baf0fbfeSJeff Kirsher 				 FTMAC100_MACCR_RDMA_EN	| \
167baf0fbfeSJeff Kirsher 				 FTMAC100_MACCR_CRC_APD	| \
168baf0fbfeSJeff Kirsher 				 FTMAC100_MACCR_FULLDUP	| \
169baf0fbfeSJeff Kirsher 				 FTMAC100_MACCR_RX_RUNT	| \
170baf0fbfeSJeff Kirsher 				 FTMAC100_MACCR_RX_BROADPKT)
171baf0fbfeSJeff Kirsher 
172baf0fbfeSJeff Kirsher static int ftmac100_start_hw(struct ftmac100 *priv)
173baf0fbfeSJeff Kirsher {
174baf0fbfeSJeff Kirsher 	struct net_device *netdev = priv->netdev;
175baf0fbfeSJeff Kirsher 
176baf0fbfeSJeff Kirsher 	if (ftmac100_reset(priv))
177baf0fbfeSJeff Kirsher 		return -EIO;
178baf0fbfeSJeff Kirsher 
179baf0fbfeSJeff Kirsher 	/* setup ring buffer base registers */
180baf0fbfeSJeff Kirsher 	ftmac100_set_rx_ring_base(priv,
181baf0fbfeSJeff Kirsher 				  priv->descs_dma_addr +
182baf0fbfeSJeff Kirsher 				  offsetof(struct ftmac100_descs, rxdes));
183baf0fbfeSJeff Kirsher 	ftmac100_set_tx_ring_base(priv,
184baf0fbfeSJeff Kirsher 				  priv->descs_dma_addr +
185baf0fbfeSJeff Kirsher 				  offsetof(struct ftmac100_descs, txdes));
186baf0fbfeSJeff Kirsher 
187baf0fbfeSJeff Kirsher 	iowrite32(FTMAC100_APTC_RXPOLL_CNT(1), priv->base + FTMAC100_OFFSET_APTC);
188baf0fbfeSJeff Kirsher 
189baf0fbfeSJeff Kirsher 	ftmac100_set_mac(priv, netdev->dev_addr);
190baf0fbfeSJeff Kirsher 
191baf0fbfeSJeff Kirsher 	iowrite32(MACCR_ENABLE_ALL, priv->base + FTMAC100_OFFSET_MACCR);
192baf0fbfeSJeff Kirsher 	return 0;
193baf0fbfeSJeff Kirsher }
194baf0fbfeSJeff Kirsher 
195baf0fbfeSJeff Kirsher static void ftmac100_stop_hw(struct ftmac100 *priv)
196baf0fbfeSJeff Kirsher {
197baf0fbfeSJeff Kirsher 	iowrite32(0, priv->base + FTMAC100_OFFSET_MACCR);
198baf0fbfeSJeff Kirsher }
199baf0fbfeSJeff Kirsher 
200baf0fbfeSJeff Kirsher /******************************************************************************
201baf0fbfeSJeff Kirsher  * internal functions (receive descriptor)
202baf0fbfeSJeff Kirsher  *****************************************************************************/
203baf0fbfeSJeff Kirsher static bool ftmac100_rxdes_first_segment(struct ftmac100_rxdes *rxdes)
204baf0fbfeSJeff Kirsher {
205baf0fbfeSJeff Kirsher 	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_FRS);
206baf0fbfeSJeff Kirsher }
207baf0fbfeSJeff Kirsher 
208baf0fbfeSJeff Kirsher static bool ftmac100_rxdes_last_segment(struct ftmac100_rxdes *rxdes)
209baf0fbfeSJeff Kirsher {
210baf0fbfeSJeff Kirsher 	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_LRS);
211baf0fbfeSJeff Kirsher }
212baf0fbfeSJeff Kirsher 
213baf0fbfeSJeff Kirsher static bool ftmac100_rxdes_owned_by_dma(struct ftmac100_rxdes *rxdes)
214baf0fbfeSJeff Kirsher {
215baf0fbfeSJeff Kirsher 	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RXDMA_OWN);
216baf0fbfeSJeff Kirsher }
217baf0fbfeSJeff Kirsher 
218baf0fbfeSJeff Kirsher static void ftmac100_rxdes_set_dma_own(struct ftmac100_rxdes *rxdes)
219baf0fbfeSJeff Kirsher {
220baf0fbfeSJeff Kirsher 	/* clear status bits */
221baf0fbfeSJeff Kirsher 	rxdes->rxdes0 = cpu_to_le32(FTMAC100_RXDES0_RXDMA_OWN);
222baf0fbfeSJeff Kirsher }
223baf0fbfeSJeff Kirsher 
224baf0fbfeSJeff Kirsher static bool ftmac100_rxdes_rx_error(struct ftmac100_rxdes *rxdes)
225baf0fbfeSJeff Kirsher {
226baf0fbfeSJeff Kirsher 	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RX_ERR);
227baf0fbfeSJeff Kirsher }
228baf0fbfeSJeff Kirsher 
229baf0fbfeSJeff Kirsher static bool ftmac100_rxdes_crc_error(struct ftmac100_rxdes *rxdes)
230baf0fbfeSJeff Kirsher {
231baf0fbfeSJeff Kirsher 	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_CRC_ERR);
232baf0fbfeSJeff Kirsher }
233baf0fbfeSJeff Kirsher 
234baf0fbfeSJeff Kirsher static bool ftmac100_rxdes_frame_too_long(struct ftmac100_rxdes *rxdes)
235baf0fbfeSJeff Kirsher {
236baf0fbfeSJeff Kirsher 	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_FTL);
237baf0fbfeSJeff Kirsher }
238baf0fbfeSJeff Kirsher 
239baf0fbfeSJeff Kirsher static bool ftmac100_rxdes_runt(struct ftmac100_rxdes *rxdes)
240baf0fbfeSJeff Kirsher {
241baf0fbfeSJeff Kirsher 	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RUNT);
242baf0fbfeSJeff Kirsher }
243baf0fbfeSJeff Kirsher 
244baf0fbfeSJeff Kirsher static bool ftmac100_rxdes_odd_nibble(struct ftmac100_rxdes *rxdes)
245baf0fbfeSJeff Kirsher {
246baf0fbfeSJeff Kirsher 	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RX_ODD_NB);
247baf0fbfeSJeff Kirsher }
248baf0fbfeSJeff Kirsher 
249baf0fbfeSJeff Kirsher static unsigned int ftmac100_rxdes_frame_length(struct ftmac100_rxdes *rxdes)
250baf0fbfeSJeff Kirsher {
251baf0fbfeSJeff Kirsher 	return le32_to_cpu(rxdes->rxdes0) & FTMAC100_RXDES0_RFL;
252baf0fbfeSJeff Kirsher }
253baf0fbfeSJeff Kirsher 
254baf0fbfeSJeff Kirsher static bool ftmac100_rxdes_multicast(struct ftmac100_rxdes *rxdes)
255baf0fbfeSJeff Kirsher {
256baf0fbfeSJeff Kirsher 	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_MULTICAST);
257baf0fbfeSJeff Kirsher }
258baf0fbfeSJeff Kirsher 
259baf0fbfeSJeff Kirsher static void ftmac100_rxdes_set_buffer_size(struct ftmac100_rxdes *rxdes,
260baf0fbfeSJeff Kirsher 					   unsigned int size)
261baf0fbfeSJeff Kirsher {
262baf0fbfeSJeff Kirsher 	rxdes->rxdes1 &= cpu_to_le32(FTMAC100_RXDES1_EDORR);
263baf0fbfeSJeff Kirsher 	rxdes->rxdes1 |= cpu_to_le32(FTMAC100_RXDES1_RXBUF_SIZE(size));
264baf0fbfeSJeff Kirsher }
265baf0fbfeSJeff Kirsher 
266baf0fbfeSJeff Kirsher static void ftmac100_rxdes_set_end_of_ring(struct ftmac100_rxdes *rxdes)
267baf0fbfeSJeff Kirsher {
268baf0fbfeSJeff Kirsher 	rxdes->rxdes1 |= cpu_to_le32(FTMAC100_RXDES1_EDORR);
269baf0fbfeSJeff Kirsher }
270baf0fbfeSJeff Kirsher 
271baf0fbfeSJeff Kirsher static void ftmac100_rxdes_set_dma_addr(struct ftmac100_rxdes *rxdes,
272baf0fbfeSJeff Kirsher 					dma_addr_t addr)
273baf0fbfeSJeff Kirsher {
274baf0fbfeSJeff Kirsher 	rxdes->rxdes2 = cpu_to_le32(addr);
275baf0fbfeSJeff Kirsher }
276baf0fbfeSJeff Kirsher 
277baf0fbfeSJeff Kirsher static dma_addr_t ftmac100_rxdes_get_dma_addr(struct ftmac100_rxdes *rxdes)
278baf0fbfeSJeff Kirsher {
279baf0fbfeSJeff Kirsher 	return le32_to_cpu(rxdes->rxdes2);
280baf0fbfeSJeff Kirsher }
281baf0fbfeSJeff Kirsher 
282baf0fbfeSJeff Kirsher /*
283baf0fbfeSJeff Kirsher  * rxdes3 is not used by hardware. We use it to keep track of page.
284baf0fbfeSJeff Kirsher  * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu().
285baf0fbfeSJeff Kirsher  */
286baf0fbfeSJeff Kirsher static void ftmac100_rxdes_set_page(struct ftmac100_rxdes *rxdes, struct page *page)
287baf0fbfeSJeff Kirsher {
288baf0fbfeSJeff Kirsher 	rxdes->rxdes3 = (unsigned int)page;
289baf0fbfeSJeff Kirsher }
290baf0fbfeSJeff Kirsher 
291baf0fbfeSJeff Kirsher static struct page *ftmac100_rxdes_get_page(struct ftmac100_rxdes *rxdes)
292baf0fbfeSJeff Kirsher {
293baf0fbfeSJeff Kirsher 	return (struct page *)rxdes->rxdes3;
294baf0fbfeSJeff Kirsher }
295baf0fbfeSJeff Kirsher 
296baf0fbfeSJeff Kirsher /******************************************************************************
297baf0fbfeSJeff Kirsher  * internal functions (receive)
298baf0fbfeSJeff Kirsher  *****************************************************************************/
299baf0fbfeSJeff Kirsher static int ftmac100_next_rx_pointer(int pointer)
300baf0fbfeSJeff Kirsher {
301baf0fbfeSJeff Kirsher 	return (pointer + 1) & (RX_QUEUE_ENTRIES - 1);
302baf0fbfeSJeff Kirsher }
303baf0fbfeSJeff Kirsher 
304baf0fbfeSJeff Kirsher static void ftmac100_rx_pointer_advance(struct ftmac100 *priv)
305baf0fbfeSJeff Kirsher {
306baf0fbfeSJeff Kirsher 	priv->rx_pointer = ftmac100_next_rx_pointer(priv->rx_pointer);
307baf0fbfeSJeff Kirsher }
308baf0fbfeSJeff Kirsher 
309baf0fbfeSJeff Kirsher static struct ftmac100_rxdes *ftmac100_current_rxdes(struct ftmac100 *priv)
310baf0fbfeSJeff Kirsher {
311baf0fbfeSJeff Kirsher 	return &priv->descs->rxdes[priv->rx_pointer];
312baf0fbfeSJeff Kirsher }
313baf0fbfeSJeff Kirsher 
314baf0fbfeSJeff Kirsher static struct ftmac100_rxdes *
315baf0fbfeSJeff Kirsher ftmac100_rx_locate_first_segment(struct ftmac100 *priv)
316baf0fbfeSJeff Kirsher {
317baf0fbfeSJeff Kirsher 	struct ftmac100_rxdes *rxdes = ftmac100_current_rxdes(priv);
318baf0fbfeSJeff Kirsher 
319baf0fbfeSJeff Kirsher 	while (!ftmac100_rxdes_owned_by_dma(rxdes)) {
320baf0fbfeSJeff Kirsher 		if (ftmac100_rxdes_first_segment(rxdes))
321baf0fbfeSJeff Kirsher 			return rxdes;
322baf0fbfeSJeff Kirsher 
323baf0fbfeSJeff Kirsher 		ftmac100_rxdes_set_dma_own(rxdes);
324baf0fbfeSJeff Kirsher 		ftmac100_rx_pointer_advance(priv);
325baf0fbfeSJeff Kirsher 		rxdes = ftmac100_current_rxdes(priv);
326baf0fbfeSJeff Kirsher 	}
327baf0fbfeSJeff Kirsher 
328baf0fbfeSJeff Kirsher 	return NULL;
329baf0fbfeSJeff Kirsher }
330baf0fbfeSJeff Kirsher 
331baf0fbfeSJeff Kirsher static bool ftmac100_rx_packet_error(struct ftmac100 *priv,
332baf0fbfeSJeff Kirsher 				     struct ftmac100_rxdes *rxdes)
333baf0fbfeSJeff Kirsher {
334baf0fbfeSJeff Kirsher 	struct net_device *netdev = priv->netdev;
335baf0fbfeSJeff Kirsher 	bool error = false;
336baf0fbfeSJeff Kirsher 
337baf0fbfeSJeff Kirsher 	if (unlikely(ftmac100_rxdes_rx_error(rxdes))) {
338baf0fbfeSJeff Kirsher 		if (net_ratelimit())
339baf0fbfeSJeff Kirsher 			netdev_info(netdev, "rx err\n");
340baf0fbfeSJeff Kirsher 
341baf0fbfeSJeff Kirsher 		netdev->stats.rx_errors++;
342baf0fbfeSJeff Kirsher 		error = true;
343baf0fbfeSJeff Kirsher 	}
344baf0fbfeSJeff Kirsher 
345baf0fbfeSJeff Kirsher 	if (unlikely(ftmac100_rxdes_crc_error(rxdes))) {
346baf0fbfeSJeff Kirsher 		if (net_ratelimit())
347baf0fbfeSJeff Kirsher 			netdev_info(netdev, "rx crc err\n");
348baf0fbfeSJeff Kirsher 
349baf0fbfeSJeff Kirsher 		netdev->stats.rx_crc_errors++;
350baf0fbfeSJeff Kirsher 		error = true;
351baf0fbfeSJeff Kirsher 	}
352baf0fbfeSJeff Kirsher 
353baf0fbfeSJeff Kirsher 	if (unlikely(ftmac100_rxdes_frame_too_long(rxdes))) {
354baf0fbfeSJeff Kirsher 		if (net_ratelimit())
355baf0fbfeSJeff Kirsher 			netdev_info(netdev, "rx frame too long\n");
356baf0fbfeSJeff Kirsher 
357baf0fbfeSJeff Kirsher 		netdev->stats.rx_length_errors++;
358baf0fbfeSJeff Kirsher 		error = true;
359baf0fbfeSJeff Kirsher 	} else if (unlikely(ftmac100_rxdes_runt(rxdes))) {
360baf0fbfeSJeff Kirsher 		if (net_ratelimit())
361baf0fbfeSJeff Kirsher 			netdev_info(netdev, "rx runt\n");
362baf0fbfeSJeff Kirsher 
363baf0fbfeSJeff Kirsher 		netdev->stats.rx_length_errors++;
364baf0fbfeSJeff Kirsher 		error = true;
365baf0fbfeSJeff Kirsher 	} else if (unlikely(ftmac100_rxdes_odd_nibble(rxdes))) {
366baf0fbfeSJeff Kirsher 		if (net_ratelimit())
367baf0fbfeSJeff Kirsher 			netdev_info(netdev, "rx odd nibble\n");
368baf0fbfeSJeff Kirsher 
369baf0fbfeSJeff Kirsher 		netdev->stats.rx_length_errors++;
370baf0fbfeSJeff Kirsher 		error = true;
371baf0fbfeSJeff Kirsher 	}
372baf0fbfeSJeff Kirsher 
373baf0fbfeSJeff Kirsher 	return error;
374baf0fbfeSJeff Kirsher }
375baf0fbfeSJeff Kirsher 
376baf0fbfeSJeff Kirsher static void ftmac100_rx_drop_packet(struct ftmac100 *priv)
377baf0fbfeSJeff Kirsher {
378baf0fbfeSJeff Kirsher 	struct net_device *netdev = priv->netdev;
379baf0fbfeSJeff Kirsher 	struct ftmac100_rxdes *rxdes = ftmac100_current_rxdes(priv);
380baf0fbfeSJeff Kirsher 	bool done = false;
381baf0fbfeSJeff Kirsher 
382baf0fbfeSJeff Kirsher 	if (net_ratelimit())
383baf0fbfeSJeff Kirsher 		netdev_dbg(netdev, "drop packet %p\n", rxdes);
384baf0fbfeSJeff Kirsher 
385baf0fbfeSJeff Kirsher 	do {
386baf0fbfeSJeff Kirsher 		if (ftmac100_rxdes_last_segment(rxdes))
387baf0fbfeSJeff Kirsher 			done = true;
388baf0fbfeSJeff Kirsher 
389baf0fbfeSJeff Kirsher 		ftmac100_rxdes_set_dma_own(rxdes);
390baf0fbfeSJeff Kirsher 		ftmac100_rx_pointer_advance(priv);
391baf0fbfeSJeff Kirsher 		rxdes = ftmac100_current_rxdes(priv);
392baf0fbfeSJeff Kirsher 	} while (!done && !ftmac100_rxdes_owned_by_dma(rxdes));
393baf0fbfeSJeff Kirsher 
394baf0fbfeSJeff Kirsher 	netdev->stats.rx_dropped++;
395baf0fbfeSJeff Kirsher }
396baf0fbfeSJeff Kirsher 
397baf0fbfeSJeff Kirsher static bool ftmac100_rx_packet(struct ftmac100 *priv, int *processed)
398baf0fbfeSJeff Kirsher {
399baf0fbfeSJeff Kirsher 	struct net_device *netdev = priv->netdev;
400baf0fbfeSJeff Kirsher 	struct ftmac100_rxdes *rxdes;
401baf0fbfeSJeff Kirsher 	struct sk_buff *skb;
402baf0fbfeSJeff Kirsher 	struct page *page;
403baf0fbfeSJeff Kirsher 	dma_addr_t map;
404baf0fbfeSJeff Kirsher 	int length;
405baf0fbfeSJeff Kirsher 
406baf0fbfeSJeff Kirsher 	rxdes = ftmac100_rx_locate_first_segment(priv);
407baf0fbfeSJeff Kirsher 	if (!rxdes)
408baf0fbfeSJeff Kirsher 		return false;
409baf0fbfeSJeff Kirsher 
410baf0fbfeSJeff Kirsher 	if (unlikely(ftmac100_rx_packet_error(priv, rxdes))) {
411baf0fbfeSJeff Kirsher 		ftmac100_rx_drop_packet(priv);
412baf0fbfeSJeff Kirsher 		return true;
413baf0fbfeSJeff Kirsher 	}
414baf0fbfeSJeff Kirsher 
415baf0fbfeSJeff Kirsher 	/*
416baf0fbfeSJeff Kirsher 	 * It is impossible to get multi-segment packets
417baf0fbfeSJeff Kirsher 	 * because we always provide big enough receive buffers.
418baf0fbfeSJeff Kirsher 	 */
419baf0fbfeSJeff Kirsher 	if (unlikely(!ftmac100_rxdes_last_segment(rxdes)))
420baf0fbfeSJeff Kirsher 		BUG();
421baf0fbfeSJeff Kirsher 
422baf0fbfeSJeff Kirsher 	/* start processing */
423baf0fbfeSJeff Kirsher 	skb = netdev_alloc_skb_ip_align(netdev, 128);
424baf0fbfeSJeff Kirsher 	if (unlikely(!skb)) {
425baf0fbfeSJeff Kirsher 		if (net_ratelimit())
426baf0fbfeSJeff Kirsher 			netdev_err(netdev, "rx skb alloc failed\n");
427baf0fbfeSJeff Kirsher 
428baf0fbfeSJeff Kirsher 		ftmac100_rx_drop_packet(priv);
429baf0fbfeSJeff Kirsher 		return true;
430baf0fbfeSJeff Kirsher 	}
431baf0fbfeSJeff Kirsher 
432baf0fbfeSJeff Kirsher 	if (unlikely(ftmac100_rxdes_multicast(rxdes)))
433baf0fbfeSJeff Kirsher 		netdev->stats.multicast++;
434baf0fbfeSJeff Kirsher 
435baf0fbfeSJeff Kirsher 	map = ftmac100_rxdes_get_dma_addr(rxdes);
436baf0fbfeSJeff Kirsher 	dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
437baf0fbfeSJeff Kirsher 
438baf0fbfeSJeff Kirsher 	length = ftmac100_rxdes_frame_length(rxdes);
439baf0fbfeSJeff Kirsher 	page = ftmac100_rxdes_get_page(rxdes);
440baf0fbfeSJeff Kirsher 	skb_fill_page_desc(skb, 0, page, 0, length);
441baf0fbfeSJeff Kirsher 	skb->len += length;
442baf0fbfeSJeff Kirsher 	skb->data_len += length;
44396cd8951SEric Dumazet 
4446ecd09ddSEric Dumazet 	if (length > 128) {
44596cd8951SEric Dumazet 		skb->truesize += PAGE_SIZE;
4466ecd09ddSEric Dumazet 		/* We pull the minimum amount into linear part */
4476ecd09ddSEric Dumazet 		__pskb_pull_tail(skb, ETH_HLEN);
4486ecd09ddSEric Dumazet 	} else {
4496ecd09ddSEric Dumazet 		/* Small frames are copied into linear part to free one page */
4506ecd09ddSEric Dumazet 		__pskb_pull_tail(skb, length);
4516ecd09ddSEric Dumazet 	}
452baf0fbfeSJeff Kirsher 	ftmac100_alloc_rx_page(priv, rxdes, GFP_ATOMIC);
453baf0fbfeSJeff Kirsher 
454baf0fbfeSJeff Kirsher 	ftmac100_rx_pointer_advance(priv);
455baf0fbfeSJeff Kirsher 
456baf0fbfeSJeff Kirsher 	skb->protocol = eth_type_trans(skb, netdev);
457baf0fbfeSJeff Kirsher 
458baf0fbfeSJeff Kirsher 	netdev->stats.rx_packets++;
459baf0fbfeSJeff Kirsher 	netdev->stats.rx_bytes += skb->len;
460baf0fbfeSJeff Kirsher 
461baf0fbfeSJeff Kirsher 	/* push packet to protocol stack */
462baf0fbfeSJeff Kirsher 	netif_receive_skb(skb);
463baf0fbfeSJeff Kirsher 
464baf0fbfeSJeff Kirsher 	(*processed)++;
465baf0fbfeSJeff Kirsher 	return true;
466baf0fbfeSJeff Kirsher }
467baf0fbfeSJeff Kirsher 
468baf0fbfeSJeff Kirsher /******************************************************************************
469baf0fbfeSJeff Kirsher  * internal functions (transmit descriptor)
470baf0fbfeSJeff Kirsher  *****************************************************************************/
471baf0fbfeSJeff Kirsher static void ftmac100_txdes_reset(struct ftmac100_txdes *txdes)
472baf0fbfeSJeff Kirsher {
473baf0fbfeSJeff Kirsher 	/* clear all except end of ring bit */
474baf0fbfeSJeff Kirsher 	txdes->txdes0 = 0;
475baf0fbfeSJeff Kirsher 	txdes->txdes1 &= cpu_to_le32(FTMAC100_TXDES1_EDOTR);
476baf0fbfeSJeff Kirsher 	txdes->txdes2 = 0;
477baf0fbfeSJeff Kirsher 	txdes->txdes3 = 0;
478baf0fbfeSJeff Kirsher }
479baf0fbfeSJeff Kirsher 
480baf0fbfeSJeff Kirsher static bool ftmac100_txdes_owned_by_dma(struct ftmac100_txdes *txdes)
481baf0fbfeSJeff Kirsher {
482baf0fbfeSJeff Kirsher 	return txdes->txdes0 & cpu_to_le32(FTMAC100_TXDES0_TXDMA_OWN);
483baf0fbfeSJeff Kirsher }
484baf0fbfeSJeff Kirsher 
485baf0fbfeSJeff Kirsher static void ftmac100_txdes_set_dma_own(struct ftmac100_txdes *txdes)
486baf0fbfeSJeff Kirsher {
487baf0fbfeSJeff Kirsher 	/*
488baf0fbfeSJeff Kirsher 	 * Make sure dma own bit will not be set before any other
489baf0fbfeSJeff Kirsher 	 * descriptor fields.
490baf0fbfeSJeff Kirsher 	 */
491baf0fbfeSJeff Kirsher 	wmb();
492baf0fbfeSJeff Kirsher 	txdes->txdes0 |= cpu_to_le32(FTMAC100_TXDES0_TXDMA_OWN);
493baf0fbfeSJeff Kirsher }
494baf0fbfeSJeff Kirsher 
495baf0fbfeSJeff Kirsher static bool ftmac100_txdes_excessive_collision(struct ftmac100_txdes *txdes)
496baf0fbfeSJeff Kirsher {
497baf0fbfeSJeff Kirsher 	return txdes->txdes0 & cpu_to_le32(FTMAC100_TXDES0_TXPKT_EXSCOL);
498baf0fbfeSJeff Kirsher }
499baf0fbfeSJeff Kirsher 
500baf0fbfeSJeff Kirsher static bool ftmac100_txdes_late_collision(struct ftmac100_txdes *txdes)
501baf0fbfeSJeff Kirsher {
502baf0fbfeSJeff Kirsher 	return txdes->txdes0 & cpu_to_le32(FTMAC100_TXDES0_TXPKT_LATECOL);
503baf0fbfeSJeff Kirsher }
504baf0fbfeSJeff Kirsher 
505baf0fbfeSJeff Kirsher static void ftmac100_txdes_set_end_of_ring(struct ftmac100_txdes *txdes)
506baf0fbfeSJeff Kirsher {
507baf0fbfeSJeff Kirsher 	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_EDOTR);
508baf0fbfeSJeff Kirsher }
509baf0fbfeSJeff Kirsher 
510baf0fbfeSJeff Kirsher static void ftmac100_txdes_set_first_segment(struct ftmac100_txdes *txdes)
511baf0fbfeSJeff Kirsher {
512baf0fbfeSJeff Kirsher 	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_FTS);
513baf0fbfeSJeff Kirsher }
514baf0fbfeSJeff Kirsher 
515baf0fbfeSJeff Kirsher static void ftmac100_txdes_set_last_segment(struct ftmac100_txdes *txdes)
516baf0fbfeSJeff Kirsher {
517baf0fbfeSJeff Kirsher 	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_LTS);
518baf0fbfeSJeff Kirsher }
519baf0fbfeSJeff Kirsher 
520baf0fbfeSJeff Kirsher static void ftmac100_txdes_set_txint(struct ftmac100_txdes *txdes)
521baf0fbfeSJeff Kirsher {
522baf0fbfeSJeff Kirsher 	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_TXIC);
523baf0fbfeSJeff Kirsher }
524baf0fbfeSJeff Kirsher 
525baf0fbfeSJeff Kirsher static void ftmac100_txdes_set_buffer_size(struct ftmac100_txdes *txdes,
526baf0fbfeSJeff Kirsher 					   unsigned int len)
527baf0fbfeSJeff Kirsher {
528baf0fbfeSJeff Kirsher 	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_TXBUF_SIZE(len));
529baf0fbfeSJeff Kirsher }
530baf0fbfeSJeff Kirsher 
531baf0fbfeSJeff Kirsher static void ftmac100_txdes_set_dma_addr(struct ftmac100_txdes *txdes,
532baf0fbfeSJeff Kirsher 					dma_addr_t addr)
533baf0fbfeSJeff Kirsher {
534baf0fbfeSJeff Kirsher 	txdes->txdes2 = cpu_to_le32(addr);
535baf0fbfeSJeff Kirsher }
536baf0fbfeSJeff Kirsher 
537baf0fbfeSJeff Kirsher static dma_addr_t ftmac100_txdes_get_dma_addr(struct ftmac100_txdes *txdes)
538baf0fbfeSJeff Kirsher {
539baf0fbfeSJeff Kirsher 	return le32_to_cpu(txdes->txdes2);
540baf0fbfeSJeff Kirsher }
541baf0fbfeSJeff Kirsher 
542baf0fbfeSJeff Kirsher /*
543baf0fbfeSJeff Kirsher  * txdes3 is not used by hardware. We use it to keep track of socket buffer.
544baf0fbfeSJeff Kirsher  * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu().
545baf0fbfeSJeff Kirsher  */
546baf0fbfeSJeff Kirsher static void ftmac100_txdes_set_skb(struct ftmac100_txdes *txdes, struct sk_buff *skb)
547baf0fbfeSJeff Kirsher {
548baf0fbfeSJeff Kirsher 	txdes->txdes3 = (unsigned int)skb;
549baf0fbfeSJeff Kirsher }
550baf0fbfeSJeff Kirsher 
551baf0fbfeSJeff Kirsher static struct sk_buff *ftmac100_txdes_get_skb(struct ftmac100_txdes *txdes)
552baf0fbfeSJeff Kirsher {
553baf0fbfeSJeff Kirsher 	return (struct sk_buff *)txdes->txdes3;
554baf0fbfeSJeff Kirsher }
555baf0fbfeSJeff Kirsher 
556baf0fbfeSJeff Kirsher /******************************************************************************
557baf0fbfeSJeff Kirsher  * internal functions (transmit)
558baf0fbfeSJeff Kirsher  *****************************************************************************/
559baf0fbfeSJeff Kirsher static int ftmac100_next_tx_pointer(int pointer)
560baf0fbfeSJeff Kirsher {
561baf0fbfeSJeff Kirsher 	return (pointer + 1) & (TX_QUEUE_ENTRIES - 1);
562baf0fbfeSJeff Kirsher }
563baf0fbfeSJeff Kirsher 
564baf0fbfeSJeff Kirsher static void ftmac100_tx_pointer_advance(struct ftmac100 *priv)
565baf0fbfeSJeff Kirsher {
566baf0fbfeSJeff Kirsher 	priv->tx_pointer = ftmac100_next_tx_pointer(priv->tx_pointer);
567baf0fbfeSJeff Kirsher }
568baf0fbfeSJeff Kirsher 
569baf0fbfeSJeff Kirsher static void ftmac100_tx_clean_pointer_advance(struct ftmac100 *priv)
570baf0fbfeSJeff Kirsher {
571baf0fbfeSJeff Kirsher 	priv->tx_clean_pointer = ftmac100_next_tx_pointer(priv->tx_clean_pointer);
572baf0fbfeSJeff Kirsher }
573baf0fbfeSJeff Kirsher 
574baf0fbfeSJeff Kirsher static struct ftmac100_txdes *ftmac100_current_txdes(struct ftmac100 *priv)
575baf0fbfeSJeff Kirsher {
576baf0fbfeSJeff Kirsher 	return &priv->descs->txdes[priv->tx_pointer];
577baf0fbfeSJeff Kirsher }
578baf0fbfeSJeff Kirsher 
579baf0fbfeSJeff Kirsher static struct ftmac100_txdes *ftmac100_current_clean_txdes(struct ftmac100 *priv)
580baf0fbfeSJeff Kirsher {
581baf0fbfeSJeff Kirsher 	return &priv->descs->txdes[priv->tx_clean_pointer];
582baf0fbfeSJeff Kirsher }
583baf0fbfeSJeff Kirsher 
584baf0fbfeSJeff Kirsher static bool ftmac100_tx_complete_packet(struct ftmac100 *priv)
585baf0fbfeSJeff Kirsher {
586baf0fbfeSJeff Kirsher 	struct net_device *netdev = priv->netdev;
587baf0fbfeSJeff Kirsher 	struct ftmac100_txdes *txdes;
588baf0fbfeSJeff Kirsher 	struct sk_buff *skb;
589baf0fbfeSJeff Kirsher 	dma_addr_t map;
590baf0fbfeSJeff Kirsher 
591baf0fbfeSJeff Kirsher 	if (priv->tx_pending == 0)
592baf0fbfeSJeff Kirsher 		return false;
593baf0fbfeSJeff Kirsher 
594baf0fbfeSJeff Kirsher 	txdes = ftmac100_current_clean_txdes(priv);
595baf0fbfeSJeff Kirsher 
596baf0fbfeSJeff Kirsher 	if (ftmac100_txdes_owned_by_dma(txdes))
597baf0fbfeSJeff Kirsher 		return false;
598baf0fbfeSJeff Kirsher 
599baf0fbfeSJeff Kirsher 	skb = ftmac100_txdes_get_skb(txdes);
600baf0fbfeSJeff Kirsher 	map = ftmac100_txdes_get_dma_addr(txdes);
601baf0fbfeSJeff Kirsher 
602baf0fbfeSJeff Kirsher 	if (unlikely(ftmac100_txdes_excessive_collision(txdes) ||
603baf0fbfeSJeff Kirsher 		     ftmac100_txdes_late_collision(txdes))) {
604baf0fbfeSJeff Kirsher 		/*
605baf0fbfeSJeff Kirsher 		 * packet transmitted to ethernet lost due to late collision
606baf0fbfeSJeff Kirsher 		 * or excessive collision
607baf0fbfeSJeff Kirsher 		 */
608baf0fbfeSJeff Kirsher 		netdev->stats.tx_aborted_errors++;
609baf0fbfeSJeff Kirsher 	} else {
610baf0fbfeSJeff Kirsher 		netdev->stats.tx_packets++;
611baf0fbfeSJeff Kirsher 		netdev->stats.tx_bytes += skb->len;
612baf0fbfeSJeff Kirsher 	}
613baf0fbfeSJeff Kirsher 
614baf0fbfeSJeff Kirsher 	dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
615baf0fbfeSJeff Kirsher 	dev_kfree_skb(skb);
616baf0fbfeSJeff Kirsher 
617baf0fbfeSJeff Kirsher 	ftmac100_txdes_reset(txdes);
618baf0fbfeSJeff Kirsher 
619baf0fbfeSJeff Kirsher 	ftmac100_tx_clean_pointer_advance(priv);
620baf0fbfeSJeff Kirsher 
621baf0fbfeSJeff Kirsher 	spin_lock(&priv->tx_lock);
622baf0fbfeSJeff Kirsher 	priv->tx_pending--;
623baf0fbfeSJeff Kirsher 	spin_unlock(&priv->tx_lock);
624baf0fbfeSJeff Kirsher 	netif_wake_queue(netdev);
625baf0fbfeSJeff Kirsher 
626baf0fbfeSJeff Kirsher 	return true;
627baf0fbfeSJeff Kirsher }
628baf0fbfeSJeff Kirsher 
629baf0fbfeSJeff Kirsher static void ftmac100_tx_complete(struct ftmac100 *priv)
630baf0fbfeSJeff Kirsher {
631baf0fbfeSJeff Kirsher 	while (ftmac100_tx_complete_packet(priv))
632baf0fbfeSJeff Kirsher 		;
633baf0fbfeSJeff Kirsher }
634baf0fbfeSJeff Kirsher 
635baf0fbfeSJeff Kirsher static int ftmac100_xmit(struct ftmac100 *priv, struct sk_buff *skb,
636baf0fbfeSJeff Kirsher 			 dma_addr_t map)
637baf0fbfeSJeff Kirsher {
638baf0fbfeSJeff Kirsher 	struct net_device *netdev = priv->netdev;
639baf0fbfeSJeff Kirsher 	struct ftmac100_txdes *txdes;
640baf0fbfeSJeff Kirsher 	unsigned int len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
641baf0fbfeSJeff Kirsher 
642baf0fbfeSJeff Kirsher 	txdes = ftmac100_current_txdes(priv);
643baf0fbfeSJeff Kirsher 	ftmac100_tx_pointer_advance(priv);
644baf0fbfeSJeff Kirsher 
645baf0fbfeSJeff Kirsher 	/* setup TX descriptor */
646baf0fbfeSJeff Kirsher 	ftmac100_txdes_set_skb(txdes, skb);
647baf0fbfeSJeff Kirsher 	ftmac100_txdes_set_dma_addr(txdes, map);
648baf0fbfeSJeff Kirsher 
649baf0fbfeSJeff Kirsher 	ftmac100_txdes_set_first_segment(txdes);
650baf0fbfeSJeff Kirsher 	ftmac100_txdes_set_last_segment(txdes);
651baf0fbfeSJeff Kirsher 	ftmac100_txdes_set_txint(txdes);
652baf0fbfeSJeff Kirsher 	ftmac100_txdes_set_buffer_size(txdes, len);
653baf0fbfeSJeff Kirsher 
654baf0fbfeSJeff Kirsher 	spin_lock(&priv->tx_lock);
655baf0fbfeSJeff Kirsher 	priv->tx_pending++;
656baf0fbfeSJeff Kirsher 	if (priv->tx_pending == TX_QUEUE_ENTRIES)
657baf0fbfeSJeff Kirsher 		netif_stop_queue(netdev);
658baf0fbfeSJeff Kirsher 
659baf0fbfeSJeff Kirsher 	/* start transmit */
660baf0fbfeSJeff Kirsher 	ftmac100_txdes_set_dma_own(txdes);
661baf0fbfeSJeff Kirsher 	spin_unlock(&priv->tx_lock);
662baf0fbfeSJeff Kirsher 
663baf0fbfeSJeff Kirsher 	ftmac100_txdma_start_polling(priv);
664baf0fbfeSJeff Kirsher 	return NETDEV_TX_OK;
665baf0fbfeSJeff Kirsher }
666baf0fbfeSJeff Kirsher 
667baf0fbfeSJeff Kirsher /******************************************************************************
668baf0fbfeSJeff Kirsher  * internal functions (buffer)
669baf0fbfeSJeff Kirsher  *****************************************************************************/
670baf0fbfeSJeff Kirsher static int ftmac100_alloc_rx_page(struct ftmac100 *priv,
671baf0fbfeSJeff Kirsher 				  struct ftmac100_rxdes *rxdes, gfp_t gfp)
672baf0fbfeSJeff Kirsher {
673baf0fbfeSJeff Kirsher 	struct net_device *netdev = priv->netdev;
674baf0fbfeSJeff Kirsher 	struct page *page;
675baf0fbfeSJeff Kirsher 	dma_addr_t map;
676baf0fbfeSJeff Kirsher 
677baf0fbfeSJeff Kirsher 	page = alloc_page(gfp);
678baf0fbfeSJeff Kirsher 	if (!page) {
679baf0fbfeSJeff Kirsher 		if (net_ratelimit())
680baf0fbfeSJeff Kirsher 			netdev_err(netdev, "failed to allocate rx page\n");
681baf0fbfeSJeff Kirsher 		return -ENOMEM;
682baf0fbfeSJeff Kirsher 	}
683baf0fbfeSJeff Kirsher 
684baf0fbfeSJeff Kirsher 	map = dma_map_page(priv->dev, page, 0, RX_BUF_SIZE, DMA_FROM_DEVICE);
685baf0fbfeSJeff Kirsher 	if (unlikely(dma_mapping_error(priv->dev, map))) {
686baf0fbfeSJeff Kirsher 		if (net_ratelimit())
687baf0fbfeSJeff Kirsher 			netdev_err(netdev, "failed to map rx page\n");
688baf0fbfeSJeff Kirsher 		__free_page(page);
689baf0fbfeSJeff Kirsher 		return -ENOMEM;
690baf0fbfeSJeff Kirsher 	}
691baf0fbfeSJeff Kirsher 
692baf0fbfeSJeff Kirsher 	ftmac100_rxdes_set_page(rxdes, page);
693baf0fbfeSJeff Kirsher 	ftmac100_rxdes_set_dma_addr(rxdes, map);
694baf0fbfeSJeff Kirsher 	ftmac100_rxdes_set_buffer_size(rxdes, RX_BUF_SIZE);
695baf0fbfeSJeff Kirsher 	ftmac100_rxdes_set_dma_own(rxdes);
696baf0fbfeSJeff Kirsher 	return 0;
697baf0fbfeSJeff Kirsher }
698baf0fbfeSJeff Kirsher 
699baf0fbfeSJeff Kirsher static void ftmac100_free_buffers(struct ftmac100 *priv)
700baf0fbfeSJeff Kirsher {
701baf0fbfeSJeff Kirsher 	int i;
702baf0fbfeSJeff Kirsher 
703baf0fbfeSJeff Kirsher 	for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
704baf0fbfeSJeff Kirsher 		struct ftmac100_rxdes *rxdes = &priv->descs->rxdes[i];
705baf0fbfeSJeff Kirsher 		struct page *page = ftmac100_rxdes_get_page(rxdes);
706baf0fbfeSJeff Kirsher 		dma_addr_t map = ftmac100_rxdes_get_dma_addr(rxdes);
707baf0fbfeSJeff Kirsher 
708baf0fbfeSJeff Kirsher 		if (!page)
709baf0fbfeSJeff Kirsher 			continue;
710baf0fbfeSJeff Kirsher 
711baf0fbfeSJeff Kirsher 		dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
712baf0fbfeSJeff Kirsher 		__free_page(page);
713baf0fbfeSJeff Kirsher 	}
714baf0fbfeSJeff Kirsher 
715baf0fbfeSJeff Kirsher 	for (i = 0; i < TX_QUEUE_ENTRIES; i++) {
716baf0fbfeSJeff Kirsher 		struct ftmac100_txdes *txdes = &priv->descs->txdes[i];
717baf0fbfeSJeff Kirsher 		struct sk_buff *skb = ftmac100_txdes_get_skb(txdes);
718baf0fbfeSJeff Kirsher 		dma_addr_t map = ftmac100_txdes_get_dma_addr(txdes);
719baf0fbfeSJeff Kirsher 
720baf0fbfeSJeff Kirsher 		if (!skb)
721baf0fbfeSJeff Kirsher 			continue;
722baf0fbfeSJeff Kirsher 
723baf0fbfeSJeff Kirsher 		dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
724baf0fbfeSJeff Kirsher 		dev_kfree_skb(skb);
725baf0fbfeSJeff Kirsher 	}
726baf0fbfeSJeff Kirsher 
727baf0fbfeSJeff Kirsher 	dma_free_coherent(priv->dev, sizeof(struct ftmac100_descs),
728baf0fbfeSJeff Kirsher 			  priv->descs, priv->descs_dma_addr);
729baf0fbfeSJeff Kirsher }
730baf0fbfeSJeff Kirsher 
731baf0fbfeSJeff Kirsher static int ftmac100_alloc_buffers(struct ftmac100 *priv)
732baf0fbfeSJeff Kirsher {
733baf0fbfeSJeff Kirsher 	int i;
734baf0fbfeSJeff Kirsher 
735baf0fbfeSJeff Kirsher 	priv->descs = dma_alloc_coherent(priv->dev, sizeof(struct ftmac100_descs),
736baf0fbfeSJeff Kirsher 					 &priv->descs_dma_addr, GFP_KERNEL);
737baf0fbfeSJeff Kirsher 	if (!priv->descs)
738baf0fbfeSJeff Kirsher 		return -ENOMEM;
739baf0fbfeSJeff Kirsher 
740baf0fbfeSJeff Kirsher 	memset(priv->descs, 0, sizeof(struct ftmac100_descs));
741baf0fbfeSJeff Kirsher 
742baf0fbfeSJeff Kirsher 	/* initialize RX ring */
743baf0fbfeSJeff Kirsher 	ftmac100_rxdes_set_end_of_ring(&priv->descs->rxdes[RX_QUEUE_ENTRIES - 1]);
744baf0fbfeSJeff Kirsher 
745baf0fbfeSJeff Kirsher 	for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
746baf0fbfeSJeff Kirsher 		struct ftmac100_rxdes *rxdes = &priv->descs->rxdes[i];
747baf0fbfeSJeff Kirsher 
748baf0fbfeSJeff Kirsher 		if (ftmac100_alloc_rx_page(priv, rxdes, GFP_KERNEL))
749baf0fbfeSJeff Kirsher 			goto err;
750baf0fbfeSJeff Kirsher 	}
751baf0fbfeSJeff Kirsher 
752baf0fbfeSJeff Kirsher 	/* initialize TX ring */
753baf0fbfeSJeff Kirsher 	ftmac100_txdes_set_end_of_ring(&priv->descs->txdes[TX_QUEUE_ENTRIES - 1]);
754baf0fbfeSJeff Kirsher 	return 0;
755baf0fbfeSJeff Kirsher 
756baf0fbfeSJeff Kirsher err:
757baf0fbfeSJeff Kirsher 	ftmac100_free_buffers(priv);
758baf0fbfeSJeff Kirsher 	return -ENOMEM;
759baf0fbfeSJeff Kirsher }
760baf0fbfeSJeff Kirsher 
761baf0fbfeSJeff Kirsher /******************************************************************************
762baf0fbfeSJeff Kirsher  * struct mii_if_info functions
763baf0fbfeSJeff Kirsher  *****************************************************************************/
764baf0fbfeSJeff Kirsher static int ftmac100_mdio_read(struct net_device *netdev, int phy_id, int reg)
765baf0fbfeSJeff Kirsher {
766baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
767baf0fbfeSJeff Kirsher 	unsigned int phycr;
768baf0fbfeSJeff Kirsher 	int i;
769baf0fbfeSJeff Kirsher 
770baf0fbfeSJeff Kirsher 	phycr = FTMAC100_PHYCR_PHYAD(phy_id) |
771baf0fbfeSJeff Kirsher 		FTMAC100_PHYCR_REGAD(reg) |
772baf0fbfeSJeff Kirsher 		FTMAC100_PHYCR_MIIRD;
773baf0fbfeSJeff Kirsher 
774baf0fbfeSJeff Kirsher 	iowrite32(phycr, priv->base + FTMAC100_OFFSET_PHYCR);
775baf0fbfeSJeff Kirsher 
776baf0fbfeSJeff Kirsher 	for (i = 0; i < 10; i++) {
777baf0fbfeSJeff Kirsher 		phycr = ioread32(priv->base + FTMAC100_OFFSET_PHYCR);
778baf0fbfeSJeff Kirsher 
779baf0fbfeSJeff Kirsher 		if ((phycr & FTMAC100_PHYCR_MIIRD) == 0)
780baf0fbfeSJeff Kirsher 			return phycr & FTMAC100_PHYCR_MIIRDATA;
781baf0fbfeSJeff Kirsher 
782baf0fbfeSJeff Kirsher 		udelay(100);
783baf0fbfeSJeff Kirsher 	}
784baf0fbfeSJeff Kirsher 
785baf0fbfeSJeff Kirsher 	netdev_err(netdev, "mdio read timed out\n");
786baf0fbfeSJeff Kirsher 	return 0;
787baf0fbfeSJeff Kirsher }
788baf0fbfeSJeff Kirsher 
789baf0fbfeSJeff Kirsher static void ftmac100_mdio_write(struct net_device *netdev, int phy_id, int reg,
790baf0fbfeSJeff Kirsher 				int data)
791baf0fbfeSJeff Kirsher {
792baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
793baf0fbfeSJeff Kirsher 	unsigned int phycr;
794baf0fbfeSJeff Kirsher 	int i;
795baf0fbfeSJeff Kirsher 
796baf0fbfeSJeff Kirsher 	phycr = FTMAC100_PHYCR_PHYAD(phy_id) |
797baf0fbfeSJeff Kirsher 		FTMAC100_PHYCR_REGAD(reg) |
798baf0fbfeSJeff Kirsher 		FTMAC100_PHYCR_MIIWR;
799baf0fbfeSJeff Kirsher 
800baf0fbfeSJeff Kirsher 	data = FTMAC100_PHYWDATA_MIIWDATA(data);
801baf0fbfeSJeff Kirsher 
802baf0fbfeSJeff Kirsher 	iowrite32(data, priv->base + FTMAC100_OFFSET_PHYWDATA);
803baf0fbfeSJeff Kirsher 	iowrite32(phycr, priv->base + FTMAC100_OFFSET_PHYCR);
804baf0fbfeSJeff Kirsher 
805baf0fbfeSJeff Kirsher 	for (i = 0; i < 10; i++) {
806baf0fbfeSJeff Kirsher 		phycr = ioread32(priv->base + FTMAC100_OFFSET_PHYCR);
807baf0fbfeSJeff Kirsher 
808baf0fbfeSJeff Kirsher 		if ((phycr & FTMAC100_PHYCR_MIIWR) == 0)
809baf0fbfeSJeff Kirsher 			return;
810baf0fbfeSJeff Kirsher 
811baf0fbfeSJeff Kirsher 		udelay(100);
812baf0fbfeSJeff Kirsher 	}
813baf0fbfeSJeff Kirsher 
814baf0fbfeSJeff Kirsher 	netdev_err(netdev, "mdio write timed out\n");
815baf0fbfeSJeff Kirsher }
816baf0fbfeSJeff Kirsher 
817baf0fbfeSJeff Kirsher /******************************************************************************
818baf0fbfeSJeff Kirsher  * struct ethtool_ops functions
819baf0fbfeSJeff Kirsher  *****************************************************************************/
820baf0fbfeSJeff Kirsher static void ftmac100_get_drvinfo(struct net_device *netdev,
821baf0fbfeSJeff Kirsher 				 struct ethtool_drvinfo *info)
822baf0fbfeSJeff Kirsher {
823baf0fbfeSJeff Kirsher 	strcpy(info->driver, DRV_NAME);
824baf0fbfeSJeff Kirsher 	strcpy(info->version, DRV_VERSION);
825baf0fbfeSJeff Kirsher 	strcpy(info->bus_info, dev_name(&netdev->dev));
826baf0fbfeSJeff Kirsher }
827baf0fbfeSJeff Kirsher 
828baf0fbfeSJeff Kirsher static int ftmac100_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
829baf0fbfeSJeff Kirsher {
830baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
831baf0fbfeSJeff Kirsher 	return mii_ethtool_gset(&priv->mii, cmd);
832baf0fbfeSJeff Kirsher }
833baf0fbfeSJeff Kirsher 
834baf0fbfeSJeff Kirsher static int ftmac100_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
835baf0fbfeSJeff Kirsher {
836baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
837baf0fbfeSJeff Kirsher 	return mii_ethtool_sset(&priv->mii, cmd);
838baf0fbfeSJeff Kirsher }
839baf0fbfeSJeff Kirsher 
840baf0fbfeSJeff Kirsher static int ftmac100_nway_reset(struct net_device *netdev)
841baf0fbfeSJeff Kirsher {
842baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
843baf0fbfeSJeff Kirsher 	return mii_nway_restart(&priv->mii);
844baf0fbfeSJeff Kirsher }
845baf0fbfeSJeff Kirsher 
846baf0fbfeSJeff Kirsher static u32 ftmac100_get_link(struct net_device *netdev)
847baf0fbfeSJeff Kirsher {
848baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
849baf0fbfeSJeff Kirsher 	return mii_link_ok(&priv->mii);
850baf0fbfeSJeff Kirsher }
851baf0fbfeSJeff Kirsher 
852baf0fbfeSJeff Kirsher static const struct ethtool_ops ftmac100_ethtool_ops = {
853baf0fbfeSJeff Kirsher 	.set_settings		= ftmac100_set_settings,
854baf0fbfeSJeff Kirsher 	.get_settings		= ftmac100_get_settings,
855baf0fbfeSJeff Kirsher 	.get_drvinfo		= ftmac100_get_drvinfo,
856baf0fbfeSJeff Kirsher 	.nway_reset		= ftmac100_nway_reset,
857baf0fbfeSJeff Kirsher 	.get_link		= ftmac100_get_link,
858baf0fbfeSJeff Kirsher };
859baf0fbfeSJeff Kirsher 
860baf0fbfeSJeff Kirsher /******************************************************************************
861baf0fbfeSJeff Kirsher  * interrupt handler
862baf0fbfeSJeff Kirsher  *****************************************************************************/
863baf0fbfeSJeff Kirsher static irqreturn_t ftmac100_interrupt(int irq, void *dev_id)
864baf0fbfeSJeff Kirsher {
865baf0fbfeSJeff Kirsher 	struct net_device *netdev = dev_id;
866baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
867baf0fbfeSJeff Kirsher 
868baf0fbfeSJeff Kirsher 	if (likely(netif_running(netdev))) {
869baf0fbfeSJeff Kirsher 		/* Disable interrupts for polling */
870baf0fbfeSJeff Kirsher 		ftmac100_disable_all_int(priv);
871baf0fbfeSJeff Kirsher 		napi_schedule(&priv->napi);
872baf0fbfeSJeff Kirsher 	}
873baf0fbfeSJeff Kirsher 
874baf0fbfeSJeff Kirsher 	return IRQ_HANDLED;
875baf0fbfeSJeff Kirsher }
876baf0fbfeSJeff Kirsher 
877baf0fbfeSJeff Kirsher /******************************************************************************
878baf0fbfeSJeff Kirsher  * struct napi_struct functions
879baf0fbfeSJeff Kirsher  *****************************************************************************/
880baf0fbfeSJeff Kirsher static int ftmac100_poll(struct napi_struct *napi, int budget)
881baf0fbfeSJeff Kirsher {
882baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = container_of(napi, struct ftmac100, napi);
883baf0fbfeSJeff Kirsher 	struct net_device *netdev = priv->netdev;
884baf0fbfeSJeff Kirsher 	unsigned int status;
885baf0fbfeSJeff Kirsher 	bool completed = true;
886baf0fbfeSJeff Kirsher 	int rx = 0;
887baf0fbfeSJeff Kirsher 
888baf0fbfeSJeff Kirsher 	status = ioread32(priv->base + FTMAC100_OFFSET_ISR);
889baf0fbfeSJeff Kirsher 
890baf0fbfeSJeff Kirsher 	if (status & (FTMAC100_INT_RPKT_FINISH | FTMAC100_INT_NORXBUF)) {
891baf0fbfeSJeff Kirsher 		/*
892baf0fbfeSJeff Kirsher 		 * FTMAC100_INT_RPKT_FINISH:
893baf0fbfeSJeff Kirsher 		 *	RX DMA has received packets into RX buffer successfully
894baf0fbfeSJeff Kirsher 		 *
895baf0fbfeSJeff Kirsher 		 * FTMAC100_INT_NORXBUF:
896baf0fbfeSJeff Kirsher 		 *	RX buffer unavailable
897baf0fbfeSJeff Kirsher 		 */
898baf0fbfeSJeff Kirsher 		bool retry;
899baf0fbfeSJeff Kirsher 
900baf0fbfeSJeff Kirsher 		do {
901baf0fbfeSJeff Kirsher 			retry = ftmac100_rx_packet(priv, &rx);
902baf0fbfeSJeff Kirsher 		} while (retry && rx < budget);
903baf0fbfeSJeff Kirsher 
904baf0fbfeSJeff Kirsher 		if (retry && rx == budget)
905baf0fbfeSJeff Kirsher 			completed = false;
906baf0fbfeSJeff Kirsher 	}
907baf0fbfeSJeff Kirsher 
908baf0fbfeSJeff Kirsher 	if (status & (FTMAC100_INT_XPKT_OK | FTMAC100_INT_XPKT_LOST)) {
909baf0fbfeSJeff Kirsher 		/*
910baf0fbfeSJeff Kirsher 		 * FTMAC100_INT_XPKT_OK:
911baf0fbfeSJeff Kirsher 		 *	packet transmitted to ethernet successfully
912baf0fbfeSJeff Kirsher 		 *
913baf0fbfeSJeff Kirsher 		 * FTMAC100_INT_XPKT_LOST:
914baf0fbfeSJeff Kirsher 		 *	packet transmitted to ethernet lost due to late
915baf0fbfeSJeff Kirsher 		 *	collision or excessive collision
916baf0fbfeSJeff Kirsher 		 */
917baf0fbfeSJeff Kirsher 		ftmac100_tx_complete(priv);
918baf0fbfeSJeff Kirsher 	}
919baf0fbfeSJeff Kirsher 
920baf0fbfeSJeff Kirsher 	if (status & (FTMAC100_INT_NORXBUF | FTMAC100_INT_RPKT_LOST |
921baf0fbfeSJeff Kirsher 		      FTMAC100_INT_AHB_ERR | FTMAC100_INT_PHYSTS_CHG)) {
922baf0fbfeSJeff Kirsher 		if (net_ratelimit())
923baf0fbfeSJeff Kirsher 			netdev_info(netdev, "[ISR] = 0x%x: %s%s%s%s\n", status,
924baf0fbfeSJeff Kirsher 				    status & FTMAC100_INT_NORXBUF ? "NORXBUF " : "",
925baf0fbfeSJeff Kirsher 				    status & FTMAC100_INT_RPKT_LOST ? "RPKT_LOST " : "",
926baf0fbfeSJeff Kirsher 				    status & FTMAC100_INT_AHB_ERR ? "AHB_ERR " : "",
927baf0fbfeSJeff Kirsher 				    status & FTMAC100_INT_PHYSTS_CHG ? "PHYSTS_CHG" : "");
928baf0fbfeSJeff Kirsher 
929baf0fbfeSJeff Kirsher 		if (status & FTMAC100_INT_NORXBUF) {
930baf0fbfeSJeff Kirsher 			/* RX buffer unavailable */
931baf0fbfeSJeff Kirsher 			netdev->stats.rx_over_errors++;
932baf0fbfeSJeff Kirsher 		}
933baf0fbfeSJeff Kirsher 
934baf0fbfeSJeff Kirsher 		if (status & FTMAC100_INT_RPKT_LOST) {
935baf0fbfeSJeff Kirsher 			/* received packet lost due to RX FIFO full */
936baf0fbfeSJeff Kirsher 			netdev->stats.rx_fifo_errors++;
937baf0fbfeSJeff Kirsher 		}
938baf0fbfeSJeff Kirsher 
939baf0fbfeSJeff Kirsher 		if (status & FTMAC100_INT_PHYSTS_CHG) {
940baf0fbfeSJeff Kirsher 			/* PHY link status change */
941baf0fbfeSJeff Kirsher 			mii_check_link(&priv->mii);
942baf0fbfeSJeff Kirsher 		}
943baf0fbfeSJeff Kirsher 	}
944baf0fbfeSJeff Kirsher 
945baf0fbfeSJeff Kirsher 	if (completed) {
946baf0fbfeSJeff Kirsher 		/* stop polling */
947baf0fbfeSJeff Kirsher 		napi_complete(napi);
948baf0fbfeSJeff Kirsher 		ftmac100_enable_all_int(priv);
949baf0fbfeSJeff Kirsher 	}
950baf0fbfeSJeff Kirsher 
951baf0fbfeSJeff Kirsher 	return rx;
952baf0fbfeSJeff Kirsher }
953baf0fbfeSJeff Kirsher 
954baf0fbfeSJeff Kirsher /******************************************************************************
955baf0fbfeSJeff Kirsher  * struct net_device_ops functions
956baf0fbfeSJeff Kirsher  *****************************************************************************/
957baf0fbfeSJeff Kirsher static int ftmac100_open(struct net_device *netdev)
958baf0fbfeSJeff Kirsher {
959baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
960baf0fbfeSJeff Kirsher 	int err;
961baf0fbfeSJeff Kirsher 
962baf0fbfeSJeff Kirsher 	err = ftmac100_alloc_buffers(priv);
963baf0fbfeSJeff Kirsher 	if (err) {
964baf0fbfeSJeff Kirsher 		netdev_err(netdev, "failed to allocate buffers\n");
965baf0fbfeSJeff Kirsher 		goto err_alloc;
966baf0fbfeSJeff Kirsher 	}
967baf0fbfeSJeff Kirsher 
968baf0fbfeSJeff Kirsher 	err = request_irq(priv->irq, ftmac100_interrupt, 0, netdev->name, netdev);
969baf0fbfeSJeff Kirsher 	if (err) {
970baf0fbfeSJeff Kirsher 		netdev_err(netdev, "failed to request irq %d\n", priv->irq);
971baf0fbfeSJeff Kirsher 		goto err_irq;
972baf0fbfeSJeff Kirsher 	}
973baf0fbfeSJeff Kirsher 
974baf0fbfeSJeff Kirsher 	priv->rx_pointer = 0;
975baf0fbfeSJeff Kirsher 	priv->tx_clean_pointer = 0;
976baf0fbfeSJeff Kirsher 	priv->tx_pointer = 0;
977baf0fbfeSJeff Kirsher 	priv->tx_pending = 0;
978baf0fbfeSJeff Kirsher 
979baf0fbfeSJeff Kirsher 	err = ftmac100_start_hw(priv);
980baf0fbfeSJeff Kirsher 	if (err)
981baf0fbfeSJeff Kirsher 		goto err_hw;
982baf0fbfeSJeff Kirsher 
983baf0fbfeSJeff Kirsher 	napi_enable(&priv->napi);
984baf0fbfeSJeff Kirsher 	netif_start_queue(netdev);
985baf0fbfeSJeff Kirsher 
986baf0fbfeSJeff Kirsher 	ftmac100_enable_all_int(priv);
987baf0fbfeSJeff Kirsher 
988baf0fbfeSJeff Kirsher 	return 0;
989baf0fbfeSJeff Kirsher 
990baf0fbfeSJeff Kirsher err_hw:
991baf0fbfeSJeff Kirsher 	free_irq(priv->irq, netdev);
992baf0fbfeSJeff Kirsher err_irq:
993baf0fbfeSJeff Kirsher 	ftmac100_free_buffers(priv);
994baf0fbfeSJeff Kirsher err_alloc:
995baf0fbfeSJeff Kirsher 	return err;
996baf0fbfeSJeff Kirsher }
997baf0fbfeSJeff Kirsher 
998baf0fbfeSJeff Kirsher static int ftmac100_stop(struct net_device *netdev)
999baf0fbfeSJeff Kirsher {
1000baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
1001baf0fbfeSJeff Kirsher 
1002baf0fbfeSJeff Kirsher 	ftmac100_disable_all_int(priv);
1003baf0fbfeSJeff Kirsher 	netif_stop_queue(netdev);
1004baf0fbfeSJeff Kirsher 	napi_disable(&priv->napi);
1005baf0fbfeSJeff Kirsher 	ftmac100_stop_hw(priv);
1006baf0fbfeSJeff Kirsher 	free_irq(priv->irq, netdev);
1007baf0fbfeSJeff Kirsher 	ftmac100_free_buffers(priv);
1008baf0fbfeSJeff Kirsher 
1009baf0fbfeSJeff Kirsher 	return 0;
1010baf0fbfeSJeff Kirsher }
1011baf0fbfeSJeff Kirsher 
1012baf0fbfeSJeff Kirsher static int ftmac100_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
1013baf0fbfeSJeff Kirsher {
1014baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
1015baf0fbfeSJeff Kirsher 	dma_addr_t map;
1016baf0fbfeSJeff Kirsher 
1017baf0fbfeSJeff Kirsher 	if (unlikely(skb->len > MAX_PKT_SIZE)) {
1018baf0fbfeSJeff Kirsher 		if (net_ratelimit())
1019baf0fbfeSJeff Kirsher 			netdev_dbg(netdev, "tx packet too big\n");
1020baf0fbfeSJeff Kirsher 
1021baf0fbfeSJeff Kirsher 		netdev->stats.tx_dropped++;
1022baf0fbfeSJeff Kirsher 		dev_kfree_skb(skb);
1023baf0fbfeSJeff Kirsher 		return NETDEV_TX_OK;
1024baf0fbfeSJeff Kirsher 	}
1025baf0fbfeSJeff Kirsher 
1026baf0fbfeSJeff Kirsher 	map = dma_map_single(priv->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
1027baf0fbfeSJeff Kirsher 	if (unlikely(dma_mapping_error(priv->dev, map))) {
1028baf0fbfeSJeff Kirsher 		/* drop packet */
1029baf0fbfeSJeff Kirsher 		if (net_ratelimit())
1030baf0fbfeSJeff Kirsher 			netdev_err(netdev, "map socket buffer failed\n");
1031baf0fbfeSJeff Kirsher 
1032baf0fbfeSJeff Kirsher 		netdev->stats.tx_dropped++;
1033baf0fbfeSJeff Kirsher 		dev_kfree_skb(skb);
1034baf0fbfeSJeff Kirsher 		return NETDEV_TX_OK;
1035baf0fbfeSJeff Kirsher 	}
1036baf0fbfeSJeff Kirsher 
1037baf0fbfeSJeff Kirsher 	return ftmac100_xmit(priv, skb, map);
1038baf0fbfeSJeff Kirsher }
1039baf0fbfeSJeff Kirsher 
1040baf0fbfeSJeff Kirsher /* optional */
1041baf0fbfeSJeff Kirsher static int ftmac100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
1042baf0fbfeSJeff Kirsher {
1043baf0fbfeSJeff Kirsher 	struct ftmac100 *priv = netdev_priv(netdev);
1044baf0fbfeSJeff Kirsher 	struct mii_ioctl_data *data = if_mii(ifr);
1045baf0fbfeSJeff Kirsher 
1046baf0fbfeSJeff Kirsher 	return generic_mii_ioctl(&priv->mii, data, cmd, NULL);
1047baf0fbfeSJeff Kirsher }
1048baf0fbfeSJeff Kirsher 
1049baf0fbfeSJeff Kirsher static const struct net_device_ops ftmac100_netdev_ops = {
1050baf0fbfeSJeff Kirsher 	.ndo_open		= ftmac100_open,
1051baf0fbfeSJeff Kirsher 	.ndo_stop		= ftmac100_stop,
1052baf0fbfeSJeff Kirsher 	.ndo_start_xmit		= ftmac100_hard_start_xmit,
1053baf0fbfeSJeff Kirsher 	.ndo_set_mac_address	= eth_mac_addr,
1054baf0fbfeSJeff Kirsher 	.ndo_validate_addr	= eth_validate_addr,
1055baf0fbfeSJeff Kirsher 	.ndo_do_ioctl		= ftmac100_do_ioctl,
1056baf0fbfeSJeff Kirsher };
1057baf0fbfeSJeff Kirsher 
1058baf0fbfeSJeff Kirsher /******************************************************************************
1059baf0fbfeSJeff Kirsher  * struct platform_driver functions
1060baf0fbfeSJeff Kirsher  *****************************************************************************/
1061baf0fbfeSJeff Kirsher static int ftmac100_probe(struct platform_device *pdev)
1062baf0fbfeSJeff Kirsher {
1063baf0fbfeSJeff Kirsher 	struct resource *res;
1064baf0fbfeSJeff Kirsher 	int irq;
1065baf0fbfeSJeff Kirsher 	struct net_device *netdev;
1066baf0fbfeSJeff Kirsher 	struct ftmac100 *priv;
1067baf0fbfeSJeff Kirsher 	int err;
1068baf0fbfeSJeff Kirsher 
1069baf0fbfeSJeff Kirsher 	if (!pdev)
1070baf0fbfeSJeff Kirsher 		return -ENODEV;
1071baf0fbfeSJeff Kirsher 
1072baf0fbfeSJeff Kirsher 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1073baf0fbfeSJeff Kirsher 	if (!res)
1074baf0fbfeSJeff Kirsher 		return -ENXIO;
1075baf0fbfeSJeff Kirsher 
1076baf0fbfeSJeff Kirsher 	irq = platform_get_irq(pdev, 0);
1077baf0fbfeSJeff Kirsher 	if (irq < 0)
1078baf0fbfeSJeff Kirsher 		return irq;
1079baf0fbfeSJeff Kirsher 
1080baf0fbfeSJeff Kirsher 	/* setup net_device */
1081baf0fbfeSJeff Kirsher 	netdev = alloc_etherdev(sizeof(*priv));
1082baf0fbfeSJeff Kirsher 	if (!netdev) {
1083baf0fbfeSJeff Kirsher 		err = -ENOMEM;
1084baf0fbfeSJeff Kirsher 		goto err_alloc_etherdev;
1085baf0fbfeSJeff Kirsher 	}
1086baf0fbfeSJeff Kirsher 
1087baf0fbfeSJeff Kirsher 	SET_NETDEV_DEV(netdev, &pdev->dev);
1088baf0fbfeSJeff Kirsher 	SET_ETHTOOL_OPS(netdev, &ftmac100_ethtool_ops);
1089baf0fbfeSJeff Kirsher 	netdev->netdev_ops = &ftmac100_netdev_ops;
1090baf0fbfeSJeff Kirsher 
1091baf0fbfeSJeff Kirsher 	platform_set_drvdata(pdev, netdev);
1092baf0fbfeSJeff Kirsher 
1093baf0fbfeSJeff Kirsher 	/* setup private data */
1094baf0fbfeSJeff Kirsher 	priv = netdev_priv(netdev);
1095baf0fbfeSJeff Kirsher 	priv->netdev = netdev;
1096baf0fbfeSJeff Kirsher 	priv->dev = &pdev->dev;
1097baf0fbfeSJeff Kirsher 
1098baf0fbfeSJeff Kirsher 	spin_lock_init(&priv->tx_lock);
1099baf0fbfeSJeff Kirsher 
1100baf0fbfeSJeff Kirsher 	/* initialize NAPI */
1101baf0fbfeSJeff Kirsher 	netif_napi_add(netdev, &priv->napi, ftmac100_poll, 64);
1102baf0fbfeSJeff Kirsher 
1103baf0fbfeSJeff Kirsher 	/* map io memory */
1104baf0fbfeSJeff Kirsher 	priv->res = request_mem_region(res->start, resource_size(res),
1105baf0fbfeSJeff Kirsher 				       dev_name(&pdev->dev));
1106baf0fbfeSJeff Kirsher 	if (!priv->res) {
1107baf0fbfeSJeff Kirsher 		dev_err(&pdev->dev, "Could not reserve memory region\n");
1108baf0fbfeSJeff Kirsher 		err = -ENOMEM;
1109baf0fbfeSJeff Kirsher 		goto err_req_mem;
1110baf0fbfeSJeff Kirsher 	}
1111baf0fbfeSJeff Kirsher 
1112baf0fbfeSJeff Kirsher 	priv->base = ioremap(res->start, resource_size(res));
1113baf0fbfeSJeff Kirsher 	if (!priv->base) {
1114baf0fbfeSJeff Kirsher 		dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
1115baf0fbfeSJeff Kirsher 		err = -EIO;
1116baf0fbfeSJeff Kirsher 		goto err_ioremap;
1117baf0fbfeSJeff Kirsher 	}
1118baf0fbfeSJeff Kirsher 
1119baf0fbfeSJeff Kirsher 	priv->irq = irq;
1120baf0fbfeSJeff Kirsher 
1121baf0fbfeSJeff Kirsher 	/* initialize struct mii_if_info */
1122baf0fbfeSJeff Kirsher 	priv->mii.phy_id	= 0;
1123baf0fbfeSJeff Kirsher 	priv->mii.phy_id_mask	= 0x1f;
1124baf0fbfeSJeff Kirsher 	priv->mii.reg_num_mask	= 0x1f;
1125baf0fbfeSJeff Kirsher 	priv->mii.dev		= netdev;
1126baf0fbfeSJeff Kirsher 	priv->mii.mdio_read	= ftmac100_mdio_read;
1127baf0fbfeSJeff Kirsher 	priv->mii.mdio_write	= ftmac100_mdio_write;
1128baf0fbfeSJeff Kirsher 
1129baf0fbfeSJeff Kirsher 	/* register network device */
1130baf0fbfeSJeff Kirsher 	err = register_netdev(netdev);
1131baf0fbfeSJeff Kirsher 	if (err) {
1132baf0fbfeSJeff Kirsher 		dev_err(&pdev->dev, "Failed to register netdev\n");
1133baf0fbfeSJeff Kirsher 		goto err_register_netdev;
1134baf0fbfeSJeff Kirsher 	}
1135baf0fbfeSJeff Kirsher 
1136baf0fbfeSJeff Kirsher 	netdev_info(netdev, "irq %d, mapped at %p\n", priv->irq, priv->base);
1137baf0fbfeSJeff Kirsher 
1138baf0fbfeSJeff Kirsher 	if (!is_valid_ether_addr(netdev->dev_addr)) {
1139f2cedb63SDanny Kukawka 		eth_hw_addr_random(netdev);
1140baf0fbfeSJeff Kirsher 		netdev_info(netdev, "generated random MAC address %pM\n",
1141baf0fbfeSJeff Kirsher 			    netdev->dev_addr);
1142baf0fbfeSJeff Kirsher 	}
1143baf0fbfeSJeff Kirsher 
1144baf0fbfeSJeff Kirsher 	return 0;
1145baf0fbfeSJeff Kirsher 
1146baf0fbfeSJeff Kirsher err_register_netdev:
1147baf0fbfeSJeff Kirsher 	iounmap(priv->base);
1148baf0fbfeSJeff Kirsher err_ioremap:
1149baf0fbfeSJeff Kirsher 	release_resource(priv->res);
1150baf0fbfeSJeff Kirsher err_req_mem:
1151baf0fbfeSJeff Kirsher 	netif_napi_del(&priv->napi);
1152baf0fbfeSJeff Kirsher 	platform_set_drvdata(pdev, NULL);
1153baf0fbfeSJeff Kirsher 	free_netdev(netdev);
1154baf0fbfeSJeff Kirsher err_alloc_etherdev:
1155baf0fbfeSJeff Kirsher 	return err;
1156baf0fbfeSJeff Kirsher }
1157baf0fbfeSJeff Kirsher 
1158baf0fbfeSJeff Kirsher static int __exit ftmac100_remove(struct platform_device *pdev)
1159baf0fbfeSJeff Kirsher {
1160baf0fbfeSJeff Kirsher 	struct net_device *netdev;
1161baf0fbfeSJeff Kirsher 	struct ftmac100 *priv;
1162baf0fbfeSJeff Kirsher 
1163baf0fbfeSJeff Kirsher 	netdev = platform_get_drvdata(pdev);
1164baf0fbfeSJeff Kirsher 	priv = netdev_priv(netdev);
1165baf0fbfeSJeff Kirsher 
1166baf0fbfeSJeff Kirsher 	unregister_netdev(netdev);
1167baf0fbfeSJeff Kirsher 
1168baf0fbfeSJeff Kirsher 	iounmap(priv->base);
1169baf0fbfeSJeff Kirsher 	release_resource(priv->res);
1170baf0fbfeSJeff Kirsher 
1171baf0fbfeSJeff Kirsher 	netif_napi_del(&priv->napi);
1172baf0fbfeSJeff Kirsher 	platform_set_drvdata(pdev, NULL);
1173baf0fbfeSJeff Kirsher 	free_netdev(netdev);
1174baf0fbfeSJeff Kirsher 	return 0;
1175baf0fbfeSJeff Kirsher }
1176baf0fbfeSJeff Kirsher 
1177baf0fbfeSJeff Kirsher static struct platform_driver ftmac100_driver = {
1178baf0fbfeSJeff Kirsher 	.probe		= ftmac100_probe,
1179baf0fbfeSJeff Kirsher 	.remove		= __exit_p(ftmac100_remove),
1180baf0fbfeSJeff Kirsher 	.driver		= {
1181baf0fbfeSJeff Kirsher 		.name	= DRV_NAME,
1182baf0fbfeSJeff Kirsher 		.owner	= THIS_MODULE,
1183baf0fbfeSJeff Kirsher 	},
1184baf0fbfeSJeff Kirsher };
1185baf0fbfeSJeff Kirsher 
1186baf0fbfeSJeff Kirsher /******************************************************************************
1187baf0fbfeSJeff Kirsher  * initialization / finalization
1188baf0fbfeSJeff Kirsher  *****************************************************************************/
1189baf0fbfeSJeff Kirsher static int __init ftmac100_init(void)
1190baf0fbfeSJeff Kirsher {
1191baf0fbfeSJeff Kirsher 	pr_info("Loading version " DRV_VERSION " ...\n");
1192baf0fbfeSJeff Kirsher 	return platform_driver_register(&ftmac100_driver);
1193baf0fbfeSJeff Kirsher }
1194baf0fbfeSJeff Kirsher 
1195baf0fbfeSJeff Kirsher static void __exit ftmac100_exit(void)
1196baf0fbfeSJeff Kirsher {
1197baf0fbfeSJeff Kirsher 	platform_driver_unregister(&ftmac100_driver);
1198baf0fbfeSJeff Kirsher }
1199baf0fbfeSJeff Kirsher 
1200baf0fbfeSJeff Kirsher module_init(ftmac100_init);
1201baf0fbfeSJeff Kirsher module_exit(ftmac100_exit);
1202baf0fbfeSJeff Kirsher 
1203baf0fbfeSJeff Kirsher MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
1204baf0fbfeSJeff Kirsher MODULE_DESCRIPTION("FTMAC100 driver");
1205baf0fbfeSJeff Kirsher MODULE_LICENSE("GPL");
1206