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/ni65.c |
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/ni65.c')
-rw-r--r-- | drivers/net/ni65.c | 1277 |
1 files changed, 1277 insertions, 0 deletions
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c new file mode 100644 index 000000000000..925d1dfcc4dc --- /dev/null +++ b/drivers/net/ni65.c | |||
@@ -0,0 +1,1277 @@ | |||
1 | /* | ||
2 | * ni6510 (am7990 'lance' chip) driver for Linux-net-3 | ||
3 | * BETAcode v0.71 (96/09/29) for 2.0.0 (or later) | ||
4 | * copyrights (c) 1994,1995,1996 by M.Hipp | ||
5 | * | ||
6 | * This driver can handle the old ni6510 board and the newer ni6510 | ||
7 | * EtherBlaster. (probably it also works with every full NE2100 | ||
8 | * compatible card) | ||
9 | * | ||
10 | * To compile as module, type: | ||
11 | * gcc -O2 -fomit-frame-pointer -m486 -D__KERNEL__ -DMODULE -c ni65.c | ||
12 | * driver probes: io: 0x360,0x300,0x320,0x340 / dma: 3,5,6,7 | ||
13 | * | ||
14 | * This is an extension to the Linux operating system, and is covered by the | ||
15 | * same GNU General Public License that covers the Linux-kernel. | ||
16 | * | ||
17 | * comments/bugs/suggestions can be sent to: | ||
18 | * Michael Hipp | ||
19 | * email: hippm@informatik.uni-tuebingen.de | ||
20 | * | ||
21 | * sources: | ||
22 | * some things are from the 'ni6510-packet-driver for dos by Russ Nelson' | ||
23 | * and from the original drivers by D.Becker | ||
24 | * | ||
25 | * known problems: | ||
26 | * - on some PCI boards (including my own) the card/board/ISA-bridge has | ||
27 | * problems with bus master DMA. This results in lotsa overruns. | ||
28 | * It may help to '#define RCV_PARANOIA_CHECK' or try to #undef | ||
29 | * the XMT and RCV_VIA_SKB option .. this reduces driver performance. | ||
30 | * Or just play with your BIOS options to optimize ISA-DMA access. | ||
31 | * Maybe you also wanna play with the LOW_PERFORAMCE and MID_PERFORMANCE | ||
32 | * defines -> please report me your experience then | ||
33 | * - Harald reported for ASUS SP3G mainboards, that you should use | ||
34 | * the 'optimal settings' from the user's manual on page 3-12! | ||
35 | * | ||
36 | * credits: | ||
37 | * thanx to Jason Sullivan for sending me a ni6510 card! | ||
38 | * lot of debug runs with ASUS SP3G Boards (Intel Saturn) by Harald Koenig | ||
39 | * | ||
40 | * simple performance test: (486DX-33/Ni6510-EB receives from 486DX4-100/Ni6510-EB) | ||
41 | * average: FTP -> 8384421 bytes received in 8.5 seconds | ||
42 | * (no RCV_VIA_SKB,no XMT_VIA_SKB,PARANOIA_CHECK,4 XMIT BUFS, 8 RCV_BUFFS) | ||
43 | * peak: FTP -> 8384421 bytes received in 7.5 seconds | ||
44 | * (RCV_VIA_SKB,XMT_VIA_SKB,no PARANOIA_CHECK,1(!) XMIT BUF, 16 RCV BUFFS) | ||
45 | */ | ||
46 | |||
47 | /* | ||
48 | * 99.Jun.8: added support for /proc/net/dev byte count for xosview (HK) | ||
49 | * 96.Sept.29: virt_to_bus stuff added for new memory modell | ||
50 | * 96.April.29: Added Harald Koenig's Patches (MH) | ||
51 | * 96.April.13: enhanced error handling .. more tests (MH) | ||
52 | * 96.April.5/6: a lot of performance tests. Got it stable now (hopefully) (MH) | ||
53 | * 96.April.1: (no joke ;) .. added EtherBlaster and Module support (MH) | ||
54 | * 96.Feb.19: fixed a few bugs .. cleanups .. tested for 1.3.66 (MH) | ||
55 | * hopefully no more 16MB limit | ||
56 | * | ||
57 | * 95.Nov.18: multicast tweaked (AC). | ||
58 | * | ||
59 | * 94.Aug.22: changes in xmit_intr (ack more than one xmitted-packet), ni65_send_packet (p->lock) (MH) | ||
60 | * | ||
61 | * 94.July.16: fixed bugs in recv_skb and skb-alloc stuff (MH) | ||
62 | */ | ||
63 | |||
64 | #include <linux/kernel.h> | ||
65 | #include <linux/string.h> | ||
66 | #include <linux/errno.h> | ||
67 | #include <linux/ioport.h> | ||
68 | #include <linux/slab.h> | ||
69 | #include <linux/interrupt.h> | ||
70 | #include <linux/delay.h> | ||
71 | #include <linux/init.h> | ||
72 | #include <linux/netdevice.h> | ||
73 | #include <linux/etherdevice.h> | ||
74 | #include <linux/skbuff.h> | ||
75 | #include <linux/module.h> | ||
76 | #include <linux/bitops.h> | ||
77 | |||
78 | #include <asm/io.h> | ||
79 | #include <asm/dma.h> | ||
80 | |||
81 | #include "ni65.h" | ||
82 | |||
83 | /* | ||
84 | * the current setting allows an acceptable performance | ||
85 | * for 'RCV_PARANOIA_CHECK' read the 'known problems' part in | ||
86 | * the header of this file | ||
87 | * 'invert' the defines for max. performance. This may cause DMA problems | ||
88 | * on some boards (e.g on my ASUS SP3G) | ||
89 | */ | ||
90 | #undef XMT_VIA_SKB | ||
91 | #undef RCV_VIA_SKB | ||
92 | #define RCV_PARANOIA_CHECK | ||
93 | |||
94 | #define MID_PERFORMANCE | ||
95 | |||
96 | #if defined( LOW_PERFORMANCE ) | ||
97 | static int isa0=7,isa1=7,csr80=0x0c10; | ||
98 | #elif defined( MID_PERFORMANCE ) | ||
99 | static int isa0=5,isa1=5,csr80=0x2810; | ||
100 | #else /* high performance */ | ||
101 | static int isa0=4,isa1=4,csr80=0x0017; | ||
102 | #endif | ||
103 | |||
104 | /* | ||
105 | * a few card/vendor specific defines | ||
106 | */ | ||
107 | #define NI65_ID0 0x00 | ||
108 | #define NI65_ID1 0x55 | ||
109 | #define NI65_EB_ID0 0x52 | ||
110 | #define NI65_EB_ID1 0x44 | ||
111 | #define NE2100_ID0 0x57 | ||
112 | #define NE2100_ID1 0x57 | ||
113 | |||
114 | #define PORT p->cmdr_addr | ||
115 | |||
116 | /* | ||
117 | * buffer configuration | ||
118 | */ | ||
119 | #if 1 | ||
120 | #define RMDNUM 16 | ||
121 | #define RMDNUMMASK 0x80000000 | ||
122 | #else | ||
123 | #define RMDNUM 8 | ||
124 | #define RMDNUMMASK 0x60000000 /* log2(RMDNUM)<<29 */ | ||
125 | #endif | ||
126 | |||
127 | #if 0 | ||
128 | #define TMDNUM 1 | ||
129 | #define TMDNUMMASK 0x00000000 | ||
130 | #else | ||
131 | #define TMDNUM 4 | ||
132 | #define TMDNUMMASK 0x40000000 /* log2(TMDNUM)<<29 */ | ||
133 | #endif | ||
134 | |||
135 | /* slightly oversized */ | ||
136 | #define R_BUF_SIZE 1544 | ||
137 | #define T_BUF_SIZE 1544 | ||
138 | |||
139 | /* | ||
140 | * lance register defines | ||
141 | */ | ||
142 | #define L_DATAREG 0x00 | ||
143 | #define L_ADDRREG 0x02 | ||
144 | #define L_RESET 0x04 | ||
145 | #define L_CONFIG 0x05 | ||
146 | #define L_BUSIF 0x06 | ||
147 | |||
148 | /* | ||
149 | * to access the lance/am7990-regs, you have to write | ||
150 | * reg-number into L_ADDRREG, then you can access it using L_DATAREG | ||
151 | */ | ||
152 | #define CSR0 0x00 | ||
153 | #define CSR1 0x01 | ||
154 | #define CSR2 0x02 | ||
155 | #define CSR3 0x03 | ||
156 | |||
157 | #define INIT_RING_BEFORE_START 0x1 | ||
158 | #define FULL_RESET_ON_ERROR 0x2 | ||
159 | |||
160 | #if 0 | ||
161 | #define writereg(val,reg) {outw(reg,PORT+L_ADDRREG);inw(PORT+L_ADDRREG); \ | ||
162 | outw(val,PORT+L_DATAREG);inw(PORT+L_DATAREG);} | ||
163 | #define readreg(reg) (outw(reg,PORT+L_ADDRREG),inw(PORT+L_ADDRREG),\ | ||
164 | inw(PORT+L_DATAREG)) | ||
165 | #if 0 | ||
166 | #define writedatareg(val) {outw(val,PORT+L_DATAREG);inw(PORT+L_DATAREG);} | ||
167 | #else | ||
168 | #define writedatareg(val) { writereg(val,CSR0); } | ||
169 | #endif | ||
170 | #else | ||
171 | #define writereg(val,reg) {outw(reg,PORT+L_ADDRREG);outw(val,PORT+L_DATAREG);} | ||
172 | #define readreg(reg) (outw(reg,PORT+L_ADDRREG),inw(PORT+L_DATAREG)) | ||
173 | #define writedatareg(val) { writereg(val,CSR0); } | ||
174 | #endif | ||
175 | |||
176 | static unsigned char ni_vendor[] = { 0x02,0x07,0x01 }; | ||
177 | |||
178 | static struct card { | ||
179 | unsigned char id0,id1; | ||
180 | short id_offset; | ||
181 | short total_size; | ||
182 | short cmd_offset; | ||
183 | short addr_offset; | ||
184 | unsigned char *vendor_id; | ||
185 | char *cardname; | ||
186 | long config; | ||
187 | } cards[] = { | ||
188 | { | ||
189 | .id0 = NI65_ID0, | ||
190 | .id1 = NI65_ID1, | ||
191 | .id_offset = 0x0e, | ||
192 | .total_size = 0x10, | ||
193 | .cmd_offset = 0x0, | ||
194 | .addr_offset = 0x8, | ||
195 | .vendor_id = ni_vendor, | ||
196 | .cardname = "ni6510", | ||
197 | .config = 0x1, | ||
198 | }, | ||
199 | { | ||
200 | .id0 = NI65_EB_ID0, | ||
201 | .id1 = NI65_EB_ID1, | ||
202 | .id_offset = 0x0e, | ||
203 | .total_size = 0x18, | ||
204 | .cmd_offset = 0x10, | ||
205 | .addr_offset = 0x0, | ||
206 | .vendor_id = ni_vendor, | ||
207 | .cardname = "ni6510 EtherBlaster", | ||
208 | .config = 0x2, | ||
209 | }, | ||
210 | { | ||
211 | .id0 = NE2100_ID0, | ||
212 | .id1 = NE2100_ID1, | ||
213 | .id_offset = 0x0e, | ||
214 | .total_size = 0x18, | ||
215 | .cmd_offset = 0x10, | ||
216 | .addr_offset = 0x0, | ||
217 | .vendor_id = NULL, | ||
218 | .cardname = "generic NE2100", | ||
219 | .config = 0x0, | ||
220 | }, | ||
221 | }; | ||
222 | #define NUM_CARDS 3 | ||
223 | |||
224 | struct priv | ||
225 | { | ||
226 | struct rmd rmdhead[RMDNUM]; | ||
227 | struct tmd tmdhead[TMDNUM]; | ||
228 | struct init_block ib; | ||
229 | int rmdnum; | ||
230 | int tmdnum,tmdlast; | ||
231 | #ifdef RCV_VIA_SKB | ||
232 | struct sk_buff *recv_skb[RMDNUM]; | ||
233 | #else | ||
234 | void *recvbounce[RMDNUM]; | ||
235 | #endif | ||
236 | #ifdef XMT_VIA_SKB | ||
237 | struct sk_buff *tmd_skb[TMDNUM]; | ||
238 | #endif | ||
239 | void *tmdbounce[TMDNUM]; | ||
240 | int tmdbouncenum; | ||
241 | int lock,xmit_queued; | ||
242 | struct net_device_stats stats; | ||
243 | void *self; | ||
244 | int cmdr_addr; | ||
245 | int cardno; | ||
246 | int features; | ||
247 | spinlock_t ring_lock; | ||
248 | }; | ||
249 | |||
250 | static int ni65_probe1(struct net_device *dev,int); | ||
251 | static irqreturn_t ni65_interrupt(int irq, void * dev_id, struct pt_regs *regs); | ||
252 | static void ni65_recv_intr(struct net_device *dev,int); | ||
253 | static void ni65_xmit_intr(struct net_device *dev,int); | ||
254 | static int ni65_open(struct net_device *dev); | ||
255 | static int ni65_lance_reinit(struct net_device *dev); | ||
256 | static void ni65_init_lance(struct priv *p,unsigned char*,int,int); | ||
257 | static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev); | ||
258 | static void ni65_timeout(struct net_device *dev); | ||
259 | static int ni65_close(struct net_device *dev); | ||
260 | static int ni65_alloc_buffer(struct net_device *dev); | ||
261 | static void ni65_free_buffer(struct priv *p); | ||
262 | static struct net_device_stats *ni65_get_stats(struct net_device *); | ||
263 | static void set_multicast_list(struct net_device *dev); | ||
264 | |||
265 | static int irqtab[] __initdata = { 9,12,15,5 }; /* irq config-translate */ | ||
266 | static int dmatab[] __initdata = { 0,3,5,6,7 }; /* dma config-translate and autodetect */ | ||
267 | |||
268 | static int debuglevel = 1; | ||
269 | |||
270 | /* | ||
271 | * set 'performance' registers .. we must STOP lance for that | ||
272 | */ | ||
273 | static void ni65_set_performance(struct priv *p) | ||
274 | { | ||
275 | writereg(CSR0_STOP | CSR0_CLRALL,CSR0); /* STOP */ | ||
276 | |||
277 | if( !(cards[p->cardno].config & 0x02) ) | ||
278 | return; | ||
279 | |||
280 | outw(80,PORT+L_ADDRREG); | ||
281 | if(inw(PORT+L_ADDRREG) != 80) | ||
282 | return; | ||
283 | |||
284 | writereg( (csr80 & 0x3fff) ,80); /* FIFO watermarks */ | ||
285 | outw(0,PORT+L_ADDRREG); | ||
286 | outw((short)isa0,PORT+L_BUSIF); /* write ISA 0: DMA_R : isa0 * 50ns */ | ||
287 | outw(1,PORT+L_ADDRREG); | ||
288 | outw((short)isa1,PORT+L_BUSIF); /* write ISA 1: DMA_W : isa1 * 50ns */ | ||
289 | |||
290 | outw(CSR0,PORT+L_ADDRREG); /* switch back to CSR0 */ | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * open interface (up) | ||
295 | */ | ||
296 | static int ni65_open(struct net_device *dev) | ||
297 | { | ||
298 | struct priv *p = (struct priv *) dev->priv; | ||
299 | int irqval = request_irq(dev->irq, &ni65_interrupt,0, | ||
300 | cards[p->cardno].cardname,dev); | ||
301 | if (irqval) { | ||
302 | printk(KERN_ERR "%s: unable to get IRQ %d (irqval=%d).\n", | ||
303 | dev->name,dev->irq, irqval); | ||
304 | return -EAGAIN; | ||
305 | } | ||
306 | |||
307 | if(ni65_lance_reinit(dev)) | ||
308 | { | ||
309 | netif_start_queue(dev); | ||
310 | return 0; | ||
311 | } | ||
312 | else | ||
313 | { | ||
314 | free_irq(dev->irq,dev); | ||
315 | return -EAGAIN; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | /* | ||
320 | * close interface (down) | ||
321 | */ | ||
322 | static int ni65_close(struct net_device *dev) | ||
323 | { | ||
324 | struct priv *p = (struct priv *) dev->priv; | ||
325 | |||
326 | netif_stop_queue(dev); | ||
327 | |||
328 | outw(inw(PORT+L_RESET),PORT+L_RESET); /* that's the hard way */ | ||
329 | |||
330 | #ifdef XMT_VIA_SKB | ||
331 | { | ||
332 | int i; | ||
333 | for(i=0;i<TMDNUM;i++) | ||
334 | { | ||
335 | if(p->tmd_skb[i]) { | ||
336 | dev_kfree_skb(p->tmd_skb[i]); | ||
337 | p->tmd_skb[i] = NULL; | ||
338 | } | ||
339 | } | ||
340 | } | ||
341 | #endif | ||
342 | free_irq(dev->irq,dev); | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static void cleanup_card(struct net_device *dev) | ||
347 | { | ||
348 | struct priv *p = (struct priv *) dev->priv; | ||
349 | disable_dma(dev->dma); | ||
350 | free_dma(dev->dma); | ||
351 | release_region(dev->base_addr, cards[p->cardno].total_size); | ||
352 | ni65_free_buffer(p); | ||
353 | } | ||
354 | |||
355 | /* set: io,irq,dma or set it when calling insmod */ | ||
356 | static int irq; | ||
357 | static int io; | ||
358 | static int dma; | ||
359 | |||
360 | /* | ||
361 | * Probe The Card (not the lance-chip) | ||
362 | */ | ||
363 | struct net_device * __init ni65_probe(int unit) | ||
364 | { | ||
365 | struct net_device *dev = alloc_etherdev(0); | ||
366 | static int ports[] = {0x360,0x300,0x320,0x340, 0}; | ||
367 | int *port; | ||
368 | int err = 0; | ||
369 | |||
370 | if (!dev) | ||
371 | return ERR_PTR(-ENOMEM); | ||
372 | |||
373 | if (unit >= 0) { | ||
374 | sprintf(dev->name, "eth%d", unit); | ||
375 | netdev_boot_setup_check(dev); | ||
376 | irq = dev->irq; | ||
377 | dma = dev->dma; | ||
378 | } else { | ||
379 | dev->base_addr = io; | ||
380 | } | ||
381 | |||
382 | if (dev->base_addr > 0x1ff) { /* Check a single specified location. */ | ||
383 | err = ni65_probe1(dev, dev->base_addr); | ||
384 | } else if (dev->base_addr > 0) { /* Don't probe at all. */ | ||
385 | err = -ENXIO; | ||
386 | } else { | ||
387 | for (port = ports; *port && ni65_probe1(dev, *port); port++) | ||
388 | ; | ||
389 | if (!*port) | ||
390 | err = -ENODEV; | ||
391 | } | ||
392 | if (err) | ||
393 | goto out; | ||
394 | |||
395 | err = register_netdev(dev); | ||
396 | if (err) | ||
397 | goto out1; | ||
398 | return dev; | ||
399 | out1: | ||
400 | cleanup_card(dev); | ||
401 | out: | ||
402 | free_netdev(dev); | ||
403 | return ERR_PTR(err); | ||
404 | } | ||
405 | |||
406 | /* | ||
407 | * this is the real card probe .. | ||
408 | */ | ||
409 | static int __init ni65_probe1(struct net_device *dev,int ioaddr) | ||
410 | { | ||
411 | int i,j; | ||
412 | struct priv *p; | ||
413 | unsigned long flags; | ||
414 | |||
415 | dev->irq = irq; | ||
416 | dev->dma = dma; | ||
417 | |||
418 | for(i=0;i<NUM_CARDS;i++) { | ||
419 | if(!request_region(ioaddr, cards[i].total_size, cards[i].cardname)) | ||
420 | continue; | ||
421 | if(cards[i].id_offset >= 0) { | ||
422 | if(inb(ioaddr+cards[i].id_offset+0) != cards[i].id0 || | ||
423 | inb(ioaddr+cards[i].id_offset+1) != cards[i].id1) { | ||
424 | release_region(ioaddr, cards[i].total_size); | ||
425 | continue; | ||
426 | } | ||
427 | } | ||
428 | if(cards[i].vendor_id) { | ||
429 | for(j=0;j<3;j++) | ||
430 | if(inb(ioaddr+cards[i].addr_offset+j) != cards[i].vendor_id[j]) { | ||
431 | release_region(ioaddr, cards[i].total_size); | ||
432 | continue; | ||
433 | } | ||
434 | } | ||
435 | break; | ||
436 | } | ||
437 | if(i == NUM_CARDS) | ||
438 | return -ENODEV; | ||
439 | |||
440 | for(j=0;j<6;j++) | ||
441 | dev->dev_addr[j] = inb(ioaddr+cards[i].addr_offset+j); | ||
442 | |||
443 | if( (j=ni65_alloc_buffer(dev)) < 0) { | ||
444 | release_region(ioaddr, cards[i].total_size); | ||
445 | return j; | ||
446 | } | ||
447 | p = (struct priv *) dev->priv; | ||
448 | p->cmdr_addr = ioaddr + cards[i].cmd_offset; | ||
449 | p->cardno = i; | ||
450 | spin_lock_init(&p->ring_lock); | ||
451 | |||
452 | printk(KERN_INFO "%s: %s found at %#3x, ", dev->name, cards[p->cardno].cardname , ioaddr); | ||
453 | |||
454 | outw(inw(PORT+L_RESET),PORT+L_RESET); /* first: reset the card */ | ||
455 | if( (j=readreg(CSR0)) != 0x4) { | ||
456 | printk("failed.\n"); | ||
457 | printk(KERN_ERR "%s: Can't RESET card: %04x\n", dev->name, j); | ||
458 | ni65_free_buffer(p); | ||
459 | release_region(ioaddr, cards[p->cardno].total_size); | ||
460 | return -EAGAIN; | ||
461 | } | ||
462 | |||
463 | outw(88,PORT+L_ADDRREG); | ||
464 | if(inw(PORT+L_ADDRREG) == 88) { | ||
465 | unsigned long v; | ||
466 | v = inw(PORT+L_DATAREG); | ||
467 | v <<= 16; | ||
468 | outw(89,PORT+L_ADDRREG); | ||
469 | v |= inw(PORT+L_DATAREG); | ||
470 | printk("Version %#08lx, ",v); | ||
471 | p->features = INIT_RING_BEFORE_START; | ||
472 | } | ||
473 | else { | ||
474 | printk("ancient LANCE, "); | ||
475 | p->features = 0x0; | ||
476 | } | ||
477 | |||
478 | if(test_bit(0,&cards[i].config)) { | ||
479 | dev->irq = irqtab[(inw(ioaddr+L_CONFIG)>>2)&3]; | ||
480 | dev->dma = dmatab[inw(ioaddr+L_CONFIG)&3]; | ||
481 | printk("IRQ %d (from card), DMA %d (from card).\n",dev->irq,dev->dma); | ||
482 | } | ||
483 | else { | ||
484 | if(dev->dma == 0) { | ||
485 | /* 'stuck test' from lance.c */ | ||
486 | long dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) | | ||
487 | (inb(DMA2_STAT_REG) & 0xf0); | ||
488 | for(i=1;i<5;i++) { | ||
489 | int dma = dmatab[i]; | ||
490 | if(test_bit(dma,&dma_channels) || request_dma(dma,"ni6510")) | ||
491 | continue; | ||
492 | |||
493 | flags=claim_dma_lock(); | ||
494 | disable_dma(dma); | ||
495 | set_dma_mode(dma,DMA_MODE_CASCADE); | ||
496 | enable_dma(dma); | ||
497 | release_dma_lock(flags); | ||
498 | |||
499 | ni65_init_lance(p,dev->dev_addr,0,0); /* trigger memory access */ | ||
500 | |||
501 | flags=claim_dma_lock(); | ||
502 | disable_dma(dma); | ||
503 | free_dma(dma); | ||
504 | release_dma_lock(flags); | ||
505 | |||
506 | if(readreg(CSR0) & CSR0_IDON) | ||
507 | break; | ||
508 | } | ||
509 | if(i == 5) { | ||
510 | printk("failed.\n"); | ||
511 | printk(KERN_ERR "%s: Can't detect DMA channel!\n", dev->name); | ||
512 | ni65_free_buffer(p); | ||
513 | release_region(ioaddr, cards[p->cardno].total_size); | ||
514 | return -EAGAIN; | ||
515 | } | ||
516 | dev->dma = dmatab[i]; | ||
517 | printk("DMA %d (autodetected), ",dev->dma); | ||
518 | } | ||
519 | else | ||
520 | printk("DMA %d (assigned), ",dev->dma); | ||
521 | |||
522 | if(dev->irq < 2) | ||
523 | { | ||
524 | unsigned long irq_mask; | ||
525 | |||
526 | ni65_init_lance(p,dev->dev_addr,0,0); | ||
527 | irq_mask = probe_irq_on(); | ||
528 | writereg(CSR0_INIT|CSR0_INEA,CSR0); /* trigger interrupt */ | ||
529 | msleep(20); | ||
530 | dev->irq = probe_irq_off(irq_mask); | ||
531 | if(!dev->irq) | ||
532 | { | ||
533 | printk("Failed to detect IRQ line!\n"); | ||
534 | ni65_free_buffer(p); | ||
535 | release_region(ioaddr, cards[p->cardno].total_size); | ||
536 | return -EAGAIN; | ||
537 | } | ||
538 | printk("IRQ %d (autodetected).\n",dev->irq); | ||
539 | } | ||
540 | else | ||
541 | printk("IRQ %d (assigned).\n",dev->irq); | ||
542 | } | ||
543 | |||
544 | if(request_dma(dev->dma, cards[p->cardno].cardname ) != 0) | ||
545 | { | ||
546 | printk(KERN_ERR "%s: Can't request dma-channel %d\n",dev->name,(int) dev->dma); | ||
547 | ni65_free_buffer(p); | ||
548 | release_region(ioaddr, cards[p->cardno].total_size); | ||
549 | return -EAGAIN; | ||
550 | } | ||
551 | |||
552 | dev->base_addr = ioaddr; | ||
553 | SET_MODULE_OWNER(dev); | ||
554 | dev->open = ni65_open; | ||
555 | dev->stop = ni65_close; | ||
556 | dev->hard_start_xmit = ni65_send_packet; | ||
557 | dev->tx_timeout = ni65_timeout; | ||
558 | dev->watchdog_timeo = HZ/2; | ||
559 | dev->get_stats = ni65_get_stats; | ||
560 | dev->set_multicast_list = set_multicast_list; | ||
561 | return 0; /* everything is OK */ | ||
562 | } | ||
563 | |||
564 | /* | ||
565 | * set lance register and trigger init | ||
566 | */ | ||
567 | static void ni65_init_lance(struct priv *p,unsigned char *daddr,int filter,int mode) | ||
568 | { | ||
569 | int i; | ||
570 | u32 pib; | ||
571 | |||
572 | writereg(CSR0_CLRALL|CSR0_STOP,CSR0); | ||
573 | |||
574 | for(i=0;i<6;i++) | ||
575 | p->ib.eaddr[i] = daddr[i]; | ||
576 | |||
577 | for(i=0;i<8;i++) | ||
578 | p->ib.filter[i] = filter; | ||
579 | p->ib.mode = mode; | ||
580 | |||
581 | p->ib.trp = (u32) isa_virt_to_bus(p->tmdhead) | TMDNUMMASK; | ||
582 | p->ib.rrp = (u32) isa_virt_to_bus(p->rmdhead) | RMDNUMMASK; | ||
583 | writereg(0,CSR3); /* busmaster/no word-swap */ | ||
584 | pib = (u32) isa_virt_to_bus(&p->ib); | ||
585 | writereg(pib & 0xffff,CSR1); | ||
586 | writereg(pib >> 16,CSR2); | ||
587 | |||
588 | writereg(CSR0_INIT,CSR0); /* this changes L_ADDRREG to CSR0 */ | ||
589 | |||
590 | for(i=0;i<32;i++) | ||
591 | { | ||
592 | mdelay(4); | ||
593 | if(inw(PORT+L_DATAREG) & (CSR0_IDON | CSR0_MERR) ) | ||
594 | break; /* init ok ? */ | ||
595 | } | ||
596 | } | ||
597 | |||
598 | /* | ||
599 | * allocate memory area and check the 16MB border | ||
600 | */ | ||
601 | static void *ni65_alloc_mem(struct net_device *dev,char *what,int size,int type) | ||
602 | { | ||
603 | struct sk_buff *skb=NULL; | ||
604 | unsigned char *ptr; | ||
605 | void *ret; | ||
606 | |||
607 | if(type) { | ||
608 | ret = skb = alloc_skb(2+16+size,GFP_KERNEL|GFP_DMA); | ||
609 | if(!skb) { | ||
610 | printk(KERN_WARNING "%s: unable to allocate %s memory.\n",dev->name,what); | ||
611 | return NULL; | ||
612 | } | ||
613 | skb->dev = dev; | ||
614 | skb_reserve(skb,2+16); | ||
615 | skb_put(skb,R_BUF_SIZE); /* grab the whole space .. (not necessary) */ | ||
616 | ptr = skb->data; | ||
617 | } | ||
618 | else { | ||
619 | ret = ptr = kmalloc(T_BUF_SIZE,GFP_KERNEL | GFP_DMA); | ||
620 | if(!ret) { | ||
621 | printk(KERN_WARNING "%s: unable to allocate %s memory.\n",dev->name,what); | ||
622 | return NULL; | ||
623 | } | ||
624 | } | ||
625 | if( (u32) virt_to_phys(ptr+size) > 0x1000000) { | ||
626 | printk(KERN_WARNING "%s: unable to allocate %s memory in lower 16MB!\n",dev->name,what); | ||
627 | if(type) | ||
628 | kfree_skb(skb); | ||
629 | else | ||
630 | kfree(ptr); | ||
631 | return NULL; | ||
632 | } | ||
633 | return ret; | ||
634 | } | ||
635 | |||
636 | /* | ||
637 | * allocate all memory structures .. send/recv buffers etc ... | ||
638 | */ | ||
639 | static int ni65_alloc_buffer(struct net_device *dev) | ||
640 | { | ||
641 | unsigned char *ptr; | ||
642 | struct priv *p; | ||
643 | int i; | ||
644 | |||
645 | /* | ||
646 | * we need 8-aligned memory .. | ||
647 | */ | ||
648 | ptr = ni65_alloc_mem(dev,"BUFFER",sizeof(struct priv)+8,0); | ||
649 | if(!ptr) | ||
650 | return -ENOMEM; | ||
651 | |||
652 | p = dev->priv = (struct priv *) (((unsigned long) ptr + 7) & ~0x7); | ||
653 | memset((char *) dev->priv,0,sizeof(struct priv)); | ||
654 | p->self = ptr; | ||
655 | |||
656 | for(i=0;i<TMDNUM;i++) | ||
657 | { | ||
658 | #ifdef XMT_VIA_SKB | ||
659 | p->tmd_skb[i] = NULL; | ||
660 | #endif | ||
661 | p->tmdbounce[i] = ni65_alloc_mem(dev,"XMIT",T_BUF_SIZE,0); | ||
662 | if(!p->tmdbounce[i]) { | ||
663 | ni65_free_buffer(p); | ||
664 | return -ENOMEM; | ||
665 | } | ||
666 | } | ||
667 | |||
668 | for(i=0;i<RMDNUM;i++) | ||
669 | { | ||
670 | #ifdef RCV_VIA_SKB | ||
671 | p->recv_skb[i] = ni65_alloc_mem(dev,"RECV",R_BUF_SIZE,1); | ||
672 | if(!p->recv_skb[i]) { | ||
673 | ni65_free_buffer(p); | ||
674 | return -ENOMEM; | ||
675 | } | ||
676 | #else | ||
677 | p->recvbounce[i] = ni65_alloc_mem(dev,"RECV",R_BUF_SIZE,0); | ||
678 | if(!p->recvbounce[i]) { | ||
679 | ni65_free_buffer(p); | ||
680 | return -ENOMEM; | ||
681 | } | ||
682 | #endif | ||
683 | } | ||
684 | |||
685 | return 0; /* everything is OK */ | ||
686 | } | ||
687 | |||
688 | /* | ||
689 | * free buffers and private struct | ||
690 | */ | ||
691 | static void ni65_free_buffer(struct priv *p) | ||
692 | { | ||
693 | int i; | ||
694 | |||
695 | if(!p) | ||
696 | return; | ||
697 | |||
698 | for(i=0;i<TMDNUM;i++) { | ||
699 | if(p->tmdbounce[i]) | ||
700 | kfree(p->tmdbounce[i]); | ||
701 | #ifdef XMT_VIA_SKB | ||
702 | if(p->tmd_skb[i]) | ||
703 | dev_kfree_skb(p->tmd_skb[i]); | ||
704 | #endif | ||
705 | } | ||
706 | |||
707 | for(i=0;i<RMDNUM;i++) | ||
708 | { | ||
709 | #ifdef RCV_VIA_SKB | ||
710 | if(p->recv_skb[i]) | ||
711 | dev_kfree_skb(p->recv_skb[i]); | ||
712 | #else | ||
713 | if(p->recvbounce[i]) | ||
714 | kfree(p->recvbounce[i]); | ||
715 | #endif | ||
716 | } | ||
717 | if(p->self) | ||
718 | kfree(p->self); | ||
719 | } | ||
720 | |||
721 | |||
722 | /* | ||
723 | * stop and (re)start lance .. e.g after an error | ||
724 | */ | ||
725 | static void ni65_stop_start(struct net_device *dev,struct priv *p) | ||
726 | { | ||
727 | int csr0 = CSR0_INEA; | ||
728 | |||
729 | writedatareg(CSR0_STOP); | ||
730 | |||
731 | if(debuglevel > 1) | ||
732 | printk(KERN_DEBUG "ni65_stop_start\n"); | ||
733 | |||
734 | if(p->features & INIT_RING_BEFORE_START) { | ||
735 | int i; | ||
736 | #ifdef XMT_VIA_SKB | ||
737 | struct sk_buff *skb_save[TMDNUM]; | ||
738 | #endif | ||
739 | unsigned long buffer[TMDNUM]; | ||
740 | short blen[TMDNUM]; | ||
741 | |||
742 | if(p->xmit_queued) { | ||
743 | while(1) { | ||
744 | if((p->tmdhead[p->tmdlast].u.s.status & XMIT_OWN)) | ||
745 | break; | ||
746 | p->tmdlast = (p->tmdlast + 1) & (TMDNUM-1); | ||
747 | if(p->tmdlast == p->tmdnum) | ||
748 | break; | ||
749 | } | ||
750 | } | ||
751 | |||
752 | for(i=0;i<TMDNUM;i++) { | ||
753 | struct tmd *tmdp = p->tmdhead + i; | ||
754 | #ifdef XMT_VIA_SKB | ||
755 | skb_save[i] = p->tmd_skb[i]; | ||
756 | #endif | ||
757 | buffer[i] = (u32) isa_bus_to_virt(tmdp->u.buffer); | ||
758 | blen[i] = tmdp->blen; | ||
759 | tmdp->u.s.status = 0x0; | ||
760 | } | ||
761 | |||
762 | for(i=0;i<RMDNUM;i++) { | ||
763 | struct rmd *rmdp = p->rmdhead + i; | ||
764 | rmdp->u.s.status = RCV_OWN; | ||
765 | } | ||
766 | p->tmdnum = p->xmit_queued = 0; | ||
767 | writedatareg(CSR0_STRT | csr0); | ||
768 | |||
769 | for(i=0;i<TMDNUM;i++) { | ||
770 | int num = (i + p->tmdlast) & (TMDNUM-1); | ||
771 | p->tmdhead[i].u.buffer = (u32) isa_virt_to_bus((char *)buffer[num]); /* status is part of buffer field */ | ||
772 | p->tmdhead[i].blen = blen[num]; | ||
773 | if(p->tmdhead[i].u.s.status & XMIT_OWN) { | ||
774 | p->tmdnum = (p->tmdnum + 1) & (TMDNUM-1); | ||
775 | p->xmit_queued = 1; | ||
776 | writedatareg(CSR0_TDMD | CSR0_INEA | csr0); | ||
777 | } | ||
778 | #ifdef XMT_VIA_SKB | ||
779 | p->tmd_skb[i] = skb_save[num]; | ||
780 | #endif | ||
781 | } | ||
782 | p->rmdnum = p->tmdlast = 0; | ||
783 | if(!p->lock) | ||
784 | if (p->tmdnum || !p->xmit_queued) | ||
785 | netif_wake_queue(dev); | ||
786 | dev->trans_start = jiffies; | ||
787 | } | ||
788 | else | ||
789 | writedatareg(CSR0_STRT | csr0); | ||
790 | } | ||
791 | |||
792 | /* | ||
793 | * init lance (write init-values .. init-buffers) (open-helper) | ||
794 | */ | ||
795 | static int ni65_lance_reinit(struct net_device *dev) | ||
796 | { | ||
797 | int i; | ||
798 | struct priv *p = (struct priv *) dev->priv; | ||
799 | unsigned long flags; | ||
800 | |||
801 | p->lock = 0; | ||
802 | p->xmit_queued = 0; | ||
803 | |||
804 | flags=claim_dma_lock(); | ||
805 | disable_dma(dev->dma); /* I've never worked with dma, but we do it like the packetdriver */ | ||
806 | set_dma_mode(dev->dma,DMA_MODE_CASCADE); | ||
807 | enable_dma(dev->dma); | ||
808 | release_dma_lock(flags); | ||
809 | |||
810 | outw(inw(PORT+L_RESET),PORT+L_RESET); /* first: reset the card */ | ||
811 | if( (i=readreg(CSR0) ) != 0x4) | ||
812 | { | ||
813 | printk(KERN_ERR "%s: can't RESET %s card: %04x\n",dev->name, | ||
814 | cards[p->cardno].cardname,(int) i); | ||
815 | flags=claim_dma_lock(); | ||
816 | disable_dma(dev->dma); | ||
817 | release_dma_lock(flags); | ||
818 | return 0; | ||
819 | } | ||
820 | |||
821 | p->rmdnum = p->tmdnum = p->tmdlast = p->tmdbouncenum = 0; | ||
822 | for(i=0;i<TMDNUM;i++) | ||
823 | { | ||
824 | struct tmd *tmdp = p->tmdhead + i; | ||
825 | #ifdef XMT_VIA_SKB | ||
826 | if(p->tmd_skb[i]) { | ||
827 | dev_kfree_skb(p->tmd_skb[i]); | ||
828 | p->tmd_skb[i] = NULL; | ||
829 | } | ||
830 | #endif | ||
831 | tmdp->u.buffer = 0x0; | ||
832 | tmdp->u.s.status = XMIT_START | XMIT_END; | ||
833 | tmdp->blen = tmdp->status2 = 0; | ||
834 | } | ||
835 | |||
836 | for(i=0;i<RMDNUM;i++) | ||
837 | { | ||
838 | struct rmd *rmdp = p->rmdhead + i; | ||
839 | #ifdef RCV_VIA_SKB | ||
840 | rmdp->u.buffer = (u32) isa_virt_to_bus(p->recv_skb[i]->data); | ||
841 | #else | ||
842 | rmdp->u.buffer = (u32) isa_virt_to_bus(p->recvbounce[i]); | ||
843 | #endif | ||
844 | rmdp->blen = -(R_BUF_SIZE-8); | ||
845 | rmdp->mlen = 0; | ||
846 | rmdp->u.s.status = RCV_OWN; | ||
847 | } | ||
848 | |||
849 | if(dev->flags & IFF_PROMISC) | ||
850 | ni65_init_lance(p,dev->dev_addr,0x00,M_PROM); | ||
851 | else if(dev->mc_count || dev->flags & IFF_ALLMULTI) | ||
852 | ni65_init_lance(p,dev->dev_addr,0xff,0x0); | ||
853 | else | ||
854 | ni65_init_lance(p,dev->dev_addr,0x00,0x00); | ||
855 | |||
856 | /* | ||
857 | * ni65_set_lance_mem() sets L_ADDRREG to CSR0 | ||
858 | * NOW, WE WILL NEVER CHANGE THE L_ADDRREG, CSR0 IS ALWAYS SELECTED | ||
859 | */ | ||
860 | |||
861 | if(inw(PORT+L_DATAREG) & CSR0_IDON) { | ||
862 | ni65_set_performance(p); | ||
863 | /* init OK: start lance , enable interrupts */ | ||
864 | writedatareg(CSR0_CLRALL | CSR0_INEA | CSR0_STRT); | ||
865 | return 1; /* ->OK */ | ||
866 | } | ||
867 | printk(KERN_ERR "%s: can't init lance, status: %04x\n",dev->name,(int) inw(PORT+L_DATAREG)); | ||
868 | flags=claim_dma_lock(); | ||
869 | disable_dma(dev->dma); | ||
870 | release_dma_lock(flags); | ||
871 | return 0; /* ->Error */ | ||
872 | } | ||
873 | |||
874 | /* | ||
875 | * interrupt handler | ||
876 | */ | ||
877 | static irqreturn_t ni65_interrupt(int irq, void * dev_id, struct pt_regs * regs) | ||
878 | { | ||
879 | int csr0 = 0; | ||
880 | struct net_device *dev = dev_id; | ||
881 | struct priv *p; | ||
882 | int bcnt = 32; | ||
883 | |||
884 | p = (struct priv *) dev->priv; | ||
885 | |||
886 | spin_lock(&p->ring_lock); | ||
887 | |||
888 | while(--bcnt) { | ||
889 | csr0 = inw(PORT+L_DATAREG); | ||
890 | |||
891 | #if 0 | ||
892 | writedatareg( (csr0 & CSR0_CLRALL) ); /* ack interrupts, disable int. */ | ||
893 | #else | ||
894 | writedatareg( (csr0 & CSR0_CLRALL) | CSR0_INEA ); /* ack interrupts, interrupts enabled */ | ||
895 | #endif | ||
896 | |||
897 | if(!(csr0 & (CSR0_ERR | CSR0_RINT | CSR0_TINT))) | ||
898 | break; | ||
899 | |||
900 | if(csr0 & CSR0_RINT) /* RECV-int? */ | ||
901 | ni65_recv_intr(dev,csr0); | ||
902 | if(csr0 & CSR0_TINT) /* XMIT-int? */ | ||
903 | ni65_xmit_intr(dev,csr0); | ||
904 | |||
905 | if(csr0 & CSR0_ERR) | ||
906 | { | ||
907 | struct priv *p = (struct priv *) dev->priv; | ||
908 | if(debuglevel > 1) | ||
909 | printk(KERN_ERR "%s: general error: %04x.\n",dev->name,csr0); | ||
910 | if(csr0 & CSR0_BABL) | ||
911 | p->stats.tx_errors++; | ||
912 | if(csr0 & CSR0_MISS) { | ||
913 | int i; | ||
914 | for(i=0;i<RMDNUM;i++) | ||
915 | printk("%02x ",p->rmdhead[i].u.s.status); | ||
916 | printk("\n"); | ||
917 | p->stats.rx_errors++; | ||
918 | } | ||
919 | if(csr0 & CSR0_MERR) { | ||
920 | if(debuglevel > 1) | ||
921 | printk(KERN_ERR "%s: Ooops .. memory error: %04x.\n",dev->name,csr0); | ||
922 | ni65_stop_start(dev,p); | ||
923 | } | ||
924 | } | ||
925 | } | ||
926 | |||
927 | #ifdef RCV_PARANOIA_CHECK | ||
928 | { | ||
929 | int j; | ||
930 | for(j=0;j<RMDNUM;j++) | ||
931 | { | ||
932 | struct priv *p = (struct priv *) dev->priv; | ||
933 | int i,k,num1,num2; | ||
934 | for(i=RMDNUM-1;i>0;i--) { | ||
935 | num2 = (p->rmdnum + i) & (RMDNUM-1); | ||
936 | if(!(p->rmdhead[num2].u.s.status & RCV_OWN)) | ||
937 | break; | ||
938 | } | ||
939 | |||
940 | if(i) { | ||
941 | for(k=0;k<RMDNUM;k++) { | ||
942 | num1 = (p->rmdnum + k) & (RMDNUM-1); | ||
943 | if(!(p->rmdhead[num1].u.s.status & RCV_OWN)) | ||
944 | break; | ||
945 | } | ||
946 | if(!k) | ||
947 | break; | ||
948 | |||
949 | if(debuglevel > 0) | ||
950 | { | ||
951 | char buf[256],*buf1; | ||
952 | int k; | ||
953 | buf1 = buf; | ||
954 | for(k=0;k<RMDNUM;k++) { | ||
955 | sprintf(buf1,"%02x ",(p->rmdhead[k].u.s.status)); /* & RCV_OWN) ); */ | ||
956 | buf1 += 3; | ||
957 | } | ||
958 | *buf1 = 0; | ||
959 | printk(KERN_ERR "%s: Ooops, receive ring corrupted %2d %2d | %s\n",dev->name,p->rmdnum,i,buf); | ||
960 | } | ||
961 | |||
962 | p->rmdnum = num1; | ||
963 | ni65_recv_intr(dev,csr0); | ||
964 | if((p->rmdhead[num2].u.s.status & RCV_OWN)) | ||
965 | break; /* ok, we are 'in sync' again */ | ||
966 | } | ||
967 | else | ||
968 | break; | ||
969 | } | ||
970 | } | ||
971 | #endif | ||
972 | |||
973 | if( (csr0 & (CSR0_RXON | CSR0_TXON)) != (CSR0_RXON | CSR0_TXON) ) { | ||
974 | printk(KERN_DEBUG "%s: RX or TX was offline -> restart\n",dev->name); | ||
975 | ni65_stop_start(dev,p); | ||
976 | } | ||
977 | else | ||
978 | writedatareg(CSR0_INEA); | ||
979 | |||
980 | spin_unlock(&p->ring_lock); | ||
981 | return IRQ_HANDLED; | ||
982 | } | ||
983 | |||
984 | /* | ||
985 | * We have received an Xmit-Interrupt .. | ||
986 | * send a new packet if necessary | ||
987 | */ | ||
988 | static void ni65_xmit_intr(struct net_device *dev,int csr0) | ||
989 | { | ||
990 | struct priv *p = (struct priv *) dev->priv; | ||
991 | |||
992 | while(p->xmit_queued) | ||
993 | { | ||
994 | struct tmd *tmdp = p->tmdhead + p->tmdlast; | ||
995 | int tmdstat = tmdp->u.s.status; | ||
996 | |||
997 | if(tmdstat & XMIT_OWN) | ||
998 | break; | ||
999 | |||
1000 | if(tmdstat & XMIT_ERR) | ||
1001 | { | ||
1002 | #if 0 | ||
1003 | if(tmdp->status2 & XMIT_TDRMASK && debuglevel > 3) | ||
1004 | printk(KERN_ERR "%s: tdr-problems (e.g. no resistor)\n",dev->name); | ||
1005 | #endif | ||
1006 | /* checking some errors */ | ||
1007 | if(tmdp->status2 & XMIT_RTRY) | ||
1008 | p->stats.tx_aborted_errors++; | ||
1009 | if(tmdp->status2 & XMIT_LCAR) | ||
1010 | p->stats.tx_carrier_errors++; | ||
1011 | if(tmdp->status2 & (XMIT_BUFF | XMIT_UFLO )) { | ||
1012 | /* this stops the xmitter */ | ||
1013 | p->stats.tx_fifo_errors++; | ||
1014 | if(debuglevel > 0) | ||
1015 | printk(KERN_ERR "%s: Xmit FIFO/BUFF error\n",dev->name); | ||
1016 | if(p->features & INIT_RING_BEFORE_START) { | ||
1017 | tmdp->u.s.status = XMIT_OWN | XMIT_START | XMIT_END; /* test: resend this frame */ | ||
1018 | ni65_stop_start(dev,p); | ||
1019 | break; /* no more Xmit processing .. */ | ||
1020 | } | ||
1021 | else | ||
1022 | ni65_stop_start(dev,p); | ||
1023 | } | ||
1024 | if(debuglevel > 2) | ||
1025 | printk(KERN_ERR "%s: xmit-error: %04x %02x-%04x\n",dev->name,csr0,(int) tmdstat,(int) tmdp->status2); | ||
1026 | if(!(csr0 & CSR0_BABL)) /* don't count errors twice */ | ||
1027 | p->stats.tx_errors++; | ||
1028 | tmdp->status2 = 0; | ||
1029 | } | ||
1030 | else { | ||
1031 | p->stats.tx_bytes -= (short)(tmdp->blen); | ||
1032 | p->stats.tx_packets++; | ||
1033 | } | ||
1034 | |||
1035 | #ifdef XMT_VIA_SKB | ||
1036 | if(p->tmd_skb[p->tmdlast]) { | ||
1037 | dev_kfree_skb_irq(p->tmd_skb[p->tmdlast]); | ||
1038 | p->tmd_skb[p->tmdlast] = NULL; | ||
1039 | } | ||
1040 | #endif | ||
1041 | |||
1042 | p->tmdlast = (p->tmdlast + 1) & (TMDNUM-1); | ||
1043 | if(p->tmdlast == p->tmdnum) | ||
1044 | p->xmit_queued = 0; | ||
1045 | } | ||
1046 | netif_wake_queue(dev); | ||
1047 | } | ||
1048 | |||
1049 | /* | ||
1050 | * We have received a packet | ||
1051 | */ | ||
1052 | static void ni65_recv_intr(struct net_device *dev,int csr0) | ||
1053 | { | ||
1054 | struct rmd *rmdp; | ||
1055 | int rmdstat,len; | ||
1056 | int cnt=0; | ||
1057 | struct priv *p = (struct priv *) dev->priv; | ||
1058 | |||
1059 | rmdp = p->rmdhead + p->rmdnum; | ||
1060 | while(!( (rmdstat = rmdp->u.s.status) & RCV_OWN)) | ||
1061 | { | ||
1062 | cnt++; | ||
1063 | if( (rmdstat & (RCV_START | RCV_END | RCV_ERR)) != (RCV_START | RCV_END) ) /* error or oversized? */ | ||
1064 | { | ||
1065 | if(!(rmdstat & RCV_ERR)) { | ||
1066 | if(rmdstat & RCV_START) | ||
1067 | { | ||
1068 | p->stats.rx_length_errors++; | ||
1069 | printk(KERN_ERR "%s: recv, packet too long: %d\n",dev->name,rmdp->mlen & 0x0fff); | ||
1070 | } | ||
1071 | } | ||
1072 | else { | ||
1073 | if(debuglevel > 2) | ||
1074 | printk(KERN_ERR "%s: receive-error: %04x, lance-status: %04x/%04x\n", | ||
1075 | dev->name,(int) rmdstat,csr0,(int) inw(PORT+L_DATAREG) ); | ||
1076 | if(rmdstat & RCV_FRAM) | ||
1077 | p->stats.rx_frame_errors++; | ||
1078 | if(rmdstat & RCV_OFLO) | ||
1079 | p->stats.rx_over_errors++; | ||
1080 | if(rmdstat & RCV_CRC) | ||
1081 | p->stats.rx_crc_errors++; | ||
1082 | if(rmdstat & RCV_BUF_ERR) | ||
1083 | p->stats.rx_fifo_errors++; | ||
1084 | } | ||
1085 | if(!(csr0 & CSR0_MISS)) /* don't count errors twice */ | ||
1086 | p->stats.rx_errors++; | ||
1087 | } | ||
1088 | else if( (len = (rmdp->mlen & 0x0fff) - 4) >= 60) | ||
1089 | { | ||
1090 | #ifdef RCV_VIA_SKB | ||
1091 | struct sk_buff *skb = alloc_skb(R_BUF_SIZE+2+16,GFP_ATOMIC); | ||
1092 | if (skb) | ||
1093 | skb_reserve(skb,16); | ||
1094 | #else | ||
1095 | struct sk_buff *skb = dev_alloc_skb(len+2); | ||
1096 | #endif | ||
1097 | if(skb) | ||
1098 | { | ||
1099 | skb_reserve(skb,2); | ||
1100 | skb->dev = dev; | ||
1101 | #ifdef RCV_VIA_SKB | ||
1102 | if( (unsigned long) (skb->data + R_BUF_SIZE) > 0x1000000) { | ||
1103 | skb_put(skb,len); | ||
1104 | eth_copy_and_sum(skb, (unsigned char *)(p->recv_skb[p->rmdnum]->data),len,0); | ||
1105 | } | ||
1106 | else { | ||
1107 | struct sk_buff *skb1 = p->recv_skb[p->rmdnum]; | ||
1108 | skb_put(skb,R_BUF_SIZE); | ||
1109 | p->recv_skb[p->rmdnum] = skb; | ||
1110 | rmdp->u.buffer = (u32) isa_virt_to_bus(skb->data); | ||
1111 | skb = skb1; | ||
1112 | skb_trim(skb,len); | ||
1113 | } | ||
1114 | #else | ||
1115 | skb_put(skb,len); | ||
1116 | eth_copy_and_sum(skb, (unsigned char *) p->recvbounce[p->rmdnum],len,0); | ||
1117 | #endif | ||
1118 | p->stats.rx_packets++; | ||
1119 | p->stats.rx_bytes += len; | ||
1120 | skb->protocol=eth_type_trans(skb,dev); | ||
1121 | netif_rx(skb); | ||
1122 | dev->last_rx = jiffies; | ||
1123 | } | ||
1124 | else | ||
1125 | { | ||
1126 | printk(KERN_ERR "%s: can't alloc new sk_buff\n",dev->name); | ||
1127 | p->stats.rx_dropped++; | ||
1128 | } | ||
1129 | } | ||
1130 | else { | ||
1131 | printk(KERN_INFO "%s: received runt packet\n",dev->name); | ||
1132 | p->stats.rx_errors++; | ||
1133 | } | ||
1134 | rmdp->blen = -(R_BUF_SIZE-8); | ||
1135 | rmdp->mlen = 0; | ||
1136 | rmdp->u.s.status = RCV_OWN; /* change owner */ | ||
1137 | p->rmdnum = (p->rmdnum + 1) & (RMDNUM-1); | ||
1138 | rmdp = p->rmdhead + p->rmdnum; | ||
1139 | } | ||
1140 | } | ||
1141 | |||
1142 | /* | ||
1143 | * kick xmitter .. | ||
1144 | */ | ||
1145 | |||
1146 | static void ni65_timeout(struct net_device *dev) | ||
1147 | { | ||
1148 | int i; | ||
1149 | struct priv *p = (struct priv *) dev->priv; | ||
1150 | |||
1151 | printk(KERN_ERR "%s: xmitter timed out, try to restart!\n",dev->name); | ||
1152 | for(i=0;i<TMDNUM;i++) | ||
1153 | printk("%02x ",p->tmdhead[i].u.s.status); | ||
1154 | printk("\n"); | ||
1155 | ni65_lance_reinit(dev); | ||
1156 | dev->trans_start = jiffies; | ||
1157 | netif_wake_queue(dev); | ||
1158 | } | ||
1159 | |||
1160 | /* | ||
1161 | * Send a packet | ||
1162 | */ | ||
1163 | |||
1164 | static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev) | ||
1165 | { | ||
1166 | struct priv *p = (struct priv *) dev->priv; | ||
1167 | |||
1168 | netif_stop_queue(dev); | ||
1169 | |||
1170 | if (test_and_set_bit(0, (void*)&p->lock)) { | ||
1171 | printk(KERN_ERR "%s: Queue was locked.\n", dev->name); | ||
1172 | return 1; | ||
1173 | } | ||
1174 | |||
1175 | { | ||
1176 | short len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; | ||
1177 | struct tmd *tmdp; | ||
1178 | unsigned long flags; | ||
1179 | |||
1180 | #ifdef XMT_VIA_SKB | ||
1181 | if( (unsigned long) (skb->data + skb->len) > 0x1000000) { | ||
1182 | #endif | ||
1183 | |||
1184 | memcpy((char *) p->tmdbounce[p->tmdbouncenum] ,(char *)skb->data, | ||
1185 | (skb->len > T_BUF_SIZE) ? T_BUF_SIZE : skb->len); | ||
1186 | if (len > skb->len) | ||
1187 | memset((char *)p->tmdbounce[p->tmdbouncenum]+skb->len, 0, len-skb->len); | ||
1188 | dev_kfree_skb (skb); | ||
1189 | |||
1190 | spin_lock_irqsave(&p->ring_lock, flags); | ||
1191 | tmdp = p->tmdhead + p->tmdnum; | ||
1192 | tmdp->u.buffer = (u32) isa_virt_to_bus(p->tmdbounce[p->tmdbouncenum]); | ||
1193 | p->tmdbouncenum = (p->tmdbouncenum + 1) & (TMDNUM - 1); | ||
1194 | |||
1195 | #ifdef XMT_VIA_SKB | ||
1196 | } | ||
1197 | else { | ||
1198 | spin_lock_irqsave(&p->ring_lock, flags); | ||
1199 | |||
1200 | tmdp = p->tmdhead + p->tmdnum; | ||
1201 | tmdp->u.buffer = (u32) isa_virt_to_bus(skb->data); | ||
1202 | p->tmd_skb[p->tmdnum] = skb; | ||
1203 | } | ||
1204 | #endif | ||
1205 | tmdp->blen = -len; | ||
1206 | |||
1207 | tmdp->u.s.status = XMIT_OWN | XMIT_START | XMIT_END; | ||
1208 | writedatareg(CSR0_TDMD | CSR0_INEA); /* enable xmit & interrupt */ | ||
1209 | |||
1210 | p->xmit_queued = 1; | ||
1211 | p->tmdnum = (p->tmdnum + 1) & (TMDNUM-1); | ||
1212 | |||
1213 | if(p->tmdnum != p->tmdlast) | ||
1214 | netif_wake_queue(dev); | ||
1215 | |||
1216 | p->lock = 0; | ||
1217 | dev->trans_start = jiffies; | ||
1218 | |||
1219 | spin_unlock_irqrestore(&p->ring_lock, flags); | ||
1220 | } | ||
1221 | |||
1222 | return 0; | ||
1223 | } | ||
1224 | |||
1225 | static struct net_device_stats *ni65_get_stats(struct net_device *dev) | ||
1226 | { | ||
1227 | |||
1228 | #if 0 | ||
1229 | int i; | ||
1230 | struct priv *p = (struct priv *) dev->priv; | ||
1231 | for(i=0;i<RMDNUM;i++) | ||
1232 | { | ||
1233 | struct rmd *rmdp = p->rmdhead + ((p->rmdnum + i) & (RMDNUM-1)); | ||
1234 | printk("%02x ",rmdp->u.s.status); | ||
1235 | } | ||
1236 | printk("\n"); | ||
1237 | #endif | ||
1238 | |||
1239 | return &((struct priv *) dev->priv)->stats; | ||
1240 | } | ||
1241 | |||
1242 | static void set_multicast_list(struct net_device *dev) | ||
1243 | { | ||
1244 | if(!ni65_lance_reinit(dev)) | ||
1245 | printk(KERN_ERR "%s: Can't switch card into MC mode!\n",dev->name); | ||
1246 | netif_wake_queue(dev); | ||
1247 | } | ||
1248 | |||
1249 | #ifdef MODULE | ||
1250 | static struct net_device *dev_ni65; | ||
1251 | |||
1252 | module_param(irq, int, 0); | ||
1253 | module_param(io, int, 0); | ||
1254 | module_param(dma, int, 0); | ||
1255 | MODULE_PARM_DESC(irq, "ni6510 IRQ number (ignored for some cards)"); | ||
1256 | MODULE_PARM_DESC(io, "ni6510 I/O base address"); | ||
1257 | MODULE_PARM_DESC(dma, "ni6510 ISA DMA channel (ignored for some cards)"); | ||
1258 | |||
1259 | int init_module(void) | ||
1260 | { | ||
1261 | dev_ni65 = ni65_probe(-1); | ||
1262 | return IS_ERR(dev_ni65) ? PTR_ERR(dev_ni65) : 0; | ||
1263 | } | ||
1264 | |||
1265 | void cleanup_module(void) | ||
1266 | { | ||
1267 | unregister_netdev(dev_ni65); | ||
1268 | cleanup_card(dev_ni65); | ||
1269 | free_netdev(dev_ni65); | ||
1270 | } | ||
1271 | #endif /* MODULE */ | ||
1272 | |||
1273 | MODULE_LICENSE("GPL"); | ||
1274 | |||
1275 | /* | ||
1276 | * END of ni65.c | ||
1277 | */ | ||