1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * linux/drivers/acorn/net/ether1.c
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 1996-2000 Russell King
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Acorn ether1 driver (82586 chip) for Acorn machines
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * We basically keep two queues in the cards memory - one for transmit
10*4882a593Smuzhiyun * and one for receive. Each has a head and a tail. The head is where
11*4882a593Smuzhiyun * we/the chip adds packets to be transmitted/received, and the tail
12*4882a593Smuzhiyun * is where the transmitter has got to/where the receiver will stop.
13*4882a593Smuzhiyun * Both of these queues are circular, and since the chip is running
14*4882a593Smuzhiyun * all the time, we have to be careful when we modify the pointers etc
15*4882a593Smuzhiyun * so that the buffer memory contents is valid all the time.
16*4882a593Smuzhiyun *
17*4882a593Smuzhiyun * Change log:
18*4882a593Smuzhiyun * 1.00 RMK Released
19*4882a593Smuzhiyun * 1.01 RMK 19/03/1996 Transfers the last odd byte onto/off of the card now.
20*4882a593Smuzhiyun * 1.02 RMK 25/05/1997 Added code to restart RU if it goes not ready
21*4882a593Smuzhiyun * 1.03 RMK 14/09/1997 Cleaned up the handling of a reset during the TX interrupt.
22*4882a593Smuzhiyun * Should prevent lockup.
23*4882a593Smuzhiyun * 1.04 RMK 17/09/1997 Added more info when initialsation of chip goes wrong.
24*4882a593Smuzhiyun * TDR now only reports failure when chip reports non-zero
25*4882a593Smuzhiyun * TDR time-distance.
26*4882a593Smuzhiyun * 1.05 RMK 31/12/1997 Removed calls to dev_tint for 2.1
27*4882a593Smuzhiyun * 1.06 RMK 10/02/2000 Updated for 2.3.43
28*4882a593Smuzhiyun * 1.07 RMK 13/05/2000 Updated for 2.3.99-pre8
29*4882a593Smuzhiyun */
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #include <linux/module.h>
32*4882a593Smuzhiyun #include <linux/kernel.h>
33*4882a593Smuzhiyun #include <linux/types.h>
34*4882a593Smuzhiyun #include <linux/fcntl.h>
35*4882a593Smuzhiyun #include <linux/interrupt.h>
36*4882a593Smuzhiyun #include <linux/ioport.h>
37*4882a593Smuzhiyun #include <linux/in.h>
38*4882a593Smuzhiyun #include <linux/slab.h>
39*4882a593Smuzhiyun #include <linux/string.h>
40*4882a593Smuzhiyun #include <linux/errno.h>
41*4882a593Smuzhiyun #include <linux/device.h>
42*4882a593Smuzhiyun #include <linux/init.h>
43*4882a593Smuzhiyun #include <linux/netdevice.h>
44*4882a593Smuzhiyun #include <linux/etherdevice.h>
45*4882a593Smuzhiyun #include <linux/skbuff.h>
46*4882a593Smuzhiyun #include <linux/bitops.h>
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun #include <asm/io.h>
49*4882a593Smuzhiyun #include <asm/dma.h>
50*4882a593Smuzhiyun #include <asm/ecard.h>
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun #define __ETHER1_C
53*4882a593Smuzhiyun #include "ether1.h"
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun static unsigned int net_debug = NET_DEBUG;
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun #define BUFFER_SIZE 0x10000
58*4882a593Smuzhiyun #define TX_AREA_START 0x00100
59*4882a593Smuzhiyun #define TX_AREA_END 0x05000
60*4882a593Smuzhiyun #define RX_AREA_START 0x05000
61*4882a593Smuzhiyun #define RX_AREA_END 0x0fc00
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun static int ether1_open(struct net_device *dev);
64*4882a593Smuzhiyun static netdev_tx_t ether1_sendpacket(struct sk_buff *skb,
65*4882a593Smuzhiyun struct net_device *dev);
66*4882a593Smuzhiyun static irqreturn_t ether1_interrupt(int irq, void *dev_id);
67*4882a593Smuzhiyun static int ether1_close(struct net_device *dev);
68*4882a593Smuzhiyun static void ether1_setmulticastlist(struct net_device *dev);
69*4882a593Smuzhiyun static void ether1_timeout(struct net_device *dev, unsigned int txqueue);
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun static char version[] = "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun #define BUS_16 16
76*4882a593Smuzhiyun #define BUS_8 8
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun #define DISABLEIRQS 1
81*4882a593Smuzhiyun #define NORMALIRQS 0
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun #define ether1_readw(dev, addr, type, offset, svflgs) ether1_inw_p (dev, addr + (int)(&((type *)0)->offset), svflgs)
84*4882a593Smuzhiyun #define ether1_writew(dev, val, addr, type, offset, svflgs) ether1_outw_p (dev, val, addr + (int)(&((type *)0)->offset), svflgs)
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun static inline unsigned short
ether1_inw_p(struct net_device * dev,int addr,int svflgs)87*4882a593Smuzhiyun ether1_inw_p (struct net_device *dev, int addr, int svflgs)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun unsigned long flags;
90*4882a593Smuzhiyun unsigned short ret;
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun if (svflgs)
93*4882a593Smuzhiyun local_irq_save (flags);
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun writeb(addr >> 12, REG_PAGE);
96*4882a593Smuzhiyun ret = readw(ETHER1_RAM + ((addr & 4095) << 1));
97*4882a593Smuzhiyun if (svflgs)
98*4882a593Smuzhiyun local_irq_restore (flags);
99*4882a593Smuzhiyun return ret;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun static inline void
ether1_outw_p(struct net_device * dev,unsigned short val,int addr,int svflgs)103*4882a593Smuzhiyun ether1_outw_p (struct net_device *dev, unsigned short val, int addr, int svflgs)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun unsigned long flags;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun if (svflgs)
108*4882a593Smuzhiyun local_irq_save (flags);
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun writeb(addr >> 12, REG_PAGE);
111*4882a593Smuzhiyun writew(val, ETHER1_RAM + ((addr & 4095) << 1));
112*4882a593Smuzhiyun if (svflgs)
113*4882a593Smuzhiyun local_irq_restore (flags);
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun /*
117*4882a593Smuzhiyun * Some inline assembler to allow fast transfers on to/off of the card.
118*4882a593Smuzhiyun * Since this driver depends on some features presented by the ARM
119*4882a593Smuzhiyun * specific architecture, and that you can't configure this driver
120*4882a593Smuzhiyun * without specifiing ARM mode, this is not a problem.
121*4882a593Smuzhiyun *
122*4882a593Smuzhiyun * This routine is essentially an optimised memcpy from the card's
123*4882a593Smuzhiyun * onboard RAM to kernel memory.
124*4882a593Smuzhiyun */
125*4882a593Smuzhiyun static void
ether1_writebuffer(struct net_device * dev,void * data,unsigned int start,unsigned int length)126*4882a593Smuzhiyun ether1_writebuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun unsigned int page, thislen, offset;
129*4882a593Smuzhiyun void __iomem *addr;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun offset = start & 4095;
132*4882a593Smuzhiyun page = start >> 12;
133*4882a593Smuzhiyun addr = ETHER1_RAM + (offset << 1);
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun if (offset + length > 4096)
136*4882a593Smuzhiyun thislen = 4096 - offset;
137*4882a593Smuzhiyun else
138*4882a593Smuzhiyun thislen = length;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun do {
141*4882a593Smuzhiyun int used;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun writeb(page, REG_PAGE);
144*4882a593Smuzhiyun length -= thislen;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun __asm__ __volatile__(
147*4882a593Smuzhiyun "subs %3, %3, #2\n\
148*4882a593Smuzhiyun bmi 2f\n\
149*4882a593Smuzhiyun 1: ldr %0, [%1], #2\n\
150*4882a593Smuzhiyun mov %0, %0, lsl #16\n\
151*4882a593Smuzhiyun orr %0, %0, %0, lsr #16\n\
152*4882a593Smuzhiyun str %0, [%2], #4\n\
153*4882a593Smuzhiyun subs %3, %3, #2\n\
154*4882a593Smuzhiyun bmi 2f\n\
155*4882a593Smuzhiyun ldr %0, [%1], #2\n\
156*4882a593Smuzhiyun mov %0, %0, lsl #16\n\
157*4882a593Smuzhiyun orr %0, %0, %0, lsr #16\n\
158*4882a593Smuzhiyun str %0, [%2], #4\n\
159*4882a593Smuzhiyun subs %3, %3, #2\n\
160*4882a593Smuzhiyun bmi 2f\n\
161*4882a593Smuzhiyun ldr %0, [%1], #2\n\
162*4882a593Smuzhiyun mov %0, %0, lsl #16\n\
163*4882a593Smuzhiyun orr %0, %0, %0, lsr #16\n\
164*4882a593Smuzhiyun str %0, [%2], #4\n\
165*4882a593Smuzhiyun subs %3, %3, #2\n\
166*4882a593Smuzhiyun bmi 2f\n\
167*4882a593Smuzhiyun ldr %0, [%1], #2\n\
168*4882a593Smuzhiyun mov %0, %0, lsl #16\n\
169*4882a593Smuzhiyun orr %0, %0, %0, lsr #16\n\
170*4882a593Smuzhiyun str %0, [%2], #4\n\
171*4882a593Smuzhiyun subs %3, %3, #2\n\
172*4882a593Smuzhiyun bpl 1b\n\
173*4882a593Smuzhiyun 2: adds %3, %3, #1\n\
174*4882a593Smuzhiyun ldreqb %0, [%1]\n\
175*4882a593Smuzhiyun streqb %0, [%2]"
176*4882a593Smuzhiyun : "=&r" (used), "=&r" (data)
177*4882a593Smuzhiyun : "r" (addr), "r" (thislen), "1" (data));
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun addr = ETHER1_RAM;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun thislen = length;
182*4882a593Smuzhiyun if (thislen > 4096)
183*4882a593Smuzhiyun thislen = 4096;
184*4882a593Smuzhiyun page++;
185*4882a593Smuzhiyun } while (thislen);
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun static void
ether1_readbuffer(struct net_device * dev,void * data,unsigned int start,unsigned int length)189*4882a593Smuzhiyun ether1_readbuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun unsigned int page, thislen, offset;
192*4882a593Smuzhiyun void __iomem *addr;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun offset = start & 4095;
195*4882a593Smuzhiyun page = start >> 12;
196*4882a593Smuzhiyun addr = ETHER1_RAM + (offset << 1);
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun if (offset + length > 4096)
199*4882a593Smuzhiyun thislen = 4096 - offset;
200*4882a593Smuzhiyun else
201*4882a593Smuzhiyun thislen = length;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun do {
204*4882a593Smuzhiyun int used;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun writeb(page, REG_PAGE);
207*4882a593Smuzhiyun length -= thislen;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun __asm__ __volatile__(
210*4882a593Smuzhiyun "subs %3, %3, #2\n\
211*4882a593Smuzhiyun bmi 2f\n\
212*4882a593Smuzhiyun 1: ldr %0, [%2], #4\n\
213*4882a593Smuzhiyun strb %0, [%1], #1\n\
214*4882a593Smuzhiyun mov %0, %0, lsr #8\n\
215*4882a593Smuzhiyun strb %0, [%1], #1\n\
216*4882a593Smuzhiyun subs %3, %3, #2\n\
217*4882a593Smuzhiyun bmi 2f\n\
218*4882a593Smuzhiyun ldr %0, [%2], #4\n\
219*4882a593Smuzhiyun strb %0, [%1], #1\n\
220*4882a593Smuzhiyun mov %0, %0, lsr #8\n\
221*4882a593Smuzhiyun strb %0, [%1], #1\n\
222*4882a593Smuzhiyun subs %3, %3, #2\n\
223*4882a593Smuzhiyun bmi 2f\n\
224*4882a593Smuzhiyun ldr %0, [%2], #4\n\
225*4882a593Smuzhiyun strb %0, [%1], #1\n\
226*4882a593Smuzhiyun mov %0, %0, lsr #8\n\
227*4882a593Smuzhiyun strb %0, [%1], #1\n\
228*4882a593Smuzhiyun subs %3, %3, #2\n\
229*4882a593Smuzhiyun bmi 2f\n\
230*4882a593Smuzhiyun ldr %0, [%2], #4\n\
231*4882a593Smuzhiyun strb %0, [%1], #1\n\
232*4882a593Smuzhiyun mov %0, %0, lsr #8\n\
233*4882a593Smuzhiyun strb %0, [%1], #1\n\
234*4882a593Smuzhiyun subs %3, %3, #2\n\
235*4882a593Smuzhiyun bpl 1b\n\
236*4882a593Smuzhiyun 2: adds %3, %3, #1\n\
237*4882a593Smuzhiyun ldreqb %0, [%2]\n\
238*4882a593Smuzhiyun streqb %0, [%1]"
239*4882a593Smuzhiyun : "=&r" (used), "=&r" (data)
240*4882a593Smuzhiyun : "r" (addr), "r" (thislen), "1" (data));
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun addr = ETHER1_RAM;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun thislen = length;
245*4882a593Smuzhiyun if (thislen > 4096)
246*4882a593Smuzhiyun thislen = 4096;
247*4882a593Smuzhiyun page++;
248*4882a593Smuzhiyun } while (thislen);
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun static int
ether1_ramtest(struct net_device * dev,unsigned char byte)252*4882a593Smuzhiyun ether1_ramtest(struct net_device *dev, unsigned char byte)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun unsigned char *buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL);
255*4882a593Smuzhiyun int i, ret = BUFFER_SIZE;
256*4882a593Smuzhiyun int max_errors = 15;
257*4882a593Smuzhiyun int bad = -1;
258*4882a593Smuzhiyun int bad_start = 0;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun if (!buffer)
261*4882a593Smuzhiyun return 1;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun memset (buffer, byte, BUFFER_SIZE);
264*4882a593Smuzhiyun ether1_writebuffer (dev, buffer, 0, BUFFER_SIZE);
265*4882a593Smuzhiyun memset (buffer, byte ^ 0xff, BUFFER_SIZE);
266*4882a593Smuzhiyun ether1_readbuffer (dev, buffer, 0, BUFFER_SIZE);
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun for (i = 0; i < BUFFER_SIZE; i++) {
269*4882a593Smuzhiyun if (buffer[i] != byte) {
270*4882a593Smuzhiyun if (max_errors >= 0 && bad != buffer[i]) {
271*4882a593Smuzhiyun if (bad != -1)
272*4882a593Smuzhiyun printk ("\n");
273*4882a593Smuzhiyun printk (KERN_CRIT "%s: RAM failed with (%02X instead of %02X) at 0x%04X",
274*4882a593Smuzhiyun dev->name, buffer[i], byte, i);
275*4882a593Smuzhiyun ret = -ENODEV;
276*4882a593Smuzhiyun max_errors --;
277*4882a593Smuzhiyun bad = buffer[i];
278*4882a593Smuzhiyun bad_start = i;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun } else {
281*4882a593Smuzhiyun if (bad != -1) {
282*4882a593Smuzhiyun if (bad_start == i - 1)
283*4882a593Smuzhiyun printk ("\n");
284*4882a593Smuzhiyun else
285*4882a593Smuzhiyun printk (" - 0x%04X\n", i - 1);
286*4882a593Smuzhiyun bad = -1;
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun if (bad != -1)
292*4882a593Smuzhiyun printk (" - 0x%04X\n", BUFFER_SIZE);
293*4882a593Smuzhiyun kfree (buffer);
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun return ret;
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun static int
ether1_reset(struct net_device * dev)299*4882a593Smuzhiyun ether1_reset (struct net_device *dev)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun writeb(CTRL_RST|CTRL_ACK, REG_CONTROL);
302*4882a593Smuzhiyun return BUS_16;
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun static int
ether1_init_2(struct net_device * dev)306*4882a593Smuzhiyun ether1_init_2(struct net_device *dev)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun int i;
309*4882a593Smuzhiyun dev->mem_start = 0;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun i = ether1_ramtest (dev, 0x5a);
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun if (i > 0)
314*4882a593Smuzhiyun i = ether1_ramtest (dev, 0x1e);
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun if (i <= 0)
317*4882a593Smuzhiyun return -ENODEV;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun dev->mem_end = i;
320*4882a593Smuzhiyun return 0;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun /*
324*4882a593Smuzhiyun * These are the structures that are loaded into the ether RAM card to
325*4882a593Smuzhiyun * initialise the 82586
326*4882a593Smuzhiyun */
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun /* at 0x0100 */
329*4882a593Smuzhiyun #define NOP_ADDR (TX_AREA_START)
330*4882a593Smuzhiyun #define NOP_SIZE (0x06)
331*4882a593Smuzhiyun static nop_t init_nop = {
332*4882a593Smuzhiyun 0,
333*4882a593Smuzhiyun CMD_NOP,
334*4882a593Smuzhiyun NOP_ADDR
335*4882a593Smuzhiyun };
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun /* at 0x003a */
338*4882a593Smuzhiyun #define TDR_ADDR (0x003a)
339*4882a593Smuzhiyun #define TDR_SIZE (0x08)
340*4882a593Smuzhiyun static tdr_t init_tdr = {
341*4882a593Smuzhiyun 0,
342*4882a593Smuzhiyun CMD_TDR | CMD_INTR,
343*4882a593Smuzhiyun NOP_ADDR,
344*4882a593Smuzhiyun 0
345*4882a593Smuzhiyun };
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun /* at 0x002e */
348*4882a593Smuzhiyun #define MC_ADDR (0x002e)
349*4882a593Smuzhiyun #define MC_SIZE (0x0c)
350*4882a593Smuzhiyun static mc_t init_mc = {
351*4882a593Smuzhiyun 0,
352*4882a593Smuzhiyun CMD_SETMULTICAST,
353*4882a593Smuzhiyun TDR_ADDR,
354*4882a593Smuzhiyun 0,
355*4882a593Smuzhiyun { { 0, } }
356*4882a593Smuzhiyun };
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun /* at 0x0022 */
359*4882a593Smuzhiyun #define SA_ADDR (0x0022)
360*4882a593Smuzhiyun #define SA_SIZE (0x0c)
361*4882a593Smuzhiyun static sa_t init_sa = {
362*4882a593Smuzhiyun 0,
363*4882a593Smuzhiyun CMD_SETADDRESS,
364*4882a593Smuzhiyun MC_ADDR,
365*4882a593Smuzhiyun { 0, }
366*4882a593Smuzhiyun };
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun /* at 0x0010 */
369*4882a593Smuzhiyun #define CFG_ADDR (0x0010)
370*4882a593Smuzhiyun #define CFG_SIZE (0x12)
371*4882a593Smuzhiyun static cfg_t init_cfg = {
372*4882a593Smuzhiyun 0,
373*4882a593Smuzhiyun CMD_CONFIG,
374*4882a593Smuzhiyun SA_ADDR,
375*4882a593Smuzhiyun 8,
376*4882a593Smuzhiyun 8,
377*4882a593Smuzhiyun CFG8_SRDY,
378*4882a593Smuzhiyun CFG9_PREAMB8 | CFG9_ADDRLENBUF | CFG9_ADDRLEN(6),
379*4882a593Smuzhiyun 0,
380*4882a593Smuzhiyun 0x60,
381*4882a593Smuzhiyun 0,
382*4882a593Smuzhiyun CFG13_RETRY(15) | CFG13_SLOTH(2),
383*4882a593Smuzhiyun 0,
384*4882a593Smuzhiyun };
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun /* at 0x0000 */
387*4882a593Smuzhiyun #define SCB_ADDR (0x0000)
388*4882a593Smuzhiyun #define SCB_SIZE (0x10)
389*4882a593Smuzhiyun static scb_t init_scb = {
390*4882a593Smuzhiyun 0,
391*4882a593Smuzhiyun SCB_CMDACKRNR | SCB_CMDACKCNA | SCB_CMDACKFR | SCB_CMDACKCX,
392*4882a593Smuzhiyun CFG_ADDR,
393*4882a593Smuzhiyun RX_AREA_START,
394*4882a593Smuzhiyun 0,
395*4882a593Smuzhiyun 0,
396*4882a593Smuzhiyun 0,
397*4882a593Smuzhiyun 0
398*4882a593Smuzhiyun };
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun /* at 0xffee */
401*4882a593Smuzhiyun #define ISCP_ADDR (0xffee)
402*4882a593Smuzhiyun #define ISCP_SIZE (0x08)
403*4882a593Smuzhiyun static iscp_t init_iscp = {
404*4882a593Smuzhiyun 1,
405*4882a593Smuzhiyun SCB_ADDR,
406*4882a593Smuzhiyun 0x0000,
407*4882a593Smuzhiyun 0x0000
408*4882a593Smuzhiyun };
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun /* at 0xfff6 */
411*4882a593Smuzhiyun #define SCP_ADDR (0xfff6)
412*4882a593Smuzhiyun #define SCP_SIZE (0x0a)
413*4882a593Smuzhiyun static scp_t init_scp = {
414*4882a593Smuzhiyun SCP_SY_16BBUS,
415*4882a593Smuzhiyun { 0, 0 },
416*4882a593Smuzhiyun ISCP_ADDR,
417*4882a593Smuzhiyun 0
418*4882a593Smuzhiyun };
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun #define RFD_SIZE (0x16)
421*4882a593Smuzhiyun static rfd_t init_rfd = {
422*4882a593Smuzhiyun 0,
423*4882a593Smuzhiyun 0,
424*4882a593Smuzhiyun 0,
425*4882a593Smuzhiyun 0,
426*4882a593Smuzhiyun { 0, },
427*4882a593Smuzhiyun { 0, },
428*4882a593Smuzhiyun 0
429*4882a593Smuzhiyun };
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun #define RBD_SIZE (0x0a)
432*4882a593Smuzhiyun static rbd_t init_rbd = {
433*4882a593Smuzhiyun 0,
434*4882a593Smuzhiyun 0,
435*4882a593Smuzhiyun 0,
436*4882a593Smuzhiyun 0,
437*4882a593Smuzhiyun ETH_FRAME_LEN + 8
438*4882a593Smuzhiyun };
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun #define TX_SIZE (0x08)
441*4882a593Smuzhiyun #define TBD_SIZE (0x08)
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun static int
ether1_init_for_open(struct net_device * dev)444*4882a593Smuzhiyun ether1_init_for_open (struct net_device *dev)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun int i, status, addr, next, next2;
447*4882a593Smuzhiyun int failures = 0;
448*4882a593Smuzhiyun unsigned long timeout;
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun writeb(CTRL_RST|CTRL_ACK, REG_CONTROL);
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun for (i = 0; i < 6; i++)
453*4882a593Smuzhiyun init_sa.sa_addr[i] = dev->dev_addr[i];
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun /* load data structures into ether1 RAM */
456*4882a593Smuzhiyun ether1_writebuffer (dev, &init_scp, SCP_ADDR, SCP_SIZE);
457*4882a593Smuzhiyun ether1_writebuffer (dev, &init_iscp, ISCP_ADDR, ISCP_SIZE);
458*4882a593Smuzhiyun ether1_writebuffer (dev, &init_scb, SCB_ADDR, SCB_SIZE);
459*4882a593Smuzhiyun ether1_writebuffer (dev, &init_cfg, CFG_ADDR, CFG_SIZE);
460*4882a593Smuzhiyun ether1_writebuffer (dev, &init_sa, SA_ADDR, SA_SIZE);
461*4882a593Smuzhiyun ether1_writebuffer (dev, &init_mc, MC_ADDR, MC_SIZE);
462*4882a593Smuzhiyun ether1_writebuffer (dev, &init_tdr, TDR_ADDR, TDR_SIZE);
463*4882a593Smuzhiyun ether1_writebuffer (dev, &init_nop, NOP_ADDR, NOP_SIZE);
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun if (ether1_readw(dev, CFG_ADDR, cfg_t, cfg_command, NORMALIRQS) != CMD_CONFIG) {
466*4882a593Smuzhiyun printk (KERN_ERR "%s: detected either RAM fault or compiler bug\n",
467*4882a593Smuzhiyun dev->name);
468*4882a593Smuzhiyun return 1;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun /*
472*4882a593Smuzhiyun * setup circularly linked list of { rfd, rbd, buffer }, with
473*4882a593Smuzhiyun * all rfds circularly linked, rbds circularly linked.
474*4882a593Smuzhiyun * First rfd is linked to scp, first rbd is linked to first
475*4882a593Smuzhiyun * rfd. Last rbd has a suspend command.
476*4882a593Smuzhiyun */
477*4882a593Smuzhiyun addr = RX_AREA_START;
478*4882a593Smuzhiyun do {
479*4882a593Smuzhiyun next = addr + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10;
480*4882a593Smuzhiyun next2 = next + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10;
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun if (next2 >= RX_AREA_END) {
483*4882a593Smuzhiyun next = RX_AREA_START;
484*4882a593Smuzhiyun init_rfd.rfd_command = RFD_CMDEL | RFD_CMDSUSPEND;
485*4882a593Smuzhiyun priv(dev)->rx_tail = addr;
486*4882a593Smuzhiyun } else
487*4882a593Smuzhiyun init_rfd.rfd_command = 0;
488*4882a593Smuzhiyun if (addr == RX_AREA_START)
489*4882a593Smuzhiyun init_rfd.rfd_rbdoffset = addr + RFD_SIZE;
490*4882a593Smuzhiyun else
491*4882a593Smuzhiyun init_rfd.rfd_rbdoffset = 0;
492*4882a593Smuzhiyun init_rfd.rfd_link = next;
493*4882a593Smuzhiyun init_rbd.rbd_link = next + RFD_SIZE;
494*4882a593Smuzhiyun init_rbd.rbd_bufl = addr + RFD_SIZE + RBD_SIZE;
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun ether1_writebuffer (dev, &init_rfd, addr, RFD_SIZE);
497*4882a593Smuzhiyun ether1_writebuffer (dev, &init_rbd, addr + RFD_SIZE, RBD_SIZE);
498*4882a593Smuzhiyun addr = next;
499*4882a593Smuzhiyun } while (next2 < RX_AREA_END);
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun priv(dev)->tx_link = NOP_ADDR;
502*4882a593Smuzhiyun priv(dev)->tx_head = NOP_ADDR + NOP_SIZE;
503*4882a593Smuzhiyun priv(dev)->tx_tail = TDR_ADDR;
504*4882a593Smuzhiyun priv(dev)->rx_head = RX_AREA_START;
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun /* release reset & give 586 a prod */
507*4882a593Smuzhiyun priv(dev)->resetting = 1;
508*4882a593Smuzhiyun priv(dev)->initialising = 1;
509*4882a593Smuzhiyun writeb(CTRL_RST, REG_CONTROL);
510*4882a593Smuzhiyun writeb(0, REG_CONTROL);
511*4882a593Smuzhiyun writeb(CTRL_CA, REG_CONTROL);
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun /* 586 should now unset iscp.busy */
514*4882a593Smuzhiyun timeout = jiffies + HZ/2;
515*4882a593Smuzhiyun while (ether1_readw(dev, ISCP_ADDR, iscp_t, iscp_busy, DISABLEIRQS) == 1) {
516*4882a593Smuzhiyun if (time_after(jiffies, timeout)) {
517*4882a593Smuzhiyun printk (KERN_WARNING "%s: can't initialise 82586: iscp is busy\n", dev->name);
518*4882a593Smuzhiyun return 1;
519*4882a593Smuzhiyun }
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun /* check status of commands that we issued */
523*4882a593Smuzhiyun timeout += HZ/10;
524*4882a593Smuzhiyun while (((status = ether1_readw(dev, CFG_ADDR, cfg_t, cfg_status, DISABLEIRQS))
525*4882a593Smuzhiyun & STAT_COMPLETE) == 0) {
526*4882a593Smuzhiyun if (time_after(jiffies, timeout))
527*4882a593Smuzhiyun break;
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
531*4882a593Smuzhiyun printk (KERN_WARNING "%s: can't initialise 82586: config status %04X\n", dev->name, status);
532*4882a593Smuzhiyun printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
533*4882a593Smuzhiyun ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
534*4882a593Smuzhiyun ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
535*4882a593Smuzhiyun ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
536*4882a593Smuzhiyun ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
537*4882a593Smuzhiyun failures += 1;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun timeout += HZ/10;
541*4882a593Smuzhiyun while (((status = ether1_readw(dev, SA_ADDR, sa_t, sa_status, DISABLEIRQS))
542*4882a593Smuzhiyun & STAT_COMPLETE) == 0) {
543*4882a593Smuzhiyun if (time_after(jiffies, timeout))
544*4882a593Smuzhiyun break;
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
548*4882a593Smuzhiyun printk (KERN_WARNING "%s: can't initialise 82586: set address status %04X\n", dev->name, status);
549*4882a593Smuzhiyun printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
550*4882a593Smuzhiyun ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
551*4882a593Smuzhiyun ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
552*4882a593Smuzhiyun ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
553*4882a593Smuzhiyun ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
554*4882a593Smuzhiyun failures += 1;
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun timeout += HZ/10;
558*4882a593Smuzhiyun while (((status = ether1_readw(dev, MC_ADDR, mc_t, mc_status, DISABLEIRQS))
559*4882a593Smuzhiyun & STAT_COMPLETE) == 0) {
560*4882a593Smuzhiyun if (time_after(jiffies, timeout))
561*4882a593Smuzhiyun break;
562*4882a593Smuzhiyun }
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
565*4882a593Smuzhiyun printk (KERN_WARNING "%s: can't initialise 82586: set multicast status %04X\n", dev->name, status);
566*4882a593Smuzhiyun printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
567*4882a593Smuzhiyun ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
568*4882a593Smuzhiyun ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
569*4882a593Smuzhiyun ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
570*4882a593Smuzhiyun ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
571*4882a593Smuzhiyun failures += 1;
572*4882a593Smuzhiyun }
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun timeout += HZ;
575*4882a593Smuzhiyun while (((status = ether1_readw(dev, TDR_ADDR, tdr_t, tdr_status, DISABLEIRQS))
576*4882a593Smuzhiyun & STAT_COMPLETE) == 0) {
577*4882a593Smuzhiyun if (time_after(jiffies, timeout))
578*4882a593Smuzhiyun break;
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
582*4882a593Smuzhiyun printk (KERN_WARNING "%s: can't tdr (ignored)\n", dev->name);
583*4882a593Smuzhiyun printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
584*4882a593Smuzhiyun ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
585*4882a593Smuzhiyun ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
586*4882a593Smuzhiyun ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
587*4882a593Smuzhiyun ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
588*4882a593Smuzhiyun } else {
589*4882a593Smuzhiyun status = ether1_readw(dev, TDR_ADDR, tdr_t, tdr_result, DISABLEIRQS);
590*4882a593Smuzhiyun if (status & TDR_XCVRPROB)
591*4882a593Smuzhiyun printk (KERN_WARNING "%s: i/f failed tdr: transceiver problem\n", dev->name);
592*4882a593Smuzhiyun else if ((status & (TDR_SHORT|TDR_OPEN)) && (status & TDR_TIME)) {
593*4882a593Smuzhiyun #ifdef FANCY
594*4882a593Smuzhiyun printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d.%d us away\n", dev->name,
595*4882a593Smuzhiyun status & TDR_SHORT ? "short" : "open", (status & TDR_TIME) / 10,
596*4882a593Smuzhiyun (status & TDR_TIME) % 10);
597*4882a593Smuzhiyun #else
598*4882a593Smuzhiyun printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d clks away\n", dev->name,
599*4882a593Smuzhiyun status & TDR_SHORT ? "short" : "open", (status & TDR_TIME));
600*4882a593Smuzhiyun #endif
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun if (failures)
605*4882a593Smuzhiyun ether1_reset (dev);
606*4882a593Smuzhiyun return failures ? 1 : 0;
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun static int
ether1_txalloc(struct net_device * dev,int size)612*4882a593Smuzhiyun ether1_txalloc (struct net_device *dev, int size)
613*4882a593Smuzhiyun {
614*4882a593Smuzhiyun int start, tail;
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun size = (size + 1) & ~1;
617*4882a593Smuzhiyun tail = priv(dev)->tx_tail;
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun if (priv(dev)->tx_head + size > TX_AREA_END) {
620*4882a593Smuzhiyun if (tail > priv(dev)->tx_head)
621*4882a593Smuzhiyun return -1;
622*4882a593Smuzhiyun start = TX_AREA_START;
623*4882a593Smuzhiyun if (start + size > tail)
624*4882a593Smuzhiyun return -1;
625*4882a593Smuzhiyun priv(dev)->tx_head = start + size;
626*4882a593Smuzhiyun } else {
627*4882a593Smuzhiyun if (priv(dev)->tx_head < tail && (priv(dev)->tx_head + size) > tail)
628*4882a593Smuzhiyun return -1;
629*4882a593Smuzhiyun start = priv(dev)->tx_head;
630*4882a593Smuzhiyun priv(dev)->tx_head += size;
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun return start;
634*4882a593Smuzhiyun }
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun static int
ether1_open(struct net_device * dev)637*4882a593Smuzhiyun ether1_open (struct net_device *dev)
638*4882a593Smuzhiyun {
639*4882a593Smuzhiyun if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev))
640*4882a593Smuzhiyun return -EAGAIN;
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun if (ether1_init_for_open (dev)) {
643*4882a593Smuzhiyun free_irq (dev->irq, dev);
644*4882a593Smuzhiyun return -EAGAIN;
645*4882a593Smuzhiyun }
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun netif_start_queue(dev);
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun return 0;
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun static void
ether1_timeout(struct net_device * dev,unsigned int txqueue)653*4882a593Smuzhiyun ether1_timeout(struct net_device *dev, unsigned int txqueue)
654*4882a593Smuzhiyun {
655*4882a593Smuzhiyun printk(KERN_WARNING "%s: transmit timeout, network cable problem?\n",
656*4882a593Smuzhiyun dev->name);
657*4882a593Smuzhiyun printk(KERN_WARNING "%s: resetting device\n", dev->name);
658*4882a593Smuzhiyun
659*4882a593Smuzhiyun ether1_reset (dev);
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun if (ether1_init_for_open (dev))
662*4882a593Smuzhiyun printk (KERN_ERR "%s: unable to restart interface\n", dev->name);
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun dev->stats.tx_errors++;
665*4882a593Smuzhiyun netif_wake_queue(dev);
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun static netdev_tx_t
ether1_sendpacket(struct sk_buff * skb,struct net_device * dev)669*4882a593Smuzhiyun ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
670*4882a593Smuzhiyun {
671*4882a593Smuzhiyun int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr;
672*4882a593Smuzhiyun unsigned long flags;
673*4882a593Smuzhiyun tx_t tx;
674*4882a593Smuzhiyun tbd_t tbd;
675*4882a593Smuzhiyun nop_t nop;
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun if (priv(dev)->restart) {
678*4882a593Smuzhiyun printk(KERN_WARNING "%s: resetting device\n", dev->name);
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun ether1_reset(dev);
681*4882a593Smuzhiyun
682*4882a593Smuzhiyun if (ether1_init_for_open(dev))
683*4882a593Smuzhiyun printk(KERN_ERR "%s: unable to restart interface\n", dev->name);
684*4882a593Smuzhiyun else
685*4882a593Smuzhiyun priv(dev)->restart = 0;
686*4882a593Smuzhiyun }
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun if (skb->len < ETH_ZLEN) {
689*4882a593Smuzhiyun if (skb_padto(skb, ETH_ZLEN))
690*4882a593Smuzhiyun goto out;
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun /*
694*4882a593Smuzhiyun * insert packet followed by a nop
695*4882a593Smuzhiyun */
696*4882a593Smuzhiyun txaddr = ether1_txalloc (dev, TX_SIZE);
697*4882a593Smuzhiyun tbdaddr = ether1_txalloc (dev, TBD_SIZE);
698*4882a593Smuzhiyun dataddr = ether1_txalloc (dev, skb->len);
699*4882a593Smuzhiyun nopaddr = ether1_txalloc (dev, NOP_SIZE);
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun tx.tx_status = 0;
702*4882a593Smuzhiyun tx.tx_command = CMD_TX | CMD_INTR;
703*4882a593Smuzhiyun tx.tx_link = nopaddr;
704*4882a593Smuzhiyun tx.tx_tbdoffset = tbdaddr;
705*4882a593Smuzhiyun tbd.tbd_opts = TBD_EOL | skb->len;
706*4882a593Smuzhiyun tbd.tbd_link = I82586_NULL;
707*4882a593Smuzhiyun tbd.tbd_bufl = dataddr;
708*4882a593Smuzhiyun tbd.tbd_bufh = 0;
709*4882a593Smuzhiyun nop.nop_status = 0;
710*4882a593Smuzhiyun nop.nop_command = CMD_NOP;
711*4882a593Smuzhiyun nop.nop_link = nopaddr;
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun local_irq_save(flags);
714*4882a593Smuzhiyun ether1_writebuffer (dev, &tx, txaddr, TX_SIZE);
715*4882a593Smuzhiyun ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE);
716*4882a593Smuzhiyun ether1_writebuffer (dev, skb->data, dataddr, skb->len);
717*4882a593Smuzhiyun ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE);
718*4882a593Smuzhiyun tmp = priv(dev)->tx_link;
719*4882a593Smuzhiyun priv(dev)->tx_link = nopaddr;
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun /* now reset the previous nop pointer */
722*4882a593Smuzhiyun ether1_writew(dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS);
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun local_irq_restore(flags);
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun /* handle transmit */
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun /* check to see if we have room for a full sized ether frame */
729*4882a593Smuzhiyun tmp = priv(dev)->tx_head;
730*4882a593Smuzhiyun tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
731*4882a593Smuzhiyun priv(dev)->tx_head = tmp;
732*4882a593Smuzhiyun dev_kfree_skb (skb);
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun if (tst == -1)
735*4882a593Smuzhiyun netif_stop_queue(dev);
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun out:
738*4882a593Smuzhiyun return NETDEV_TX_OK;
739*4882a593Smuzhiyun }
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun static void
ether1_xmit_done(struct net_device * dev)742*4882a593Smuzhiyun ether1_xmit_done (struct net_device *dev)
743*4882a593Smuzhiyun {
744*4882a593Smuzhiyun nop_t nop;
745*4882a593Smuzhiyun int caddr, tst;
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun caddr = priv(dev)->tx_tail;
748*4882a593Smuzhiyun
749*4882a593Smuzhiyun again:
750*4882a593Smuzhiyun ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun switch (nop.nop_command & CMD_MASK) {
753*4882a593Smuzhiyun case CMD_TDR:
754*4882a593Smuzhiyun /* special case */
755*4882a593Smuzhiyun if (ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
756*4882a593Smuzhiyun != (unsigned short)I82586_NULL) {
757*4882a593Smuzhiyun ether1_writew(dev, SCB_CMDCUCSTART | SCB_CMDRXSTART, SCB_ADDR, scb_t,
758*4882a593Smuzhiyun scb_command, NORMALIRQS);
759*4882a593Smuzhiyun writeb(CTRL_CA, REG_CONTROL);
760*4882a593Smuzhiyun }
761*4882a593Smuzhiyun priv(dev)->tx_tail = NOP_ADDR;
762*4882a593Smuzhiyun return;
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun case CMD_NOP:
765*4882a593Smuzhiyun if (nop.nop_link == caddr) {
766*4882a593Smuzhiyun if (priv(dev)->initialising == 0)
767*4882a593Smuzhiyun printk (KERN_WARNING "%s: strange command complete with no tx command!\n", dev->name);
768*4882a593Smuzhiyun else
769*4882a593Smuzhiyun priv(dev)->initialising = 0;
770*4882a593Smuzhiyun return;
771*4882a593Smuzhiyun }
772*4882a593Smuzhiyun if (caddr == nop.nop_link)
773*4882a593Smuzhiyun return;
774*4882a593Smuzhiyun caddr = nop.nop_link;
775*4882a593Smuzhiyun goto again;
776*4882a593Smuzhiyun
777*4882a593Smuzhiyun case CMD_TX:
778*4882a593Smuzhiyun if (nop.nop_status & STAT_COMPLETE)
779*4882a593Smuzhiyun break;
780*4882a593Smuzhiyun printk (KERN_ERR "%s: strange command complete without completed command\n", dev->name);
781*4882a593Smuzhiyun priv(dev)->restart = 1;
782*4882a593Smuzhiyun return;
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun default:
785*4882a593Smuzhiyun printk (KERN_WARNING "%s: strange command %d complete! (offset %04X)", dev->name,
786*4882a593Smuzhiyun nop.nop_command & CMD_MASK, caddr);
787*4882a593Smuzhiyun priv(dev)->restart = 1;
788*4882a593Smuzhiyun return;
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun
791*4882a593Smuzhiyun while (nop.nop_status & STAT_COMPLETE) {
792*4882a593Smuzhiyun if (nop.nop_status & STAT_OK) {
793*4882a593Smuzhiyun dev->stats.tx_packets++;
794*4882a593Smuzhiyun dev->stats.collisions += (nop.nop_status & STAT_COLLISIONS);
795*4882a593Smuzhiyun } else {
796*4882a593Smuzhiyun dev->stats.tx_errors++;
797*4882a593Smuzhiyun
798*4882a593Smuzhiyun if (nop.nop_status & STAT_COLLAFTERTX)
799*4882a593Smuzhiyun dev->stats.collisions++;
800*4882a593Smuzhiyun if (nop.nop_status & STAT_NOCARRIER)
801*4882a593Smuzhiyun dev->stats.tx_carrier_errors++;
802*4882a593Smuzhiyun if (nop.nop_status & STAT_TXLOSTCTS)
803*4882a593Smuzhiyun printk (KERN_WARNING "%s: cts lost\n", dev->name);
804*4882a593Smuzhiyun if (nop.nop_status & STAT_TXSLOWDMA)
805*4882a593Smuzhiyun dev->stats.tx_fifo_errors++;
806*4882a593Smuzhiyun if (nop.nop_status & STAT_COLLEXCESSIVE)
807*4882a593Smuzhiyun dev->stats.collisions += 16;
808*4882a593Smuzhiyun }
809*4882a593Smuzhiyun
810*4882a593Smuzhiyun if (nop.nop_link == caddr) {
811*4882a593Smuzhiyun printk (KERN_ERR "%s: tx buffer chaining error: tx command points to itself\n", dev->name);
812*4882a593Smuzhiyun break;
813*4882a593Smuzhiyun }
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun caddr = nop.nop_link;
816*4882a593Smuzhiyun ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
817*4882a593Smuzhiyun if ((nop.nop_command & CMD_MASK) != CMD_NOP) {
818*4882a593Smuzhiyun printk (KERN_ERR "%s: tx buffer chaining error: no nop after tx command\n", dev->name);
819*4882a593Smuzhiyun break;
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun
822*4882a593Smuzhiyun if (caddr == nop.nop_link)
823*4882a593Smuzhiyun break;
824*4882a593Smuzhiyun
825*4882a593Smuzhiyun caddr = nop.nop_link;
826*4882a593Smuzhiyun ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
827*4882a593Smuzhiyun if ((nop.nop_command & CMD_MASK) != CMD_TX) {
828*4882a593Smuzhiyun printk (KERN_ERR "%s: tx buffer chaining error: no tx command after nop\n", dev->name);
829*4882a593Smuzhiyun break;
830*4882a593Smuzhiyun }
831*4882a593Smuzhiyun }
832*4882a593Smuzhiyun priv(dev)->tx_tail = caddr;
833*4882a593Smuzhiyun
834*4882a593Smuzhiyun caddr = priv(dev)->tx_head;
835*4882a593Smuzhiyun tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
836*4882a593Smuzhiyun priv(dev)->tx_head = caddr;
837*4882a593Smuzhiyun if (tst != -1)
838*4882a593Smuzhiyun netif_wake_queue(dev);
839*4882a593Smuzhiyun }
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun static void
ether1_recv_done(struct net_device * dev)842*4882a593Smuzhiyun ether1_recv_done (struct net_device *dev)
843*4882a593Smuzhiyun {
844*4882a593Smuzhiyun int status;
845*4882a593Smuzhiyun int nexttail, rbdaddr;
846*4882a593Smuzhiyun rbd_t rbd;
847*4882a593Smuzhiyun
848*4882a593Smuzhiyun do {
849*4882a593Smuzhiyun status = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_status, NORMALIRQS);
850*4882a593Smuzhiyun if ((status & RFD_COMPLETE) == 0)
851*4882a593Smuzhiyun break;
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun rbdaddr = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_rbdoffset, NORMALIRQS);
854*4882a593Smuzhiyun ether1_readbuffer (dev, &rbd, rbdaddr, RBD_SIZE);
855*4882a593Smuzhiyun
856*4882a593Smuzhiyun if ((rbd.rbd_status & (RBD_EOF | RBD_ACNTVALID)) == (RBD_EOF | RBD_ACNTVALID)) {
857*4882a593Smuzhiyun int length = rbd.rbd_status & RBD_ACNT;
858*4882a593Smuzhiyun struct sk_buff *skb;
859*4882a593Smuzhiyun
860*4882a593Smuzhiyun length = (length + 1) & ~1;
861*4882a593Smuzhiyun skb = netdev_alloc_skb(dev, length + 2);
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun if (skb) {
864*4882a593Smuzhiyun skb_reserve (skb, 2);
865*4882a593Smuzhiyun
866*4882a593Smuzhiyun ether1_readbuffer (dev, skb_put (skb, length), rbd.rbd_bufl, length);
867*4882a593Smuzhiyun
868*4882a593Smuzhiyun skb->protocol = eth_type_trans (skb, dev);
869*4882a593Smuzhiyun netif_rx (skb);
870*4882a593Smuzhiyun dev->stats.rx_packets++;
871*4882a593Smuzhiyun } else
872*4882a593Smuzhiyun dev->stats.rx_dropped++;
873*4882a593Smuzhiyun } else {
874*4882a593Smuzhiyun printk(KERN_WARNING "%s: %s\n", dev->name,
875*4882a593Smuzhiyun (rbd.rbd_status & RBD_EOF) ? "oversized packet" : "acnt not valid");
876*4882a593Smuzhiyun dev->stats.rx_dropped++;
877*4882a593Smuzhiyun }
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun nexttail = ether1_readw(dev, priv(dev)->rx_tail, rfd_t, rfd_link, NORMALIRQS);
880*4882a593Smuzhiyun /* nexttail should be rx_head */
881*4882a593Smuzhiyun if (nexttail != priv(dev)->rx_head)
882*4882a593Smuzhiyun printk(KERN_ERR "%s: receiver buffer chaining error (%04X != %04X)\n",
883*4882a593Smuzhiyun dev->name, nexttail, priv(dev)->rx_head);
884*4882a593Smuzhiyun ether1_writew(dev, RFD_CMDEL | RFD_CMDSUSPEND, nexttail, rfd_t, rfd_command, NORMALIRQS);
885*4882a593Smuzhiyun ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_command, NORMALIRQS);
886*4882a593Smuzhiyun ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_status, NORMALIRQS);
887*4882a593Smuzhiyun ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_rbdoffset, NORMALIRQS);
888*4882a593Smuzhiyun
889*4882a593Smuzhiyun priv(dev)->rx_tail = nexttail;
890*4882a593Smuzhiyun priv(dev)->rx_head = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_link, NORMALIRQS);
891*4882a593Smuzhiyun } while (1);
892*4882a593Smuzhiyun }
893*4882a593Smuzhiyun
894*4882a593Smuzhiyun static irqreturn_t
ether1_interrupt(int irq,void * dev_id)895*4882a593Smuzhiyun ether1_interrupt (int irq, void *dev_id)
896*4882a593Smuzhiyun {
897*4882a593Smuzhiyun struct net_device *dev = (struct net_device *)dev_id;
898*4882a593Smuzhiyun int status;
899*4882a593Smuzhiyun
900*4882a593Smuzhiyun status = ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS);
901*4882a593Smuzhiyun
902*4882a593Smuzhiyun if (status) {
903*4882a593Smuzhiyun ether1_writew(dev, status & (SCB_STRNR | SCB_STCNA | SCB_STFR | SCB_STCX),
904*4882a593Smuzhiyun SCB_ADDR, scb_t, scb_command, NORMALIRQS);
905*4882a593Smuzhiyun writeb(CTRL_CA | CTRL_ACK, REG_CONTROL);
906*4882a593Smuzhiyun if (status & SCB_STCX) {
907*4882a593Smuzhiyun ether1_xmit_done (dev);
908*4882a593Smuzhiyun }
909*4882a593Smuzhiyun if (status & SCB_STCNA) {
910*4882a593Smuzhiyun if (priv(dev)->resetting == 0)
911*4882a593Smuzhiyun printk (KERN_WARNING "%s: CU went not ready ???\n", dev->name);
912*4882a593Smuzhiyun else
913*4882a593Smuzhiyun priv(dev)->resetting += 1;
914*4882a593Smuzhiyun if (ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
915*4882a593Smuzhiyun != (unsigned short)I82586_NULL) {
916*4882a593Smuzhiyun ether1_writew(dev, SCB_CMDCUCSTART, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
917*4882a593Smuzhiyun writeb(CTRL_CA, REG_CONTROL);
918*4882a593Smuzhiyun }
919*4882a593Smuzhiyun if (priv(dev)->resetting == 2)
920*4882a593Smuzhiyun priv(dev)->resetting = 0;
921*4882a593Smuzhiyun }
922*4882a593Smuzhiyun if (status & SCB_STFR) {
923*4882a593Smuzhiyun ether1_recv_done (dev);
924*4882a593Smuzhiyun }
925*4882a593Smuzhiyun if (status & SCB_STRNR) {
926*4882a593Smuzhiyun if (ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS) & SCB_STRXSUSP) {
927*4882a593Smuzhiyun printk (KERN_WARNING "%s: RU went not ready: RU suspended\n", dev->name);
928*4882a593Smuzhiyun ether1_writew(dev, SCB_CMDRXRESUME, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
929*4882a593Smuzhiyun writeb(CTRL_CA, REG_CONTROL);
930*4882a593Smuzhiyun dev->stats.rx_dropped++; /* we suspended due to lack of buffer space */
931*4882a593Smuzhiyun } else
932*4882a593Smuzhiyun printk(KERN_WARNING "%s: RU went not ready: %04X\n", dev->name,
933*4882a593Smuzhiyun ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS));
934*4882a593Smuzhiyun printk (KERN_WARNING "RU ptr = %04X\n", ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset,
935*4882a593Smuzhiyun NORMALIRQS));
936*4882a593Smuzhiyun }
937*4882a593Smuzhiyun } else
938*4882a593Smuzhiyun writeb(CTRL_ACK, REG_CONTROL);
939*4882a593Smuzhiyun
940*4882a593Smuzhiyun return IRQ_HANDLED;
941*4882a593Smuzhiyun }
942*4882a593Smuzhiyun
943*4882a593Smuzhiyun static int
ether1_close(struct net_device * dev)944*4882a593Smuzhiyun ether1_close (struct net_device *dev)
945*4882a593Smuzhiyun {
946*4882a593Smuzhiyun ether1_reset (dev);
947*4882a593Smuzhiyun
948*4882a593Smuzhiyun free_irq(dev->irq, dev);
949*4882a593Smuzhiyun
950*4882a593Smuzhiyun return 0;
951*4882a593Smuzhiyun }
952*4882a593Smuzhiyun
953*4882a593Smuzhiyun /*
954*4882a593Smuzhiyun * Set or clear the multicast filter for this adaptor.
955*4882a593Smuzhiyun * num_addrs == -1 Promiscuous mode, receive all packets.
956*4882a593Smuzhiyun * num_addrs == 0 Normal mode, clear multicast list.
957*4882a593Smuzhiyun * num_addrs > 0 Multicast mode, receive normal and MC packets, and do
958*4882a593Smuzhiyun * best-effort filtering.
959*4882a593Smuzhiyun */
960*4882a593Smuzhiyun static void
ether1_setmulticastlist(struct net_device * dev)961*4882a593Smuzhiyun ether1_setmulticastlist (struct net_device *dev)
962*4882a593Smuzhiyun {
963*4882a593Smuzhiyun }
964*4882a593Smuzhiyun
965*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
966*4882a593Smuzhiyun
ether1_banner(void)967*4882a593Smuzhiyun static void ether1_banner(void)
968*4882a593Smuzhiyun {
969*4882a593Smuzhiyun static unsigned int version_printed = 0;
970*4882a593Smuzhiyun
971*4882a593Smuzhiyun if (net_debug && version_printed++ == 0)
972*4882a593Smuzhiyun printk(KERN_INFO "%s", version);
973*4882a593Smuzhiyun }
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun static const struct net_device_ops ether1_netdev_ops = {
976*4882a593Smuzhiyun .ndo_open = ether1_open,
977*4882a593Smuzhiyun .ndo_stop = ether1_close,
978*4882a593Smuzhiyun .ndo_start_xmit = ether1_sendpacket,
979*4882a593Smuzhiyun .ndo_set_rx_mode = ether1_setmulticastlist,
980*4882a593Smuzhiyun .ndo_tx_timeout = ether1_timeout,
981*4882a593Smuzhiyun .ndo_validate_addr = eth_validate_addr,
982*4882a593Smuzhiyun .ndo_set_mac_address = eth_mac_addr,
983*4882a593Smuzhiyun };
984*4882a593Smuzhiyun
985*4882a593Smuzhiyun static int
ether1_probe(struct expansion_card * ec,const struct ecard_id * id)986*4882a593Smuzhiyun ether1_probe(struct expansion_card *ec, const struct ecard_id *id)
987*4882a593Smuzhiyun {
988*4882a593Smuzhiyun struct net_device *dev;
989*4882a593Smuzhiyun int i, ret = 0;
990*4882a593Smuzhiyun
991*4882a593Smuzhiyun ether1_banner();
992*4882a593Smuzhiyun
993*4882a593Smuzhiyun ret = ecard_request_resources(ec);
994*4882a593Smuzhiyun if (ret)
995*4882a593Smuzhiyun goto out;
996*4882a593Smuzhiyun
997*4882a593Smuzhiyun dev = alloc_etherdev(sizeof(struct ether1_priv));
998*4882a593Smuzhiyun if (!dev) {
999*4882a593Smuzhiyun ret = -ENOMEM;
1000*4882a593Smuzhiyun goto release;
1001*4882a593Smuzhiyun }
1002*4882a593Smuzhiyun
1003*4882a593Smuzhiyun SET_NETDEV_DEV(dev, &ec->dev);
1004*4882a593Smuzhiyun
1005*4882a593Smuzhiyun dev->irq = ec->irq;
1006*4882a593Smuzhiyun priv(dev)->base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
1007*4882a593Smuzhiyun if (!priv(dev)->base) {
1008*4882a593Smuzhiyun ret = -ENOMEM;
1009*4882a593Smuzhiyun goto free;
1010*4882a593Smuzhiyun }
1011*4882a593Smuzhiyun
1012*4882a593Smuzhiyun if ((priv(dev)->bus_type = ether1_reset(dev)) == 0) {
1013*4882a593Smuzhiyun ret = -ENODEV;
1014*4882a593Smuzhiyun goto free;
1015*4882a593Smuzhiyun }
1016*4882a593Smuzhiyun
1017*4882a593Smuzhiyun for (i = 0; i < 6; i++)
1018*4882a593Smuzhiyun dev->dev_addr[i] = readb(IDPROM_ADDRESS + (i << 2));
1019*4882a593Smuzhiyun
1020*4882a593Smuzhiyun if (ether1_init_2(dev)) {
1021*4882a593Smuzhiyun ret = -ENODEV;
1022*4882a593Smuzhiyun goto free;
1023*4882a593Smuzhiyun }
1024*4882a593Smuzhiyun
1025*4882a593Smuzhiyun dev->netdev_ops = ðer1_netdev_ops;
1026*4882a593Smuzhiyun dev->watchdog_timeo = 5 * HZ / 100;
1027*4882a593Smuzhiyun
1028*4882a593Smuzhiyun ret = register_netdev(dev);
1029*4882a593Smuzhiyun if (ret)
1030*4882a593Smuzhiyun goto free;
1031*4882a593Smuzhiyun
1032*4882a593Smuzhiyun printk(KERN_INFO "%s: ether1 in slot %d, %pM\n",
1033*4882a593Smuzhiyun dev->name, ec->slot_no, dev->dev_addr);
1034*4882a593Smuzhiyun
1035*4882a593Smuzhiyun ecard_set_drvdata(ec, dev);
1036*4882a593Smuzhiyun return 0;
1037*4882a593Smuzhiyun
1038*4882a593Smuzhiyun free:
1039*4882a593Smuzhiyun free_netdev(dev);
1040*4882a593Smuzhiyun release:
1041*4882a593Smuzhiyun ecard_release_resources(ec);
1042*4882a593Smuzhiyun out:
1043*4882a593Smuzhiyun return ret;
1044*4882a593Smuzhiyun }
1045*4882a593Smuzhiyun
ether1_remove(struct expansion_card * ec)1046*4882a593Smuzhiyun static void ether1_remove(struct expansion_card *ec)
1047*4882a593Smuzhiyun {
1048*4882a593Smuzhiyun struct net_device *dev = ecard_get_drvdata(ec);
1049*4882a593Smuzhiyun
1050*4882a593Smuzhiyun ecard_set_drvdata(ec, NULL);
1051*4882a593Smuzhiyun
1052*4882a593Smuzhiyun unregister_netdev(dev);
1053*4882a593Smuzhiyun free_netdev(dev);
1054*4882a593Smuzhiyun ecard_release_resources(ec);
1055*4882a593Smuzhiyun }
1056*4882a593Smuzhiyun
1057*4882a593Smuzhiyun static const struct ecard_id ether1_ids[] = {
1058*4882a593Smuzhiyun { MANU_ACORN, PROD_ACORN_ETHER1 },
1059*4882a593Smuzhiyun { 0xffff, 0xffff }
1060*4882a593Smuzhiyun };
1061*4882a593Smuzhiyun
1062*4882a593Smuzhiyun static struct ecard_driver ether1_driver = {
1063*4882a593Smuzhiyun .probe = ether1_probe,
1064*4882a593Smuzhiyun .remove = ether1_remove,
1065*4882a593Smuzhiyun .id_table = ether1_ids,
1066*4882a593Smuzhiyun .drv = {
1067*4882a593Smuzhiyun .name = "ether1",
1068*4882a593Smuzhiyun },
1069*4882a593Smuzhiyun };
1070*4882a593Smuzhiyun
ether1_init(void)1071*4882a593Smuzhiyun static int __init ether1_init(void)
1072*4882a593Smuzhiyun {
1073*4882a593Smuzhiyun return ecard_register_driver(ðer1_driver);
1074*4882a593Smuzhiyun }
1075*4882a593Smuzhiyun
ether1_exit(void)1076*4882a593Smuzhiyun static void __exit ether1_exit(void)
1077*4882a593Smuzhiyun {
1078*4882a593Smuzhiyun ecard_remove_driver(ðer1_driver);
1079*4882a593Smuzhiyun }
1080*4882a593Smuzhiyun
1081*4882a593Smuzhiyun module_init(ether1_init);
1082*4882a593Smuzhiyun module_exit(ether1_exit);
1083*4882a593Smuzhiyun
1084*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1085