xref: /OK3568_Linux_fs/kernel/drivers/net/ethernet/amd/am79c961a.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  linux/drivers/net/ethernet/amd/am79c961a.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  by Russell King <rmk@arm.linux.org.uk> 1995-2001.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Derived from various things including skeleton.c
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * This is a special driver for the am79c961A Lance chip used in the
10*4882a593Smuzhiyun  * Intel (formally Digital Equipment Corp) EBSA110 platform.  Please
11*4882a593Smuzhiyun  * note that this can not be built as a module (it doesn't make sense).
12*4882a593Smuzhiyun  */
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/types.h>
15*4882a593Smuzhiyun #include <linux/interrupt.h>
16*4882a593Smuzhiyun #include <linux/ioport.h>
17*4882a593Smuzhiyun #include <linux/slab.h>
18*4882a593Smuzhiyun #include <linux/string.h>
19*4882a593Smuzhiyun #include <linux/errno.h>
20*4882a593Smuzhiyun #include <linux/netdevice.h>
21*4882a593Smuzhiyun #include <linux/etherdevice.h>
22*4882a593Smuzhiyun #include <linux/delay.h>
23*4882a593Smuzhiyun #include <linux/init.h>
24*4882a593Smuzhiyun #include <linux/crc32.h>
25*4882a593Smuzhiyun #include <linux/bitops.h>
26*4882a593Smuzhiyun #include <linux/platform_device.h>
27*4882a593Smuzhiyun #include <linux/io.h>
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #include <mach/hardware.h>
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #define TX_BUFFERS 15
32*4882a593Smuzhiyun #define RX_BUFFERS 25
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #include "am79c961a.h"
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun static irqreturn_t
37*4882a593Smuzhiyun am79c961_interrupt (int irq, void *dev_id);
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun static unsigned int net_debug = NET_DEBUG;
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun static const char version[] =
42*4882a593Smuzhiyun 	"am79c961 ethernet driver (C) 1995-2001 Russell King v0.04\n";
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun /* --------------------------------------------------------------------------- */
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun #ifdef __arm__
write_rreg(u_long base,u_int reg,u_int val)47*4882a593Smuzhiyun static void write_rreg(u_long base, u_int reg, u_int val)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun 	asm volatile(
50*4882a593Smuzhiyun 	"strh	%1, [%2]	@ NET_RAP\n\t"
51*4882a593Smuzhiyun 	"strh	%0, [%2, #-4]	@ NET_RDP"
52*4882a593Smuzhiyun 	:
53*4882a593Smuzhiyun 	: "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun 
read_rreg(u_long base_addr,u_int reg)56*4882a593Smuzhiyun static inline unsigned short read_rreg(u_long base_addr, u_int reg)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	unsigned short v;
59*4882a593Smuzhiyun 	asm volatile(
60*4882a593Smuzhiyun 	"strh	%1, [%2]	@ NET_RAP\n\t"
61*4882a593Smuzhiyun 	"ldrh	%0, [%2, #-4]	@ NET_RDP"
62*4882a593Smuzhiyun 	: "=r" (v)
63*4882a593Smuzhiyun 	: "r" (reg), "r" (ISAIO_BASE + 0x0464));
64*4882a593Smuzhiyun 	return v;
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun 
write_ireg(u_long base,u_int reg,u_int val)67*4882a593Smuzhiyun static inline void write_ireg(u_long base, u_int reg, u_int val)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun 	asm volatile(
70*4882a593Smuzhiyun 	"strh	%1, [%2]	@ NET_RAP\n\t"
71*4882a593Smuzhiyun 	"strh	%0, [%2, #8]	@ NET_IDP"
72*4882a593Smuzhiyun 	:
73*4882a593Smuzhiyun 	: "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun 
read_ireg(u_long base_addr,u_int reg)76*4882a593Smuzhiyun static inline unsigned short read_ireg(u_long base_addr, u_int reg)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun 	u_short v;
79*4882a593Smuzhiyun 	asm volatile(
80*4882a593Smuzhiyun 	"strh	%1, [%2]	@ NAT_RAP\n\t"
81*4882a593Smuzhiyun 	"ldrh	%0, [%2, #8]	@ NET_IDP\n\t"
82*4882a593Smuzhiyun 	: "=r" (v)
83*4882a593Smuzhiyun 	: "r" (reg), "r" (ISAIO_BASE + 0x0464));
84*4882a593Smuzhiyun 	return v;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun #define am_writeword(dev,off,val) __raw_writew(val, ISAMEM_BASE + ((off) << 1))
88*4882a593Smuzhiyun #define am_readword(dev,off)      __raw_readw(ISAMEM_BASE + ((off) << 1))
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun static void
am_writebuffer(struct net_device * dev,u_int offset,unsigned char * buf,unsigned int length)91*4882a593Smuzhiyun am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun 	offset = ISAMEM_BASE + (offset << 1);
94*4882a593Smuzhiyun 	length = (length + 1) & ~1;
95*4882a593Smuzhiyun 	if ((int)buf & 2) {
96*4882a593Smuzhiyun 		asm volatile("strh	%2, [%0], #4"
97*4882a593Smuzhiyun 		 : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
98*4882a593Smuzhiyun 		buf += 2;
99*4882a593Smuzhiyun 		length -= 2;
100*4882a593Smuzhiyun 	}
101*4882a593Smuzhiyun 	while (length > 8) {
102*4882a593Smuzhiyun 		register unsigned int tmp asm("r2"), tmp2 asm("r3");
103*4882a593Smuzhiyun 		asm volatile(
104*4882a593Smuzhiyun 			"ldmia	%0!, {%1, %2}"
105*4882a593Smuzhiyun 			: "+r" (buf), "=&r" (tmp), "=&r" (tmp2));
106*4882a593Smuzhiyun 		length -= 8;
107*4882a593Smuzhiyun 		asm volatile(
108*4882a593Smuzhiyun 			"strh	%1, [%0], #4\n\t"
109*4882a593Smuzhiyun 			"mov	%1, %1, lsr #16\n\t"
110*4882a593Smuzhiyun 			"strh	%1, [%0], #4\n\t"
111*4882a593Smuzhiyun 			"strh	%2, [%0], #4\n\t"
112*4882a593Smuzhiyun 			"mov	%2, %2, lsr #16\n\t"
113*4882a593Smuzhiyun 			"strh	%2, [%0], #4"
114*4882a593Smuzhiyun 		: "+r" (offset), "=&r" (tmp), "=&r" (tmp2));
115*4882a593Smuzhiyun 	}
116*4882a593Smuzhiyun 	while (length > 0) {
117*4882a593Smuzhiyun 		asm volatile("strh	%2, [%0], #4"
118*4882a593Smuzhiyun 		 : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
119*4882a593Smuzhiyun 		buf += 2;
120*4882a593Smuzhiyun 		length -= 2;
121*4882a593Smuzhiyun 	}
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun static void
am_readbuffer(struct net_device * dev,u_int offset,unsigned char * buf,unsigned int length)125*4882a593Smuzhiyun am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	offset = ISAMEM_BASE + (offset << 1);
128*4882a593Smuzhiyun 	length = (length + 1) & ~1;
129*4882a593Smuzhiyun 	if ((int)buf & 2) {
130*4882a593Smuzhiyun 		unsigned int tmp;
131*4882a593Smuzhiyun 		asm volatile(
132*4882a593Smuzhiyun 			"ldrh	%2, [%0], #4\n\t"
133*4882a593Smuzhiyun 			"strb	%2, [%1], #1\n\t"
134*4882a593Smuzhiyun 			"mov	%2, %2, lsr #8\n\t"
135*4882a593Smuzhiyun 			"strb	%2, [%1], #1"
136*4882a593Smuzhiyun 		: "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf));
137*4882a593Smuzhiyun 		length -= 2;
138*4882a593Smuzhiyun 	}
139*4882a593Smuzhiyun 	while (length > 8) {
140*4882a593Smuzhiyun 		register unsigned int tmp asm("r2"), tmp2 asm("r3"), tmp3;
141*4882a593Smuzhiyun 		asm volatile(
142*4882a593Smuzhiyun 			"ldrh	%2, [%0], #4\n\t"
143*4882a593Smuzhiyun 			"ldrh	%4, [%0], #4\n\t"
144*4882a593Smuzhiyun 			"ldrh	%3, [%0], #4\n\t"
145*4882a593Smuzhiyun 			"orr	%2, %2, %4, lsl #16\n\t"
146*4882a593Smuzhiyun 			"ldrh	%4, [%0], #4\n\t"
147*4882a593Smuzhiyun 			"orr	%3, %3, %4, lsl #16\n\t"
148*4882a593Smuzhiyun 			"stmia	%1!, {%2, %3}"
149*4882a593Smuzhiyun 		: "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3)
150*4882a593Smuzhiyun 		: "0" (offset), "1" (buf));
151*4882a593Smuzhiyun 		length -= 8;
152*4882a593Smuzhiyun 	}
153*4882a593Smuzhiyun 	while (length > 0) {
154*4882a593Smuzhiyun 		unsigned int tmp;
155*4882a593Smuzhiyun 		asm volatile(
156*4882a593Smuzhiyun 			"ldrh	%2, [%0], #4\n\t"
157*4882a593Smuzhiyun 			"strb	%2, [%1], #1\n\t"
158*4882a593Smuzhiyun 			"mov	%2, %2, lsr #8\n\t"
159*4882a593Smuzhiyun 			"strb	%2, [%1], #1"
160*4882a593Smuzhiyun 		: "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf));
161*4882a593Smuzhiyun 		length -= 2;
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun #else
165*4882a593Smuzhiyun #error Not compatible
166*4882a593Smuzhiyun #endif
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun static int
am79c961_ramtest(struct net_device * dev,unsigned int val)169*4882a593Smuzhiyun am79c961_ramtest(struct net_device *dev, unsigned int val)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun 	unsigned char *buffer = kmalloc (65536, GFP_KERNEL);
172*4882a593Smuzhiyun 	int i, error = 0, errorcount = 0;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	if (!buffer)
175*4882a593Smuzhiyun 		return 0;
176*4882a593Smuzhiyun 	memset (buffer, val, 65536);
177*4882a593Smuzhiyun 	am_writebuffer(dev, 0, buffer, 65536);
178*4882a593Smuzhiyun 	memset (buffer, val ^ 255, 65536);
179*4882a593Smuzhiyun 	am_readbuffer(dev, 0, buffer, 65536);
180*4882a593Smuzhiyun 	for (i = 0; i < 65536; i++) {
181*4882a593Smuzhiyun 		if (buffer[i] != val && !error) {
182*4882a593Smuzhiyun 			printk ("%s: buffer error (%02X %02X) %05X - ", dev->name, val, buffer[i], i);
183*4882a593Smuzhiyun 			error = 1;
184*4882a593Smuzhiyun 			errorcount ++;
185*4882a593Smuzhiyun 		} else if (error && buffer[i] == val) {
186*4882a593Smuzhiyun 			printk ("%05X\n", i);
187*4882a593Smuzhiyun 			error = 0;
188*4882a593Smuzhiyun 		}
189*4882a593Smuzhiyun 	}
190*4882a593Smuzhiyun 	if (error)
191*4882a593Smuzhiyun 		printk ("10000\n");
192*4882a593Smuzhiyun 	kfree (buffer);
193*4882a593Smuzhiyun 	return errorcount;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun 
am79c961_mc_hash(char * addr,u16 * hash)196*4882a593Smuzhiyun static void am79c961_mc_hash(char *addr, u16 *hash)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun 	int idx, bit;
199*4882a593Smuzhiyun 	u32 crc;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	crc = ether_crc_le(ETH_ALEN, addr);
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	idx = crc >> 30;
204*4882a593Smuzhiyun 	bit = (crc >> 26) & 15;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	hash[idx] |= 1 << bit;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun 
am79c961_get_rx_mode(struct net_device * dev,u16 * hash)209*4882a593Smuzhiyun static unsigned int am79c961_get_rx_mode(struct net_device *dev, u16 *hash)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun 	unsigned int mode = MODE_PORT_10BT;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	if (dev->flags & IFF_PROMISC) {
214*4882a593Smuzhiyun 		mode |= MODE_PROMISC;
215*4882a593Smuzhiyun 		memset(hash, 0xff, 4 * sizeof(*hash));
216*4882a593Smuzhiyun 	} else if (dev->flags & IFF_ALLMULTI) {
217*4882a593Smuzhiyun 		memset(hash, 0xff, 4 * sizeof(*hash));
218*4882a593Smuzhiyun 	} else {
219*4882a593Smuzhiyun 		struct netdev_hw_addr *ha;
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 		memset(hash, 0, 4 * sizeof(*hash));
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 		netdev_for_each_mc_addr(ha, dev)
224*4882a593Smuzhiyun 			am79c961_mc_hash(ha->addr, hash);
225*4882a593Smuzhiyun 	}
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	return mode;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun static void
am79c961_init_for_open(struct net_device * dev)231*4882a593Smuzhiyun am79c961_init_for_open(struct net_device *dev)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
234*4882a593Smuzhiyun 	unsigned long flags;
235*4882a593Smuzhiyun 	unsigned char *p;
236*4882a593Smuzhiyun 	u_int hdr_addr, first_free_addr;
237*4882a593Smuzhiyun 	u16 multi_hash[4], mode = am79c961_get_rx_mode(dev, multi_hash);
238*4882a593Smuzhiyun 	int i;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	/*
241*4882a593Smuzhiyun 	 * Stop the chip.
242*4882a593Smuzhiyun 	 */
243*4882a593Smuzhiyun 	spin_lock_irqsave(&priv->chip_lock, flags);
244*4882a593Smuzhiyun 	write_rreg (dev->base_addr, CSR0, CSR0_BABL|CSR0_CERR|CSR0_MISS|CSR0_MERR|CSR0_TINT|CSR0_RINT|CSR0_STOP);
245*4882a593Smuzhiyun 	spin_unlock_irqrestore(&priv->chip_lock, flags);
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	write_ireg (dev->base_addr, 5, 0x00a0); /* Receive address LED */
248*4882a593Smuzhiyun 	write_ireg (dev->base_addr, 6, 0x0081); /* Collision LED */
249*4882a593Smuzhiyun 	write_ireg (dev->base_addr, 7, 0x0090); /* XMIT LED */
250*4882a593Smuzhiyun 	write_ireg (dev->base_addr, 2, 0x0000); /* MODE register selects media */
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	for (i = LADRL; i <= LADRH; i++)
253*4882a593Smuzhiyun 		write_rreg (dev->base_addr, i, multi_hash[i - LADRL]);
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2)
256*4882a593Smuzhiyun 		write_rreg (dev->base_addr, i, p[0] | (p[1] << 8));
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	write_rreg (dev->base_addr, MODE, mode);
259*4882a593Smuzhiyun 	write_rreg (dev->base_addr, POLLINT, 0);
260*4882a593Smuzhiyun 	write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS);
261*4882a593Smuzhiyun 	write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS);
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	first_free_addr = RX_BUFFERS * 8 + TX_BUFFERS * 8 + 16;
264*4882a593Smuzhiyun 	hdr_addr = 0;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	priv->rxhead = 0;
267*4882a593Smuzhiyun 	priv->rxtail = 0;
268*4882a593Smuzhiyun 	priv->rxhdr = hdr_addr;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	for (i = 0; i < RX_BUFFERS; i++) {
271*4882a593Smuzhiyun 		priv->rxbuffer[i] = first_free_addr;
272*4882a593Smuzhiyun 		am_writeword (dev, hdr_addr, first_free_addr);
273*4882a593Smuzhiyun 		am_writeword (dev, hdr_addr + 2, RMD_OWN);
274*4882a593Smuzhiyun 		am_writeword (dev, hdr_addr + 4, (-1600));
275*4882a593Smuzhiyun 		am_writeword (dev, hdr_addr + 6, 0);
276*4882a593Smuzhiyun 		first_free_addr += 1600;
277*4882a593Smuzhiyun 		hdr_addr += 8;
278*4882a593Smuzhiyun 	}
279*4882a593Smuzhiyun 	priv->txhead = 0;
280*4882a593Smuzhiyun 	priv->txtail = 0;
281*4882a593Smuzhiyun 	priv->txhdr = hdr_addr;
282*4882a593Smuzhiyun 	for (i = 0; i < TX_BUFFERS; i++) {
283*4882a593Smuzhiyun 		priv->txbuffer[i] = first_free_addr;
284*4882a593Smuzhiyun 		am_writeword (dev, hdr_addr, first_free_addr);
285*4882a593Smuzhiyun 		am_writeword (dev, hdr_addr + 2, TMD_STP|TMD_ENP);
286*4882a593Smuzhiyun 		am_writeword (dev, hdr_addr + 4, 0xf000);
287*4882a593Smuzhiyun 		am_writeword (dev, hdr_addr + 6, 0);
288*4882a593Smuzhiyun 		first_free_addr += 1600;
289*4882a593Smuzhiyun 		hdr_addr += 8;
290*4882a593Smuzhiyun 	}
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	write_rreg (dev->base_addr, BASERXL, priv->rxhdr);
293*4882a593Smuzhiyun 	write_rreg (dev->base_addr, BASERXH, 0);
294*4882a593Smuzhiyun 	write_rreg (dev->base_addr, BASETXL, priv->txhdr);
295*4882a593Smuzhiyun 	write_rreg (dev->base_addr, BASERXH, 0);
296*4882a593Smuzhiyun 	write_rreg (dev->base_addr, CSR0, CSR0_STOP);
297*4882a593Smuzhiyun 	write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM|CSR3_DXSUFLO);
298*4882a593Smuzhiyun 	write_rreg (dev->base_addr, CSR4, CSR4_APAD_XMIT|CSR4_MFCOM|CSR4_RCVCCOM|CSR4_TXSTRTM|CSR4_JABM);
299*4882a593Smuzhiyun 	write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT);
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun 
am79c961_timer(struct timer_list * t)302*4882a593Smuzhiyun static void am79c961_timer(struct timer_list *t)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun 	struct dev_priv *priv = from_timer(priv, t, timer);
305*4882a593Smuzhiyun 	struct net_device *dev = priv->dev;
306*4882a593Smuzhiyun 	unsigned int lnkstat, carrier;
307*4882a593Smuzhiyun 	unsigned long flags;
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	spin_lock_irqsave(&priv->chip_lock, flags);
310*4882a593Smuzhiyun 	lnkstat = read_ireg(dev->base_addr, ISALED0) & ISALED0_LNKST;
311*4882a593Smuzhiyun 	spin_unlock_irqrestore(&priv->chip_lock, flags);
312*4882a593Smuzhiyun 	carrier = netif_carrier_ok(dev);
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	if (lnkstat && !carrier) {
315*4882a593Smuzhiyun 		netif_carrier_on(dev);
316*4882a593Smuzhiyun 		printk("%s: link up\n", dev->name);
317*4882a593Smuzhiyun 	} else if (!lnkstat && carrier) {
318*4882a593Smuzhiyun 		netif_carrier_off(dev);
319*4882a593Smuzhiyun 		printk("%s: link down\n", dev->name);
320*4882a593Smuzhiyun 	}
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	mod_timer(&priv->timer, jiffies + msecs_to_jiffies(500));
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun /*
326*4882a593Smuzhiyun  * Open/initialize the board.
327*4882a593Smuzhiyun  */
328*4882a593Smuzhiyun static int
am79c961_open(struct net_device * dev)329*4882a593Smuzhiyun am79c961_open(struct net_device *dev)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
332*4882a593Smuzhiyun 	int ret;
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	ret = request_irq(dev->irq, am79c961_interrupt, 0, dev->name, dev);
335*4882a593Smuzhiyun 	if (ret)
336*4882a593Smuzhiyun 		return ret;
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	am79c961_init_for_open(dev);
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	netif_carrier_off(dev);
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	priv->timer.expires = jiffies;
343*4882a593Smuzhiyun 	add_timer(&priv->timer);
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	netif_start_queue(dev);
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	return 0;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun /*
351*4882a593Smuzhiyun  * The inverse routine to am79c961_open().
352*4882a593Smuzhiyun  */
353*4882a593Smuzhiyun static int
am79c961_close(struct net_device * dev)354*4882a593Smuzhiyun am79c961_close(struct net_device *dev)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
357*4882a593Smuzhiyun 	unsigned long flags;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	del_timer_sync(&priv->timer);
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	netif_stop_queue(dev);
362*4882a593Smuzhiyun 	netif_carrier_off(dev);
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	spin_lock_irqsave(&priv->chip_lock, flags);
365*4882a593Smuzhiyun 	write_rreg (dev->base_addr, CSR0, CSR0_STOP);
366*4882a593Smuzhiyun 	write_rreg (dev->base_addr, CSR3, CSR3_MASKALL);
367*4882a593Smuzhiyun 	spin_unlock_irqrestore(&priv->chip_lock, flags);
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	free_irq (dev->irq, dev);
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	return 0;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun /*
375*4882a593Smuzhiyun  * Set or clear promiscuous/multicast mode filter for this adapter.
376*4882a593Smuzhiyun  */
am79c961_setmulticastlist(struct net_device * dev)377*4882a593Smuzhiyun static void am79c961_setmulticastlist (struct net_device *dev)
378*4882a593Smuzhiyun {
379*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
380*4882a593Smuzhiyun 	unsigned long flags;
381*4882a593Smuzhiyun 	u16 multi_hash[4], mode = am79c961_get_rx_mode(dev, multi_hash);
382*4882a593Smuzhiyun 	int i, stopped;
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	spin_lock_irqsave(&priv->chip_lock, flags);
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	stopped = read_rreg(dev->base_addr, CSR0) & CSR0_STOP;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	if (!stopped) {
389*4882a593Smuzhiyun 		/*
390*4882a593Smuzhiyun 		 * Put the chip into suspend mode
391*4882a593Smuzhiyun 		 */
392*4882a593Smuzhiyun 		write_rreg(dev->base_addr, CTRL1, CTRL1_SPND);
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 		/*
395*4882a593Smuzhiyun 		 * Spin waiting for chip to report suspend mode
396*4882a593Smuzhiyun 		 */
397*4882a593Smuzhiyun 		while ((read_rreg(dev->base_addr, CTRL1) & CTRL1_SPND) == 0) {
398*4882a593Smuzhiyun 			spin_unlock_irqrestore(&priv->chip_lock, flags);
399*4882a593Smuzhiyun 			nop();
400*4882a593Smuzhiyun 			spin_lock_irqsave(&priv->chip_lock, flags);
401*4882a593Smuzhiyun 		}
402*4882a593Smuzhiyun 	}
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	/*
405*4882a593Smuzhiyun 	 * Update the multicast hash table
406*4882a593Smuzhiyun 	 */
407*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(multi_hash); i++)
408*4882a593Smuzhiyun 		write_rreg(dev->base_addr, i + LADRL, multi_hash[i]);
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	/*
411*4882a593Smuzhiyun 	 * Write the mode register
412*4882a593Smuzhiyun 	 */
413*4882a593Smuzhiyun 	write_rreg(dev->base_addr, MODE, mode);
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	if (!stopped) {
416*4882a593Smuzhiyun 		/*
417*4882a593Smuzhiyun 		 * Put the chip back into running mode
418*4882a593Smuzhiyun 		 */
419*4882a593Smuzhiyun 		write_rreg(dev->base_addr, CTRL1, 0);
420*4882a593Smuzhiyun 	}
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	spin_unlock_irqrestore(&priv->chip_lock, flags);
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun 
am79c961_timeout(struct net_device * dev,unsigned int txqueue)425*4882a593Smuzhiyun static void am79c961_timeout(struct net_device *dev, unsigned int txqueue)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun 	printk(KERN_WARNING "%s: transmit timed out, network cable problem?\n",
428*4882a593Smuzhiyun 		dev->name);
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	/*
431*4882a593Smuzhiyun 	 * ought to do some setup of the tx side here
432*4882a593Smuzhiyun 	 */
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	netif_wake_queue(dev);
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun /*
438*4882a593Smuzhiyun  * Transmit a packet
439*4882a593Smuzhiyun  */
440*4882a593Smuzhiyun static netdev_tx_t
am79c961_sendpacket(struct sk_buff * skb,struct net_device * dev)441*4882a593Smuzhiyun am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
444*4882a593Smuzhiyun 	unsigned int hdraddr, bufaddr;
445*4882a593Smuzhiyun 	unsigned int head;
446*4882a593Smuzhiyun 	unsigned long flags;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	head = priv->txhead;
449*4882a593Smuzhiyun 	hdraddr = priv->txhdr + (head << 3);
450*4882a593Smuzhiyun 	bufaddr = priv->txbuffer[head];
451*4882a593Smuzhiyun 	head += 1;
452*4882a593Smuzhiyun 	if (head >= TX_BUFFERS)
453*4882a593Smuzhiyun 		head = 0;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	am_writebuffer (dev, bufaddr, skb->data, skb->len);
456*4882a593Smuzhiyun 	am_writeword (dev, hdraddr + 4, -skb->len);
457*4882a593Smuzhiyun 	am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP);
458*4882a593Smuzhiyun 	priv->txhead = head;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	spin_lock_irqsave(&priv->chip_lock, flags);
461*4882a593Smuzhiyun 	write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA);
462*4882a593Smuzhiyun 	spin_unlock_irqrestore(&priv->chip_lock, flags);
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 	/*
465*4882a593Smuzhiyun 	 * If the next packet is owned by the ethernet device,
466*4882a593Smuzhiyun 	 * then the tx ring is full and we can't add another
467*4882a593Smuzhiyun 	 * packet.
468*4882a593Smuzhiyun 	 */
469*4882a593Smuzhiyun 	if (am_readword(dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN)
470*4882a593Smuzhiyun 		netif_stop_queue(dev);
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	dev_consume_skb_any(skb);
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	return NETDEV_TX_OK;
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun /*
478*4882a593Smuzhiyun  * If we have a good packet(s), get it/them out of the buffers.
479*4882a593Smuzhiyun  */
480*4882a593Smuzhiyun static void
am79c961_rx(struct net_device * dev,struct dev_priv * priv)481*4882a593Smuzhiyun am79c961_rx(struct net_device *dev, struct dev_priv *priv)
482*4882a593Smuzhiyun {
483*4882a593Smuzhiyun 	do {
484*4882a593Smuzhiyun 		struct sk_buff *skb;
485*4882a593Smuzhiyun 		u_int hdraddr;
486*4882a593Smuzhiyun 		u_int pktaddr;
487*4882a593Smuzhiyun 		u_int status;
488*4882a593Smuzhiyun 		int len;
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 		hdraddr = priv->rxhdr + (priv->rxtail << 3);
491*4882a593Smuzhiyun 		pktaddr = priv->rxbuffer[priv->rxtail];
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 		status = am_readword (dev, hdraddr + 2);
494*4882a593Smuzhiyun 		if (status & RMD_OWN) /* do we own it? */
495*4882a593Smuzhiyun 			break;
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun 		priv->rxtail ++;
498*4882a593Smuzhiyun 		if (priv->rxtail >= RX_BUFFERS)
499*4882a593Smuzhiyun 			priv->rxtail = 0;
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 		if ((status & (RMD_ERR|RMD_STP|RMD_ENP)) != (RMD_STP|RMD_ENP)) {
502*4882a593Smuzhiyun 			am_writeword (dev, hdraddr + 2, RMD_OWN);
503*4882a593Smuzhiyun 			dev->stats.rx_errors++;
504*4882a593Smuzhiyun 			if (status & RMD_ERR) {
505*4882a593Smuzhiyun 				if (status & RMD_FRAM)
506*4882a593Smuzhiyun 					dev->stats.rx_frame_errors++;
507*4882a593Smuzhiyun 				if (status & RMD_CRC)
508*4882a593Smuzhiyun 					dev->stats.rx_crc_errors++;
509*4882a593Smuzhiyun 			} else if (status & RMD_STP)
510*4882a593Smuzhiyun 				dev->stats.rx_length_errors++;
511*4882a593Smuzhiyun 			continue;
512*4882a593Smuzhiyun 		}
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 		len = am_readword(dev, hdraddr + 6);
515*4882a593Smuzhiyun 		skb = netdev_alloc_skb(dev, len + 2);
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 		if (skb) {
518*4882a593Smuzhiyun 			skb_reserve(skb, 2);
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 			am_readbuffer(dev, pktaddr, skb_put(skb, len), len);
521*4882a593Smuzhiyun 			am_writeword(dev, hdraddr + 2, RMD_OWN);
522*4882a593Smuzhiyun 			skb->protocol = eth_type_trans(skb, dev);
523*4882a593Smuzhiyun 			netif_rx(skb);
524*4882a593Smuzhiyun 			dev->stats.rx_bytes += len;
525*4882a593Smuzhiyun 			dev->stats.rx_packets++;
526*4882a593Smuzhiyun 		} else {
527*4882a593Smuzhiyun 			am_writeword (dev, hdraddr + 2, RMD_OWN);
528*4882a593Smuzhiyun 			dev->stats.rx_dropped++;
529*4882a593Smuzhiyun 			break;
530*4882a593Smuzhiyun 		}
531*4882a593Smuzhiyun 	} while (1);
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun /*
535*4882a593Smuzhiyun  * Update stats for the transmitted packet
536*4882a593Smuzhiyun  */
537*4882a593Smuzhiyun static void
am79c961_tx(struct net_device * dev,struct dev_priv * priv)538*4882a593Smuzhiyun am79c961_tx(struct net_device *dev, struct dev_priv *priv)
539*4882a593Smuzhiyun {
540*4882a593Smuzhiyun 	do {
541*4882a593Smuzhiyun 		short len;
542*4882a593Smuzhiyun 		u_int hdraddr;
543*4882a593Smuzhiyun 		u_int status;
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 		hdraddr = priv->txhdr + (priv->txtail << 3);
546*4882a593Smuzhiyun 		status = am_readword (dev, hdraddr + 2);
547*4882a593Smuzhiyun 		if (status & TMD_OWN)
548*4882a593Smuzhiyun 			break;
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 		priv->txtail ++;
551*4882a593Smuzhiyun 		if (priv->txtail >= TX_BUFFERS)
552*4882a593Smuzhiyun 			priv->txtail = 0;
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 		if (status & TMD_ERR) {
555*4882a593Smuzhiyun 			u_int status2;
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 			dev->stats.tx_errors++;
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun 			status2 = am_readword (dev, hdraddr + 6);
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun 			/*
562*4882a593Smuzhiyun 			 * Clear the error byte
563*4882a593Smuzhiyun 			 */
564*4882a593Smuzhiyun 			am_writeword (dev, hdraddr + 6, 0);
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 			if (status2 & TST_RTRY)
567*4882a593Smuzhiyun 				dev->stats.collisions += 16;
568*4882a593Smuzhiyun 			if (status2 & TST_LCOL)
569*4882a593Smuzhiyun 				dev->stats.tx_window_errors++;
570*4882a593Smuzhiyun 			if (status2 & TST_LCAR)
571*4882a593Smuzhiyun 				dev->stats.tx_carrier_errors++;
572*4882a593Smuzhiyun 			if (status2 & TST_UFLO)
573*4882a593Smuzhiyun 				dev->stats.tx_fifo_errors++;
574*4882a593Smuzhiyun 			continue;
575*4882a593Smuzhiyun 		}
576*4882a593Smuzhiyun 		dev->stats.tx_packets++;
577*4882a593Smuzhiyun 		len = am_readword (dev, hdraddr + 4);
578*4882a593Smuzhiyun 		dev->stats.tx_bytes += -len;
579*4882a593Smuzhiyun 	} while (priv->txtail != priv->txhead);
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	netif_wake_queue(dev);
582*4882a593Smuzhiyun }
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun static irqreturn_t
am79c961_interrupt(int irq,void * dev_id)585*4882a593Smuzhiyun am79c961_interrupt(int irq, void *dev_id)
586*4882a593Smuzhiyun {
587*4882a593Smuzhiyun 	struct net_device *dev = (struct net_device *)dev_id;
588*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
589*4882a593Smuzhiyun 	u_int status, n = 100;
590*4882a593Smuzhiyun 	int handled = 0;
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	do {
593*4882a593Smuzhiyun 		status = read_rreg(dev->base_addr, CSR0);
594*4882a593Smuzhiyun 		write_rreg(dev->base_addr, CSR0, status &
595*4882a593Smuzhiyun 			   (CSR0_IENA|CSR0_TINT|CSR0_RINT|
596*4882a593Smuzhiyun 			    CSR0_MERR|CSR0_MISS|CSR0_CERR|CSR0_BABL));
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 		if (status & CSR0_RINT) {
599*4882a593Smuzhiyun 			handled = 1;
600*4882a593Smuzhiyun 			am79c961_rx(dev, priv);
601*4882a593Smuzhiyun 		}
602*4882a593Smuzhiyun 		if (status & CSR0_TINT) {
603*4882a593Smuzhiyun 			handled = 1;
604*4882a593Smuzhiyun 			am79c961_tx(dev, priv);
605*4882a593Smuzhiyun 		}
606*4882a593Smuzhiyun 		if (status & CSR0_MISS) {
607*4882a593Smuzhiyun 			handled = 1;
608*4882a593Smuzhiyun 			dev->stats.rx_dropped++;
609*4882a593Smuzhiyun 		}
610*4882a593Smuzhiyun 		if (status & CSR0_CERR) {
611*4882a593Smuzhiyun 			handled = 1;
612*4882a593Smuzhiyun 			mod_timer(&priv->timer, jiffies);
613*4882a593Smuzhiyun 		}
614*4882a593Smuzhiyun 	} while (--n && status & (CSR0_RINT | CSR0_TINT));
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	return IRQ_RETVAL(handled);
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun #ifdef CONFIG_NET_POLL_CONTROLLER
am79c961_poll_controller(struct net_device * dev)620*4882a593Smuzhiyun static void am79c961_poll_controller(struct net_device *dev)
621*4882a593Smuzhiyun {
622*4882a593Smuzhiyun 	unsigned long flags;
623*4882a593Smuzhiyun 	local_irq_save(flags);
624*4882a593Smuzhiyun 	am79c961_interrupt(dev->irq, dev);
625*4882a593Smuzhiyun 	local_irq_restore(flags);
626*4882a593Smuzhiyun }
627*4882a593Smuzhiyun #endif
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun /*
630*4882a593Smuzhiyun  * Initialise the chip.  Note that we always expect
631*4882a593Smuzhiyun  * to be entered with interrupts enabled.
632*4882a593Smuzhiyun  */
633*4882a593Smuzhiyun static int
am79c961_hw_init(struct net_device * dev)634*4882a593Smuzhiyun am79c961_hw_init(struct net_device *dev)
635*4882a593Smuzhiyun {
636*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	spin_lock_irq(&priv->chip_lock);
639*4882a593Smuzhiyun 	write_rreg (dev->base_addr, CSR0, CSR0_STOP);
640*4882a593Smuzhiyun 	write_rreg (dev->base_addr, CSR3, CSR3_MASKALL);
641*4882a593Smuzhiyun 	spin_unlock_irq(&priv->chip_lock);
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 	am79c961_ramtest(dev, 0x66);
644*4882a593Smuzhiyun 	am79c961_ramtest(dev, 0x99);
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun 	return 0;
647*4882a593Smuzhiyun }
648*4882a593Smuzhiyun 
am79c961_banner(void)649*4882a593Smuzhiyun static void __init am79c961_banner(void)
650*4882a593Smuzhiyun {
651*4882a593Smuzhiyun 	static unsigned version_printed;
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	if (net_debug && version_printed++ == 0)
654*4882a593Smuzhiyun 		printk(KERN_INFO "%s", version);
655*4882a593Smuzhiyun }
656*4882a593Smuzhiyun static const struct net_device_ops am79c961_netdev_ops = {
657*4882a593Smuzhiyun 	.ndo_open		= am79c961_open,
658*4882a593Smuzhiyun 	.ndo_stop		= am79c961_close,
659*4882a593Smuzhiyun 	.ndo_start_xmit		= am79c961_sendpacket,
660*4882a593Smuzhiyun 	.ndo_set_rx_mode	= am79c961_setmulticastlist,
661*4882a593Smuzhiyun 	.ndo_tx_timeout		= am79c961_timeout,
662*4882a593Smuzhiyun 	.ndo_validate_addr	= eth_validate_addr,
663*4882a593Smuzhiyun 	.ndo_set_mac_address	= eth_mac_addr,
664*4882a593Smuzhiyun #ifdef CONFIG_NET_POLL_CONTROLLER
665*4882a593Smuzhiyun 	.ndo_poll_controller	= am79c961_poll_controller,
666*4882a593Smuzhiyun #endif
667*4882a593Smuzhiyun };
668*4882a593Smuzhiyun 
am79c961_probe(struct platform_device * pdev)669*4882a593Smuzhiyun static int am79c961_probe(struct platform_device *pdev)
670*4882a593Smuzhiyun {
671*4882a593Smuzhiyun 	struct resource *res;
672*4882a593Smuzhiyun 	struct net_device *dev;
673*4882a593Smuzhiyun 	struct dev_priv *priv;
674*4882a593Smuzhiyun 	int i, ret;
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
677*4882a593Smuzhiyun 	if (!res)
678*4882a593Smuzhiyun 		return -ENODEV;
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 	dev = alloc_etherdev(sizeof(struct dev_priv));
681*4882a593Smuzhiyun 	ret = -ENOMEM;
682*4882a593Smuzhiyun 	if (!dev)
683*4882a593Smuzhiyun 		goto out;
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun 	SET_NETDEV_DEV(dev, &pdev->dev);
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 	priv = netdev_priv(dev);
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun 	/*
690*4882a593Smuzhiyun 	 * Fixed address and IRQ lines here.
691*4882a593Smuzhiyun 	 * The PNP initialisation should have been
692*4882a593Smuzhiyun 	 * done by the ether bootp loader.
693*4882a593Smuzhiyun 	 */
694*4882a593Smuzhiyun 	dev->base_addr = res->start;
695*4882a593Smuzhiyun 	ret = platform_get_irq(pdev, 0);
696*4882a593Smuzhiyun 
697*4882a593Smuzhiyun 	if (ret < 0) {
698*4882a593Smuzhiyun 		ret = -ENODEV;
699*4882a593Smuzhiyun 		goto nodev;
700*4882a593Smuzhiyun 	}
701*4882a593Smuzhiyun 	dev->irq = ret;
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	ret = -ENODEV;
704*4882a593Smuzhiyun 	if (!request_region(dev->base_addr, 0x18, dev->name))
705*4882a593Smuzhiyun 		goto nodev;
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 	/*
708*4882a593Smuzhiyun 	 * Reset the device.
709*4882a593Smuzhiyun 	 */
710*4882a593Smuzhiyun 	inb(dev->base_addr + NET_RESET);
711*4882a593Smuzhiyun 	udelay(5);
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun 	/*
714*4882a593Smuzhiyun 	 * Check the manufacturer part of the
715*4882a593Smuzhiyun 	 * ether address.
716*4882a593Smuzhiyun 	 */
717*4882a593Smuzhiyun 	if (inb(dev->base_addr) != 0x08 ||
718*4882a593Smuzhiyun 	    inb(dev->base_addr + 2) != 0x00 ||
719*4882a593Smuzhiyun 	    inb(dev->base_addr + 4) != 0x2b)
720*4882a593Smuzhiyun 	    	goto release;
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun 	for (i = 0; i < 6; i++)
723*4882a593Smuzhiyun 		dev->dev_addr[i] = inb(dev->base_addr + i * 2) & 0xff;
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun 	am79c961_banner();
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	spin_lock_init(&priv->chip_lock);
728*4882a593Smuzhiyun 	priv->dev = dev;
729*4882a593Smuzhiyun 	timer_setup(&priv->timer, am79c961_timer, 0);
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	if (am79c961_hw_init(dev))
732*4882a593Smuzhiyun 		goto release;
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	dev->netdev_ops = &am79c961_netdev_ops;
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun 	ret = register_netdev(dev);
737*4882a593Smuzhiyun 	if (ret == 0) {
738*4882a593Smuzhiyun 		printk(KERN_INFO "%s: ether address %pM\n",
739*4882a593Smuzhiyun 		       dev->name, dev->dev_addr);
740*4882a593Smuzhiyun 		return 0;
741*4882a593Smuzhiyun 	}
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun release:
744*4882a593Smuzhiyun 	release_region(dev->base_addr, 0x18);
745*4882a593Smuzhiyun nodev:
746*4882a593Smuzhiyun 	free_netdev(dev);
747*4882a593Smuzhiyun out:
748*4882a593Smuzhiyun 	return ret;
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun static struct platform_driver am79c961_driver = {
752*4882a593Smuzhiyun 	.probe		= am79c961_probe,
753*4882a593Smuzhiyun 	.driver		= {
754*4882a593Smuzhiyun 		.name	= "am79c961",
755*4882a593Smuzhiyun 	},
756*4882a593Smuzhiyun };
757*4882a593Smuzhiyun 
am79c961_init(void)758*4882a593Smuzhiyun static int __init am79c961_init(void)
759*4882a593Smuzhiyun {
760*4882a593Smuzhiyun 	return platform_driver_register(&am79c961_driver);
761*4882a593Smuzhiyun }
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun __initcall(am79c961_init);
764