Commit | Line | Data |
---|---|---|
21ac5de2 | 1 | /* |
016ac65c | 2 | * Device driver for National Semiconductor DS8390/WD83C690 based ethernet |
21ac5de2 DG |
3 | * adapters. By David Greenman, 29-April-1993 |
4 | * | |
5 | * Copyright (C) 1993, David Greenman. This software may be used, modified, | |
6 | * copied, distributed, and sold, in both source and binary form provided | |
7 | * that the above copyright and these terms are retained. Under no | |
8 | * circumstances is the author responsible for the proper functioning | |
9 | * of this software, nor does the author assume any responsibility | |
10 | * for damages incurred with its use. | |
11 | * | |
016ac65c | 12 | * Currently supports the Western Digital/SMC 8003 and 8013 series, |
362c9b14 DG |
13 | * the SMC Elite Ultra (8216), the 3Com 3c503, the NE1000 and NE2000, |
14 | * and a variety of similar clones. | |
a24ec720 DG |
15 | * |
16 | * Thanks to Charles Hannum for proving to me with example code that the | |
17 | * NE1000/2000 support could be added with minimal impact. Without | |
18 | * this, I wouldn't have proceeded in this direction. | |
19 | * | |
21ac5de2 DG |
20 | */ |
21 | ||
b12abaae | 22 | /* |
de9b9c67 | 23 | * $Id: if_ed.c,v 1.30 1994/01/31 07:34:20 davidg Exp $ |
b12abaae DG |
24 | */ |
25 | ||
21ac5de2 DG |
26 | #include "ed.h" |
27 | #if NED > 0 | |
b12abaae | 28 | /* bpfilter included here in case it is needed in future net includes */ |
21ac5de2 DG |
29 | #include "bpfilter.h" |
30 | ||
31 | #include "param.h" | |
d6d150e8 | 32 | #include "systm.h" |
21ac5de2 DG |
33 | #include "errno.h" |
34 | #include "ioctl.h" | |
35 | #include "mbuf.h" | |
36 | #include "socket.h" | |
37 | #include "syslog.h" | |
38 | ||
39 | #include "net/if.h" | |
40 | #include "net/if_dl.h" | |
41 | #include "net/if_types.h" | |
42 | #include "net/netisr.h" | |
43 | ||
44 | #ifdef INET | |
45 | #include "netinet/in.h" | |
46 | #include "netinet/in_systm.h" | |
47 | #include "netinet/in_var.h" | |
48 | #include "netinet/ip.h" | |
49 | #include "netinet/if_ether.h" | |
50 | #endif | |
51 | ||
52 | #ifdef NS | |
53 | #include "netns/ns.h" | |
54 | #include "netns/ns_if.h" | |
55 | #endif | |
56 | ||
57 | #if NBPFILTER > 0 | |
58 | #include "net/bpf.h" | |
59 | #include "net/bpfdesc.h" | |
60 | #endif | |
61 | ||
62 | #include "i386/isa/isa.h" | |
63 | #include "i386/isa/isa_device.h" | |
64 | #include "i386/isa/icu.h" | |
65 | #include "i386/isa/if_edreg.h" | |
66 | ||
67 | #include "i386/include/pio.h" | |
68 | ||
4d8228f9 DG |
69 | /* For backwards compatibility */ |
70 | #ifndef IFF_ALTPHYS | |
71 | #define IFF_ALTPHYS IFF_LLC0 | |
72 | #endif | |
21ac5de2 DG |
73 | |
74 | /* | |
75 | * ed_softc: per line info and status | |
76 | */ | |
77 | struct ed_softc { | |
78 | struct arpcom arpcom; /* ethernet common */ | |
79 | ||
80 | char *type_str; /* pointer to type string */ | |
81 | u_char vendor; /* interface vendor */ | |
82 | u_char type; /* interface type code */ | |
83 | ||
21ac5de2 DG |
84 | u_short asic_addr; /* ASIC I/O bus address */ |
85 | u_short nic_addr; /* NIC (DS8390) I/O bus address */ | |
86 | ||
b12abaae DG |
87 | /* |
88 | * The following 'proto' variable is part of a work-around for 8013EBT asics | |
89 | * being write-only. It's sort of a prototype/shadow of the real thing. | |
90 | */ | |
91 | u_char wd_laar_proto; | |
016ac65c | 92 | u_char isa16bit; /* width of access to card 0=8 or 1=16 */ |
d2a46cd2 | 93 | int is790; /* set by the probe code if the card is 790 based */ |
21ac5de2 DG |
94 | |
95 | caddr_t bpf; /* BPF "magic cookie" */ | |
016ac65c DG |
96 | caddr_t mem_start; /* NIC memory start address */ |
97 | caddr_t mem_end; /* NIC memory end address */ | |
98 | u_long mem_size; /* total NIC memory size */ | |
99 | caddr_t mem_ring; /* start of RX ring-buffer (in NIC mem) */ | |
21ac5de2 | 100 | |
016ac65c | 101 | u_char mem_shared; /* NIC memory is shared with host */ |
21ac5de2 | 102 | u_char xmit_busy; /* transmitter is busy */ |
016ac65c DG |
103 | u_char txb_cnt; /* number of transmit buffers */ |
104 | u_char txb_inuse; /* number of TX buffers currently in-use*/ | |
21ac5de2 | 105 | |
016ac65c DG |
106 | u_char txb_new; /* pointer to where new buffer will be added */ |
107 | u_char txb_next_tx; /* pointer to next buffer ready to xmit */ | |
108 | u_short txb_len[8]; /* buffered xmit buffer lengths */ | |
109 | u_char tx_page_start; /* first page of TX buffer area */ | |
21ac5de2 DG |
110 | u_char rec_page_start; /* first page of RX ring-buffer */ |
111 | u_char rec_page_stop; /* last page of RX ring-buffer */ | |
112 | u_char next_packet; /* pointer to next unread RX packet */ | |
113 | } ed_softc[NED]; | |
114 | ||
8164a262 DG |
115 | int ed_attach(struct isa_device *); |
116 | void ed_init(int); | |
117 | void edintr(int); | |
118 | int ed_ioctl(struct ifnet *, int, caddr_t); | |
119 | int ed_probe(struct isa_device *); | |
120 | void ed_start(struct ifnet *); | |
121 | void ed_reset(int, int); | |
122 | void ed_watchdog(int); | |
123 | ||
4c45483e GW |
124 | static void ed_get_packet(struct ed_softc *, char *, int /*u_short*/); |
125 | static void ed_stop(int); | |
21ac5de2 DG |
126 | |
127 | static inline void ed_rint(); | |
128 | static inline void ed_xmit(); | |
129 | static inline char *ed_ring_copy(); | |
130 | ||
016ac65c DG |
131 | void ed_pio_readmem(), ed_pio_writemem(); |
132 | u_short ed_pio_write_mbufs(); | |
133 | ||
21ac5de2 DG |
134 | extern int ether_output(); |
135 | ||
016ac65c DG |
136 | struct trailer_header { |
137 | u_short ether_type; | |
138 | u_short ether_residual; | |
139 | }; | |
140 | ||
21ac5de2 DG |
141 | struct isa_driver eddriver = { |
142 | ed_probe, | |
143 | ed_attach, | |
144 | "ed" | |
145 | }; | |
146 | /* | |
147 | * Interrupt conversion table for WD/SMC ASIC | |
148 | * (IRQ* are defined in icu.h) | |
149 | */ | |
150 | static unsigned short ed_intr_mask[] = { | |
151 | IRQ9, | |
152 | IRQ3, | |
153 | IRQ5, | |
154 | IRQ7, | |
155 | IRQ10, | |
156 | IRQ11, | |
157 | IRQ15, | |
158 | IRQ4 | |
159 | }; | |
160 | ||
d2a46cd2 DG |
161 | /* |
162 | * Interrupt conversion table for 585/790 Combo | |
163 | */ | |
164 | static unsigned short ed_790_intr_mask[] = { | |
165 | 0, | |
166 | IRQ9, | |
167 | IRQ3, | |
168 | IRQ4, | |
169 | IRQ5, | |
170 | IRQ10, | |
171 | IRQ11, | |
172 | IRQ15 | |
173 | }; | |
21ac5de2 DG |
174 | #define ETHER_MIN_LEN 64 |
175 | #define ETHER_MAX_LEN 1518 | |
176 | #define ETHER_ADDR_LEN 6 | |
177 | #define ETHER_HDR_SIZE 14 | |
178 | ||
179 | /* | |
180 | * Determine if the device is present | |
181 | * | |
182 | * on entry: | |
183 | * a pointer to an isa_device struct | |
184 | * on exit: | |
185 | * NULL if device not found | |
186 | * or # of i/o addresses used (if found) | |
187 | */ | |
188 | int | |
189 | ed_probe(isa_dev) | |
190 | struct isa_device *isa_dev; | |
191 | { | |
192 | struct ed_softc *sc = &ed_softc[isa_dev->id_unit]; | |
b12abaae | 193 | int nports; |
21ac5de2 | 194 | |
b12abaae DG |
195 | if (nports = ed_probe_WD80x3(isa_dev)) |
196 | return (nports); | |
197 | ||
198 | if (nports = ed_probe_3Com(isa_dev)) | |
199 | return (nports); | |
016ac65c DG |
200 | |
201 | if (nports = ed_probe_Novell(isa_dev)) | |
202 | return (nports); | |
95445baa | 203 | |
d2a46cd2 | 204 | return(0); |
4d8228f9 | 205 | } |
21ac5de2 | 206 | |
016ac65c DG |
207 | /* |
208 | * Generic probe routine for testing for the existance of a DS8390. | |
209 | * Must be called after the NIC has just been reset. This routine | |
210 | * works by looking at certain register values that are gauranteed | |
211 | * to be initialized a certain way after power-up or reset. Seems | |
212 | * not to currently work on the 83C690. | |
213 | * | |
214 | * Specifically: | |
215 | * | |
216 | * Register reset bits set bits | |
217 | * Command Register (CR) TXP, STA RD2, STP | |
218 | * Interrupt Status (ISR) RST | |
219 | * Interrupt Mask (IMR) All bits | |
220 | * Data Control (DCR) LAS | |
221 | * Transmit Config. (TCR) LB1, LB0 | |
222 | * | |
223 | * We only look at the CR and ISR registers, however, because looking at | |
224 | * the others would require changing register pages (which would be | |
225 | * intrusive if this isn't an 8390). | |
226 | * | |
227 | * Return 1 if 8390 was found, 0 if not. | |
228 | */ | |
229 | ||
230 | int | |
231 | ed_probe_generic8390(sc) | |
232 | struct ed_softc *sc; | |
233 | { | |
234 | if ((inb(sc->nic_addr + ED_P0_CR) & | |
362c9b14 DG |
235 | (ED_CR_RD2|ED_CR_TXP|ED_CR_STA|ED_CR_STP)) != |
236 | (ED_CR_RD2|ED_CR_STP)) | |
237 | return (0); | |
016ac65c DG |
238 | if ((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RST) != ED_ISR_RST) |
239 | return (0); | |
240 | ||
241 | return(1); | |
242 | } | |
243 | ||
4d8228f9 DG |
244 | /* |
245 | * Probe and vendor-specific initialization routine for SMC/WD80x3 boards | |
246 | */ | |
247 | int | |
248 | ed_probe_WD80x3(isa_dev) | |
249 | struct isa_device *isa_dev; | |
250 | { | |
251 | struct ed_softc *sc = &ed_softc[isa_dev->id_unit]; | |
252 | int i; | |
253 | u_int memsize; | |
b12abaae DG |
254 | u_char iptr, isa16bit, sum; |
255 | ||
256 | sc->asic_addr = isa_dev->id_iobase; | |
257 | sc->nic_addr = sc->asic_addr + ED_WD_NIC_OFFSET; | |
d2a46cd2 | 258 | sc->is790 = 0; |
21ac5de2 | 259 | |
e1d36170 | 260 | #ifdef TOSH_ETHER |
788ee259 | 261 | outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_POW); |
e1d36170 AS |
262 | DELAY(10000); |
263 | #endif | |
b12abaae DG |
264 | /* |
265 | * Attempt to do a checksum over the station address PROM. | |
266 | * If it fails, it's probably not a SMC/WD board. There | |
267 | * is a problem with this, though: some clone WD boards | |
268 | * don't pass the checksum test. Danpex boards for one. | |
b12abaae DG |
269 | */ |
270 | for (sum = 0, i = 0; i < 8; ++i) | |
271 | sum += inb(sc->asic_addr + ED_WD_PROM + i); | |
55fe4dc1 DG |
272 | |
273 | if (sum != ED_WD_ROM_CHECKSUM_TOTAL) { | |
274 | /* | |
275 | * Checksum is invalid. This often happens with cheap | |
276 | * WD8003E clones. In this case, the checksum byte | |
277 | * (the eighth byte) seems to always be zero. | |
278 | */ | |
279 | if (inb(sc->asic_addr + ED_WD_CARD_ID) != ED_TYPE_WD8003E || | |
362c9b14 DG |
280 | inb(sc->asic_addr + ED_WD_PROM + 7) != 0) |
281 | return(0); | |
55fe4dc1 DG |
282 | } |
283 | ||
21ac5de2 | 284 | /* reset card to force it into a known state. */ |
e1d36170 | 285 | #ifdef TOSH_ETHER |
788ee259 | 286 | outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_RST | ED_WD_MSR_POW); |
e1d36170 | 287 | #else |
21ac5de2 | 288 | outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_RST); |
e1d36170 | 289 | #endif |
21ac5de2 DG |
290 | DELAY(100); |
291 | outb(sc->asic_addr + ED_WD_MSR, inb(sc->asic_addr + ED_WD_MSR) & ~ED_WD_MSR_RST); | |
292 | /* wait in the case this card is reading it's EEROM */ | |
293 | DELAY(5000); | |
294 | ||
016ac65c DG |
295 | sc->vendor = ED_VENDOR_WD_SMC; |
296 | sc->type = inb(sc->asic_addr + ED_WD_CARD_ID); | |
297 | ||
21ac5de2 DG |
298 | /* |
299 | * Set initial values for width/size. | |
300 | */ | |
301 | switch (sc->type) { | |
302 | case ED_TYPE_WD8003S: | |
303 | sc->type_str = "WD8003S"; | |
304 | memsize = 8192; | |
b12abaae | 305 | isa16bit = 0; |
21ac5de2 DG |
306 | break; |
307 | case ED_TYPE_WD8003E: | |
308 | sc->type_str = "WD8003E"; | |
309 | memsize = 8192; | |
b12abaae | 310 | isa16bit = 0; |
21ac5de2 | 311 | break; |
de9b9c67 DG |
312 | case ED_TYPE_WD8003W: |
313 | sc->type_str = "WD8003W"; | |
314 | memsize = 8192; | |
315 | isa16bit = 0; | |
316 | break; | |
21ac5de2 DG |
317 | case ED_TYPE_WD8013EBT: |
318 | sc->type_str = "WD8013EBT"; | |
319 | memsize = 16384; | |
b12abaae | 320 | isa16bit = 1; |
21ac5de2 | 321 | break; |
8164a262 DG |
322 | case ED_TYPE_WD8013W: |
323 | sc->type_str = "WD8013W"; | |
324 | memsize = 16384; | |
325 | isa16bit = 1; | |
326 | break; | |
4d8228f9 | 327 | case ED_TYPE_WD8013EP: /* also WD8003EP */ |
21ac5de2 | 328 | if (inb(sc->asic_addr + ED_WD_ICR) |
362c9b14 | 329 | & ED_WD_ICR_16BIT) { |
b12abaae | 330 | isa16bit = 1; |
21ac5de2 | 331 | memsize = 16384; |
4d8228f9 | 332 | sc->type_str = "WD8013EP"; |
21ac5de2 | 333 | } else { |
b12abaae | 334 | isa16bit = 0; |
21ac5de2 | 335 | memsize = 8192; |
b12abaae | 336 | sc->type_str = "WD8003EP"; |
21ac5de2 DG |
337 | } |
338 | break; | |
4d8228f9 DG |
339 | case ED_TYPE_WD8013WC: |
340 | sc->type_str = "WD8013WC"; | |
341 | memsize = 16384; | |
b12abaae | 342 | isa16bit = 1; |
4d8228f9 | 343 | break; |
21ac5de2 DG |
344 | case ED_TYPE_WD8013EBP: |
345 | sc->type_str = "WD8013EBP"; | |
346 | memsize = 16384; | |
b12abaae | 347 | isa16bit = 1; |
21ac5de2 DG |
348 | break; |
349 | case ED_TYPE_WD8013EPC: | |
350 | sc->type_str = "WD8013EPC"; | |
351 | memsize = 16384; | |
b12abaae | 352 | isa16bit = 1; |
21ac5de2 | 353 | break; |
d2a46cd2 DG |
354 | case ED_TYPE_SMC8216C: |
355 | sc->type_str = "SMC8216/SMC8216C"; | |
356 | memsize = 16384; | |
357 | isa16bit = 1; | |
358 | sc->is790 = 1; | |
359 | break; | |
360 | case ED_TYPE_SMC8216T: | |
361 | sc->type_str = "SMC8216T"; | |
362 | memsize = 16384; | |
363 | isa16bit = 1; | |
364 | sc->is790 = 1; | |
365 | break; | |
e1d36170 AS |
366 | #ifdef TOSH_ETHER |
367 | case ED_TYPE_TOSHIBA1: | |
368 | sc->type_str = "Toshiba1"; | |
369 | memsize = 32768; | |
370 | isa16bit = 1; | |
371 | break; | |
788ee259 AS |
372 | case ED_TYPE_TOSHIBA4: |
373 | sc->type_str = "Toshiba4"; | |
e1d36170 AS |
374 | memsize = 32768; |
375 | isa16bit = 1; | |
376 | break; | |
377 | #endif | |
21ac5de2 | 378 | default: |
b12abaae | 379 | sc->type_str = ""; |
21ac5de2 | 380 | memsize = 8192; |
b12abaae | 381 | isa16bit = 0; |
21ac5de2 DG |
382 | break; |
383 | } | |
384 | /* | |
385 | * Make some adjustments to initial values depending on what is | |
386 | * found in the ICR. | |
387 | */ | |
b12abaae | 388 | if (isa16bit && (sc->type != ED_TYPE_WD8013EBT) |
e1d36170 | 389 | #ifdef TOSH_ETHER |
788ee259 | 390 | && (sc->type != ED_TYPE_TOSHIBA1) && (sc->type != ED_TYPE_TOSHIBA4) |
e1d36170 | 391 | #endif |
362c9b14 | 392 | && ((inb(sc->asic_addr + ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) { |
b12abaae | 393 | isa16bit = 0; |
21ac5de2 DG |
394 | memsize = 8192; |
395 | } | |
21ac5de2 DG |
396 | |
397 | #if ED_DEBUG | |
e1d36170 AS |
398 | printf("type = %x type_str=%s isa16bit=%d memsize=%d id_msize=%d\n", |
399 | sc->type,sc->type_str,isa16bit,memsize,isa_dev->id_msize); | |
21ac5de2 DG |
400 | for (i=0; i<8; i++) |
401 | printf("%x -> %x\n", i, inb(sc->asic_addr + i)); | |
402 | #endif | |
14cdbcbb DG |
403 | /* |
404 | * Allow the user to override the autoconfiguration | |
405 | */ | |
406 | if (isa_dev->id_msize) | |
611ca7df | 407 | memsize = isa_dev->id_msize; |
14cdbcbb DG |
408 | /* |
409 | * (note that if the user specifies both of the following flags | |
410 | * that '8bit' mode intentionally has precedence) | |
411 | */ | |
412 | if (isa_dev->id_flags & ED_FLAGS_FORCE_16BIT_MODE) | |
b12abaae | 413 | isa16bit = 1; |
14cdbcbb | 414 | if (isa_dev->id_flags & ED_FLAGS_FORCE_8BIT_MODE) |
b12abaae | 415 | isa16bit = 0; |
611ca7df | 416 | |
5969b7e9 DG |
417 | /* |
418 | * Check 83C584 interrupt configuration register if this board has one | |
419 | * XXX - we could also check the IO address register. But why | |
420 | * bother...if we get past this, it *has* to be correct. | |
421 | */ | |
d2a46cd2 | 422 | if ((sc->type & ED_WD_SOFTCONFIG) && (!sc->is790)) { |
5969b7e9 DG |
423 | /* |
424 | * Assemble together the encoded interrupt number. | |
425 | */ | |
426 | iptr = (inb(isa_dev->id_iobase + ED_WD_ICR) & ED_WD_ICR_IR2) | | |
362c9b14 DG |
427 | ((inb(isa_dev->id_iobase + ED_WD_IRR) & |
428 | (ED_WD_IRR_IR0 | ED_WD_IRR_IR1)) >> 5); | |
5969b7e9 DG |
429 | /* |
430 | * Translate it using translation table, and check for correctness. | |
431 | */ | |
21ac5de2 | 432 | if (ed_intr_mask[iptr] != isa_dev->id_irq) { |
4d8228f9 DG |
433 | printf("ed%d: kernel configured irq %d doesn't match board configured irq %d\n", |
434 | isa_dev->id_unit, ffs(isa_dev->id_irq) - 1, ffs(ed_intr_mask[iptr]) - 1); | |
21ac5de2 DG |
435 | return(0); |
436 | } | |
5969b7e9 DG |
437 | /* |
438 | * Enable the interrupt. | |
439 | */ | |
440 | outb(isa_dev->id_iobase + ED_WD_IRR, | |
441 | inb(isa_dev->id_iobase + ED_WD_IRR) | ED_WD_IRR_IEN); | |
21ac5de2 | 442 | } |
d2a46cd2 DG |
443 | if (sc->is790) { |
444 | outb(isa_dev->id_iobase + 0x04, inb(isa_dev->id_iobase + 0x04) | 0x80); | |
445 | iptr = ((inb(isa_dev->id_iobase + 0x0d) & 0x0c ) >> 2) | | |
446 | ((inb(isa_dev->id_iobase + 0x0d) & 0x40) >> 4); | |
447 | outb(isa_dev->id_iobase + 0x04, inb(isa_dev->id_iobase + 0x04) & ~0x80); | |
448 | ||
449 | if (ed_790_intr_mask[iptr] != isa_dev->id_irq) { | |
450 | printf("ed%d: kernel configured irq %d doesn't match board configured irq %d %d\n", | |
451 | isa_dev->id_unit, ffs(isa_dev->id_irq) - 1, ffs(ed_790_intr_mask[iptr]) -1, iptr); | |
452 | return 0; | |
453 | } | |
454 | outb(isa_dev->id_iobase + 0x06, inb(isa_dev->id_iobase + 0x06) | 0x01); | |
455 | } | |
21ac5de2 | 456 | |
b12abaae | 457 | sc->isa16bit = isa16bit; |
016ac65c DG |
458 | |
459 | #ifdef notyet /* XXX - I'm not sure if PIO mode is even possible on WD/SMC boards */ | |
460 | /* | |
461 | * The following allows the WD/SMC boards to be used in Programmed I/O | |
462 | * mode - without mapping the NIC memory shared. ...Not the prefered | |
463 | * way, but it might be the only way. | |
464 | */ | |
465 | if (isa_dev->id_flags & ED_FLAGS_FORCE_PIO) { | |
466 | sc->mem_shared = 0; | |
467 | isa_dev->id_maddr = 0; | |
468 | } else { | |
469 | sc->mem_shared = 1; | |
470 | } | |
471 | #else | |
472 | sc->mem_shared = 1; | |
473 | #endif | |
474 | isa_dev->id_msize = memsize; | |
475 | ||
476 | sc->mem_start = (caddr_t)isa_dev->id_maddr; | |
b12abaae | 477 | |
21ac5de2 DG |
478 | /* |
479 | * allocate one xmit buffer if < 16k, two buffers otherwise | |
480 | */ | |
016ac65c DG |
481 | if ((memsize < 16384) || (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING)) { |
482 | sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE); | |
21ac5de2 DG |
483 | sc->txb_cnt = 1; |
484 | sc->rec_page_start = ED_TXBUF_SIZE; | |
485 | } else { | |
016ac65c | 486 | sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE * 2); |
21ac5de2 DG |
487 | sc->txb_cnt = 2; |
488 | sc->rec_page_start = ED_TXBUF_SIZE * 2; | |
489 | } | |
016ac65c DG |
490 | sc->mem_size = memsize; |
491 | sc->mem_end = sc->mem_start + memsize; | |
21ac5de2 DG |
492 | sc->rec_page_stop = memsize / ED_PAGE_SIZE; |
493 | sc->tx_page_start = ED_WD_PAGE_OFFSET; | |
494 | ||
495 | /* | |
496 | * Get station address from on-board ROM | |
497 | */ | |
498 | for (i = 0; i < ETHER_ADDR_LEN; ++i) | |
499 | sc->arpcom.ac_enaddr[i] = inb(sc->asic_addr + ED_WD_PROM + i); | |
500 | ||
016ac65c DG |
501 | if (sc->mem_shared) { |
502 | /* | |
503 | * Set address and enable interface shared memory. | |
504 | */ | |
d2a46cd2 | 505 | if(!sc->is790) { |
e1d36170 AS |
506 | #ifdef TOSH_ETHER |
507 | outb(sc->asic_addr + ED_WD_MSR + 1, ((kvtop(sc->mem_start) >> 8) & 0xe0) | 4); | |
508 | outb(sc->asic_addr + ED_WD_MSR + 2, ((kvtop(sc->mem_start) >> 16) & 0x0f)); | |
788ee259 | 509 | outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB | ED_WD_MSR_POW); |
e1d36170 AS |
510 | |
511 | #else | |
d2a46cd2 DG |
512 | outb(sc->asic_addr + ED_WD_MSR, ((kvtop(sc->mem_start) >> 13) & |
513 | ED_WD_MSR_ADDR) | ED_WD_MSR_MENB); | |
e1d36170 | 514 | #endif |
d2a46cd2 DG |
515 | } else { |
516 | outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB); | |
517 | outb(sc->asic_addr + 0x04, (inb(sc->asic_addr + 0x04) | 0x80)); | |
518 | outb(sc->asic_addr + 0x0b, ((kvtop(sc->mem_start) >> 13) & 0x0f) | | |
362c9b14 DG |
519 | ((kvtop(sc->mem_start) >> 11) & 0x40) | |
520 | (inb(sc->asic_addr + 0x0b) & 0xb0)); | |
d2a46cd2 DG |
521 | outb(sc->asic_addr + 0x04, (inb(sc->asic_addr + 0x04) & ~0x80)); |
522 | } | |
21ac5de2 | 523 | |
016ac65c DG |
524 | /* |
525 | * Set upper address bits and 8/16 bit access to shared memory | |
526 | */ | |
527 | if (isa16bit) { | |
d2a46cd2 DG |
528 | if (sc->is790) { |
529 | sc->wd_laar_proto = inb(sc->asic_addr + ED_WD_LAAR); | |
530 | outb(sc->asic_addr + ED_WD_LAAR, ED_WD_LAAR_M16EN); | |
531 | } else { | |
532 | outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto = | |
362c9b14 DG |
533 | ED_WD_LAAR_L16EN | ED_WD_LAAR_M16EN | |
534 | ((kvtop(sc->mem_start) >> 19) & ED_WD_LAAR_ADDRHI))); | |
d2a46cd2 | 535 | } |
016ac65c | 536 | } else { |
362c9b14 | 537 | if ((sc->type & ED_WD_SOFTCONFIG) || |
e1d36170 | 538 | #ifdef TOSH_ETHER |
788ee259 | 539 | (sc->type == ED_TYPE_TOSHIBA1) || (sc->type == ED_TYPE_TOSHIBA4) || |
e1d36170 | 540 | #endif |
362c9b14 | 541 | (sc->type == ED_TYPE_WD8013EBT) && (!sc->is790)) { |
016ac65c | 542 | outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto = |
362c9b14 | 543 | ((kvtop(sc->mem_start) >> 19) & ED_WD_LAAR_ADDRHI))); |
016ac65c DG |
544 | } |
545 | } | |
21ac5de2 | 546 | |
016ac65c DG |
547 | /* |
548 | * Now zero memory and verify that it is clear | |
549 | */ | |
550 | bzero(sc->mem_start, memsize); | |
21ac5de2 | 551 | |
016ac65c DG |
552 | for (i = 0; i < memsize; ++i) |
553 | if (sc->mem_start[i]) { | |
554 | printf("ed%d: failed to clear shared memory at %x - check configuration\n", | |
555 | isa_dev->id_unit, kvtop(sc->mem_start + i)); | |
21ac5de2 | 556 | |
016ac65c DG |
557 | /* |
558 | * Disable 16 bit access to shared memory | |
559 | */ | |
560 | if (isa16bit) | |
561 | outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto &= | |
362c9b14 | 562 | ~ED_WD_LAAR_M16EN)); |
21ac5de2 | 563 | |
016ac65c DG |
564 | return(0); |
565 | } | |
21ac5de2 | 566 | |
016ac65c DG |
567 | /* |
568 | * Disable 16bit access to shared memory - we leave it disabled so | |
569 | * that 1) machines reboot properly when the board is set | |
570 | * 16 bit mode and there are conflicting 8bit devices/ROMS | |
571 | * in the same 128k address space as this boards shared | |
572 | * memory. and 2) so that other 8 bit devices with shared | |
573 | * memory can be used in this 128k region, too. | |
574 | */ | |
575 | if (isa16bit) | |
576 | outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto &= | |
362c9b14 | 577 | ~ED_WD_LAAR_M16EN)); |
016ac65c DG |
578 | |
579 | } | |
21ac5de2 | 580 | |
21ac5de2 | 581 | return (ED_WD_IO_PORTS); |
4d8228f9 | 582 | } |
21ac5de2 | 583 | |
4d8228f9 DG |
584 | /* |
585 | * Probe and vendor-specific initialization routine for 3Com 3c503 boards | |
586 | */ | |
016ac65c | 587 | int |
4d8228f9 DG |
588 | ed_probe_3Com(isa_dev) |
589 | struct isa_device *isa_dev; | |
590 | { | |
591 | struct ed_softc *sc = &ed_softc[isa_dev->id_unit]; | |
592 | int i; | |
593 | u_int memsize; | |
b12abaae | 594 | u_char isa16bit, sum; |
21ac5de2 | 595 | |
21ac5de2 DG |
596 | sc->asic_addr = isa_dev->id_iobase + ED_3COM_ASIC_OFFSET; |
597 | sc->nic_addr = isa_dev->id_iobase + ED_3COM_NIC_OFFSET; | |
598 | ||
21ac5de2 DG |
599 | /* |
600 | * Verify that the kernel configured I/O address matches the board | |
601 | * configured address | |
602 | */ | |
286a528a | 603 | switch (inb(sc->asic_addr + ED_3COM_BCFR)) { |
21ac5de2 DG |
604 | case ED_3COM_BCFR_300: |
605 | if (isa_dev->id_iobase != 0x300) | |
606 | return(0); | |
607 | break; | |
608 | case ED_3COM_BCFR_310: | |
609 | if (isa_dev->id_iobase != 0x310) | |
610 | return(0); | |
611 | break; | |
612 | case ED_3COM_BCFR_330: | |
613 | if (isa_dev->id_iobase != 0x330) | |
614 | return(0); | |
615 | break; | |
616 | case ED_3COM_BCFR_350: | |
617 | if (isa_dev->id_iobase != 0x350) | |
618 | return(0); | |
619 | break; | |
620 | case ED_3COM_BCFR_250: | |
621 | if (isa_dev->id_iobase != 0x250) | |
622 | return(0); | |
623 | break; | |
624 | case ED_3COM_BCFR_280: | |
625 | if (isa_dev->id_iobase != 0x280) | |
626 | return(0); | |
627 | break; | |
628 | case ED_3COM_BCFR_2A0: | |
629 | if (isa_dev->id_iobase != 0x2a0) | |
630 | return(0); | |
631 | break; | |
632 | case ED_3COM_BCFR_2E0: | |
633 | if (isa_dev->id_iobase != 0x2e0) | |
634 | return(0); | |
635 | break; | |
14622cd9 DG |
636 | default: |
637 | return(0); | |
21ac5de2 DG |
638 | } |
639 | ||
640 | /* | |
641 | * Verify that the kernel shared memory address matches the | |
642 | * board configured address. | |
643 | */ | |
286a528a | 644 | switch (inb(sc->asic_addr + ED_3COM_PCFR)) { |
21ac5de2 | 645 | case ED_3COM_PCFR_DC000: |
286a528a | 646 | if (kvtop(isa_dev->id_maddr) != 0xdc000) |
21ac5de2 DG |
647 | return(0); |
648 | break; | |
649 | case ED_3COM_PCFR_D8000: | |
286a528a | 650 | if (kvtop(isa_dev->id_maddr) != 0xd8000) |
21ac5de2 DG |
651 | return(0); |
652 | break; | |
653 | case ED_3COM_PCFR_CC000: | |
286a528a | 654 | if (kvtop(isa_dev->id_maddr) != 0xcc000) |
21ac5de2 DG |
655 | return(0); |
656 | break; | |
657 | case ED_3COM_PCFR_C8000: | |
286a528a | 658 | if (kvtop(isa_dev->id_maddr) != 0xc8000) |
21ac5de2 DG |
659 | return(0); |
660 | break; | |
14622cd9 DG |
661 | default: |
662 | return(0); | |
21ac5de2 DG |
663 | } |
664 | ||
b12abaae | 665 | |
21ac5de2 | 666 | /* |
b12abaae DG |
667 | * Reset NIC and ASIC. Enable on-board transceiver throughout reset |
668 | * sequence because it'll lock up if the cable isn't connected | |
669 | * if we don't. | |
21ac5de2 | 670 | */ |
4d8228f9 DG |
671 | outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_RST | ED_3COM_CR_XSEL); |
672 | ||
21ac5de2 DG |
673 | /* |
674 | * Wait for a while, then un-reset it | |
675 | */ | |
4d8228f9 DG |
676 | DELAY(50); |
677 | /* | |
678 | * The 3Com ASIC defaults to rather strange settings for the CR after | |
679 | * a reset - it's important to set it again after the following | |
680 | * outb (this is done when we map the PROM below). | |
681 | */ | |
682 | outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL); | |
21ac5de2 DG |
683 | |
684 | /* | |
ac7f64c9 | 685 | * Wait a bit for the NIC to recover from the reset |
21ac5de2 | 686 | */ |
016ac65c DG |
687 | DELAY(5000); |
688 | ||
689 | sc->vendor = ED_VENDOR_3COM; | |
690 | sc->type_str = "3c503"; | |
691 | ||
692 | sc->mem_shared = 1; | |
693 | ||
694 | /* | |
695 | * Hmmm...a 16bit 3Com board has 16k of memory, but only an 8k | |
696 | * window to it. | |
697 | */ | |
698 | memsize = 8192; | |
21ac5de2 DG |
699 | |
700 | /* | |
4d8228f9 DG |
701 | * Get station address from on-board ROM |
702 | */ | |
703 | /* | |
704 | * First, map ethernet address PROM over the top of where the NIC | |
705 | * registers normally appear. | |
706 | */ | |
707 | outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_EALO | ED_3COM_CR_XSEL); | |
708 | ||
709 | for (i = 0; i < ETHER_ADDR_LEN; ++i) | |
710 | sc->arpcom.ac_enaddr[i] = inb(sc->nic_addr + i); | |
711 | ||
712 | /* | |
713 | * Unmap PROM - select NIC registers. The proper setting of the | |
714 | * tranceiver is set in ed_init so that the attach code | |
715 | * is given a chance to set the default based on a compile-time | |
716 | * config option | |
21ac5de2 | 717 | */ |
4d8228f9 | 718 | outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL); |
21ac5de2 DG |
719 | |
720 | /* | |
721 | * Determine if this is an 8bit or 16bit board | |
722 | */ | |
ac7f64c9 | 723 | |
21ac5de2 DG |
724 | /* |
725 | * select page 0 registers | |
726 | */ | |
727 | outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP); | |
ac7f64c9 | 728 | |
21ac5de2 DG |
729 | /* |
730 | * Attempt to clear WTS bit. If it doesn't clear, then this is a | |
731 | * 16bit board. | |
732 | */ | |
733 | outb(sc->nic_addr + ED_P0_DCR, 0); | |
ac7f64c9 | 734 | |
21ac5de2 DG |
735 | /* |
736 | * select page 2 registers | |
737 | */ | |
738 | outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_2|ED_CR_RD2|ED_CR_STP); | |
ac7f64c9 | 739 | |
21ac5de2 DG |
740 | /* |
741 | * The 3c503 forces the WTS bit to a one if this is a 16bit board | |
742 | */ | |
743 | if (inb(sc->nic_addr + ED_P2_DCR) & ED_DCR_WTS) | |
b12abaae | 744 | isa16bit = 1; |
21ac5de2 | 745 | else |
b12abaae | 746 | isa16bit = 0; |
21ac5de2 | 747 | |
21ac5de2 DG |
748 | /* |
749 | * select page 0 registers | |
750 | */ | |
ac7f64c9 | 751 | outb(sc->nic_addr + ED_P2_CR, ED_CR_RD2|ED_CR_STP); |
21ac5de2 | 752 | |
016ac65c DG |
753 | sc->mem_start = (caddr_t)isa_dev->id_maddr; |
754 | sc->mem_size = memsize; | |
755 | sc->mem_end = sc->mem_start + memsize; | |
21ac5de2 | 756 | |
016ac65c DG |
757 | /* |
758 | * We have an entire 8k window to put the transmit buffers on the | |
759 | * 16bit boards. But since the 16bit 3c503's shared memory | |
760 | * is only fast enough to overlap the loading of one full-size | |
761 | * packet, trying to load more than 2 buffers can actually | |
762 | * leave the transmitter idle during the load. So 2 seems | |
763 | * the best value. (Although a mix of variable-sized packets | |
764 | * might change this assumption. Nonetheless, we optimize for | |
765 | * linear transfers of same-size packets.) | |
766 | */ | |
767 | if (isa16bit) { | |
768 | if (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING) | |
769 | sc->txb_cnt = 1; | |
770 | else | |
771 | sc->txb_cnt = 2; | |
772 | ||
773 | sc->tx_page_start = ED_3COM_TX_PAGE_OFFSET_16BIT; | |
774 | sc->rec_page_start = ED_3COM_RX_PAGE_OFFSET_16BIT; | |
775 | sc->rec_page_stop = memsize / ED_PAGE_SIZE + | |
776 | ED_3COM_RX_PAGE_OFFSET_16BIT; | |
777 | sc->mem_ring = sc->mem_start; | |
778 | } else { | |
779 | sc->txb_cnt = 1; | |
780 | sc->tx_page_start = ED_3COM_TX_PAGE_OFFSET_8BIT; | |
781 | sc->rec_page_start = ED_TXBUF_SIZE + ED_3COM_TX_PAGE_OFFSET_8BIT; | |
782 | sc->rec_page_stop = memsize / ED_PAGE_SIZE + | |
783 | ED_3COM_TX_PAGE_OFFSET_8BIT; | |
784 | sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE); | |
785 | } | |
21ac5de2 | 786 | |
b12abaae | 787 | sc->isa16bit = isa16bit; |
21ac5de2 DG |
788 | |
789 | /* | |
790 | * Initialize GA page start/stop registers. Probably only needed | |
791 | * if doing DMA, but what the hell. | |
792 | */ | |
793 | outb(sc->asic_addr + ED_3COM_PSTR, sc->rec_page_start); | |
794 | outb(sc->asic_addr + ED_3COM_PSPR, sc->rec_page_stop); | |
795 | ||
796 | /* | |
797 | * Set IRQ. 3c503 only allows a choice of irq 2-5. | |
798 | */ | |
799 | switch (isa_dev->id_irq) { | |
800 | case IRQ2: | |
801 | outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ2); | |
802 | break; | |
803 | case IRQ3: | |
804 | outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ3); | |
805 | break; | |
806 | case IRQ4: | |
807 | outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ4); | |
808 | break; | |
809 | case IRQ5: | |
810 | outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ5); | |
811 | break; | |
812 | default: | |
4d8228f9 DG |
813 | printf("ed%d: Invalid irq configuration (%d) must be 2-5 for 3c503\n", |
814 | isa_dev->id_unit, ffs(isa_dev->id_irq) - 1); | |
21ac5de2 DG |
815 | return(0); |
816 | } | |
817 | ||
818 | /* | |
016ac65c | 819 | * Initialize GA configuration register. Set bank and enable shared mem. |
21ac5de2 DG |
820 | */ |
821 | outb(sc->asic_addr + ED_3COM_GACFR, ED_3COM_GACFR_RSEL | | |
822 | ED_3COM_GACFR_MBS0); | |
823 | ||
824 | /* | |
825 | * Initialize "Vector Pointer" registers. These gawd-awful things | |
826 | * are compared to 20 bits of the address on ISA, and if they | |
827 | * match, the shared memory is disabled. We set them to | |
828 | * 0xffff0...allegedly the reset vector. | |
829 | */ | |
830 | outb(sc->asic_addr + ED_3COM_VPTR2, 0xff); | |
831 | outb(sc->asic_addr + ED_3COM_VPTR1, 0xff); | |
832 | outb(sc->asic_addr + ED_3COM_VPTR0, 0x00); | |
833 | ||
ac7f64c9 DG |
834 | /* |
835 | * Zero memory and verify that it is clear | |
836 | */ | |
016ac65c | 837 | bzero(sc->mem_start, memsize); |
21ac5de2 DG |
838 | |
839 | for (i = 0; i < memsize; ++i) | |
016ac65c | 840 | if (sc->mem_start[i]) { |
21ac5de2 | 841 | printf("ed%d: failed to clear shared memory at %x - check configuration\n", |
016ac65c | 842 | isa_dev->id_unit, kvtop(sc->mem_start + i)); |
21ac5de2 DG |
843 | return(0); |
844 | } | |
845 | ||
846 | isa_dev->id_msize = memsize; | |
847 | return(ED_3COM_IO_PORTS); | |
848 | } | |
016ac65c DG |
849 | |
850 | /* | |
851 | * Probe and vendor-specific initialization routine for NE1000/2000 boards | |
852 | */ | |
853 | int | |
854 | ed_probe_Novell(isa_dev) | |
855 | struct isa_device *isa_dev; | |
856 | { | |
857 | struct ed_softc *sc = &ed_softc[isa_dev->id_unit]; | |
858 | u_int memsize, n; | |
859 | u_char romdata[16], isa16bit = 0, tmp; | |
860 | static char test_pattern[32] = "THIS is A memory TEST pattern"; | |
861 | char test_buffer[32]; | |
862 | ||
863 | sc->asic_addr = isa_dev->id_iobase + ED_NOVELL_ASIC_OFFSET; | |
864 | sc->nic_addr = isa_dev->id_iobase + ED_NOVELL_NIC_OFFSET; | |
865 | ||
866 | /* XXX - do Novell-specific probe here */ | |
867 | ||
868 | /* Reset the board */ | |
869 | tmp = inb(sc->asic_addr + ED_NOVELL_RESET); | |
870 | ||
016ac65c DG |
871 | /* |
872 | * I don't know if this is necessary; probably cruft leftover from | |
873 | * Clarkson packet driver code. Doesn't do a thing on the boards | |
9cfebed5 DG |
874 | * I've tested. -DG [note that a outb(0x84, 0) seems to work |
875 | * here, and is non-invasive...but some boards don't seem to reset | |
876 | * and I don't have complete documentation on what the 'right' | |
877 | * thing to do is...so we do the invasive thing for now. Yuck.] | |
016ac65c DG |
878 | */ |
879 | outb(sc->asic_addr + ED_NOVELL_RESET, tmp); | |
880 | DELAY(5000); | |
016ac65c | 881 | |
7fdaa9b3 DG |
882 | /* |
883 | * This is needed because some NE clones apparently don't reset the | |
884 | * NIC properly (or the NIC chip doesn't reset fully on power-up) | |
9cfebed5 DG |
885 | * XXX - this makes the probe invasive! ...Done against my better |
886 | * judgement. -DLG | |
7fdaa9b3 DG |
887 | */ |
888 | outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP); | |
016ac65c | 889 | |
9cfebed5 DG |
890 | DELAY(5000); |
891 | ||
892 | /* Make sure that we really have an 8390 based board */ | |
893 | if (!ed_probe_generic8390(sc)) | |
894 | return(0); | |
895 | ||
016ac65c DG |
896 | sc->vendor = ED_VENDOR_NOVELL; |
897 | sc->mem_shared = 0; | |
898 | isa_dev->id_maddr = 0; | |
899 | ||
900 | /* | |
901 | * Test the ability to read and write to the NIC memory. This has | |
902 | * the side affect of determining if this is an NE1000 or an NE2000. | |
903 | */ | |
904 | ||
905 | /* | |
906 | * This prevents packets from being stored in the NIC memory when | |
907 | * the readmem routine turns on the start bit in the CR. | |
908 | */ | |
909 | outb(sc->nic_addr + ED_P0_RCR, ED_RCR_MON); | |
910 | ||
911 | /* Temporarily initialize DCR for byte operations */ | |
912 | outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1|ED_DCR_LS); | |
913 | ||
914 | outb(sc->nic_addr + ED_P0_PSTART, 8192 / ED_PAGE_SIZE); | |
915 | outb(sc->nic_addr + ED_P0_PSTOP, 16384 / ED_PAGE_SIZE); | |
916 | ||
917 | sc->isa16bit = 0; | |
918 | ||
919 | /* | |
920 | * Write a test pattern in byte mode. If this fails, then there | |
921 | * probably isn't any memory at 8k - which likely means | |
922 | * that the board is an NE2000. | |
923 | */ | |
924 | ed_pio_writemem(sc, test_pattern, 8192, sizeof(test_pattern)); | |
925 | ed_pio_readmem(sc, 8192, test_buffer, sizeof(test_pattern)); | |
926 | ||
927 | if (bcmp(test_pattern, test_buffer, sizeof(test_pattern))) { | |
928 | /* not an NE1000 - try NE2000 */ | |
929 | ||
362c9b14 | 930 | outb(sc->nic_addr + ED_P0_DCR, ED_DCR_WTS|ED_DCR_FT1|ED_DCR_LS); |
016ac65c DG |
931 | outb(sc->nic_addr + ED_P0_PSTART, 16384 / ED_PAGE_SIZE); |
932 | outb(sc->nic_addr + ED_P0_PSTOP, 32768 / ED_PAGE_SIZE); | |
933 | ||
934 | sc->isa16bit = 1; | |
935 | /* | |
936 | * Write a test pattern in word mode. If this also fails, then | |
937 | * we don't know what this board is. | |
938 | */ | |
939 | ed_pio_writemem(sc, test_pattern, 16384, sizeof(test_pattern)); | |
940 | ed_pio_readmem(sc, 16384, test_buffer, sizeof(test_pattern)); | |
941 | ||
942 | if (bcmp(test_pattern, test_buffer, sizeof(test_pattern))) | |
943 | return(0); /* not an NE2000 either */ | |
944 | ||
945 | sc->type = ED_TYPE_NE2000; | |
946 | sc->type_str = "NE2000"; | |
947 | } else { | |
948 | sc->type = ED_TYPE_NE1000; | |
949 | sc->type_str = "NE1000"; | |
950 | } | |
951 | ||
952 | /* 8k of memory plus an additional 8k if 16bit */ | |
953 | memsize = 8192 + sc->isa16bit * 8192; | |
954 | ||
955 | #if 0 /* probably not useful - NE boards only come two ways */ | |
956 | /* allow kernel config file overrides */ | |
957 | if (isa_dev->id_msize) | |
958 | memsize = isa_dev->id_msize; | |
959 | #endif | |
960 | ||
961 | sc->mem_size = memsize; | |
962 | ||
963 | /* NIC memory doesn't start at zero on an NE board */ | |
964 | /* The start address is tied to the bus width */ | |
965 | sc->mem_start = (char *) 8192 + sc->isa16bit * 8192; | |
966 | sc->mem_end = sc->mem_start + memsize; | |
967 | sc->tx_page_start = memsize / ED_PAGE_SIZE; | |
968 | ||
969 | /* | |
970 | * Use one xmit buffer if < 16k, two buffers otherwise (if not told | |
971 | * otherwise). | |
972 | */ | |
973 | if ((memsize < 16384) || (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING)) | |
974 | sc->txb_cnt = 1; | |
975 | else | |
976 | sc->txb_cnt = 2; | |
977 | ||
978 | sc->rec_page_start = sc->tx_page_start + sc->txb_cnt * ED_TXBUF_SIZE; | |
979 | sc->rec_page_stop = sc->tx_page_start + memsize / ED_PAGE_SIZE; | |
980 | ||
981 | sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE; | |
982 | ||
983 | ed_pio_readmem(sc, 0, romdata, 16); | |
a23f6e67 | 984 | for (n = 0; n < ETHER_ADDR_LEN; n++) |
016ac65c DG |
985 | sc->arpcom.ac_enaddr[n] = romdata[n*(sc->isa16bit+1)]; |
986 | ||
987 | /* clear any pending interrupts that might have occurred above */ | |
988 | outb(sc->nic_addr + ED_P0_ISR, 0xff); | |
989 | ||
990 | return(ED_NOVELL_IO_PORTS); | |
991 | } | |
21ac5de2 DG |
992 | |
993 | /* | |
994 | * Install interface into kernel networking data structures | |
995 | */ | |
996 | int | |
997 | ed_attach(isa_dev) | |
998 | struct isa_device *isa_dev; | |
999 | { | |
1000 | struct ed_softc *sc = &ed_softc[isa_dev->id_unit]; | |
1001 | struct ifnet *ifp = &sc->arpcom.ac_if; | |
1002 | struct ifaddr *ifa; | |
1003 | struct sockaddr_dl *sdl; | |
1004 | ||
1005 | /* | |
1006 | * Set interface to stopped condition (reset) | |
1007 | */ | |
1008 | ed_stop(isa_dev->id_unit); | |
1009 | ||
1010 | /* | |
1011 | * Initialize ifnet structure | |
1012 | */ | |
1013 | ifp->if_unit = isa_dev->id_unit; | |
1014 | ifp->if_name = "ed" ; | |
1015 | ifp->if_mtu = ETHERMTU; | |
21ac5de2 DG |
1016 | ifp->if_init = ed_init; |
1017 | ifp->if_output = ether_output; | |
1018 | ifp->if_start = ed_start; | |
1019 | ifp->if_ioctl = ed_ioctl; | |
1020 | ifp->if_reset = ed_reset; | |
1021 | ifp->if_watchdog = ed_watchdog; | |
1022 | ||
ac7f64c9 | 1023 | /* |
4d8228f9 | 1024 | * Set default state for ALTPHYS flag (used to disable the tranceiver |
ac7f64c9 DG |
1025 | * for AUI operation), based on compile-time config option. |
1026 | */ | |
1027 | if (isa_dev->id_flags & ED_FLAGS_DISABLE_TRANCEIVER) | |
362c9b14 DG |
1028 | ifp->if_flags = |
1029 | (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_ALTPHYS); | |
ac7f64c9 DG |
1030 | else |
1031 | ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS); | |
1032 | ||
5969b7e9 DG |
1033 | /* |
1034 | * Attach the interface | |
1035 | */ | |
21ac5de2 DG |
1036 | if_attach(ifp); |
1037 | ||
21ac5de2 DG |
1038 | /* |
1039 | * Search down the ifa address list looking for the AF_LINK type entry | |
1040 | */ | |
1041 | ifa = ifp->if_addrlist; | |
1042 | while ((ifa != 0) && (ifa->ifa_addr != 0) && | |
1043 | (ifa->ifa_addr->sa_family != AF_LINK)) | |
1044 | ifa = ifa->ifa_next; | |
21ac5de2 | 1045 | /* |
5969b7e9 DG |
1046 | * If we find an AF_LINK type entry we fill in the hardware address. |
1047 | * This is useful for netstat(1) to keep track of which interface | |
1048 | * is which. | |
21ac5de2 DG |
1049 | */ |
1050 | if ((ifa != 0) && (ifa->ifa_addr != 0)) { | |
1051 | /* | |
ac7f64c9 | 1052 | * Fill in the link-level address for this interface |
21ac5de2 DG |
1053 | */ |
1054 | sdl = (struct sockaddr_dl *)ifa->ifa_addr; | |
1055 | sdl->sdl_type = IFT_ETHER; | |
1056 | sdl->sdl_alen = ETHER_ADDR_LEN; | |
1057 | sdl->sdl_slen = 0; | |
1058 | bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN); | |
1059 | } | |
1060 | ||
1061 | /* | |
1062 | * Print additional info when attached | |
1063 | */ | |
b12abaae DG |
1064 | printf("ed%d: address %s, ", isa_dev->id_unit, |
1065 | ether_sprintf(sc->arpcom.ac_enaddr)); | |
1066 | ||
1067 | if (sc->type_str && (*sc->type_str != 0)) | |
1068 | printf("type %s ", sc->type_str); | |
1069 | else | |
1070 | printf("type unknown (0x%x) ", sc->type); | |
1071 | ||
1072 | printf("%s ",sc->isa16bit ? "(16 bit)" : "(8 bit)"); | |
1073 | ||
1074 | printf("%s\n", ((sc->vendor == ED_VENDOR_3COM) && | |
788ee259 | 1075 | (ifp->if_flags & IFF_ALTPHYS)) ? " tranceiver disabled" : ""); |
14cdbcbb DG |
1076 | |
1077 | /* | |
1078 | * If BPF is in the kernel, call the attach for it | |
1079 | */ | |
1080 | #if NBPFILTER > 0 | |
1081 | bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); | |
1082 | #endif | |
4c45483e | 1083 | return 1; |
21ac5de2 DG |
1084 | } |
1085 | ||
1086 | /* | |
1087 | * Reset interface. | |
1088 | */ | |
4c45483e GW |
1089 | void |
1090 | ed_reset(unit, uban) | |
21ac5de2 | 1091 | int unit; |
4c45483e | 1092 | int uban; /* XXX */ |
21ac5de2 DG |
1093 | { |
1094 | int s; | |
1095 | ||
d2a46cd2 | 1096 | s = splimp(); |
21ac5de2 DG |
1097 | |
1098 | /* | |
1099 | * Stop interface and re-initialize. | |
1100 | */ | |
1101 | ed_stop(unit); | |
1102 | ed_init(unit); | |
1103 | ||
dd18dc33 | 1104 | (void) splx(s); |
21ac5de2 DG |
1105 | } |
1106 | ||
1107 | /* | |
1108 | * Take interface offline. | |
1109 | */ | |
1110 | void | |
1111 | ed_stop(unit) | |
1112 | int unit; | |
1113 | { | |
1114 | struct ed_softc *sc = &ed_softc[unit]; | |
1115 | int n = 5000; | |
1116 | ||
1117 | /* | |
1118 | * Stop everything on the interface, and select page 0 registers. | |
1119 | */ | |
d2a46cd2 DG |
1120 | if (sc->is790) { |
1121 | outb(sc->nic_addr + ED_P0_CR, ED_CR_STP); | |
1122 | } else { | |
1123 | outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP); | |
1124 | } | |
21ac5de2 DG |
1125 | /* |
1126 | * Wait for interface to enter stopped state, but limit # of checks | |
1127 | * to 'n' (about 5ms). It shouldn't even take 5us on modern | |
1128 | * DS8390's, but just in case it's an old one. | |
1129 | */ | |
d6d150e8 DG |
1130 | while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RST) == 0) && --n); |
1131 | ||
21ac5de2 DG |
1132 | } |
1133 | ||
5969b7e9 DG |
1134 | /* |
1135 | * Device timeout/watchdog routine. Entered if the device neglects to | |
1136 | * generate an interrupt after a transmit has been started on it. | |
1137 | */ | |
4c45483e | 1138 | void |
21ac5de2 DG |
1139 | ed_watchdog(unit) |
1140 | int unit; | |
1141 | { | |
9cfebed5 DG |
1142 | struct ed_softc *sc = &ed_softc[unit]; |
1143 | ||
21ac5de2 | 1144 | log(LOG_ERR, "ed%d: device timeout\n", unit); |
9cfebed5 | 1145 | ++sc->arpcom.ac_if.if_oerrors; |
21ac5de2 | 1146 | |
4c45483e | 1147 | ed_reset(unit, 0); |
21ac5de2 DG |
1148 | } |
1149 | ||
1150 | /* | |
1151 | * Initialize device. | |
1152 | */ | |
4c45483e | 1153 | void |
21ac5de2 DG |
1154 | ed_init(unit) |
1155 | int unit; | |
1156 | { | |
1157 | struct ed_softc *sc = &ed_softc[unit]; | |
1158 | struct ifnet *ifp = &sc->arpcom.ac_if; | |
1159 | int i, s; | |
1160 | u_char command; | |
1161 | ||
1162 | ||
1163 | /* address not known */ | |
1164 | if (ifp->if_addrlist == (struct ifaddr *)0) return; | |
1165 | ||
1166 | /* | |
1167 | * Initialize the NIC in the exact order outlined in the NS manual. | |
1168 | * This init procedure is "mandatory"...don't change what or when | |
1169 | * things happen. | |
1170 | */ | |
d2a46cd2 | 1171 | s = splimp(); |
21ac5de2 DG |
1172 | |
1173 | /* reset transmitter flags */ | |
21ac5de2 DG |
1174 | sc->xmit_busy = 0; |
1175 | sc->arpcom.ac_if.if_timer = 0; | |
1176 | ||
016ac65c DG |
1177 | sc->txb_inuse = 0; |
1178 | sc->txb_new = 0; | |
1179 | sc->txb_next_tx = 0; | |
21ac5de2 DG |
1180 | |
1181 | /* This variable is used below - don't move this assignment */ | |
1182 | sc->next_packet = sc->rec_page_start + 1; | |
1183 | ||
1184 | /* | |
1185 | * Set interface for page 0, Remote DMA complete, Stopped | |
1186 | */ | |
d2a46cd2 DG |
1187 | if (sc->is790) { |
1188 | outb(sc->nic_addr + ED_P0_CR, ED_CR_STP); | |
1189 | } else { | |
1190 | outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP); | |
1191 | } | |
b12abaae | 1192 | if (sc->isa16bit) { |
21ac5de2 DG |
1193 | /* |
1194 | * Set FIFO threshold to 8, No auto-init Remote DMA, | |
b6a07cb6 | 1195 | * byte order=80x86, word-wide DMA xfers, |
21ac5de2 | 1196 | */ |
b6a07cb6 | 1197 | outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1|ED_DCR_WTS|ED_DCR_LS); |
21ac5de2 DG |
1198 | } else { |
1199 | /* | |
1200 | * Same as above, but byte-wide DMA xfers | |
1201 | */ | |
b6a07cb6 | 1202 | outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1|ED_DCR_LS); |
21ac5de2 DG |
1203 | } |
1204 | ||
1205 | /* | |
1206 | * Clear Remote Byte Count Registers | |
1207 | */ | |
1208 | outb(sc->nic_addr + ED_P0_RBCR0, 0); | |
1209 | outb(sc->nic_addr + ED_P0_RBCR1, 0); | |
1210 | ||
1211 | /* | |
1212 | * Enable reception of broadcast packets | |
1213 | */ | |
1214 | outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB); | |
1215 | ||
1216 | /* | |
1217 | * Place NIC in internal loopback mode | |
1218 | */ | |
1219 | outb(sc->nic_addr + ED_P0_TCR, ED_TCR_LB0); | |
1220 | ||
1221 | /* | |
1222 | * Initialize transmit/receive (ring-buffer) Page Start | |
1223 | */ | |
1224 | outb(sc->nic_addr + ED_P0_TPSR, sc->tx_page_start); | |
1225 | outb(sc->nic_addr + ED_P0_PSTART, sc->rec_page_start); | |
d2a46cd2 DG |
1226 | /* Set lower bits of byte addressable framing to 0 */ |
1227 | if (sc->is790) | |
1228 | outb(sc->nic_addr + 0x09, 0); | |
21ac5de2 DG |
1229 | |
1230 | /* | |
1231 | * Initialize Receiver (ring-buffer) Page Stop and Boundry | |
1232 | */ | |
1233 | outb(sc->nic_addr + ED_P0_PSTOP, sc->rec_page_stop); | |
1234 | outb(sc->nic_addr + ED_P0_BNRY, sc->rec_page_start); | |
1235 | ||
1236 | /* | |
1237 | * Clear all interrupts. A '1' in each bit position clears the | |
1238 | * corresponding flag. | |
1239 | */ | |
1240 | outb(sc->nic_addr + ED_P0_ISR, 0xff); | |
1241 | ||
1242 | /* | |
1243 | * Enable the following interrupts: receive/transmit complete, | |
1244 | * receive/transmit error, and Receiver OverWrite. | |
1245 | * | |
1246 | * Counter overflow and Remote DMA complete are *not* enabled. | |
1247 | */ | |
1248 | outb(sc->nic_addr + ED_P0_IMR, | |
362c9b14 | 1249 | ED_IMR_PRXE|ED_IMR_PTXE|ED_IMR_RXEE|ED_IMR_TXEE|ED_IMR_OVWE); |
21ac5de2 DG |
1250 | |
1251 | /* | |
1252 | * Program Command Register for page 1 | |
1253 | */ | |
d2a46cd2 DG |
1254 | if (sc->is790) { |
1255 | outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_STP); | |
1256 | } else { | |
1257 | outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STP); | |
1258 | } | |
21ac5de2 DG |
1259 | /* |
1260 | * Copy out our station address | |
1261 | */ | |
1262 | for (i = 0; i < ETHER_ADDR_LEN; ++i) | |
1263 | outb(sc->nic_addr + ED_P1_PAR0 + i, sc->arpcom.ac_enaddr[i]); | |
1264 | ||
1265 | #if NBPFILTER > 0 | |
1266 | /* | |
1267 | * Initialize multicast address hashing registers to accept | |
1268 | * all multicasts (only used when in promiscuous mode) | |
1269 | */ | |
1270 | for (i = 0; i < 8; ++i) | |
1271 | outb(sc->nic_addr + ED_P1_MAR0 + i, 0xff); | |
1272 | #endif | |
1273 | ||
1274 | /* | |
1275 | * Set Current Page pointer to next_packet (initialized above) | |
1276 | */ | |
1277 | outb(sc->nic_addr + ED_P1_CURR, sc->next_packet); | |
1278 | ||
1279 | /* | |
1280 | * Set Command Register for page 0, Remote DMA complete, | |
1281 | * and interface Start. | |
1282 | */ | |
d2a46cd2 DG |
1283 | if (sc->is790) { |
1284 | outb(sc->nic_addr + ED_P1_CR, ED_CR_STA); | |
1285 | } else { | |
1286 | outb(sc->nic_addr + ED_P1_CR, ED_CR_RD2|ED_CR_STA); | |
1287 | } | |
21ac5de2 DG |
1288 | /* |
1289 | * Take interface out of loopback | |
1290 | */ | |
1291 | outb(sc->nic_addr + ED_P0_TCR, 0); | |
1292 | ||
ac7f64c9 DG |
1293 | /* |
1294 | * If this is a 3Com board, the tranceiver must be software enabled | |
1295 | * (there is no settable hardware default). | |
1296 | */ | |
9f2aff44 | 1297 | if (sc->vendor == ED_VENDOR_3COM) { |
4d8228f9 | 1298 | if (ifp->if_flags & IFF_ALTPHYS) { |
9f2aff44 DG |
1299 | outb(sc->asic_addr + ED_3COM_CR, 0); |
1300 | } else { | |
1301 | outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL); | |
1302 | } | |
ac7f64c9 DG |
1303 | } |
1304 | ||
21ac5de2 DG |
1305 | /* |
1306 | * Set 'running' flag, and clear output active flag. | |
1307 | */ | |
1308 | ifp->if_flags |= IFF_RUNNING; | |
1309 | ifp->if_flags &= ~IFF_OACTIVE; | |
1310 | ||
1311 | /* | |
1312 | * ...and attempt to start output | |
1313 | */ | |
1314 | ed_start(ifp); | |
1315 | ||
1316 | (void) splx(s); | |
1317 | } | |
1318 | ||
5969b7e9 DG |
1319 | /* |
1320 | * This routine actually starts the transmission on the interface | |
1321 | */ | |
21ac5de2 DG |
1322 | static inline void ed_xmit(ifp) |
1323 | struct ifnet *ifp; | |
1324 | { | |
1325 | struct ed_softc *sc = &ed_softc[ifp->if_unit]; | |
016ac65c DG |
1326 | unsigned short len; |
1327 | ||
1328 | len = sc->txb_len[sc->txb_next_tx]; | |
21ac5de2 DG |
1329 | |
1330 | /* | |
1331 | * Set NIC for page 0 register access | |
1332 | */ | |
d2a46cd2 DG |
1333 | if (sc->is790) { |
1334 | outb(sc->nic_addr + ED_P0_CR, ED_CR_STA); | |
1335 | } else { | |
1336 | outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA); | |
1337 | } | |
21ac5de2 DG |
1338 | /* |
1339 | * Set TX buffer start page | |
1340 | */ | |
1341 | outb(sc->nic_addr + ED_P0_TPSR, sc->tx_page_start + | |
016ac65c | 1342 | sc->txb_next_tx * ED_TXBUF_SIZE); |
21ac5de2 DG |
1343 | |
1344 | /* | |
1345 | * Set TX length | |
1346 | */ | |
016ac65c | 1347 | outb(sc->nic_addr + ED_P0_TBCR0, len); |
21ac5de2 DG |
1348 | outb(sc->nic_addr + ED_P0_TBCR1, len >> 8); |
1349 | ||
1350 | /* | |
5969b7e9 | 1351 | * Set page 0, Remote DMA complete, Transmit Packet, and *Start* |
21ac5de2 | 1352 | */ |
d2a46cd2 DG |
1353 | if (sc->is790) { |
1354 | outb(sc->nic_addr + ED_P0_CR, ED_CR_TXP | ED_CR_STA); | |
1355 | } else { | |
1356 | outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_TXP|ED_CR_STA); | |
1357 | } | |
21ac5de2 | 1358 | sc->xmit_busy = 1; |
21ac5de2 | 1359 | |
5969b7e9 | 1360 | /* |
016ac65c | 1361 | * Point to next transmit buffer slot and wrap if necessary. |
5969b7e9 | 1362 | */ |
016ac65c DG |
1363 | sc->txb_next_tx++; |
1364 | if (sc->txb_next_tx == sc->txb_cnt) | |
1365 | sc->txb_next_tx = 0; | |
21ac5de2 DG |
1366 | |
1367 | /* | |
1368 | * Set a timer just in case we never hear from the board again | |
1369 | */ | |
1370 | ifp->if_timer = 2; | |
1371 | } | |
1372 | ||
1373 | /* | |
1374 | * Start output on interface. | |
1375 | * We make two assumptions here: | |
d2a46cd2 | 1376 | * 1) that the current priority is set to splimp _before_ this code |
21ac5de2 DG |
1377 | * is called *and* is returned to the appropriate priority after |
1378 | * return | |
1379 | * 2) that the IFF_OACTIVE flag is checked before this code is called | |
1380 | * (i.e. that the output part of the interface is idle) | |
1381 | */ | |
4c45483e | 1382 | void |
21ac5de2 DG |
1383 | ed_start(ifp) |
1384 | struct ifnet *ifp; | |
1385 | { | |
1386 | struct ed_softc *sc = &ed_softc[ifp->if_unit]; | |
1387 | struct mbuf *m0, *m; | |
1388 | caddr_t buffer; | |
1389 | int len; | |
21ac5de2 DG |
1390 | |
1391 | outloop: | |
5969b7e9 | 1392 | /* |
016ac65c DG |
1393 | * First, see if there are buffered packets and an idle |
1394 | * transmitter - should never happen at this point. | |
5969b7e9 | 1395 | */ |
016ac65c DG |
1396 | if (sc->txb_inuse && (sc->xmit_busy == 0)) { |
1397 | printf("ed: packets buffers, but transmitter idle\n"); | |
1398 | ed_xmit(ifp); | |
1399 | } | |
1400 | ||
1401 | /* | |
1402 | * See if there is room to put another packet in the buffer. | |
1403 | */ | |
1404 | if (sc->txb_inuse == sc->txb_cnt) { | |
1405 | /* | |
1406 | * No room. Indicate this to the outside world | |
1407 | * and exit. | |
1408 | */ | |
1409 | ifp->if_flags |= IFF_OACTIVE; | |
1410 | return; | |
1411 | } | |
21ac5de2 DG |
1412 | |
1413 | IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); | |
1414 | if (m == 0) { | |
1415 | /* | |
016ac65c DG |
1416 | * We are using the !OACTIVE flag to indicate to the outside |
1417 | * world that we can accept an additional packet rather than | |
1418 | * that the transmitter is _actually_ active. Indeed, the | |
1419 | * transmitter may be active, but if we haven't filled all | |
1420 | * the buffers with data then we still want to accept more. | |
21ac5de2 DG |
1421 | */ |
1422 | ifp->if_flags &= ~IFF_OACTIVE; | |
1423 | return; | |
1424 | } | |
1425 | ||
1426 | /* | |
1427 | * Copy the mbuf chain into the transmit buffer | |
1428 | */ | |
21ac5de2 | 1429 | |
a23f6e67 DG |
1430 | m0 = m; |
1431 | ||
016ac65c DG |
1432 | /* txb_new points to next open buffer slot */ |
1433 | buffer = sc->mem_start + (sc->txb_new * ED_TXBUF_SIZE * ED_PAGE_SIZE); | |
21ac5de2 | 1434 | |
016ac65c DG |
1435 | if (sc->mem_shared) { |
1436 | /* | |
1437 | * Special case setup for 16 bit boards... | |
1438 | */ | |
1439 | if (sc->isa16bit) { | |
1440 | switch (sc->vendor) { | |
1441 | /* | |
1442 | * For 16bit 3Com boards (which have 16k of memory), | |
1443 | * we have the xmit buffers in a different page | |
1444 | * of memory ('page 0') - so change pages. | |
1445 | */ | |
1446 | case ED_VENDOR_3COM: | |
1447 | outb(sc->asic_addr + ED_3COM_GACFR, | |
362c9b14 | 1448 | ED_3COM_GACFR_RSEL); |
016ac65c DG |
1449 | break; |
1450 | /* | |
1451 | * Enable 16bit access to shared memory on WD/SMC boards | |
1452 | * Don't update wd_laar_proto because we want to restore the | |
1453 | * previous state (because an arp reply in the input code | |
1454 | * may cause a call-back to ed_start) | |
1455 | * XXX - the call-back to 'start' is a bug, IMHO. | |
1456 | */ | |
1457 | case ED_VENDOR_WD_SMC: | |
1458 | outb(sc->asic_addr + ED_WD_LAAR, | |
362c9b14 | 1459 | (sc->wd_laar_proto | ED_WD_LAAR_M16EN)); |
016ac65c DG |
1460 | } |
1461 | } | |
21ac5de2 | 1462 | |
a23f6e67 | 1463 | for (len = 0; m != 0; m = m->m_next) { |
016ac65c DG |
1464 | bcopy(mtod(m, caddr_t), buffer, m->m_len); |
1465 | buffer += m->m_len; | |
1466 | len += m->m_len; | |
1467 | } | |
21ac5de2 | 1468 | |
21ac5de2 | 1469 | /* |
016ac65c | 1470 | * Restore previous shared memory access |
21ac5de2 | 1471 | */ |
016ac65c DG |
1472 | if (sc->isa16bit) { |
1473 | switch (sc->vendor) { | |
1474 | case ED_VENDOR_3COM: | |
1475 | outb(sc->asic_addr + ED_3COM_GACFR, | |
362c9b14 | 1476 | ED_3COM_GACFR_RSEL | ED_3COM_GACFR_MBS0); |
016ac65c DG |
1477 | break; |
1478 | case ED_VENDOR_WD_SMC: | |
1479 | outb(sc->asic_addr + ED_WD_LAAR, sc->wd_laar_proto); | |
1480 | break; | |
1481 | } | |
1482 | } | |
1483 | } else { | |
a23f6e67 | 1484 | len = ed_pio_write_mbufs(sc, m, buffer); |
016ac65c DG |
1485 | } |
1486 | ||
1487 | sc->txb_len[sc->txb_new] = MAX(len, ETHER_MIN_LEN); | |
1488 | ||
1489 | sc->txb_inuse++; | |
1490 | ||
1491 | /* | |
1492 | * Point to next buffer slot and wrap if necessary. | |
1493 | */ | |
1494 | sc->txb_new++; | |
1495 | if (sc->txb_new == sc->txb_cnt) | |
1496 | sc->txb_new = 0; | |
21ac5de2 DG |
1497 | |
1498 | if (sc->xmit_busy == 0) | |
1499 | ed_xmit(ifp); | |
1500 | /* | |
1501 | * If there is BPF support in the configuration, tap off here. | |
1502 | * The following has support for converting trailer packets | |
1503 | * back to normal. | |
b12abaae DG |
1504 | * XXX - support for trailer packets in BPF should be moved into |
1505 | * the bpf code proper to avoid code duplication in all of | |
1506 | * the drivers. | |
21ac5de2 DG |
1507 | */ |
1508 | #if NBPFILTER > 0 | |
1509 | if (sc->bpf) { | |
1510 | u_short etype; | |
1511 | int off, datasize, resid; | |
1512 | struct ether_header *eh; | |
016ac65c | 1513 | struct trailer_header trailer_header; |
21ac5de2 DG |
1514 | char ether_packet[ETHER_MAX_LEN]; |
1515 | char *ep; | |
1516 | ||
1517 | ep = ether_packet; | |
1518 | ||
1519 | /* | |
1520 | * We handle trailers below: | |
1521 | * Copy ether header first, then residual data, | |
1522 | * then data. Put all this in a temporary buffer | |
1523 | * 'ether_packet' and send off to bpf. Since the | |
1524 | * system has generated this packet, we assume | |
1525 | * that all of the offsets in the packet are | |
1526 | * correct; if they're not, the system will almost | |
1527 | * certainly crash in m_copydata. | |
1528 | * We make no assumptions about how the data is | |
1529 | * arranged in the mbuf chain (i.e. how much | |
1530 | * data is in each mbuf, if mbuf clusters are | |
1531 | * used, etc.), which is why we use m_copydata | |
1532 | * to get the ether header rather than assume | |
1533 | * that this is located in the first mbuf. | |
1534 | */ | |
1535 | /* copy ether header */ | |
1536 | m_copydata(m0, 0, sizeof(struct ether_header), ep); | |
1537 | eh = (struct ether_header *) ep; | |
1538 | ep += sizeof(struct ether_header); | |
1539 | etype = ntohs(eh->ether_type); | |
1540 | if (etype >= ETHERTYPE_TRAIL && | |
1541 | etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { | |
1542 | datasize = ((etype - ETHERTYPE_TRAIL) << 9); | |
1543 | off = datasize + sizeof(struct ether_header); | |
1544 | ||
1545 | /* copy trailer_header into a data structure */ | |
1546 | m_copydata(m0, off, sizeof(struct trailer_header), | |
362c9b14 | 1547 | (caddr_t)&trailer_header.ether_type); |
21ac5de2 DG |
1548 | |
1549 | /* copy residual data */ | |
1550 | m_copydata(m0, off+sizeof(struct trailer_header), | |
362c9b14 DG |
1551 | resid = ntohs(trailer_header.ether_residual) - |
1552 | sizeof(struct trailer_header), ep); | |
21ac5de2 DG |
1553 | ep += resid; |
1554 | ||
1555 | /* copy data */ | |
1556 | m_copydata(m0, sizeof(struct ether_header), | |
362c9b14 | 1557 | datasize, ep); |
21ac5de2 DG |
1558 | ep += datasize; |
1559 | ||
1560 | /* restore original ether packet type */ | |
1561 | eh->ether_type = trailer_header.ether_type; | |
1562 | ||
1563 | bpf_tap(sc->bpf, ether_packet, ep - ether_packet); | |
1564 | } else | |
1565 | bpf_mtap(sc->bpf, m0); | |
1566 | } | |
1567 | #endif | |
1568 | ||
1569 | m_freem(m0); | |
1570 | ||
5969b7e9 | 1571 | /* |
016ac65c | 1572 | * Loop back to the top to possibly buffer more packets |
5969b7e9 | 1573 | */ |
016ac65c | 1574 | goto outloop; |
21ac5de2 DG |
1575 | } |
1576 | ||
1577 | /* | |
1578 | * Ethernet interface receiver interrupt. | |
1579 | */ | |
b12abaae | 1580 | static inline void |
21ac5de2 DG |
1581 | ed_rint(unit) |
1582 | int unit; | |
1583 | { | |
1584 | register struct ed_softc *sc = &ed_softc[unit]; | |
1585 | u_char boundry, current; | |
1586 | u_short len; | |
016ac65c DG |
1587 | struct ed_ring packet_hdr; |
1588 | char *packet_ptr; | |
21ac5de2 DG |
1589 | |
1590 | /* | |
1591 | * Set NIC to page 1 registers to get 'current' pointer | |
1592 | */ | |
d2a46cd2 DG |
1593 | if (sc->is790) { |
1594 | outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_STA); | |
1595 | } else { | |
1596 | outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STA); | |
1597 | } | |
21ac5de2 DG |
1598 | /* |
1599 | * 'sc->next_packet' is the logical beginning of the ring-buffer - i.e. | |
1600 | * it points to where new data has been buffered. The 'CURR' | |
1601 | * (current) register points to the logical end of the ring-buffer | |
1602 | * - i.e. it points to where additional new data will be added. | |
1603 | * We loop here until the logical beginning equals the logical | |
1604 | * end (or in other words, until the ring-buffer is empty). | |
1605 | */ | |
1606 | while (sc->next_packet != inb(sc->nic_addr + ED_P1_CURR)) { | |
1607 | ||
016ac65c DG |
1608 | /* get pointer to this buffer's header structure */ |
1609 | packet_ptr = sc->mem_ring + | |
362c9b14 | 1610 | (sc->next_packet - sc->rec_page_start) * ED_PAGE_SIZE; |
21ac5de2 DG |
1611 | |
1612 | /* | |
1613 | * The byte count includes the FCS - Frame Check Sequence (a | |
1614 | * 32 bit CRC). | |
1615 | */ | |
016ac65c DG |
1616 | if (sc->mem_shared) |
1617 | packet_hdr = *(struct ed_ring *)packet_ptr; | |
1618 | else | |
1619 | ed_pio_readmem(sc, packet_ptr, (char *) &packet_hdr, | |
362c9b14 | 1620 | sizeof(packet_hdr)); |
016ac65c | 1621 | len = packet_hdr.count; |
21ac5de2 DG |
1622 | if ((len >= ETHER_MIN_LEN) && (len <= ETHER_MAX_LEN)) { |
1623 | /* | |
1624 | * Go get packet. len - 4 removes CRC from length. | |
21ac5de2 | 1625 | */ |
016ac65c | 1626 | ed_get_packet(sc, packet_ptr + 4, len - 4); |
21ac5de2 DG |
1627 | ++sc->arpcom.ac_if.if_ipackets; |
1628 | } else { | |
1629 | /* | |
1630 | * Really BAD...probably indicates that the ring pointers | |
1631 | * are corrupted. Also seen on early rev chips under | |
1632 | * high load - the byte order of the length gets switched. | |
1633 | */ | |
1634 | log(LOG_ERR, | |
362c9b14 DG |
1635 | "ed%d: NIC memory corrupt - invalid packet length %d\n", |
1636 | unit, len); | |
9cfebed5 | 1637 | ++sc->arpcom.ac_if.if_ierrors; |
4c45483e | 1638 | ed_reset(unit, 0); |
21ac5de2 DG |
1639 | return; |
1640 | } | |
1641 | ||
1642 | /* | |
1643 | * Update next packet pointer | |
1644 | */ | |
016ac65c | 1645 | sc->next_packet = packet_hdr.next_packet; |
21ac5de2 DG |
1646 | |
1647 | /* | |
1648 | * Update NIC boundry pointer - being careful to keep it | |
1649 | * one buffer behind. (as recommended by NS databook) | |
1650 | */ | |
1651 | boundry = sc->next_packet - 1; | |
1652 | if (boundry < sc->rec_page_start) | |
1653 | boundry = sc->rec_page_stop - 1; | |
1654 | ||
1655 | /* | |
1656 | * Set NIC to page 0 registers to update boundry register | |
1657 | */ | |
d2a46cd2 DG |
1658 | if (sc->is790) { |
1659 | outb(sc->nic_addr + ED_P0_CR, ED_CR_STA); | |
1660 | } else { | |
1661 | outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA); | |
1662 | } | |
21ac5de2 DG |
1663 | outb(sc->nic_addr + ED_P0_BNRY, boundry); |
1664 | ||
1665 | /* | |
1666 | * Set NIC to page 1 registers before looping to top (prepare to | |
1667 | * get 'CURR' current pointer) | |
1668 | */ | |
d2a46cd2 DG |
1669 | if (sc->is790) { |
1670 | outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_STA); | |
1671 | } else { | |
1672 | outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STA); | |
1673 | } | |
21ac5de2 DG |
1674 | } |
1675 | } | |
1676 | ||
1677 | /* | |
1678 | * Ethernet interface interrupt processor | |
1679 | */ | |
4c45483e | 1680 | void |
21ac5de2 DG |
1681 | edintr(unit) |
1682 | int unit; | |
1683 | { | |
1684 | struct ed_softc *sc = &ed_softc[unit]; | |
1685 | u_char isr; | |
1686 | ||
1687 | /* | |
1688 | * Set NIC to page 0 registers | |
1689 | */ | |
d2a46cd2 DG |
1690 | if (sc->is790) { |
1691 | outb(sc->nic_addr + ED_P0_CR, ED_CR_STA); | |
1692 | } else { | |
1693 | outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA); | |
1694 | } | |
21ac5de2 DG |
1695 | /* |
1696 | * loop until there are no more new interrupts | |
1697 | */ | |
1698 | while (isr = inb(sc->nic_addr + ED_P0_ISR)) { | |
1699 | ||
1700 | /* | |
b12abaae | 1701 | * reset all the bits that we are 'acknowledging' |
21ac5de2 DG |
1702 | * by writing a '1' to each bit position that was set |
1703 | * (writing a '1' *clears* the bit) | |
1704 | */ | |
1705 | outb(sc->nic_addr + ED_P0_ISR, isr); | |
1706 | ||
1707 | /* | |
b12abaae DG |
1708 | * Handle transmitter interrupts. Handle these first |
1709 | * because the receiver will reset the board under | |
1710 | * some conditions. | |
21ac5de2 | 1711 | */ |
b12abaae | 1712 | if (isr & (ED_ISR_PTX|ED_ISR_TXE)) { |
d2a46cd2 | 1713 | u_char collisions = inb(sc->nic_addr + ED_P0_NCR) & 0x0f; |
21ac5de2 DG |
1714 | |
1715 | /* | |
b12abaae DG |
1716 | * Check for transmit error. If a TX completed with an |
1717 | * error, we end up throwing the packet away. Really | |
1718 | * the only error that is possible is excessive | |
1719 | * collisions, and in this case it is best to allow the | |
1720 | * automatic mechanisms of TCP to backoff the flow. Of | |
1721 | * course, with UDP we're screwed, but this is expected | |
1722 | * when a network is heavily loaded. | |
21ac5de2 | 1723 | */ |
d2a46cd2 | 1724 | (void) inb(sc->nic_addr + ED_P0_TSR); |
b12abaae DG |
1725 | if (isr & ED_ISR_TXE) { |
1726 | ||
21ac5de2 | 1727 | /* |
b12abaae | 1728 | * Excessive collisions (16) |
21ac5de2 | 1729 | */ |
b12abaae | 1730 | if ((inb(sc->nic_addr + ED_P0_TSR) & ED_TSR_ABT) |
362c9b14 | 1731 | && (collisions == 0)) { |
b12abaae DG |
1732 | /* |
1733 | * When collisions total 16, the | |
1734 | * P0_NCR will indicate 0, and the | |
1735 | * TSR_ABT is set. | |
1736 | */ | |
1737 | collisions = 16; | |
1738 | } | |
21ac5de2 | 1739 | |
b12abaae DG |
1740 | /* |
1741 | * update output errors counter | |
1742 | */ | |
1743 | ++sc->arpcom.ac_if.if_oerrors; | |
1744 | } else { | |
1745 | /* | |
1746 | * Update total number of successfully | |
1747 | * transmitted packets. | |
1748 | */ | |
1749 | ++sc->arpcom.ac_if.if_opackets; | |
1750 | } | |
21ac5de2 DG |
1751 | |
1752 | /* | |
1753 | * reset tx busy and output active flags | |
1754 | */ | |
1755 | sc->xmit_busy = 0; | |
1756 | sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; | |
1757 | ||
1758 | /* | |
5969b7e9 | 1759 | * clear watchdog timer |
21ac5de2 DG |
1760 | */ |
1761 | sc->arpcom.ac_if.if_timer = 0; | |
21ac5de2 | 1762 | |
21ac5de2 | 1763 | /* |
b12abaae DG |
1764 | * Add in total number of collisions on last |
1765 | * transmission. | |
21ac5de2 | 1766 | */ |
b12abaae DG |
1767 | sc->arpcom.ac_if.if_collisions += collisions; |
1768 | ||
1769 | /* | |
016ac65c DG |
1770 | * Decrement buffer in-use count if not zero (can only |
1771 | * be zero if a transmitter interrupt occured while | |
1772 | * not actually transmitting). | |
b12abaae DG |
1773 | * If data is ready to transmit, start it transmitting, |
1774 | * otherwise defer until after handling receiver | |
1775 | */ | |
016ac65c | 1776 | if (sc->txb_inuse && --sc->txb_inuse) |
b12abaae | 1777 | ed_xmit(&sc->arpcom.ac_if); |
21ac5de2 DG |
1778 | } |
1779 | ||
1780 | /* | |
b12abaae | 1781 | * Handle receiver interrupts |
21ac5de2 | 1782 | */ |
b12abaae DG |
1783 | if (isr & (ED_ISR_PRX|ED_ISR_RXE|ED_ISR_OVW)) { |
1784 | /* | |
1785 | * Overwrite warning. In order to make sure that a lockup | |
1786 | * of the local DMA hasn't occurred, we reset and | |
1787 | * re-init the NIC. The NSC manual suggests only a | |
1788 | * partial reset/re-init is necessary - but some | |
1789 | * chips seem to want more. The DMA lockup has been | |
1790 | * seen only with early rev chips - Methinks this | |
1791 | * bug was fixed in later revs. -DG | |
1792 | */ | |
1793 | if (isr & ED_ISR_OVW) { | |
1794 | ++sc->arpcom.ac_if.if_ierrors; | |
016ac65c | 1795 | #ifdef DIAGNOSTIC |
b12abaae DG |
1796 | log(LOG_WARNING, |
1797 | "ed%d: warning - receiver ring buffer overrun\n", | |
1798 | unit); | |
016ac65c | 1799 | #endif |
b12abaae DG |
1800 | /* |
1801 | * Stop/reset/re-init NIC | |
1802 | */ | |
4c45483e | 1803 | ed_reset(unit, 0); |
b12abaae | 1804 | } else { |
21ac5de2 | 1805 | |
b12abaae DG |
1806 | /* |
1807 | * Receiver Error. One or more of: CRC error, frame | |
1808 | * alignment error FIFO overrun, or missed packet. | |
1809 | */ | |
1810 | if (isr & ED_ISR_RXE) { | |
1811 | ++sc->arpcom.ac_if.if_ierrors; | |
1812 | #ifdef ED_DEBUG | |
1813 | printf("ed%d: receive error %x\n", unit, | |
1814 | inb(sc->nic_addr + ED_P0_RSR)); | |
1815 | #endif | |
1816 | } | |
21ac5de2 | 1817 | |
b12abaae DG |
1818 | /* |
1819 | * Go get the packet(s) | |
1820 | * XXX - Doing this on an error is dubious | |
1821 | * because there shouldn't be any data to | |
1822 | * get (we've configured the interface to | |
1823 | * not accept packets with errors). | |
1824 | */ | |
21ac5de2 | 1825 | |
b12abaae DG |
1826 | /* |
1827 | * Enable 16bit access to shared memory first | |
1828 | * on WD/SMC boards. | |
1829 | */ | |
1830 | if (sc->isa16bit && | |
362c9b14 | 1831 | (sc->vendor == ED_VENDOR_WD_SMC)) { |
21ac5de2 | 1832 | |
21ac5de2 | 1833 | outb(sc->asic_addr + ED_WD_LAAR, |
362c9b14 DG |
1834 | (sc->wd_laar_proto |= |
1835 | ED_WD_LAAR_M16EN)); | |
21ac5de2 DG |
1836 | } |
1837 | ||
b12abaae DG |
1838 | ed_rint (unit); |
1839 | ||
1840 | /* disable 16bit access */ | |
1841 | if (sc->isa16bit && | |
1842 | (sc->vendor == ED_VENDOR_WD_SMC)) { | |
21ac5de2 | 1843 | |
21ac5de2 | 1844 | outb(sc->asic_addr + ED_WD_LAAR, |
362c9b14 DG |
1845 | (sc->wd_laar_proto &= |
1846 | ~ED_WD_LAAR_M16EN)); | |
21ac5de2 | 1847 | } |
b12abaae | 1848 | } |
21ac5de2 DG |
1849 | } |
1850 | ||
1851 | /* | |
1852 | * If it looks like the transmitter can take more data, | |
b12abaae DG |
1853 | * attempt to start output on the interface. |
1854 | * This is done after handling the receiver to | |
1855 | * give the receiver priority. | |
21ac5de2 | 1856 | */ |
b12abaae | 1857 | if ((sc->arpcom.ac_if.if_flags & IFF_OACTIVE) == 0) |
21ac5de2 | 1858 | ed_start(&sc->arpcom.ac_if); |
21ac5de2 DG |
1859 | |
1860 | /* | |
d6d150e8 DG |
1861 | * return NIC CR to standard state: page 0, remote DMA complete, |
1862 | * start (toggling the TXP bit off, even if was just set | |
1863 | * in the transmit routine, is *okay* - it is 'edge' | |
1864 | * triggered from low to high) | |
21ac5de2 | 1865 | */ |
d2a46cd2 DG |
1866 | if (sc->is790) { |
1867 | outb(sc->nic_addr + ED_P0_CR, ED_CR_STA); | |
1868 | } else { | |
1869 | outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA); | |
1870 | } | |
d6d150e8 DG |
1871 | /* |
1872 | * If the Network Talley Counters overflow, read them to | |
1873 | * reset them. It appears that old 8390's won't | |
1874 | * clear the ISR flag otherwise - resulting in an | |
1875 | * infinite loop. | |
1876 | */ | |
1877 | if (isr & ED_ISR_CNT) { | |
1878 | (void) inb(sc->nic_addr + ED_P0_CNTR0); | |
1879 | (void) inb(sc->nic_addr + ED_P0_CNTR1); | |
1880 | (void) inb(sc->nic_addr + ED_P0_CNTR2); | |
1881 | } | |
21ac5de2 DG |
1882 | } |
1883 | } | |
1884 | ||
1885 | /* | |
1886 | * Process an ioctl request. This code needs some work - it looks | |
1887 | * pretty ugly. | |
1888 | */ | |
1889 | int | |
1890 | ed_ioctl(ifp, command, data) | |
1891 | register struct ifnet *ifp; | |
1892 | int command; | |
1893 | caddr_t data; | |
1894 | { | |
1895 | register struct ifaddr *ifa = (struct ifaddr *)data; | |
1896 | struct ed_softc *sc = &ed_softc[ifp->if_unit]; | |
1897 | struct ifreq *ifr = (struct ifreq *)data; | |
1898 | int s, error = 0; | |
1899 | ||
d2a46cd2 | 1900 | s = splimp(); |
21ac5de2 DG |
1901 | |
1902 | switch (command) { | |
1903 | ||
1904 | case SIOCSIFADDR: | |
1905 | ifp->if_flags |= IFF_UP; | |
1906 | ||
1907 | switch (ifa->ifa_addr->sa_family) { | |
1908 | #ifdef INET | |
1909 | case AF_INET: | |
1910 | ed_init(ifp->if_unit); /* before arpwhohas */ | |
1911 | /* | |
1912 | * See if another station has *our* IP address. | |
1913 | * i.e.: There is an address conflict! If a | |
1914 | * conflict exists, a message is sent to the | |
1915 | * console. | |
1916 | */ | |
362c9b14 | 1917 | ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; |
21ac5de2 DG |
1918 | arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); |
1919 | break; | |
1920 | #endif | |
1921 | #ifdef NS | |
1922 | /* | |
1923 | * XXX - This code is probably wrong | |
1924 | */ | |
1925 | case AF_NS: | |
1926 | { | |
1927 | register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); | |
1928 | ||
1929 | if (ns_nullhost(*ina)) | |
1930 | ina->x_host = | |
1931 | *(union ns_host *)(sc->arpcom.ac_enaddr); | |
1932 | else { | |
1933 | /* | |
1934 | * | |
1935 | */ | |
1936 | bcopy((caddr_t)ina->x_host.c_host, | |
362c9b14 DG |
1937 | (caddr_t)sc->arpcom.ac_enaddr, |
1938 | sizeof(sc->arpcom.ac_enaddr)); | |
21ac5de2 DG |
1939 | } |
1940 | /* | |
1941 | * Set new address | |
1942 | */ | |
1943 | ed_init(ifp->if_unit); | |
1944 | break; | |
1945 | } | |
1946 | #endif | |
1947 | default: | |
1948 | ed_init(ifp->if_unit); | |
1949 | break; | |
1950 | } | |
1951 | break; | |
1952 | ||
b27f876d DG |
1953 | case SIOCGIFADDR: |
1954 | { | |
1955 | struct sockaddr *sa; | |
1956 | sa = (struct sockaddr *)&ifr->ifr_data; | |
1957 | bcopy((caddr_t)sc->arpcom.ac_enaddr, | |
1958 | (caddr_t) sa->sa_data, ETHER_ADDR_LEN); | |
1959 | } | |
1960 | break; | |
1961 | ||
21ac5de2 DG |
1962 | case SIOCSIFFLAGS: |
1963 | /* | |
1964 | * If interface is marked down and it is running, then stop it | |
1965 | */ | |
1966 | if (((ifp->if_flags & IFF_UP) == 0) && | |
1967 | (ifp->if_flags & IFF_RUNNING)) { | |
1968 | ed_stop(ifp->if_unit); | |
1969 | ifp->if_flags &= ~IFF_RUNNING; | |
1970 | } else { | |
1971 | /* | |
1972 | * If interface is marked up and it is stopped, then start it | |
1973 | */ | |
1974 | if ((ifp->if_flags & IFF_UP) && | |
1975 | ((ifp->if_flags & IFF_RUNNING) == 0)) | |
1976 | ed_init(ifp->if_unit); | |
1977 | } | |
1978 | #if NBPFILTER > 0 | |
1979 | if (ifp->if_flags & IFF_PROMISC) { | |
1980 | /* | |
1981 | * Set promiscuous mode on interface. | |
1982 | * XXX - for multicasts to work, we would need to | |
1983 | * write 1's in all bits of multicast | |
1984 | * hashing array. For now we assume that | |
1985 | * this was done in ed_init(). | |
1986 | */ | |
1987 | outb(sc->nic_addr + ED_P0_RCR, | |
362c9b14 | 1988 | ED_RCR_PRO|ED_RCR_AM|ED_RCR_AB); |
ac7f64c9 | 1989 | } else { |
21ac5de2 DG |
1990 | /* |
1991 | * XXX - for multicasts to work, we would need to | |
1992 | * rewrite the multicast hashing array with the | |
1993 | * proper hash (would have been destroyed above). | |
1994 | */ | |
1995 | outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB); | |
ac7f64c9 | 1996 | } |
21ac5de2 | 1997 | #endif |
ac7f64c9 DG |
1998 | /* |
1999 | * An unfortunate hack to provide the (required) software control | |
4d8228f9 | 2000 | * of the tranceiver for 3Com boards. The ALTPHYS flag disables |
ac7f64c9 DG |
2001 | * the tranceiver if set. |
2002 | */ | |
9f2aff44 | 2003 | if (sc->vendor == ED_VENDOR_3COM) { |
4d8228f9 | 2004 | if (ifp->if_flags & IFF_ALTPHYS) { |
9f2aff44 DG |
2005 | outb(sc->asic_addr + ED_3COM_CR, 0); |
2006 | } else { | |
2007 | outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL); | |
2008 | } | |
ac7f64c9 DG |
2009 | } |
2010 | ||
21ac5de2 DG |
2011 | break; |
2012 | ||
2013 | default: | |
2014 | error = EINVAL; | |
2015 | } | |
2016 | (void) splx(s); | |
2017 | return (error); | |
2018 | } | |
2019 | ||
2020 | /* | |
2021 | * Macro to calculate a new address within shared memory when given an offset | |
2022 | * from an address, taking into account ring-wrap. | |
2023 | */ | |
2024 | #define ringoffset(sc, start, off, type) \ | |
016ac65c DG |
2025 | ((type)( ((caddr_t)(start)+(off) >= (sc)->mem_end) ? \ |
2026 | (((caddr_t)(start)+(off))) - (sc)->mem_end \ | |
2027 | + (sc)->mem_ring: \ | |
21ac5de2 DG |
2028 | ((caddr_t)(start)+(off)) )) |
2029 | ||
2030 | /* | |
2031 | * Retreive packet from shared memory and send to the next level up via | |
2032 | * ether_input(). If there is a BPF listener, give a copy to BPF, too. | |
2033 | */ | |
4c45483e | 2034 | static void |
21ac5de2 DG |
2035 | ed_get_packet(sc, buf, len) |
2036 | struct ed_softc *sc; | |
2037 | char *buf; | |
2038 | u_short len; | |
2039 | { | |
2040 | struct ether_header *eh; | |
4c45483e | 2041 | struct mbuf *m, *head = 0, *ed_ring_to_mbuf(); |
21ac5de2 DG |
2042 | u_short off; |
2043 | int resid; | |
2044 | u_short etype; | |
016ac65c | 2045 | struct trailer_header trailer_header; |
21ac5de2 DG |
2046 | |
2047 | /* Allocate a header mbuf */ | |
2048 | MGETHDR(m, M_DONTWAIT, MT_DATA); | |
2049 | if (m == 0) | |
2050 | goto bad; | |
2051 | m->m_pkthdr.rcvif = &sc->arpcom.ac_if; | |
2052 | m->m_pkthdr.len = len; | |
2053 | m->m_len = 0; | |
2054 | head = m; | |
2055 | ||
21ac5de2 DG |
2056 | /* The following sillines is to make NFS happy */ |
2057 | #define EROUND ((sizeof(struct ether_header) + 3) & ~3) | |
2058 | #define EOFF (EROUND - sizeof(struct ether_header)) | |
2059 | ||
2060 | /* | |
2061 | * The following assumes there is room for | |
2062 | * the ether header in the header mbuf | |
2063 | */ | |
2064 | head->m_data += EOFF; | |
016ac65c DG |
2065 | eh = mtod(head, struct ether_header *); |
2066 | ||
2067 | if (sc->mem_shared) | |
2068 | bcopy(buf, mtod(head, caddr_t), sizeof(struct ether_header)); | |
2069 | else | |
2070 | ed_pio_readmem(sc, buf, mtod(head, caddr_t), | |
362c9b14 | 2071 | sizeof(struct ether_header)); |
21ac5de2 DG |
2072 | buf += sizeof(struct ether_header); |
2073 | head->m_len += sizeof(struct ether_header); | |
2074 | len -= sizeof(struct ether_header); | |
2075 | ||
2076 | etype = ntohs((u_short)eh->ether_type); | |
2077 | ||
2078 | /* | |
2079 | * Deal with trailer protocol: | |
2080 | * If trailer protocol, calculate the datasize as 'off', | |
2081 | * which is also the offset to the trailer header. | |
2082 | * Set resid to the amount of packet data following the | |
2083 | * trailer header. | |
2084 | * Finally, copy residual data into mbuf chain. | |
2085 | */ | |
2086 | if (etype >= ETHERTYPE_TRAIL && | |
2087 | etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { | |
2088 | ||
2089 | off = (etype - ETHERTYPE_TRAIL) << 9; | |
2090 | if ((off + sizeof(struct trailer_header)) > len) | |
2091 | goto bad; /* insanity */ | |
2092 | ||
016ac65c DG |
2093 | /* |
2094 | * If we have shared memory, we can get info directly from the | |
2095 | * stored packet, otherwise we must get a local copy | |
2096 | * of the trailer header using PIO. | |
2097 | */ | |
2098 | if (sc->mem_shared) { | |
2099 | eh->ether_type = *ringoffset(sc, buf, off, u_short *); | |
2100 | resid = ntohs(*ringoffset(sc, buf, off+2, u_short *)); | |
2101 | } else { | |
2102 | struct trailer_header trailer_header; | |
2103 | ed_pio_readmem(sc, | |
362c9b14 DG |
2104 | ringoffset(sc, buf, off, caddr_t), |
2105 | (char *) &trailer_header, | |
2106 | sizeof(trailer_header)); | |
016ac65c DG |
2107 | eh->ether_type = trailer_header.ether_type; |
2108 | resid = trailer_header.ether_residual; | |
2109 | } | |
21ac5de2 DG |
2110 | |
2111 | if ((off + resid) > len) goto bad; /* insanity */ | |
2112 | ||
2113 | resid -= sizeof(struct trailer_header); | |
2114 | if (resid < 0) goto bad; /* insanity */ | |
2115 | ||
362c9b14 DG |
2116 | m = ed_ring_to_mbuf(sc, ringoffset(sc, buf, off+4, char *), |
2117 | head, resid); | |
21ac5de2 DG |
2118 | if (m == 0) goto bad; |
2119 | ||
2120 | len = off; | |
2121 | head->m_pkthdr.len -= 4; /* subtract trailer header */ | |
2122 | } | |
2123 | ||
2124 | /* | |
2125 | * Pull packet off interface. Or if this was a trailer packet, | |
2126 | * the data portion is appended. | |
2127 | */ | |
2128 | m = ed_ring_to_mbuf(sc, buf, m, len); | |
2129 | if (m == 0) goto bad; | |
2130 | ||
2131 | #if NBPFILTER > 0 | |
2132 | /* | |
2133 | * Check if there's a BPF listener on this interface. | |
2134 | * If so, hand off the raw packet to bpf. | |
2135 | */ | |
2136 | if (sc->bpf) { | |
2137 | bpf_mtap(sc->bpf, head); | |
2138 | ||
2139 | /* | |
2140 | * Note that the interface cannot be in promiscuous mode if | |
2141 | * there are no BPF listeners. And if we are in promiscuous | |
2142 | * mode, we have to check if this packet is really ours. | |
2143 | * | |
2144 | * XXX This test does not support multicasts. | |
2145 | */ | |
2146 | if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) && | |
362c9b14 DG |
2147 | bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, |
2148 | sizeof(eh->ether_dhost)) != 0 && | |
2149 | bcmp(eh->ether_dhost, etherbroadcastaddr, | |
2150 | sizeof(eh->ether_dhost)) != 0) { | |
21ac5de2 | 2151 | |
362c9b14 DG |
2152 | m_freem(head); |
2153 | return; | |
21ac5de2 DG |
2154 | } |
2155 | } | |
2156 | #endif | |
2157 | ||
2158 | /* | |
2159 | * Fix up data start offset in mbuf to point past ether header | |
2160 | */ | |
2161 | m_adj(head, sizeof(struct ether_header)); | |
2162 | ||
2163 | /* | |
2164 | * silly ether_input routine needs 'type' in host byte order | |
2165 | */ | |
2166 | eh->ether_type = ntohs(eh->ether_type); | |
2167 | ||
2168 | ether_input(&sc->arpcom.ac_if, eh, head); | |
2169 | return; | |
2170 | ||
2171 | bad: if (head) | |
2172 | m_freem(head); | |
2173 | return; | |
2174 | } | |
2175 | ||
2176 | /* | |
2177 | * Supporting routines | |
2178 | */ | |
2179 | ||
016ac65c DG |
2180 | /* |
2181 | * Given a NIC memory source address and a host memory destination | |
2182 | * address, copy 'amount' from NIC to host using Programmed I/O. | |
2183 | * The 'amount' is rounded up to a word - okay as long as mbufs | |
2184 | * are word sized. | |
2185 | * This routine is currently Novell-specific. | |
2186 | */ | |
2187 | void | |
2188 | ed_pio_readmem(sc,src,dst,amount) | |
2189 | struct ed_softc *sc; | |
2190 | unsigned short src; | |
2191 | unsigned char *dst; | |
2192 | unsigned short amount; | |
2193 | { | |
2194 | unsigned short tmp_amount; | |
2195 | ||
2196 | /* select page 0 registers */ | |
2197 | outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA); | |
2198 | ||
2199 | /* round up to a word */ | |
2200 | tmp_amount = amount; | |
2201 | if (amount & 1) ++amount; | |
2202 | ||
2203 | /* set up DMA byte count */ | |
2204 | outb(sc->nic_addr + ED_P0_RBCR0, amount); | |
2205 | outb(sc->nic_addr + ED_P0_RBCR1, amount>>8); | |
2206 | ||
2207 | /* set up source address in NIC mem */ | |
2208 | outb(sc->nic_addr + ED_P0_RSAR0, src); | |
2209 | outb(sc->nic_addr + ED_P0_RSAR1, src>>8); | |
2210 | ||
2211 | outb(sc->nic_addr + ED_P0_CR, ED_CR_RD0 | ED_CR_STA); | |
2212 | ||
2213 | if (sc->isa16bit) { | |
2214 | insw(sc->asic_addr + ED_NOVELL_DATA, dst, amount/2); | |
2215 | } else | |
2216 | insb(sc->asic_addr + ED_NOVELL_DATA, dst, amount); | |
2217 | ||
2218 | } | |
2219 | ||
2220 | /* | |
2221 | * Stripped down routine for writing a linear buffer to NIC memory. | |
2222 | * Only used in the probe routine to test the memory. 'len' must | |
2223 | * be even. | |
2224 | */ | |
2225 | void | |
2226 | ed_pio_writemem(sc,src,dst,len) | |
2227 | struct ed_softc *sc; | |
2228 | char *src; | |
2229 | unsigned short dst; | |
2230 | unsigned short len; | |
2231 | { | |
a23f6e67 | 2232 | int maxwait=100; /* about 120us */ |
016ac65c DG |
2233 | |
2234 | /* select page 0 registers */ | |
2235 | outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA); | |
2236 | ||
2237 | /* reset remote DMA complete flag */ | |
2238 | outb(sc->nic_addr + ED_P0_ISR, ED_ISR_RDC); | |
2239 | ||
2240 | /* set up DMA byte count */ | |
2241 | outb(sc->nic_addr + ED_P0_RBCR0, len); | |
2242 | outb(sc->nic_addr + ED_P0_RBCR1, len>>8); | |
2243 | ||
2244 | /* set up destination address in NIC mem */ | |
2245 | outb(sc->nic_addr + ED_P0_RSAR0, dst); | |
2246 | outb(sc->nic_addr + ED_P0_RSAR1, dst>>8); | |
2247 | ||
2248 | /* set remote DMA write */ | |
2249 | outb(sc->nic_addr + ED_P0_CR, ED_CR_RD1 | ED_CR_STA); | |
2250 | ||
2251 | if (sc->isa16bit) | |
2252 | outsw(sc->asic_addr + ED_NOVELL_DATA, src, len/2); | |
2253 | else | |
2254 | outsb(sc->asic_addr + ED_NOVELL_DATA, src, len); | |
2255 | /* | |
2256 | * Wait for remote DMA complete. This is necessary because on the | |
2257 | * transmit side, data is handled internally by the NIC in bursts | |
2258 | * and we can't start another remote DMA until this one completes. | |
2259 | * Not waiting causes really bad things to happen - like the NIC | |
2260 | * irrecoverably jamming the ISA bus. | |
2261 | */ | |
2262 | while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RDC) != ED_ISR_RDC) && --maxwait); | |
2263 | } | |
2264 | ||
2265 | /* | |
2266 | * Write an mbuf chain to the destination NIC memory address using | |
2267 | * programmed I/O. | |
2268 | */ | |
2269 | u_short | |
2270 | ed_pio_write_mbufs(sc,m,dst) | |
2271 | struct ed_softc *sc; | |
2272 | struct mbuf *m; | |
2273 | unsigned short dst; | |
2274 | { | |
2275 | unsigned short len, mb_offset; | |
2276 | struct mbuf *mp; | |
2277 | unsigned char residual[2]; | |
a23f6e67 | 2278 | int maxwait=100; /* about 120us */ |
016ac65c DG |
2279 | |
2280 | /* First, count up the total number of bytes to copy */ | |
2281 | for (len = 0, mp = m; mp; mp = mp->m_next) | |
2282 | len += mp->m_len; | |
2283 | ||
2284 | /* select page 0 registers */ | |
2285 | outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA); | |
2286 | ||
2287 | /* reset remote DMA complete flag */ | |
2288 | outb(sc->nic_addr + ED_P0_ISR, ED_ISR_RDC); | |
2289 | ||
2290 | /* set up DMA byte count */ | |
2291 | outb(sc->nic_addr + ED_P0_RBCR0, len); | |
2292 | outb(sc->nic_addr + ED_P0_RBCR1, len>>8); | |
2293 | ||
2294 | /* set up destination address in NIC mem */ | |
2295 | outb(sc->nic_addr + ED_P0_RSAR0, dst); | |
2296 | outb(sc->nic_addr + ED_P0_RSAR1, dst>>8); | |
2297 | ||
2298 | /* set remote DMA write */ | |
2299 | outb(sc->nic_addr + ED_P0_CR, ED_CR_RD1 | ED_CR_STA); | |
2300 | ||
2301 | mb_offset = 0; | |
2302 | /* | |
2303 | * Transfer the mbuf chain to the NIC memory. | |
2304 | * The following code isn't too pretty. The problem is that we can only | |
2305 | * transfer words to the board, and if an mbuf has an odd number | |
2306 | * of bytes in it, this is a problem. It's not a simple matter of | |
2307 | * just removing a byte from the next mbuf (adjusting data++ and | |
2308 | * len--) because this will hose-over the mbuf chain which might | |
2309 | * be needed later for BPF. Instead, we maintain an offset | |
2310 | * (mb_offset) which let's us skip over the first byte in the | |
2311 | * following mbuf. | |
2312 | */ | |
2313 | while (m) { | |
2314 | if (m->m_len - mb_offset) { | |
2315 | if (sc->isa16bit) { | |
2316 | if ((m->m_len - mb_offset) > 1) | |
2317 | outsw(sc->asic_addr + ED_NOVELL_DATA, | |
362c9b14 DG |
2318 | mtod(m, caddr_t) + mb_offset, |
2319 | (m->m_len - mb_offset) / 2); | |
016ac65c DG |
2320 | |
2321 | /* | |
2322 | * if odd number of bytes, get the odd byte from | |
2323 | * the next mbuf with data | |
2324 | */ | |
2325 | if ((m->m_len - mb_offset) & 1) { | |
2326 | /* first the last byte in current mbuf */ | |
362c9b14 DG |
2327 | residual[0] = *(mtod(m, caddr_t) + |
2328 | m->m_len - 1); | |
016ac65c DG |
2329 | |
2330 | /* advance past any empty mbufs */ | |
2331 | while (m->m_next && (m->m_next->m_len == 0)) | |
2332 | m = m->m_next; | |
2333 | ||
2334 | if (m->m_next) { | |
2335 | /* remove first byte in next mbuf */ | |
2336 | residual[1] = *(mtod(m->m_next, caddr_t)); | |
2337 | mb_offset = 1; | |
2338 | } | |
2339 | ||
2340 | outw(sc->asic_addr + ED_NOVELL_DATA, | |
362c9b14 | 2341 | *((unsigned short *) residual)); |
016ac65c DG |
2342 | } else |
2343 | mb_offset = 0; | |
2344 | } else | |
2345 | outsb(sc->asic_addr + ED_NOVELL_DATA, m->m_data, m->m_len); | |
2346 | ||
2347 | } | |
2348 | m = m->m_next; | |
2349 | } | |
2350 | ||
2351 | /* | |
2352 | * Wait for remote DMA complete. This is necessary because on the | |
2353 | * transmit side, data is handled internally by the NIC in bursts | |
2354 | * and we can't start another remote DMA until this one completes. | |
2355 | * Not waiting causes really bad things to happen - like the NIC | |
2356 | * irrecoverably jamming the ISA bus. | |
2357 | */ | |
2358 | while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RDC) != ED_ISR_RDC) && --maxwait); | |
2359 | ||
2360 | if (!maxwait) { | |
2361 | log(LOG_WARNING, "ed%d: remote transmit DMA failed to complete\n", | |
362c9b14 | 2362 | sc->arpcom.ac_if.if_unit); |
4c45483e | 2363 | ed_reset(sc->arpcom.ac_if.if_unit, 0); |
016ac65c DG |
2364 | } |
2365 | ||
2366 | return(len); | |
2367 | } | |
2368 | ||
21ac5de2 DG |
2369 | /* |
2370 | * Given a source and destination address, copy 'amount' of a packet from | |
2371 | * the ring buffer into a linear destination buffer. Takes into account | |
2372 | * ring-wrap. | |
2373 | */ | |
2374 | static inline char * | |
2375 | ed_ring_copy(sc,src,dst,amount) | |
2376 | struct ed_softc *sc; | |
2377 | char *src; | |
2378 | char *dst; | |
2379 | u_short amount; | |
2380 | { | |
2381 | u_short tmp_amount; | |
2382 | ||
2383 | /* does copy wrap to lower addr in ring buffer? */ | |
016ac65c DG |
2384 | if (src + amount > sc->mem_end) { |
2385 | tmp_amount = sc->mem_end - src; | |
2386 | ||
2387 | /* copy amount up to end of NIC memory */ | |
2388 | if (sc->mem_shared) | |
2389 | bcopy(src,dst,tmp_amount); | |
2390 | else | |
2391 | ed_pio_readmem(sc,src,dst,tmp_amount); | |
2392 | ||
21ac5de2 | 2393 | amount -= tmp_amount; |
016ac65c | 2394 | src = sc->mem_ring; |
21ac5de2 DG |
2395 | dst += tmp_amount; |
2396 | } | |
2397 | ||
016ac65c DG |
2398 | if (sc->mem_shared) |
2399 | bcopy(src, dst, amount); | |
2400 | else | |
2401 | ed_pio_readmem(sc, src, dst, amount); | |
21ac5de2 DG |
2402 | |
2403 | return(src + amount); | |
2404 | } | |
2405 | ||
2406 | /* | |
2407 | * Copy data from receive buffer to end of mbuf chain | |
2408 | * allocate additional mbufs as needed. return pointer | |
2409 | * to last mbuf in chain. | |
2410 | * sc = ed info (softc) | |
2411 | * src = pointer in ed ring buffer | |
2412 | * dst = pointer to last mbuf in mbuf chain to copy to | |
2413 | * amount = amount of data to copy | |
2414 | */ | |
2415 | struct mbuf * | |
2416 | ed_ring_to_mbuf(sc,src,dst,total_len) | |
2417 | struct ed_softc *sc; | |
2418 | char *src; | |
2419 | struct mbuf *dst; | |
2420 | u_short total_len; | |
2421 | { | |
2422 | register struct mbuf *m = dst; | |
2423 | ||
2424 | while (total_len) { | |
2425 | register u_short amount = min(total_len, M_TRAILINGSPACE(m)); | |
2426 | ||
2427 | if (amount == 0) { /* no more data in this mbuf, alloc another */ | |
2428 | /* | |
5969b7e9 DG |
2429 | * If there is enough data for an mbuf cluster, attempt |
2430 | * to allocate one of those, otherwise, a regular | |
2431 | * mbuf will do. | |
2432 | * Note that a regular mbuf is always required, even if | |
2433 | * we get a cluster - getting a cluster does not | |
2434 | * allocate any mbufs, and one is needed to assign | |
2435 | * the cluster to. The mbuf that has a cluster | |
2436 | * extension can not be used to contain data - only | |
2437 | * the cluster can contain data. | |
21ac5de2 DG |
2438 | */ |
2439 | dst = m; | |
2440 | MGET(m, M_DONTWAIT, MT_DATA); | |
2441 | if (m == 0) | |
2442 | return (0); | |
2443 | ||
2444 | if (total_len >= MINCLSIZE) | |
2445 | MCLGET(m, M_DONTWAIT); | |
2446 | ||
2447 | m->m_len = 0; | |
2448 | dst->m_next = m; | |
2449 | amount = min(total_len, M_TRAILINGSPACE(m)); | |
2450 | } | |
2451 | ||
2452 | src = ed_ring_copy(sc, src, mtod(m, caddr_t) + m->m_len, amount); | |
2453 | ||
2454 | m->m_len += amount; | |
2455 | total_len -= amount; | |
2456 | ||
2457 | } | |
2458 | return (m); | |
2459 | } | |
2460 | #endif |