diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/net/arm |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/net/arm')
-rw-r--r-- | drivers/net/arm/Kconfig | 46 | ||||
-rw-r--r-- | drivers/net/arm/Makefile | 10 | ||||
-rw-r--r-- | drivers/net/arm/am79c961a.c | 750 | ||||
-rw-r--r-- | drivers/net/arm/am79c961a.h | 148 | ||||
-rw-r--r-- | drivers/net/arm/ether00.c | 1017 | ||||
-rw-r--r-- | drivers/net/arm/ether1.c | 1110 | ||||
-rw-r--r-- | drivers/net/arm/ether1.h | 281 | ||||
-rw-r--r-- | drivers/net/arm/ether3.c | 936 | ||||
-rw-r--r-- | drivers/net/arm/ether3.h | 177 | ||||
-rw-r--r-- | drivers/net/arm/etherh.c | 862 |
10 files changed, 5337 insertions, 0 deletions
diff --git a/drivers/net/arm/Kconfig b/drivers/net/arm/Kconfig new file mode 100644 index 000000000000..470364deded0 --- /dev/null +++ b/drivers/net/arm/Kconfig | |||
@@ -0,0 +1,46 @@ | |||
1 | # | ||
2 | # Acorn Network device configuration | ||
3 | # These are for Acorn's Expansion card network interfaces | ||
4 | # | ||
5 | config ARM_AM79C961A | ||
6 | bool "ARM EBSA110 AM79C961A support" | ||
7 | depends on NET_ETHERNET && ARM && ARCH_EBSA110 | ||
8 | select CRC32 | ||
9 | help | ||
10 | If you wish to compile a kernel for the EBSA-110, then you should | ||
11 | always answer Y to this. | ||
12 | |||
13 | config ARM_ETHER1 | ||
14 | tristate "Acorn Ether1 support" | ||
15 | depends on NET_ETHERNET && ARM && ARCH_ACORN | ||
16 | help | ||
17 | If you have an Acorn system with one of these (AKA25) network cards, | ||
18 | you should say Y to this option if you wish to use it with Linux. | ||
19 | |||
20 | config ARM_ETHER3 | ||
21 | tristate "Acorn/ANT Ether3 support" | ||
22 | depends on NET_ETHERNET && ARM && ARCH_ACORN | ||
23 | help | ||
24 | If you have an Acorn system with one of these network cards, you | ||
25 | should say Y to this option if you wish to use it with Linux. | ||
26 | |||
27 | config ARM_ETHERH | ||
28 | tristate "I-cubed EtherH/ANT EtherM support" | ||
29 | depends on NET_ETHERNET && ARM && ARCH_ACORN | ||
30 | select CRC32 | ||
31 | help | ||
32 | If you have an Acorn system with one of these network cards, you | ||
33 | should say Y to this option if you wish to use it with Linux. | ||
34 | |||
35 | config ARM_ETHER00 | ||
36 | tristate "Altera Ether00 support" | ||
37 | depends on NET_ETHERNET && ARM && ARCH_CAMELOT | ||
38 | help | ||
39 | This is the driver for Altera's ether00 ethernet mac IP core. Say | ||
40 | Y here if you want to build support for this into the kernel. It | ||
41 | is also available as a module (say M here) that can be inserted/ | ||
42 | removed from the kernel at the same time as the PLD is configured. | ||
43 | If this driver is running on an epxa10 development board then it | ||
44 | will generate a suitable hw address based on the board serial | ||
45 | number (MTD support is required for this). Otherwise you will | ||
46 | need to set a suitable hw address using ifconfig. | ||
diff --git a/drivers/net/arm/Makefile b/drivers/net/arm/Makefile new file mode 100644 index 000000000000..b0d706834d89 --- /dev/null +++ b/drivers/net/arm/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | # File: drivers/net/arm/Makefile | ||
2 | # | ||
3 | # Makefile for the ARM network device drivers | ||
4 | # | ||
5 | |||
6 | obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o | ||
7 | obj-$(CONFIG_ARM_ETHER00) += ether00.o | ||
8 | obj-$(CONFIG_ARM_ETHERH) += etherh.o | ||
9 | obj-$(CONFIG_ARM_ETHER3) += ether3.o | ||
10 | obj-$(CONFIG_ARM_ETHER1) += ether1.o | ||
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c new file mode 100644 index 000000000000..9b659e3c8d67 --- /dev/null +++ b/drivers/net/arm/am79c961a.c | |||
@@ -0,0 +1,750 @@ | |||
1 | /* | ||
2 | * linux/drivers/net/am79c961.c | ||
3 | * | ||
4 | * by Russell King <rmk@arm.linux.org.uk> 1995-2001. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * Derived from various things including skeleton.c | ||
11 | * | ||
12 | * This is a special driver for the am79c961A Lance chip used in the | ||
13 | * Intel (formally Digital Equipment Corp) EBSA110 platform. Please | ||
14 | * note that this can not be built as a module (it doesn't make sense). | ||
15 | */ | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <linux/fcntl.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/ioport.h> | ||
21 | #include <linux/in.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/string.h> | ||
24 | #include <linux/errno.h> | ||
25 | #include <linux/netdevice.h> | ||
26 | #include <linux/etherdevice.h> | ||
27 | #include <linux/skbuff.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/crc32.h> | ||
31 | #include <linux/bitops.h> | ||
32 | |||
33 | #include <asm/system.h> | ||
34 | #include <asm/irq.h> | ||
35 | #include <asm/io.h> | ||
36 | #include <asm/dma.h> | ||
37 | |||
38 | #define TX_BUFFERS 15 | ||
39 | #define RX_BUFFERS 25 | ||
40 | |||
41 | #include "am79c961a.h" | ||
42 | |||
43 | static irqreturn_t | ||
44 | am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs); | ||
45 | |||
46 | static unsigned int net_debug = NET_DEBUG; | ||
47 | |||
48 | static const char version[] = | ||
49 | "am79c961 ethernet driver (C) 1995-2001 Russell King v0.04\n"; | ||
50 | |||
51 | /* --------------------------------------------------------------------------- */ | ||
52 | |||
53 | #ifdef __arm__ | ||
54 | static void write_rreg(u_long base, u_int reg, u_int val) | ||
55 | { | ||
56 | __asm__( | ||
57 | "str%?h %1, [%2] @ NET_RAP\n\t" | ||
58 | "str%?h %0, [%2, #-4] @ NET_RDP" | ||
59 | : | ||
60 | : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464)); | ||
61 | } | ||
62 | |||
63 | static inline unsigned short read_rreg(u_long base_addr, u_int reg) | ||
64 | { | ||
65 | unsigned short v; | ||
66 | __asm__( | ||
67 | "str%?h %1, [%2] @ NET_RAP\n\t" | ||
68 | "ldr%?h %0, [%2, #-4] @ NET_RDP" | ||
69 | : "=r" (v) | ||
70 | : "r" (reg), "r" (ISAIO_BASE + 0x0464)); | ||
71 | return v; | ||
72 | } | ||
73 | |||
74 | static inline void write_ireg(u_long base, u_int reg, u_int val) | ||
75 | { | ||
76 | __asm__( | ||
77 | "str%?h %1, [%2] @ NET_RAP\n\t" | ||
78 | "str%?h %0, [%2, #8] @ NET_IDP" | ||
79 | : | ||
80 | : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464)); | ||
81 | } | ||
82 | |||
83 | static inline unsigned short read_ireg(u_long base_addr, u_int reg) | ||
84 | { | ||
85 | u_short v; | ||
86 | __asm__( | ||
87 | "str%?h %1, [%2] @ NAT_RAP\n\t" | ||
88 | "str%?h %0, [%2, #8] @ NET_IDP\n\t" | ||
89 | : "=r" (v) | ||
90 | : "r" (reg), "r" (ISAIO_BASE + 0x0464)); | ||
91 | return v; | ||
92 | } | ||
93 | |||
94 | #define am_writeword(dev,off,val) __raw_writew(val, ISAMEM_BASE + ((off) << 1)) | ||
95 | #define am_readword(dev,off) __raw_readw(ISAMEM_BASE + ((off) << 1)) | ||
96 | |||
97 | static inline void | ||
98 | am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length) | ||
99 | { | ||
100 | offset = ISAMEM_BASE + (offset << 1); | ||
101 | length = (length + 1) & ~1; | ||
102 | if ((int)buf & 2) { | ||
103 | __asm__ __volatile__("str%?h %2, [%0], #4" | ||
104 | : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8))); | ||
105 | buf += 2; | ||
106 | length -= 2; | ||
107 | } | ||
108 | while (length > 8) { | ||
109 | unsigned int tmp, tmp2; | ||
110 | __asm__ __volatile__( | ||
111 | "ldm%?ia %1!, {%2, %3}\n\t" | ||
112 | "str%?h %2, [%0], #4\n\t" | ||
113 | "mov%? %2, %2, lsr #16\n\t" | ||
114 | "str%?h %2, [%0], #4\n\t" | ||
115 | "str%?h %3, [%0], #4\n\t" | ||
116 | "mov%? %3, %3, lsr #16\n\t" | ||
117 | "str%?h %3, [%0], #4" | ||
118 | : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2) | ||
119 | : "0" (offset), "1" (buf)); | ||
120 | length -= 8; | ||
121 | } | ||
122 | while (length > 0) { | ||
123 | __asm__ __volatile__("str%?h %2, [%0], #4" | ||
124 | : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8))); | ||
125 | buf += 2; | ||
126 | length -= 2; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | static inline void | ||
131 | am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length) | ||
132 | { | ||
133 | offset = ISAMEM_BASE + (offset << 1); | ||
134 | length = (length + 1) & ~1; | ||
135 | if ((int)buf & 2) { | ||
136 | unsigned int tmp; | ||
137 | __asm__ __volatile__( | ||
138 | "ldr%?h %2, [%0], #4\n\t" | ||
139 | "str%?b %2, [%1], #1\n\t" | ||
140 | "mov%? %2, %2, lsr #8\n\t" | ||
141 | "str%?b %2, [%1], #1" | ||
142 | : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf)); | ||
143 | length -= 2; | ||
144 | } | ||
145 | while (length > 8) { | ||
146 | unsigned int tmp, tmp2, tmp3; | ||
147 | __asm__ __volatile__( | ||
148 | "ldr%?h %2, [%0], #4\n\t" | ||
149 | "ldr%?h %3, [%0], #4\n\t" | ||
150 | "orr%? %2, %2, %3, lsl #16\n\t" | ||
151 | "ldr%?h %3, [%0], #4\n\t" | ||
152 | "ldr%?h %4, [%0], #4\n\t" | ||
153 | "orr%? %3, %3, %4, lsl #16\n\t" | ||
154 | "stm%?ia %1!, {%2, %3}" | ||
155 | : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3) | ||
156 | : "0" (offset), "1" (buf)); | ||
157 | length -= 8; | ||
158 | } | ||
159 | while (length > 0) { | ||
160 | unsigned int tmp; | ||
161 | __asm__ __volatile__( | ||
162 | "ldr%?h %2, [%0], #4\n\t" | ||
163 | "str%?b %2, [%1], #1\n\t" | ||
164 | "mov%? %2, %2, lsr #8\n\t" | ||
165 | "str%?b %2, [%1], #1" | ||
166 | : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf)); | ||
167 | length -= 2; | ||
168 | } | ||
169 | } | ||
170 | #else | ||
171 | #error Not compatible | ||
172 | #endif | ||
173 | |||
174 | static int | ||
175 | am79c961_ramtest(struct net_device *dev, unsigned int val) | ||
176 | { | ||
177 | unsigned char *buffer = kmalloc (65536, GFP_KERNEL); | ||
178 | int i, error = 0, errorcount = 0; | ||
179 | |||
180 | if (!buffer) | ||
181 | return 0; | ||
182 | memset (buffer, val, 65536); | ||
183 | am_writebuffer(dev, 0, buffer, 65536); | ||
184 | memset (buffer, val ^ 255, 65536); | ||
185 | am_readbuffer(dev, 0, buffer, 65536); | ||
186 | for (i = 0; i < 65536; i++) { | ||
187 | if (buffer[i] != val && !error) { | ||
188 | printk ("%s: buffer error (%02X %02X) %05X - ", dev->name, val, buffer[i], i); | ||
189 | error = 1; | ||
190 | errorcount ++; | ||
191 | } else if (error && buffer[i] == val) { | ||
192 | printk ("%05X\n", i); | ||
193 | error = 0; | ||
194 | } | ||
195 | } | ||
196 | if (error) | ||
197 | printk ("10000\n"); | ||
198 | kfree (buffer); | ||
199 | return errorcount; | ||
200 | } | ||
201 | |||
202 | static void | ||
203 | am79c961_init_for_open(struct net_device *dev) | ||
204 | { | ||
205 | struct dev_priv *priv = netdev_priv(dev); | ||
206 | unsigned long flags; | ||
207 | unsigned char *p; | ||
208 | u_int hdr_addr, first_free_addr; | ||
209 | int i; | ||
210 | |||
211 | /* | ||
212 | * Stop the chip. | ||
213 | */ | ||
214 | spin_lock_irqsave(priv->chip_lock, flags); | ||
215 | write_rreg (dev->base_addr, CSR0, CSR0_BABL|CSR0_CERR|CSR0_MISS|CSR0_MERR|CSR0_TINT|CSR0_RINT|CSR0_STOP); | ||
216 | spin_unlock_irqrestore(priv->chip_lock, flags); | ||
217 | |||
218 | write_ireg (dev->base_addr, 5, 0x00a0); /* Receive address LED */ | ||
219 | write_ireg (dev->base_addr, 6, 0x0081); /* Collision LED */ | ||
220 | write_ireg (dev->base_addr, 7, 0x0090); /* XMIT LED */ | ||
221 | write_ireg (dev->base_addr, 2, 0x0000); /* MODE register selects media */ | ||
222 | |||
223 | for (i = LADRL; i <= LADRH; i++) | ||
224 | write_rreg (dev->base_addr, i, 0); | ||
225 | |||
226 | for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2) | ||
227 | write_rreg (dev->base_addr, i, p[0] | (p[1] << 8)); | ||
228 | |||
229 | i = MODE_PORT_10BT; | ||
230 | if (dev->flags & IFF_PROMISC) | ||
231 | i |= MODE_PROMISC; | ||
232 | |||
233 | write_rreg (dev->base_addr, MODE, i); | ||
234 | write_rreg (dev->base_addr, POLLINT, 0); | ||
235 | write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS); | ||
236 | write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS); | ||
237 | |||
238 | first_free_addr = RX_BUFFERS * 8 + TX_BUFFERS * 8 + 16; | ||
239 | hdr_addr = 0; | ||
240 | |||
241 | priv->rxhead = 0; | ||
242 | priv->rxtail = 0; | ||
243 | priv->rxhdr = hdr_addr; | ||
244 | |||
245 | for (i = 0; i < RX_BUFFERS; i++) { | ||
246 | priv->rxbuffer[i] = first_free_addr; | ||
247 | am_writeword (dev, hdr_addr, first_free_addr); | ||
248 | am_writeword (dev, hdr_addr + 2, RMD_OWN); | ||
249 | am_writeword (dev, hdr_addr + 4, (-1600)); | ||
250 | am_writeword (dev, hdr_addr + 6, 0); | ||
251 | first_free_addr += 1600; | ||
252 | hdr_addr += 8; | ||
253 | } | ||
254 | priv->txhead = 0; | ||
255 | priv->txtail = 0; | ||
256 | priv->txhdr = hdr_addr; | ||
257 | for (i = 0; i < TX_BUFFERS; i++) { | ||
258 | priv->txbuffer[i] = first_free_addr; | ||
259 | am_writeword (dev, hdr_addr, first_free_addr); | ||
260 | am_writeword (dev, hdr_addr + 2, TMD_STP|TMD_ENP); | ||
261 | am_writeword (dev, hdr_addr + 4, 0xf000); | ||
262 | am_writeword (dev, hdr_addr + 6, 0); | ||
263 | first_free_addr += 1600; | ||
264 | hdr_addr += 8; | ||
265 | } | ||
266 | |||
267 | write_rreg (dev->base_addr, BASERXL, priv->rxhdr); | ||
268 | write_rreg (dev->base_addr, BASERXH, 0); | ||
269 | write_rreg (dev->base_addr, BASETXL, priv->txhdr); | ||
270 | write_rreg (dev->base_addr, BASERXH, 0); | ||
271 | write_rreg (dev->base_addr, CSR0, CSR0_STOP); | ||
272 | write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM|CSR3_DXSUFLO); | ||
273 | write_rreg (dev->base_addr, CSR4, CSR4_APAD_XMIT|CSR4_MFCOM|CSR4_RCVCCOM|CSR4_TXSTRTM|CSR4_JABM); | ||
274 | write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT); | ||
275 | } | ||
276 | |||
277 | static void am79c961_timer(unsigned long data) | ||
278 | { | ||
279 | struct net_device *dev = (struct net_device *)data; | ||
280 | struct dev_priv *priv = netdev_priv(dev); | ||
281 | unsigned int lnkstat, carrier; | ||
282 | |||
283 | lnkstat = read_ireg(dev->base_addr, ISALED0) & ISALED0_LNKST; | ||
284 | carrier = netif_carrier_ok(dev); | ||
285 | |||
286 | if (lnkstat && !carrier) | ||
287 | netif_carrier_on(dev); | ||
288 | else if (!lnkstat && carrier) | ||
289 | netif_carrier_off(dev); | ||
290 | |||
291 | mod_timer(&priv->timer, jiffies + 5*HZ); | ||
292 | } | ||
293 | |||
294 | /* | ||
295 | * Open/initialize the board. | ||
296 | */ | ||
297 | static int | ||
298 | am79c961_open(struct net_device *dev) | ||
299 | { | ||
300 | struct dev_priv *priv = netdev_priv(dev); | ||
301 | int ret; | ||
302 | |||
303 | memset (&priv->stats, 0, sizeof (priv->stats)); | ||
304 | |||
305 | ret = request_irq(dev->irq, am79c961_interrupt, 0, dev->name, dev); | ||
306 | if (ret) | ||
307 | return ret; | ||
308 | |||
309 | am79c961_init_for_open(dev); | ||
310 | |||
311 | netif_carrier_off(dev); | ||
312 | |||
313 | priv->timer.expires = jiffies; | ||
314 | add_timer(&priv->timer); | ||
315 | |||
316 | netif_start_queue(dev); | ||
317 | |||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | /* | ||
322 | * The inverse routine to am79c961_open(). | ||
323 | */ | ||
324 | static int | ||
325 | am79c961_close(struct net_device *dev) | ||
326 | { | ||
327 | struct dev_priv *priv = netdev_priv(dev); | ||
328 | unsigned long flags; | ||
329 | |||
330 | del_timer_sync(&priv->timer); | ||
331 | |||
332 | netif_stop_queue(dev); | ||
333 | netif_carrier_off(dev); | ||
334 | |||
335 | spin_lock_irqsave(priv->chip_lock, flags); | ||
336 | write_rreg (dev->base_addr, CSR0, CSR0_STOP); | ||
337 | write_rreg (dev->base_addr, CSR3, CSR3_MASKALL); | ||
338 | spin_unlock_irqrestore(priv->chip_lock, flags); | ||
339 | |||
340 | free_irq (dev->irq, dev); | ||
341 | |||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | /* | ||
346 | * Get the current statistics. | ||
347 | */ | ||
348 | static struct net_device_stats *am79c961_getstats (struct net_device *dev) | ||
349 | { | ||
350 | struct dev_priv *priv = netdev_priv(dev); | ||
351 | return &priv->stats; | ||
352 | } | ||
353 | |||
354 | static void am79c961_mc_hash(struct dev_mc_list *dmi, unsigned short *hash) | ||
355 | { | ||
356 | if (dmi->dmi_addrlen == ETH_ALEN && dmi->dmi_addr[0] & 0x01) { | ||
357 | int idx, bit; | ||
358 | u32 crc; | ||
359 | |||
360 | crc = ether_crc_le(ETH_ALEN, dmi->dmi_addr); | ||
361 | |||
362 | idx = crc >> 30; | ||
363 | bit = (crc >> 26) & 15; | ||
364 | |||
365 | hash[idx] |= 1 << bit; | ||
366 | } | ||
367 | } | ||
368 | |||
369 | /* | ||
370 | * Set or clear promiscuous/multicast mode filter for this adapter. | ||
371 | */ | ||
372 | static void am79c961_setmulticastlist (struct net_device *dev) | ||
373 | { | ||
374 | struct dev_priv *priv = netdev_priv(dev); | ||
375 | unsigned long flags; | ||
376 | unsigned short multi_hash[4], mode; | ||
377 | int i, stopped; | ||
378 | |||
379 | mode = MODE_PORT_10BT; | ||
380 | |||
381 | if (dev->flags & IFF_PROMISC) { | ||
382 | mode |= MODE_PROMISC; | ||
383 | } else if (dev->flags & IFF_ALLMULTI) { | ||
384 | memset(multi_hash, 0xff, sizeof(multi_hash)); | ||
385 | } else { | ||
386 | struct dev_mc_list *dmi; | ||
387 | |||
388 | memset(multi_hash, 0x00, sizeof(multi_hash)); | ||
389 | |||
390 | for (dmi = dev->mc_list; dmi; dmi = dmi->next) | ||
391 | am79c961_mc_hash(dmi, multi_hash); | ||
392 | } | ||
393 | |||
394 | spin_lock_irqsave(priv->chip_lock, flags); | ||
395 | |||
396 | stopped = read_rreg(dev->base_addr, CSR0) & CSR0_STOP; | ||
397 | |||
398 | if (!stopped) { | ||
399 | /* | ||
400 | * Put the chip into suspend mode | ||
401 | */ | ||
402 | write_rreg(dev->base_addr, CTRL1, CTRL1_SPND); | ||
403 | |||
404 | /* | ||
405 | * Spin waiting for chip to report suspend mode | ||
406 | */ | ||
407 | while ((read_rreg(dev->base_addr, CTRL1) & CTRL1_SPND) == 0) { | ||
408 | spin_unlock_irqrestore(priv->chip_lock, flags); | ||
409 | nop(); | ||
410 | spin_lock_irqsave(priv->chip_lock, flags); | ||
411 | } | ||
412 | } | ||
413 | |||
414 | /* | ||
415 | * Update the multicast hash table | ||
416 | */ | ||
417 | for (i = 0; i < sizeof(multi_hash) / sizeof(multi_hash[0]); i++) | ||
418 | write_rreg(dev->base_addr, i + LADRL, multi_hash[i]); | ||
419 | |||
420 | /* | ||
421 | * Write the mode register | ||
422 | */ | ||
423 | write_rreg(dev->base_addr, MODE, mode); | ||
424 | |||
425 | if (!stopped) { | ||
426 | /* | ||
427 | * Put the chip back into running mode | ||
428 | */ | ||
429 | write_rreg(dev->base_addr, CTRL1, 0); | ||
430 | } | ||
431 | |||
432 | spin_unlock_irqrestore(priv->chip_lock, flags); | ||
433 | } | ||
434 | |||
435 | static void am79c961_timeout(struct net_device *dev) | ||
436 | { | ||
437 | printk(KERN_WARNING "%s: transmit timed out, network cable problem?\n", | ||
438 | dev->name); | ||
439 | |||
440 | /* | ||
441 | * ought to do some setup of the tx side here | ||
442 | */ | ||
443 | |||
444 | netif_wake_queue(dev); | ||
445 | } | ||
446 | |||
447 | /* | ||
448 | * Transmit a packet | ||
449 | */ | ||
450 | static int | ||
451 | am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev) | ||
452 | { | ||
453 | struct dev_priv *priv = netdev_priv(dev); | ||
454 | unsigned int hdraddr, bufaddr; | ||
455 | unsigned int head; | ||
456 | unsigned long flags; | ||
457 | |||
458 | head = priv->txhead; | ||
459 | hdraddr = priv->txhdr + (head << 3); | ||
460 | bufaddr = priv->txbuffer[head]; | ||
461 | head += 1; | ||
462 | if (head >= TX_BUFFERS) | ||
463 | head = 0; | ||
464 | |||
465 | am_writebuffer (dev, bufaddr, skb->data, skb->len); | ||
466 | am_writeword (dev, hdraddr + 4, -skb->len); | ||
467 | am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP); | ||
468 | priv->txhead = head; | ||
469 | |||
470 | spin_lock_irqsave(priv->chip_lock, flags); | ||
471 | write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA); | ||
472 | dev->trans_start = jiffies; | ||
473 | spin_unlock_irqrestore(priv->chip_lock, flags); | ||
474 | |||
475 | /* | ||
476 | * If the next packet is owned by the ethernet device, | ||
477 | * then the tx ring is full and we can't add another | ||
478 | * packet. | ||
479 | */ | ||
480 | if (am_readword(dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN) | ||
481 | netif_stop_queue(dev); | ||
482 | |||
483 | dev_kfree_skb(skb); | ||
484 | |||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | /* | ||
489 | * If we have a good packet(s), get it/them out of the buffers. | ||
490 | */ | ||
491 | static void | ||
492 | am79c961_rx(struct net_device *dev, struct dev_priv *priv) | ||
493 | { | ||
494 | do { | ||
495 | struct sk_buff *skb; | ||
496 | u_int hdraddr; | ||
497 | u_int pktaddr; | ||
498 | u_int status; | ||
499 | int len; | ||
500 | |||
501 | hdraddr = priv->rxhdr + (priv->rxtail << 3); | ||
502 | pktaddr = priv->rxbuffer[priv->rxtail]; | ||
503 | |||
504 | status = am_readword (dev, hdraddr + 2); | ||
505 | if (status & RMD_OWN) /* do we own it? */ | ||
506 | break; | ||
507 | |||
508 | priv->rxtail ++; | ||
509 | if (priv->rxtail >= RX_BUFFERS) | ||
510 | priv->rxtail = 0; | ||
511 | |||
512 | if ((status & (RMD_ERR|RMD_STP|RMD_ENP)) != (RMD_STP|RMD_ENP)) { | ||
513 | am_writeword (dev, hdraddr + 2, RMD_OWN); | ||
514 | priv->stats.rx_errors ++; | ||
515 | if (status & RMD_ERR) { | ||
516 | if (status & RMD_FRAM) | ||
517 | priv->stats.rx_frame_errors ++; | ||
518 | if (status & RMD_CRC) | ||
519 | priv->stats.rx_crc_errors ++; | ||
520 | } else if (status & RMD_STP) | ||
521 | priv->stats.rx_length_errors ++; | ||
522 | continue; | ||
523 | } | ||
524 | |||
525 | len = am_readword(dev, hdraddr + 6); | ||
526 | skb = dev_alloc_skb(len + 2); | ||
527 | |||
528 | if (skb) { | ||
529 | skb->dev = dev; | ||
530 | skb_reserve(skb, 2); | ||
531 | |||
532 | am_readbuffer(dev, pktaddr, skb_put(skb, len), len); | ||
533 | am_writeword(dev, hdraddr + 2, RMD_OWN); | ||
534 | skb->protocol = eth_type_trans(skb, dev); | ||
535 | netif_rx(skb); | ||
536 | dev->last_rx = jiffies; | ||
537 | priv->stats.rx_bytes += len; | ||
538 | priv->stats.rx_packets ++; | ||
539 | } else { | ||
540 | am_writeword (dev, hdraddr + 2, RMD_OWN); | ||
541 | printk (KERN_WARNING "%s: memory squeeze, dropping packet.\n", dev->name); | ||
542 | priv->stats.rx_dropped ++; | ||
543 | break; | ||
544 | } | ||
545 | } while (1); | ||
546 | } | ||
547 | |||
548 | /* | ||
549 | * Update stats for the transmitted packet | ||
550 | */ | ||
551 | static void | ||
552 | am79c961_tx(struct net_device *dev, struct dev_priv *priv) | ||
553 | { | ||
554 | do { | ||
555 | short len; | ||
556 | u_int hdraddr; | ||
557 | u_int status; | ||
558 | |||
559 | hdraddr = priv->txhdr + (priv->txtail << 3); | ||
560 | status = am_readword (dev, hdraddr + 2); | ||
561 | if (status & TMD_OWN) | ||
562 | break; | ||
563 | |||
564 | priv->txtail ++; | ||
565 | if (priv->txtail >= TX_BUFFERS) | ||
566 | priv->txtail = 0; | ||
567 | |||
568 | if (status & TMD_ERR) { | ||
569 | u_int status2; | ||
570 | |||
571 | priv->stats.tx_errors ++; | ||
572 | |||
573 | status2 = am_readword (dev, hdraddr + 6); | ||
574 | |||
575 | /* | ||
576 | * Clear the error byte | ||
577 | */ | ||
578 | am_writeword (dev, hdraddr + 6, 0); | ||
579 | |||
580 | if (status2 & TST_RTRY) | ||
581 | priv->stats.collisions += 16; | ||
582 | if (status2 & TST_LCOL) | ||
583 | priv->stats.tx_window_errors ++; | ||
584 | if (status2 & TST_LCAR) | ||
585 | priv->stats.tx_carrier_errors ++; | ||
586 | if (status2 & TST_UFLO) | ||
587 | priv->stats.tx_fifo_errors ++; | ||
588 | continue; | ||
589 | } | ||
590 | priv->stats.tx_packets ++; | ||
591 | len = am_readword (dev, hdraddr + 4); | ||
592 | priv->stats.tx_bytes += -len; | ||
593 | } while (priv->txtail != priv->txhead); | ||
594 | |||
595 | netif_wake_queue(dev); | ||
596 | } | ||
597 | |||
598 | static irqreturn_t | ||
599 | am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
600 | { | ||
601 | struct net_device *dev = (struct net_device *)dev_id; | ||
602 | struct dev_priv *priv = netdev_priv(dev); | ||
603 | u_int status, n = 100; | ||
604 | int handled = 0; | ||
605 | |||
606 | do { | ||
607 | status = read_rreg(dev->base_addr, CSR0); | ||
608 | write_rreg(dev->base_addr, CSR0, status & | ||
609 | (CSR0_IENA|CSR0_TINT|CSR0_RINT| | ||
610 | CSR0_MERR|CSR0_MISS|CSR0_CERR|CSR0_BABL)); | ||
611 | |||
612 | if (status & CSR0_RINT) { | ||
613 | handled = 1; | ||
614 | am79c961_rx(dev, priv); | ||
615 | } | ||
616 | if (status & CSR0_TINT) { | ||
617 | handled = 1; | ||
618 | am79c961_tx(dev, priv); | ||
619 | } | ||
620 | if (status & CSR0_MISS) { | ||
621 | handled = 1; | ||
622 | priv->stats.rx_dropped ++; | ||
623 | } | ||
624 | if (status & CSR0_CERR) { | ||
625 | handled = 1; | ||
626 | mod_timer(&priv->timer, jiffies); | ||
627 | } | ||
628 | } while (--n && status & (CSR0_RINT | CSR0_TINT)); | ||
629 | |||
630 | return IRQ_RETVAL(handled); | ||
631 | } | ||
632 | |||
633 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
634 | static void am79c961_poll_controller(struct net_device *dev) | ||
635 | { | ||
636 | unsigned long flags; | ||
637 | local_irq_save(flags); | ||
638 | am79c961_interrupt(dev->irq, dev, NULL); | ||
639 | local_irq_restore(flags); | ||
640 | } | ||
641 | #endif | ||
642 | |||
643 | /* | ||
644 | * Initialise the chip. Note that we always expect | ||
645 | * to be entered with interrupts enabled. | ||
646 | */ | ||
647 | static int | ||
648 | am79c961_hw_init(struct net_device *dev) | ||
649 | { | ||
650 | struct dev_priv *priv = netdev_priv(dev); | ||
651 | |||
652 | spin_lock_irq(&priv->chip_lock); | ||
653 | write_rreg (dev->base_addr, CSR0, CSR0_STOP); | ||
654 | write_rreg (dev->base_addr, CSR3, CSR3_MASKALL); | ||
655 | spin_unlock_irq(&priv->chip_lock); | ||
656 | |||
657 | am79c961_ramtest(dev, 0x66); | ||
658 | am79c961_ramtest(dev, 0x99); | ||
659 | |||
660 | return 0; | ||
661 | } | ||
662 | |||
663 | static void __init am79c961_banner(void) | ||
664 | { | ||
665 | static unsigned version_printed; | ||
666 | |||
667 | if (net_debug && version_printed++ == 0) | ||
668 | printk(KERN_INFO "%s", version); | ||
669 | } | ||
670 | |||
671 | static int __init am79c961_init(void) | ||
672 | { | ||
673 | struct net_device *dev; | ||
674 | struct dev_priv *priv; | ||
675 | int i, ret; | ||
676 | |||
677 | dev = alloc_etherdev(sizeof(struct dev_priv)); | ||
678 | ret = -ENOMEM; | ||
679 | if (!dev) | ||
680 | goto out; | ||
681 | |||
682 | priv = netdev_priv(dev); | ||
683 | |||
684 | /* | ||
685 | * Fixed address and IRQ lines here. | ||
686 | * The PNP initialisation should have been | ||
687 | * done by the ether bootp loader. | ||
688 | */ | ||
689 | dev->base_addr = 0x220; | ||
690 | dev->irq = IRQ_EBSA110_ETHERNET; | ||
691 | |||
692 | ret = -ENODEV; | ||
693 | if (!request_region(dev->base_addr, 0x18, dev->name)) | ||
694 | goto nodev; | ||
695 | |||
696 | /* | ||
697 | * Reset the device. | ||
698 | */ | ||
699 | inb(dev->base_addr + NET_RESET); | ||
700 | udelay(5); | ||
701 | |||
702 | /* | ||
703 | * Check the manufacturer part of the | ||
704 | * ether address. | ||
705 | */ | ||
706 | if (inb(dev->base_addr) != 0x08 || | ||
707 | inb(dev->base_addr + 2) != 0x00 || | ||
708 | inb(dev->base_addr + 4) != 0x2b) | ||
709 | goto release; | ||
710 | |||
711 | am79c961_banner(); | ||
712 | printk(KERN_INFO "%s: ether address ", dev->name); | ||
713 | |||
714 | /* Retrive and print the ethernet address. */ | ||
715 | for (i = 0; i < 6; i++) { | ||
716 | dev->dev_addr[i] = inb(dev->base_addr + i * 2) & 0xff; | ||
717 | printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]); | ||
718 | } | ||
719 | |||
720 | spin_lock_init(&priv->chip_lock); | ||
721 | init_timer(&priv->timer); | ||
722 | priv->timer.data = (unsigned long)dev; | ||
723 | priv->timer.function = am79c961_timer; | ||
724 | |||
725 | if (am79c961_hw_init(dev)) | ||
726 | goto release; | ||
727 | |||
728 | dev->open = am79c961_open; | ||
729 | dev->stop = am79c961_close; | ||
730 | dev->hard_start_xmit = am79c961_sendpacket; | ||
731 | dev->get_stats = am79c961_getstats; | ||
732 | dev->set_multicast_list = am79c961_setmulticastlist; | ||
733 | dev->tx_timeout = am79c961_timeout; | ||
734 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
735 | dev->poll_controller = am79c961_poll_controller; | ||
736 | #endif | ||
737 | |||
738 | ret = register_netdev(dev); | ||
739 | if (ret == 0) | ||
740 | return 0; | ||
741 | |||
742 | release: | ||
743 | release_region(dev->base_addr, 0x18); | ||
744 | nodev: | ||
745 | free_netdev(dev); | ||
746 | out: | ||
747 | return ret; | ||
748 | } | ||
749 | |||
750 | __initcall(am79c961_init); | ||
diff --git a/drivers/net/arm/am79c961a.h b/drivers/net/arm/am79c961a.h new file mode 100644 index 000000000000..1e9b05050cbe --- /dev/null +++ b/drivers/net/arm/am79c961a.h | |||
@@ -0,0 +1,148 @@ | |||
1 | /* | ||
2 | * linux/drivers/net/am79c961.h | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef _LINUX_am79c961a_H | ||
10 | #define _LINUX_am79c961a_H | ||
11 | |||
12 | /* use 0 for production, 1 for verification, >2 for debug. debug flags: */ | ||
13 | #define DEBUG_TX 2 | ||
14 | #define DEBUG_RX 4 | ||
15 | #define DEBUG_INT 8 | ||
16 | #define DEBUG_IC 16 | ||
17 | #ifndef NET_DEBUG | ||
18 | #define NET_DEBUG 0 | ||
19 | #endif | ||
20 | |||
21 | #define NET_UID 0 | ||
22 | #define NET_RDP 0x10 | ||
23 | #define NET_RAP 0x12 | ||
24 | #define NET_RESET 0x14 | ||
25 | #define NET_IDP 0x16 | ||
26 | |||
27 | /* | ||
28 | * RAP registers | ||
29 | */ | ||
30 | #define CSR0 0 | ||
31 | #define CSR0_INIT 0x0001 | ||
32 | #define CSR0_STRT 0x0002 | ||
33 | #define CSR0_STOP 0x0004 | ||
34 | #define CSR0_TDMD 0x0008 | ||
35 | #define CSR0_TXON 0x0010 | ||
36 | #define CSR0_RXON 0x0020 | ||
37 | #define CSR0_IENA 0x0040 | ||
38 | #define CSR0_INTR 0x0080 | ||
39 | #define CSR0_IDON 0x0100 | ||
40 | #define CSR0_TINT 0x0200 | ||
41 | #define CSR0_RINT 0x0400 | ||
42 | #define CSR0_MERR 0x0800 | ||
43 | #define CSR0_MISS 0x1000 | ||
44 | #define CSR0_CERR 0x2000 | ||
45 | #define CSR0_BABL 0x4000 | ||
46 | #define CSR0_ERR 0x8000 | ||
47 | |||
48 | #define CSR3 3 | ||
49 | #define CSR3_EMBA 0x0008 | ||
50 | #define CSR3_DXMT2PD 0x0010 | ||
51 | #define CSR3_LAPPEN 0x0020 | ||
52 | #define CSR3_DXSUFLO 0x0040 | ||
53 | #define CSR3_IDONM 0x0100 | ||
54 | #define CSR3_TINTM 0x0200 | ||
55 | #define CSR3_RINTM 0x0400 | ||
56 | #define CSR3_MERRM 0x0800 | ||
57 | #define CSR3_MISSM 0x1000 | ||
58 | #define CSR3_BABLM 0x4000 | ||
59 | #define CSR3_MASKALL 0x5F00 | ||
60 | |||
61 | #define CSR4 4 | ||
62 | #define CSR4_JABM 0x0001 | ||
63 | #define CSR4_JAB 0x0002 | ||
64 | #define CSR4_TXSTRTM 0x0004 | ||
65 | #define CSR4_TXSTRT 0x0008 | ||
66 | #define CSR4_RCVCCOM 0x0010 | ||
67 | #define CSR4_RCVCCO 0x0020 | ||
68 | #define CSR4_MFCOM 0x0100 | ||
69 | #define CSR4_MFCO 0x0200 | ||
70 | #define CSR4_ASTRP_RCV 0x0400 | ||
71 | #define CSR4_APAD_XMIT 0x0800 | ||
72 | |||
73 | #define CTRL1 5 | ||
74 | #define CTRL1_SPND 0x0001 | ||
75 | |||
76 | #define LADRL 8 | ||
77 | #define LADRM1 9 | ||
78 | #define LADRM2 10 | ||
79 | #define LADRH 11 | ||
80 | #define PADRL 12 | ||
81 | #define PADRM 13 | ||
82 | #define PADRH 14 | ||
83 | |||
84 | #define MODE 15 | ||
85 | #define MODE_DISRX 0x0001 | ||
86 | #define MODE_DISTX 0x0002 | ||
87 | #define MODE_LOOP 0x0004 | ||
88 | #define MODE_DTCRC 0x0008 | ||
89 | #define MODE_COLL 0x0010 | ||
90 | #define MODE_DRETRY 0x0020 | ||
91 | #define MODE_INTLOOP 0x0040 | ||
92 | #define MODE_PORT_AUI 0x0000 | ||
93 | #define MODE_PORT_10BT 0x0080 | ||
94 | #define MODE_DRXPA 0x2000 | ||
95 | #define MODE_DRXBA 0x4000 | ||
96 | #define MODE_PROMISC 0x8000 | ||
97 | |||
98 | #define BASERXL 24 | ||
99 | #define BASERXH 25 | ||
100 | #define BASETXL 30 | ||
101 | #define BASETXH 31 | ||
102 | |||
103 | #define POLLINT 47 | ||
104 | |||
105 | #define SIZERXR 76 | ||
106 | #define SIZETXR 78 | ||
107 | |||
108 | #define CSR_MFC 112 | ||
109 | |||
110 | #define RMD_ENP 0x0100 | ||
111 | #define RMD_STP 0x0200 | ||
112 | #define RMD_CRC 0x0800 | ||
113 | #define RMD_FRAM 0x2000 | ||
114 | #define RMD_ERR 0x4000 | ||
115 | #define RMD_OWN 0x8000 | ||
116 | |||
117 | #define TMD_ENP 0x0100 | ||
118 | #define TMD_STP 0x0200 | ||
119 | #define TMD_MORE 0x1000 | ||
120 | #define TMD_ERR 0x4000 | ||
121 | #define TMD_OWN 0x8000 | ||
122 | |||
123 | #define TST_RTRY 0x0400 | ||
124 | #define TST_LCAR 0x0800 | ||
125 | #define TST_LCOL 0x1000 | ||
126 | #define TST_UFLO 0x4000 | ||
127 | #define TST_BUFF 0x8000 | ||
128 | |||
129 | #define ISALED0 0x0004 | ||
130 | #define ISALED0_LNKST 0x8000 | ||
131 | |||
132 | struct dev_priv { | ||
133 | struct net_device_stats stats; | ||
134 | unsigned long rxbuffer[RX_BUFFERS]; | ||
135 | unsigned long txbuffer[TX_BUFFERS]; | ||
136 | unsigned char txhead; | ||
137 | unsigned char txtail; | ||
138 | unsigned char rxhead; | ||
139 | unsigned char rxtail; | ||
140 | unsigned long rxhdr; | ||
141 | unsigned long txhdr; | ||
142 | spinlock_t chip_lock; | ||
143 | struct timer_list timer; | ||
144 | }; | ||
145 | |||
146 | extern int am79c961_probe (struct net_device *dev); | ||
147 | |||
148 | #endif | ||
diff --git a/drivers/net/arm/ether00.c b/drivers/net/arm/ether00.c new file mode 100644 index 000000000000..4f1f4e31bda5 --- /dev/null +++ b/drivers/net/arm/ether00.c | |||
@@ -0,0 +1,1017 @@ | |||
1 | /* | ||
2 | * drivers/net/ether00.c | ||
3 | * | ||
4 | * Copyright (C) 2001 Altera Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | /* includes */ | ||
22 | #include <linux/config.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <linux/sched.h> | ||
25 | #include <linux/netdevice.h> | ||
26 | #include <linux/skbuff.h> | ||
27 | #include <linux/etherdevice.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/tqueue.h> | ||
30 | #include <linux/mtd/mtd.h> | ||
31 | #include <linux/pld/pld_hotswap.h> | ||
32 | #include <asm/arch/excalibur.h> | ||
33 | #include <asm/arch/hardware.h> | ||
34 | #include <asm/irq.h> | ||
35 | #include <asm/io.h> | ||
36 | #include <asm/sizes.h> | ||
37 | |||
38 | #include <asm/arch/ether00.h> | ||
39 | #include <asm/arch/tdkphy.h> | ||
40 | |||
41 | |||
42 | MODULE_AUTHOR("Clive Davies"); | ||
43 | MODULE_DESCRIPTION("Altera Ether00 IP core driver"); | ||
44 | MODULE_LICENSE("GPL"); | ||
45 | |||
46 | #define PKT_BUF_SZ 1540 /* Size of each rx buffer */ | ||
47 | #define ETH_NR 4 /* Number of MACs this driver supports */ | ||
48 | |||
49 | #define DEBUG(x) | ||
50 | |||
51 | #define __dma_va(x) (unsigned int)((unsigned int)priv->dma_data+(((unsigned int)(x))&(EXC_SPSRAM_BLOCK0_SIZE-1))) | ||
52 | #define __dma_pa(x) (unsigned int)(EXC_SPSRAM_BLOCK0_BASE+(((unsigned int)(x))-(unsigned int)priv->dma_data)) | ||
53 | |||
54 | #define ETHER00_BASE 0 | ||
55 | #define ETHER00_TYPE | ||
56 | #define ETHER00_NAME "ether00" | ||
57 | #define MAC_REG_SIZE 0x400 /* size of MAC register area */ | ||
58 | |||
59 | |||
60 | |||
61 | /* typedefs */ | ||
62 | |||
63 | /* The definition of the driver control structure */ | ||
64 | |||
65 | #define RX_NUM_BUFF 10 | ||
66 | #define RX_NUM_FDESC 10 | ||
67 | #define TX_NUM_FDESC 10 | ||
68 | |||
69 | struct tx_fda_ent{ | ||
70 | FDA_DESC fd; | ||
71 | BUF_DESC bd; | ||
72 | BUF_DESC pad; | ||
73 | }; | ||
74 | struct rx_fda_ent{ | ||
75 | FDA_DESC fd; | ||
76 | BUF_DESC bd; | ||
77 | BUF_DESC pad; | ||
78 | }; | ||
79 | struct rx_blist_ent{ | ||
80 | FDA_DESC fd; | ||
81 | BUF_DESC bd; | ||
82 | BUF_DESC pad; | ||
83 | }; | ||
84 | struct net_priv | ||
85 | { | ||
86 | struct net_device_stats stats; | ||
87 | struct sk_buff* skb; | ||
88 | void* dma_data; | ||
89 | struct rx_blist_ent* rx_blist_vp; | ||
90 | struct rx_fda_ent* rx_fda_ptr; | ||
91 | struct tx_fda_ent* tx_fdalist_vp; | ||
92 | struct tq_struct tq_memupdate; | ||
93 | unsigned char memupdate_scheduled; | ||
94 | unsigned char rx_disabled; | ||
95 | unsigned char queue_stopped; | ||
96 | spinlock_t rx_lock; | ||
97 | }; | ||
98 | |||
99 | static const char vendor_id[2]={0x07,0xed}; | ||
100 | |||
101 | #ifdef ETHER00_DEBUG | ||
102 | |||
103 | /* Dump (most) registers for debugging puposes */ | ||
104 | |||
105 | static void dump_regs(struct net_device *dev){ | ||
106 | struct net_priv* priv=dev->priv; | ||
107 | unsigned int* i; | ||
108 | |||
109 | printk("\n RX free descriptor area:\n"); | ||
110 | |||
111 | for(i=(unsigned int*)priv->rx_fda_ptr; | ||
112 | i<((unsigned int*)(priv->rx_fda_ptr+RX_NUM_FDESC));){ | ||
113 | printk("%#8x %#8x %#8x %#8x\n",*i,*(i+1),*(i+2),*(i+3)); | ||
114 | i+=4; | ||
115 | } | ||
116 | |||
117 | printk("\n RX buffer list:\n"); | ||
118 | |||
119 | for(i=(unsigned int*)priv->rx_blist_vp; | ||
120 | i<((unsigned int*)(priv->rx_blist_vp+RX_NUM_BUFF));){ | ||
121 | printk("%#8x %#8x %#8x %#8x\n",*i,*(i+1),*(i+2),*(i+3)); | ||
122 | i+=4; | ||
123 | } | ||
124 | |||
125 | printk("\n TX frame descriptor list:\n"); | ||
126 | |||
127 | for(i=(unsigned int*)priv->tx_fdalist_vp; | ||
128 | i<((unsigned int*)(priv->tx_fdalist_vp+TX_NUM_FDESC));){ | ||
129 | printk("%#8x %#8x %#8x %#8x\n",*i,*(i+1),*(i+2),*(i+3)); | ||
130 | i+=4; | ||
131 | } | ||
132 | |||
133 | printk("\ndma ctl=%#x\n",readw(ETHER_DMA_CTL(dev->base_addr))); | ||
134 | printk("txfrmptr=%#x\n",readw(ETHER_TXFRMPTR(dev->base_addr))); | ||
135 | printk("txthrsh=%#x\n",readw(ETHER_TXTHRSH(dev->base_addr))); | ||
136 | printk("txpollctr=%#x\n",readw(ETHER_TXPOLLCTR(dev->base_addr))); | ||
137 | printk("blfrmptr=%#x\n",readw(ETHER_BLFRMPTR(dev->base_addr))); | ||
138 | printk("rxfragsize=%#x\n",readw(ETHER_RXFRAGSIZE(dev->base_addr))); | ||
139 | printk("tx_int_en=%#x\n",readw(ETHER_INT_EN(dev->base_addr))); | ||
140 | printk("fda_bas=%#x\n",readw(ETHER_FDA_BAS(dev->base_addr))); | ||
141 | printk("fda_lim=%#x\n",readw(ETHER_FDA_LIM(dev->base_addr))); | ||
142 | printk("int_src=%#x\n",readw(ETHER_INT_SRC(dev->base_addr))); | ||
143 | printk("pausecnt=%#x\n",readw(ETHER_PAUSECNT(dev->base_addr))); | ||
144 | printk("rempaucnt=%#x\n",readw(ETHER_REMPAUCNT(dev->base_addr))); | ||
145 | printk("txconfrmstat=%#x\n",readw(ETHER_TXCONFRMSTAT(dev->base_addr))); | ||
146 | printk("mac_ctl=%#x\n",readw(ETHER_MAC_CTL(dev->base_addr))); | ||
147 | printk("arc_ctl=%#x\n",readw(ETHER_ARC_CTL(dev->base_addr))); | ||
148 | printk("tx_ctl=%#x\n",readw(ETHER_TX_CTL(dev->base_addr))); | ||
149 | } | ||
150 | #endif /* ETHER00_DEBUG */ | ||
151 | |||
152 | |||
153 | static int ether00_write_phy(struct net_device *dev, short address, short value) | ||
154 | { | ||
155 | volatile int count = 1024; | ||
156 | writew(value,ETHER_MD_DATA(dev->base_addr)); | ||
157 | writew( ETHER_MD_CA_BUSY_MSK | | ||
158 | ETHER_MD_CA_WR_MSK | | ||
159 | (address & ETHER_MD_CA_ADDR_MSK), | ||
160 | ETHER_MD_CA(dev->base_addr)); | ||
161 | |||
162 | /* Wait for the command to complete */ | ||
163 | while((readw(ETHER_MD_CA(dev->base_addr)) & ETHER_MD_CA_BUSY_MSK)&&count){ | ||
164 | count--; | ||
165 | } | ||
166 | if (!count){ | ||
167 | printk("Write to phy failed, addr=%#x, data=%#x\n",address, value); | ||
168 | return -EIO; | ||
169 | } | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static int ether00_read_phy(struct net_device *dev, short address) | ||
174 | { | ||
175 | volatile int count = 1024; | ||
176 | writew( ETHER_MD_CA_BUSY_MSK | | ||
177 | (address & ETHER_MD_CA_ADDR_MSK), | ||
178 | ETHER_MD_CA(dev->base_addr)); | ||
179 | |||
180 | /* Wait for the command to complete */ | ||
181 | while((readw(ETHER_MD_CA(dev->base_addr)) & ETHER_MD_CA_BUSY_MSK)&&count){ | ||
182 | count--; | ||
183 | } | ||
184 | if (!count){ | ||
185 | printk(KERN_WARNING "Read from phy timed out\n"); | ||
186 | return -EIO; | ||
187 | } | ||
188 | return readw(ETHER_MD_DATA(dev->base_addr)); | ||
189 | } | ||
190 | |||
191 | static void ether00_phy_int(int irq_num, void* dev_id, struct pt_regs* regs) | ||
192 | { | ||
193 | struct net_device* dev=dev_id; | ||
194 | int irq_status; | ||
195 | |||
196 | irq_status=ether00_read_phy(dev, PHY_IRQ_CONTROL); | ||
197 | |||
198 | if(irq_status & PHY_IRQ_CONTROL_ANEG_COMP_INT_MSK){ | ||
199 | /* | ||
200 | * Autonegotiation complete on epxa10db. The mac doesn't | ||
201 | * twig if we're in full duplex so we need to check the | ||
202 | * phy status register and configure the mac accordingly | ||
203 | */ | ||
204 | if(ether00_read_phy(dev, PHY_STATUS)&(PHY_STATUS_10T_F_MSK|PHY_STATUS_100_X_F_MSK)){ | ||
205 | int tmp; | ||
206 | tmp=readl(ETHER_MAC_CTL(dev->base_addr)); | ||
207 | writel(tmp|ETHER_MAC_CTL_FULLDUP_MSK,ETHER_MAC_CTL(dev->base_addr)); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | if(irq_status&PHY_IRQ_CONTROL_LS_CHG_INT_MSK){ | ||
212 | |||
213 | if(ether00_read_phy(dev, PHY_STATUS)& PHY_STATUS_LINK_MSK){ | ||
214 | /* Link is up */ | ||
215 | netif_carrier_on(dev); | ||
216 | //printk("Carrier on\n"); | ||
217 | }else{ | ||
218 | netif_carrier_off(dev); | ||
219 | //printk("Carrier off\n"); | ||
220 | |||
221 | } | ||
222 | } | ||
223 | |||
224 | } | ||
225 | |||
226 | static void setup_blist_entry(struct sk_buff* skb,struct rx_blist_ent* blist_ent_ptr){ | ||
227 | /* Make the buffer consistent with the cache as the mac is going to write | ||
228 | * directly into it*/ | ||
229 | blist_ent_ptr->fd.FDSystem=(unsigned int)skb; | ||
230 | blist_ent_ptr->bd.BuffData=(char*)__pa(skb->data); | ||
231 | consistent_sync(skb->data,PKT_BUF_SZ,PCI_DMA_FROMDEVICE); | ||
232 | /* align IP on 16 Byte (DMA_CTL set to skip 2 bytes) */ | ||
233 | skb_reserve(skb,2); | ||
234 | blist_ent_ptr->bd.BuffLength=PKT_BUF_SZ-2; | ||
235 | blist_ent_ptr->fd.FDLength=1; | ||
236 | blist_ent_ptr->fd.FDCtl=FDCTL_COWNSFD_MSK; | ||
237 | blist_ent_ptr->bd.BDCtl=BDCTL_COWNSBD_MSK; | ||
238 | } | ||
239 | |||
240 | |||
241 | static int ether00_mem_init(struct net_device* dev) | ||
242 | { | ||
243 | struct net_priv* priv=dev->priv; | ||
244 | struct tx_fda_ent *tx_fd_ptr,*tx_end_ptr; | ||
245 | struct rx_blist_ent* blist_ent_ptr; | ||
246 | int i; | ||
247 | |||
248 | /* | ||
249 | * Grab a block of on chip SRAM to contain the control stuctures for | ||
250 | * the ethernet MAC. This uncached becuase it needs to be accesses by both | ||
251 | * bus masters (cpu + mac). However, it shouldn't matter too much in terms | ||
252 | * of speed as its on chip memory | ||
253 | */ | ||
254 | priv->dma_data=ioremap_nocache(EXC_SPSRAM_BLOCK0_BASE,EXC_SPSRAM_BLOCK0_SIZE ); | ||
255 | if (!priv->dma_data) | ||
256 | return -ENOMEM; | ||
257 | |||
258 | priv->rx_fda_ptr=(struct rx_fda_ent*)priv->dma_data; | ||
259 | /* | ||
260 | * Now share it out amongst the Frame descriptors and the buffer list | ||
261 | */ | ||
262 | priv->rx_blist_vp=(struct rx_blist_ent*)((unsigned int)priv->dma_data+RX_NUM_FDESC*sizeof(struct rx_fda_ent)); | ||
263 | |||
264 | /* | ||
265 | *Initalise the FDA list | ||
266 | */ | ||
267 | /* set ownership to the controller */ | ||
268 | memset(priv->rx_fda_ptr,0x80,RX_NUM_FDESC*sizeof(struct rx_fda_ent)); | ||
269 | |||
270 | /* | ||
271 | *Initialise the buffer list | ||
272 | */ | ||
273 | blist_ent_ptr=priv->rx_blist_vp; | ||
274 | i=0; | ||
275 | while(blist_ent_ptr<(priv->rx_blist_vp+RX_NUM_BUFF)){ | ||
276 | struct sk_buff *skb; | ||
277 | blist_ent_ptr->fd.FDLength=1; | ||
278 | skb=dev_alloc_skb(PKT_BUF_SZ); | ||
279 | if(skb){ | ||
280 | setup_blist_entry(skb,blist_ent_ptr); | ||
281 | blist_ent_ptr->fd.FDNext=(FDA_DESC*)__dma_pa(blist_ent_ptr+1); | ||
282 | blist_ent_ptr->bd.BDStat=i++; | ||
283 | blist_ent_ptr++; | ||
284 | } | ||
285 | else | ||
286 | { | ||
287 | printk("Failed to initalise buffer list\n"); | ||
288 | } | ||
289 | |||
290 | } | ||
291 | blist_ent_ptr--; | ||
292 | blist_ent_ptr->fd.FDNext=(FDA_DESC*)__dma_pa(priv->rx_blist_vp); | ||
293 | |||
294 | priv->tx_fdalist_vp=(struct tx_fda_ent*)(priv->rx_blist_vp+RX_NUM_BUFF); | ||
295 | |||
296 | /* Initialise the buffers to be a circular list. The mac will then go poll | ||
297 | * the list until it finds a frame ready to transmit */ | ||
298 | tx_end_ptr=priv->tx_fdalist_vp+TX_NUM_FDESC; | ||
299 | for(tx_fd_ptr=priv->tx_fdalist_vp;tx_fd_ptr<tx_end_ptr;tx_fd_ptr++){ | ||
300 | tx_fd_ptr->fd.FDNext=(FDA_DESC*)__dma_pa((tx_fd_ptr+1)); | ||
301 | tx_fd_ptr->fd.FDCtl=1; | ||
302 | tx_fd_ptr->fd.FDStat=0; | ||
303 | tx_fd_ptr->fd.FDLength=1; | ||
304 | |||
305 | } | ||
306 | /* Change the last FDNext pointer to make a circular list */ | ||
307 | tx_fd_ptr--; | ||
308 | tx_fd_ptr->fd.FDNext=(FDA_DESC*)__dma_pa(priv->tx_fdalist_vp); | ||
309 | |||
310 | /* Point the device at the chain of Rx and Tx Buffers */ | ||
311 | writel((unsigned int)__dma_pa(priv->rx_fda_ptr),ETHER_FDA_BAS(dev->base_addr)); | ||
312 | writel((RX_NUM_FDESC-1)*sizeof(struct rx_fda_ent),ETHER_FDA_LIM(dev->base_addr)); | ||
313 | writel((unsigned int)__dma_pa(priv->rx_blist_vp),ETHER_BLFRMPTR(dev->base_addr)); | ||
314 | |||
315 | writel((unsigned int)__dma_pa(priv->tx_fdalist_vp),ETHER_TXFRMPTR(dev->base_addr)); | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | |||
321 | void ether00_mem_update(void* dev_id) | ||
322 | { | ||
323 | struct net_device* dev=dev_id; | ||
324 | struct net_priv* priv=dev->priv; | ||
325 | struct sk_buff* skb; | ||
326 | struct tx_fda_ent *fda_ptr=priv->tx_fdalist_vp; | ||
327 | struct rx_blist_ent* blist_ent_ptr; | ||
328 | unsigned long flags; | ||
329 | |||
330 | priv->tq_memupdate.sync=0; | ||
331 | //priv->tq_memupdate.list= | ||
332 | priv->memupdate_scheduled=0; | ||
333 | |||
334 | /* Transmit interrupt */ | ||
335 | while(fda_ptr<(priv->tx_fdalist_vp+TX_NUM_FDESC)){ | ||
336 | if(!(FDCTL_COWNSFD_MSK&fda_ptr->fd.FDCtl) && (ETHER_TX_STAT_COMP_MSK&fda_ptr->fd.FDStat)){ | ||
337 | priv->stats.tx_packets++; | ||
338 | priv->stats.tx_bytes+=fda_ptr->bd.BuffLength; | ||
339 | skb=(struct sk_buff*)fda_ptr->fd.FDSystem; | ||
340 | //printk("%d:txcln:fda=%#x skb=%#x\n",jiffies,fda_ptr,skb); | ||
341 | dev_kfree_skb(skb); | ||
342 | fda_ptr->fd.FDSystem=0; | ||
343 | fda_ptr->fd.FDStat=0; | ||
344 | fda_ptr->fd.FDCtl=0; | ||
345 | } | ||
346 | fda_ptr++; | ||
347 | } | ||
348 | /* Fill in any missing buffers from the received queue */ | ||
349 | spin_lock_irqsave(&priv->rx_lock,flags); | ||
350 | blist_ent_ptr=priv->rx_blist_vp; | ||
351 | while(blist_ent_ptr<(priv->rx_blist_vp+RX_NUM_BUFF)){ | ||
352 | /* fd.FDSystem of 0 indicates we failed to allocate the buffer in the ISR */ | ||
353 | if(!blist_ent_ptr->fd.FDSystem){ | ||
354 | struct sk_buff *skb; | ||
355 | skb=dev_alloc_skb(PKT_BUF_SZ); | ||
356 | blist_ent_ptr->fd.FDSystem=(unsigned int)skb; | ||
357 | if(skb){ | ||
358 | setup_blist_entry(skb,blist_ent_ptr); | ||
359 | } | ||
360 | else | ||
361 | { | ||
362 | break; | ||
363 | } | ||
364 | } | ||
365 | blist_ent_ptr++; | ||
366 | } | ||
367 | spin_unlock_irqrestore(&priv->rx_lock,flags); | ||
368 | if(priv->queue_stopped){ | ||
369 | //printk("%d:cln:start q\n",jiffies); | ||
370 | netif_start_queue(dev); | ||
371 | } | ||
372 | if(priv->rx_disabled){ | ||
373 | //printk("%d:enable_irq\n",jiffies); | ||
374 | priv->rx_disabled=0; | ||
375 | writel(ETHER_RX_CTL_RXEN_MSK,ETHER_RX_CTL(dev->base_addr)); | ||
376 | |||
377 | } | ||
378 | } | ||
379 | |||
380 | |||
381 | static void ether00_int( int irq_num, void* dev_id, struct pt_regs* regs) | ||
382 | { | ||
383 | struct net_device* dev=dev_id; | ||
384 | struct net_priv* priv=dev->priv; | ||
385 | |||
386 | unsigned int interruptValue; | ||
387 | |||
388 | interruptValue=readl(ETHER_INT_SRC(dev->base_addr)); | ||
389 | |||
390 | //printk("INT_SRC=%x\n",interruptValue); | ||
391 | |||
392 | if(!(readl(ETHER_INT_SRC(dev->base_addr)) & ETHER_INT_SRC_IRQ_MSK)) | ||
393 | { | ||
394 | return; /* Interrupt wasn't caused by us!! */ | ||
395 | } | ||
396 | |||
397 | if(readl(ETHER_INT_SRC(dev->base_addr))& | ||
398 | (ETHER_INT_SRC_INTMACRX_MSK | | ||
399 | ETHER_INT_SRC_FDAEX_MSK | | ||
400 | ETHER_INT_SRC_BLEX_MSK)) { | ||
401 | struct rx_blist_ent* blist_ent_ptr; | ||
402 | struct rx_fda_ent* fda_ent_ptr; | ||
403 | struct sk_buff* skb; | ||
404 | |||
405 | fda_ent_ptr=priv->rx_fda_ptr; | ||
406 | spin_lock(&priv->rx_lock); | ||
407 | while(fda_ent_ptr<(priv->rx_fda_ptr+RX_NUM_FDESC)){ | ||
408 | int result; | ||
409 | |||
410 | if(!(fda_ent_ptr->fd.FDCtl&FDCTL_COWNSFD_MSK)) | ||
411 | { | ||
412 | /* This frame is ready for processing */ | ||
413 | /*find the corresponding buffer in the bufferlist */ | ||
414 | blist_ent_ptr=priv->rx_blist_vp+fda_ent_ptr->bd.BDStat; | ||
415 | skb=(struct sk_buff*)blist_ent_ptr->fd.FDSystem; | ||
416 | |||
417 | /* Pass this skb up the stack */ | ||
418 | skb->dev=dev; | ||
419 | skb_put(skb,fda_ent_ptr->fd.FDLength); | ||
420 | skb->protocol=eth_type_trans(skb,dev); | ||
421 | skb->ip_summed=CHECKSUM_UNNECESSARY; | ||
422 | result=netif_rx(skb); | ||
423 | /* Update statistics */ | ||
424 | priv->stats.rx_packets++; | ||
425 | priv->stats.rx_bytes+=fda_ent_ptr->fd.FDLength; | ||
426 | |||
427 | /* Free the FDA entry */ | ||
428 | fda_ent_ptr->bd.BDStat=0xff; | ||
429 | fda_ent_ptr->fd.FDCtl=FDCTL_COWNSFD_MSK; | ||
430 | |||
431 | /* Allocate a new skb and point the bd entry to it */ | ||
432 | blist_ent_ptr->fd.FDSystem=0; | ||
433 | skb=dev_alloc_skb(PKT_BUF_SZ); | ||
434 | //printk("allocskb=%#x\n",skb); | ||
435 | if(skb){ | ||
436 | setup_blist_entry(skb,blist_ent_ptr); | ||
437 | |||
438 | } | ||
439 | else if(!priv->memupdate_scheduled){ | ||
440 | int tmp; | ||
441 | /* There are no buffers at the moment, so schedule */ | ||
442 | /* the background task to sort this out */ | ||
443 | schedule_task(&priv->tq_memupdate); | ||
444 | priv->memupdate_scheduled=1; | ||
445 | printk(KERN_DEBUG "%s:No buffers",dev->name); | ||
446 | /* If this interrupt was due to a lack of buffers then | ||
447 | * we'd better stop the receiver too */ | ||
448 | if(interruptValueÐER_INT_SRC_BLEX_MSK){ | ||
449 | priv->rx_disabled=1; | ||
450 | tmp=readl(ETHER_INT_SRC(dev->base_addr)); | ||
451 | writel(tmp&~ETHER_RX_CTL_RXEN_MSK,ETHER_RX_CTL(dev->base_addr)); | ||
452 | printk(KERN_DEBUG "%s:Halting rx",dev->name); | ||
453 | } | ||
454 | |||
455 | } | ||
456 | |||
457 | } | ||
458 | fda_ent_ptr++; | ||
459 | } | ||
460 | spin_unlock(&priv->rx_lock); | ||
461 | |||
462 | /* Clear the interrupts */ | ||
463 | writel(ETHER_INT_SRC_INTMACRX_MSK | ETHER_INT_SRC_FDAEX_MSK | ||
464 | | ETHER_INT_SRC_BLEX_MSK,ETHER_INT_SRC(dev->base_addr)); | ||
465 | |||
466 | } | ||
467 | |||
468 | if(readl(ETHER_INT_SRC(dev->base_addr))ÐER_INT_SRC_INTMACTX_MSK){ | ||
469 | |||
470 | if(!priv->memupdate_scheduled){ | ||
471 | schedule_task(&priv->tq_memupdate); | ||
472 | priv->memupdate_scheduled=1; | ||
473 | } | ||
474 | /* Clear the interrupt */ | ||
475 | writel(ETHER_INT_SRC_INTMACTX_MSK,ETHER_INT_SRC(dev->base_addr)); | ||
476 | } | ||
477 | |||
478 | if (readl(ETHER_INT_SRC(dev->base_addr)) & (ETHER_INT_SRC_SWINT_MSK| | ||
479 | ETHER_INT_SRC_INTEARNOT_MSK| | ||
480 | ETHER_INT_SRC_INTLINK_MSK| | ||
481 | ETHER_INT_SRC_INTEXBD_MSK| | ||
482 | ETHER_INT_SRC_INTTXCTLCMP_MSK)) | ||
483 | { | ||
484 | /* | ||
485 | * Not using any of these so they shouldn't happen | ||
486 | * | ||
487 | * In the cased of INTEXBD - if you allocate more | ||
488 | * than 28 decsriptors you may need to think about this | ||
489 | */ | ||
490 | printk("Not using this interrupt\n"); | ||
491 | } | ||
492 | |||
493 | if (readl(ETHER_INT_SRC(dev->base_addr)) & | ||
494 | (ETHER_INT_SRC_INTSBUS_MSK | | ||
495 | ETHER_INT_SRC_INTNRABT_MSK | ||
496 | |ETHER_INT_SRC_DMPARERR_MSK)) | ||
497 | { | ||
498 | /* | ||
499 | * Hardware errors, we can either ignore them and hope they go away | ||
500 | *or reset the device, I'll try the first for now to see if they happen | ||
501 | */ | ||
502 | printk("Hardware error\n"); | ||
503 | } | ||
504 | } | ||
505 | |||
506 | static void ether00_setup_ethernet_address(struct net_device* dev) | ||
507 | { | ||
508 | int tmp; | ||
509 | |||
510 | dev->addr_len=6; | ||
511 | writew(0,ETHER_ARC_ADR(dev->base_addr)); | ||
512 | writel((dev->dev_addr[0]<<24) | | ||
513 | (dev->dev_addr[1]<<16) | | ||
514 | (dev->dev_addr[2]<<8) | | ||
515 | dev->dev_addr[3], | ||
516 | ETHER_ARC_DATA(dev->base_addr)); | ||
517 | |||
518 | writew(4,ETHER_ARC_ADR(dev->base_addr)); | ||
519 | tmp=readl(ETHER_ARC_DATA(dev->base_addr)); | ||
520 | tmp&=0xffff; | ||
521 | tmp|=(dev->dev_addr[4]<<24) | (dev->dev_addr[5]<<16); | ||
522 | writel(tmp, ETHER_ARC_DATA(dev->base_addr)); | ||
523 | /* Enable this entry in the ARC */ | ||
524 | |||
525 | writel(1,ETHER_ARC_ENA(dev->base_addr)); | ||
526 | |||
527 | return; | ||
528 | } | ||
529 | |||
530 | |||
531 | static void ether00_reset(struct net_device *dev) | ||
532 | { | ||
533 | /* reset the controller */ | ||
534 | writew(ETHER_MAC_CTL_RESET_MSK,ETHER_MAC_CTL(dev->base_addr)); | ||
535 | |||
536 | /* | ||
537 | * Make sure we're not going to send anything | ||
538 | */ | ||
539 | |||
540 | writew(ETHER_TX_CTL_TXHALT_MSK,ETHER_TX_CTL(dev->base_addr)); | ||
541 | |||
542 | /* | ||
543 | * Make sure we're not going to receive anything | ||
544 | */ | ||
545 | writew(ETHER_RX_CTL_RXHALT_MSK,ETHER_RX_CTL(dev->base_addr)); | ||
546 | |||
547 | /* | ||
548 | * Disable Interrupts for now, and set the burst size to 8 bytes | ||
549 | */ | ||
550 | |||
551 | writel(ETHER_DMA_CTL_INTMASK_MSK | | ||
552 | ((8 << ETHER_DMA_CTL_DMBURST_OFST) & ETHER_DMA_CTL_DMBURST_MSK) | ||
553 | |(2<<ETHER_DMA_CTL_RXALIGN_OFST), | ||
554 | ETHER_DMA_CTL(dev->base_addr)); | ||
555 | |||
556 | |||
557 | /* | ||
558 | * Set TxThrsh - start transmitting a packet after 1514 | ||
559 | * bytes or when a packet is complete, whichever comes first | ||
560 | */ | ||
561 | writew(1514,ETHER_TXTHRSH(dev->base_addr)); | ||
562 | |||
563 | /* | ||
564 | * Set TxPollCtr. Each cycle is | ||
565 | * 61.44 microseconds with a 33 MHz bus | ||
566 | */ | ||
567 | writew(1,ETHER_TXPOLLCTR(dev->base_addr)); | ||
568 | |||
569 | /* | ||
570 | * Set Rx_Ctl - Turn off reception and let RxData turn it | ||
571 | * on later | ||
572 | */ | ||
573 | writew(ETHER_RX_CTL_RXHALT_MSK,ETHER_RX_CTL(dev->base_addr)); | ||
574 | |||
575 | } | ||
576 | |||
577 | |||
578 | static void ether00_set_multicast(struct net_device* dev) | ||
579 | { | ||
580 | int count=dev->mc_count; | ||
581 | |||
582 | /* Set promiscuous mode if it's asked for. */ | ||
583 | |||
584 | if (dev->flags&IFF_PROMISC){ | ||
585 | |||
586 | writew( ETHER_ARC_CTL_COMPEN_MSK | | ||
587 | ETHER_ARC_CTL_BROADACC_MSK | | ||
588 | ETHER_ARC_CTL_GROUPACC_MSK | | ||
589 | ETHER_ARC_CTL_STATIONACC_MSK, | ||
590 | ETHER_ARC_CTL(dev->base_addr)); | ||
591 | return; | ||
592 | } | ||
593 | |||
594 | /* | ||
595 | * Get all multicast packets if required, or if there are too | ||
596 | * many addresses to fit in hardware | ||
597 | */ | ||
598 | if (dev->flags & IFF_ALLMULTI){ | ||
599 | writew( ETHER_ARC_CTL_COMPEN_MSK | | ||
600 | ETHER_ARC_CTL_GROUPACC_MSK | | ||
601 | ETHER_ARC_CTL_BROADACC_MSK, | ||
602 | ETHER_ARC_CTL(dev->base_addr)); | ||
603 | return; | ||
604 | } | ||
605 | if (dev->mc_count > (ETHER_ARC_SIZE - 1)){ | ||
606 | |||
607 | printk(KERN_WARNING "Too many multicast addresses for hardware to filter - receiving all multicast packets\n"); | ||
608 | writew( ETHER_ARC_CTL_COMPEN_MSK | | ||
609 | ETHER_ARC_CTL_GROUPACC_MSK | | ||
610 | ETHER_ARC_CTL_BROADACC_MSK, | ||
611 | ETHER_ARC_CTL(dev->base_addr)); | ||
612 | return; | ||
613 | } | ||
614 | |||
615 | if(dev->mc_count){ | ||
616 | struct dev_mc_list *mc_list_ent=dev->mc_list; | ||
617 | unsigned int temp,i; | ||
618 | DEBUG(printk("mc_count=%d mc_list=%#x\n",dev-> mc_count, dev->mc_list)); | ||
619 | DEBUG(printk("mc addr=%02#x%02x%02x%02x%02x%02x\n", | ||
620 | mc_list_ent->dmi_addr[5], | ||
621 | mc_list_ent->dmi_addr[4], | ||
622 | mc_list_ent->dmi_addr[3], | ||
623 | mc_list_ent->dmi_addr[2], | ||
624 | mc_list_ent->dmi_addr[1], | ||
625 | mc_list_ent->dmi_addr[0]);) | ||
626 | |||
627 | /* | ||
628 | * The first 6 bytes are the MAC address, so | ||
629 | * don't change them! | ||
630 | */ | ||
631 | writew(4,ETHER_ARC_ADR(dev->base_addr)); | ||
632 | temp=readl(ETHER_ARC_DATA(dev->base_addr)); | ||
633 | temp&=0xffff0000; | ||
634 | |||
635 | /* Disable the current multicast stuff */ | ||
636 | writel(1,ETHER_ARC_ENA(dev->base_addr)); | ||
637 | |||
638 | for(;;){ | ||
639 | temp|=mc_list_ent->dmi_addr[1] | | ||
640 | mc_list_ent->dmi_addr[0]<<8; | ||
641 | writel(temp,ETHER_ARC_DATA(dev->base_addr)); | ||
642 | |||
643 | i=readl(ETHER_ARC_ADR(dev->base_addr)); | ||
644 | writew(i+4,ETHER_ARC_ADR(dev->base_addr)); | ||
645 | |||
646 | temp=mc_list_ent->dmi_addr[5]| | ||
647 | mc_list_ent->dmi_addr[4]<<8 | | ||
648 | mc_list_ent->dmi_addr[3]<<16 | | ||
649 | mc_list_ent->dmi_addr[2]<<24; | ||
650 | writel(temp,ETHER_ARC_DATA(dev->base_addr)); | ||
651 | |||
652 | count--; | ||
653 | if(!mc_list_ent->next || !count){ | ||
654 | break; | ||
655 | } | ||
656 | DEBUG(printk("mc_list_next=%#x\n",mc_list_ent->next);) | ||
657 | mc_list_ent=mc_list_ent->next; | ||
658 | |||
659 | |||
660 | i=readl(ETHER_ARC_ADR(dev->base_addr)); | ||
661 | writel(i+4,ETHER_ARC_ADR(dev->base_addr)); | ||
662 | |||
663 | temp=mc_list_ent->dmi_addr[3]| | ||
664 | mc_list_ent->dmi_addr[2]<<8 | | ||
665 | mc_list_ent->dmi_addr[1]<<16 | | ||
666 | mc_list_ent->dmi_addr[0]<<24; | ||
667 | writel(temp,ETHER_ARC_DATA(dev->base_addr)); | ||
668 | |||
669 | i=readl(ETHER_ARC_ADR(dev->base_addr)); | ||
670 | writel(i+4,ETHER_ARC_ADR(dev->base_addr)); | ||
671 | |||
672 | temp=mc_list_ent->dmi_addr[4]<<16 | | ||
673 | mc_list_ent->dmi_addr[5]<<24; | ||
674 | |||
675 | writel(temp,ETHER_ARC_DATA(dev->base_addr)); | ||
676 | |||
677 | count--; | ||
678 | if(!mc_list_ent->next || !count){ | ||
679 | break; | ||
680 | } | ||
681 | mc_list_ent=mc_list_ent->next; | ||
682 | } | ||
683 | |||
684 | |||
685 | if(count) | ||
686 | printk(KERN_WARNING "Multicast list size error\n"); | ||
687 | |||
688 | |||
689 | writew( ETHER_ARC_CTL_BROADACC_MSK| | ||
690 | ETHER_ARC_CTL_COMPEN_MSK, | ||
691 | ETHER_ARC_CTL(dev->base_addr)); | ||
692 | |||
693 | } | ||
694 | |||
695 | /* enable the active ARC enties */ | ||
696 | writew((1<<(count+2))-1,ETHER_ARC_ENA(dev->base_addr)); | ||
697 | } | ||
698 | |||
699 | |||
700 | static int ether00_open(struct net_device* dev) | ||
701 | { | ||
702 | int result,tmp; | ||
703 | struct net_priv* priv; | ||
704 | |||
705 | if (!is_valid_ether_addr(dev->dev_addr)) | ||
706 | return -EINVAL; | ||
707 | |||
708 | /* Install interrupt handlers */ | ||
709 | result=request_irq(dev->irq,ether00_int,0,"ether00",dev); | ||
710 | if(result) | ||
711 | goto open_err1; | ||
712 | |||
713 | result=request_irq(2,ether00_phy_int,0,"ether00_phy",dev); | ||
714 | if(result) | ||
715 | goto open_err2; | ||
716 | |||
717 | ether00_reset(dev); | ||
718 | result=ether00_mem_init(dev); | ||
719 | if(result) | ||
720 | goto open_err3; | ||
721 | |||
722 | |||
723 | ether00_setup_ethernet_address(dev); | ||
724 | |||
725 | ether00_set_multicast(dev); | ||
726 | |||
727 | result=ether00_write_phy(dev,PHY_CONTROL, PHY_CONTROL_ANEGEN_MSK | PHY_CONTROL_RANEG_MSK); | ||
728 | if(result) | ||
729 | goto open_err4; | ||
730 | result=ether00_write_phy(dev,PHY_IRQ_CONTROL, PHY_IRQ_CONTROL_LS_CHG_IE_MSK | | ||
731 | PHY_IRQ_CONTROL_ANEG_COMP_IE_MSK); | ||
732 | if(result) | ||
733 | goto open_err4; | ||
734 | |||
735 | /* Start the device enable interrupts */ | ||
736 | writew(ETHER_RX_CTL_RXEN_MSK | ||
737 | // | ETHER_RX_CTL_STRIPCRC_MSK | ||
738 | | ETHER_RX_CTL_ENGOOD_MSK | ||
739 | | ETHER_RX_CTL_ENRXPAR_MSK| ETHER_RX_CTL_ENLONGERR_MSK | ||
740 | | ETHER_RX_CTL_ENOVER_MSK| ETHER_RX_CTL_ENCRCERR_MSK, | ||
741 | ETHER_RX_CTL(dev->base_addr)); | ||
742 | |||
743 | writew(ETHER_TX_CTL_TXEN_MSK| | ||
744 | ETHER_TX_CTL_ENEXDEFER_MSK| | ||
745 | ETHER_TX_CTL_ENLCARR_MSK| | ||
746 | ETHER_TX_CTL_ENEXCOLL_MSK| | ||
747 | ETHER_TX_CTL_ENLATECOLL_MSK| | ||
748 | ETHER_TX_CTL_ENTXPAR_MSK| | ||
749 | ETHER_TX_CTL_ENCOMP_MSK, | ||
750 | ETHER_TX_CTL(dev->base_addr)); | ||
751 | |||
752 | tmp=readl(ETHER_DMA_CTL(dev->base_addr)); | ||
753 | writel(tmp&~ETHER_DMA_CTL_INTMASK_MSK,ETHER_DMA_CTL(dev->base_addr)); | ||
754 | |||
755 | return 0; | ||
756 | |||
757 | open_err4: | ||
758 | ether00_reset(dev); | ||
759 | open_err3: | ||
760 | free_irq(2,dev); | ||
761 | open_err2: | ||
762 | free_irq(dev->irq,dev); | ||
763 | open_err1: | ||
764 | return result; | ||
765 | |||
766 | } | ||
767 | |||
768 | |||
769 | static int ether00_tx(struct sk_buff* skb, struct net_device* dev) | ||
770 | { | ||
771 | struct net_priv *priv=dev->priv; | ||
772 | struct tx_fda_ent *fda_ptr; | ||
773 | int i; | ||
774 | |||
775 | |||
776 | /* | ||
777 | * Find an empty slot in which to stick the frame | ||
778 | */ | ||
779 | fda_ptr=(struct tx_fda_ent*)__dma_va(readl(ETHER_TXFRMPTR(dev->base_addr))); | ||
780 | i=0; | ||
781 | while(i<TX_NUM_FDESC){ | ||
782 | if (fda_ptr->fd.FDStat||(fda_ptr->fd.FDCtl & FDCTL_COWNSFD_MSK)){ | ||
783 | fda_ptr =(struct tx_fda_ent*) __dma_va((struct tx_fda_ent*)fda_ptr->fd.FDNext); | ||
784 | } | ||
785 | else { | ||
786 | break; | ||
787 | } | ||
788 | i++; | ||
789 | } | ||
790 | |||
791 | /* Write the skb data from the cache*/ | ||
792 | consistent_sync(skb->data,skb->len,PCI_DMA_TODEVICE); | ||
793 | fda_ptr->bd.BuffData=(char*)__pa(skb->data); | ||
794 | fda_ptr->bd.BuffLength=(unsigned short)skb->len; | ||
795 | /* Save the pointer to the skb for freeing later */ | ||
796 | fda_ptr->fd.FDSystem=(unsigned int)skb; | ||
797 | fda_ptr->fd.FDStat=0; | ||
798 | /* Pass ownership of the buffers to the controller */ | ||
799 | fda_ptr->fd.FDCtl=1; | ||
800 | fda_ptr->fd.FDCtl|=FDCTL_COWNSFD_MSK; | ||
801 | |||
802 | /* If the next buffer in the list is full, stop the queue */ | ||
803 | fda_ptr=(struct tx_fda_ent*)__dma_va(fda_ptr->fd.FDNext); | ||
804 | if ((fda_ptr->fd.FDStat)||(fda_ptr->fd.FDCtl & FDCTL_COWNSFD_MSK)){ | ||
805 | netif_stop_queue(dev); | ||
806 | priv->queue_stopped=1; | ||
807 | } | ||
808 | |||
809 | return 0; | ||
810 | } | ||
811 | |||
812 | static struct net_device_stats *ether00_stats(struct net_device* dev) | ||
813 | { | ||
814 | struct net_priv *priv=dev->priv; | ||
815 | return &priv->stats; | ||
816 | } | ||
817 | |||
818 | |||
819 | static int ether00_stop(struct net_device* dev) | ||
820 | { | ||
821 | struct net_priv *priv=dev->priv; | ||
822 | int tmp; | ||
823 | |||
824 | /* Stop/disable the device. */ | ||
825 | tmp=readw(ETHER_RX_CTL(dev->base_addr)); | ||
826 | tmp&=~(ETHER_RX_CTL_RXEN_MSK | ETHER_RX_CTL_ENGOOD_MSK); | ||
827 | tmp|=ETHER_RX_CTL_RXHALT_MSK; | ||
828 | writew(tmp,ETHER_RX_CTL(dev->base_addr)); | ||
829 | |||
830 | tmp=readl(ETHER_TX_CTL(dev->base_addr)); | ||
831 | tmp&=~ETHER_TX_CTL_TXEN_MSK; | ||
832 | tmp|=ETHER_TX_CTL_TXHALT_MSK; | ||
833 | writel(tmp,ETHER_TX_CTL(dev->base_addr)); | ||
834 | |||
835 | /* Free up system resources */ | ||
836 | free_irq(dev->irq,dev); | ||
837 | free_irq(2,dev); | ||
838 | iounmap(priv->dma_data); | ||
839 | |||
840 | return 0; | ||
841 | } | ||
842 | |||
843 | |||
844 | static void ether00_get_ethernet_address(struct net_device* dev) | ||
845 | { | ||
846 | struct mtd_info *mymtd=NULL; | ||
847 | int i; | ||
848 | size_t retlen; | ||
849 | |||
850 | /* | ||
851 | * For the Epxa10 dev board (camelot), the ethernet MAC | ||
852 | * address is of the form 00:aa:aa:00:xx:xx where | ||
853 | * 00:aa:aa is the Altera vendor ID and xx:xx is the | ||
854 | * last 2 bytes of the board serial number, as programmed | ||
855 | * into the OTP area of the flash device on EBI1. If this | ||
856 | * isn't an expa10 dev board, or there's no mtd support to | ||
857 | * read the serial number from flash then we'll force the | ||
858 | * use to set their own mac address using ifconfig. | ||
859 | */ | ||
860 | |||
861 | #ifdef CONFIG_ARCH_CAMELOT | ||
862 | #ifdef CONFIG_MTD | ||
863 | /* get the mtd_info structure for the first mtd device*/ | ||
864 | for(i=0;i<MAX_MTD_DEVICES;i++){ | ||
865 | mymtd=get_mtd_device(NULL,i); | ||
866 | if(!mymtd||!strcmp(mymtd->name,"EPXA10DB flash")) | ||
867 | break; | ||
868 | } | ||
869 | |||
870 | if(!mymtd || !mymtd->read_user_prot_reg){ | ||
871 | printk(KERN_WARNING "%s: Failed to read MAC address from flash\n",dev->name); | ||
872 | }else{ | ||
873 | mymtd->read_user_prot_reg(mymtd,2,1,&retlen,&dev->dev_addr[5]); | ||
874 | mymtd->read_user_prot_reg(mymtd,3,1,&retlen,&dev->dev_addr[4]); | ||
875 | dev->dev_addr[3]=0; | ||
876 | dev->dev_addr[2]=vendor_id[1]; | ||
877 | dev->dev_addr[1]=vendor_id[0]; | ||
878 | dev->dev_addr[0]=0; | ||
879 | } | ||
880 | #else | ||
881 | printk(KERN_WARNING "%s: MTD support required to read MAC address from EPXA10 dev board\n", dev->name); | ||
882 | #endif | ||
883 | #endif | ||
884 | |||
885 | if (!is_valid_ether_addr(dev->dev_addr)) | ||
886 | printk("%s: Invalid ethernet MAC address. Please set using " | ||
887 | "ifconfig\n", dev->name); | ||
888 | |||
889 | } | ||
890 | |||
891 | /* | ||
892 | * Keep a mapping of dev_info addresses -> port lines to use when | ||
893 | * removing ports dev==NULL indicates unused entry | ||
894 | */ | ||
895 | |||
896 | |||
897 | static struct net_device* dev_list[ETH_NR]; | ||
898 | |||
899 | static int ether00_add_device(struct pldhs_dev_info* dev_info,void* dev_ps_data) | ||
900 | { | ||
901 | struct net_device *dev; | ||
902 | struct net_priv *priv; | ||
903 | void *map_addr; | ||
904 | int result; | ||
905 | int i; | ||
906 | |||
907 | i=0; | ||
908 | while(dev_list[i] && i < ETH_NR) | ||
909 | i++; | ||
910 | |||
911 | if(i==ETH_NR){ | ||
912 | printk(KERN_WARNING "ether00: Maximum number of ports reached\n"); | ||
913 | return 0; | ||
914 | } | ||
915 | |||
916 | |||
917 | if (!request_mem_region(dev_info->base_addr, MAC_REG_SIZE, "ether00")) | ||
918 | return -EBUSY; | ||
919 | |||
920 | dev = alloc_etherdev(sizeof(struct net_priv)); | ||
921 | if(!dev) { | ||
922 | result = -ENOMEM; | ||
923 | goto out_release; | ||
924 | } | ||
925 | priv = dev->priv; | ||
926 | |||
927 | priv->tq_memupdate.routine=ether00_mem_update; | ||
928 | priv->tq_memupdate.data=(void*) dev; | ||
929 | |||
930 | spin_lock_init(&priv->rx_lock); | ||
931 | |||
932 | map_addr=ioremap_nocache(dev_info->base_addr,SZ_4K); | ||
933 | if(!map_addr){ | ||
934 | result = -ENOMEM; | ||
935 | out_kfree; | ||
936 | } | ||
937 | |||
938 | dev->open=ether00_open; | ||
939 | dev->stop=ether00_stop; | ||
940 | dev->set_multicast_list=ether00_set_multicast; | ||
941 | dev->hard_start_xmit=ether00_tx; | ||
942 | dev->get_stats=ether00_stats; | ||
943 | |||
944 | ether00_get_ethernet_address(dev); | ||
945 | |||
946 | SET_MODULE_OWNER(dev); | ||
947 | |||
948 | dev->base_addr=(unsigned int)map_addr; | ||
949 | dev->irq=dev_info->irq; | ||
950 | dev->features=NETIF_F_DYNALLOC | NETIF_F_HW_CSUM; | ||
951 | |||
952 | result=register_netdev(dev); | ||
953 | if(result){ | ||
954 | printk("Ether00: Error %i registering driver\n",result); | ||
955 | goto out_unmap; | ||
956 | } | ||
957 | printk("registered ether00 device at %#x\n",dev_info->base_addr); | ||
958 | |||
959 | dev_list[i]=dev; | ||
960 | |||
961 | return result; | ||
962 | |||
963 | out_unmap: | ||
964 | iounmap(map_addr); | ||
965 | out_kfree: | ||
966 | free_netdev(dev); | ||
967 | out_release: | ||
968 | release_mem_region(dev_info->base_addr, MAC_REG_SIZE); | ||
969 | return result; | ||
970 | } | ||
971 | |||
972 | |||
973 | static int ether00_remove_devices(void) | ||
974 | { | ||
975 | int i; | ||
976 | |||
977 | for(i=0;i<ETH_NR;i++){ | ||
978 | if(dev_list[i]){ | ||
979 | netif_device_detach(dev_list[i]); | ||
980 | unregister_netdev(dev_list[i]); | ||
981 | iounmap((void*)dev_list[i]->base_addr); | ||
982 | release_mem_region(dev_list[i]->base_addr, MAC_REG_SIZE); | ||
983 | free_netdev(dev_list[i]); | ||
984 | dev_list[i]=0; | ||
985 | } | ||
986 | } | ||
987 | return 0; | ||
988 | } | ||
989 | |||
990 | static struct pld_hotswap_ops ether00_pldhs_ops={ | ||
991 | .name = ETHER00_NAME, | ||
992 | .add_device = ether00_add_device, | ||
993 | .remove_devices = ether00_remove_devices, | ||
994 | }; | ||
995 | |||
996 | |||
997 | static void __exit ether00_cleanup_module(void) | ||
998 | { | ||
999 | int result; | ||
1000 | result=ether00_remove_devices(); | ||
1001 | if(result) | ||
1002 | printk(KERN_WARNING "ether00: failed to remove all devices\n"); | ||
1003 | |||
1004 | pldhs_unregister_driver(ETHER00_NAME); | ||
1005 | } | ||
1006 | module_exit(ether00_cleanup_module); | ||
1007 | |||
1008 | |||
1009 | static int __init ether00_mod_init(void) | ||
1010 | { | ||
1011 | printk("mod init\n"); | ||
1012 | return pldhs_register_driver(ðer00_pldhs_ops); | ||
1013 | |||
1014 | } | ||
1015 | |||
1016 | module_init(ether00_mod_init); | ||
1017 | |||
diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c new file mode 100644 index 000000000000..36475eb2727f --- /dev/null +++ b/drivers/net/arm/ether1.c | |||
@@ -0,0 +1,1110 @@ | |||
1 | /* | ||
2 | * linux/drivers/acorn/net/ether1.c | ||
3 | * | ||
4 | * Copyright (C) 1996-2000 Russell King | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * Acorn ether1 driver (82586 chip) for Acorn machines | ||
11 | * | ||
12 | * We basically keep two queues in the cards memory - one for transmit | ||
13 | * and one for receive. Each has a head and a tail. The head is where | ||
14 | * we/the chip adds packets to be transmitted/received, and the tail | ||
15 | * is where the transmitter has got to/where the receiver will stop. | ||
16 | * Both of these queues are circular, and since the chip is running | ||
17 | * all the time, we have to be careful when we modify the pointers etc | ||
18 | * so that the buffer memory contents is valid all the time. | ||
19 | * | ||
20 | * Change log: | ||
21 | * 1.00 RMK Released | ||
22 | * 1.01 RMK 19/03/1996 Transfers the last odd byte onto/off of the card now. | ||
23 | * 1.02 RMK 25/05/1997 Added code to restart RU if it goes not ready | ||
24 | * 1.03 RMK 14/09/1997 Cleaned up the handling of a reset during the TX interrupt. | ||
25 | * Should prevent lockup. | ||
26 | * 1.04 RMK 17/09/1997 Added more info when initialsation of chip goes wrong. | ||
27 | * TDR now only reports failure when chip reports non-zero | ||
28 | * TDR time-distance. | ||
29 | * 1.05 RMK 31/12/1997 Removed calls to dev_tint for 2.1 | ||
30 | * 1.06 RMK 10/02/2000 Updated for 2.3.43 | ||
31 | * 1.07 RMK 13/05/2000 Updated for 2.3.99-pre8 | ||
32 | */ | ||
33 | |||
34 | #include <linux/module.h> | ||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/sched.h> | ||
37 | #include <linux/types.h> | ||
38 | #include <linux/fcntl.h> | ||
39 | #include <linux/interrupt.h> | ||
40 | #include <linux/ptrace.h> | ||
41 | #include <linux/ioport.h> | ||
42 | #include <linux/in.h> | ||
43 | #include <linux/slab.h> | ||
44 | #include <linux/string.h> | ||
45 | #include <linux/errno.h> | ||
46 | #include <linux/device.h> | ||
47 | #include <linux/init.h> | ||
48 | #include <linux/netdevice.h> | ||
49 | #include <linux/etherdevice.h> | ||
50 | #include <linux/skbuff.h> | ||
51 | #include <linux/bitops.h> | ||
52 | |||
53 | #include <asm/system.h> | ||
54 | #include <asm/io.h> | ||
55 | #include <asm/dma.h> | ||
56 | #include <asm/ecard.h> | ||
57 | |||
58 | #define __ETHER1_C | ||
59 | #include "ether1.h" | ||
60 | |||
61 | static unsigned int net_debug = NET_DEBUG; | ||
62 | |||
63 | #define BUFFER_SIZE 0x10000 | ||
64 | #define TX_AREA_START 0x00100 | ||
65 | #define TX_AREA_END 0x05000 | ||
66 | #define RX_AREA_START 0x05000 | ||
67 | #define RX_AREA_END 0x0fc00 | ||
68 | |||
69 | static int ether1_open(struct net_device *dev); | ||
70 | static int ether1_sendpacket(struct sk_buff *skb, struct net_device *dev); | ||
71 | static irqreturn_t ether1_interrupt(int irq, void *dev_id, struct pt_regs *regs); | ||
72 | static int ether1_close(struct net_device *dev); | ||
73 | static struct net_device_stats *ether1_getstats(struct net_device *dev); | ||
74 | static void ether1_setmulticastlist(struct net_device *dev); | ||
75 | static void ether1_timeout(struct net_device *dev); | ||
76 | |||
77 | /* ------------------------------------------------------------------------- */ | ||
78 | |||
79 | static char version[] __initdata = "ether1 ethernet driver (c) 2000 Russell King v1.07\n"; | ||
80 | |||
81 | #define BUS_16 16 | ||
82 | #define BUS_8 8 | ||
83 | |||
84 | /* ------------------------------------------------------------------------- */ | ||
85 | |||
86 | #define DISABLEIRQS 1 | ||
87 | #define NORMALIRQS 0 | ||
88 | |||
89 | #define ether1_readw(dev, addr, type, offset, svflgs) ether1_inw_p (dev, addr + (int)(&((type *)0)->offset), svflgs) | ||
90 | #define ether1_writew(dev, val, addr, type, offset, svflgs) ether1_outw_p (dev, val, addr + (int)(&((type *)0)->offset), svflgs) | ||
91 | |||
92 | static inline unsigned short | ||
93 | ether1_inw_p (struct net_device *dev, int addr, int svflgs) | ||
94 | { | ||
95 | unsigned long flags; | ||
96 | unsigned short ret; | ||
97 | |||
98 | if (svflgs) | ||
99 | local_irq_save (flags); | ||
100 | |||
101 | writeb(addr >> 12, REG_PAGE); | ||
102 | ret = readw(ETHER1_RAM + ((addr & 4095) << 1)); | ||
103 | if (svflgs) | ||
104 | local_irq_restore (flags); | ||
105 | return ret; | ||
106 | } | ||
107 | |||
108 | static inline void | ||
109 | ether1_outw_p (struct net_device *dev, unsigned short val, int addr, int svflgs) | ||
110 | { | ||
111 | unsigned long flags; | ||
112 | |||
113 | if (svflgs) | ||
114 | local_irq_save (flags); | ||
115 | |||
116 | writeb(addr >> 12, REG_PAGE); | ||
117 | writew(val, ETHER1_RAM + ((addr & 4095) << 1)); | ||
118 | if (svflgs) | ||
119 | local_irq_restore (flags); | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * Some inline assembler to allow fast transfers on to/off of the card. | ||
124 | * Since this driver depends on some features presented by the ARM | ||
125 | * specific architecture, and that you can't configure this driver | ||
126 | * without specifiing ARM mode, this is not a problem. | ||
127 | * | ||
128 | * This routine is essentially an optimised memcpy from the card's | ||
129 | * onboard RAM to kernel memory. | ||
130 | */ | ||
131 | static void | ||
132 | ether1_writebuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length) | ||
133 | { | ||
134 | unsigned int page, thislen, offset; | ||
135 | void __iomem *addr; | ||
136 | |||
137 | offset = start & 4095; | ||
138 | page = start >> 12; | ||
139 | addr = ETHER1_RAM + (offset << 1); | ||
140 | |||
141 | if (offset + length > 4096) | ||
142 | thislen = 4096 - offset; | ||
143 | else | ||
144 | thislen = length; | ||
145 | |||
146 | do { | ||
147 | int used; | ||
148 | |||
149 | writeb(page, REG_PAGE); | ||
150 | length -= thislen; | ||
151 | |||
152 | __asm__ __volatile__( | ||
153 | "subs %3, %3, #2\n\ | ||
154 | bmi 2f\n\ | ||
155 | 1: ldr %0, [%1], #2\n\ | ||
156 | mov %0, %0, lsl #16\n\ | ||
157 | orr %0, %0, %0, lsr #16\n\ | ||
158 | str %0, [%2], #4\n\ | ||
159 | subs %3, %3, #2\n\ | ||
160 | bmi 2f\n\ | ||
161 | ldr %0, [%1], #2\n\ | ||
162 | mov %0, %0, lsl #16\n\ | ||
163 | orr %0, %0, %0, lsr #16\n\ | ||
164 | str %0, [%2], #4\n\ | ||
165 | subs %3, %3, #2\n\ | ||
166 | bmi 2f\n\ | ||
167 | ldr %0, [%1], #2\n\ | ||
168 | mov %0, %0, lsl #16\n\ | ||
169 | orr %0, %0, %0, lsr #16\n\ | ||
170 | str %0, [%2], #4\n\ | ||
171 | subs %3, %3, #2\n\ | ||
172 | bmi 2f\n\ | ||
173 | ldr %0, [%1], #2\n\ | ||
174 | mov %0, %0, lsl #16\n\ | ||
175 | orr %0, %0, %0, lsr #16\n\ | ||
176 | str %0, [%2], #4\n\ | ||
177 | subs %3, %3, #2\n\ | ||
178 | bpl 1b\n\ | ||
179 | 2: adds %3, %3, #1\n\ | ||
180 | ldreqb %0, [%1]\n\ | ||
181 | streqb %0, [%2]" | ||
182 | : "=&r" (used), "=&r" (data) | ||
183 | : "r" (addr), "r" (thislen), "1" (data)); | ||
184 | |||
185 | addr = ETHER1_RAM; | ||
186 | |||
187 | thislen = length; | ||
188 | if (thislen > 4096) | ||
189 | thislen = 4096; | ||
190 | page++; | ||
191 | } while (thislen); | ||
192 | } | ||
193 | |||
194 | static void | ||
195 | ether1_readbuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length) | ||
196 | { | ||
197 | unsigned int page, thislen, offset; | ||
198 | void __iomem *addr; | ||
199 | |||
200 | offset = start & 4095; | ||
201 | page = start >> 12; | ||
202 | addr = ETHER1_RAM + (offset << 1); | ||
203 | |||
204 | if (offset + length > 4096) | ||
205 | thislen = 4096 - offset; | ||
206 | else | ||
207 | thislen = length; | ||
208 | |||
209 | do { | ||
210 | int used; | ||
211 | |||
212 | writeb(page, REG_PAGE); | ||
213 | length -= thislen; | ||
214 | |||
215 | __asm__ __volatile__( | ||
216 | "subs %3, %3, #2\n\ | ||
217 | bmi 2f\n\ | ||
218 | 1: ldr %0, [%2], #4\n\ | ||
219 | strb %0, [%1], #1\n\ | ||
220 | mov %0, %0, lsr #8\n\ | ||
221 | strb %0, [%1], #1\n\ | ||
222 | subs %3, %3, #2\n\ | ||
223 | bmi 2f\n\ | ||
224 | ldr %0, [%2], #4\n\ | ||
225 | strb %0, [%1], #1\n\ | ||
226 | mov %0, %0, lsr #8\n\ | ||
227 | strb %0, [%1], #1\n\ | ||
228 | subs %3, %3, #2\n\ | ||
229 | bmi 2f\n\ | ||
230 | ldr %0, [%2], #4\n\ | ||
231 | strb %0, [%1], #1\n\ | ||
232 | mov %0, %0, lsr #8\n\ | ||
233 | strb %0, [%1], #1\n\ | ||
234 | subs %3, %3, #2\n\ | ||
235 | bmi 2f\n\ | ||
236 | ldr %0, [%2], #4\n\ | ||
237 | strb %0, [%1], #1\n\ | ||
238 | mov %0, %0, lsr #8\n\ | ||
239 | strb %0, [%1], #1\n\ | ||
240 | subs %3, %3, #2\n\ | ||
241 | bpl 1b\n\ | ||
242 | 2: adds %3, %3, #1\n\ | ||
243 | ldreqb %0, [%2]\n\ | ||
244 | streqb %0, [%1]" | ||
245 | : "=&r" (used), "=&r" (data) | ||
246 | : "r" (addr), "r" (thislen), "1" (data)); | ||
247 | |||
248 | addr = ETHER1_RAM; | ||
249 | |||
250 | thislen = length; | ||
251 | if (thislen > 4096) | ||
252 | thislen = 4096; | ||
253 | page++; | ||
254 | } while (thislen); | ||
255 | } | ||
256 | |||
257 | static int __init | ||
258 | ether1_ramtest(struct net_device *dev, unsigned char byte) | ||
259 | { | ||
260 | unsigned char *buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL); | ||
261 | int i, ret = BUFFER_SIZE; | ||
262 | int max_errors = 15; | ||
263 | int bad = -1; | ||
264 | int bad_start = 0; | ||
265 | |||
266 | if (!buffer) | ||
267 | return 1; | ||
268 | |||
269 | memset (buffer, byte, BUFFER_SIZE); | ||
270 | ether1_writebuffer (dev, buffer, 0, BUFFER_SIZE); | ||
271 | memset (buffer, byte ^ 0xff, BUFFER_SIZE); | ||
272 | ether1_readbuffer (dev, buffer, 0, BUFFER_SIZE); | ||
273 | |||
274 | for (i = 0; i < BUFFER_SIZE; i++) { | ||
275 | if (buffer[i] != byte) { | ||
276 | if (max_errors >= 0 && bad != buffer[i]) { | ||
277 | if (bad != -1) | ||
278 | printk ("\n"); | ||
279 | printk (KERN_CRIT "%s: RAM failed with (%02X instead of %02X) at 0x%04X", | ||
280 | dev->name, buffer[i], byte, i); | ||
281 | ret = -ENODEV; | ||
282 | max_errors --; | ||
283 | bad = buffer[i]; | ||
284 | bad_start = i; | ||
285 | } | ||
286 | } else { | ||
287 | if (bad != -1) { | ||
288 | if (bad_start == i - 1) | ||
289 | printk ("\n"); | ||
290 | else | ||
291 | printk (" - 0x%04X\n", i - 1); | ||
292 | bad = -1; | ||
293 | } | ||
294 | } | ||
295 | } | ||
296 | |||
297 | if (bad != -1) | ||
298 | printk (" - 0x%04X\n", BUFFER_SIZE); | ||
299 | kfree (buffer); | ||
300 | |||
301 | return ret; | ||
302 | } | ||
303 | |||
304 | static int | ||
305 | ether1_reset (struct net_device *dev) | ||
306 | { | ||
307 | writeb(CTRL_RST|CTRL_ACK, REG_CONTROL); | ||
308 | return BUS_16; | ||
309 | } | ||
310 | |||
311 | static int __init | ||
312 | ether1_init_2(struct net_device *dev) | ||
313 | { | ||
314 | int i; | ||
315 | dev->mem_start = 0; | ||
316 | |||
317 | i = ether1_ramtest (dev, 0x5a); | ||
318 | |||
319 | if (i > 0) | ||
320 | i = ether1_ramtest (dev, 0x1e); | ||
321 | |||
322 | if (i <= 0) | ||
323 | return -ENODEV; | ||
324 | |||
325 | dev->mem_end = i; | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | /* | ||
330 | * These are the structures that are loaded into the ether RAM card to | ||
331 | * initialise the 82586 | ||
332 | */ | ||
333 | |||
334 | /* at 0x0100 */ | ||
335 | #define NOP_ADDR (TX_AREA_START) | ||
336 | #define NOP_SIZE (0x06) | ||
337 | static nop_t init_nop = { | ||
338 | 0, | ||
339 | CMD_NOP, | ||
340 | NOP_ADDR | ||
341 | }; | ||
342 | |||
343 | /* at 0x003a */ | ||
344 | #define TDR_ADDR (0x003a) | ||
345 | #define TDR_SIZE (0x08) | ||
346 | static tdr_t init_tdr = { | ||
347 | 0, | ||
348 | CMD_TDR | CMD_INTR, | ||
349 | NOP_ADDR, | ||
350 | 0 | ||
351 | }; | ||
352 | |||
353 | /* at 0x002e */ | ||
354 | #define MC_ADDR (0x002e) | ||
355 | #define MC_SIZE (0x0c) | ||
356 | static mc_t init_mc = { | ||
357 | 0, | ||
358 | CMD_SETMULTICAST, | ||
359 | TDR_ADDR, | ||
360 | 0, | ||
361 | { { 0, } } | ||
362 | }; | ||
363 | |||
364 | /* at 0x0022 */ | ||
365 | #define SA_ADDR (0x0022) | ||
366 | #define SA_SIZE (0x0c) | ||
367 | static sa_t init_sa = { | ||
368 | 0, | ||
369 | CMD_SETADDRESS, | ||
370 | MC_ADDR, | ||
371 | { 0, } | ||
372 | }; | ||
373 | |||
374 | /* at 0x0010 */ | ||
375 | #define CFG_ADDR (0x0010) | ||
376 | #define CFG_SIZE (0x12) | ||
377 | static cfg_t init_cfg = { | ||
378 | 0, | ||
379 | CMD_CONFIG, | ||
380 | SA_ADDR, | ||
381 | 8, | ||
382 | 8, | ||
383 | CFG8_SRDY, | ||
384 | CFG9_PREAMB8 | CFG9_ADDRLENBUF | CFG9_ADDRLEN(6), | ||
385 | 0, | ||
386 | 0x60, | ||
387 | 0, | ||
388 | CFG13_RETRY(15) | CFG13_SLOTH(2), | ||
389 | 0, | ||
390 | }; | ||
391 | |||
392 | /* at 0x0000 */ | ||
393 | #define SCB_ADDR (0x0000) | ||
394 | #define SCB_SIZE (0x10) | ||
395 | static scb_t init_scb = { | ||
396 | 0, | ||
397 | SCB_CMDACKRNR | SCB_CMDACKCNA | SCB_CMDACKFR | SCB_CMDACKCX, | ||
398 | CFG_ADDR, | ||
399 | RX_AREA_START, | ||
400 | 0, | ||
401 | 0, | ||
402 | 0, | ||
403 | 0 | ||
404 | }; | ||
405 | |||
406 | /* at 0xffee */ | ||
407 | #define ISCP_ADDR (0xffee) | ||
408 | #define ISCP_SIZE (0x08) | ||
409 | static iscp_t init_iscp = { | ||
410 | 1, | ||
411 | SCB_ADDR, | ||
412 | 0x0000, | ||
413 | 0x0000 | ||
414 | }; | ||
415 | |||
416 | /* at 0xfff6 */ | ||
417 | #define SCP_ADDR (0xfff6) | ||
418 | #define SCP_SIZE (0x0a) | ||
419 | static scp_t init_scp = { | ||
420 | SCP_SY_16BBUS, | ||
421 | { 0, 0 }, | ||
422 | ISCP_ADDR, | ||
423 | 0 | ||
424 | }; | ||
425 | |||
426 | #define RFD_SIZE (0x16) | ||
427 | static rfd_t init_rfd = { | ||
428 | 0, | ||
429 | 0, | ||
430 | 0, | ||
431 | 0, | ||
432 | { 0, }, | ||
433 | { 0, }, | ||
434 | 0 | ||
435 | }; | ||
436 | |||
437 | #define RBD_SIZE (0x0a) | ||
438 | static rbd_t init_rbd = { | ||
439 | 0, | ||
440 | 0, | ||
441 | 0, | ||
442 | 0, | ||
443 | ETH_FRAME_LEN + 8 | ||
444 | }; | ||
445 | |||
446 | #define TX_SIZE (0x08) | ||
447 | #define TBD_SIZE (0x08) | ||
448 | |||
449 | static int | ||
450 | ether1_init_for_open (struct net_device *dev) | ||
451 | { | ||
452 | int i, status, addr, next, next2; | ||
453 | int failures = 0; | ||
454 | unsigned long timeout; | ||
455 | |||
456 | writeb(CTRL_RST|CTRL_ACK, REG_CONTROL); | ||
457 | |||
458 | for (i = 0; i < 6; i++) | ||
459 | init_sa.sa_addr[i] = dev->dev_addr[i]; | ||
460 | |||
461 | /* load data structures into ether1 RAM */ | ||
462 | ether1_writebuffer (dev, &init_scp, SCP_ADDR, SCP_SIZE); | ||
463 | ether1_writebuffer (dev, &init_iscp, ISCP_ADDR, ISCP_SIZE); | ||
464 | ether1_writebuffer (dev, &init_scb, SCB_ADDR, SCB_SIZE); | ||
465 | ether1_writebuffer (dev, &init_cfg, CFG_ADDR, CFG_SIZE); | ||
466 | ether1_writebuffer (dev, &init_sa, SA_ADDR, SA_SIZE); | ||
467 | ether1_writebuffer (dev, &init_mc, MC_ADDR, MC_SIZE); | ||
468 | ether1_writebuffer (dev, &init_tdr, TDR_ADDR, TDR_SIZE); | ||
469 | ether1_writebuffer (dev, &init_nop, NOP_ADDR, NOP_SIZE); | ||
470 | |||
471 | if (ether1_readw(dev, CFG_ADDR, cfg_t, cfg_command, NORMALIRQS) != CMD_CONFIG) { | ||
472 | printk (KERN_ERR "%s: detected either RAM fault or compiler bug\n", | ||
473 | dev->name); | ||
474 | return 1; | ||
475 | } | ||
476 | |||
477 | /* | ||
478 | * setup circularly linked list of { rfd, rbd, buffer }, with | ||
479 | * all rfds circularly linked, rbds circularly linked. | ||
480 | * First rfd is linked to scp, first rbd is linked to first | ||
481 | * rfd. Last rbd has a suspend command. | ||
482 | */ | ||
483 | addr = RX_AREA_START; | ||
484 | do { | ||
485 | next = addr + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10; | ||
486 | next2 = next + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10; | ||
487 | |||
488 | if (next2 >= RX_AREA_END) { | ||
489 | next = RX_AREA_START; | ||
490 | init_rfd.rfd_command = RFD_CMDEL | RFD_CMDSUSPEND; | ||
491 | priv(dev)->rx_tail = addr; | ||
492 | } else | ||
493 | init_rfd.rfd_command = 0; | ||
494 | if (addr == RX_AREA_START) | ||
495 | init_rfd.rfd_rbdoffset = addr + RFD_SIZE; | ||
496 | else | ||
497 | init_rfd.rfd_rbdoffset = 0; | ||
498 | init_rfd.rfd_link = next; | ||
499 | init_rbd.rbd_link = next + RFD_SIZE; | ||
500 | init_rbd.rbd_bufl = addr + RFD_SIZE + RBD_SIZE; | ||
501 | |||
502 | ether1_writebuffer (dev, &init_rfd, addr, RFD_SIZE); | ||
503 | ether1_writebuffer (dev, &init_rbd, addr + RFD_SIZE, RBD_SIZE); | ||
504 | addr = next; | ||
505 | } while (next2 < RX_AREA_END); | ||
506 | |||
507 | priv(dev)->tx_link = NOP_ADDR; | ||
508 | priv(dev)->tx_head = NOP_ADDR + NOP_SIZE; | ||
509 | priv(dev)->tx_tail = TDR_ADDR; | ||
510 | priv(dev)->rx_head = RX_AREA_START; | ||
511 | |||
512 | /* release reset & give 586 a prod */ | ||
513 | priv(dev)->resetting = 1; | ||
514 | priv(dev)->initialising = 1; | ||
515 | writeb(CTRL_RST, REG_CONTROL); | ||
516 | writeb(0, REG_CONTROL); | ||
517 | writeb(CTRL_CA, REG_CONTROL); | ||
518 | |||
519 | /* 586 should now unset iscp.busy */ | ||
520 | timeout = jiffies + HZ/2; | ||
521 | while (ether1_readw(dev, ISCP_ADDR, iscp_t, iscp_busy, DISABLEIRQS) == 1) { | ||
522 | if (time_after(jiffies, timeout)) { | ||
523 | printk (KERN_WARNING "%s: can't initialise 82586: iscp is busy\n", dev->name); | ||
524 | return 1; | ||
525 | } | ||
526 | } | ||
527 | |||
528 | /* check status of commands that we issued */ | ||
529 | timeout += HZ/10; | ||
530 | while (((status = ether1_readw(dev, CFG_ADDR, cfg_t, cfg_status, DISABLEIRQS)) | ||
531 | & STAT_COMPLETE) == 0) { | ||
532 | if (time_after(jiffies, timeout)) | ||
533 | break; | ||
534 | } | ||
535 | |||
536 | if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) { | ||
537 | printk (KERN_WARNING "%s: can't initialise 82586: config status %04X\n", dev->name, status); | ||
538 | printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name, | ||
539 | ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS), | ||
540 | ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS), | ||
541 | ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS), | ||
542 | ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS)); | ||
543 | failures += 1; | ||
544 | } | ||
545 | |||
546 | timeout += HZ/10; | ||
547 | while (((status = ether1_readw(dev, SA_ADDR, sa_t, sa_status, DISABLEIRQS)) | ||
548 | & STAT_COMPLETE) == 0) { | ||
549 | if (time_after(jiffies, timeout)) | ||
550 | break; | ||
551 | } | ||
552 | |||
553 | if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) { | ||
554 | printk (KERN_WARNING "%s: can't initialise 82586: set address status %04X\n", dev->name, status); | ||
555 | printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name, | ||
556 | ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS), | ||
557 | ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS), | ||
558 | ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS), | ||
559 | ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS)); | ||
560 | failures += 1; | ||
561 | } | ||
562 | |||
563 | timeout += HZ/10; | ||
564 | while (((status = ether1_readw(dev, MC_ADDR, mc_t, mc_status, DISABLEIRQS)) | ||
565 | & STAT_COMPLETE) == 0) { | ||
566 | if (time_after(jiffies, timeout)) | ||
567 | break; | ||
568 | } | ||
569 | |||
570 | if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) { | ||
571 | printk (KERN_WARNING "%s: can't initialise 82586: set multicast status %04X\n", dev->name, status); | ||
572 | printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name, | ||
573 | ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS), | ||
574 | ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS), | ||
575 | ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS), | ||
576 | ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS)); | ||
577 | failures += 1; | ||
578 | } | ||
579 | |||
580 | timeout += HZ; | ||
581 | while (((status = ether1_readw(dev, TDR_ADDR, tdr_t, tdr_status, DISABLEIRQS)) | ||
582 | & STAT_COMPLETE) == 0) { | ||
583 | if (time_after(jiffies, timeout)) | ||
584 | break; | ||
585 | } | ||
586 | |||
587 | if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) { | ||
588 | printk (KERN_WARNING "%s: can't tdr (ignored)\n", dev->name); | ||
589 | printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name, | ||
590 | ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS), | ||
591 | ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS), | ||
592 | ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS), | ||
593 | ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS)); | ||
594 | } else { | ||
595 | status = ether1_readw(dev, TDR_ADDR, tdr_t, tdr_result, DISABLEIRQS); | ||
596 | if (status & TDR_XCVRPROB) | ||
597 | printk (KERN_WARNING "%s: i/f failed tdr: transceiver problem\n", dev->name); | ||
598 | else if ((status & (TDR_SHORT|TDR_OPEN)) && (status & TDR_TIME)) { | ||
599 | #ifdef FANCY | ||
600 | printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d.%d us away\n", dev->name, | ||
601 | status & TDR_SHORT ? "short" : "open", (status & TDR_TIME) / 10, | ||
602 | (status & TDR_TIME) % 10); | ||
603 | #else | ||
604 | printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d clks away\n", dev->name, | ||
605 | status & TDR_SHORT ? "short" : "open", (status & TDR_TIME)); | ||
606 | #endif | ||
607 | } | ||
608 | } | ||
609 | |||
610 | if (failures) | ||
611 | ether1_reset (dev); | ||
612 | return failures ? 1 : 0; | ||
613 | } | ||
614 | |||
615 | /* ------------------------------------------------------------------------- */ | ||
616 | |||
617 | static int | ||
618 | ether1_txalloc (struct net_device *dev, int size) | ||
619 | { | ||
620 | int start, tail; | ||
621 | |||
622 | size = (size + 1) & ~1; | ||
623 | tail = priv(dev)->tx_tail; | ||
624 | |||
625 | if (priv(dev)->tx_head + size > TX_AREA_END) { | ||
626 | if (tail > priv(dev)->tx_head) | ||
627 | return -1; | ||
628 | start = TX_AREA_START; | ||
629 | if (start + size > tail) | ||
630 | return -1; | ||
631 | priv(dev)->tx_head = start + size; | ||
632 | } else { | ||
633 | if (priv(dev)->tx_head < tail && (priv(dev)->tx_head + size) > tail) | ||
634 | return -1; | ||
635 | start = priv(dev)->tx_head; | ||
636 | priv(dev)->tx_head += size; | ||
637 | } | ||
638 | |||
639 | return start; | ||
640 | } | ||
641 | |||
642 | static int | ||
643 | ether1_open (struct net_device *dev) | ||
644 | { | ||
645 | if (!is_valid_ether_addr(dev->dev_addr)) { | ||
646 | printk(KERN_WARNING "%s: invalid ethernet MAC address\n", | ||
647 | dev->name); | ||
648 | return -EINVAL; | ||
649 | } | ||
650 | |||
651 | if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev)) | ||
652 | return -EAGAIN; | ||
653 | |||
654 | memset (&priv(dev)->stats, 0, sizeof (struct net_device_stats)); | ||
655 | |||
656 | if (ether1_init_for_open (dev)) { | ||
657 | free_irq (dev->irq, dev); | ||
658 | return -EAGAIN; | ||
659 | } | ||
660 | |||
661 | netif_start_queue(dev); | ||
662 | |||
663 | return 0; | ||
664 | } | ||
665 | |||
666 | static void | ||
667 | ether1_timeout(struct net_device *dev) | ||
668 | { | ||
669 | printk(KERN_WARNING "%s: transmit timeout, network cable problem?\n", | ||
670 | dev->name); | ||
671 | printk(KERN_WARNING "%s: resetting device\n", dev->name); | ||
672 | |||
673 | ether1_reset (dev); | ||
674 | |||
675 | if (ether1_init_for_open (dev)) | ||
676 | printk (KERN_ERR "%s: unable to restart interface\n", dev->name); | ||
677 | |||
678 | priv(dev)->stats.tx_errors++; | ||
679 | netif_wake_queue(dev); | ||
680 | } | ||
681 | |||
682 | static int | ||
683 | ether1_sendpacket (struct sk_buff *skb, struct net_device *dev) | ||
684 | { | ||
685 | int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr; | ||
686 | unsigned long flags; | ||
687 | tx_t tx; | ||
688 | tbd_t tbd; | ||
689 | nop_t nop; | ||
690 | |||
691 | if (priv(dev)->restart) { | ||
692 | printk(KERN_WARNING "%s: resetting device\n", dev->name); | ||
693 | |||
694 | ether1_reset(dev); | ||
695 | |||
696 | if (ether1_init_for_open(dev)) | ||
697 | printk(KERN_ERR "%s: unable to restart interface\n", dev->name); | ||
698 | else | ||
699 | priv(dev)->restart = 0; | ||
700 | } | ||
701 | |||
702 | if (skb->len < ETH_ZLEN) { | ||
703 | skb = skb_padto(skb, ETH_ZLEN); | ||
704 | if (skb == NULL) | ||
705 | goto out; | ||
706 | } | ||
707 | |||
708 | /* | ||
709 | * insert packet followed by a nop | ||
710 | */ | ||
711 | txaddr = ether1_txalloc (dev, TX_SIZE); | ||
712 | tbdaddr = ether1_txalloc (dev, TBD_SIZE); | ||
713 | dataddr = ether1_txalloc (dev, skb->len); | ||
714 | nopaddr = ether1_txalloc (dev, NOP_SIZE); | ||
715 | |||
716 | tx.tx_status = 0; | ||
717 | tx.tx_command = CMD_TX | CMD_INTR; | ||
718 | tx.tx_link = nopaddr; | ||
719 | tx.tx_tbdoffset = tbdaddr; | ||
720 | tbd.tbd_opts = TBD_EOL | skb->len; | ||
721 | tbd.tbd_link = I82586_NULL; | ||
722 | tbd.tbd_bufl = dataddr; | ||
723 | tbd.tbd_bufh = 0; | ||
724 | nop.nop_status = 0; | ||
725 | nop.nop_command = CMD_NOP; | ||
726 | nop.nop_link = nopaddr; | ||
727 | |||
728 | local_irq_save(flags); | ||
729 | ether1_writebuffer (dev, &tx, txaddr, TX_SIZE); | ||
730 | ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE); | ||
731 | ether1_writebuffer (dev, skb->data, dataddr, skb->len); | ||
732 | ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE); | ||
733 | tmp = priv(dev)->tx_link; | ||
734 | priv(dev)->tx_link = nopaddr; | ||
735 | |||
736 | /* now reset the previous nop pointer */ | ||
737 | ether1_writew(dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS); | ||
738 | |||
739 | local_irq_restore(flags); | ||
740 | |||
741 | /* handle transmit */ | ||
742 | dev->trans_start = jiffies; | ||
743 | |||
744 | /* check to see if we have room for a full sized ether frame */ | ||
745 | tmp = priv(dev)->tx_head; | ||
746 | tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN); | ||
747 | priv(dev)->tx_head = tmp; | ||
748 | dev_kfree_skb (skb); | ||
749 | |||
750 | if (tst == -1) | ||
751 | netif_stop_queue(dev); | ||
752 | |||
753 | out: | ||
754 | return 0; | ||
755 | } | ||
756 | |||
757 | static void | ||
758 | ether1_xmit_done (struct net_device *dev) | ||
759 | { | ||
760 | nop_t nop; | ||
761 | int caddr, tst; | ||
762 | |||
763 | caddr = priv(dev)->tx_tail; | ||
764 | |||
765 | again: | ||
766 | ether1_readbuffer (dev, &nop, caddr, NOP_SIZE); | ||
767 | |||
768 | switch (nop.nop_command & CMD_MASK) { | ||
769 | case CMD_TDR: | ||
770 | /* special case */ | ||
771 | if (ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS) | ||
772 | != (unsigned short)I82586_NULL) { | ||
773 | ether1_writew(dev, SCB_CMDCUCSTART | SCB_CMDRXSTART, SCB_ADDR, scb_t, | ||
774 | scb_command, NORMALIRQS); | ||
775 | writeb(CTRL_CA, REG_CONTROL); | ||
776 | } | ||
777 | priv(dev)->tx_tail = NOP_ADDR; | ||
778 | return; | ||
779 | |||
780 | case CMD_NOP: | ||
781 | if (nop.nop_link == caddr) { | ||
782 | if (priv(dev)->initialising == 0) | ||
783 | printk (KERN_WARNING "%s: strange command complete with no tx command!\n", dev->name); | ||
784 | else | ||
785 | priv(dev)->initialising = 0; | ||
786 | return; | ||
787 | } | ||
788 | if (caddr == nop.nop_link) | ||
789 | return; | ||
790 | caddr = nop.nop_link; | ||
791 | goto again; | ||
792 | |||
793 | case CMD_TX: | ||
794 | if (nop.nop_status & STAT_COMPLETE) | ||
795 | break; | ||
796 | printk (KERN_ERR "%s: strange command complete without completed command\n", dev->name); | ||
797 | priv(dev)->restart = 1; | ||
798 | return; | ||
799 | |||
800 | default: | ||
801 | printk (KERN_WARNING "%s: strange command %d complete! (offset %04X)", dev->name, | ||
802 | nop.nop_command & CMD_MASK, caddr); | ||
803 | priv(dev)->restart = 1; | ||
804 | return; | ||
805 | } | ||
806 | |||
807 | while (nop.nop_status & STAT_COMPLETE) { | ||
808 | if (nop.nop_status & STAT_OK) { | ||
809 | priv(dev)->stats.tx_packets ++; | ||
810 | priv(dev)->stats.collisions += (nop.nop_status & STAT_COLLISIONS); | ||
811 | } else { | ||
812 | priv(dev)->stats.tx_errors ++; | ||
813 | |||
814 | if (nop.nop_status & STAT_COLLAFTERTX) | ||
815 | priv(dev)->stats.collisions ++; | ||
816 | if (nop.nop_status & STAT_NOCARRIER) | ||
817 | priv(dev)->stats.tx_carrier_errors ++; | ||
818 | if (nop.nop_status & STAT_TXLOSTCTS) | ||
819 | printk (KERN_WARNING "%s: cts lost\n", dev->name); | ||
820 | if (nop.nop_status & STAT_TXSLOWDMA) | ||
821 | priv(dev)->stats.tx_fifo_errors ++; | ||
822 | if (nop.nop_status & STAT_COLLEXCESSIVE) | ||
823 | priv(dev)->stats.collisions += 16; | ||
824 | } | ||
825 | |||
826 | if (nop.nop_link == caddr) { | ||
827 | printk (KERN_ERR "%s: tx buffer chaining error: tx command points to itself\n", dev->name); | ||
828 | break; | ||
829 | } | ||
830 | |||
831 | caddr = nop.nop_link; | ||
832 | ether1_readbuffer (dev, &nop, caddr, NOP_SIZE); | ||
833 | if ((nop.nop_command & CMD_MASK) != CMD_NOP) { | ||
834 | printk (KERN_ERR "%s: tx buffer chaining error: no nop after tx command\n", dev->name); | ||
835 | break; | ||
836 | } | ||
837 | |||
838 | if (caddr == nop.nop_link) | ||
839 | break; | ||
840 | |||
841 | caddr = nop.nop_link; | ||
842 | ether1_readbuffer (dev, &nop, caddr, NOP_SIZE); | ||
843 | if ((nop.nop_command & CMD_MASK) != CMD_TX) { | ||
844 | printk (KERN_ERR "%s: tx buffer chaining error: no tx command after nop\n", dev->name); | ||
845 | break; | ||
846 | } | ||
847 | } | ||
848 | priv(dev)->tx_tail = caddr; | ||
849 | |||
850 | caddr = priv(dev)->tx_head; | ||
851 | tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN); | ||
852 | priv(dev)->tx_head = caddr; | ||
853 | if (tst != -1) | ||
854 | netif_wake_queue(dev); | ||
855 | } | ||
856 | |||
857 | static void | ||
858 | ether1_recv_done (struct net_device *dev) | ||
859 | { | ||
860 | int status; | ||
861 | int nexttail, rbdaddr; | ||
862 | rbd_t rbd; | ||
863 | |||
864 | do { | ||
865 | status = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_status, NORMALIRQS); | ||
866 | if ((status & RFD_COMPLETE) == 0) | ||
867 | break; | ||
868 | |||
869 | rbdaddr = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_rbdoffset, NORMALIRQS); | ||
870 | ether1_readbuffer (dev, &rbd, rbdaddr, RBD_SIZE); | ||
871 | |||
872 | if ((rbd.rbd_status & (RBD_EOF | RBD_ACNTVALID)) == (RBD_EOF | RBD_ACNTVALID)) { | ||
873 | int length = rbd.rbd_status & RBD_ACNT; | ||
874 | struct sk_buff *skb; | ||
875 | |||
876 | length = (length + 1) & ~1; | ||
877 | skb = dev_alloc_skb (length + 2); | ||
878 | |||
879 | if (skb) { | ||
880 | skb->dev = dev; | ||
881 | skb_reserve (skb, 2); | ||
882 | |||
883 | ether1_readbuffer (dev, skb_put (skb, length), rbd.rbd_bufl, length); | ||
884 | |||
885 | skb->protocol = eth_type_trans (skb, dev); | ||
886 | netif_rx (skb); | ||
887 | priv(dev)->stats.rx_packets ++; | ||
888 | } else | ||
889 | priv(dev)->stats.rx_dropped ++; | ||
890 | } else { | ||
891 | printk(KERN_WARNING "%s: %s\n", dev->name, | ||
892 | (rbd.rbd_status & RBD_EOF) ? "oversized packet" : "acnt not valid"); | ||
893 | priv(dev)->stats.rx_dropped ++; | ||
894 | } | ||
895 | |||
896 | nexttail = ether1_readw(dev, priv(dev)->rx_tail, rfd_t, rfd_link, NORMALIRQS); | ||
897 | /* nexttail should be rx_head */ | ||
898 | if (nexttail != priv(dev)->rx_head) | ||
899 | printk(KERN_ERR "%s: receiver buffer chaining error (%04X != %04X)\n", | ||
900 | dev->name, nexttail, priv(dev)->rx_head); | ||
901 | ether1_writew(dev, RFD_CMDEL | RFD_CMDSUSPEND, nexttail, rfd_t, rfd_command, NORMALIRQS); | ||
902 | ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_command, NORMALIRQS); | ||
903 | ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_status, NORMALIRQS); | ||
904 | ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_rbdoffset, NORMALIRQS); | ||
905 | |||
906 | priv(dev)->rx_tail = nexttail; | ||
907 | priv(dev)->rx_head = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_link, NORMALIRQS); | ||
908 | } while (1); | ||
909 | } | ||
910 | |||
911 | static irqreturn_t | ||
912 | ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs) | ||
913 | { | ||
914 | struct net_device *dev = (struct net_device *)dev_id; | ||
915 | int status; | ||
916 | |||
917 | status = ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS); | ||
918 | |||
919 | if (status) { | ||
920 | ether1_writew(dev, status & (SCB_STRNR | SCB_STCNA | SCB_STFR | SCB_STCX), | ||
921 | SCB_ADDR, scb_t, scb_command, NORMALIRQS); | ||
922 | writeb(CTRL_CA | CTRL_ACK, REG_CONTROL); | ||
923 | if (status & SCB_STCX) { | ||
924 | ether1_xmit_done (dev); | ||
925 | } | ||
926 | if (status & SCB_STCNA) { | ||
927 | if (priv(dev)->resetting == 0) | ||
928 | printk (KERN_WARNING "%s: CU went not ready ???\n", dev->name); | ||
929 | else | ||
930 | priv(dev)->resetting += 1; | ||
931 | if (ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS) | ||
932 | != (unsigned short)I82586_NULL) { | ||
933 | ether1_writew(dev, SCB_CMDCUCSTART, SCB_ADDR, scb_t, scb_command, NORMALIRQS); | ||
934 | writeb(CTRL_CA, REG_CONTROL); | ||
935 | } | ||
936 | if (priv(dev)->resetting == 2) | ||
937 | priv(dev)->resetting = 0; | ||
938 | } | ||
939 | if (status & SCB_STFR) { | ||
940 | ether1_recv_done (dev); | ||
941 | } | ||
942 | if (status & SCB_STRNR) { | ||
943 | if (ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS) & SCB_STRXSUSP) { | ||
944 | printk (KERN_WARNING "%s: RU went not ready: RU suspended\n", dev->name); | ||
945 | ether1_writew(dev, SCB_CMDRXRESUME, SCB_ADDR, scb_t, scb_command, NORMALIRQS); | ||
946 | writeb(CTRL_CA, REG_CONTROL); | ||
947 | priv(dev)->stats.rx_dropped ++; /* we suspended due to lack of buffer space */ | ||
948 | } else | ||
949 | printk(KERN_WARNING "%s: RU went not ready: %04X\n", dev->name, | ||
950 | ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS)); | ||
951 | printk (KERN_WARNING "RU ptr = %04X\n", ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, | ||
952 | NORMALIRQS)); | ||
953 | } | ||
954 | } else | ||
955 | writeb(CTRL_ACK, REG_CONTROL); | ||
956 | |||
957 | return IRQ_HANDLED; | ||
958 | } | ||
959 | |||
960 | static int | ||
961 | ether1_close (struct net_device *dev) | ||
962 | { | ||
963 | ether1_reset (dev); | ||
964 | |||
965 | free_irq(dev->irq, dev); | ||
966 | |||
967 | return 0; | ||
968 | } | ||
969 | |||
970 | static struct net_device_stats * | ||
971 | ether1_getstats (struct net_device *dev) | ||
972 | { | ||
973 | return &priv(dev)->stats; | ||
974 | } | ||
975 | |||
976 | /* | ||
977 | * Set or clear the multicast filter for this adaptor. | ||
978 | * num_addrs == -1 Promiscuous mode, receive all packets. | ||
979 | * num_addrs == 0 Normal mode, clear multicast list. | ||
980 | * num_addrs > 0 Multicast mode, receive normal and MC packets, and do | ||
981 | * best-effort filtering. | ||
982 | */ | ||
983 | static void | ||
984 | ether1_setmulticastlist (struct net_device *dev) | ||
985 | { | ||
986 | } | ||
987 | |||
988 | /* ------------------------------------------------------------------------- */ | ||
989 | |||
990 | static void __init ether1_banner(void) | ||
991 | { | ||
992 | static unsigned int version_printed = 0; | ||
993 | |||
994 | if (net_debug && version_printed++ == 0) | ||
995 | printk(KERN_INFO "%s", version); | ||
996 | } | ||
997 | |||
998 | static int __devinit | ||
999 | ether1_probe(struct expansion_card *ec, const struct ecard_id *id) | ||
1000 | { | ||
1001 | struct net_device *dev; | ||
1002 | int i, ret = 0; | ||
1003 | |||
1004 | ether1_banner(); | ||
1005 | |||
1006 | ret = ecard_request_resources(ec); | ||
1007 | if (ret) | ||
1008 | goto out; | ||
1009 | |||
1010 | dev = alloc_etherdev(sizeof(struct ether1_priv)); | ||
1011 | if (!dev) { | ||
1012 | ret = -ENOMEM; | ||
1013 | goto release; | ||
1014 | } | ||
1015 | |||
1016 | SET_MODULE_OWNER(dev); | ||
1017 | SET_NETDEV_DEV(dev, &ec->dev); | ||
1018 | |||
1019 | dev->irq = ec->irq; | ||
1020 | priv(dev)->base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCFAST), | ||
1021 | ecard_resource_len(ec, ECARD_RES_IOCFAST)); | ||
1022 | if (!priv(dev)->base) { | ||
1023 | ret = -ENOMEM; | ||
1024 | goto free; | ||
1025 | } | ||
1026 | |||
1027 | if ((priv(dev)->bus_type = ether1_reset(dev)) == 0) { | ||
1028 | ret = -ENODEV; | ||
1029 | goto free; | ||
1030 | } | ||
1031 | |||
1032 | for (i = 0; i < 6; i++) | ||
1033 | dev->dev_addr[i] = readb(IDPROM_ADDRESS + (i << 2)); | ||
1034 | |||
1035 | if (ether1_init_2(dev)) { | ||
1036 | ret = -ENODEV; | ||
1037 | goto free; | ||
1038 | } | ||
1039 | |||
1040 | dev->open = ether1_open; | ||
1041 | dev->stop = ether1_close; | ||
1042 | dev->hard_start_xmit = ether1_sendpacket; | ||
1043 | dev->get_stats = ether1_getstats; | ||
1044 | dev->set_multicast_list = ether1_setmulticastlist; | ||
1045 | dev->tx_timeout = ether1_timeout; | ||
1046 | dev->watchdog_timeo = 5 * HZ / 100; | ||
1047 | |||
1048 | ret = register_netdev(dev); | ||
1049 | if (ret) | ||
1050 | goto free; | ||
1051 | |||
1052 | printk(KERN_INFO "%s: ether1 in slot %d, ", | ||
1053 | dev->name, ec->slot_no); | ||
1054 | |||
1055 | for (i = 0; i < 6; i++) | ||
1056 | printk ("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); | ||
1057 | |||
1058 | ecard_set_drvdata(ec, dev); | ||
1059 | return 0; | ||
1060 | |||
1061 | free: | ||
1062 | if (priv(dev)->base) | ||
1063 | iounmap(priv(dev)->base); | ||
1064 | free_netdev(dev); | ||
1065 | release: | ||
1066 | ecard_release_resources(ec); | ||
1067 | out: | ||
1068 | return ret; | ||
1069 | } | ||
1070 | |||
1071 | static void __devexit ether1_remove(struct expansion_card *ec) | ||
1072 | { | ||
1073 | struct net_device *dev = ecard_get_drvdata(ec); | ||
1074 | |||
1075 | ecard_set_drvdata(ec, NULL); | ||
1076 | |||
1077 | unregister_netdev(dev); | ||
1078 | iounmap(priv(dev)->base); | ||
1079 | free_netdev(dev); | ||
1080 | ecard_release_resources(ec); | ||
1081 | } | ||
1082 | |||
1083 | static const struct ecard_id ether1_ids[] = { | ||
1084 | { MANU_ACORN, PROD_ACORN_ETHER1 }, | ||
1085 | { 0xffff, 0xffff } | ||
1086 | }; | ||
1087 | |||
1088 | static struct ecard_driver ether1_driver = { | ||
1089 | .probe = ether1_probe, | ||
1090 | .remove = __devexit_p(ether1_remove), | ||
1091 | .id_table = ether1_ids, | ||
1092 | .drv = { | ||
1093 | .name = "ether1", | ||
1094 | }, | ||
1095 | }; | ||
1096 | |||
1097 | static int __init ether1_init(void) | ||
1098 | { | ||
1099 | return ecard_register_driver(ðer1_driver); | ||
1100 | } | ||
1101 | |||
1102 | static void __exit ether1_exit(void) | ||
1103 | { | ||
1104 | ecard_remove_driver(ðer1_driver); | ||
1105 | } | ||
1106 | |||
1107 | module_init(ether1_init); | ||
1108 | module_exit(ether1_exit); | ||
1109 | |||
1110 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/arm/ether1.h b/drivers/net/arm/ether1.h new file mode 100644 index 000000000000..c8a4b2389d85 --- /dev/null +++ b/drivers/net/arm/ether1.h | |||
@@ -0,0 +1,281 @@ | |||
1 | /* | ||
2 | * linux/drivers/acorn/net/ether1.h | ||
3 | * | ||
4 | * Copyright (C) 1996 Russell King | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * Network driver for Acorn Ether1 cards. | ||
11 | */ | ||
12 | |||
13 | #ifndef _LINUX_ether1_H | ||
14 | #define _LINUX_ether1_H | ||
15 | |||
16 | #ifdef __ETHER1_C | ||
17 | /* use 0 for production, 1 for verification, >2 for debug */ | ||
18 | #ifndef NET_DEBUG | ||
19 | #define NET_DEBUG 0 | ||
20 | #endif | ||
21 | |||
22 | #define priv(dev) ((struct ether1_priv *)netdev_priv(dev)) | ||
23 | |||
24 | /* Page register */ | ||
25 | #define REG_PAGE (priv(dev)->base + 0x0000) | ||
26 | |||
27 | /* Control register */ | ||
28 | #define REG_CONTROL (priv(dev)->base + 0x0004) | ||
29 | #define CTRL_RST 0x01 | ||
30 | #define CTRL_LOOPBACK 0x02 | ||
31 | #define CTRL_CA 0x04 | ||
32 | #define CTRL_ACK 0x08 | ||
33 | |||
34 | #define ETHER1_RAM (priv(dev)->base + 0x2000) | ||
35 | |||
36 | /* HW address */ | ||
37 | #define IDPROM_ADDRESS (priv(dev)->base + 0x0024) | ||
38 | |||
39 | struct ether1_priv { | ||
40 | void __iomem *base; | ||
41 | struct net_device_stats stats; | ||
42 | unsigned int tx_link; | ||
43 | unsigned int tx_head; | ||
44 | volatile unsigned int tx_tail; | ||
45 | volatile unsigned int rx_head; | ||
46 | volatile unsigned int rx_tail; | ||
47 | unsigned char bus_type; | ||
48 | unsigned char resetting; | ||
49 | unsigned char initialising : 1; | ||
50 | unsigned char restart : 1; | ||
51 | }; | ||
52 | |||
53 | #define I82586_NULL (-1) | ||
54 | |||
55 | typedef struct { /* tdr */ | ||
56 | unsigned short tdr_status; | ||
57 | unsigned short tdr_command; | ||
58 | unsigned short tdr_link; | ||
59 | unsigned short tdr_result; | ||
60 | #define TDR_TIME (0x7ff) | ||
61 | #define TDR_SHORT (1 << 12) | ||
62 | #define TDR_OPEN (1 << 13) | ||
63 | #define TDR_XCVRPROB (1 << 14) | ||
64 | #define TDR_LNKOK (1 << 15) | ||
65 | } tdr_t; | ||
66 | |||
67 | typedef struct { /* transmit */ | ||
68 | unsigned short tx_status; | ||
69 | unsigned short tx_command; | ||
70 | unsigned short tx_link; | ||
71 | unsigned short tx_tbdoffset; | ||
72 | } tx_t; | ||
73 | |||
74 | typedef struct { /* tbd */ | ||
75 | unsigned short tbd_opts; | ||
76 | #define TBD_CNT (0x3fff) | ||
77 | #define TBD_EOL (1 << 15) | ||
78 | unsigned short tbd_link; | ||
79 | unsigned short tbd_bufl; | ||
80 | unsigned short tbd_bufh; | ||
81 | } tbd_t; | ||
82 | |||
83 | typedef struct { /* rfd */ | ||
84 | unsigned short rfd_status; | ||
85 | #define RFD_NOEOF (1 << 6) | ||
86 | #define RFD_FRAMESHORT (1 << 7) | ||
87 | #define RFD_DMAOVRN (1 << 8) | ||
88 | #define RFD_NORESOURCES (1 << 9) | ||
89 | #define RFD_ALIGNERROR (1 << 10) | ||
90 | #define RFD_CRCERROR (1 << 11) | ||
91 | #define RFD_OK (1 << 13) | ||
92 | #define RFD_FDCONSUMED (1 << 14) | ||
93 | #define RFD_COMPLETE (1 << 15) | ||
94 | unsigned short rfd_command; | ||
95 | #define RFD_CMDSUSPEND (1 << 14) | ||
96 | #define RFD_CMDEL (1 << 15) | ||
97 | unsigned short rfd_link; | ||
98 | unsigned short rfd_rbdoffset; | ||
99 | unsigned char rfd_dest[6]; | ||
100 | unsigned char rfd_src[6]; | ||
101 | unsigned short rfd_len; | ||
102 | } rfd_t; | ||
103 | |||
104 | typedef struct { /* rbd */ | ||
105 | unsigned short rbd_status; | ||
106 | #define RBD_ACNT (0x3fff) | ||
107 | #define RBD_ACNTVALID (1 << 14) | ||
108 | #define RBD_EOF (1 << 15) | ||
109 | unsigned short rbd_link; | ||
110 | unsigned short rbd_bufl; | ||
111 | unsigned short rbd_bufh; | ||
112 | unsigned short rbd_len; | ||
113 | } rbd_t; | ||
114 | |||
115 | typedef struct { /* nop */ | ||
116 | unsigned short nop_status; | ||
117 | unsigned short nop_command; | ||
118 | unsigned short nop_link; | ||
119 | } nop_t; | ||
120 | |||
121 | typedef struct { /* set multicast */ | ||
122 | unsigned short mc_status; | ||
123 | unsigned short mc_command; | ||
124 | unsigned short mc_link; | ||
125 | unsigned short mc_cnt; | ||
126 | unsigned char mc_addrs[1][6]; | ||
127 | } mc_t; | ||
128 | |||
129 | typedef struct { /* set address */ | ||
130 | unsigned short sa_status; | ||
131 | unsigned short sa_command; | ||
132 | unsigned short sa_link; | ||
133 | unsigned char sa_addr[6]; | ||
134 | } sa_t; | ||
135 | |||
136 | typedef struct { /* config command */ | ||
137 | unsigned short cfg_status; | ||
138 | unsigned short cfg_command; | ||
139 | unsigned short cfg_link; | ||
140 | unsigned char cfg_bytecnt; /* size foll data: 4 - 12 */ | ||
141 | unsigned char cfg_fifolim; /* FIFO threshold */ | ||
142 | unsigned char cfg_byte8; | ||
143 | #define CFG8_SRDY (1 << 6) | ||
144 | #define CFG8_SAVEBADF (1 << 7) | ||
145 | unsigned char cfg_byte9; | ||
146 | #define CFG9_ADDRLEN(x) (x) | ||
147 | #define CFG9_ADDRLENBUF (1 << 3) | ||
148 | #define CFG9_PREAMB2 (0 << 4) | ||
149 | #define CFG9_PREAMB4 (1 << 4) | ||
150 | #define CFG9_PREAMB8 (2 << 4) | ||
151 | #define CFG9_PREAMB16 (3 << 4) | ||
152 | #define CFG9_ILOOPBACK (1 << 6) | ||
153 | #define CFG9_ELOOPBACK (1 << 7) | ||
154 | unsigned char cfg_byte10; | ||
155 | #define CFG10_LINPRI(x) (x) | ||
156 | #define CFG10_ACR(x) (x << 4) | ||
157 | #define CFG10_BOFMET (1 << 7) | ||
158 | unsigned char cfg_ifs; | ||
159 | unsigned char cfg_slotl; | ||
160 | unsigned char cfg_byte13; | ||
161 | #define CFG13_SLOTH(x) (x) | ||
162 | #define CFG13_RETRY(x) (x << 4) | ||
163 | unsigned char cfg_byte14; | ||
164 | #define CFG14_PROMISC (1 << 0) | ||
165 | #define CFG14_DISBRD (1 << 1) | ||
166 | #define CFG14_MANCH (1 << 2) | ||
167 | #define CFG14_TNCRS (1 << 3) | ||
168 | #define CFG14_NOCRC (1 << 4) | ||
169 | #define CFG14_CRC16 (1 << 5) | ||
170 | #define CFG14_BTSTF (1 << 6) | ||
171 | #define CFG14_FLGPAD (1 << 7) | ||
172 | unsigned char cfg_byte15; | ||
173 | #define CFG15_CSTF(x) (x) | ||
174 | #define CFG15_ICSS (1 << 3) | ||
175 | #define CFG15_CDTF(x) (x << 4) | ||
176 | #define CFG15_ICDS (1 << 7) | ||
177 | unsigned short cfg_minfrmlen; | ||
178 | } cfg_t; | ||
179 | |||
180 | typedef struct { /* scb */ | ||
181 | unsigned short scb_status; /* status of 82586 */ | ||
182 | #define SCB_STRXMASK (7 << 4) /* Receive unit status */ | ||
183 | #define SCB_STRXIDLE (0 << 4) /* Idle */ | ||
184 | #define SCB_STRXSUSP (1 << 4) /* Suspended */ | ||
185 | #define SCB_STRXNRES (2 << 4) /* No resources */ | ||
186 | #define SCB_STRXRDY (4 << 4) /* Ready */ | ||
187 | #define SCB_STCUMASK (7 << 8) /* Command unit status */ | ||
188 | #define SCB_STCUIDLE (0 << 8) /* Idle */ | ||
189 | #define SCB_STCUSUSP (1 << 8) /* Suspended */ | ||
190 | #define SCB_STCUACTV (2 << 8) /* Active */ | ||
191 | #define SCB_STRNR (1 << 12) /* Receive unit not ready */ | ||
192 | #define SCB_STCNA (1 << 13) /* Command unit not ready */ | ||
193 | #define SCB_STFR (1 << 14) /* Frame received */ | ||
194 | #define SCB_STCX (1 << 15) /* Command completed */ | ||
195 | unsigned short scb_command; /* Next command */ | ||
196 | #define SCB_CMDRXSTART (1 << 4) /* Start (at rfa_offset) */ | ||
197 | #define SCB_CMDRXRESUME (2 << 4) /* Resume reception */ | ||
198 | #define SCB_CMDRXSUSPEND (3 << 4) /* Suspend reception */ | ||
199 | #define SCB_CMDRXABORT (4 << 4) /* Abort reception */ | ||
200 | #define SCB_CMDCUCSTART (1 << 8) /* Start (at cbl_offset) */ | ||
201 | #define SCB_CMDCUCRESUME (2 << 8) /* Resume execution */ | ||
202 | #define SCB_CMDCUCSUSPEND (3 << 8) /* Suspend execution */ | ||
203 | #define SCB_CMDCUCABORT (4 << 8) /* Abort execution */ | ||
204 | #define SCB_CMDACKRNR (1 << 12) /* Ack RU not ready */ | ||
205 | #define SCB_CMDACKCNA (1 << 13) /* Ack CU not ready */ | ||
206 | #define SCB_CMDACKFR (1 << 14) /* Ack Frame received */ | ||
207 | #define SCB_CMDACKCX (1 << 15) /* Ack Command complete */ | ||
208 | unsigned short scb_cbl_offset; /* Offset of first command unit */ | ||
209 | unsigned short scb_rfa_offset; /* Offset of first receive frame area */ | ||
210 | unsigned short scb_crc_errors; /* Properly aligned frame with CRC error*/ | ||
211 | unsigned short scb_aln_errors; /* Misaligned frames */ | ||
212 | unsigned short scb_rsc_errors; /* Frames lost due to no space */ | ||
213 | unsigned short scb_ovn_errors; /* Frames lost due to slow bus */ | ||
214 | } scb_t; | ||
215 | |||
216 | typedef struct { /* iscp */ | ||
217 | unsigned short iscp_busy; /* set by CPU before CA */ | ||
218 | unsigned short iscp_offset; /* offset of SCB */ | ||
219 | unsigned short iscp_basel; /* base of SCB */ | ||
220 | unsigned short iscp_baseh; | ||
221 | } iscp_t; | ||
222 | |||
223 | /* this address must be 0xfff6 */ | ||
224 | typedef struct { /* scp */ | ||
225 | unsigned short scp_sysbus; /* bus size */ | ||
226 | #define SCP_SY_16BBUS 0x00 | ||
227 | #define SCP_SY_8BBUS 0x01 | ||
228 | unsigned short scp_junk[2]; /* junk */ | ||
229 | unsigned short scp_iscpl; /* lower 16 bits of iscp */ | ||
230 | unsigned short scp_iscph; /* upper 16 bits of iscp */ | ||
231 | } scp_t; | ||
232 | |||
233 | /* commands */ | ||
234 | #define CMD_NOP 0 | ||
235 | #define CMD_SETADDRESS 1 | ||
236 | #define CMD_CONFIG 2 | ||
237 | #define CMD_SETMULTICAST 3 | ||
238 | #define CMD_TX 4 | ||
239 | #define CMD_TDR 5 | ||
240 | #define CMD_DUMP 6 | ||
241 | #define CMD_DIAGNOSE 7 | ||
242 | |||
243 | #define CMD_MASK 7 | ||
244 | |||
245 | #define CMD_INTR (1 << 13) | ||
246 | #define CMD_SUSP (1 << 14) | ||
247 | #define CMD_EOL (1 << 15) | ||
248 | |||
249 | #define STAT_COLLISIONS (15) | ||
250 | #define STAT_COLLEXCESSIVE (1 << 5) | ||
251 | #define STAT_COLLAFTERTX (1 << 6) | ||
252 | #define STAT_TXDEFERRED (1 << 7) | ||
253 | #define STAT_TXSLOWDMA (1 << 8) | ||
254 | #define STAT_TXLOSTCTS (1 << 9) | ||
255 | #define STAT_NOCARRIER (1 << 10) | ||
256 | #define STAT_FAIL (1 << 11) | ||
257 | #define STAT_ABORTED (1 << 12) | ||
258 | #define STAT_OK (1 << 13) | ||
259 | #define STAT_BUSY (1 << 14) | ||
260 | #define STAT_COMPLETE (1 << 15) | ||
261 | #endif | ||
262 | #endif | ||
263 | |||
264 | /* | ||
265 | * Ether1 card definitions: | ||
266 | * | ||
267 | * FAST accesses: | ||
268 | * +0 Page register | ||
269 | * 16 pages | ||
270 | * +4 Control | ||
271 | * '1' = reset | ||
272 | * '2' = loopback | ||
273 | * '4' = CA | ||
274 | * '8' = int ack | ||
275 | * | ||
276 | * RAM at address + 0x2000 | ||
277 | * Pod. Prod id = 3 | ||
278 | * Words after ID block [base + 8 words] | ||
279 | * +0 pcb issue (0x0c and 0xf3 invalid) | ||
280 | * +1 - +6 eth hw address | ||
281 | */ | ||
diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c new file mode 100644 index 000000000000..1cc53abc3a39 --- /dev/null +++ b/drivers/net/arm/ether3.c | |||
@@ -0,0 +1,936 @@ | |||
1 | /* | ||
2 | * linux/drivers/acorn/net/ether3.c | ||
3 | * | ||
4 | * Copyright (C) 1995-2000 Russell King | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * SEEQ nq8005 ethernet driver for Acorn/ANT Ether3 card | ||
11 | * for Acorn machines | ||
12 | * | ||
13 | * By Russell King, with some suggestions from borris@ant.co.uk | ||
14 | * | ||
15 | * Changelog: | ||
16 | * 1.04 RMK 29/02/1996 Won't pass packets that are from our ethernet | ||
17 | * address up to the higher levels - they're | ||
18 | * silently ignored. I/F can now be put into | ||
19 | * multicast mode. Receiver routine optimised. | ||
20 | * 1.05 RMK 30/02/1996 Now claims interrupt at open when part of | ||
21 | * the kernel rather than when a module. | ||
22 | * 1.06 RMK 02/03/1996 Various code cleanups | ||
23 | * 1.07 RMK 13/10/1996 Optimised interrupt routine and transmit | ||
24 | * routines. | ||
25 | * 1.08 RMK 14/10/1996 Fixed problem with too many packets, | ||
26 | * prevented the kernel message about dropped | ||
27 | * packets appearing too many times a second. | ||
28 | * Now does not disable all IRQs, only the IRQ | ||
29 | * used by this card. | ||
30 | * 1.09 RMK 10/11/1996 Only enables TX irq when buffer space is low, | ||
31 | * but we still service the TX queue if we get a | ||
32 | * RX interrupt. | ||
33 | * 1.10 RMK 15/07/1997 Fixed autoprobing of NQ8004. | ||
34 | * 1.11 RMK 16/11/1997 Fixed autoprobing of NQ8005A. | ||
35 | * 1.12 RMK 31/12/1997 Removed reference to dev_tint for Linux 2.1. | ||
36 | * RMK 27/06/1998 Changed asm/delay.h to linux/delay.h. | ||
37 | * 1.13 RMK 29/06/1998 Fixed problem with transmission of packets. | ||
38 | * Chip seems to have a bug in, whereby if the | ||
39 | * packet starts two bytes from the end of the | ||
40 | * buffer, it corrupts the receiver chain, and | ||
41 | * never updates the transmit status correctly. | ||
42 | * 1.14 RMK 07/01/1998 Added initial code for ETHERB addressing. | ||
43 | * 1.15 RMK 30/04/1999 More fixes to the transmit routine for buggy | ||
44 | * hardware. | ||
45 | * 1.16 RMK 10/02/2000 Updated for 2.3.43 | ||
46 | * 1.17 RMK 13/05/2000 Updated for 2.3.99-pre8 | ||
47 | */ | ||
48 | |||
49 | #include <linux/module.h> | ||
50 | #include <linux/kernel.h> | ||
51 | #include <linux/sched.h> | ||
52 | #include <linux/types.h> | ||
53 | #include <linux/fcntl.h> | ||
54 | #include <linux/interrupt.h> | ||
55 | #include <linux/ptrace.h> | ||
56 | #include <linux/ioport.h> | ||
57 | #include <linux/in.h> | ||
58 | #include <linux/slab.h> | ||
59 | #include <linux/string.h> | ||
60 | #include <linux/errno.h> | ||
61 | #include <linux/netdevice.h> | ||
62 | #include <linux/etherdevice.h> | ||
63 | #include <linux/skbuff.h> | ||
64 | #include <linux/device.h> | ||
65 | #include <linux/init.h> | ||
66 | #include <linux/delay.h> | ||
67 | #include <linux/bitops.h> | ||
68 | |||
69 | #include <asm/system.h> | ||
70 | #include <asm/ecard.h> | ||
71 | #include <asm/io.h> | ||
72 | #include <asm/irq.h> | ||
73 | |||
74 | static char version[] __initdata = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n"; | ||
75 | |||
76 | #include "ether3.h" | ||
77 | |||
78 | static unsigned int net_debug = NET_DEBUG; | ||
79 | |||
80 | static void ether3_setmulticastlist(struct net_device *dev); | ||
81 | static int ether3_rx(struct net_device *dev, unsigned int maxcnt); | ||
82 | static void ether3_tx(struct net_device *dev); | ||
83 | static int ether3_open (struct net_device *dev); | ||
84 | static int ether3_sendpacket (struct sk_buff *skb, struct net_device *dev); | ||
85 | static irqreturn_t ether3_interrupt (int irq, void *dev_id, struct pt_regs *regs); | ||
86 | static int ether3_close (struct net_device *dev); | ||
87 | static struct net_device_stats *ether3_getstats (struct net_device *dev); | ||
88 | static void ether3_setmulticastlist (struct net_device *dev); | ||
89 | static void ether3_timeout(struct net_device *dev); | ||
90 | |||
91 | #define BUS_16 2 | ||
92 | #define BUS_8 1 | ||
93 | #define BUS_UNKNOWN 0 | ||
94 | |||
95 | /* --------------------------------------------------------------------------- */ | ||
96 | |||
97 | typedef enum { | ||
98 | buffer_write, | ||
99 | buffer_read | ||
100 | } buffer_rw_t; | ||
101 | |||
102 | /* | ||
103 | * ether3 read/write. Slow things down a bit... | ||
104 | * The SEEQ8005 doesn't like us writing to its registers | ||
105 | * too quickly. | ||
106 | */ | ||
107 | static inline void ether3_outb(int v, const void __iomem *r) | ||
108 | { | ||
109 | writeb(v, r); | ||
110 | udelay(1); | ||
111 | } | ||
112 | |||
113 | static inline void ether3_outw(int v, const void __iomem *r) | ||
114 | { | ||
115 | writew(v, r); | ||
116 | udelay(1); | ||
117 | } | ||
118 | #define ether3_inb(r) ({ unsigned int __v = readb((r)); udelay(1); __v; }) | ||
119 | #define ether3_inw(r) ({ unsigned int __v = readw((r)); udelay(1); __v; }) | ||
120 | |||
121 | static int | ||
122 | ether3_setbuffer(struct net_device *dev, buffer_rw_t read, int start) | ||
123 | { | ||
124 | int timeout = 1000; | ||
125 | |||
126 | ether3_outw(priv(dev)->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); | ||
127 | ether3_outw(priv(dev)->regs.command | CMD_FIFOWRITE, REG_COMMAND); | ||
128 | |||
129 | while ((ether3_inw(REG_STATUS) & STAT_FIFOEMPTY) == 0) { | ||
130 | if (!timeout--) { | ||
131 | printk("%s: setbuffer broken\n", dev->name); | ||
132 | priv(dev)->broken = 1; | ||
133 | return 1; | ||
134 | } | ||
135 | udelay(1); | ||
136 | } | ||
137 | |||
138 | if (read == buffer_read) { | ||
139 | ether3_outw(start, REG_DMAADDR); | ||
140 | ether3_outw(priv(dev)->regs.command | CMD_FIFOREAD, REG_COMMAND); | ||
141 | } else { | ||
142 | ether3_outw(priv(dev)->regs.command | CMD_FIFOWRITE, REG_COMMAND); | ||
143 | ether3_outw(start, REG_DMAADDR); | ||
144 | } | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * write data to the buffer memory | ||
150 | */ | ||
151 | #define ether3_writebuffer(dev,data,length) \ | ||
152 | writesw(REG_BUFWIN, (data), (length) >> 1) | ||
153 | |||
154 | #define ether3_writeword(dev,data) \ | ||
155 | writew((data), REG_BUFWIN) | ||
156 | |||
157 | #define ether3_writelong(dev,data) { \ | ||
158 | void __iomem *reg_bufwin = REG_BUFWIN; \ | ||
159 | writew((data), reg_bufwin); \ | ||
160 | writew((data) >> 16, reg_bufwin); \ | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * read data from the buffer memory | ||
165 | */ | ||
166 | #define ether3_readbuffer(dev,data,length) \ | ||
167 | readsw(REG_BUFWIN, (data), (length) >> 1) | ||
168 | |||
169 | #define ether3_readword(dev) \ | ||
170 | readw(REG_BUFWIN) | ||
171 | |||
172 | #define ether3_readlong(dev) \ | ||
173 | readw(REG_BUFWIN) | (readw(REG_BUFWIN) << 16) | ||
174 | |||
175 | /* | ||
176 | * Switch LED off... | ||
177 | */ | ||
178 | static void ether3_ledoff(unsigned long data) | ||
179 | { | ||
180 | struct net_device *dev = (struct net_device *)data; | ||
181 | ether3_outw(priv(dev)->regs.config2 |= CFG2_CTRLO, REG_CONFIG2); | ||
182 | } | ||
183 | |||
184 | /* | ||
185 | * switch LED on... | ||
186 | */ | ||
187 | static inline void ether3_ledon(struct net_device *dev) | ||
188 | { | ||
189 | del_timer(&priv(dev)->timer); | ||
190 | priv(dev)->timer.expires = jiffies + HZ / 50; /* leave on for 1/50th second */ | ||
191 | priv(dev)->timer.data = (unsigned long)dev; | ||
192 | priv(dev)->timer.function = ether3_ledoff; | ||
193 | add_timer(&priv(dev)->timer); | ||
194 | if (priv(dev)->regs.config2 & CFG2_CTRLO) | ||
195 | ether3_outw(priv(dev)->regs.config2 &= ~CFG2_CTRLO, REG_CONFIG2); | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * Read the ethernet address string from the on board rom. | ||
200 | * This is an ascii string!!! | ||
201 | */ | ||
202 | static int __init | ||
203 | ether3_addr(char *addr, struct expansion_card *ec) | ||
204 | { | ||
205 | struct in_chunk_dir cd; | ||
206 | char *s; | ||
207 | |||
208 | if (ecard_readchunk(&cd, ec, 0xf5, 0) && (s = strchr(cd.d.string, '('))) { | ||
209 | int i; | ||
210 | for (i = 0; i<6; i++) { | ||
211 | addr[i] = simple_strtoul(s + 1, &s, 0x10); | ||
212 | if (*s != (i==5?')' : ':' )) | ||
213 | break; | ||
214 | } | ||
215 | if (i == 6) | ||
216 | return 0; | ||
217 | } | ||
218 | /* I wonder if we should even let the user continue in this case | ||
219 | * - no, it would be better to disable the device | ||
220 | */ | ||
221 | printk(KERN_ERR "ether3: Couldn't read a valid MAC address from card.\n"); | ||
222 | return -ENODEV; | ||
223 | } | ||
224 | |||
225 | /* --------------------------------------------------------------------------- */ | ||
226 | |||
227 | static int __init | ||
228 | ether3_ramtest(struct net_device *dev, unsigned char byte) | ||
229 | { | ||
230 | unsigned char *buffer = kmalloc(RX_END, GFP_KERNEL); | ||
231 | int i,ret = 0; | ||
232 | int max_errors = 4; | ||
233 | int bad = -1; | ||
234 | |||
235 | if (!buffer) | ||
236 | return 1; | ||
237 | |||
238 | memset(buffer, byte, RX_END); | ||
239 | ether3_setbuffer(dev, buffer_write, 0); | ||
240 | ether3_writebuffer(dev, buffer, TX_END); | ||
241 | ether3_setbuffer(dev, buffer_write, RX_START); | ||
242 | ether3_writebuffer(dev, buffer + RX_START, RX_LEN); | ||
243 | memset(buffer, byte ^ 0xff, RX_END); | ||
244 | ether3_setbuffer(dev, buffer_read, 0); | ||
245 | ether3_readbuffer(dev, buffer, TX_END); | ||
246 | ether3_setbuffer(dev, buffer_read, RX_START); | ||
247 | ether3_readbuffer(dev, buffer + RX_START, RX_LEN); | ||
248 | |||
249 | for (i = 0; i < RX_END; i++) { | ||
250 | if (buffer[i] != byte) { | ||
251 | if (max_errors > 0 && bad != buffer[i]) { | ||
252 | printk("%s: RAM failed with (%02X instead of %02X) at 0x%04X", | ||
253 | dev->name, buffer[i], byte, i); | ||
254 | ret = 2; | ||
255 | max_errors--; | ||
256 | bad = i; | ||
257 | } | ||
258 | } else { | ||
259 | if (bad != -1) { | ||
260 | if (bad != i - 1) | ||
261 | printk(" - 0x%04X\n", i - 1); | ||
262 | printk("\n"); | ||
263 | bad = -1; | ||
264 | } | ||
265 | } | ||
266 | } | ||
267 | if (bad != -1) | ||
268 | printk(" - 0xffff\n"); | ||
269 | kfree(buffer); | ||
270 | |||
271 | return ret; | ||
272 | } | ||
273 | |||
274 | /* ------------------------------------------------------------------------------- */ | ||
275 | |||
276 | static int __init ether3_init_2(struct net_device *dev) | ||
277 | { | ||
278 | int i; | ||
279 | |||
280 | priv(dev)->regs.config1 = CFG1_RECVCOMPSTAT0|CFG1_DMABURST8; | ||
281 | priv(dev)->regs.config2 = CFG2_CTRLO|CFG2_RECVCRC|CFG2_ERRENCRC; | ||
282 | priv(dev)->regs.command = 0; | ||
283 | |||
284 | /* | ||
285 | * Set up our hardware address | ||
286 | */ | ||
287 | ether3_outw(priv(dev)->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1); | ||
288 | for (i = 0; i < 6; i++) | ||
289 | ether3_outb(dev->dev_addr[i], REG_BUFWIN); | ||
290 | |||
291 | if (dev->flags & IFF_PROMISC) | ||
292 | priv(dev)->regs.config1 |= CFG1_RECVPROMISC; | ||
293 | else if (dev->flags & IFF_MULTICAST) | ||
294 | priv(dev)->regs.config1 |= CFG1_RECVSPECBRMULTI; | ||
295 | else | ||
296 | priv(dev)->regs.config1 |= CFG1_RECVSPECBROAD; | ||
297 | |||
298 | /* | ||
299 | * There is a problem with the NQ8005 in that it occasionally loses the | ||
300 | * last two bytes. To get round this problem, we receive the CRC as | ||
301 | * well. That way, if we do lose the last two, then it doesn't matter. | ||
302 | */ | ||
303 | ether3_outw(priv(dev)->regs.config1 | CFG1_TRANSEND, REG_CONFIG1); | ||
304 | ether3_outw((TX_END>>8) - 1, REG_BUFWIN); | ||
305 | ether3_outw(priv(dev)->rx_head, REG_RECVPTR); | ||
306 | ether3_outw(0, REG_TRANSMITPTR); | ||
307 | ether3_outw(priv(dev)->rx_head >> 8, REG_RECVEND); | ||
308 | ether3_outw(priv(dev)->regs.config2, REG_CONFIG2); | ||
309 | ether3_outw(priv(dev)->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); | ||
310 | ether3_outw(priv(dev)->regs.command, REG_COMMAND); | ||
311 | |||
312 | i = ether3_ramtest(dev, 0x5A); | ||
313 | if(i) | ||
314 | return i; | ||
315 | i = ether3_ramtest(dev, 0x1E); | ||
316 | if(i) | ||
317 | return i; | ||
318 | |||
319 | ether3_setbuffer(dev, buffer_write, 0); | ||
320 | ether3_writelong(dev, 0); | ||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | static void | ||
325 | ether3_init_for_open(struct net_device *dev) | ||
326 | { | ||
327 | int i; | ||
328 | |||
329 | memset(&priv(dev)->stats, 0, sizeof(struct net_device_stats)); | ||
330 | |||
331 | /* Reset the chip */ | ||
332 | ether3_outw(CFG2_RESET, REG_CONFIG2); | ||
333 | udelay(4); | ||
334 | |||
335 | priv(dev)->regs.command = 0; | ||
336 | ether3_outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND); | ||
337 | while (ether3_inw(REG_STATUS) & (STAT_RXON|STAT_TXON)) | ||
338 | barrier(); | ||
339 | |||
340 | ether3_outw(priv(dev)->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1); | ||
341 | for (i = 0; i < 6; i++) | ||
342 | ether3_outb(dev->dev_addr[i], REG_BUFWIN); | ||
343 | |||
344 | priv(dev)->tx_head = 0; | ||
345 | priv(dev)->tx_tail = 0; | ||
346 | priv(dev)->regs.config2 |= CFG2_CTRLO; | ||
347 | priv(dev)->rx_head = RX_START; | ||
348 | |||
349 | ether3_outw(priv(dev)->regs.config1 | CFG1_TRANSEND, REG_CONFIG1); | ||
350 | ether3_outw((TX_END>>8) - 1, REG_BUFWIN); | ||
351 | ether3_outw(priv(dev)->rx_head, REG_RECVPTR); | ||
352 | ether3_outw(priv(dev)->rx_head >> 8, REG_RECVEND); | ||
353 | ether3_outw(0, REG_TRANSMITPTR); | ||
354 | ether3_outw(priv(dev)->regs.config2, REG_CONFIG2); | ||
355 | ether3_outw(priv(dev)->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); | ||
356 | |||
357 | ether3_setbuffer(dev, buffer_write, 0); | ||
358 | ether3_writelong(dev, 0); | ||
359 | |||
360 | priv(dev)->regs.command = CMD_ENINTRX | CMD_ENINTTX; | ||
361 | ether3_outw(priv(dev)->regs.command | CMD_RXON, REG_COMMAND); | ||
362 | } | ||
363 | |||
364 | static inline int | ||
365 | ether3_probe_bus_8(struct net_device *dev, int val) | ||
366 | { | ||
367 | int write_low, write_high, read_low, read_high; | ||
368 | |||
369 | write_low = val & 255; | ||
370 | write_high = val >> 8; | ||
371 | |||
372 | printk(KERN_DEBUG "ether3_probe: write8 [%02X:%02X]", write_high, write_low); | ||
373 | |||
374 | ether3_outb(write_low, REG_RECVPTR); | ||
375 | ether3_outb(write_high, REG_RECVPTR + 4); | ||
376 | |||
377 | read_low = ether3_inb(REG_RECVPTR); | ||
378 | read_high = ether3_inb(REG_RECVPTR + 4); | ||
379 | |||
380 | printk(", read8 [%02X:%02X]\n", read_high, read_low); | ||
381 | |||
382 | return read_low == write_low && read_high == write_high; | ||
383 | } | ||
384 | |||
385 | static inline int | ||
386 | ether3_probe_bus_16(struct net_device *dev, int val) | ||
387 | { | ||
388 | int read_val; | ||
389 | |||
390 | ether3_outw(val, REG_RECVPTR); | ||
391 | read_val = ether3_inw(REG_RECVPTR); | ||
392 | |||
393 | printk(KERN_DEBUG "ether3_probe: write16 [%04X], read16 [%04X]\n", val, read_val); | ||
394 | |||
395 | return read_val == val; | ||
396 | } | ||
397 | |||
398 | /* | ||
399 | * Open/initialize the board. This is called (in the current kernel) | ||
400 | * sometime after booting when the 'ifconfig' program is run. | ||
401 | * | ||
402 | * This routine should set everything up anew at each open, even | ||
403 | * registers that "should" only need to be set once at boot, so that | ||
404 | * there is non-reboot way to recover if something goes wrong. | ||
405 | */ | ||
406 | static int | ||
407 | ether3_open(struct net_device *dev) | ||
408 | { | ||
409 | if (!is_valid_ether_addr(dev->dev_addr)) { | ||
410 | printk(KERN_WARNING "%s: invalid ethernet MAC address\n", | ||
411 | dev->name); | ||
412 | return -EINVAL; | ||
413 | } | ||
414 | |||
415 | if (request_irq(dev->irq, ether3_interrupt, 0, "ether3", dev)) | ||
416 | return -EAGAIN; | ||
417 | |||
418 | ether3_init_for_open(dev); | ||
419 | |||
420 | netif_start_queue(dev); | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | /* | ||
426 | * The inverse routine to ether3_open(). | ||
427 | */ | ||
428 | static int | ||
429 | ether3_close(struct net_device *dev) | ||
430 | { | ||
431 | netif_stop_queue(dev); | ||
432 | |||
433 | disable_irq(dev->irq); | ||
434 | |||
435 | ether3_outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND); | ||
436 | priv(dev)->regs.command = 0; | ||
437 | while (ether3_inw(REG_STATUS) & (STAT_RXON|STAT_TXON)) | ||
438 | barrier(); | ||
439 | ether3_outb(0x80, REG_CONFIG2 + 4); | ||
440 | ether3_outw(0, REG_COMMAND); | ||
441 | |||
442 | free_irq(dev->irq, dev); | ||
443 | |||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | /* | ||
448 | * Get the current statistics. This may be called with the card open or | ||
449 | * closed. | ||
450 | */ | ||
451 | static struct net_device_stats *ether3_getstats(struct net_device *dev) | ||
452 | { | ||
453 | return &priv(dev)->stats; | ||
454 | } | ||
455 | |||
456 | /* | ||
457 | * Set or clear promiscuous/multicast mode filter for this adaptor. | ||
458 | * | ||
459 | * We don't attempt any packet filtering. The card may have a SEEQ 8004 | ||
460 | * in which does not have the other ethernet address registers present... | ||
461 | */ | ||
462 | static void ether3_setmulticastlist(struct net_device *dev) | ||
463 | { | ||
464 | priv(dev)->regs.config1 &= ~CFG1_RECVPROMISC; | ||
465 | |||
466 | if (dev->flags & IFF_PROMISC) { | ||
467 | /* promiscuous mode */ | ||
468 | priv(dev)->regs.config1 |= CFG1_RECVPROMISC; | ||
469 | } else if (dev->flags & IFF_ALLMULTI) { | ||
470 | priv(dev)->regs.config1 |= CFG1_RECVSPECBRMULTI; | ||
471 | } else | ||
472 | priv(dev)->regs.config1 |= CFG1_RECVSPECBROAD; | ||
473 | |||
474 | ether3_outw(priv(dev)->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); | ||
475 | } | ||
476 | |||
477 | static void ether3_timeout(struct net_device *dev) | ||
478 | { | ||
479 | unsigned long flags; | ||
480 | |||
481 | del_timer(&priv(dev)->timer); | ||
482 | |||
483 | local_irq_save(flags); | ||
484 | printk(KERN_ERR "%s: transmit timed out, network cable problem?\n", dev->name); | ||
485 | printk(KERN_ERR "%s: state: { status=%04X cfg1=%04X cfg2=%04X }\n", dev->name, | ||
486 | ether3_inw(REG_STATUS), ether3_inw(REG_CONFIG1), ether3_inw(REG_CONFIG2)); | ||
487 | printk(KERN_ERR "%s: { rpr=%04X rea=%04X tpr=%04X }\n", dev->name, | ||
488 | ether3_inw(REG_RECVPTR), ether3_inw(REG_RECVEND), ether3_inw(REG_TRANSMITPTR)); | ||
489 | printk(KERN_ERR "%s: tx head=%X tx tail=%X\n", dev->name, | ||
490 | priv(dev)->tx_head, priv(dev)->tx_tail); | ||
491 | ether3_setbuffer(dev, buffer_read, priv(dev)->tx_tail); | ||
492 | printk(KERN_ERR "%s: packet status = %08X\n", dev->name, ether3_readlong(dev)); | ||
493 | local_irq_restore(flags); | ||
494 | |||
495 | priv(dev)->regs.config2 |= CFG2_CTRLO; | ||
496 | priv(dev)->stats.tx_errors += 1; | ||
497 | ether3_outw(priv(dev)->regs.config2, REG_CONFIG2); | ||
498 | priv(dev)->tx_head = priv(dev)->tx_tail = 0; | ||
499 | |||
500 | netif_wake_queue(dev); | ||
501 | } | ||
502 | |||
503 | /* | ||
504 | * Transmit a packet | ||
505 | */ | ||
506 | static int | ||
507 | ether3_sendpacket(struct sk_buff *skb, struct net_device *dev) | ||
508 | { | ||
509 | unsigned long flags; | ||
510 | unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; | ||
511 | unsigned int ptr, next_ptr; | ||
512 | |||
513 | if (priv(dev)->broken) { | ||
514 | dev_kfree_skb(skb); | ||
515 | priv(dev)->stats.tx_dropped ++; | ||
516 | netif_start_queue(dev); | ||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | length = (length + 1) & ~1; | ||
521 | if (length != skb->len) { | ||
522 | skb = skb_padto(skb, length); | ||
523 | if (skb == NULL) | ||
524 | goto out; | ||
525 | } | ||
526 | |||
527 | next_ptr = (priv(dev)->tx_head + 1) & 15; | ||
528 | |||
529 | local_irq_save(flags); | ||
530 | |||
531 | if (priv(dev)->tx_tail == next_ptr) { | ||
532 | local_irq_restore(flags); | ||
533 | return 1; /* unable to queue */ | ||
534 | } | ||
535 | |||
536 | dev->trans_start = jiffies; | ||
537 | ptr = 0x600 * priv(dev)->tx_head; | ||
538 | priv(dev)->tx_head = next_ptr; | ||
539 | next_ptr *= 0x600; | ||
540 | |||
541 | #define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS) | ||
542 | |||
543 | ether3_setbuffer(dev, buffer_write, next_ptr); | ||
544 | ether3_writelong(dev, 0); | ||
545 | ether3_setbuffer(dev, buffer_write, ptr); | ||
546 | ether3_writelong(dev, 0); | ||
547 | ether3_writebuffer(dev, skb->data, length); | ||
548 | ether3_writeword(dev, htons(next_ptr)); | ||
549 | ether3_writeword(dev, TXHDR_CHAINCONTINUE >> 16); | ||
550 | ether3_setbuffer(dev, buffer_write, ptr); | ||
551 | ether3_writeword(dev, htons((ptr + length + 4))); | ||
552 | ether3_writeword(dev, TXHDR_FLAGS >> 16); | ||
553 | ether3_ledon(dev); | ||
554 | |||
555 | if (!(ether3_inw(REG_STATUS) & STAT_TXON)) { | ||
556 | ether3_outw(ptr, REG_TRANSMITPTR); | ||
557 | ether3_outw(priv(dev)->regs.command | CMD_TXON, REG_COMMAND); | ||
558 | } | ||
559 | |||
560 | next_ptr = (priv(dev)->tx_head + 1) & 15; | ||
561 | local_irq_restore(flags); | ||
562 | |||
563 | dev_kfree_skb(skb); | ||
564 | |||
565 | if (priv(dev)->tx_tail == next_ptr) | ||
566 | netif_stop_queue(dev); | ||
567 | |||
568 | out: | ||
569 | return 0; | ||
570 | } | ||
571 | |||
572 | static irqreturn_t | ||
573 | ether3_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
574 | { | ||
575 | struct net_device *dev = (struct net_device *)dev_id; | ||
576 | unsigned int status, handled = IRQ_NONE; | ||
577 | |||
578 | #if NET_DEBUG > 1 | ||
579 | if(net_debug & DEBUG_INT) | ||
580 | printk("eth3irq: %d ", irq); | ||
581 | #endif | ||
582 | |||
583 | status = ether3_inw(REG_STATUS); | ||
584 | |||
585 | if (status & STAT_INTRX) { | ||
586 | ether3_outw(CMD_ACKINTRX | priv(dev)->regs.command, REG_COMMAND); | ||
587 | ether3_rx(dev, 12); | ||
588 | handled = IRQ_HANDLED; | ||
589 | } | ||
590 | |||
591 | if (status & STAT_INTTX) { | ||
592 | ether3_outw(CMD_ACKINTTX | priv(dev)->regs.command, REG_COMMAND); | ||
593 | ether3_tx(dev); | ||
594 | handled = IRQ_HANDLED; | ||
595 | } | ||
596 | |||
597 | #if NET_DEBUG > 1 | ||
598 | if(net_debug & DEBUG_INT) | ||
599 | printk("done\n"); | ||
600 | #endif | ||
601 | return handled; | ||
602 | } | ||
603 | |||
604 | /* | ||
605 | * If we have a good packet(s), get it/them out of the buffers. | ||
606 | */ | ||
607 | static int ether3_rx(struct net_device *dev, unsigned int maxcnt) | ||
608 | { | ||
609 | unsigned int next_ptr = priv(dev)->rx_head, received = 0; | ||
610 | |||
611 | ether3_ledon(dev); | ||
612 | |||
613 | do { | ||
614 | unsigned int this_ptr, status; | ||
615 | unsigned char addrs[16]; | ||
616 | |||
617 | /* | ||
618 | * read the first 16 bytes from the buffer. | ||
619 | * This contains the status bytes etc and ethernet addresses, | ||
620 | * and we also check the source ethernet address to see if | ||
621 | * it originated from us. | ||
622 | */ | ||
623 | { | ||
624 | unsigned int temp_ptr; | ||
625 | ether3_setbuffer(dev, buffer_read, next_ptr); | ||
626 | temp_ptr = ether3_readword(dev); | ||
627 | status = ether3_readword(dev); | ||
628 | if ((status & (RXSTAT_DONE | RXHDR_CHAINCONTINUE | RXHDR_RECEIVE)) != | ||
629 | (RXSTAT_DONE | RXHDR_CHAINCONTINUE) || !temp_ptr) | ||
630 | break; | ||
631 | |||
632 | this_ptr = next_ptr + 4; | ||
633 | next_ptr = ntohs(temp_ptr); | ||
634 | } | ||
635 | ether3_setbuffer(dev, buffer_read, this_ptr); | ||
636 | ether3_readbuffer(dev, addrs+2, 12); | ||
637 | |||
638 | if (next_ptr < RX_START || next_ptr >= RX_END) { | ||
639 | int i; | ||
640 | printk("%s: bad next pointer @%04X: ", dev->name, priv(dev)->rx_head); | ||
641 | printk("%02X %02X %02X %02X ", next_ptr >> 8, next_ptr & 255, status & 255, status >> 8); | ||
642 | for (i = 2; i < 14; i++) | ||
643 | printk("%02X ", addrs[i]); | ||
644 | printk("\n"); | ||
645 | next_ptr = priv(dev)->rx_head; | ||
646 | break; | ||
647 | } | ||
648 | /* | ||
649 | * ignore our own packets... | ||
650 | */ | ||
651 | if (!(*(unsigned long *)&dev->dev_addr[0] ^ *(unsigned long *)&addrs[2+6]) && | ||
652 | !(*(unsigned short *)&dev->dev_addr[4] ^ *(unsigned short *)&addrs[2+10])) { | ||
653 | maxcnt ++; /* compensate for loopedback packet */ | ||
654 | ether3_outw(next_ptr >> 8, REG_RECVEND); | ||
655 | } else | ||
656 | if (!(status & (RXSTAT_OVERSIZE|RXSTAT_CRCERROR|RXSTAT_DRIBBLEERROR|RXSTAT_SHORTPACKET))) { | ||
657 | unsigned int length = next_ptr - this_ptr; | ||
658 | struct sk_buff *skb; | ||
659 | |||
660 | if (next_ptr <= this_ptr) | ||
661 | length += RX_END - RX_START; | ||
662 | |||
663 | skb = dev_alloc_skb(length + 2); | ||
664 | if (skb) { | ||
665 | unsigned char *buf; | ||
666 | |||
667 | skb->dev = dev; | ||
668 | skb_reserve(skb, 2); | ||
669 | buf = skb_put(skb, length); | ||
670 | ether3_readbuffer(dev, buf + 12, length - 12); | ||
671 | ether3_outw(next_ptr >> 8, REG_RECVEND); | ||
672 | *(unsigned short *)(buf + 0) = *(unsigned short *)(addrs + 2); | ||
673 | *(unsigned long *)(buf + 2) = *(unsigned long *)(addrs + 4); | ||
674 | *(unsigned long *)(buf + 6) = *(unsigned long *)(addrs + 8); | ||
675 | *(unsigned short *)(buf + 10) = *(unsigned short *)(addrs + 12); | ||
676 | skb->protocol = eth_type_trans(skb, dev); | ||
677 | netif_rx(skb); | ||
678 | received ++; | ||
679 | } else | ||
680 | goto dropping; | ||
681 | } else { | ||
682 | struct net_device_stats *stats = &priv(dev)->stats; | ||
683 | ether3_outw(next_ptr >> 8, REG_RECVEND); | ||
684 | if (status & RXSTAT_OVERSIZE) stats->rx_over_errors ++; | ||
685 | if (status & RXSTAT_CRCERROR) stats->rx_crc_errors ++; | ||
686 | if (status & RXSTAT_DRIBBLEERROR) stats->rx_fifo_errors ++; | ||
687 | if (status & RXSTAT_SHORTPACKET) stats->rx_length_errors ++; | ||
688 | stats->rx_errors++; | ||
689 | } | ||
690 | } | ||
691 | while (-- maxcnt); | ||
692 | |||
693 | done: | ||
694 | priv(dev)->stats.rx_packets += received; | ||
695 | priv(dev)->rx_head = next_ptr; | ||
696 | /* | ||
697 | * If rx went off line, then that means that the buffer may be full. We | ||
698 | * have dropped at least one packet. | ||
699 | */ | ||
700 | if (!(ether3_inw(REG_STATUS) & STAT_RXON)) { | ||
701 | priv(dev)->stats.rx_dropped ++; | ||
702 | ether3_outw(next_ptr, REG_RECVPTR); | ||
703 | ether3_outw(priv(dev)->regs.command | CMD_RXON, REG_COMMAND); | ||
704 | } | ||
705 | |||
706 | return maxcnt; | ||
707 | |||
708 | dropping:{ | ||
709 | static unsigned long last_warned; | ||
710 | |||
711 | ether3_outw(next_ptr >> 8, REG_RECVEND); | ||
712 | /* | ||
713 | * Don't print this message too many times... | ||
714 | */ | ||
715 | if (time_after(jiffies, last_warned + 10 * HZ)) { | ||
716 | last_warned = jiffies; | ||
717 | printk("%s: memory squeeze, dropping packet.\n", dev->name); | ||
718 | } | ||
719 | priv(dev)->stats.rx_dropped ++; | ||
720 | goto done; | ||
721 | } | ||
722 | } | ||
723 | |||
724 | /* | ||
725 | * Update stats for the transmitted packet(s) | ||
726 | */ | ||
727 | static void ether3_tx(struct net_device *dev) | ||
728 | { | ||
729 | unsigned int tx_tail = priv(dev)->tx_tail; | ||
730 | int max_work = 14; | ||
731 | |||
732 | do { | ||
733 | unsigned long status; | ||
734 | |||
735 | /* | ||
736 | * Read the packet header | ||
737 | */ | ||
738 | ether3_setbuffer(dev, buffer_read, tx_tail * 0x600); | ||
739 | status = ether3_readlong(dev); | ||
740 | |||
741 | /* | ||
742 | * Check to see if this packet has been transmitted | ||
743 | */ | ||
744 | if ((status & (TXSTAT_DONE | TXHDR_TRANSMIT)) != | ||
745 | (TXSTAT_DONE | TXHDR_TRANSMIT)) | ||
746 | break; | ||
747 | |||
748 | /* | ||
749 | * Update errors | ||
750 | */ | ||
751 | if (!(status & (TXSTAT_BABBLED | TXSTAT_16COLLISIONS))) | ||
752 | priv(dev)->stats.tx_packets++; | ||
753 | else { | ||
754 | priv(dev)->stats.tx_errors ++; | ||
755 | if (status & TXSTAT_16COLLISIONS) | ||
756 | priv(dev)->stats.collisions += 16; | ||
757 | if (status & TXSTAT_BABBLED) | ||
758 | priv(dev)->stats.tx_fifo_errors ++; | ||
759 | } | ||
760 | |||
761 | tx_tail = (tx_tail + 1) & 15; | ||
762 | } while (--max_work); | ||
763 | |||
764 | if (priv(dev)->tx_tail != tx_tail) { | ||
765 | priv(dev)->tx_tail = tx_tail; | ||
766 | netif_wake_queue(dev); | ||
767 | } | ||
768 | } | ||
769 | |||
770 | static void __init ether3_banner(void) | ||
771 | { | ||
772 | static unsigned version_printed = 0; | ||
773 | |||
774 | if (net_debug && version_printed++ == 0) | ||
775 | printk(KERN_INFO "%s", version); | ||
776 | } | ||
777 | |||
778 | static int __devinit | ||
779 | ether3_probe(struct expansion_card *ec, const struct ecard_id *id) | ||
780 | { | ||
781 | const struct ether3_data *data = id->data; | ||
782 | struct net_device *dev; | ||
783 | int i, bus_type, ret; | ||
784 | |||
785 | ether3_banner(); | ||
786 | |||
787 | ret = ecard_request_resources(ec); | ||
788 | if (ret) | ||
789 | goto out; | ||
790 | |||
791 | dev = alloc_etherdev(sizeof(struct dev_priv)); | ||
792 | if (!dev) { | ||
793 | ret = -ENOMEM; | ||
794 | goto release; | ||
795 | } | ||
796 | |||
797 | SET_MODULE_OWNER(dev); | ||
798 | SET_NETDEV_DEV(dev, &ec->dev); | ||
799 | |||
800 | priv(dev)->base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC), | ||
801 | ecard_resource_len(ec, ECARD_RES_MEMC)); | ||
802 | if (!priv(dev)->base) { | ||
803 | ret = -ENOMEM; | ||
804 | goto free; | ||
805 | } | ||
806 | |||
807 | ec->irqaddr = priv(dev)->base + data->base_offset; | ||
808 | ec->irqmask = 0xf0; | ||
809 | |||
810 | priv(dev)->seeq = priv(dev)->base + data->base_offset; | ||
811 | dev->irq = ec->irq; | ||
812 | |||
813 | ether3_addr(dev->dev_addr, ec); | ||
814 | |||
815 | init_timer(&priv(dev)->timer); | ||
816 | |||
817 | /* Reset card... | ||
818 | */ | ||
819 | ether3_outb(0x80, REG_CONFIG2 + 4); | ||
820 | bus_type = BUS_UNKNOWN; | ||
821 | udelay(4); | ||
822 | |||
823 | /* Test using Receive Pointer (16-bit register) to find out | ||
824 | * how the ether3 is connected to the bus... | ||
825 | */ | ||
826 | if (ether3_probe_bus_8(dev, 0x100) && | ||
827 | ether3_probe_bus_8(dev, 0x201)) | ||
828 | bus_type = BUS_8; | ||
829 | |||
830 | if (bus_type == BUS_UNKNOWN && | ||
831 | ether3_probe_bus_16(dev, 0x101) && | ||
832 | ether3_probe_bus_16(dev, 0x201)) | ||
833 | bus_type = BUS_16; | ||
834 | |||
835 | switch (bus_type) { | ||
836 | case BUS_UNKNOWN: | ||
837 | printk(KERN_ERR "%s: unable to identify bus width\n", dev->name); | ||
838 | ret = -ENODEV; | ||
839 | goto free; | ||
840 | |||
841 | case BUS_8: | ||
842 | printk(KERN_ERR "%s: %s found, but is an unsupported " | ||
843 | "8-bit card\n", dev->name, data->name); | ||
844 | ret = -ENODEV; | ||
845 | goto free; | ||
846 | |||
847 | default: | ||
848 | break; | ||
849 | } | ||
850 | |||
851 | if (ether3_init_2(dev)) { | ||
852 | ret = -ENODEV; | ||
853 | goto free; | ||
854 | } | ||
855 | |||
856 | dev->open = ether3_open; | ||
857 | dev->stop = ether3_close; | ||
858 | dev->hard_start_xmit = ether3_sendpacket; | ||
859 | dev->get_stats = ether3_getstats; | ||
860 | dev->set_multicast_list = ether3_setmulticastlist; | ||
861 | dev->tx_timeout = ether3_timeout; | ||
862 | dev->watchdog_timeo = 5 * HZ / 100; | ||
863 | |||
864 | ret = register_netdev(dev); | ||
865 | if (ret) | ||
866 | goto free; | ||
867 | |||
868 | printk("%s: %s in slot %d, ", dev->name, data->name, ec->slot_no); | ||
869 | for (i = 0; i < 6; i++) | ||
870 | printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); | ||
871 | |||
872 | ecard_set_drvdata(ec, dev); | ||
873 | return 0; | ||
874 | |||
875 | free: | ||
876 | if (priv(dev)->base) | ||
877 | iounmap(priv(dev)->base); | ||
878 | free_netdev(dev); | ||
879 | release: | ||
880 | ecard_release_resources(ec); | ||
881 | out: | ||
882 | return ret; | ||
883 | } | ||
884 | |||
885 | static void __devexit ether3_remove(struct expansion_card *ec) | ||
886 | { | ||
887 | struct net_device *dev = ecard_get_drvdata(ec); | ||
888 | |||
889 | ecard_set_drvdata(ec, NULL); | ||
890 | |||
891 | unregister_netdev(dev); | ||
892 | iounmap(priv(dev)->base); | ||
893 | free_netdev(dev); | ||
894 | ecard_release_resources(ec); | ||
895 | } | ||
896 | |||
897 | static struct ether3_data ether3 = { | ||
898 | .name = "ether3", | ||
899 | .base_offset = 0, | ||
900 | }; | ||
901 | |||
902 | static struct ether3_data etherb = { | ||
903 | .name = "etherb", | ||
904 | .base_offset = 0x800, | ||
905 | }; | ||
906 | |||
907 | static const struct ecard_id ether3_ids[] = { | ||
908 | { MANU_ANT2, PROD_ANT_ETHER3, ðer3 }, | ||
909 | { MANU_ANT, PROD_ANT_ETHER3, ðer3 }, | ||
910 | { MANU_ANT, PROD_ANT_ETHERB, ðerb }, | ||
911 | { 0xffff, 0xffff } | ||
912 | }; | ||
913 | |||
914 | static struct ecard_driver ether3_driver = { | ||
915 | .probe = ether3_probe, | ||
916 | .remove = __devexit_p(ether3_remove), | ||
917 | .id_table = ether3_ids, | ||
918 | .drv = { | ||
919 | .name = "ether3", | ||
920 | }, | ||
921 | }; | ||
922 | |||
923 | static int __init ether3_init(void) | ||
924 | { | ||
925 | return ecard_register_driver(ðer3_driver); | ||
926 | } | ||
927 | |||
928 | static void __exit ether3_exit(void) | ||
929 | { | ||
930 | ecard_remove_driver(ðer3_driver); | ||
931 | } | ||
932 | |||
933 | module_init(ether3_init); | ||
934 | module_exit(ether3_exit); | ||
935 | |||
936 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/arm/ether3.h b/drivers/net/arm/ether3.h new file mode 100644 index 000000000000..1921a3a07da7 --- /dev/null +++ b/drivers/net/arm/ether3.h | |||
@@ -0,0 +1,177 @@ | |||
1 | /* | ||
2 | * linux/drivers/acorn/net/ether3.h | ||
3 | * | ||
4 | * Copyright (C) 1995-2000 Russell King | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * network driver for Acorn/ANT Ether3 cards | ||
11 | */ | ||
12 | |||
13 | #ifndef _LINUX_ether3_H | ||
14 | #define _LINUX_ether3_H | ||
15 | |||
16 | /* use 0 for production, 1 for verification, >2 for debug. debug flags: */ | ||
17 | #define DEBUG_TX 2 | ||
18 | #define DEBUG_RX 4 | ||
19 | #define DEBUG_INT 8 | ||
20 | #define DEBUG_IC 16 | ||
21 | #ifndef NET_DEBUG | ||
22 | #define NET_DEBUG 0 | ||
23 | #endif | ||
24 | |||
25 | #define priv(dev) ((struct dev_priv *)netdev_priv(dev)) | ||
26 | |||
27 | /* Command register definitions & bits */ | ||
28 | #define REG_COMMAND (priv(dev)->seeq + 0x0000) | ||
29 | #define CMD_ENINTDMA 0x0001 | ||
30 | #define CMD_ENINTRX 0x0002 | ||
31 | #define CMD_ENINTTX 0x0004 | ||
32 | #define CMD_ENINTBUFWIN 0x0008 | ||
33 | #define CMD_ACKINTDMA 0x0010 | ||
34 | #define CMD_ACKINTRX 0x0020 | ||
35 | #define CMD_ACKINTTX 0x0040 | ||
36 | #define CMD_ACKINTBUFWIN 0x0080 | ||
37 | #define CMD_DMAON 0x0100 | ||
38 | #define CMD_RXON 0x0200 | ||
39 | #define CMD_TXON 0x0400 | ||
40 | #define CMD_DMAOFF 0x0800 | ||
41 | #define CMD_RXOFF 0x1000 | ||
42 | #define CMD_TXOFF 0x2000 | ||
43 | #define CMD_FIFOREAD 0x4000 | ||
44 | #define CMD_FIFOWRITE 0x8000 | ||
45 | |||
46 | /* status register */ | ||
47 | #define REG_STATUS (priv(dev)->seeq + 0x0000) | ||
48 | #define STAT_ENINTSTAT 0x0001 | ||
49 | #define STAT_ENINTRX 0x0002 | ||
50 | #define STAT_ENINTTX 0x0004 | ||
51 | #define STAT_ENINTBUFWIN 0x0008 | ||
52 | #define STAT_INTDMA 0x0010 | ||
53 | #define STAT_INTRX 0x0020 | ||
54 | #define STAT_INTTX 0x0040 | ||
55 | #define STAT_INTBUFWIN 0x0080 | ||
56 | #define STAT_DMAON 0x0100 | ||
57 | #define STAT_RXON 0x0200 | ||
58 | #define STAT_TXON 0x0400 | ||
59 | #define STAT_FIFOFULL 0x2000 | ||
60 | #define STAT_FIFOEMPTY 0x4000 | ||
61 | #define STAT_FIFODIR 0x8000 | ||
62 | |||
63 | /* configuration register 1 */ | ||
64 | #define REG_CONFIG1 (priv(dev)->seeq + 0x0040) | ||
65 | #define CFG1_BUFSELSTAT0 0x0000 | ||
66 | #define CFG1_BUFSELSTAT1 0x0001 | ||
67 | #define CFG1_BUFSELSTAT2 0x0002 | ||
68 | #define CFG1_BUFSELSTAT3 0x0003 | ||
69 | #define CFG1_BUFSELSTAT4 0x0004 | ||
70 | #define CFG1_BUFSELSTAT5 0x0005 | ||
71 | #define CFG1_ADDRPROM 0x0006 | ||
72 | #define CFG1_TRANSEND 0x0007 | ||
73 | #define CFG1_LOCBUFMEM 0x0008 | ||
74 | #define CFG1_INTVECTOR 0x0009 | ||
75 | #define CFG1_RECVSPECONLY 0x0000 | ||
76 | #define CFG1_RECVSPECBROAD 0x4000 | ||
77 | #define CFG1_RECVSPECBRMULTI 0x8000 | ||
78 | #define CFG1_RECVPROMISC 0xC000 | ||
79 | |||
80 | /* The following aren't in 8004 */ | ||
81 | #define CFG1_DMABURSTCONT 0x0000 | ||
82 | #define CFG1_DMABURST800NS 0x0010 | ||
83 | #define CFG1_DMABURST1600NS 0x0020 | ||
84 | #define CFG1_DMABURST3200NS 0x0030 | ||
85 | #define CFG1_DMABURST1 0x0000 | ||
86 | #define CFG1_DMABURST4 0x0040 | ||
87 | #define CFG1_DMABURST8 0x0080 | ||
88 | #define CFG1_DMABURST16 0x00C0 | ||
89 | #define CFG1_RECVCOMPSTAT0 0x0100 | ||
90 | #define CFG1_RECVCOMPSTAT1 0x0200 | ||
91 | #define CFG1_RECVCOMPSTAT2 0x0400 | ||
92 | #define CFG1_RECVCOMPSTAT3 0x0800 | ||
93 | #define CFG1_RECVCOMPSTAT4 0x1000 | ||
94 | #define CFG1_RECVCOMPSTAT5 0x2000 | ||
95 | |||
96 | /* configuration register 2 */ | ||
97 | #define REG_CONFIG2 (priv(dev)->seeq + 0x0080) | ||
98 | #define CFG2_BYTESWAP 0x0001 | ||
99 | #define CFG2_ERRENCRC 0x0008 | ||
100 | #define CFG2_ERRENDRIBBLE 0x0010 | ||
101 | #define CFG2_ERRSHORTFRAME 0x0020 | ||
102 | #define CFG2_SLOTSELECT 0x0040 | ||
103 | #define CFG2_PREAMSELECT 0x0080 | ||
104 | #define CFG2_ADDRLENGTH 0x0100 | ||
105 | #define CFG2_RECVCRC 0x0200 | ||
106 | #define CFG2_XMITNOCRC 0x0400 | ||
107 | #define CFG2_LOOPBACK 0x0800 | ||
108 | #define CFG2_CTRLO 0x1000 | ||
109 | #define CFG2_RESET 0x8000 | ||
110 | |||
111 | #define REG_RECVEND (priv(dev)->seeq + 0x00c0) | ||
112 | |||
113 | #define REG_BUFWIN (priv(dev)->seeq + 0x0100) | ||
114 | |||
115 | #define REG_RECVPTR (priv(dev)->seeq + 0x0140) | ||
116 | |||
117 | #define REG_TRANSMITPTR (priv(dev)->seeq + 0x0180) | ||
118 | |||
119 | #define REG_DMAADDR (priv(dev)->seeq + 0x01c0) | ||
120 | |||
121 | /* | ||
122 | * Cards transmit/receive headers | ||
123 | */ | ||
124 | #define TX_NEXT (0xffff) | ||
125 | #define TXHDR_ENBABBLEINT (1 << 16) | ||
126 | #define TXHDR_ENCOLLISIONINT (1 << 17) | ||
127 | #define TXHDR_EN16COLLISION (1 << 18) | ||
128 | #define TXHDR_ENSUCCESS (1 << 19) | ||
129 | #define TXHDR_DATAFOLLOWS (1 << 21) | ||
130 | #define TXHDR_CHAINCONTINUE (1 << 22) | ||
131 | #define TXHDR_TRANSMIT (1 << 23) | ||
132 | #define TXSTAT_BABBLED (1 << 24) | ||
133 | #define TXSTAT_COLLISION (1 << 25) | ||
134 | #define TXSTAT_16COLLISIONS (1 << 26) | ||
135 | #define TXSTAT_DONE (1 << 31) | ||
136 | |||
137 | #define RX_NEXT (0xffff) | ||
138 | #define RXHDR_CHAINCONTINUE (1 << 6) | ||
139 | #define RXHDR_RECEIVE (1 << 7) | ||
140 | #define RXSTAT_OVERSIZE (1 << 8) | ||
141 | #define RXSTAT_CRCERROR (1 << 9) | ||
142 | #define RXSTAT_DRIBBLEERROR (1 << 10) | ||
143 | #define RXSTAT_SHORTPACKET (1 << 11) | ||
144 | #define RXSTAT_DONE (1 << 15) | ||
145 | |||
146 | |||
147 | #define TX_START 0x0000 | ||
148 | #define TX_END 0x6000 | ||
149 | #define RX_START 0x6000 | ||
150 | #define RX_LEN 0xA000 | ||
151 | #define RX_END 0x10000 | ||
152 | /* must be a power of 2 and greater than MAX_TX_BUFFERED */ | ||
153 | #define MAX_TXED 16 | ||
154 | #define MAX_TX_BUFFERED 10 | ||
155 | |||
156 | struct dev_priv { | ||
157 | void __iomem *base; | ||
158 | void __iomem *seeq; | ||
159 | struct { | ||
160 | unsigned int command; | ||
161 | unsigned int config1; | ||
162 | unsigned int config2; | ||
163 | } regs; | ||
164 | unsigned char tx_head; /* buffer nr to insert next packet */ | ||
165 | unsigned char tx_tail; /* buffer nr of transmitting packet */ | ||
166 | unsigned int rx_head; /* address to fetch next packet from */ | ||
167 | struct net_device_stats stats; | ||
168 | struct timer_list timer; | ||
169 | int broken; /* 0 = ok, 1 = something went wrong */ | ||
170 | }; | ||
171 | |||
172 | struct ether3_data { | ||
173 | const char name[8]; | ||
174 | unsigned long base_offset; | ||
175 | }; | ||
176 | |||
177 | #endif | ||
diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c new file mode 100644 index 000000000000..942a2819576c --- /dev/null +++ b/drivers/net/arm/etherh.c | |||
@@ -0,0 +1,862 @@ | |||
1 | /* | ||
2 | * linux/drivers/acorn/net/etherh.c | ||
3 | * | ||
4 | * Copyright (C) 2000-2002 Russell King | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * NS8390 I-cubed EtherH and ANT EtherM specific driver | ||
11 | * Thanks to I-Cubed for information on their cards. | ||
12 | * EtherM conversion (C) 1999 Chris Kemp and Tim Watterton | ||
13 | * EtherM integration (C) 2000 Aleph One Ltd (Tak-Shing Chan) | ||
14 | * EtherM integration re-engineered by Russell King. | ||
15 | * | ||
16 | * Changelog: | ||
17 | * 08-12-1996 RMK 1.00 Created | ||
18 | * RMK 1.03 Added support for EtherLan500 cards | ||
19 | * 23-11-1997 RMK 1.04 Added media autodetection | ||
20 | * 16-04-1998 RMK 1.05 Improved media autodetection | ||
21 | * 10-02-2000 RMK 1.06 Updated for 2.3.43 | ||
22 | * 13-05-2000 RMK 1.07 Updated for 2.3.99-pre8 | ||
23 | * 12-10-1999 CK/TEW EtherM driver first release | ||
24 | * 21-12-2000 TTC EtherH/EtherM integration | ||
25 | * 25-12-2000 RMK 1.08 Clean integration of EtherM into this driver. | ||
26 | * 03-01-2002 RMK 1.09 Always enable IRQs if we're in the nic slot. | ||
27 | */ | ||
28 | |||
29 | #include <linux/module.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/sched.h> | ||
32 | #include <linux/types.h> | ||
33 | #include <linux/fcntl.h> | ||
34 | #include <linux/interrupt.h> | ||
35 | #include <linux/ptrace.h> | ||
36 | #include <linux/ioport.h> | ||
37 | #include <linux/in.h> | ||
38 | #include <linux/slab.h> | ||
39 | #include <linux/string.h> | ||
40 | #include <linux/errno.h> | ||
41 | #include <linux/netdevice.h> | ||
42 | #include <linux/etherdevice.h> | ||
43 | #include <linux/ethtool.h> | ||
44 | #include <linux/skbuff.h> | ||
45 | #include <linux/delay.h> | ||
46 | #include <linux/device.h> | ||
47 | #include <linux/init.h> | ||
48 | #include <linux/bitops.h> | ||
49 | |||
50 | #include <asm/system.h> | ||
51 | #include <asm/ecard.h> | ||
52 | #include <asm/io.h> | ||
53 | #include <asm/irq.h> | ||
54 | |||
55 | #include "../8390.h" | ||
56 | |||
57 | #define NET_DEBUG 0 | ||
58 | #define DEBUG_INIT 2 | ||
59 | |||
60 | #define DRV_NAME "etherh" | ||
61 | #define DRV_VERSION "1.11" | ||
62 | |||
63 | static unsigned int net_debug = NET_DEBUG; | ||
64 | |||
65 | struct etherh_priv { | ||
66 | void __iomem *ioc_fast; | ||
67 | void __iomem *memc; | ||
68 | void __iomem *dma_base; | ||
69 | unsigned int id; | ||
70 | void __iomem *ctrl_port; | ||
71 | unsigned char ctrl; | ||
72 | u32 supported; | ||
73 | }; | ||
74 | |||
75 | struct etherh_data { | ||
76 | unsigned long ns8390_offset; | ||
77 | unsigned long dataport_offset; | ||
78 | unsigned long ctrlport_offset; | ||
79 | int ctrl_ioc; | ||
80 | const char name[16]; | ||
81 | u32 supported; | ||
82 | unsigned char tx_start_page; | ||
83 | unsigned char stop_page; | ||
84 | }; | ||
85 | |||
86 | MODULE_AUTHOR("Russell King"); | ||
87 | MODULE_DESCRIPTION("EtherH/EtherM driver"); | ||
88 | MODULE_LICENSE("GPL"); | ||
89 | |||
90 | static char version[] __initdata = | ||
91 | "EtherH/EtherM Driver (c) 2002-2004 Russell King " DRV_VERSION "\n"; | ||
92 | |||
93 | #define ETHERH500_DATAPORT 0x800 /* MEMC */ | ||
94 | #define ETHERH500_NS8390 0x000 /* MEMC */ | ||
95 | #define ETHERH500_CTRLPORT 0x800 /* IOC */ | ||
96 | |||
97 | #define ETHERH600_DATAPORT 0x040 /* MEMC */ | ||
98 | #define ETHERH600_NS8390 0x800 /* MEMC */ | ||
99 | #define ETHERH600_CTRLPORT 0x200 /* MEMC */ | ||
100 | |||
101 | #define ETHERH_CP_IE 1 | ||
102 | #define ETHERH_CP_IF 2 | ||
103 | #define ETHERH_CP_HEARTBEAT 2 | ||
104 | |||
105 | #define ETHERH_TX_START_PAGE 1 | ||
106 | #define ETHERH_STOP_PAGE 127 | ||
107 | |||
108 | /* | ||
109 | * These came from CK/TEW | ||
110 | */ | ||
111 | #define ETHERM_DATAPORT 0x200 /* MEMC */ | ||
112 | #define ETHERM_NS8390 0x800 /* MEMC */ | ||
113 | #define ETHERM_CTRLPORT 0x23c /* MEMC */ | ||
114 | |||
115 | #define ETHERM_TX_START_PAGE 64 | ||
116 | #define ETHERM_STOP_PAGE 127 | ||
117 | |||
118 | /* ------------------------------------------------------------------------ */ | ||
119 | |||
120 | #define etherh_priv(dev) \ | ||
121 | ((struct etherh_priv *)(((char *)netdev_priv(dev)) + sizeof(struct ei_device))) | ||
122 | |||
123 | static inline void etherh_set_ctrl(struct etherh_priv *eh, unsigned char mask) | ||
124 | { | ||
125 | unsigned char ctrl = eh->ctrl | mask; | ||
126 | eh->ctrl = ctrl; | ||
127 | writeb(ctrl, eh->ctrl_port); | ||
128 | } | ||
129 | |||
130 | static inline void etherh_clr_ctrl(struct etherh_priv *eh, unsigned char mask) | ||
131 | { | ||
132 | unsigned char ctrl = eh->ctrl & ~mask; | ||
133 | eh->ctrl = ctrl; | ||
134 | writeb(ctrl, eh->ctrl_port); | ||
135 | } | ||
136 | |||
137 | static inline unsigned int etherh_get_stat(struct etherh_priv *eh) | ||
138 | { | ||
139 | return readb(eh->ctrl_port); | ||
140 | } | ||
141 | |||
142 | |||
143 | |||
144 | |||
145 | static void etherh_irq_enable(ecard_t *ec, int irqnr) | ||
146 | { | ||
147 | struct etherh_priv *eh = ec->irq_data; | ||
148 | |||
149 | etherh_set_ctrl(eh, ETHERH_CP_IE); | ||
150 | } | ||
151 | |||
152 | static void etherh_irq_disable(ecard_t *ec, int irqnr) | ||
153 | { | ||
154 | struct etherh_priv *eh = ec->irq_data; | ||
155 | |||
156 | etherh_clr_ctrl(eh, ETHERH_CP_IE); | ||
157 | } | ||
158 | |||
159 | static expansioncard_ops_t etherh_ops = { | ||
160 | .irqenable = etherh_irq_enable, | ||
161 | .irqdisable = etherh_irq_disable, | ||
162 | }; | ||
163 | |||
164 | |||
165 | |||
166 | |||
167 | static void | ||
168 | etherh_setif(struct net_device *dev) | ||
169 | { | ||
170 | struct ei_device *ei_local = netdev_priv(dev); | ||
171 | unsigned long flags; | ||
172 | void __iomem *addr; | ||
173 | |||
174 | local_irq_save(flags); | ||
175 | |||
176 | /* set the interface type */ | ||
177 | switch (etherh_priv(dev)->id) { | ||
178 | case PROD_I3_ETHERLAN600: | ||
179 | case PROD_I3_ETHERLAN600A: | ||
180 | addr = (void *)dev->base_addr + EN0_RCNTHI; | ||
181 | |||
182 | switch (dev->if_port) { | ||
183 | case IF_PORT_10BASE2: | ||
184 | writeb((readb(addr) & 0xf8) | 1, addr); | ||
185 | break; | ||
186 | case IF_PORT_10BASET: | ||
187 | writeb((readb(addr) & 0xf8), addr); | ||
188 | break; | ||
189 | } | ||
190 | break; | ||
191 | |||
192 | case PROD_I3_ETHERLAN500: | ||
193 | switch (dev->if_port) { | ||
194 | case IF_PORT_10BASE2: | ||
195 | etherh_clr_ctrl(etherh_priv(dev), ETHERH_CP_IF); | ||
196 | break; | ||
197 | |||
198 | case IF_PORT_10BASET: | ||
199 | etherh_set_ctrl(etherh_priv(dev), ETHERH_CP_IF); | ||
200 | break; | ||
201 | } | ||
202 | break; | ||
203 | |||
204 | default: | ||
205 | break; | ||
206 | } | ||
207 | |||
208 | local_irq_restore(flags); | ||
209 | } | ||
210 | |||
211 | static int | ||
212 | etherh_getifstat(struct net_device *dev) | ||
213 | { | ||
214 | struct ei_device *ei_local = netdev_priv(dev); | ||
215 | void __iomem *addr; | ||
216 | int stat = 0; | ||
217 | |||
218 | switch (etherh_priv(dev)->id) { | ||
219 | case PROD_I3_ETHERLAN600: | ||
220 | case PROD_I3_ETHERLAN600A: | ||
221 | addr = (void *)dev->base_addr + EN0_RCNTHI; | ||
222 | switch (dev->if_port) { | ||
223 | case IF_PORT_10BASE2: | ||
224 | stat = 1; | ||
225 | break; | ||
226 | case IF_PORT_10BASET: | ||
227 | stat = readb(addr) & 4; | ||
228 | break; | ||
229 | } | ||
230 | break; | ||
231 | |||
232 | case PROD_I3_ETHERLAN500: | ||
233 | switch (dev->if_port) { | ||
234 | case IF_PORT_10BASE2: | ||
235 | stat = 1; | ||
236 | break; | ||
237 | case IF_PORT_10BASET: | ||
238 | stat = etherh_get_stat(etherh_priv(dev)) & ETHERH_CP_HEARTBEAT; | ||
239 | break; | ||
240 | } | ||
241 | break; | ||
242 | |||
243 | default: | ||
244 | stat = 0; | ||
245 | break; | ||
246 | } | ||
247 | |||
248 | return stat != 0; | ||
249 | } | ||
250 | |||
251 | /* | ||
252 | * Configure the interface. Note that we ignore the other | ||
253 | * parts of ifmap, since its mostly meaningless for this driver. | ||
254 | */ | ||
255 | static int etherh_set_config(struct net_device *dev, struct ifmap *map) | ||
256 | { | ||
257 | switch (map->port) { | ||
258 | case IF_PORT_10BASE2: | ||
259 | case IF_PORT_10BASET: | ||
260 | /* | ||
261 | * If the user explicitly sets the interface | ||
262 | * media type, turn off automedia detection. | ||
263 | */ | ||
264 | dev->flags &= ~IFF_AUTOMEDIA; | ||
265 | dev->if_port = map->port; | ||
266 | break; | ||
267 | |||
268 | default: | ||
269 | return -EINVAL; | ||
270 | } | ||
271 | |||
272 | etherh_setif(dev); | ||
273 | |||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | /* | ||
278 | * Reset the 8390 (hard reset). Note that we can't actually do this. | ||
279 | */ | ||
280 | static void | ||
281 | etherh_reset(struct net_device *dev) | ||
282 | { | ||
283 | struct ei_device *ei_local = netdev_priv(dev); | ||
284 | void __iomem *addr = (void *)dev->base_addr; | ||
285 | |||
286 | writeb(E8390_NODMA+E8390_PAGE0+E8390_STOP, addr); | ||
287 | |||
288 | /* | ||
289 | * See if we need to change the interface type. | ||
290 | * Note that we use 'interface_num' as a flag | ||
291 | * to indicate that we need to change the media. | ||
292 | */ | ||
293 | if (dev->flags & IFF_AUTOMEDIA && ei_local->interface_num) { | ||
294 | ei_local->interface_num = 0; | ||
295 | |||
296 | if (dev->if_port == IF_PORT_10BASET) | ||
297 | dev->if_port = IF_PORT_10BASE2; | ||
298 | else | ||
299 | dev->if_port = IF_PORT_10BASET; | ||
300 | |||
301 | etherh_setif(dev); | ||
302 | } | ||
303 | } | ||
304 | |||
305 | /* | ||
306 | * Write a block of data out to the 8390 | ||
307 | */ | ||
308 | static void | ||
309 | etherh_block_output (struct net_device *dev, int count, const unsigned char *buf, int start_page) | ||
310 | { | ||
311 | struct ei_device *ei_local = netdev_priv(dev); | ||
312 | unsigned long dma_start; | ||
313 | void __iomem *dma_base, *addr; | ||
314 | |||
315 | if (ei_local->dmaing) { | ||
316 | printk(KERN_ERR "%s: DMAing conflict in etherh_block_input: " | ||
317 | " DMAstat %d irqlock %d\n", dev->name, | ||
318 | ei_local->dmaing, ei_local->irqlock); | ||
319 | return; | ||
320 | } | ||
321 | |||
322 | /* | ||
323 | * Make sure we have a round number of bytes if we're in word mode. | ||
324 | */ | ||
325 | if (count & 1 && ei_local->word16) | ||
326 | count++; | ||
327 | |||
328 | ei_local->dmaing = 1; | ||
329 | |||
330 | addr = (void *)dev->base_addr; | ||
331 | dma_base = etherh_priv(dev)->dma_base; | ||
332 | |||
333 | count = (count + 1) & ~1; | ||
334 | writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD); | ||
335 | |||
336 | writeb (0x42, addr + EN0_RCNTLO); | ||
337 | writeb (0x00, addr + EN0_RCNTHI); | ||
338 | writeb (0x42, addr + EN0_RSARLO); | ||
339 | writeb (0x00, addr + EN0_RSARHI); | ||
340 | writeb (E8390_RREAD | E8390_START, addr + E8390_CMD); | ||
341 | |||
342 | udelay (1); | ||
343 | |||
344 | writeb (ENISR_RDC, addr + EN0_ISR); | ||
345 | writeb (count, addr + EN0_RCNTLO); | ||
346 | writeb (count >> 8, addr + EN0_RCNTHI); | ||
347 | writeb (0, addr + EN0_RSARLO); | ||
348 | writeb (start_page, addr + EN0_RSARHI); | ||
349 | writeb (E8390_RWRITE | E8390_START, addr + E8390_CMD); | ||
350 | |||
351 | if (ei_local->word16) | ||
352 | writesw (dma_base, buf, count >> 1); | ||
353 | else | ||
354 | writesb (dma_base, buf, count); | ||
355 | |||
356 | dma_start = jiffies; | ||
357 | |||
358 | while ((readb (addr + EN0_ISR) & ENISR_RDC) == 0) | ||
359 | if (jiffies - dma_start > 2*HZ/100) { /* 20ms */ | ||
360 | printk(KERN_ERR "%s: timeout waiting for TX RDC\n", | ||
361 | dev->name); | ||
362 | etherh_reset (dev); | ||
363 | NS8390_init (dev, 1); | ||
364 | break; | ||
365 | } | ||
366 | |||
367 | writeb (ENISR_RDC, addr + EN0_ISR); | ||
368 | ei_local->dmaing = 0; | ||
369 | } | ||
370 | |||
371 | /* | ||
372 | * Read a block of data from the 8390 | ||
373 | */ | ||
374 | static void | ||
375 | etherh_block_input (struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) | ||
376 | { | ||
377 | struct ei_device *ei_local = netdev_priv(dev); | ||
378 | unsigned char *buf; | ||
379 | void __iomem *dma_base, *addr; | ||
380 | |||
381 | if (ei_local->dmaing) { | ||
382 | printk(KERN_ERR "%s: DMAing conflict in etherh_block_input: " | ||
383 | " DMAstat %d irqlock %d\n", dev->name, | ||
384 | ei_local->dmaing, ei_local->irqlock); | ||
385 | return; | ||
386 | } | ||
387 | |||
388 | ei_local->dmaing = 1; | ||
389 | |||
390 | addr = (void *)dev->base_addr; | ||
391 | dma_base = etherh_priv(dev)->dma_base; | ||
392 | |||
393 | buf = skb->data; | ||
394 | writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD); | ||
395 | writeb (count, addr + EN0_RCNTLO); | ||
396 | writeb (count >> 8, addr + EN0_RCNTHI); | ||
397 | writeb (ring_offset, addr + EN0_RSARLO); | ||
398 | writeb (ring_offset >> 8, addr + EN0_RSARHI); | ||
399 | writeb (E8390_RREAD | E8390_START, addr + E8390_CMD); | ||
400 | |||
401 | if (ei_local->word16) { | ||
402 | readsw (dma_base, buf, count >> 1); | ||
403 | if (count & 1) | ||
404 | buf[count - 1] = readb (dma_base); | ||
405 | } else | ||
406 | readsb (dma_base, buf, count); | ||
407 | |||
408 | writeb (ENISR_RDC, addr + EN0_ISR); | ||
409 | ei_local->dmaing = 0; | ||
410 | } | ||
411 | |||
412 | /* | ||
413 | * Read a header from the 8390 | ||
414 | */ | ||
415 | static void | ||
416 | etherh_get_header (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) | ||
417 | { | ||
418 | struct ei_device *ei_local = netdev_priv(dev); | ||
419 | void __iomem *dma_base, *addr; | ||
420 | |||
421 | if (ei_local->dmaing) { | ||
422 | printk(KERN_ERR "%s: DMAing conflict in etherh_get_header: " | ||
423 | " DMAstat %d irqlock %d\n", dev->name, | ||
424 | ei_local->dmaing, ei_local->irqlock); | ||
425 | return; | ||
426 | } | ||
427 | |||
428 | ei_local->dmaing = 1; | ||
429 | |||
430 | addr = (void *)dev->base_addr; | ||
431 | dma_base = etherh_priv(dev)->dma_base; | ||
432 | |||
433 | writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD); | ||
434 | writeb (sizeof (*hdr), addr + EN0_RCNTLO); | ||
435 | writeb (0, addr + EN0_RCNTHI); | ||
436 | writeb (0, addr + EN0_RSARLO); | ||
437 | writeb (ring_page, addr + EN0_RSARHI); | ||
438 | writeb (E8390_RREAD | E8390_START, addr + E8390_CMD); | ||
439 | |||
440 | if (ei_local->word16) | ||
441 | readsw (dma_base, hdr, sizeof (*hdr) >> 1); | ||
442 | else | ||
443 | readsb (dma_base, hdr, sizeof (*hdr)); | ||
444 | |||
445 | writeb (ENISR_RDC, addr + EN0_ISR); | ||
446 | ei_local->dmaing = 0; | ||
447 | } | ||
448 | |||
449 | /* | ||
450 | * Open/initialize the board. This is called (in the current kernel) | ||
451 | * sometime after booting when the 'ifconfig' program is run. | ||
452 | * | ||
453 | * This routine should set everything up anew at each open, even | ||
454 | * registers that "should" only need to be set once at boot, so that | ||
455 | * there is non-reboot way to recover if something goes wrong. | ||
456 | */ | ||
457 | static int | ||
458 | etherh_open(struct net_device *dev) | ||
459 | { | ||
460 | struct ei_device *ei_local = netdev_priv(dev); | ||
461 | |||
462 | if (!is_valid_ether_addr(dev->dev_addr)) { | ||
463 | printk(KERN_WARNING "%s: invalid ethernet MAC address\n", | ||
464 | dev->name); | ||
465 | return -EINVAL; | ||
466 | } | ||
467 | |||
468 | if (request_irq(dev->irq, ei_interrupt, 0, dev->name, dev)) | ||
469 | return -EAGAIN; | ||
470 | |||
471 | /* | ||
472 | * Make sure that we aren't going to change the | ||
473 | * media type on the next reset - we are about to | ||
474 | * do automedia manually now. | ||
475 | */ | ||
476 | ei_local->interface_num = 0; | ||
477 | |||
478 | /* | ||
479 | * If we are doing automedia detection, do it now. | ||
480 | * This is more reliable than the 8390's detection. | ||
481 | */ | ||
482 | if (dev->flags & IFF_AUTOMEDIA) { | ||
483 | dev->if_port = IF_PORT_10BASET; | ||
484 | etherh_setif(dev); | ||
485 | mdelay(1); | ||
486 | if (!etherh_getifstat(dev)) { | ||
487 | dev->if_port = IF_PORT_10BASE2; | ||
488 | etherh_setif(dev); | ||
489 | } | ||
490 | } else | ||
491 | etherh_setif(dev); | ||
492 | |||
493 | etherh_reset(dev); | ||
494 | ei_open(dev); | ||
495 | |||
496 | return 0; | ||
497 | } | ||
498 | |||
499 | /* | ||
500 | * The inverse routine to etherh_open(). | ||
501 | */ | ||
502 | static int | ||
503 | etherh_close(struct net_device *dev) | ||
504 | { | ||
505 | ei_close (dev); | ||
506 | free_irq (dev->irq, dev); | ||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | /* | ||
511 | * Initialisation | ||
512 | */ | ||
513 | |||
514 | static void __init etherh_banner(void) | ||
515 | { | ||
516 | static int version_printed; | ||
517 | |||
518 | if (net_debug && version_printed++ == 0) | ||
519 | printk(KERN_INFO "%s", version); | ||
520 | } | ||
521 | |||
522 | /* | ||
523 | * Read the ethernet address string from the on board rom. | ||
524 | * This is an ascii string... | ||
525 | */ | ||
526 | static int __init etherh_addr(char *addr, struct expansion_card *ec) | ||
527 | { | ||
528 | struct in_chunk_dir cd; | ||
529 | char *s; | ||
530 | |||
531 | if (!ecard_readchunk(&cd, ec, 0xf5, 0)) { | ||
532 | printk(KERN_ERR "%s: unable to read podule description string\n", | ||
533 | ec->dev.bus_id); | ||
534 | goto no_addr; | ||
535 | } | ||
536 | |||
537 | s = strchr(cd.d.string, '('); | ||
538 | if (s) { | ||
539 | int i; | ||
540 | |||
541 | for (i = 0; i < 6; i++) { | ||
542 | addr[i] = simple_strtoul(s + 1, &s, 0x10); | ||
543 | if (*s != (i == 5? ')' : ':')) | ||
544 | break; | ||
545 | } | ||
546 | |||
547 | if (i == 6) | ||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | printk(KERN_ERR "%s: unable to parse MAC address: %s\n", | ||
552 | ec->dev.bus_id, cd.d.string); | ||
553 | |||
554 | no_addr: | ||
555 | return -ENODEV; | ||
556 | } | ||
557 | |||
558 | /* | ||
559 | * Create an ethernet address from the system serial number. | ||
560 | */ | ||
561 | static int __init etherm_addr(char *addr) | ||
562 | { | ||
563 | unsigned int serial; | ||
564 | |||
565 | if (system_serial_low == 0 && system_serial_high == 0) | ||
566 | return -ENODEV; | ||
567 | |||
568 | serial = system_serial_low | system_serial_high; | ||
569 | |||
570 | addr[0] = 0; | ||
571 | addr[1] = 0; | ||
572 | addr[2] = 0xa4; | ||
573 | addr[3] = 0x10 + (serial >> 24); | ||
574 | addr[4] = serial >> 16; | ||
575 | addr[5] = serial >> 8; | ||
576 | return 0; | ||
577 | } | ||
578 | |||
579 | static void etherh_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) | ||
580 | { | ||
581 | strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); | ||
582 | strlcpy(info->version, DRV_VERSION, sizeof(info->version)); | ||
583 | strlcpy(info->bus_info, dev->class_dev.dev->bus_id, | ||
584 | sizeof(info->bus_info)); | ||
585 | } | ||
586 | |||
587 | static int etherh_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
588 | { | ||
589 | cmd->supported = etherh_priv(dev)->supported; | ||
590 | cmd->speed = SPEED_10; | ||
591 | cmd->duplex = DUPLEX_HALF; | ||
592 | cmd->port = dev->if_port == IF_PORT_10BASET ? PORT_TP : PORT_BNC; | ||
593 | cmd->autoneg = dev->flags & IFF_AUTOMEDIA ? AUTONEG_ENABLE : AUTONEG_DISABLE; | ||
594 | return 0; | ||
595 | } | ||
596 | |||
597 | static int etherh_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
598 | { | ||
599 | switch (cmd->autoneg) { | ||
600 | case AUTONEG_ENABLE: | ||
601 | dev->flags |= IFF_AUTOMEDIA; | ||
602 | break; | ||
603 | |||
604 | case AUTONEG_DISABLE: | ||
605 | switch (cmd->port) { | ||
606 | case PORT_TP: | ||
607 | dev->if_port = IF_PORT_10BASET; | ||
608 | break; | ||
609 | |||
610 | case PORT_BNC: | ||
611 | dev->if_port = IF_PORT_10BASE2; | ||
612 | break; | ||
613 | |||
614 | default: | ||
615 | return -EINVAL; | ||
616 | } | ||
617 | dev->flags &= ~IFF_AUTOMEDIA; | ||
618 | break; | ||
619 | |||
620 | default: | ||
621 | return -EINVAL; | ||
622 | } | ||
623 | |||
624 | etherh_setif(dev); | ||
625 | |||
626 | return 0; | ||
627 | } | ||
628 | |||
629 | static struct ethtool_ops etherh_ethtool_ops = { | ||
630 | .get_settings = etherh_get_settings, | ||
631 | .set_settings = etherh_set_settings, | ||
632 | .get_drvinfo = etherh_get_drvinfo, | ||
633 | }; | ||
634 | |||
635 | static u32 etherh_regoffsets[16]; | ||
636 | static u32 etherm_regoffsets[16]; | ||
637 | |||
638 | static int __init | ||
639 | etherh_probe(struct expansion_card *ec, const struct ecard_id *id) | ||
640 | { | ||
641 | const struct etherh_data *data = id->data; | ||
642 | struct ei_device *ei_local; | ||
643 | struct net_device *dev; | ||
644 | struct etherh_priv *eh; | ||
645 | int i, ret; | ||
646 | |||
647 | etherh_banner(); | ||
648 | |||
649 | ret = ecard_request_resources(ec); | ||
650 | if (ret) | ||
651 | goto out; | ||
652 | |||
653 | dev = __alloc_ei_netdev(sizeof(struct etherh_priv)); | ||
654 | if (!dev) { | ||
655 | ret = -ENOMEM; | ||
656 | goto release; | ||
657 | } | ||
658 | |||
659 | SET_MODULE_OWNER(dev); | ||
660 | SET_NETDEV_DEV(dev, &ec->dev); | ||
661 | |||
662 | dev->open = etherh_open; | ||
663 | dev->stop = etherh_close; | ||
664 | dev->set_config = etherh_set_config; | ||
665 | dev->irq = ec->irq; | ||
666 | dev->ethtool_ops = ðerh_ethtool_ops; | ||
667 | |||
668 | if (data->supported & SUPPORTED_Autoneg) | ||
669 | dev->flags |= IFF_AUTOMEDIA; | ||
670 | if (data->supported & SUPPORTED_TP) { | ||
671 | dev->flags |= IFF_PORTSEL; | ||
672 | dev->if_port = IF_PORT_10BASET; | ||
673 | } else if (data->supported & SUPPORTED_BNC) { | ||
674 | dev->flags |= IFF_PORTSEL; | ||
675 | dev->if_port = IF_PORT_10BASE2; | ||
676 | } else | ||
677 | dev->if_port = IF_PORT_UNKNOWN; | ||
678 | |||
679 | eh = etherh_priv(dev); | ||
680 | eh->supported = data->supported; | ||
681 | eh->ctrl = 0; | ||
682 | eh->id = ec->cid.product; | ||
683 | eh->memc = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC), PAGE_SIZE); | ||
684 | if (!eh->memc) { | ||
685 | ret = -ENOMEM; | ||
686 | goto free; | ||
687 | } | ||
688 | |||
689 | eh->ctrl_port = eh->memc; | ||
690 | if (data->ctrl_ioc) { | ||
691 | eh->ioc_fast = ioremap(ecard_resource_start(ec, ECARD_RES_IOCFAST), PAGE_SIZE); | ||
692 | if (!eh->ioc_fast) { | ||
693 | ret = -ENOMEM; | ||
694 | goto free; | ||
695 | } | ||
696 | eh->ctrl_port = eh->ioc_fast; | ||
697 | } | ||
698 | |||
699 | dev->base_addr = (unsigned long)eh->memc + data->ns8390_offset; | ||
700 | eh->dma_base = eh->memc + data->dataport_offset; | ||
701 | eh->ctrl_port += data->ctrlport_offset; | ||
702 | |||
703 | /* | ||
704 | * IRQ and control port handling - only for non-NIC slot cards. | ||
705 | */ | ||
706 | if (ec->slot_no != 8) { | ||
707 | ec->ops = ðerh_ops; | ||
708 | ec->irq_data = eh; | ||
709 | } else { | ||
710 | /* | ||
711 | * If we're in the NIC slot, make sure the IRQ is enabled | ||
712 | */ | ||
713 | etherh_set_ctrl(eh, ETHERH_CP_IE); | ||
714 | } | ||
715 | |||
716 | ei_local = netdev_priv(dev); | ||
717 | spin_lock_init(&ei_local->page_lock); | ||
718 | |||
719 | if (ec->cid.product == PROD_ANT_ETHERM) { | ||
720 | etherm_addr(dev->dev_addr); | ||
721 | ei_local->reg_offset = etherm_regoffsets; | ||
722 | } else { | ||
723 | etherh_addr(dev->dev_addr, ec); | ||
724 | ei_local->reg_offset = etherh_regoffsets; | ||
725 | } | ||
726 | |||
727 | ei_local->name = dev->name; | ||
728 | ei_local->word16 = 1; | ||
729 | ei_local->tx_start_page = data->tx_start_page; | ||
730 | ei_local->rx_start_page = ei_local->tx_start_page + TX_PAGES; | ||
731 | ei_local->stop_page = data->stop_page; | ||
732 | ei_local->reset_8390 = etherh_reset; | ||
733 | ei_local->block_input = etherh_block_input; | ||
734 | ei_local->block_output = etherh_block_output; | ||
735 | ei_local->get_8390_hdr = etherh_get_header; | ||
736 | ei_local->interface_num = 0; | ||
737 | |||
738 | etherh_reset(dev); | ||
739 | NS8390_init(dev, 0); | ||
740 | |||
741 | ret = register_netdev(dev); | ||
742 | if (ret) | ||
743 | goto free; | ||
744 | |||
745 | printk(KERN_INFO "%s: %s in slot %d, ", | ||
746 | dev->name, data->name, ec->slot_no); | ||
747 | |||
748 | for (i = 0; i < 6; i++) | ||
749 | printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); | ||
750 | |||
751 | ecard_set_drvdata(ec, dev); | ||
752 | |||
753 | return 0; | ||
754 | |||
755 | free: | ||
756 | if (eh->ioc_fast) | ||
757 | iounmap(eh->ioc_fast); | ||
758 | if (eh->memc) | ||
759 | iounmap(eh->memc); | ||
760 | free_netdev(dev); | ||
761 | release: | ||
762 | ecard_release_resources(ec); | ||
763 | out: | ||
764 | return ret; | ||
765 | } | ||
766 | |||
767 | static void __devexit etherh_remove(struct expansion_card *ec) | ||
768 | { | ||
769 | struct net_device *dev = ecard_get_drvdata(ec); | ||
770 | struct etherh_priv *eh = etherh_priv(dev); | ||
771 | |||
772 | ecard_set_drvdata(ec, NULL); | ||
773 | |||
774 | unregister_netdev(dev); | ||
775 | ec->ops = NULL; | ||
776 | |||
777 | if (eh->ioc_fast) | ||
778 | iounmap(eh->ioc_fast); | ||
779 | iounmap(eh->memc); | ||
780 | |||
781 | free_netdev(dev); | ||
782 | |||
783 | ecard_release_resources(ec); | ||
784 | } | ||
785 | |||
786 | static struct etherh_data etherm_data = { | ||
787 | .ns8390_offset = ETHERM_NS8390, | ||
788 | .dataport_offset = ETHERM_NS8390 + ETHERM_DATAPORT, | ||
789 | .ctrlport_offset = ETHERM_NS8390 + ETHERM_CTRLPORT, | ||
790 | .name = "ANT EtherM", | ||
791 | .supported = SUPPORTED_10baseT_Half, | ||
792 | .tx_start_page = ETHERM_TX_START_PAGE, | ||
793 | .stop_page = ETHERM_STOP_PAGE, | ||
794 | }; | ||
795 | |||
796 | static struct etherh_data etherlan500_data = { | ||
797 | .ns8390_offset = ETHERH500_NS8390, | ||
798 | .dataport_offset = ETHERH500_NS8390 + ETHERH500_DATAPORT, | ||
799 | .ctrlport_offset = ETHERH500_CTRLPORT, | ||
800 | .ctrl_ioc = 1, | ||
801 | .name = "i3 EtherH 500", | ||
802 | .supported = SUPPORTED_10baseT_Half, | ||
803 | .tx_start_page = ETHERH_TX_START_PAGE, | ||
804 | .stop_page = ETHERH_STOP_PAGE, | ||
805 | }; | ||
806 | |||
807 | static struct etherh_data etherlan600_data = { | ||
808 | .ns8390_offset = ETHERH600_NS8390, | ||
809 | .dataport_offset = ETHERH600_NS8390 + ETHERH600_DATAPORT, | ||
810 | .ctrlport_offset = ETHERH600_NS8390 + ETHERH600_CTRLPORT, | ||
811 | .name = "i3 EtherH 600", | ||
812 | .supported = SUPPORTED_10baseT_Half | SUPPORTED_TP | SUPPORTED_BNC | SUPPORTED_Autoneg, | ||
813 | .tx_start_page = ETHERH_TX_START_PAGE, | ||
814 | .stop_page = ETHERH_STOP_PAGE, | ||
815 | }; | ||
816 | |||
817 | static struct etherh_data etherlan600a_data = { | ||
818 | .ns8390_offset = ETHERH600_NS8390, | ||
819 | .dataport_offset = ETHERH600_NS8390 + ETHERH600_DATAPORT, | ||
820 | .ctrlport_offset = ETHERH600_NS8390 + ETHERH600_CTRLPORT, | ||
821 | .name = "i3 EtherH 600A", | ||
822 | .supported = SUPPORTED_10baseT_Half | SUPPORTED_TP | SUPPORTED_BNC | SUPPORTED_Autoneg, | ||
823 | .tx_start_page = ETHERH_TX_START_PAGE, | ||
824 | .stop_page = ETHERH_STOP_PAGE, | ||
825 | }; | ||
826 | |||
827 | static const struct ecard_id etherh_ids[] = { | ||
828 | { MANU_ANT, PROD_ANT_ETHERM, ðerm_data }, | ||
829 | { MANU_I3, PROD_I3_ETHERLAN500, ðerlan500_data }, | ||
830 | { MANU_I3, PROD_I3_ETHERLAN600, ðerlan600_data }, | ||
831 | { MANU_I3, PROD_I3_ETHERLAN600A, ðerlan600a_data }, | ||
832 | { 0xffff, 0xffff } | ||
833 | }; | ||
834 | |||
835 | static struct ecard_driver etherh_driver = { | ||
836 | .probe = etherh_probe, | ||
837 | .remove = __devexit_p(etherh_remove), | ||
838 | .id_table = etherh_ids, | ||
839 | .drv = { | ||
840 | .name = DRV_NAME, | ||
841 | }, | ||
842 | }; | ||
843 | |||
844 | static int __init etherh_init(void) | ||
845 | { | ||
846 | int i; | ||
847 | |||
848 | for (i = 0; i < 16; i++) { | ||
849 | etherh_regoffsets[i] = i << 2; | ||
850 | etherm_regoffsets[i] = i << 5; | ||
851 | } | ||
852 | |||
853 | return ecard_register_driver(ðerh_driver); | ||
854 | } | ||
855 | |||
856 | static void __exit etherh_exit(void) | ||
857 | { | ||
858 | ecard_remove_driver(ðerh_driver); | ||
859 | } | ||
860 | |||
861 | module_init(etherh_init); | ||
862 | module_exit(etherh_exit); | ||