iPXE
ns8390.c
Go to the documentation of this file.
1 /**************************************************************************
2 ETHERBOOT - BOOTP/TFTP Bootstrap Program
3 
4 Author: Martin Renters
5  Date: May/94
6 
7  This code is based heavily on David Greenman's if_ed.c driver
8 
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.
15 
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)
25 
26 **************************************************************************/
27 
28 FILE_LICENCE ( BSD2 );
29 
30 /* #warning "ns8390.c: FIXME: split ISA and PCI, clean up" */
31 
32 #if 1
33 
34 #if !defined(INCLUDE_NS8390) && !defined(INCLUDE_WD) && \
35  !defined(INCLUDE_NE) && !defined(INCLUDE_3C503)
36  /* The driver named ns8390 is the PCI driver, often called
37  "PCI ne2000 clones". */
38 # define INCLUDE_NS8390 1
39 #endif
40 
41 #include "etherboot.h"
42 #include "nic.h"
43 #include "ns8390.h"
44 #include <ipxe/ethernet.h>
45 #ifdef INCLUDE_NS8390
46 #include <ipxe/pci.h>
47 #else
48 #include <ipxe/isa.h>
49 #endif
50 
51 static unsigned char eth_vendor, eth_flags;
52 #ifdef INCLUDE_WD
53 static unsigned char eth_laar;
54 #endif
55 static unsigned short eth_nic_base, eth_asic_base;
56 static unsigned char eth_memsize, eth_rx_start, eth_tx_start;
58 static unsigned char eth_drain_receiver;
59 
60 #ifdef INCLUDE_WD
61 static struct wd_board {
62  const char *name;
63  char id;
64  char flags;
65  char memsize;
66 } wd_boards[] = {
67  {"WD8003S", TYPE_WD8003S, 0, MEM_8192},
68  {"WD8003E", TYPE_WD8003E, 0, MEM_8192},
69  {"WD8013EBT", TYPE_WD8013EBT, FLAG_16BIT, MEM_16384},
70  {"WD8003W", TYPE_WD8003W, 0, MEM_8192},
71  {"WD8003EB", TYPE_WD8003EB, 0, MEM_8192},
72  {"WD8013W", TYPE_WD8013W, FLAG_16BIT, MEM_16384},
73  {"WD8003EP/WD8013EP",
75  {"WD8013WC", TYPE_WD8013WC, FLAG_16BIT, MEM_16384},
76  {"WD8013EPC", TYPE_WD8013EPC, FLAG_16BIT, MEM_16384},
77  {"SMC8216T", TYPE_SMC8216T, FLAG_16BIT | FLAG_790, MEM_16384},
78  {"SMC8216C", TYPE_SMC8216C, FLAG_16BIT | FLAG_790, MEM_16384},
79  {"SMC8416T", TYPE_SMC8416T, FLAG_16BIT | FLAG_790, MEM_8192},
80  {"SMC8416C/BT", TYPE_SMC8416C, FLAG_16BIT | FLAG_790, MEM_8192},
81  {"SMC8013EBP", TYPE_SMC8013EBP,FLAG_16BIT, MEM_16384},
82  {NULL, 0, 0, 0}
83 };
84 #endif
85 
86 #ifdef INCLUDE_3C503
87 static unsigned char t503_output; /* AUI or internal xcvr (Thinnet) */
88 #endif
89 
90 #if defined(INCLUDE_WD)
91 #define ASIC_PIO WD_IAR
92 #define eth_probe wd_probe
93 #if defined(INCLUDE_3C503) || defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
94 Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
95 #endif
96 #endif
97 
98 #if defined(INCLUDE_3C503)
99 #define eth_probe t503_probe
100 #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || defined(INCLUDE_WD)
101 Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
102 #endif
103 #endif
104 
105 #if defined(INCLUDE_NE)
106 #define eth_probe ne_probe
107 #if defined(INCLUDE_NS8390) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
108 Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
109 #endif
110 #endif
111 
112 #if defined(INCLUDE_NS8390)
113 #define eth_probe nepci_probe
114 #if defined(INCLUDE_NE) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
115 Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
116 #endif
117 #endif
118 
119 #if defined(INCLUDE_3C503)
120 #define ASIC_PIO _3COM_RFMSB
121 #else
122 #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
123 #define ASIC_PIO NE_DATA
124 #endif
125 #endif
126 
127 #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM)) || (defined(INCLUDE_WD) && defined(WD_790_PIO))
128 /**************************************************************************
129 ETH_PIO_READ - Read a frame via Programmed I/O
130 **************************************************************************/
131 static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt)
132 {
133 #ifdef INCLUDE_WD
134  outb(src & 0xff, eth_asic_base + WD_GP2);
135  outb(src >> 8, eth_asic_base + WD_GP2);
136 #else
140  outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
145 
146 #ifdef INCLUDE_3C503
147  outb(src & 0xff, eth_asic_base + _3COM_DALSB);
149  outb(t503_output | _3COM_CR_START, eth_asic_base + _3COM_CR);
150 #endif
151 #endif
152 
153  if (eth_flags & FLAG_16BIT)
154  cnt = (cnt + 1) >> 1;
155 
156  while(cnt--) {
157 #ifdef INCLUDE_3C503
159  ;
160 #endif
161 
162  if (eth_flags & FLAG_16BIT) {
163  *((unsigned short *)dst) = inw(eth_asic_base + ASIC_PIO);
164  dst += 2;
165  }
166  else
167  *(dst++) = inb(eth_asic_base + ASIC_PIO);
168  }
169 
170 #ifdef INCLUDE_3C503
171  outb(t503_output, eth_asic_base + _3COM_CR);
172 #endif
173 }
174 
175 /**************************************************************************
176 ETH_PIO_WRITE - Write a frame via Programmed I/O
177 **************************************************************************/
178 static void eth_pio_write(const unsigned char *src, unsigned int dst, unsigned int cnt)
179 {
180 #ifdef COMPEX_RL2000_FIX
181  unsigned int x;
182 #endif /* COMPEX_RL2000_FIX */
183 #ifdef INCLUDE_WD
184  outb(dst & 0xff, eth_asic_base + WD_GP2);
185  outb(dst >> 8, eth_asic_base + WD_GP2);
186 #else
191  outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
193  outb(dst>>8, eth_nic_base + D8390_P0_RSAR1);
196 
197 #ifdef INCLUDE_3C503
198  outb(dst & 0xff, eth_asic_base + _3COM_DALSB);
199  outb(dst >> 8, eth_asic_base + _3COM_DAMSB);
200 
202 #endif
203 #endif
204 
205  if (eth_flags & FLAG_16BIT)
206  cnt = (cnt + 1) >> 1;
207 
208  while(cnt--)
209  {
210 #ifdef INCLUDE_3C503
212  ;
213 #endif
214 
215  if (eth_flags & FLAG_16BIT) {
216  outw(*((unsigned short *)src), eth_asic_base + ASIC_PIO);
217  src += 2;
218  }
219  else
220  outb(*(src++), eth_asic_base + ASIC_PIO);
221  }
222 
223 #ifdef INCLUDE_3C503
224  outb(t503_output, eth_asic_base + _3COM_CR);
225 #else
226 #ifdef COMPEX_RL2000_FIX
227  for (x = 0;
228  x < COMPEX_RL2000_TRIES &&
230  != D8390_ISR_RDC;
231  ++x);
232  if (x >= COMPEX_RL2000_TRIES)
233  printf("Warning: Compex RL2000 aborted wait!\n");
234 #endif /* COMPEX_RL2000_FIX */
235 #ifndef INCLUDE_WD
237  != D8390_ISR_RDC);
238 #endif
239 #endif
240 }
241 #else
242 /**************************************************************************
243 ETH_PIO_READ - Dummy routine when NE2000 not compiled in
244 **************************************************************************/
245 static void eth_pio_read(unsigned int src __unused, unsigned char *dst __unused, unsigned int cnt __unused) {}
246 #endif
247 
248 
249 /**************************************************************************
250 enable_multycast - Enable Multicast
251 **************************************************************************/
252 static void enable_multicast(unsigned short eth_nic_base)
253 {
254  unsigned char mcfilter[8];
255  int i;
256  memset(mcfilter, 0xFF, 8);
259  for(i=0;i<8;i++)
260  {
261  outb(mcfilter[i], eth_nic_base + 8 + i);
262  if(inb(eth_nic_base + 8 + i)!=mcfilter[i])
263  printf("Error SMC 83C690 Multicast filter read/write mishap %d\n",i);
264  }
266  outb(4 | 0x08, eth_nic_base+D8390_P0_RCR);
267 }
268 
269 /**************************************************************************
270 NS8390_RESET - Reset adapter
271 **************************************************************************/
272 static void ns8390_reset(struct nic *nic)
273 {
274  int i;
275 
276  eth_drain_receiver = 0;
277 #ifdef INCLUDE_WD
278  if (eth_flags & FLAG_790)
280  else
281 #endif
284  if (eth_flags & FLAG_16BIT)
286  else
290  outb(0x20, eth_nic_base+D8390_P0_RCR); /* monitor mode */
294 #ifdef INCLUDE_WD
295  if (eth_flags & FLAG_790) {
296 #ifdef WD_790_PIO
297  outb(0x10, eth_asic_base + 0x06); /* disable interrupts, enable PIO */
298  outb(0x01, eth_nic_base + 0x09); /* enable ring read auto-wrap */
299 #else
300  outb(0, eth_nic_base + 0x09);
301 #endif
302  }
303 #endif
308 #ifdef INCLUDE_WD
309  if (eth_flags & FLAG_790)
312  else
313 #endif
316  for (i=0; i<ETH_ALEN; i++)
318  for (i=0; i<ETH_ALEN; i++)
321 #ifdef INCLUDE_WD
322  if (eth_flags & FLAG_790)
325  else
326 #endif
330  outb(0, eth_nic_base+D8390_P0_TCR); /* transmitter on */
331  outb(4, eth_nic_base+D8390_P0_RCR); /* allow rx broadcast frames */
332 
334 
335 #ifdef INCLUDE_3C503
336  /*
337  * No way to tell whether or not we're supposed to use
338  * the 3Com's transceiver unless the user tells us.
339  * 'flags' should have some compile time default value
340  * which can be changed from the command menu.
341  */
342  t503_output = (nic->flags) ? 0 : _3COM_CR_XSEL;
343  outb(t503_output, eth_asic_base + _3COM_CR);
344 #endif
345 }
346 
347 static int ns8390_poll(struct nic *nic, int retrieve);
348 
349 #ifndef INCLUDE_3C503
350 /**************************************************************************
351 ETH_RX_OVERRUN - Bring adapter back to work after an RX overrun
352 **************************************************************************/
353 static void eth_rx_overrun(struct nic *nic)
354 {
355  int start_time;
356 
357 #ifdef INCLUDE_WD
358  if (eth_flags & FLAG_790)
360  else
361 #endif
364 
365  /* wait for at least 1.6ms - we wait one timer tick */
366  start_time = currticks();
367  while (currticks() - start_time <= 1)
368  /* Nothing */;
369 
370  outb(0, eth_nic_base+D8390_P0_RBCR0); /* reset byte counter */
372 
373  /*
374  * Linux driver checks for interrupted TX here. This is not necessary,
375  * because the transmit routine waits until the frame is sent.
376  */
377 
378  /* enter loopback mode and restart NIC */
380 #ifdef INCLUDE_WD
381  if (eth_flags & FLAG_790)
383  else
384 #endif
387 
388  /* clear the RX ring, acknowledge overrun interrupt */
389  eth_drain_receiver = 1;
390  while (ns8390_poll(nic, 1))
391  /* Nothing */;
392  eth_drain_receiver = 0;
394 
395  /* leave loopback mode - no packets to be resent (see Linux driver) */
397 }
398 #endif /* INCLUDE_3C503 */
399 
400 /**************************************************************************
401 NS8390_TRANSMIT - Transmit a frame
402 **************************************************************************/
403 static void ns8390_transmit(
404  struct nic *nic,
405  const char *d, /* Destination */
406  unsigned int t, /* Type */
407  unsigned int s, /* size */
408  const char *p) /* Packet */
409 {
410 #if defined(INCLUDE_3C503) || (defined(INCLUDE_WD) && ! defined(WD_790_PIO))
411  Address eth_vmem = bus_to_virt(eth_bmem);
412 #endif
413 #ifdef INCLUDE_3C503
414  if (!(eth_flags & FLAG_PIO)) {
415  memcpy((char *)eth_vmem, d, ETH_ALEN); /* dst */
416  memcpy((char *)eth_vmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
417  *((char *)eth_vmem+12) = t>>8; /* type */
418  *((char *)eth_vmem+13) = t;
419  memcpy((char *)eth_vmem+ETH_HLEN, p, s);
420  s += ETH_HLEN;
421  while (s < ETH_ZLEN) *((char *)eth_vmem+(s++)) = 0;
422  }
423 #endif
424 
425 #ifdef INCLUDE_WD
426  if (eth_flags & FLAG_16BIT) {
427  outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
428  inb(0x84);
429  }
430 #ifndef WD_790_PIO
431  /* Memory interface */
432  if (eth_flags & FLAG_790) {
434  inb(0x84);
435  }
436  inb(0x84);
437  memcpy((char *)eth_vmem, d, ETH_ALEN); /* dst */
438  memcpy((char *)eth_vmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
439  *((char *)eth_vmem+12) = t>>8; /* type */
440  *((char *)eth_vmem+13) = t;
441  memcpy((char *)eth_vmem+ETH_HLEN, p, s);
442  s += ETH_HLEN;
443  while (s < ETH_ZLEN) *((char *)eth_vmem+(s++)) = 0;
444  if (eth_flags & FLAG_790) {
445  outb(0, eth_asic_base + WD_MSR);
446  inb(0x84);
447  }
448 #else
449  inb(0x84);
450 #endif
451 #endif
452 
453 #if defined(INCLUDE_3C503)
454  if (eth_flags & FLAG_PIO)
455 #endif
456 #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM)) || (defined(INCLUDE_WD) && defined(WD_790_PIO))
457  {
458  /* Programmed I/O */
459  unsigned short type;
460  type = (t >> 8) | (t << 8);
461  eth_pio_write( (unsigned char *) d, eth_tx_start<<8, ETH_ALEN);
463  /* bcc generates worse code without (const+const) below */
464  eth_pio_write((unsigned char *)&type, (eth_tx_start<<8)+(ETH_ALEN+ETH_ALEN), 2);
465  eth_pio_write( (unsigned char *) p, (eth_tx_start<<8)+ETH_HLEN, s);
466  s += ETH_HLEN;
467  if (s < ETH_ZLEN) s = ETH_ZLEN;
468  }
469 #endif
470 #if defined(INCLUDE_3C503)
471 #endif
472 
473 #ifdef INCLUDE_WD
474  if (eth_flags & FLAG_16BIT) {
475  outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
476  inb(0x84);
477  }
478  if (eth_flags & FLAG_790)
481  else
482 #endif
488 #ifdef INCLUDE_WD
489  if (eth_flags & FLAG_790)
492  else
493 #endif
497 }
498 
499 /**************************************************************************
500 NS8390_POLL - Wait for a frame
501 **************************************************************************/
502 static int ns8390_poll(struct nic *nic, int retrieve)
503 {
504  int ret = 0;
505  unsigned char rstat, curr, next;
506  unsigned short len, frag;
507  unsigned short pktoff;
508  unsigned char *p;
509  struct ringbuffer pkthdr;
510 
511 #ifndef INCLUDE_3C503
512  /* avoid infinite recursion: see eth_rx_overrun() */
515  return(0);
516  }
517 #endif /* INCLUDE_3C503 */
518  rstat = inb(eth_nic_base+D8390_P0_RSR);
519  if (!(rstat & D8390_RSTAT_PRX)) return(0);
521  if (next >= eth_memsize) next = eth_rx_start;
525  if (curr >= eth_memsize) curr=eth_rx_start;
526  if (curr == next) return(0);
527 
528  if ( ! retrieve ) return 1;
529 
530 #ifdef INCLUDE_WD
531  if (eth_flags & FLAG_16BIT) {
532  outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
533  inb(0x84);
534  }
535 #ifndef WD_790_PIO
536  if (eth_flags & FLAG_790) {
538  inb(0x84);
539  }
540 #endif
541  inb(0x84);
542 #endif
543  pktoff = next << 8;
544  if (eth_flags & FLAG_PIO)
545  eth_pio_read(pktoff, (unsigned char *)&pkthdr, 4);
546  else
547  memcpy(&pkthdr, bus_to_virt(eth_rmem + pktoff), 4);
548  pktoff += sizeof(pkthdr);
549  /* incoming length includes FCS so must sub 4 */
550  len = pkthdr.len - 4;
551  if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN
552  || len > ETH_FRAME_LEN) {
553  printf("Bogus packet, ignoring\n");
554  return (0);
555  }
556  else {
557  p = nic->packet;
558  nic->packetlen = len; /* available to caller */
559  frag = (eth_memsize << 8) - pktoff;
560  if (len > frag) { /* We have a wrap-around */
561  /* read first part */
562  if (eth_flags & FLAG_PIO)
563  eth_pio_read(pktoff, p, frag);
564  else
565  memcpy(p, bus_to_virt(eth_rmem + pktoff), frag);
566  pktoff = eth_rx_start << 8;
567  p += frag;
568  len -= frag;
569  }
570  /* read second part */
571  if (eth_flags & FLAG_PIO)
572  eth_pio_read(pktoff, p, len);
573  else
574  memcpy(p, bus_to_virt(eth_rmem + pktoff), len);
575  ret = 1;
576  }
577 #ifdef INCLUDE_WD
578 #ifndef WD_790_PIO
579  if (eth_flags & FLAG_790) {
580  outb(0, eth_asic_base + WD_MSR);
581  inb(0x84);
582  }
583 #endif
584  if (eth_flags & FLAG_16BIT) {
585  outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
586  inb(0x84);
587  }
588  inb(0x84);
589 #endif
590  next = pkthdr.next; /* frame number of next packet */
591  if (next == eth_rx_start)
592  next = eth_memsize;
594  return(ret);
595 }
596 
597 /**************************************************************************
598 NS8390_DISABLE - Turn off adapter
599 **************************************************************************/
600 static void ns8390_disable ( struct nic *nic ) {
601  ns8390_reset(nic);
602 }
603 
604 /**************************************************************************
605 NS8390_IRQ - Enable, Disable, or Force interrupts
606 **************************************************************************/
607 static void ns8390_irq(struct nic *nic __unused, irq_action_t action __unused)
608 {
609  switch ( action ) {
610  case DISABLE :
611  break;
612  case ENABLE :
613  break;
614  case FORCE :
615  break;
616  }
617 }
618 
620 static struct nic_operations ns8390_operations = {
622  .poll = ns8390_poll,
623  .transmit = ns8390_transmit,
624  .irq = ns8390_irq,
625 };
626 
627 /**************************************************************************
628 ETH_PROBE - Look for an adapter
629 **************************************************************************/
630 #ifdef INCLUDE_NS8390
631 static int eth_probe (struct nic *nic, struct pci_device *pci)
632 #else
633 static int eth_probe (struct dev *dev, unsigned short *probe_addrs __unused)
634 #endif
635 {
636  int i;
637 #ifdef INCLUDE_NS8390
638  unsigned short pci_probe_addrs[] = { pci->ioaddr, 0 };
639  unsigned short *probe_addrs = pci_probe_addrs;
640 #endif
642  eth_drain_receiver = 0;
643 
644  nic->irqno = 0;
645 
646 #ifdef INCLUDE_WD
647 {
648  /******************************************************************
649  Search for WD/SMC cards
650  ******************************************************************/
651  struct wd_board *brd;
652  unsigned short chksum;
653  unsigned char c;
655  eth_asic_base += 0x20) {
656  chksum = 0;
657  for (i=8; i<16; i++)
658  chksum += inb(eth_asic_base+i);
659  /* Extra checks to avoid soundcard */
660  if ((chksum & 0xFF) == 0xFF &&
661  inb(eth_asic_base+8) != 0xFF &&
662  inb(eth_asic_base+9) != 0xFF)
663  break;
664  }
666  return (0);
667  /* We've found a board */
670 
672 
673  c = inb(eth_asic_base+WD_BID); /* Get board id */
674  for (brd = wd_boards; brd->name; brd++)
675  if (brd->id == c) break;
676  if (!brd->name) {
677  printf("Unknown WD/SMC NIC type %hhX\n", c);
678  return (0); /* Unknown type */
679  }
680  eth_flags = brd->flags;
681  eth_memsize = brd->memsize;
682  eth_tx_start = 0;
684  if ((c == TYPE_WD8013EP) &&
688  }
689  if ((c & WD_SOFTCONFIG) && (!(eth_flags & FLAG_790))) {
690  eth_bmem = (0x80000 |
691  ((inb(eth_asic_base + WD_MSR) & 0x3F) << 13));
692  } else
694  if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) {
695  /* from Linux driver, 8416BT detects as 8216 sometimes */
696  unsigned int addr = inb(eth_asic_base + 0xb);
697  if (((addr >> 4) & 3) == 0) {
698  brd += 2;
699  eth_memsize = brd->memsize;
700  }
701  }
702  outb(0x80, eth_asic_base + WD_MSR); /* Reset */
703  for (i=0; i<ETH_ALEN; i++) {
705  }
706  DBG ( "\n%s base %4.4x", brd->name, eth_asic_base );
707  if (eth_flags & FLAG_790) {
708 #ifdef WD_790_PIO
709  DBG ( ", PIO mode, addr %s\n", eth_ntoa ( nic->node_addr ) );
710  eth_bmem = 0;
711  eth_flags |= FLAG_PIO; /* force PIO mode */
713 #else
714  DBG ( ", Memory %x, MAC Addr %s\n", eth_bmem, eth_ntoa ( nic->node_addr) );
715 
717  outb((inb(eth_asic_base+0x04) |
718  0x80), eth_asic_base+0x04);
719  outb(((unsigned)(eth_bmem >> 13) & 0x0F) |
720  ((unsigned)(eth_bmem >> 11) & 0x40) |
721  (inb(eth_asic_base+0x0B) & 0xB0), eth_asic_base+0x0B);
722  outb((inb(eth_asic_base+0x04) &
723  ~0x80), eth_asic_base+0x04);
724 #endif
725  } else {
726 
727  DBG (", Memory %x, MAC Addr %s\n", eth_bmem, eth_ntoa ( nic->node_addr) );
728 
729  outb(((unsigned)(eth_bmem >> 13) & 0x3F) | 0x40, eth_asic_base+WD_MSR);
730  }
731  if (eth_flags & FLAG_16BIT) {
732  if (eth_flags & FLAG_790) {
733  eth_laar = inb(eth_asic_base + WD_LAAR);
735  } else {
736  outb((eth_laar =
738 /*
739  The previous line used to be
740  WD_LAAR_M16EN | WD_LAAR_L16EN | 1));
741  jluke@deakin.edu.au reported that removing WD_LAAR_M16EN made
742  it work for WD8013s. This seems to work for my 8013 boards. I
743  don't know what is really happening. I wish I had data sheets
744  or more time to decode the Linux driver. - Ken
745 */
746  }
747  inb(0x84);
748  }
749 }
750 #endif
751 #ifdef INCLUDE_3C503
752 #ifdef T503_AUI
753  nic->flags = 1; /* aui */
754 #else
755  nic->flags = 0; /* no aui */
756 #endif
757  /******************************************************************
758  Search for 3Com 3c503 if no WD/SMC cards
759  ******************************************************************/
760  if (eth_vendor == VENDOR_NONE) {
761  int idx;
762  int iobase_reg, membase_reg;
763  static unsigned short base[] = {
764  0x300, 0x310, 0x330, 0x350,
765  0x250, 0x280, 0x2A0, 0x2E0, 0 };
766 
767  /* Loop through possible addresses checking each one */
768 
769  for (idx = 0; (eth_nic_base = base[idx]) != 0; ++idx) {
770 
772 /*
773  * Note that we use the same settings for both 8 and 16 bit cards:
774  * both have an 8K bank of memory at page 1 while only the 16 bit
775  * cards have a bank at page 0.
776  */
778  eth_tx_start = 32;
780 
781  /* Check our base address. iobase and membase should */
782  /* both have a maximum of 1 bit set or be 0. */
783 
784  iobase_reg = inb(eth_asic_base + _3COM_BCFR);
785  membase_reg = inb(eth_asic_base + _3COM_PCFR);
786 
787  if ((iobase_reg & (iobase_reg - 1)) ||
788  (membase_reg & (membase_reg - 1)))
789  continue; /* nope */
790 
791  /* Now get the shared memory address */
792 
793  eth_flags = 0;
794 
795  switch (membase_reg) {
796  case _3COM_PCFR_DC000:
797  eth_bmem = 0xdc000;
798  break;
799  case _3COM_PCFR_D8000:
800  eth_bmem = 0xd8000;
801  break;
802  case _3COM_PCFR_CC000:
803  eth_bmem = 0xcc000;
804  break;
805  case _3COM_PCFR_C8000:
806  eth_bmem = 0xc8000;
807  break;
808  case _3COM_PCFR_PIO:
809  eth_flags |= FLAG_PIO;
810  eth_bmem = 0;
811  break;
812  default:
813  continue; /* nope */
814  }
815  break;
816  }
817 
818  if (base[idx] == 0) /* not found */
819  return (0);
820 #ifndef T503_SHMEM
821  eth_flags |= FLAG_PIO; /* force PIO mode */
822  eth_bmem = 0;
823 #endif
825 
826 
827  /* Need this to make ns8390_poll() happy. */
828 
829  eth_rmem = eth_bmem - 0x2000;
830 
831  /* Reset NIC and ASIC */
832 
835 
836  /* Get our ethernet address */
837 
840  DBG ( "\n3Com 3c503 base %4.4x, ", eth_nic_base );
841  if (eth_flags & FLAG_PIO)
842  DBG ( "PIO mode" );
843  else
844  DBG ( "memory %4.4x", eth_bmem );
845  for (i=0; i<ETH_ALEN; i++) {
846  nic->node_addr[i] = inb(eth_nic_base+i);
847  }
848  DBG ( ", %s, MAC Addr %s\n", nic->flags ? "AUI" : "internal xcvr",
849  eth_ntoa ( nic->node_addr ) );
850 
852  /*
853  * Initialize GA configuration register. Set bank and enable shared
854  * mem. We always use bank 1. Disable interrupts.
855  */
858 
859  outb(0xff, eth_asic_base + _3COM_VPTR2);
860  outb(0xff, eth_asic_base + _3COM_VPTR1);
861  outb(0x00, eth_asic_base + _3COM_VPTR0);
862  /*
863  * Clear memory and verify that it worked (we use only 8K)
864  */
865 
866  if (!(eth_flags & FLAG_PIO)) {
867  memset(bus_to_virt(eth_bmem), 0, 0x2000);
868  for(i = 0; i < 0x2000; ++i)
869  if (*((char *)(bus_to_virt(eth_bmem+i)))) {
870  printf ("Failed to clear 3c503 shared mem.\n");
871  return (0);
872  }
873  }
874  /*
875  * Initialize GA page/start/stop registers.
876  */
879  }
880 #endif
881 #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
882 {
883  /******************************************************************
884  Search for NE1000/2000 if no WD/SMC or 3com cards
885  ******************************************************************/
886  unsigned char c;
887  if (eth_vendor == VENDOR_NONE) {
888  unsigned char romdata[16];
889  unsigned char testbuf[32];
890  int idx;
891  static unsigned char test[] = "NE*000 memory";
892  static unsigned short base[] = {
893 #ifdef NE_SCAN
894  NE_SCAN,
895 #endif
896  0 };
897  /* if no addresses supplied, fall back on defaults */
898  if (probe_addrs == NULL || probe_addrs[0] == 0)
899  probe_addrs = base;
900  eth_bmem = 0; /* No shared memory */
901  for (idx = 0; (eth_nic_base = probe_addrs[idx]) != 0; ++idx) {
905  eth_tx_start = 32;
909  (void) inb(0x84);
916 #ifdef NS8390_FORCE_16BIT
917  eth_flags |= FLAG_16BIT; /* force 16-bit mode */
918 #endif
919 
920  eth_pio_write( (unsigned char *) test, 8192, sizeof(test));
921  eth_pio_read(8192, testbuf, sizeof(test));
922  if (!memcmp(test, testbuf, sizeof(test)))
923  break;
926  eth_tx_start = 64;
932  eth_pio_write( (unsigned char *) test, 16384, sizeof(test));
933  eth_pio_read(16384, testbuf, sizeof(test));
934  if (!memcmp(testbuf, test, sizeof(test)))
935  break;
936  }
937  if (eth_nic_base == 0)
938  return (0);
939  if (eth_nic_base > ISA_MAX_ADDR) /* PCI probably */
942  eth_pio_read(0, romdata, sizeof(romdata));
943  for (i=0; i<ETH_ALEN; i++) {
944  nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)];
945  }
947  DBG ( "\nNE%c000 base %4.4x, MAC Addr %s\n",
948  (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base,
949  eth_ntoa ( nic->node_addr ) );
950  }
951 }
952 #endif
953  if (eth_vendor == VENDOR_NONE)
954  return(0);
955  if (eth_vendor != VENDOR_3COM)
956  eth_rmem = eth_bmem;
957  ns8390_reset(nic);
959 
960  /* Based on PnP ISA map */
961 #ifdef INCLUDE_WD
962  dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
963  dev->devid.device_id = htons(0x812a);
964 #endif
965 #ifdef INCLUDE_3C503
966  dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
967  dev->devid.device_id = htons(0x80f3);
968 #endif
969 #ifdef INCLUDE_NE
970  dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
971  dev->devid.device_id = htons(0x80d6);
972 #endif
973  return 1;
974 }
975 
976 #ifdef INCLUDE_WD
977 struct isa_driver wd_driver __isa_driver = {
978  .type = NIC_DRIVER,
979  .name = "WD",
980  .probe = wd_probe,
981  .ioaddrs = 0,
982 };
983 ISA_ROM("wd","WD8003/8013, SMC8216/8416, SMC 83c790 (EtherEZ)");
984 #endif
985 
986 #ifdef INCLUDE_3C503
987 struct isa_driver t503_driver __isa_driver = {
988  .type = NIC_DRIVER,
989  .name = "3C503",
990  .probe = t503_probe,
991  .ioaddrs = 0,
992 };
993 ISA_ROM("3c503","3Com503, Etherlink II[/16]");
994 #endif
995 
996 #ifdef INCLUDE_NE
997 struct isa_driver ne_driver __isa_driver = {
998  .type = NIC_DRIVER,
999  .name = "NE*000",
1000  .probe = ne_probe,
1001  .ioaddrs = 0,
1002 };
1003 ISA_ROM("ne","NE1000/2000 and clones");
1004 #endif
1005 
1006 #ifdef INCLUDE_NS8390
1007 static struct pci_device_id nepci_nics[] = {
1008 /* A few NE2000 PCI clones, list not exhaustive */
1009 PCI_ROM(0x10ec, 0x8029, "rtl8029", "Realtek 8029", 0),
1010 PCI_ROM(0x1186, 0x0300, "dlink-528", "D-Link DE-528", 0),
1011 PCI_ROM(0x1050, 0x0940, "winbond940", "Winbond NE2000-PCI", 0), /* Winbond 86C940 / 89C940 */
1012 PCI_ROM(0x1050, 0x5a5a, "winbond940f", "Winbond W89c940F", 0), /* Winbond 89C940F */
1013 PCI_ROM(0x11f6, 0x1401, "compexrl2000", "Compex ReadyLink 2000", 0),
1014 PCI_ROM(0x8e2e, 0x3000, "ktiet32p2", "KTI ET32P2", 0),
1015 PCI_ROM(0x4a14, 0x5000, "nv5000sc", "NetVin NV5000SC", 0),
1016 PCI_ROM(0x12c3, 0x0058, "holtek80232", "Holtek HT80232", 0),
1017 PCI_ROM(0x12c3, 0x5598, "holtek80229", "Holtek HT80229", 0),
1018 PCI_ROM(0x10bd, 0x0e34, "surecom-ne34", "Surecom NE34", 0),
1019 PCI_ROM(0x1106, 0x0926, "via86c926", "Via 86c926", 0),
1020 };
1021 
1022 PCI_DRIVER ( nepci_driver, nepci_nics, PCI_NO_CLASS );
1023 
1024 DRIVER ( "NE2000/PCI", nic_driver, pci_driver, nepci_driver,
1025  nepci_probe, ns8390_disable );
1026 
1027 #endif /* INCLUDE_NS8390 */
1028 
1029 #endif
1030 
1031 /*
1032  * Local variables:
1033  * c-basic-offset: 8
1034  * c-indent-level: 8
1035  * tab-width: 8
1036  * End:
1037  */
#define D8390_P0_RCR
Definition: ns8390.h:182
#define _3COM_PCFR_CC000
Definition: ns8390.h:107
unsigned char irqno
Definition: nic.h:56
static unsigned char eth_memsize
Definition: ns8390.c:56
#define VENDOR_3COM
Definition: ns8390.h:14
static Address eth_bmem
Definition: ns8390.c:57
#define _3COM_STREG
Definition: ns8390.h:128
uint32_t c
Definition: md4.c:30
Definition: nic.h:35
static struct pci_device_id nepci_nics[]
Definition: ns8390.c:1007
#define _3COM_DALSB
Definition: ns8390.h:149
#define _3COM_CR_RST
Definition: ns8390.h:111
#define _3COM_GACFR_RSEL
Definition: ns8390.h:123
const char * name
Definition: ath9k_hw.c:1984
int printf(const char *fmt,...)
Write a formatted string to the console.
Definition: vsprintf.c:464
uint16_t inw(volatile uint16_t *io_addr)
Read 16-bit word from I/O-mapped device.
#define TYPE_WD8013WC
Definition: ns8390.h:69
#define D8390_P0_IMR
Definition: ns8390.h:185
#define WD_MSR
Definition: ns8390.h:39
#define VENDOR_NOVELL
Definition: ns8390.h:13
A PCI driver.
Definition: pci.h:224
#define D8390_DCR_FT1
Definition: ns8390.h:208
int flags
Definition: nic.h:51
uint32_t next
Next descriptor address.
Definition: myson.h:18
#define outw(data, io_addr)
Definition: io.h:319
unsigned long ioaddr
I/O address.
Definition: pci.h:200
#define FLAG_PIO
Definition: ns8390.h:16
#define TYPE_WD8013EPC
Definition: ns8390.h:70
#define WD_NIC_ADDR
Definition: ns8390.h:34
#define _3COM_VPTR0
Definition: ns8390.h:152
#define MEM_16384
Definition: ns8390.h:21
#define _3COM_PCFR_PIO
Definition: ns8390.h:105
#define ASIC_PIO
Definition: ns8390.c:123
static unsigned short eth_asic_base
Definition: ns8390.c:55
#define D8390_COMMAND_PS1
Definition: ns8390.h:197
uint8_t type
Type.
Definition: ena.h:16
#define _3COM_CR
Definition: ns8390.h:110
#define D8390_P0_RSAR1
Definition: ns8390.h:178
#define TYPE_SMC8416C
Definition: ns8390.h:74
#define FLAG_790
Definition: ns8390.h:18
#define _3COM_CR_XSEL
Definition: ns8390.h:112
#define WD_HIGH_BASE
Definition: ns8390.h:30
#define _3COM_DAMSB
Definition: ns8390.h:148
#define TYPE_SMC8013EBP
Definition: ns8390.h:75
PCI_DRIVER(nepci_driver, nepci_nics, PCI_NO_CLASS)
#define TYPE_WD8013W
Definition: ns8390.h:67
#define _3COM_STREG_DPRDY
Definition: ns8390.h:134
#define NE_RESET
Definition: ns8390.h:160
#define MEM_8192
Definition: ns8390.h:20
static void eth_rx_overrun(struct nic *nic)
Definition: ns8390.c:353
#define D8390_RCR_MON
Definition: ns8390.h:206
#define WD_LAAR_M16EN
Definition: ns8390.h:55
#define D8390_P0_DCR
Definition: ns8390.h:184
int dummy_connect(struct nic *nic __unused)
Definition: legacy.c:151
static unsigned char eth_vendor
Definition: ns8390.c:51
static __always_inline void * bus_to_virt(unsigned long bus_addr)
Convert bus address to a virtual address.
Definition: io.h:195
static int ns8390_poll(struct nic *nic, int retrieve)
Definition: ns8390.c:502
static struct nic_operations ns8390_operations
Definition: ns8390.c:619
#define FLAG_16BIT
Definition: ns8390.h:17
#define _3COM_PCFR_DC000
Definition: ns8390.h:109
static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt)
Definition: ns8390.c:131
#define TYPE_SMC8216T
Definition: ns8390.h:71
#define _3COM_PSPR
Definition: ns8390.h:93
#define D8390_COMMAND_RD0
Definition: ns8390.h:201
#define _3COM_GACFR_NIM
Definition: ns8390.h:127
void * memcpy(void *dest, const void *src, size_t len) __nonnull
unsigned int ioaddr
Definition: nic.h:55
#define WD_ICR_16BIT
Definition: ns8390.h:50
#define WD_SOFTCONFIG
Definition: ns8390.h:57
#define _3COM_PCFR_C8000
Definition: ns8390.h:106
#define WD_LAAR
Definition: ns8390.h:44
static void ns8390_transmit(struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p)
Definition: ns8390.c:403
#define ETH_HLEN
Definition: if_ether.h:9
#define WD_BID
Definition: ns8390.h:48
Ethernet protocol.
#define TYPE_WD8013EBT
Definition: ns8390.h:64
static unsigned char eth_flags
Definition: ns8390.c:51
#define ETH_FRAME_LEN
Definition: if_ether.h:11
#define NE_ASIC_OFFSET
Definition: ns8390.h:159
#define _3COM_CR_DDIR
Definition: ns8390.h:117
#define D8390_COMMAND_RD1
Definition: ns8390.h:200
#define GENERIC_ISAPNP_VENDOR
Definition: isa_ids.h:38
irq_action_t
Definition: nic.h:34
#define D8390_DCR_LS
Definition: ns8390.h:209
#define _3COM_GACFR_TCM
Definition: ns8390.h:126
#define _3COM_GACFR
Definition: ns8390.h:119
#define _3COM_VPTR1
Definition: ns8390.h:151
#define D8390_ISR_OVW
Definition: ns8390.h:216
#define TYPE_WD8003EB
Definition: ns8390.h:66
#define WD_DEFAULT_MEM
Definition: ns8390.h:32
uint8_t id
Request identifier.
Definition: ena.h:12
static __always_inline void off_t userptr_t src
Definition: efi_uaccess.h:66
unsigned int packetlen
Definition: nic.h:54
#define D8390_P0_TCR
Definition: ns8390.h:183
FILE_LICENCE(BSD2)
#define _3COM_VPTR2
Definition: ns8390.h:150
#define D8390_P0_RSR
Definition: ns8390.h:181
#define D8390_P1_CURR
Definition: ns8390.h:193
#define _3COM_PCFR
Definition: ns8390.h:104
PCI bus.
static void eth_pio_write(const unsigned char *src, unsigned int dst, unsigned int cnt)
Definition: ns8390.c:178
A PCI device.
Definition: pci.h:187
const char * eth_ntoa(const void *ll_addr)
Transcribe Ethernet address.
Definition: ethernet.c:175
#define eth_probe
Definition: ns8390.c:113
static unsigned short eth_nic_base
Definition: ns8390.c:55
u32 addr
Definition: sky2.h:8
static void ns8390_reset(struct nic *nic)
Definition: ns8390.c:272
#define D8390_ISR_RDC
Definition: ns8390.h:218
#define D8390_COMMAND_PS0
Definition: ns8390.h:196
static void ns8390_disable(struct nic *nic)
Definition: ns8390.c:600
#define _3COM_ASIC_OFFSET
Definition: ns8390.h:89
#define COMPEX_RL2000_TRIES
Definition: ns8390.h:163
uint8_t inb(volatile uint8_t *io_addr)
Read byte from I/O-mapped device.
#define ETH_ALEN
Definition: if_ether.h:8
#define ETH_ZLEN
Definition: if_ether.h:10
A PCI device ID list entry.
Definition: pci.h:151
unsigned long Address
Definition: etherboot.h:21
Definition: nic.h:37
#define WD_LAR
Definition: ns8390.h:47
#define D8390_P0_RBCR0
Definition: ns8390.h:179
Definition: nic.h:49
#define __isa_driver
Declare an ISA driver.
Definition: isa.h:65
#define D8390_P1_PAR0
Definition: ns8390.h:187
#define ISA_ROM(IMAGE, DESCRIPTION)
Definition: isa.h:92
#define INCLUDE_NS8390
Definition: ns8390.c:38
#define _3COM_PCFR_D8000
Definition: ns8390.h:108
#define D8390_P0_COMMAND
Definition: ns8390.h:168
uint16_t base
Base address.
Definition: edd.h:14
#define _3COM_BCFR
Definition: ns8390.h:95
#define _3COM_GACFR_MBS0
Definition: ns8390.h:120
#define D8390_COMMAND_RD2
Definition: ns8390.h:199
#define D8390_COMMAND_TXP
Definition: ns8390.h:202
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
Definition: nic.h:36
unsigned char * packet
Definition: nic.h:53
#define VENDOR_NONE
Definition: ns8390.h:11
unsigned char * node_addr
Definition: nic.h:52
DRIVER("NE2000/PCI", nic_driver, pci_driver, nepci_driver, nepci_probe, ns8390_disable)
#define outb(data, io_addr)
Definition: io.h:309
#define VENDOR_WD
Definition: ns8390.h:12
#define D8390_P0_PSTOP
Definition: ns8390.h:170
#define D8390_P0_TBCR0
Definition: ns8390.h:174
#define D8390_P0_RBCR1
Definition: ns8390.h:180
uint32_t len
Length.
Definition: ena.h:14
#define ISA_MAX_ADDR
Definition: ns8390.h:24
#define TYPE_WD8013EP
Definition: ns8390.h:68
#define D8390_P1_MAR0
Definition: ns8390.h:194
#define _3COM_CR_EALO
Definition: ns8390.h:113
#define D8390_COMMAND_STP
Definition: ns8390.h:204
#define WD_LOW_BASE
Definition: ns8390.h:29
static unsigned char eth_rx_start
Definition: ns8390.c:56
static void ns8390_irq(struct nic *nic __unused, irq_action_t action __unused)
Definition: ns8390.c:607
#define MEM_32768
Definition: ns8390.h:22
static Address eth_rmem
Definition: ns8390.c:57
uint32_t d
Definition: md4.c:31
#define _3COM_PSTR
Definition: ns8390.h:92
#define D8390_P0_ISR
Definition: ns8390.h:176
#define D8390_P0_TPSR
Definition: ns8390.h:173
#define D8390_RSTAT_PRX
Definition: ns8390.h:221
#define WD_LAAR_L16EN
Definition: ns8390.h:54
#define D8390_TXBUF_SIZE
Definition: ns8390.h:226
#define D8390_P0_BOUND
Definition: ns8390.h:171
An ISA driver.
Definition: isa.h:34
#define D8390_P0_PSTART
Definition: ns8390.h:169
#define WD_GP2
Definition: ns8390.h:46
static int ne_probe(struct nic *nic, struct isa_device *isa)
Definition: ne2k_isa.c:135
#define TYPE_SMC8216C
Definition: ns8390.h:72
unsigned long currticks(void)
Get current system time in ticks.
Definition: timer.c:42
#define D8390_P0_RSAR0
Definition: ns8390.h:177
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
struct nic_operations * nic_op
Definition: nic.h:50
#define TYPE_WD8003S
Definition: ns8390.h:62
static unsigned char eth_tx_start
Definition: ns8390.c:56
#define _3COM_CR_START
Definition: ns8390.h:118
#define TYPE_SMC8416T
Definition: ns8390.h:73
static unsigned char eth_drain_receiver
Definition: ns8390.c:58
static void enable_multicast(unsigned short eth_nic_base)
Definition: ns8390.c:252
int(* connect)(struct nic *)
Definition: nic.h:63
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition: string.c:98
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362
#define TYPE_WD8003W
Definition: ns8390.h:65
#define WD_ICR
Definition: ns8390.h:40
#define PCI_ROM(_vendor, _device, _name, _description, _data)
Definition: pci.h:283
#define htons(value)
Definition: byteswap.h:135
#define TYPE_WD8003E
Definition: ns8390.h:63
#define D8390_P0_TBCR1
Definition: ns8390.h:175
static int test
Definition: epic100.c:73
#define WD_MSR_MENB
Definition: ns8390.h:52
#define D8390_DCR_WTS
Definition: ns8390.h:210
#define D8390_COMMAND_STA
Definition: ns8390.h:203
void * memset(void *dest, int character, size_t len) __nonnull
uint8_t flags
Flags.
Definition: ena.h:18