Updated PCI IDs to latest snapshot.
[tangerine.git] / arch / common / boot / grub / netboot / ns8390.c
blob07ec459f10fedc7f4118a83de5e0bde9d9db9f9b
1 /**************************************************************************
2 ETHERBOOT - BOOTP/TFTP Bootstrap Program
4 Author: Martin Renters
5 Date: May/94
7 This code is based heavily on David Greenman's if_ed.c driver
9 Copyright (C) 1993-1994, David Greenman, Martin Renters.
10 This software may be used, modified, copied, distributed, and sold, in
11 both source and binary form provided that the above copyright and these
12 terms are retained. Under no circumstances are the authors responsible for
13 the proper functioning of this software, nor do the authors assume any
14 responsibility for damages incurred with its use.
16 3c503 support added by Bill Paul (wpaul@ctr.columbia.edu) on 11/15/94
17 SMC8416 support added by Bill Paul (wpaul@ctr.columbia.edu) on 12/25/94
18 3c503 PIO support added by Jim Hague (jim.hague@acm.org) on 2/17/98
19 RX overrun by Klaus Espenlaub (espenlaub@informatik.uni-ulm.de) on 3/10/99
20 parts taken from the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
22 **************************************************************************/
24 #include "etherboot.h"
25 #include "nic.h"
26 #include "ns8390.h"
27 #ifdef INCLUDE_NS8390
28 #include "pci.h"
29 #endif
30 #include "cards.h"
32 static unsigned char eth_vendor, eth_flags, eth_laar;
33 static unsigned short eth_nic_base, eth_asic_base;
34 static unsigned char eth_memsize, eth_rx_start, eth_tx_start;
35 static Address eth_bmem, eth_rmem;
36 static unsigned char eth_drain_receiver;
38 #ifdef INCLUDE_WD
39 static struct wd_board {
40 const char *name;
41 char id;
42 char flags;
43 char memsize;
44 } wd_boards[] = {
45 {"WD8003S", TYPE_WD8003S, 0, MEM_8192},
46 {"WD8003E", TYPE_WD8003E, 0, MEM_8192},
47 {"WD8013EBT", TYPE_WD8013EBT, FLAG_16BIT, MEM_16384},
48 {"WD8003W", TYPE_WD8003W, 0, MEM_8192},
49 {"WD8003EB", TYPE_WD8003EB, 0, MEM_8192},
50 {"WD8013W", TYPE_WD8013W, FLAG_16BIT, MEM_16384},
51 {"WD8003EP/WD8013EP",
52 TYPE_WD8013EP, 0, MEM_8192},
53 {"WD8013WC", TYPE_WD8013WC, FLAG_16BIT, MEM_16384},
54 {"WD8013EPC", TYPE_WD8013EPC, FLAG_16BIT, MEM_16384},
55 {"SMC8216T", TYPE_SMC8216T, FLAG_16BIT | FLAG_790, MEM_16384},
56 {"SMC8216C", TYPE_SMC8216C, FLAG_16BIT | FLAG_790, MEM_16384},
57 {"SMC8416T", TYPE_SMC8416T, FLAG_16BIT | FLAG_790, MEM_8192},
58 {"SMC8416C/BT", TYPE_SMC8416C, FLAG_16BIT | FLAG_790, MEM_8192},
59 {"SMC8013EBP", TYPE_SMC8013EBP,FLAG_16BIT, MEM_16384},
60 {NULL, 0, 0, 0}
62 #endif
64 #ifdef INCLUDE_3C503
65 static unsigned char t503_output; /* AUI or internal xcvr (Thinnet) */
66 #endif
68 #if defined(INCLUDE_WD)
69 #define eth_probe wd_probe
70 #if defined(INCLUDE_3C503) || defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
71 Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
72 #endif
73 #endif
75 #if defined(INCLUDE_3C503)
76 #define eth_probe t503_probe
77 #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || defined(INCLUDE_WD)
78 Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
79 #endif
80 #endif
82 #if defined(INCLUDE_NE)
83 #define eth_probe ne_probe
84 #if defined(INCLUDE_NS8390) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
85 Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
86 #endif
87 #endif
89 #if defined(INCLUDE_NS8390)
90 #define eth_probe nepci_probe
91 #if defined(INCLUDE_NE) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
92 Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
93 #endif
94 #endif
96 #if defined(INCLUDE_3C503)
97 #define ASIC_PIO _3COM_RFMSB
98 #else
99 #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
100 #define ASIC_PIO NE_DATA
101 #endif
102 #endif
104 #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM))
105 /**************************************************************************
106 ETH_PIO_READ - Read a frame via Programmed I/O
107 **************************************************************************/
108 static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt)
110 if (eth_flags & FLAG_16BIT) { ++cnt; cnt &= ~1; }
111 outb(D8390_COMMAND_RD2 |
112 D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
113 outb(cnt, eth_nic_base + D8390_P0_RBCR0);
114 outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
115 outb(src, eth_nic_base + D8390_P0_RSAR0);
116 outb(src>>8, eth_nic_base + D8390_P0_RSAR1);
117 outb(D8390_COMMAND_RD0 |
118 D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
120 #ifdef INCLUDE_3C503
121 outb(src & 0xff, eth_asic_base + _3COM_DALSB);
122 outb(src >> 8, eth_asic_base + _3COM_DAMSB);
123 outb(t503_output | _3COM_CR_START, eth_asic_base + _3COM_CR);
124 #endif
126 if (eth_flags & FLAG_16BIT)
127 cnt >>= 1;
129 while(cnt--) {
130 #ifdef INCLUDE_3C503
131 while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0)
133 #endif
135 if (eth_flags & FLAG_16BIT) {
136 *((unsigned short *)dst) = inw(eth_asic_base + ASIC_PIO);
137 dst += 2;
139 else
140 *(dst++) = inb(eth_asic_base + ASIC_PIO);
143 #ifdef INCLUDE_3C503
144 outb(t503_output, eth_asic_base + _3COM_CR);
145 #endif
148 /**************************************************************************
149 ETH_PIO_WRITE - Write a frame via Programmed I/O
150 **************************************************************************/
151 static void eth_pio_write(const unsigned char *src, unsigned int dst, unsigned int cnt)
153 #ifdef COMPEX_RL2000_FIX
154 unsigned int x;
155 #endif /* COMPEX_RL2000_FIX */
156 if (eth_flags & FLAG_16BIT) { ++cnt; cnt &= ~1; }
157 outb(D8390_COMMAND_RD2 |
158 D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
159 outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
160 outb(cnt, eth_nic_base + D8390_P0_RBCR0);
161 outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
162 outb(dst, eth_nic_base + D8390_P0_RSAR0);
163 outb(dst>>8, eth_nic_base + D8390_P0_RSAR1);
164 outb(D8390_COMMAND_RD1 |
165 D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
167 #ifdef INCLUDE_3C503
168 outb(dst & 0xff, eth_asic_base + _3COM_DALSB);
169 outb(dst >> 8, eth_asic_base + _3COM_DAMSB);
171 outb(t503_output | _3COM_CR_DDIR | _3COM_CR_START, eth_asic_base + _3COM_CR);
172 #endif
174 if (eth_flags & FLAG_16BIT)
175 cnt >>= 1;
177 while(cnt--)
179 #ifdef INCLUDE_3C503
180 while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0)
182 #endif
184 if (eth_flags & FLAG_16BIT) {
185 outw(*((unsigned short *)src), eth_asic_base + ASIC_PIO);
186 src += 2;
188 else
189 outb(*(src++), eth_asic_base + ASIC_PIO);
192 #ifdef INCLUDE_3C503
193 outb(t503_output, eth_asic_base + _3COM_CR);
194 #else
195 #ifdef COMPEX_RL2000_FIX
196 for (x = 0;
197 x < COMPEX_RL2000_TRIES &&
198 (inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
199 != D8390_ISR_RDC;
200 ++x);
201 if (x >= COMPEX_RL2000_TRIES)
202 printf("Warning: Compex RL2000 aborted wait!\n");
203 #endif /* COMPEX_RL2000_FIX */
204 while((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
205 != D8390_ISR_RDC);
206 #endif
208 #else
209 /**************************************************************************
210 ETH_PIO_READ - Dummy routine when NE2000 not compiled in
211 **************************************************************************/
212 static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt) {}
213 #endif
215 /**************************************************************************
216 NS8390_RESET - Reset adapter
217 **************************************************************************/
218 static void ns8390_reset(struct nic *nic)
220 int i;
222 eth_drain_receiver = 0;
223 #ifdef INCLUDE_WD
224 if (eth_flags & FLAG_790)
225 outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
226 else
227 #endif
228 outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
229 D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
230 if (eth_flags & FLAG_16BIT)
231 outb(0x49, eth_nic_base+D8390_P0_DCR);
232 else
233 outb(0x48, eth_nic_base+D8390_P0_DCR);
234 outb(0, eth_nic_base+D8390_P0_RBCR0);
235 outb(0, eth_nic_base+D8390_P0_RBCR1);
236 outb(0x20, eth_nic_base+D8390_P0_RCR); /* monitor mode */
237 outb(2, eth_nic_base+D8390_P0_TCR);
238 outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
239 outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART);
240 #ifdef INCLUDE_WD
241 if (eth_flags & FLAG_790) outb(0, eth_nic_base + 0x09);
242 #endif
243 outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP);
244 outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND);
245 outb(0xFF, eth_nic_base+D8390_P0_ISR);
246 outb(0, eth_nic_base+D8390_P0_IMR);
247 #ifdef INCLUDE_WD
248 if (eth_flags & FLAG_790)
249 outb(D8390_COMMAND_PS1 |
250 D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
251 else
252 #endif
253 outb(D8390_COMMAND_PS1 |
254 D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
255 for (i=0; i<ETH_ALEN; i++)
256 outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i);
257 for (i=0; i<ETH_ALEN; i++)
258 outb(0xFF, eth_nic_base+D8390_P1_MAR0+i);
259 outb(eth_rx_start, eth_nic_base+D8390_P1_CURR);
260 #ifdef INCLUDE_WD
261 if (eth_flags & FLAG_790)
262 outb(D8390_COMMAND_PS0 |
263 D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
264 else
265 #endif
266 outb(D8390_COMMAND_PS0 |
267 D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
268 outb(0xFF, eth_nic_base+D8390_P0_ISR);
269 outb(0, eth_nic_base+D8390_P0_TCR);
270 outb(4, eth_nic_base+D8390_P0_RCR); /* allow broadcast frames */
272 #ifdef INCLUDE_3C503
274 * No way to tell whether or not we're supposed to use
275 * the 3Com's transceiver unless the user tells us.
276 * 'flags' should have some compile time default value
277 * which can be changed from the command menu.
279 t503_output = (nic->flags) ? 0 : _3COM_CR_XSEL;
280 outb(t503_output, eth_asic_base + _3COM_CR);
281 #endif
284 static int ns8390_poll(struct nic *nic);
286 #ifndef INCLUDE_3C503
287 /**************************************************************************
288 ETH_RX_OVERRUN - Bring adapter back to work after an RX overrun
289 **************************************************************************/
290 static void eth_rx_overrun(struct nic *nic)
292 int start_time;
294 #ifdef INCLUDE_WD
295 if (eth_flags & FLAG_790)
296 outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
297 else
298 #endif
299 outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
300 D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
302 /* wait for at least 1.6ms - we wait one timer tick */
303 start_time = currticks();
304 while (currticks() - start_time <= 1)
305 /* Nothing */;
307 outb(0, eth_nic_base+D8390_P0_RBCR0); /* reset byte counter */
308 outb(0, eth_nic_base+D8390_P0_RBCR1);
311 * Linux driver checks for interrupted TX here. This is not necessary,
312 * because the transmit routine waits until the frame is sent.
315 /* enter loopback mode and restart NIC */
316 outb(2, eth_nic_base+D8390_P0_TCR);
317 #ifdef INCLUDE_WD
318 if (eth_flags & FLAG_790)
319 outb(D8390_COMMAND_PS0 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
320 else
321 #endif
322 outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
323 D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
325 /* clear the RX ring, acknowledge overrun interrupt */
326 eth_drain_receiver = 1;
327 while (ns8390_poll(nic))
328 /* Nothing */;
329 eth_drain_receiver = 0;
330 outb(D8390_ISR_OVW, eth_nic_base+D8390_P0_ISR);
332 /* leave loopback mode - no packets to be resent (see Linux driver) */
333 outb(0, eth_nic_base+D8390_P0_TCR);
335 #endif /* INCLUDE_3C503 */
337 /**************************************************************************
338 NS8390_TRANSMIT - Transmit a frame
339 **************************************************************************/
340 static void ns8390_transmit(
341 struct nic *nic,
342 const char *d, /* Destination */
343 unsigned int t, /* Type */
344 unsigned int s, /* size */
345 const char *p) /* Packet */
347 #ifdef INCLUDE_3C503
348 if (!(eth_flags & FLAG_PIO)) {
349 memcpy((char *)eth_bmem, d, ETH_ALEN); /* dst */
350 memcpy((char *)eth_bmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
351 *((char *)eth_bmem+12) = t>>8; /* type */
352 *((char *)eth_bmem+13) = t;
353 memcpy((char *)eth_bmem+ETH_HLEN, p, s);
354 s += ETH_HLEN;
355 while (s < ETH_ZLEN) *((char *)eth_bmem+(s++)) = 0;
357 #endif
359 #ifdef INCLUDE_WD
360 /* Memory interface */
361 if (eth_flags & FLAG_16BIT) {
362 outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
363 inb(0x84);
365 if (eth_flags & FLAG_790) {
366 outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
367 inb(0x84);
369 inb(0x84);
370 memcpy((char *)eth_bmem, d, ETH_ALEN); /* dst */
371 memcpy((char *)eth_bmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
372 *((char *)eth_bmem+12) = t>>8; /* type */
373 *((char *)eth_bmem+13) = t;
374 memcpy((char *)eth_bmem+ETH_HLEN, p, s);
375 s += ETH_HLEN;
376 while (s < ETH_ZLEN) *((char *)eth_bmem+(s++)) = 0;
377 if (eth_flags & FLAG_790) {
378 outb(0, eth_asic_base + WD_MSR);
379 inb(0x84);
381 if (eth_flags & FLAG_16BIT) {
382 outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
383 inb(0x84);
385 #endif
387 #if defined(INCLUDE_3C503)
388 if (eth_flags & FLAG_PIO) {
389 #endif
390 #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM))
391 /* Programmed I/O */
392 unsigned short type;
393 type = (t >> 8) | (t << 8);
394 eth_pio_write(d, eth_tx_start<<8, ETH_ALEN);
395 eth_pio_write(nic->node_addr, (eth_tx_start<<8)+ETH_ALEN, ETH_ALEN);
396 /* bcc generates worse code without (const+const) below */
397 eth_pio_write((unsigned char *)&type, (eth_tx_start<<8)+(ETH_ALEN+ETH_ALEN), 2);
398 eth_pio_write(p, (eth_tx_start<<8)+ETH_HLEN, s);
399 s += ETH_HLEN;
400 if (s < ETH_ZLEN) s = ETH_ZLEN;
401 #endif
402 #if defined(INCLUDE_3C503)
404 #endif
406 #ifdef INCLUDE_WD
407 if (eth_flags & FLAG_790)
408 outb(D8390_COMMAND_PS0 |
409 D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
410 else
411 #endif
412 outb(D8390_COMMAND_PS0 |
413 D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
414 outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
415 outb(s, eth_nic_base+D8390_P0_TBCR0);
416 outb(s>>8, eth_nic_base+D8390_P0_TBCR1);
417 #ifdef INCLUDE_WD
418 if (eth_flags & FLAG_790)
419 outb(D8390_COMMAND_PS0 |
420 D8390_COMMAND_TXP | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
421 else
422 #endif
423 outb(D8390_COMMAND_PS0 |
424 D8390_COMMAND_TXP | D8390_COMMAND_RD2 |
425 D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
428 /**************************************************************************
429 NS8390_POLL - Wait for a frame
430 **************************************************************************/
431 static int ns8390_poll(struct nic *nic)
433 int ret = 0;
434 unsigned char rstat, curr, next;
435 unsigned short len, frag;
436 unsigned short pktoff;
437 unsigned char *p;
438 struct ringbuffer pkthdr;
440 #ifndef INCLUDE_3C503
441 /* avoid infinite recursion: see eth_rx_overrun() */
442 if (!eth_drain_receiver && (inb(eth_nic_base+D8390_P0_ISR) & D8390_ISR_OVW)) {
443 eth_rx_overrun(nic);
444 return(0);
446 #endif /* INCLUDE_3C503 */
447 rstat = inb(eth_nic_base+D8390_P0_RSR);
448 if (!(rstat & D8390_RSTAT_PRX)) return(0);
449 next = inb(eth_nic_base+D8390_P0_BOUND)+1;
450 if (next >= eth_memsize) next = eth_rx_start;
451 outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND);
452 curr = inb(eth_nic_base+D8390_P1_CURR);
453 outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND);
454 if (curr >= eth_memsize) curr=eth_rx_start;
455 if (curr == next) return(0);
456 #ifdef INCLUDE_WD
457 if (eth_flags & FLAG_16BIT) {
458 outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
459 inb(0x84);
461 if (eth_flags & FLAG_790) {
462 outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
463 inb(0x84);
465 inb(0x84);
466 #endif
467 pktoff = next << 8;
468 if (eth_flags & FLAG_PIO)
469 eth_pio_read(pktoff, (char *)&pkthdr, 4);
470 else
471 memcpy(&pkthdr, (char *)eth_rmem + pktoff, 4);
472 pktoff += sizeof(pkthdr);
473 /* incoming length includes FCS so must sub 4 */
474 len = pkthdr.len - 4;
475 if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN
476 || len > ETH_FRAME_LEN) {
477 printf("Bogus packet, ignoring\n");
478 return (0);
480 else {
481 p = nic->packet;
482 nic->packetlen = len; /* available to caller */
483 frag = (eth_memsize << 8) - pktoff;
484 if (len > frag) { /* We have a wrap-around */
485 /* read first part */
486 if (eth_flags & FLAG_PIO)
487 eth_pio_read(pktoff, p, frag);
488 else
489 memcpy(p, (char *)eth_rmem + pktoff, frag);
490 pktoff = eth_rx_start << 8;
491 p += frag;
492 len -= frag;
494 /* read second part */
495 if (eth_flags & FLAG_PIO)
496 eth_pio_read(pktoff, p, len);
497 else
498 memcpy(p, (char *)eth_rmem + pktoff, len);
499 ret = 1;
501 #ifdef INCLUDE_WD
502 if (eth_flags & FLAG_790) {
503 outb(0, eth_asic_base + WD_MSR);
504 inb(0x84);
506 if (eth_flags & FLAG_16BIT) {
507 outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
508 inb(0x84);
510 inb(0x84);
511 #endif
512 next = pkthdr.next; /* frame number of next packet */
513 if (next == eth_rx_start)
514 next = eth_memsize;
515 outb(next-1, eth_nic_base+D8390_P0_BOUND);
516 return(ret);
519 /**************************************************************************
520 NS8390_DISABLE - Turn off adapter
521 **************************************************************************/
522 static void ns8390_disable(struct nic *nic)
526 /**************************************************************************
527 ETH_PROBE - Look for an adapter
528 **************************************************************************/
529 #ifdef INCLUDE_NS8390
530 struct nic *eth_probe(struct nic *nic, unsigned short *probe_addrs,
531 struct pci_device *pci)
532 #else
533 struct nic *eth_probe(struct nic *nic, unsigned short *probe_addrs)
534 #endif
536 int i;
537 struct wd_board *brd;
538 unsigned short chksum;
539 unsigned char c;
540 eth_vendor = VENDOR_NONE;
541 eth_drain_receiver = 0;
543 #ifdef INCLUDE_WD
544 /******************************************************************
545 Search for WD/SMC cards
546 ******************************************************************/
547 for (eth_asic_base = WD_LOW_BASE; eth_asic_base <= WD_HIGH_BASE;
548 eth_asic_base += 0x20) {
549 chksum = 0;
550 for (i=8; i<16; i++)
551 chksum += inb(eth_asic_base+i);
552 /* Extra checks to avoid soundcard */
553 if ((chksum & 0xFF) == 0xFF &&
554 inb(eth_asic_base+8) != 0xFF &&
555 inb(eth_asic_base+9) != 0xFF)
556 break;
558 if (eth_asic_base > WD_HIGH_BASE)
559 return (0);
560 /* We've found a board */
561 eth_vendor = VENDOR_WD;
562 eth_nic_base = eth_asic_base + WD_NIC_ADDR;
563 c = inb(eth_asic_base+WD_BID); /* Get board id */
564 for (brd = wd_boards; brd->name; brd++)
565 if (brd->id == c) break;
566 if (!brd->name) {
567 printf("Unknown WD/SMC NIC type %hhX\n", c);
568 return (0); /* Unknown type */
570 eth_flags = brd->flags;
571 eth_memsize = brd->memsize;
572 eth_tx_start = 0;
573 eth_rx_start = D8390_TXBUF_SIZE;
574 if ((c == TYPE_WD8013EP) &&
575 (inb(eth_asic_base + WD_ICR) & WD_ICR_16BIT)) {
576 eth_flags = FLAG_16BIT;
577 eth_memsize = MEM_16384;
579 if ((c & WD_SOFTCONFIG) && (!(eth_flags & FLAG_790))) {
580 eth_bmem = (0x80000 |
581 ((inb(eth_asic_base + WD_MSR) & 0x3F) << 13));
582 } else
583 eth_bmem = WD_DEFAULT_MEM;
584 if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) {
585 *((unsigned int *)(eth_bmem + 8192)) = (unsigned int)0;
586 if (*((unsigned int *)(eth_bmem + 8192))) {
587 brd += 2;
588 eth_memsize = brd->memsize;
591 outb(0x80, eth_asic_base + WD_MSR); /* Reset */
592 for (i=0; i<ETH_ALEN; i++) {
593 nic->node_addr[i] = inb(i+eth_asic_base+WD_LAR);
595 printf("\n%s base %#hx, memory %#hx, addr %!\n",
596 brd->name, eth_asic_base, eth_bmem, nic->node_addr);
597 if (eth_flags & FLAG_790) {
598 outb(WD_MSR_MENB, eth_asic_base+WD_MSR);
599 outb((inb(eth_asic_base+0x04) |
600 0x80), eth_asic_base+0x04);
601 outb((((unsigned)eth_bmem >> 13) & 0x0F) |
602 (((unsigned)eth_bmem >> 11) & 0x40) |
603 (inb(eth_asic_base+0x0B) & 0xB0), eth_asic_base+0x0B);
604 outb((inb(eth_asic_base+0x04) &
605 ~0x80), eth_asic_base+0x04);
606 } else {
607 outb((((unsigned)eth_bmem >> 13) & 0x3F) | 0x40, eth_asic_base+WD_MSR);
609 if (eth_flags & FLAG_16BIT) {
610 if (eth_flags & FLAG_790) {
611 eth_laar = inb(eth_asic_base + WD_LAAR);
612 outb(WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
613 } else {
614 outb((eth_laar =
615 WD_LAAR_L16EN | 1), eth_asic_base + WD_LAAR);
617 The previous line used to be
618 WD_LAAR_M16EN | WD_LAAR_L16EN | 1));
619 jluke@deakin.edu.au reported that removing WD_LAAR_M16EN made
620 it work for WD8013s. This seems to work for my 8013 boards. I
621 don't know what is really happening. I wish I had data sheets
622 or more time to decode the Linux driver. - Ken
625 inb(0x84);
627 #endif
628 #ifdef INCLUDE_3C503
629 /******************************************************************
630 Search for 3Com 3c503 if no WD/SMC cards
631 ******************************************************************/
632 if (eth_vendor == VENDOR_NONE) {
633 int idx;
634 int iobase_reg, membase_reg;
635 static unsigned short base[] = {
636 0x300, 0x310, 0x330, 0x350,
637 0x250, 0x280, 0x2A0, 0x2E0, 0 };
639 /* Loop through possible addresses checking each one */
641 for (idx = 0; (eth_nic_base = base[idx]) != 0; ++idx) {
643 eth_asic_base = eth_nic_base + _3COM_ASIC_OFFSET;
645 * Note that we use the same settings for both 8 and 16 bit cards:
646 * both have an 8K bank of memory at page 1 while only the 16 bit
647 * cards have a bank at page 0.
649 eth_memsize = MEM_16384;
650 eth_tx_start = 32;
651 eth_rx_start = 32 + D8390_TXBUF_SIZE;
653 /* Check our base address. iobase and membase should */
654 /* both have a maximum of 1 bit set or be 0. */
656 iobase_reg = inb(eth_asic_base + _3COM_BCFR);
657 membase_reg = inb(eth_asic_base + _3COM_PCFR);
659 if ((iobase_reg & (iobase_reg - 1)) ||
660 (membase_reg & (membase_reg - 1)))
661 continue; /* nope */
663 /* Now get the shared memory address */
665 eth_flags = 0;
667 switch (membase_reg) {
668 case _3COM_PCFR_DC000:
669 eth_bmem = 0xdc000;
670 break;
671 case _3COM_PCFR_D8000:
672 eth_bmem = 0xd8000;
673 break;
674 case _3COM_PCFR_CC000:
675 eth_bmem = 0xcc000;
676 break;
677 case _3COM_PCFR_C8000:
678 eth_bmem = 0xc8000;
679 break;
680 case _3COM_PCFR_PIO:
681 eth_flags |= FLAG_PIO;
682 eth_bmem = 0;
683 break;
684 default:
685 continue; /* nope */
687 break;
690 if (base[idx] == 0) /* not found */
691 return (0);
692 #ifndef T503_SHMEM
693 eth_flags |= FLAG_PIO; /* force PIO mode */
694 eth_bmem = 0;
695 #endif
696 eth_vendor = VENDOR_3COM;
699 /* Need this to make ns8390_poll() happy. */
701 eth_rmem = eth_bmem - 0x2000;
703 /* Reset NIC and ASIC */
705 outb(_3COM_CR_RST | _3COM_CR_XSEL, eth_asic_base + _3COM_CR );
706 outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR );
708 /* Get our ethernet address */
710 outb(_3COM_CR_EALO | _3COM_CR_XSEL, eth_asic_base + _3COM_CR);
711 printf("\n3Com 3c503 base %#hx, ", eth_nic_base);
712 if (eth_flags & FLAG_PIO)
713 printf("PIO mode");
714 else
715 printf("memory %#hx", eth_bmem);
716 for (i=0; i<ETH_ALEN; i++) {
717 nic->node_addr[i] = inb(eth_nic_base+i);
719 printf(", %s, addr %!\n", nic->flags ? "AUI" : "internal xcvr",
720 nic->node_addr);
721 outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR);
723 * Initialize GA configuration register. Set bank and enable shared
724 * mem. We always use bank 1. Disable interrupts.
726 outb(_3COM_GACFR_RSEL |
727 _3COM_GACFR_MBS0 | _3COM_GACFR_TCM | _3COM_GACFR_NIM, eth_asic_base + _3COM_GACFR);
729 outb(0xff, eth_asic_base + _3COM_VPTR2);
730 outb(0xff, eth_asic_base + _3COM_VPTR1);
731 outb(0x00, eth_asic_base + _3COM_VPTR0);
733 * Clear memory and verify that it worked (we use only 8K)
736 if (!(eth_flags & FLAG_PIO)) {
737 memset((char *)eth_bmem, 0, 0x2000);
738 for(i = 0; i < 0x2000; ++i)
739 if (*(((char *)eth_bmem)+i)) {
740 printf ("Failed to clear 3c503 shared mem.\n");
741 return (0);
745 * Initialize GA page/start/stop registers.
747 outb(eth_tx_start, eth_asic_base + _3COM_PSTR);
748 outb(eth_memsize, eth_asic_base + _3COM_PSPR);
750 #endif
751 #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
752 /******************************************************************
753 Search for NE1000/2000 if no WD/SMC or 3com cards
754 ******************************************************************/
755 if (eth_vendor == VENDOR_NONE) {
756 char romdata[16], testbuf[32];
757 int idx;
758 static char test[] = "NE*000 memory";
759 static unsigned short base[] = {
760 #ifdef NE_SCAN
761 NE_SCAN,
762 #endif
763 0 };
764 /* if no addresses supplied, fall back on defaults */
765 if (probe_addrs == 0 || probe_addrs[0] == 0)
766 probe_addrs = base;
767 eth_bmem = 0; /* No shared memory */
768 for (idx = 0; (eth_nic_base = probe_addrs[idx]) != 0; ++idx) {
769 eth_flags = FLAG_PIO;
770 eth_asic_base = eth_nic_base + NE_ASIC_OFFSET;
771 eth_memsize = MEM_16384;
772 eth_tx_start = 32;
773 eth_rx_start = 32 + D8390_TXBUF_SIZE;
774 c = inb(eth_asic_base + NE_RESET);
775 outb(c, eth_asic_base + NE_RESET);
776 inb(0x84);
777 outb(D8390_COMMAND_STP |
778 D8390_COMMAND_RD2, eth_nic_base + D8390_P0_COMMAND);
779 outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
780 outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
781 outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
782 outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
783 #ifdef NS8390_FORCE_16BIT
784 eth_flags |= FLAG_16BIT; /* force 16-bit mode */
785 #endif
787 eth_pio_write(test, 8192, sizeof(test));
788 eth_pio_read(8192, testbuf, sizeof(test));
789 if (!memcmp(test, testbuf, sizeof(test)))
790 break;
791 eth_flags |= FLAG_16BIT;
792 eth_memsize = MEM_32768;
793 eth_tx_start = 64;
794 eth_rx_start = 64 + D8390_TXBUF_SIZE;
795 outb(D8390_DCR_WTS |
796 D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
797 outb(MEM_16384, eth_nic_base + D8390_P0_PSTART);
798 outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP);
799 eth_pio_write(test, 16384, sizeof(test));
800 eth_pio_read(16384, testbuf, sizeof(test));
801 if (!memcmp(testbuf, test, sizeof(test)))
802 break;
804 if (eth_nic_base == 0)
805 return (0);
806 if (eth_nic_base > ISA_MAX_ADDR) /* PCI probably */
807 eth_flags |= FLAG_16BIT;
808 eth_vendor = VENDOR_NOVELL;
809 eth_pio_read(0, romdata, sizeof(romdata));
810 for (i=0; i<ETH_ALEN; i++) {
811 nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)];
813 printf("\nNE%c000 base %#hx, addr %!\n",
814 (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base,
815 nic->node_addr);
817 #endif
818 if (eth_vendor == VENDOR_NONE)
819 return(0);
820 if (eth_vendor != VENDOR_3COM)
821 eth_rmem = eth_bmem;
822 ns8390_reset(nic);
823 nic->reset = ns8390_reset;
824 nic->poll = ns8390_poll;
825 nic->transmit = ns8390_transmit;
826 nic->disable = ns8390_disable;
827 return(nic);
831 * Local variables:
832 * c-basic-offset: 8
833 * End: