• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/net/
1/*
2 * Ethernet driver for S6105 on chip network device
3 * (c)2008 emlix GmbH http://www.emlix.com
4 * Authors:	Oskar Schirmer <os@emlix.com>
5 *		Daniel Gloeckner <dg@emlix.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 */
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/interrupt.h>
15#include <linux/types.h>
16#include <linux/delay.h>
17#include <linux/init.h>
18#include <linux/spinlock.h>
19#include <linux/netdevice.h>
20#include <linux/etherdevice.h>
21#include <linux/if.h>
22#include <linux/stddef.h>
23#include <linux/mii.h>
24#include <linux/phy.h>
25#include <linux/platform_device.h>
26#include <variant/hardware.h>
27#include <variant/dmac.h>
28
29#define DRV_NAME "s6gmac"
30#define DRV_PRMT DRV_NAME ": "
31
32
33/* register declarations */
34
35#define S6_GMAC_MACCONF1	0x000
36#define S6_GMAC_MACCONF1_TXENA		0
37#define S6_GMAC_MACCONF1_SYNCTX		1
38#define S6_GMAC_MACCONF1_RXENA		2
39#define S6_GMAC_MACCONF1_SYNCRX		3
40#define S6_GMAC_MACCONF1_TXFLOWCTRL	4
41#define S6_GMAC_MACCONF1_RXFLOWCTRL	5
42#define S6_GMAC_MACCONF1_LOOPBACK	8
43#define S6_GMAC_MACCONF1_RESTXFUNC	16
44#define S6_GMAC_MACCONF1_RESRXFUNC	17
45#define S6_GMAC_MACCONF1_RESTXMACCTRL	18
46#define S6_GMAC_MACCONF1_RESRXMACCTRL	19
47#define S6_GMAC_MACCONF1_SIMULRES	30
48#define S6_GMAC_MACCONF1_SOFTRES	31
49#define S6_GMAC_MACCONF2	0x004
50#define S6_GMAC_MACCONF2_FULL		0
51#define S6_GMAC_MACCONF2_CRCENA		1
52#define S6_GMAC_MACCONF2_PADCRCENA	2
53#define S6_GMAC_MACCONF2_LENGTHFCHK	4
54#define S6_GMAC_MACCONF2_HUGEFRAMENA	5
55#define S6_GMAC_MACCONF2_IFMODE		8
56#define S6_GMAC_MACCONF2_IFMODE_NIBBLE		1
57#define S6_GMAC_MACCONF2_IFMODE_BYTE		2
58#define S6_GMAC_MACCONF2_IFMODE_MASK		3
59#define S6_GMAC_MACCONF2_PREAMBLELEN	12
60#define S6_GMAC_MACCONF2_PREAMBLELEN_MASK	0x0F
61#define S6_GMAC_MACIPGIFG	0x008
62#define S6_GMAC_MACIPGIFG_B2BINTERPGAP	0
63#define S6_GMAC_MACIPGIFG_B2BINTERPGAP_MASK	0x7F
64#define S6_GMAC_MACIPGIFG_MINIFGENFORCE	8
65#define S6_GMAC_MACIPGIFG_B2BINTERPGAP2	16
66#define S6_GMAC_MACIPGIFG_B2BINTERPGAP1	24
67#define S6_GMAC_MACHALFDUPLEX	0x00C
68#define S6_GMAC_MACHALFDUPLEX_COLLISWIN	0
69#define S6_GMAC_MACHALFDUPLEX_COLLISWIN_MASK	0x3F
70#define S6_GMAC_MACHALFDUPLEX_RETXMAX	12
71#define S6_GMAC_MACHALFDUPLEX_RETXMAX_MASK	0x0F
72#define S6_GMAC_MACHALFDUPLEX_EXCESSDEF	16
73#define S6_GMAC_MACHALFDUPLEX_NOBACKOFF	17
74#define S6_GMAC_MACHALFDUPLEX_BPNOBCKOF	18
75#define S6_GMAC_MACHALFDUPLEX_ALTBEBENA	19
76#define S6_GMAC_MACHALFDUPLEX_ALTBEBTRN	20
77#define S6_GMAC_MACHALFDUPLEX_ALTBEBTR_MASK	0x0F
78#define S6_GMAC_MACMAXFRAMELEN	0x010
79#define S6_GMAC_MACMIICONF	0x020
80#define S6_GMAC_MACMIICONF_CSEL		0
81#define S6_GMAC_MACMIICONF_CSEL_DIV10		0
82#define S6_GMAC_MACMIICONF_CSEL_DIV12		1
83#define S6_GMAC_MACMIICONF_CSEL_DIV14		2
84#define S6_GMAC_MACMIICONF_CSEL_DIV18		3
85#define S6_GMAC_MACMIICONF_CSEL_DIV24		4
86#define S6_GMAC_MACMIICONF_CSEL_DIV34		5
87#define S6_GMAC_MACMIICONF_CSEL_DIV68		6
88#define S6_GMAC_MACMIICONF_CSEL_DIV168		7
89#define S6_GMAC_MACMIICONF_CSEL_MASK		7
90#define S6_GMAC_MACMIICONF_PREAMBLESUPR	4
91#define S6_GMAC_MACMIICONF_SCANAUTOINCR	5
92#define S6_GMAC_MACMIICMD	0x024
93#define S6_GMAC_MACMIICMD_READ		0
94#define S6_GMAC_MACMIICMD_SCAN		1
95#define S6_GMAC_MACMIIADDR	0x028
96#define S6_GMAC_MACMIIADDR_REG		0
97#define S6_GMAC_MACMIIADDR_REG_MASK		0x1F
98#define S6_GMAC_MACMIIADDR_PHY		8
99#define S6_GMAC_MACMIIADDR_PHY_MASK		0x1F
100#define S6_GMAC_MACMIICTRL	0x02C
101#define S6_GMAC_MACMIISTAT	0x030
102#define S6_GMAC_MACMIIINDI	0x034
103#define S6_GMAC_MACMIIINDI_BUSY		0
104#define S6_GMAC_MACMIIINDI_SCAN		1
105#define S6_GMAC_MACMIIINDI_INVAL	2
106#define S6_GMAC_MACINTERFSTAT	0x03C
107#define S6_GMAC_MACINTERFSTAT_LINKFAIL	3
108#define S6_GMAC_MACINTERFSTAT_EXCESSDEF	9
109#define S6_GMAC_MACSTATADDR1	0x040
110#define S6_GMAC_MACSTATADDR2	0x044
111
112#define S6_GMAC_FIFOCONF0	0x048
113#define S6_GMAC_FIFOCONF0_HSTRSTWT	0
114#define S6_GMAC_FIFOCONF0_HSTRSTSR	1
115#define S6_GMAC_FIFOCONF0_HSTRSTFR	2
116#define S6_GMAC_FIFOCONF0_HSTRSTST	3
117#define S6_GMAC_FIFOCONF0_HSTRSTFT	4
118#define S6_GMAC_FIFOCONF0_WTMENREQ	8
119#define S6_GMAC_FIFOCONF0_SRFENREQ	9
120#define S6_GMAC_FIFOCONF0_FRFENREQ	10
121#define S6_GMAC_FIFOCONF0_STFENREQ	11
122#define S6_GMAC_FIFOCONF0_FTFENREQ	12
123#define S6_GMAC_FIFOCONF0_WTMENRPLY	16
124#define S6_GMAC_FIFOCONF0_SRFENRPLY	17
125#define S6_GMAC_FIFOCONF0_FRFENRPLY	18
126#define S6_GMAC_FIFOCONF0_STFENRPLY	19
127#define S6_GMAC_FIFOCONF0_FTFENRPLY	20
128#define S6_GMAC_FIFOCONF1	0x04C
129#define S6_GMAC_FIFOCONF2	0x050
130#define S6_GMAC_FIFOCONF2_CFGLWM	0
131#define S6_GMAC_FIFOCONF2_CFGHWM	16
132#define S6_GMAC_FIFOCONF3	0x054
133#define S6_GMAC_FIFOCONF3_CFGFTTH	0
134#define S6_GMAC_FIFOCONF3_CFGHWMFT	16
135#define S6_GMAC_FIFOCONF4	0x058
136#define S6_GMAC_FIFOCONF_RSV_PREVDROP	0
137#define S6_GMAC_FIFOCONF_RSV_RUNT	1
138#define S6_GMAC_FIFOCONF_RSV_FALSECAR	2
139#define S6_GMAC_FIFOCONF_RSV_CODEERR	3
140#define S6_GMAC_FIFOCONF_RSV_CRCERR	4
141#define S6_GMAC_FIFOCONF_RSV_LENGTHERR	5
142#define S6_GMAC_FIFOCONF_RSV_LENRANGE	6
143#define S6_GMAC_FIFOCONF_RSV_OK		7
144#define S6_GMAC_FIFOCONF_RSV_MULTICAST	8
145#define S6_GMAC_FIFOCONF_RSV_BROADCAST	9
146#define S6_GMAC_FIFOCONF_RSV_DRIBBLE	10
147#define S6_GMAC_FIFOCONF_RSV_CTRLFRAME	11
148#define S6_GMAC_FIFOCONF_RSV_PAUSECTRL	12
149#define S6_GMAC_FIFOCONF_RSV_UNOPCODE	13
150#define S6_GMAC_FIFOCONF_RSV_VLANTAG	14
151#define S6_GMAC_FIFOCONF_RSV_LONGEVENT	15
152#define S6_GMAC_FIFOCONF_RSV_TRUNCATED	16
153#define S6_GMAC_FIFOCONF_RSV_MASK		0x3FFFF
154#define S6_GMAC_FIFOCONF5	0x05C
155#define S6_GMAC_FIFOCONF5_DROPLT64	18
156#define S6_GMAC_FIFOCONF5_CFGBYTM	19
157#define S6_GMAC_FIFOCONF5_RXDROPSIZE	20
158#define S6_GMAC_FIFOCONF5_RXDROPSIZE_MASK	0xF
159
160#define S6_GMAC_STAT_REGS	0x080
161#define S6_GMAC_STAT_SIZE_MIN		12
162#define S6_GMAC_STATTR64	0x080
163#define S6_GMAC_STATTR64_SIZE		18
164#define S6_GMAC_STATTR127	0x084
165#define S6_GMAC_STATTR127_SIZE		18
166#define S6_GMAC_STATTR255	0x088
167#define S6_GMAC_STATTR255_SIZE		18
168#define S6_GMAC_STATTR511	0x08C
169#define S6_GMAC_STATTR511_SIZE		18
170#define S6_GMAC_STATTR1K	0x090
171#define S6_GMAC_STATTR1K_SIZE		18
172#define S6_GMAC_STATTRMAX	0x094
173#define S6_GMAC_STATTRMAX_SIZE		18
174#define S6_GMAC_STATTRMGV	0x098
175#define S6_GMAC_STATTRMGV_SIZE		18
176#define S6_GMAC_STATRBYT	0x09C
177#define S6_GMAC_STATRBYT_SIZE		24
178#define S6_GMAC_STATRPKT	0x0A0
179#define S6_GMAC_STATRPKT_SIZE		18
180#define S6_GMAC_STATRFCS	0x0A4
181#define S6_GMAC_STATRFCS_SIZE		12
182#define S6_GMAC_STATRMCA	0x0A8
183#define S6_GMAC_STATRMCA_SIZE		18
184#define S6_GMAC_STATRBCA	0x0AC
185#define S6_GMAC_STATRBCA_SIZE		22
186#define S6_GMAC_STATRXCF	0x0B0
187#define S6_GMAC_STATRXCF_SIZE		18
188#define S6_GMAC_STATRXPF	0x0B4
189#define S6_GMAC_STATRXPF_SIZE		12
190#define S6_GMAC_STATRXUO	0x0B8
191#define S6_GMAC_STATRXUO_SIZE		12
192#define S6_GMAC_STATRALN	0x0BC
193#define S6_GMAC_STATRALN_SIZE		12
194#define S6_GMAC_STATRFLR	0x0C0
195#define S6_GMAC_STATRFLR_SIZE		16
196#define S6_GMAC_STATRCDE	0x0C4
197#define S6_GMAC_STATRCDE_SIZE		12
198#define S6_GMAC_STATRCSE	0x0C8
199#define S6_GMAC_STATRCSE_SIZE		12
200#define S6_GMAC_STATRUND	0x0CC
201#define S6_GMAC_STATRUND_SIZE		12
202#define S6_GMAC_STATROVR	0x0D0
203#define S6_GMAC_STATROVR_SIZE		12
204#define S6_GMAC_STATRFRG	0x0D4
205#define S6_GMAC_STATRFRG_SIZE		12
206#define S6_GMAC_STATRJBR	0x0D8
207#define S6_GMAC_STATRJBR_SIZE		12
208#define S6_GMAC_STATRDRP	0x0DC
209#define S6_GMAC_STATRDRP_SIZE		12
210#define S6_GMAC_STATTBYT	0x0E0
211#define S6_GMAC_STATTBYT_SIZE		24
212#define S6_GMAC_STATTPKT	0x0E4
213#define S6_GMAC_STATTPKT_SIZE		18
214#define S6_GMAC_STATTMCA	0x0E8
215#define S6_GMAC_STATTMCA_SIZE		18
216#define S6_GMAC_STATTBCA	0x0EC
217#define S6_GMAC_STATTBCA_SIZE		18
218#define S6_GMAC_STATTXPF	0x0F0
219#define S6_GMAC_STATTXPF_SIZE		12
220#define S6_GMAC_STATTDFR	0x0F4
221#define S6_GMAC_STATTDFR_SIZE		12
222#define S6_GMAC_STATTEDF	0x0F8
223#define S6_GMAC_STATTEDF_SIZE		12
224#define S6_GMAC_STATTSCL	0x0FC
225#define S6_GMAC_STATTSCL_SIZE		12
226#define S6_GMAC_STATTMCL	0x100
227#define S6_GMAC_STATTMCL_SIZE		12
228#define S6_GMAC_STATTLCL	0x104
229#define S6_GMAC_STATTLCL_SIZE		12
230#define S6_GMAC_STATTXCL	0x108
231#define S6_GMAC_STATTXCL_SIZE		12
232#define S6_GMAC_STATTNCL	0x10C
233#define S6_GMAC_STATTNCL_SIZE		13
234#define S6_GMAC_STATTPFH	0x110
235#define S6_GMAC_STATTPFH_SIZE		12
236#define S6_GMAC_STATTDRP	0x114
237#define S6_GMAC_STATTDRP_SIZE		12
238#define S6_GMAC_STATTJBR	0x118
239#define S6_GMAC_STATTJBR_SIZE		12
240#define S6_GMAC_STATTFCS	0x11C
241#define S6_GMAC_STATTFCS_SIZE		12
242#define S6_GMAC_STATTXCF	0x120
243#define S6_GMAC_STATTXCF_SIZE		12
244#define S6_GMAC_STATTOVR	0x124
245#define S6_GMAC_STATTOVR_SIZE		12
246#define S6_GMAC_STATTUND	0x128
247#define S6_GMAC_STATTUND_SIZE		12
248#define S6_GMAC_STATTFRG	0x12C
249#define S6_GMAC_STATTFRG_SIZE		12
250#define S6_GMAC_STATCARRY(n)	(0x130 + 4*(n))
251#define S6_GMAC_STATCARRYMSK(n)	(0x138 + 4*(n))
252#define S6_GMAC_STATCARRY1_RDRP		0
253#define S6_GMAC_STATCARRY1_RJBR		1
254#define S6_GMAC_STATCARRY1_RFRG		2
255#define S6_GMAC_STATCARRY1_ROVR		3
256#define S6_GMAC_STATCARRY1_RUND		4
257#define S6_GMAC_STATCARRY1_RCSE		5
258#define S6_GMAC_STATCARRY1_RCDE		6
259#define S6_GMAC_STATCARRY1_RFLR		7
260#define S6_GMAC_STATCARRY1_RALN		8
261#define S6_GMAC_STATCARRY1_RXUO		9
262#define S6_GMAC_STATCARRY1_RXPF		10
263#define S6_GMAC_STATCARRY1_RXCF		11
264#define S6_GMAC_STATCARRY1_RBCA		12
265#define S6_GMAC_STATCARRY1_RMCA		13
266#define S6_GMAC_STATCARRY1_RFCS		14
267#define S6_GMAC_STATCARRY1_RPKT		15
268#define S6_GMAC_STATCARRY1_RBYT		16
269#define S6_GMAC_STATCARRY1_TRMGV	25
270#define S6_GMAC_STATCARRY1_TRMAX	26
271#define S6_GMAC_STATCARRY1_TR1K		27
272#define S6_GMAC_STATCARRY1_TR511	28
273#define S6_GMAC_STATCARRY1_TR255	29
274#define S6_GMAC_STATCARRY1_TR127	30
275#define S6_GMAC_STATCARRY1_TR64		31
276#define S6_GMAC_STATCARRY2_TDRP		0
277#define S6_GMAC_STATCARRY2_TPFH		1
278#define S6_GMAC_STATCARRY2_TNCL		2
279#define S6_GMAC_STATCARRY2_TXCL		3
280#define S6_GMAC_STATCARRY2_TLCL		4
281#define S6_GMAC_STATCARRY2_TMCL		5
282#define S6_GMAC_STATCARRY2_TSCL		6
283#define S6_GMAC_STATCARRY2_TEDF		7
284#define S6_GMAC_STATCARRY2_TDFR		8
285#define S6_GMAC_STATCARRY2_TXPF		9
286#define S6_GMAC_STATCARRY2_TBCA		10
287#define S6_GMAC_STATCARRY2_TMCA		11
288#define S6_GMAC_STATCARRY2_TPKT		12
289#define S6_GMAC_STATCARRY2_TBYT		13
290#define S6_GMAC_STATCARRY2_TFRG		14
291#define S6_GMAC_STATCARRY2_TUND		15
292#define S6_GMAC_STATCARRY2_TOVR		16
293#define S6_GMAC_STATCARRY2_TXCF		17
294#define S6_GMAC_STATCARRY2_TFCS		18
295#define S6_GMAC_STATCARRY2_TJBR		19
296
297#define S6_GMAC_HOST_PBLKCTRL	0x140
298#define S6_GMAC_HOST_PBLKCTRL_TXENA	0
299#define S6_GMAC_HOST_PBLKCTRL_RXENA	1
300#define S6_GMAC_HOST_PBLKCTRL_TXSRES	2
301#define S6_GMAC_HOST_PBLKCTRL_RXSRES	3
302#define S6_GMAC_HOST_PBLKCTRL_TXBSIZ	8
303#define S6_GMAC_HOST_PBLKCTRL_RXBSIZ	12
304#define S6_GMAC_HOST_PBLKCTRL_SIZ_16		4
305#define S6_GMAC_HOST_PBLKCTRL_SIZ_32		5
306#define S6_GMAC_HOST_PBLKCTRL_SIZ_64		6
307#define S6_GMAC_HOST_PBLKCTRL_SIZ_128		7
308#define S6_GMAC_HOST_PBLKCTRL_SIZ_MASK		0xF
309#define S6_GMAC_HOST_PBLKCTRL_STATENA	16
310#define S6_GMAC_HOST_PBLKCTRL_STATAUTOZ	17
311#define S6_GMAC_HOST_PBLKCTRL_STATCLEAR	18
312#define S6_GMAC_HOST_PBLKCTRL_RGMII	19
313#define S6_GMAC_HOST_INTMASK	0x144
314#define S6_GMAC_HOST_INTSTAT	0x148
315#define S6_GMAC_HOST_INT_TXBURSTOVER	3
316#define S6_GMAC_HOST_INT_TXPREWOVER	4
317#define S6_GMAC_HOST_INT_RXBURSTUNDER	5
318#define S6_GMAC_HOST_INT_RXPOSTRFULL	6
319#define S6_GMAC_HOST_INT_RXPOSTRUNDER	7
320#define S6_GMAC_HOST_RXFIFOHWM	0x14C
321#define S6_GMAC_HOST_CTRLFRAMXP	0x150
322#define S6_GMAC_HOST_DSTADDRLO(n) (0x160 + 8*(n))
323#define S6_GMAC_HOST_DSTADDRHI(n) (0x164 + 8*(n))
324#define S6_GMAC_HOST_DSTMASKLO(n) (0x180 + 8*(n))
325#define S6_GMAC_HOST_DSTMASKHI(n) (0x184 + 8*(n))
326
327#define S6_GMAC_BURST_PREWR	0x1B0
328#define S6_GMAC_BURST_PREWR_LEN		0
329#define S6_GMAC_BURST_PREWR_LEN_MASK		((1 << 20) - 1)
330#define S6_GMAC_BURST_PREWR_CFE		20
331#define S6_GMAC_BURST_PREWR_PPE		21
332#define S6_GMAC_BURST_PREWR_FCS		22
333#define S6_GMAC_BURST_PREWR_PAD		23
334#define S6_GMAC_BURST_POSTRD	0x1D0
335#define S6_GMAC_BURST_POSTRD_LEN	0
336#define S6_GMAC_BURST_POSTRD_LEN_MASK		((1 << 20) - 1)
337#define S6_GMAC_BURST_POSTRD_DROP	20
338
339
340/* data handling */
341
342#define S6_NUM_TX_SKB	8	/* must be larger than TX fifo size */
343#define S6_NUM_RX_SKB	16
344#define S6_MAX_FRLEN	1536
345
346struct s6gmac {
347	u32 reg;
348	u32 tx_dma;
349	u32 rx_dma;
350	u32 io;
351	u8 tx_chan;
352	u8 rx_chan;
353	spinlock_t lock;
354	u8 tx_skb_i, tx_skb_o;
355	u8 rx_skb_i, rx_skb_o;
356	struct sk_buff *tx_skb[S6_NUM_TX_SKB];
357	struct sk_buff *rx_skb[S6_NUM_RX_SKB];
358	unsigned long carry[sizeof(struct net_device_stats) / sizeof(long)];
359	unsigned long stats[sizeof(struct net_device_stats) / sizeof(long)];
360	struct phy_device *phydev;
361	struct {
362		struct mii_bus *bus;
363		int irq[PHY_MAX_ADDR];
364	} mii;
365	struct {
366		unsigned int mbit;
367		u8 giga;
368		u8 isup;
369		u8 full;
370	} link;
371};
372
373static void s6gmac_rx_fillfifo(struct s6gmac *pd)
374{
375	struct sk_buff *skb;
376	while ((((u8)(pd->rx_skb_i - pd->rx_skb_o)) < S6_NUM_RX_SKB) &&
377	       (!s6dmac_fifo_full(pd->rx_dma, pd->rx_chan)) &&
378	       (skb = dev_alloc_skb(S6_MAX_FRLEN + 2))) {
379		pd->rx_skb[(pd->rx_skb_i++) % S6_NUM_RX_SKB] = skb;
380		s6dmac_put_fifo_cache(pd->rx_dma, pd->rx_chan,
381			pd->io, (u32)skb->data, S6_MAX_FRLEN);
382	}
383}
384
385static void s6gmac_rx_interrupt(struct net_device *dev)
386{
387	struct s6gmac *pd = netdev_priv(dev);
388	u32 pfx;
389	struct sk_buff *skb;
390	while (((u8)(pd->rx_skb_i - pd->rx_skb_o)) >
391			s6dmac_pending_count(pd->rx_dma, pd->rx_chan)) {
392		skb = pd->rx_skb[(pd->rx_skb_o++) % S6_NUM_RX_SKB];
393		pfx = readl(pd->reg + S6_GMAC_BURST_POSTRD);
394		if (pfx & (1 << S6_GMAC_BURST_POSTRD_DROP)) {
395			dev_kfree_skb_irq(skb);
396		} else {
397			skb_put(skb, (pfx >> S6_GMAC_BURST_POSTRD_LEN)
398				& S6_GMAC_BURST_POSTRD_LEN_MASK);
399			skb->protocol = eth_type_trans(skb, dev);
400			skb->ip_summed = CHECKSUM_UNNECESSARY;
401			netif_rx(skb);
402		}
403	}
404}
405
406static void s6gmac_tx_interrupt(struct net_device *dev)
407{
408	struct s6gmac *pd = netdev_priv(dev);
409	while (((u8)(pd->tx_skb_i - pd->tx_skb_o)) >
410			s6dmac_pending_count(pd->tx_dma, pd->tx_chan)) {
411		dev_kfree_skb_irq(pd->tx_skb[(pd->tx_skb_o++) % S6_NUM_TX_SKB]);
412	}
413	if (!s6dmac_fifo_full(pd->tx_dma, pd->tx_chan))
414		netif_wake_queue(dev);
415}
416
417struct s6gmac_statinf {
418	unsigned reg_size : 4; /* 0: unused */
419	unsigned reg_off : 6;
420	unsigned net_index : 6;
421};
422
423#define S6_STATS_B (8 * sizeof(u32))
424#define S6_STATS_C(b, r, f) [b] = { \
425	BUILD_BUG_ON_ZERO(r##_SIZE < S6_GMAC_STAT_SIZE_MIN) + \
426	BUILD_BUG_ON_ZERO((r##_SIZE - (S6_GMAC_STAT_SIZE_MIN - 1)) \
427			>= (1<<4)) + \
428	r##_SIZE - (S6_GMAC_STAT_SIZE_MIN - 1), \
429	BUILD_BUG_ON_ZERO(((unsigned)((r - S6_GMAC_STAT_REGS) / sizeof(u32))) \
430			>= ((1<<6)-1)) + \
431	(r - S6_GMAC_STAT_REGS) / sizeof(u32), \
432	BUILD_BUG_ON_ZERO((offsetof(struct net_device_stats, f)) \
433			% sizeof(unsigned long)) + \
434	BUILD_BUG_ON_ZERO((((unsigned)(offsetof(struct net_device_stats, f)) \
435			/ sizeof(unsigned long)) >= (1<<6))) + \
436	BUILD_BUG_ON_ZERO((sizeof(((struct net_device_stats *)0)->f) \
437			!= sizeof(unsigned long))) + \
438	(offsetof(struct net_device_stats, f)) / sizeof(unsigned long)},
439
440static const struct s6gmac_statinf statinf[2][S6_STATS_B] = { {
441	S6_STATS_C(S6_GMAC_STATCARRY1_RBYT, S6_GMAC_STATRBYT, rx_bytes)
442	S6_STATS_C(S6_GMAC_STATCARRY1_RPKT, S6_GMAC_STATRPKT, rx_packets)
443	S6_STATS_C(S6_GMAC_STATCARRY1_RFCS, S6_GMAC_STATRFCS, rx_crc_errors)
444	S6_STATS_C(S6_GMAC_STATCARRY1_RMCA, S6_GMAC_STATRMCA, multicast)
445	S6_STATS_C(S6_GMAC_STATCARRY1_RALN, S6_GMAC_STATRALN, rx_frame_errors)
446	S6_STATS_C(S6_GMAC_STATCARRY1_RFLR, S6_GMAC_STATRFLR, rx_length_errors)
447	S6_STATS_C(S6_GMAC_STATCARRY1_RCDE, S6_GMAC_STATRCDE, rx_missed_errors)
448	S6_STATS_C(S6_GMAC_STATCARRY1_RUND, S6_GMAC_STATRUND, rx_length_errors)
449	S6_STATS_C(S6_GMAC_STATCARRY1_ROVR, S6_GMAC_STATROVR, rx_length_errors)
450	S6_STATS_C(S6_GMAC_STATCARRY1_RFRG, S6_GMAC_STATRFRG, rx_crc_errors)
451	S6_STATS_C(S6_GMAC_STATCARRY1_RJBR, S6_GMAC_STATRJBR, rx_crc_errors)
452	S6_STATS_C(S6_GMAC_STATCARRY1_RDRP, S6_GMAC_STATRDRP, rx_dropped)
453}, {
454	S6_STATS_C(S6_GMAC_STATCARRY2_TBYT, S6_GMAC_STATTBYT, tx_bytes)
455	S6_STATS_C(S6_GMAC_STATCARRY2_TPKT, S6_GMAC_STATTPKT, tx_packets)
456	S6_STATS_C(S6_GMAC_STATCARRY2_TEDF, S6_GMAC_STATTEDF, tx_aborted_errors)
457	S6_STATS_C(S6_GMAC_STATCARRY2_TXCL, S6_GMAC_STATTXCL, tx_aborted_errors)
458	S6_STATS_C(S6_GMAC_STATCARRY2_TNCL, S6_GMAC_STATTNCL, collisions)
459	S6_STATS_C(S6_GMAC_STATCARRY2_TDRP, S6_GMAC_STATTDRP, tx_dropped)
460	S6_STATS_C(S6_GMAC_STATCARRY2_TJBR, S6_GMAC_STATTJBR, tx_errors)
461	S6_STATS_C(S6_GMAC_STATCARRY2_TFCS, S6_GMAC_STATTFCS, tx_errors)
462	S6_STATS_C(S6_GMAC_STATCARRY2_TOVR, S6_GMAC_STATTOVR, tx_errors)
463	S6_STATS_C(S6_GMAC_STATCARRY2_TUND, S6_GMAC_STATTUND, tx_errors)
464	S6_STATS_C(S6_GMAC_STATCARRY2_TFRG, S6_GMAC_STATTFRG, tx_errors)
465} };
466
467static void s6gmac_stats_collect(struct s6gmac *pd,
468		const struct s6gmac_statinf *inf)
469{
470	int b;
471	for (b = 0; b < S6_STATS_B; b++) {
472		if (inf[b].reg_size) {
473			pd->stats[inf[b].net_index] +=
474				readl(pd->reg + S6_GMAC_STAT_REGS
475					+ sizeof(u32) * inf[b].reg_off);
476		}
477	}
478}
479
480static void s6gmac_stats_carry(struct s6gmac *pd,
481		const struct s6gmac_statinf *inf, u32 mask)
482{
483	int b;
484	while (mask) {
485		b = fls(mask) - 1;
486		mask &= ~(1 << b);
487		pd->carry[inf[b].net_index] += (1 << inf[b].reg_size);
488	}
489}
490
491static inline u32 s6gmac_stats_pending(struct s6gmac *pd, int carry)
492{
493	int r = readl(pd->reg + S6_GMAC_STATCARRY(carry)) &
494		~readl(pd->reg + S6_GMAC_STATCARRYMSK(carry));
495	return r;
496}
497
498static inline void s6gmac_stats_interrupt(struct s6gmac *pd, int carry)
499{
500	u32 mask;
501	mask = s6gmac_stats_pending(pd, carry);
502	if (mask) {
503		writel(mask, pd->reg + S6_GMAC_STATCARRY(carry));
504		s6gmac_stats_carry(pd, &statinf[carry][0], mask);
505	}
506}
507
508static irqreturn_t s6gmac_interrupt(int irq, void *dev_id)
509{
510	struct net_device *dev = (struct net_device *)dev_id;
511	struct s6gmac *pd = netdev_priv(dev);
512	if (!dev)
513		return IRQ_NONE;
514	spin_lock(&pd->lock);
515	if (s6dmac_termcnt_irq(pd->rx_dma, pd->rx_chan))
516		s6gmac_rx_interrupt(dev);
517	s6gmac_rx_fillfifo(pd);
518	if (s6dmac_termcnt_irq(pd->tx_dma, pd->tx_chan))
519		s6gmac_tx_interrupt(dev);
520	s6gmac_stats_interrupt(pd, 0);
521	s6gmac_stats_interrupt(pd, 1);
522	spin_unlock(&pd->lock);
523	return IRQ_HANDLED;
524}
525
526static inline void s6gmac_set_dstaddr(struct s6gmac *pd, int n,
527	u32 addrlo, u32 addrhi, u32 masklo, u32 maskhi)
528{
529	writel(addrlo, pd->reg + S6_GMAC_HOST_DSTADDRLO(n));
530	writel(addrhi, pd->reg + S6_GMAC_HOST_DSTADDRHI(n));
531	writel(masklo, pd->reg + S6_GMAC_HOST_DSTMASKLO(n));
532	writel(maskhi, pd->reg + S6_GMAC_HOST_DSTMASKHI(n));
533}
534
535static inline void s6gmac_stop_device(struct net_device *dev)
536{
537	struct s6gmac *pd = netdev_priv(dev);
538	writel(0, pd->reg + S6_GMAC_MACCONF1);
539}
540
541static inline void s6gmac_init_device(struct net_device *dev)
542{
543	struct s6gmac *pd = netdev_priv(dev);
544	int is_rgmii = !!(pd->phydev->supported
545		& (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half));
546	writel(1 << S6_GMAC_MACCONF1_SOFTRES, pd->reg + S6_GMAC_MACCONF1);
547	udelay(1000);
548	writel(1 << S6_GMAC_MACCONF1_TXENA | 1 << S6_GMAC_MACCONF1_RXENA,
549		pd->reg + S6_GMAC_MACCONF1);
550	writel(1 << S6_GMAC_HOST_PBLKCTRL_TXSRES |
551		1 << S6_GMAC_HOST_PBLKCTRL_RXSRES,
552		pd->reg + S6_GMAC_HOST_PBLKCTRL);
553	writel(S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_TXBSIZ |
554		S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_RXBSIZ |
555		1 << S6_GMAC_HOST_PBLKCTRL_STATENA |
556		1 << S6_GMAC_HOST_PBLKCTRL_STATCLEAR |
557		is_rgmii << S6_GMAC_HOST_PBLKCTRL_RGMII,
558		pd->reg + S6_GMAC_HOST_PBLKCTRL);
559	writel(1 << S6_GMAC_MACCONF1_TXENA |
560		1 << S6_GMAC_MACCONF1_RXENA |
561		(dev->flags & IFF_LOOPBACK ? 1 : 0)
562			<< S6_GMAC_MACCONF1_LOOPBACK,
563		pd->reg + S6_GMAC_MACCONF1);
564	writel(dev->mtu && (dev->mtu < (S6_MAX_FRLEN - ETH_HLEN-ETH_FCS_LEN)) ?
565			dev->mtu+ETH_HLEN+ETH_FCS_LEN : S6_MAX_FRLEN,
566		pd->reg + S6_GMAC_MACMAXFRAMELEN);
567	writel((pd->link.full ? 1 : 0) << S6_GMAC_MACCONF2_FULL |
568		1 << S6_GMAC_MACCONF2_PADCRCENA |
569		1 << S6_GMAC_MACCONF2_LENGTHFCHK |
570		(pd->link.giga ?
571			S6_GMAC_MACCONF2_IFMODE_BYTE :
572			S6_GMAC_MACCONF2_IFMODE_NIBBLE)
573			<< S6_GMAC_MACCONF2_IFMODE |
574		7 << S6_GMAC_MACCONF2_PREAMBLELEN,
575		pd->reg + S6_GMAC_MACCONF2);
576	writel(0, pd->reg + S6_GMAC_MACSTATADDR1);
577	writel(0, pd->reg + S6_GMAC_MACSTATADDR2);
578	writel(1 << S6_GMAC_FIFOCONF0_WTMENREQ |
579		1 << S6_GMAC_FIFOCONF0_SRFENREQ |
580		1 << S6_GMAC_FIFOCONF0_FRFENREQ |
581		1 << S6_GMAC_FIFOCONF0_STFENREQ |
582		1 << S6_GMAC_FIFOCONF0_FTFENREQ,
583		pd->reg + S6_GMAC_FIFOCONF0);
584	writel(128 << S6_GMAC_FIFOCONF3_CFGFTTH |
585		128 << S6_GMAC_FIFOCONF3_CFGHWMFT,
586		pd->reg + S6_GMAC_FIFOCONF3);
587	writel((S6_GMAC_FIFOCONF_RSV_MASK & ~(
588			1 << S6_GMAC_FIFOCONF_RSV_RUNT |
589			1 << S6_GMAC_FIFOCONF_RSV_CRCERR |
590			1 << S6_GMAC_FIFOCONF_RSV_OK |
591			1 << S6_GMAC_FIFOCONF_RSV_DRIBBLE |
592			1 << S6_GMAC_FIFOCONF_RSV_CTRLFRAME |
593			1 << S6_GMAC_FIFOCONF_RSV_PAUSECTRL |
594			1 << S6_GMAC_FIFOCONF_RSV_UNOPCODE |
595			1 << S6_GMAC_FIFOCONF_RSV_TRUNCATED)) |
596		1 << S6_GMAC_FIFOCONF5_DROPLT64 |
597		pd->link.giga << S6_GMAC_FIFOCONF5_CFGBYTM |
598		1 << S6_GMAC_FIFOCONF5_RXDROPSIZE,
599		pd->reg + S6_GMAC_FIFOCONF5);
600	writel(1 << S6_GMAC_FIFOCONF_RSV_RUNT |
601		1 << S6_GMAC_FIFOCONF_RSV_CRCERR |
602		1 << S6_GMAC_FIFOCONF_RSV_DRIBBLE |
603		1 << S6_GMAC_FIFOCONF_RSV_CTRLFRAME |
604		1 << S6_GMAC_FIFOCONF_RSV_PAUSECTRL |
605		1 << S6_GMAC_FIFOCONF_RSV_UNOPCODE |
606		1 << S6_GMAC_FIFOCONF_RSV_TRUNCATED,
607		pd->reg + S6_GMAC_FIFOCONF4);
608	s6gmac_set_dstaddr(pd, 0,
609		0xFFFFFFFF, 0x0000FFFF, 0xFFFFFFFF, 0x0000FFFF);
610	s6gmac_set_dstaddr(pd, 1,
611		dev->dev_addr[5] |
612		dev->dev_addr[4] << 8 |
613		dev->dev_addr[3] << 16 |
614		dev->dev_addr[2] << 24,
615		dev->dev_addr[1] |
616		dev->dev_addr[0] << 8,
617		0xFFFFFFFF, 0x0000FFFF);
618	s6gmac_set_dstaddr(pd, 2,
619		0x00000000, 0x00000100, 0x00000000, 0x00000100);
620	s6gmac_set_dstaddr(pd, 3,
621		0x00000000, 0x00000000, 0x00000000, 0x00000000);
622	writel(1 << S6_GMAC_HOST_PBLKCTRL_TXENA |
623		1 << S6_GMAC_HOST_PBLKCTRL_RXENA |
624		S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_TXBSIZ |
625		S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_RXBSIZ |
626		1 << S6_GMAC_HOST_PBLKCTRL_STATENA |
627		1 << S6_GMAC_HOST_PBLKCTRL_STATCLEAR |
628		is_rgmii << S6_GMAC_HOST_PBLKCTRL_RGMII,
629		pd->reg + S6_GMAC_HOST_PBLKCTRL);
630}
631
632static void s6mii_enable(struct s6gmac *pd)
633{
634	writel(readl(pd->reg + S6_GMAC_MACCONF1) &
635		~(1 << S6_GMAC_MACCONF1_SOFTRES),
636		pd->reg + S6_GMAC_MACCONF1);
637	writel((readl(pd->reg + S6_GMAC_MACMIICONF)
638		& ~(S6_GMAC_MACMIICONF_CSEL_MASK << S6_GMAC_MACMIICONF_CSEL))
639		| (S6_GMAC_MACMIICONF_CSEL_DIV168 << S6_GMAC_MACMIICONF_CSEL),
640		pd->reg + S6_GMAC_MACMIICONF);
641}
642
643static int s6mii_busy(struct s6gmac *pd, int tmo)
644{
645	while (readl(pd->reg + S6_GMAC_MACMIIINDI)) {
646		if (--tmo == 0)
647			return -ETIME;
648		udelay(64);
649	}
650	return 0;
651}
652
653static int s6mii_read(struct mii_bus *bus, int phy_addr, int regnum)
654{
655	struct s6gmac *pd = bus->priv;
656	s6mii_enable(pd);
657	if (s6mii_busy(pd, 256))
658		return -ETIME;
659	writel(phy_addr << S6_GMAC_MACMIIADDR_PHY |
660		regnum << S6_GMAC_MACMIIADDR_REG,
661		pd->reg + S6_GMAC_MACMIIADDR);
662	writel(1 << S6_GMAC_MACMIICMD_READ, pd->reg + S6_GMAC_MACMIICMD);
663	writel(0, pd->reg + S6_GMAC_MACMIICMD);
664	if (s6mii_busy(pd, 256))
665		return -ETIME;
666	return (u16)readl(pd->reg + S6_GMAC_MACMIISTAT);
667}
668
669static int s6mii_write(struct mii_bus *bus, int phy_addr, int regnum, u16 value)
670{
671	struct s6gmac *pd = bus->priv;
672	s6mii_enable(pd);
673	if (s6mii_busy(pd, 256))
674		return -ETIME;
675	writel(phy_addr << S6_GMAC_MACMIIADDR_PHY |
676		regnum << S6_GMAC_MACMIIADDR_REG,
677		pd->reg + S6_GMAC_MACMIIADDR);
678	writel(value, pd->reg + S6_GMAC_MACMIICTRL);
679	if (s6mii_busy(pd, 256))
680		return -ETIME;
681	return 0;
682}
683
684static int s6mii_reset(struct mii_bus *bus)
685{
686	struct s6gmac *pd = bus->priv;
687	s6mii_enable(pd);
688	if (s6mii_busy(pd, PHY_INIT_TIMEOUT))
689		return -ETIME;
690	return 0;
691}
692
693static void s6gmac_set_rgmii_txclock(struct s6gmac *pd)
694{
695	u32 pllsel = readl(S6_REG_GREG1 + S6_GREG1_PLLSEL);
696	pllsel &= ~(S6_GREG1_PLLSEL_GMAC_MASK << S6_GREG1_PLLSEL_GMAC);
697	switch (pd->link.mbit) {
698	case 10:
699		pllsel |= S6_GREG1_PLLSEL_GMAC_2500KHZ << S6_GREG1_PLLSEL_GMAC;
700		break;
701	case 100:
702		pllsel |= S6_GREG1_PLLSEL_GMAC_25MHZ << S6_GREG1_PLLSEL_GMAC;
703		break;
704	case 1000:
705		pllsel |= S6_GREG1_PLLSEL_GMAC_125MHZ << S6_GREG1_PLLSEL_GMAC;
706		break;
707	default:
708		return;
709	}
710	writel(pllsel, S6_REG_GREG1 + S6_GREG1_PLLSEL);
711}
712
713static inline void s6gmac_linkisup(struct net_device *dev, int isup)
714{
715	struct s6gmac *pd = netdev_priv(dev);
716	struct phy_device *phydev = pd->phydev;
717
718	pd->link.full = phydev->duplex;
719	pd->link.giga = (phydev->speed == 1000);
720	if (pd->link.mbit != phydev->speed) {
721		pd->link.mbit = phydev->speed;
722		s6gmac_set_rgmii_txclock(pd);
723	}
724	pd->link.isup = isup;
725	if (isup)
726		netif_carrier_on(dev);
727	phy_print_status(phydev);
728}
729
730static void s6gmac_adjust_link(struct net_device *dev)
731{
732	struct s6gmac *pd = netdev_priv(dev);
733	struct phy_device *phydev = pd->phydev;
734	if (pd->link.isup &&
735			(!phydev->link ||
736			(pd->link.mbit != phydev->speed) ||
737			(pd->link.full != phydev->duplex))) {
738		pd->link.isup = 0;
739		netif_tx_disable(dev);
740		if (!phydev->link) {
741			netif_carrier_off(dev);
742			phy_print_status(phydev);
743		}
744	}
745	if (!pd->link.isup && phydev->link) {
746		if (pd->link.full != phydev->duplex) {
747			u32 maccfg = readl(pd->reg + S6_GMAC_MACCONF2);
748			if (phydev->duplex)
749				maccfg |= 1 << S6_GMAC_MACCONF2_FULL;
750			else
751				maccfg &= ~(1 << S6_GMAC_MACCONF2_FULL);
752			writel(maccfg, pd->reg + S6_GMAC_MACCONF2);
753		}
754
755		if (pd->link.giga != (phydev->speed == 1000)) {
756			u32 fifocfg = readl(pd->reg + S6_GMAC_FIFOCONF5);
757			u32 maccfg = readl(pd->reg + S6_GMAC_MACCONF2);
758			maccfg &= ~(S6_GMAC_MACCONF2_IFMODE_MASK
759				     << S6_GMAC_MACCONF2_IFMODE);
760			if (phydev->speed == 1000) {
761				fifocfg |= 1 << S6_GMAC_FIFOCONF5_CFGBYTM;
762				maccfg |= S6_GMAC_MACCONF2_IFMODE_BYTE
763					   << S6_GMAC_MACCONF2_IFMODE;
764			} else {
765				fifocfg &= ~(1 << S6_GMAC_FIFOCONF5_CFGBYTM);
766				maccfg |= S6_GMAC_MACCONF2_IFMODE_NIBBLE
767					   << S6_GMAC_MACCONF2_IFMODE;
768			}
769			writel(fifocfg, pd->reg + S6_GMAC_FIFOCONF5);
770			writel(maccfg, pd->reg + S6_GMAC_MACCONF2);
771		}
772
773		if (!s6dmac_fifo_full(pd->tx_dma, pd->tx_chan))
774			netif_wake_queue(dev);
775		s6gmac_linkisup(dev, 1);
776	}
777}
778
779static inline int s6gmac_phy_start(struct net_device *dev)
780{
781	struct s6gmac *pd = netdev_priv(dev);
782	int i = 0;
783	struct phy_device *p = NULL;
784	while ((i < PHY_MAX_ADDR) && (!(p = pd->mii.bus->phy_map[i])))
785		i++;
786	p = phy_connect(dev, dev_name(&p->dev), &s6gmac_adjust_link, 0,
787			PHY_INTERFACE_MODE_RGMII);
788	if (IS_ERR(p)) {
789		printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
790		return PTR_ERR(p);
791	}
792	p->supported &= PHY_GBIT_FEATURES;
793	p->advertising = p->supported;
794	pd->phydev = p;
795	return 0;
796}
797
798static inline void s6gmac_init_stats(struct net_device *dev)
799{
800	struct s6gmac *pd = netdev_priv(dev);
801	u32 mask;
802	mask =	1 << S6_GMAC_STATCARRY1_RDRP |
803		1 << S6_GMAC_STATCARRY1_RJBR |
804		1 << S6_GMAC_STATCARRY1_RFRG |
805		1 << S6_GMAC_STATCARRY1_ROVR |
806		1 << S6_GMAC_STATCARRY1_RUND |
807		1 << S6_GMAC_STATCARRY1_RCDE |
808		1 << S6_GMAC_STATCARRY1_RFLR |
809		1 << S6_GMAC_STATCARRY1_RALN |
810		1 << S6_GMAC_STATCARRY1_RMCA |
811		1 << S6_GMAC_STATCARRY1_RFCS |
812		1 << S6_GMAC_STATCARRY1_RPKT |
813		1 << S6_GMAC_STATCARRY1_RBYT;
814	writel(mask, pd->reg + S6_GMAC_STATCARRY(0));
815	writel(~mask, pd->reg + S6_GMAC_STATCARRYMSK(0));
816	mask =	1 << S6_GMAC_STATCARRY2_TDRP |
817		1 << S6_GMAC_STATCARRY2_TNCL |
818		1 << S6_GMAC_STATCARRY2_TXCL |
819		1 << S6_GMAC_STATCARRY2_TEDF |
820		1 << S6_GMAC_STATCARRY2_TPKT |
821		1 << S6_GMAC_STATCARRY2_TBYT |
822		1 << S6_GMAC_STATCARRY2_TFRG |
823		1 << S6_GMAC_STATCARRY2_TUND |
824		1 << S6_GMAC_STATCARRY2_TOVR |
825		1 << S6_GMAC_STATCARRY2_TFCS |
826		1 << S6_GMAC_STATCARRY2_TJBR;
827	writel(mask, pd->reg + S6_GMAC_STATCARRY(1));
828	writel(~mask, pd->reg + S6_GMAC_STATCARRYMSK(1));
829}
830
831static inline void s6gmac_init_dmac(struct net_device *dev)
832{
833	struct s6gmac *pd = netdev_priv(dev);
834	s6dmac_disable_chan(pd->tx_dma, pd->tx_chan);
835	s6dmac_disable_chan(pd->rx_dma, pd->rx_chan);
836	s6dmac_disable_error_irqs(pd->tx_dma, 1 << S6_HIFDMA_GMACTX);
837	s6dmac_disable_error_irqs(pd->rx_dma, 1 << S6_HIFDMA_GMACRX);
838}
839
840static int s6gmac_tx(struct sk_buff *skb, struct net_device *dev)
841{
842	struct s6gmac *pd = netdev_priv(dev);
843	unsigned long flags;
844
845	spin_lock_irqsave(&pd->lock, flags);
846	writel(skb->len << S6_GMAC_BURST_PREWR_LEN |
847		0 << S6_GMAC_BURST_PREWR_CFE |
848		1 << S6_GMAC_BURST_PREWR_PPE |
849		1 << S6_GMAC_BURST_PREWR_FCS |
850		((skb->len < ETH_ZLEN) ? 1 : 0) << S6_GMAC_BURST_PREWR_PAD,
851		pd->reg + S6_GMAC_BURST_PREWR);
852	s6dmac_put_fifo_cache(pd->tx_dma, pd->tx_chan,
853		(u32)skb->data, pd->io, skb->len);
854	if (s6dmac_fifo_full(pd->tx_dma, pd->tx_chan))
855		netif_stop_queue(dev);
856	if (((u8)(pd->tx_skb_i - pd->tx_skb_o)) >= S6_NUM_TX_SKB) {
857		printk(KERN_ERR "GMAC BUG: skb tx ring overflow [%x, %x]\n",
858			pd->tx_skb_o, pd->tx_skb_i);
859		BUG();
860	}
861	pd->tx_skb[(pd->tx_skb_i++) % S6_NUM_TX_SKB] = skb;
862	spin_unlock_irqrestore(&pd->lock, flags);
863	return 0;
864}
865
866static void s6gmac_tx_timeout(struct net_device *dev)
867{
868	struct s6gmac *pd = netdev_priv(dev);
869	unsigned long flags;
870	spin_lock_irqsave(&pd->lock, flags);
871	s6gmac_tx_interrupt(dev);
872	spin_unlock_irqrestore(&pd->lock, flags);
873}
874
875static int s6gmac_open(struct net_device *dev)
876{
877	struct s6gmac *pd = netdev_priv(dev);
878	unsigned long flags;
879	phy_read_status(pd->phydev);
880	spin_lock_irqsave(&pd->lock, flags);
881	pd->link.mbit = 0;
882	s6gmac_linkisup(dev, pd->phydev->link);
883	s6gmac_init_device(dev);
884	s6gmac_init_stats(dev);
885	s6gmac_init_dmac(dev);
886	s6gmac_rx_fillfifo(pd);
887	s6dmac_enable_chan(pd->rx_dma, pd->rx_chan,
888		2, 1, 0, 1, 0, 0, 0, 7, -1, 2, 0, 1);
889	s6dmac_enable_chan(pd->tx_dma, pd->tx_chan,
890		2, 0, 1, 0, 0, 0, 0, 7, -1, 2, 0, 1);
891	writel(0 << S6_GMAC_HOST_INT_TXBURSTOVER |
892		0 << S6_GMAC_HOST_INT_TXPREWOVER |
893		0 << S6_GMAC_HOST_INT_RXBURSTUNDER |
894		0 << S6_GMAC_HOST_INT_RXPOSTRFULL |
895		0 << S6_GMAC_HOST_INT_RXPOSTRUNDER,
896		pd->reg + S6_GMAC_HOST_INTMASK);
897	spin_unlock_irqrestore(&pd->lock, flags);
898	phy_start(pd->phydev);
899	netif_start_queue(dev);
900	return 0;
901}
902
903static int s6gmac_stop(struct net_device *dev)
904{
905	struct s6gmac *pd = netdev_priv(dev);
906	unsigned long flags;
907	netif_stop_queue(dev);
908	phy_stop(pd->phydev);
909	spin_lock_irqsave(&pd->lock, flags);
910	s6gmac_init_dmac(dev);
911	s6gmac_stop_device(dev);
912	while (pd->tx_skb_i != pd->tx_skb_o)
913		dev_kfree_skb(pd->tx_skb[(pd->tx_skb_o++) % S6_NUM_TX_SKB]);
914	while (pd->rx_skb_i != pd->rx_skb_o)
915		dev_kfree_skb(pd->rx_skb[(pd->rx_skb_o++) % S6_NUM_RX_SKB]);
916	spin_unlock_irqrestore(&pd->lock, flags);
917	return 0;
918}
919
920static struct net_device_stats *s6gmac_stats(struct net_device *dev)
921{
922	struct s6gmac *pd = netdev_priv(dev);
923	struct net_device_stats *st = (struct net_device_stats *)&pd->stats;
924	int i;
925	do {
926		unsigned long flags;
927		spin_lock_irqsave(&pd->lock, flags);
928		for (i = 0; i < sizeof(pd->stats) / sizeof(unsigned long); i++)
929			pd->stats[i] =
930				pd->carry[i] << (S6_GMAC_STAT_SIZE_MIN - 1);
931		s6gmac_stats_collect(pd, &statinf[0][0]);
932		s6gmac_stats_collect(pd, &statinf[1][0]);
933		i = s6gmac_stats_pending(pd, 0) |
934			s6gmac_stats_pending(pd, 1);
935		spin_unlock_irqrestore(&pd->lock, flags);
936	} while (i);
937	st->rx_errors = st->rx_crc_errors +
938			st->rx_frame_errors +
939			st->rx_length_errors +
940			st->rx_missed_errors;
941	st->tx_errors += st->tx_aborted_errors;
942	return st;
943}
944
945static int __devinit s6gmac_probe(struct platform_device *pdev)
946{
947	struct net_device *dev;
948	struct s6gmac *pd;
949	int res;
950	unsigned long i;
951	struct mii_bus *mb;
952	dev = alloc_etherdev(sizeof(*pd));
953	if (!dev) {
954		printk(KERN_ERR DRV_PRMT "etherdev alloc failed, aborting.\n");
955		return -ENOMEM;
956	}
957	dev->open = s6gmac_open;
958	dev->stop = s6gmac_stop;
959	dev->hard_start_xmit = s6gmac_tx;
960	dev->tx_timeout = s6gmac_tx_timeout;
961	dev->watchdog_timeo = HZ;
962	dev->get_stats = s6gmac_stats;
963	dev->irq = platform_get_irq(pdev, 0);
964	pd = netdev_priv(dev);
965	memset(pd, 0, sizeof(*pd));
966	spin_lock_init(&pd->lock);
967	pd->reg = platform_get_resource(pdev, IORESOURCE_MEM, 0)->start;
968	i = platform_get_resource(pdev, IORESOURCE_DMA, 0)->start;
969	pd->tx_dma = DMA_MASK_DMAC(i);
970	pd->tx_chan = DMA_INDEX_CHNL(i);
971	i = platform_get_resource(pdev, IORESOURCE_DMA, 1)->start;
972	pd->rx_dma = DMA_MASK_DMAC(i);
973	pd->rx_chan = DMA_INDEX_CHNL(i);
974	pd->io = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
975	res = request_irq(dev->irq, s6gmac_interrupt, 0, dev->name, dev);
976	if (res) {
977		printk(KERN_ERR DRV_PRMT "irq request failed: %d\n", dev->irq);
978		goto errirq;
979	}
980	res = register_netdev(dev);
981	if (res) {
982		printk(KERN_ERR DRV_PRMT "error registering device %s\n",
983			dev->name);
984		goto errdev;
985	}
986	mb = mdiobus_alloc();
987	if (!mb) {
988		printk(KERN_ERR DRV_PRMT "error allocating mii bus\n");
989		goto errmii;
990	}
991	mb->name = "s6gmac_mii";
992	mb->read = s6mii_read;
993	mb->write = s6mii_write;
994	mb->reset = s6mii_reset;
995	mb->priv = pd;
996	snprintf(mb->id, MII_BUS_ID_SIZE, "0");
997	mb->phy_mask = ~(1 << 0);
998	mb->irq = &pd->mii.irq[0];
999	for (i = 0; i < PHY_MAX_ADDR; i++) {
1000		int n = platform_get_irq(pdev, i + 1);
1001		if (n < 0)
1002			n = PHY_POLL;
1003		pd->mii.irq[i] = n;
1004	}
1005	mdiobus_register(mb);
1006	pd->mii.bus = mb;
1007	res = s6gmac_phy_start(dev);
1008	if (res)
1009		return res;
1010	platform_set_drvdata(pdev, dev);
1011	return 0;
1012errmii:
1013	unregister_netdev(dev);
1014errdev:
1015	free_irq(dev->irq, dev);
1016errirq:
1017	free_netdev(dev);
1018	return res;
1019}
1020
1021static int __devexit s6gmac_remove(struct platform_device *pdev)
1022{
1023	struct net_device *dev = platform_get_drvdata(pdev);
1024	if (dev) {
1025		struct s6gmac *pd = netdev_priv(dev);
1026		mdiobus_unregister(pd->mii.bus);
1027		unregister_netdev(dev);
1028		free_irq(dev->irq, dev);
1029		free_netdev(dev);
1030		platform_set_drvdata(pdev, NULL);
1031	}
1032	return 0;
1033}
1034
1035static struct platform_driver s6gmac_driver = {
1036	.probe = s6gmac_probe,
1037	.remove = __devexit_p(s6gmac_remove),
1038	.driver = {
1039		.name = "s6gmac",
1040		.owner = THIS_MODULE,
1041	},
1042};
1043
1044static int __init s6gmac_init(void)
1045{
1046	printk(KERN_INFO DRV_PRMT "S6 GMAC ethernet driver\n");
1047	return platform_driver_register(&s6gmac_driver);
1048}
1049
1050
1051static void __exit s6gmac_exit(void)
1052{
1053	platform_driver_unregister(&s6gmac_driver);
1054}
1055
1056module_init(s6gmac_init);
1057module_exit(s6gmac_exit);
1058
1059MODULE_LICENSE("GPL");
1060MODULE_DESCRIPTION("S6105 on chip Ethernet driver");
1061MODULE_AUTHOR("Oskar Schirmer <os@emlix.com>");
1062