1 /**************************************************************************
2 ETHERBOOT - BOOTP/TFTP Bootstrap Program
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 Multicast support added by Timothy Legge (timlegge@users.sourceforge.net) 09/28/2003
17 Relocation support added by Ken Yap (ken_yap@users.sourceforge.net) 28/12/02
18 3c503 support added by Bill Paul (wpaul@ctr.columbia.edu) on 11/15/94
19 SMC8416 support added by Bill Paul (wpaul@ctr.columbia.edu) on 12/25/94
20 3c503 PIO support added by Jim Hague (jim.hague@acm.org) on 2/17/98
21 RX overrun by Klaus Espenlaub (espenlaub@informatik.uni-ulm.de) on 3/10/99
22 parts taken from the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
23 SMC8416 PIO support added by Andrew Bettison (andrewb@zip.com.au) on 4/3/02
24 based on the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
26 **************************************************************************/
28 #warning "ns8390.c is a horrendous mess and needs to be tidied up"
32 #include "etherboot.h"
35 #include <gpxe/ethernet.h>
42 static unsigned char eth_vendor, eth_flags;
44 static unsigned char eth_laar;
46 static unsigned short eth_nic_base, eth_asic_base;
47 static unsigned char eth_memsize, eth_rx_start, eth_tx_start;
48 static Address eth_bmem, eth_rmem;
49 static unsigned char eth_drain_receiver;
52 static struct wd_board {
58 {"WD8003S", TYPE_WD8003S, 0, MEM_8192},
59 {"WD8003E", TYPE_WD8003E, 0, MEM_8192},
60 {"WD8013EBT", TYPE_WD8013EBT, FLAG_16BIT, MEM_16384},
61 {"WD8003W", TYPE_WD8003W, 0, MEM_8192},
62 {"WD8003EB", TYPE_WD8003EB, 0, MEM_8192},
63 {"WD8013W", TYPE_WD8013W, FLAG_16BIT, MEM_16384},
65 TYPE_WD8013EP, 0, MEM_8192},
66 {"WD8013WC", TYPE_WD8013WC, FLAG_16BIT, MEM_16384},
67 {"WD8013EPC", TYPE_WD8013EPC, FLAG_16BIT, MEM_16384},
68 {"SMC8216T", TYPE_SMC8216T, FLAG_16BIT | FLAG_790, MEM_16384},
69 {"SMC8216C", TYPE_SMC8216C, FLAG_16BIT | FLAG_790, MEM_16384},
70 {"SMC8416T", TYPE_SMC8416T, FLAG_16BIT | FLAG_790, MEM_8192},
71 {"SMC8416C/BT", TYPE_SMC8416C, FLAG_16BIT | FLAG_790, MEM_8192},
72 {"SMC8013EBP", TYPE_SMC8013EBP,FLAG_16BIT, MEM_16384},
78 static unsigned char t503_output; /* AUI or internal xcvr (Thinnet) */
81 #if defined(INCLUDE_WD)
82 #define ASIC_PIO WD_IAR
83 #define eth_probe wd_probe
84 #if defined(INCLUDE_3C503) || defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
85 Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
89 #if defined(INCLUDE_3C503)
90 #define eth_probe t503_probe
91 #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || defined(INCLUDE_WD)
92 Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
96 #if defined(INCLUDE_NE)
97 #define eth_probe ne_probe
98 #if defined(INCLUDE_NS8390) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
99 Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
103 #if defined(INCLUDE_NS8390)
104 #define eth_probe nepci_probe
105 #if defined(INCLUDE_NE) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
106 Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
110 #if defined(INCLUDE_3C503)
111 #define ASIC_PIO _3COM_RFMSB
113 #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
114 #define ASIC_PIO NE_DATA
118 #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM)) || (defined(INCLUDE_WD) && defined(WD_790_PIO))
119 /**************************************************************************
120 ETH_PIO_READ - Read a frame via Programmed I/O
121 **************************************************************************/
122 static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt)
125 outb(src & 0xff, eth_asic_base + WD_GP2);
126 outb(src >> 8, eth_asic_base + WD_GP2);
128 outb(D8390_COMMAND_RD2 |
129 D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
130 outb(cnt, eth_nic_base + D8390_P0_RBCR0);
131 outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
132 outb(src, eth_nic_base + D8390_P0_RSAR0);
133 outb(src>>8, eth_nic_base + D8390_P0_RSAR1);
134 outb(D8390_COMMAND_RD0 |
135 D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
138 outb(src & 0xff, eth_asic_base + _3COM_DALSB);
139 outb(src >> 8, eth_asic_base + _3COM_DAMSB);
140 outb(t503_output | _3COM_CR_START, eth_asic_base + _3COM_CR);
144 if (eth_flags & FLAG_16BIT)
145 cnt = (cnt + 1) >> 1;
149 while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0)
153 if (eth_flags & FLAG_16BIT) {
154 *((unsigned short *)dst) = inw(eth_asic_base + ASIC_PIO);
158 *(dst++) = inb(eth_asic_base + ASIC_PIO);
162 outb(t503_output, eth_asic_base + _3COM_CR);
166 /**************************************************************************
167 ETH_PIO_WRITE - Write a frame via Programmed I/O
168 **************************************************************************/
169 static void eth_pio_write(const unsigned char *src, unsigned int dst, unsigned int cnt)
171 #ifdef COMPEX_RL2000_FIX
173 #endif /* COMPEX_RL2000_FIX */
175 outb(dst & 0xff, eth_asic_base + WD_GP2);
176 outb(dst >> 8, eth_asic_base + WD_GP2);
178 outb(D8390_COMMAND_RD2 |
179 D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
180 outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
181 outb(cnt, eth_nic_base + D8390_P0_RBCR0);
182 outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
183 outb(dst, eth_nic_base + D8390_P0_RSAR0);
184 outb(dst>>8, eth_nic_base + D8390_P0_RSAR1);
185 outb(D8390_COMMAND_RD1 |
186 D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
189 outb(dst & 0xff, eth_asic_base + _3COM_DALSB);
190 outb(dst >> 8, eth_asic_base + _3COM_DAMSB);
192 outb(t503_output | _3COM_CR_DDIR | _3COM_CR_START, eth_asic_base + _3COM_CR);
196 if (eth_flags & FLAG_16BIT)
197 cnt = (cnt + 1) >> 1;
202 while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0)
206 if (eth_flags & FLAG_16BIT) {
207 outw(*((unsigned short *)src), eth_asic_base + ASIC_PIO);
211 outb(*(src++), eth_asic_base + ASIC_PIO);
215 outb(t503_output, eth_asic_base + _3COM_CR);
217 #ifdef COMPEX_RL2000_FIX
219 x < COMPEX_RL2000_TRIES &&
220 (inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
223 if (x >= COMPEX_RL2000_TRIES)
224 printf("Warning: Compex RL2000 aborted wait!\n");
225 #endif /* COMPEX_RL2000_FIX */
227 while((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
233 /**************************************************************************
234 ETH_PIO_READ - Dummy routine when NE2000 not compiled in
235 **************************************************************************/
236 static void eth_pio_read(unsigned int src __unused, unsigned char *dst __unused, unsigned int cnt __unused) {}
240 /**************************************************************************
241 enable_multycast - Enable Multicast
242 **************************************************************************/
243 static void enable_multicast(unsigned short eth_nic_base)
245 unsigned char mcfilter[8];
247 memset(mcfilter, 0xFF, 8);
248 outb(4, eth_nic_base+D8390_P0_RCR);
249 outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1, eth_nic_base + D8390_P0_COMMAND);
252 outb(mcfilter[i], eth_nic_base + 8 + i);
253 if(inb(eth_nic_base + 8 + i)!=mcfilter[i])
254 printf("Error SMC 83C690 Multicast filter read/write mishap %d\n",i);
256 outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0, eth_nic_base + D8390_P0_COMMAND);
257 outb(4 | 0x08, eth_nic_base+D8390_P0_RCR);
260 /**************************************************************************
261 NS8390_RESET - Reset adapter
262 **************************************************************************/
263 static void ns8390_reset(struct nic *nic)
267 eth_drain_receiver = 0;
269 if (eth_flags & FLAG_790)
270 outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
273 outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
274 D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
275 if (eth_flags & FLAG_16BIT)
276 outb(0x49, eth_nic_base+D8390_P0_DCR);
278 outb(0x48, eth_nic_base+D8390_P0_DCR);
279 outb(0, eth_nic_base+D8390_P0_RBCR0);
280 outb(0, eth_nic_base+D8390_P0_RBCR1);
281 outb(0x20, eth_nic_base+D8390_P0_RCR); /* monitor mode */
282 outb(2, eth_nic_base+D8390_P0_TCR);
283 outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
284 outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART);
286 if (eth_flags & FLAG_790) {
288 outb(0x10, eth_asic_base + 0x06); /* disable interrupts, enable PIO */
289 outb(0x01, eth_nic_base + 0x09); /* enable ring read auto-wrap */
291 outb(0, eth_nic_base + 0x09);
295 outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP);
296 outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND);
297 outb(0xFF, eth_nic_base+D8390_P0_ISR);
298 outb(0, eth_nic_base+D8390_P0_IMR);
300 if (eth_flags & FLAG_790)
301 outb(D8390_COMMAND_PS1 |
302 D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
305 outb(D8390_COMMAND_PS1 |
306 D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
307 for (i=0; i<ETH_ALEN; i++)
308 outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i);
309 for (i=0; i<ETH_ALEN; i++)
310 outb(0xFF, eth_nic_base+D8390_P1_MAR0+i);
311 outb(eth_rx_start, eth_nic_base+D8390_P1_CURR);
313 if (eth_flags & FLAG_790)
314 outb(D8390_COMMAND_PS0 |
315 D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
318 outb(D8390_COMMAND_PS0 |
319 D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
320 outb(0xFF, eth_nic_base+D8390_P0_ISR);
321 outb(0, eth_nic_base+D8390_P0_TCR); /* transmitter on */
322 outb(4, eth_nic_base+D8390_P0_RCR); /* allow rx broadcast frames */
324 enable_multicast(eth_nic_base);
328 * No way to tell whether or not we're supposed to use
329 * the 3Com's transceiver unless the user tells us.
330 * 'flags' should have some compile time default value
331 * which can be changed from the command menu.
333 t503_output = (nic->flags) ? 0 : _3COM_CR_XSEL;
334 outb(t503_output, eth_asic_base + _3COM_CR);
338 static int ns8390_poll(struct nic *nic, int retrieve);
340 #ifndef INCLUDE_3C503
341 /**************************************************************************
342 ETH_RX_OVERRUN - Bring adapter back to work after an RX overrun
343 **************************************************************************/
344 static void eth_rx_overrun(struct nic *nic)
349 if (eth_flags & FLAG_790)
350 outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
353 outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
354 D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
356 /* wait for at least 1.6ms - we wait one timer tick */
357 start_time = currticks();
358 while (currticks() - start_time <= 1)
361 outb(0, eth_nic_base+D8390_P0_RBCR0); /* reset byte counter */
362 outb(0, eth_nic_base+D8390_P0_RBCR1);
365 * Linux driver checks for interrupted TX here. This is not necessary,
366 * because the transmit routine waits until the frame is sent.
369 /* enter loopback mode and restart NIC */
370 outb(2, eth_nic_base+D8390_P0_TCR);
372 if (eth_flags & FLAG_790)
373 outb(D8390_COMMAND_PS0 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
376 outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
377 D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
379 /* clear the RX ring, acknowledge overrun interrupt */
380 eth_drain_receiver = 1;
381 while (ns8390_poll(nic, 1))
383 eth_drain_receiver = 0;
384 outb(D8390_ISR_OVW, eth_nic_base+D8390_P0_ISR);
386 /* leave loopback mode - no packets to be resent (see Linux driver) */
387 outb(0, eth_nic_base+D8390_P0_TCR);
389 #endif /* INCLUDE_3C503 */
391 /**************************************************************************
392 NS8390_TRANSMIT - Transmit a frame
393 **************************************************************************/
394 static void ns8390_transmit(
396 const char *d, /* Destination */
397 unsigned int t, /* Type */
398 unsigned int s, /* size */
399 const char *p) /* Packet */
401 #if defined(INCLUDE_3C503) || (defined(INCLUDE_WD) && ! defined(WD_790_PIO))
402 Address eth_vmem = bus_to_virt(eth_bmem);
405 if (!(eth_flags & FLAG_PIO)) {
406 memcpy((char *)eth_vmem, d, ETH_ALEN); /* dst */
407 memcpy((char *)eth_vmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
408 *((char *)eth_vmem+12) = t>>8; /* type */
409 *((char *)eth_vmem+13) = t;
410 memcpy((char *)eth_vmem+ETH_HLEN, p, s);
412 while (s < ETH_ZLEN) *((char *)eth_vmem+(s++)) = 0;
417 if (eth_flags & FLAG_16BIT) {
418 outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
422 /* Memory interface */
423 if (eth_flags & FLAG_790) {
424 outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
428 memcpy((char *)eth_vmem, d, ETH_ALEN); /* dst */
429 memcpy((char *)eth_vmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
430 *((char *)eth_vmem+12) = t>>8; /* type */
431 *((char *)eth_vmem+13) = t;
432 memcpy((char *)eth_vmem+ETH_HLEN, p, s);
434 while (s < ETH_ZLEN) *((char *)eth_vmem+(s++)) = 0;
435 if (eth_flags & FLAG_790) {
436 outb(0, eth_asic_base + WD_MSR);
444 #if defined(INCLUDE_3C503)
445 if (eth_flags & FLAG_PIO)
447 #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM)) || (defined(INCLUDE_WD) && defined(WD_790_PIO))
451 type = (t >> 8) | (t << 8);
452 eth_pio_write(d, eth_tx_start<<8, ETH_ALEN);
453 eth_pio_write(nic->node_addr, (eth_tx_start<<8)+ETH_ALEN, ETH_ALEN);
454 /* bcc generates worse code without (const+const) below */
455 eth_pio_write((unsigned char *)&type, (eth_tx_start<<8)+(ETH_ALEN+ETH_ALEN), 2);
456 eth_pio_write(p, (eth_tx_start<<8)+ETH_HLEN, s);
458 if (s < ETH_ZLEN) s = ETH_ZLEN;
461 #if defined(INCLUDE_3C503)
465 if (eth_flags & FLAG_16BIT) {
466 outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
469 if (eth_flags & FLAG_790)
470 outb(D8390_COMMAND_PS0 |
471 D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
474 outb(D8390_COMMAND_PS0 |
475 D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
476 outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
477 outb(s, eth_nic_base+D8390_P0_TBCR0);
478 outb(s>>8, eth_nic_base+D8390_P0_TBCR1);
480 if (eth_flags & FLAG_790)
481 outb(D8390_COMMAND_PS0 |
482 D8390_COMMAND_TXP | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
485 outb(D8390_COMMAND_PS0 |
486 D8390_COMMAND_TXP | D8390_COMMAND_RD2 |
487 D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
490 /**************************************************************************
491 NS8390_POLL - Wait for a frame
492 **************************************************************************/
493 static int ns8390_poll(struct nic *nic, int retrieve)
496 unsigned char rstat, curr, next;
497 unsigned short len, frag;
498 unsigned short pktoff;
500 struct ringbuffer pkthdr;
502 #ifndef INCLUDE_3C503
503 /* avoid infinite recursion: see eth_rx_overrun() */
504 if (!eth_drain_receiver && (inb(eth_nic_base+D8390_P0_ISR) & D8390_ISR_OVW)) {
508 #endif /* INCLUDE_3C503 */
509 rstat = inb(eth_nic_base+D8390_P0_RSR);
510 if (!(rstat & D8390_RSTAT_PRX)) return(0);
511 next = inb(eth_nic_base+D8390_P0_BOUND)+1;
512 if (next >= eth_memsize) next = eth_rx_start;
513 outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND);
514 curr = inb(eth_nic_base+D8390_P1_CURR);
515 outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND);
516 if (curr >= eth_memsize) curr=eth_rx_start;
517 if (curr == next) return(0);
519 if ( ! retrieve ) return 1;
522 if (eth_flags & FLAG_16BIT) {
523 outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
527 if (eth_flags & FLAG_790) {
528 outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
535 if (eth_flags & FLAG_PIO)
536 eth_pio_read(pktoff, (char *)&pkthdr, 4);
538 memcpy(&pkthdr, bus_to_virt(eth_rmem + pktoff), 4);
539 pktoff += sizeof(pkthdr);
540 /* incoming length includes FCS so must sub 4 */
541 len = pkthdr.len - 4;
542 if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN
543 || len > ETH_FRAME_LEN) {
544 printf("Bogus packet, ignoring\n");
549 nic->packetlen = len; /* available to caller */
550 frag = (eth_memsize << 8) - pktoff;
551 if (len > frag) { /* We have a wrap-around */
552 /* read first part */
553 if (eth_flags & FLAG_PIO)
554 eth_pio_read(pktoff, p, frag);
556 memcpy(p, bus_to_virt(eth_rmem + pktoff), frag);
557 pktoff = eth_rx_start << 8;
561 /* read second part */
562 if (eth_flags & FLAG_PIO)
563 eth_pio_read(pktoff, p, len);
565 memcpy(p, bus_to_virt(eth_rmem + pktoff), len);
570 if (eth_flags & FLAG_790) {
571 outb(0, eth_asic_base + WD_MSR);
575 if (eth_flags & FLAG_16BIT) {
576 outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
581 next = pkthdr.next; /* frame number of next packet */
582 if (next == eth_rx_start)
584 outb(next-1, eth_nic_base+D8390_P0_BOUND);
588 /**************************************************************************
589 NS8390_DISABLE - Turn off adapter
590 **************************************************************************/
591 static void ns8390_disable ( struct nic *nic ) {
595 /**************************************************************************
596 NS8390_IRQ - Enable, Disable, or Force interrupts
597 **************************************************************************/
598 static void ns8390_irq(struct nic *nic __unused, irq_action_t action __unused)
610 /**************************************************************************
611 ETH_PROBE - Look for an adapter
612 **************************************************************************/
613 #ifdef INCLUDE_NS8390
614 static int eth_probe (struct dev *dev, struct pci_device *pci)
616 static int eth_probe (struct dev *dev, unsigned short *probe_addrs __unused)
619 struct nic *nic = (struct nic *)dev;
621 #ifdef INCLUDE_NS8390
622 unsigned short pci_probe_addrs[] = { pci->ioaddr, 0 };
623 unsigned short *probe_addrs = pci_probe_addrs;
625 eth_vendor = VENDOR_NONE;
626 eth_drain_receiver = 0;
632 /******************************************************************
633 Search for WD/SMC cards
634 ******************************************************************/
635 struct wd_board *brd;
636 unsigned short chksum;
638 for (eth_asic_base = WD_LOW_BASE; eth_asic_base <= WD_HIGH_BASE;
639 eth_asic_base += 0x20) {
642 chksum += inb(eth_asic_base+i);
643 /* Extra checks to avoid soundcard */
644 if ((chksum & 0xFF) == 0xFF &&
645 inb(eth_asic_base+8) != 0xFF &&
646 inb(eth_asic_base+9) != 0xFF)
649 if (eth_asic_base > WD_HIGH_BASE)
651 /* We've found a board */
652 eth_vendor = VENDOR_WD;
653 eth_nic_base = eth_asic_base + WD_NIC_ADDR;
655 nic->ioaddr = eth_nic_base;
657 c = inb(eth_asic_base+WD_BID); /* Get board id */
658 for (brd = wd_boards; brd->name; brd++)
659 if (brd->id == c) break;
661 printf("Unknown WD/SMC NIC type %hhX\n", c);
662 return (0); /* Unknown type */
664 eth_flags = brd->flags;
665 eth_memsize = brd->memsize;
667 eth_rx_start = D8390_TXBUF_SIZE;
668 if ((c == TYPE_WD8013EP) &&
669 (inb(eth_asic_base + WD_ICR) & WD_ICR_16BIT)) {
670 eth_flags = FLAG_16BIT;
671 eth_memsize = MEM_16384;
673 if ((c & WD_SOFTCONFIG) && (!(eth_flags & FLAG_790))) {
674 eth_bmem = (0x80000 |
675 ((inb(eth_asic_base + WD_MSR) & 0x3F) << 13));
677 eth_bmem = WD_DEFAULT_MEM;
678 if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) {
679 /* from Linux driver, 8416BT detects as 8216 sometimes */
680 unsigned int addr = inb(eth_asic_base + 0xb);
681 if (((addr >> 4) & 3) == 0) {
683 eth_memsize = brd->memsize;
686 outb(0x80, eth_asic_base + WD_MSR); /* Reset */
687 for (i=0; i<ETH_ALEN; i++) {
688 nic->node_addr[i] = inb(i+eth_asic_base+WD_LAR);
690 DBG ( "\n%s base %4.4x", brd->name, eth_asic_base );
691 if (eth_flags & FLAG_790) {
693 DBG ( ", PIO mode, addr %s\n", eth_ntoa ( nic->node_addr ) );
695 eth_flags |= FLAG_PIO; /* force PIO mode */
696 outb(0, eth_asic_base+WD_MSR);
698 DBG ( ", Memory %x, MAC Addr %s\n", eth_bmem, eth_ntoa ( nic->node_addr) );
700 outb(WD_MSR_MENB, eth_asic_base+WD_MSR);
701 outb((inb(eth_asic_base+0x04) |
702 0x80), eth_asic_base+0x04);
703 outb(((unsigned)(eth_bmem >> 13) & 0x0F) |
704 ((unsigned)(eth_bmem >> 11) & 0x40) |
705 (inb(eth_asic_base+0x0B) & 0xB0), eth_asic_base+0x0B);
706 outb((inb(eth_asic_base+0x04) &
707 ~0x80), eth_asic_base+0x04);
711 DBG (", Memory %x, MAC Addr %s\n", eth_bmem, eth_ntoa ( nic->node_addr) );
713 outb(((unsigned)(eth_bmem >> 13) & 0x3F) | 0x40, eth_asic_base+WD_MSR);
715 if (eth_flags & FLAG_16BIT) {
716 if (eth_flags & FLAG_790) {
717 eth_laar = inb(eth_asic_base + WD_LAAR);
718 outb(WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
721 WD_LAAR_L16EN | 1), eth_asic_base + WD_LAAR);
723 The previous line used to be
724 WD_LAAR_M16EN | WD_LAAR_L16EN | 1));
725 jluke@deakin.edu.au reported that removing WD_LAAR_M16EN made
726 it work for WD8013s. This seems to work for my 8013 boards. I
727 don't know what is really happening. I wish I had data sheets
728 or more time to decode the Linux driver. - Ken
737 nic->flags = 1; /* aui */
739 nic->flags = 0; /* no aui */
741 /******************************************************************
742 Search for 3Com 3c503 if no WD/SMC cards
743 ******************************************************************/
744 if (eth_vendor == VENDOR_NONE) {
746 int iobase_reg, membase_reg;
747 static unsigned short base[] = {
748 0x300, 0x310, 0x330, 0x350,
749 0x250, 0x280, 0x2A0, 0x2E0, 0 };
751 /* Loop through possible addresses checking each one */
753 for (idx = 0; (eth_nic_base = base[idx]) != 0; ++idx) {
755 eth_asic_base = eth_nic_base + _3COM_ASIC_OFFSET;
757 * Note that we use the same settings for both 8 and 16 bit cards:
758 * both have an 8K bank of memory at page 1 while only the 16 bit
759 * cards have a bank at page 0.
761 eth_memsize = MEM_16384;
763 eth_rx_start = 32 + D8390_TXBUF_SIZE;
765 /* Check our base address. iobase and membase should */
766 /* both have a maximum of 1 bit set or be 0. */
768 iobase_reg = inb(eth_asic_base + _3COM_BCFR);
769 membase_reg = inb(eth_asic_base + _3COM_PCFR);
771 if ((iobase_reg & (iobase_reg - 1)) ||
772 (membase_reg & (membase_reg - 1)))
775 /* Now get the shared memory address */
779 switch (membase_reg) {
780 case _3COM_PCFR_DC000:
783 case _3COM_PCFR_D8000:
786 case _3COM_PCFR_CC000:
789 case _3COM_PCFR_C8000:
793 eth_flags |= FLAG_PIO;
802 if (base[idx] == 0) /* not found */
805 eth_flags |= FLAG_PIO; /* force PIO mode */
808 eth_vendor = VENDOR_3COM;
811 /* Need this to make ns8390_poll() happy. */
813 eth_rmem = eth_bmem - 0x2000;
815 /* Reset NIC and ASIC */
817 outb(_3COM_CR_RST | _3COM_CR_XSEL, eth_asic_base + _3COM_CR );
818 outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR );
820 /* Get our ethernet address */
822 outb(_3COM_CR_EALO | _3COM_CR_XSEL, eth_asic_base + _3COM_CR);
823 nic->ioaddr = eth_nic_base;
824 DBG ( "\n3Com 3c503 base %4.4x, ", eth_nic_base );
825 if (eth_flags & FLAG_PIO)
828 DBG ( "memory %4.4x", eth_bmem );
829 for (i=0; i<ETH_ALEN; i++) {
830 nic->node_addr[i] = inb(eth_nic_base+i);
832 DBG ( ", %s, MAC Addr %s\n", nic->flags ? "AUI" : "internal xcvr",
833 eth_ntoa ( nic->node_addr ) );
835 outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR);
837 * Initialize GA configuration register. Set bank and enable shared
838 * mem. We always use bank 1. Disable interrupts.
840 outb(_3COM_GACFR_RSEL |
841 _3COM_GACFR_MBS0 | _3COM_GACFR_TCM | _3COM_GACFR_NIM, eth_asic_base + _3COM_GACFR);
843 outb(0xff, eth_asic_base + _3COM_VPTR2);
844 outb(0xff, eth_asic_base + _3COM_VPTR1);
845 outb(0x00, eth_asic_base + _3COM_VPTR0);
847 * Clear memory and verify that it worked (we use only 8K)
850 if (!(eth_flags & FLAG_PIO)) {
851 memset(bus_to_virt(eth_bmem), 0, 0x2000);
852 for(i = 0; i < 0x2000; ++i)
853 if (*((char *)(bus_to_virt(eth_bmem+i)))) {
854 printf ("Failed to clear 3c503 shared mem.\n");
859 * Initialize GA page/start/stop registers.
861 outb(eth_tx_start, eth_asic_base + _3COM_PSTR);
862 outb(eth_memsize, eth_asic_base + _3COM_PSPR);
865 #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
867 /******************************************************************
868 Search for NE1000/2000 if no WD/SMC or 3com cards
869 ******************************************************************/
871 if (eth_vendor == VENDOR_NONE) {
872 char romdata[16], testbuf[32];
874 static char test[] = "NE*000 memory";
875 static unsigned short base[] = {
880 /* if no addresses supplied, fall back on defaults */
881 if (probe_addrs == 0 || probe_addrs[0] == 0)
883 eth_bmem = 0; /* No shared memory */
884 for (idx = 0; (eth_nic_base = probe_addrs[idx]) != 0; ++idx) {
885 eth_flags = FLAG_PIO;
886 eth_asic_base = eth_nic_base + NE_ASIC_OFFSET;
887 eth_memsize = MEM_16384;
889 eth_rx_start = 32 + D8390_TXBUF_SIZE;
890 c = inb(eth_asic_base + NE_RESET);
891 outb(c, eth_asic_base + NE_RESET);
893 outb(D8390_COMMAND_STP |
894 D8390_COMMAND_RD2, eth_nic_base + D8390_P0_COMMAND);
895 outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
896 outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
897 outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
898 outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
899 #ifdef NS8390_FORCE_16BIT
900 eth_flags |= FLAG_16BIT; /* force 16-bit mode */
903 eth_pio_write(test, 8192, sizeof(test));
904 eth_pio_read(8192, testbuf, sizeof(test));
905 if (!memcmp(test, testbuf, sizeof(test)))
907 eth_flags |= FLAG_16BIT;
908 eth_memsize = MEM_32768;
910 eth_rx_start = 64 + D8390_TXBUF_SIZE;
912 D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
913 outb(MEM_16384, eth_nic_base + D8390_P0_PSTART);
914 outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP);
915 eth_pio_write(test, 16384, sizeof(test));
916 eth_pio_read(16384, testbuf, sizeof(test));
917 if (!memcmp(testbuf, test, sizeof(test)))
920 if (eth_nic_base == 0)
922 if (eth_nic_base > ISA_MAX_ADDR) /* PCI probably */
923 eth_flags |= FLAG_16BIT;
924 eth_vendor = VENDOR_NOVELL;
925 eth_pio_read(0, romdata, sizeof(romdata));
926 for (i=0; i<ETH_ALEN; i++) {
927 nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)];
929 nic->ioaddr = eth_nic_base;
930 DBG ( "\nNE%c000 base %4.4x, MAC Addr %s\n",
931 (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base,
932 eth_ntoa ( nic->node_addr ) );
936 if (eth_vendor == VENDOR_NONE)
938 if (eth_vendor != VENDOR_3COM)
941 static struct nic_operations ns8390_operations;
942 static struct nic_operations ns8390_operations = {
943 .connect = dummy_connect,
945 .transmit = ns8390_transmit,
947 .disable = ns8390_disable,
949 nic->nic_op = &ns8390_operations;
951 /* Based on PnP ISA map */
953 dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
954 dev->devid.device_id = htons(0x812a);
957 dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
958 dev->devid.device_id = htons(0x80f3);
961 dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
962 dev->devid.device_id = htons(0x80d6);
968 struct isa_driver wd_driver __isa_driver = {
974 ISA_ROM("wd","WD8003/8013, SMC8216/8416, SMC 83c790 (EtherEZ)");
978 struct isa_driver t503_driver __isa_driver = {
984 ISA_ROM("3c503","3Com503, Etherlink II[/16]");
988 struct isa_driver ne_driver __isa_driver = {
994 ISA_ROM("ne","NE1000/2000 and clones");
997 #ifdef INCLUDE_NS8390
998 static struct pci_device_id nepci_nics[] = {
999 /* A few NE2000 PCI clones, list not exhaustive */
1000 PCI_ROM(0x10ec, 0x8029, "rtl8029", "Realtek 8029"),
1001 PCI_ROM(0x1186, 0x0300, "dlink-528", "D-Link DE-528"),
1002 PCI_ROM(0x1050, 0x0940, "winbond940", "Winbond NE2000-PCI"), /* Winbond 86C940 / 89C940 */
1003 PCI_ROM(0x1050, 0x5a5a, "winbond940f", "Winbond W89c940F"), /* Winbond 89C940F */
1004 PCI_ROM(0x11f6, 0x1401, "compexrl2000", "Compex ReadyLink 2000"),
1005 PCI_ROM(0x8e2e, 0x3000, "ktiet32p2", "KTI ET32P2"),
1006 PCI_ROM(0x4a14, 0x5000, "nv5000sc", "NetVin NV5000SC"),
1007 PCI_ROM(0x12c3, 0x0058, "holtek80232", "Holtek HT80232"),
1008 PCI_ROM(0x12c3, 0x5598, "holtek80229", "Holtek HT80229"),
1009 PCI_ROM(0x10bd, 0x0e34, "surecom-ne34", "Surecom NE34"),
1010 PCI_ROM(0x1106, 0x0926, "via86c926", "Via 86c926"),
1013 PCI_DRIVER ( nepci_driver, "NE2000/PCI", nepci_nics, PCI_NO_CLASS );
1015 BOOT_DRIVER ( "NE2000/PCI", nepci_probe );
1017 #endif /* INCLUDE_NS8390 */