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