123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035 |
- /**************************************************************************
- ETHERBOOT - BOOTP/TFTP Bootstrap Program
-
- Author: Martin Renters
- Date: May/94
-
- This code is based heavily on David Greenman's if_ed.c driver
-
- Copyright (C) 1993-1994, David Greenman, Martin Renters.
- This software may be used, modified, copied, distributed, and sold, in
- both source and binary form provided that the above copyright and these
- terms are retained. Under no circumstances are the authors responsible for
- the proper functioning of this software, nor do the authors assume any
- responsibility for damages incurred with its use.
-
- Multicast support added by Timothy Legge (timlegge@users.sourceforge.net) 09/28/2003
- Relocation support added by Ken Yap (ken_yap@users.sourceforge.net) 28/12/02
- 3c503 support added by Bill Paul (wpaul@ctr.columbia.edu) on 11/15/94
- SMC8416 support added by Bill Paul (wpaul@ctr.columbia.edu) on 12/25/94
- 3c503 PIO support added by Jim Hague (jim.hague@acm.org) on 2/17/98
- RX overrun by Klaus Espenlaub (espenlaub@informatik.uni-ulm.de) on 3/10/99
- parts taken from the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
- SMC8416 PIO support added by Andrew Bettison (andrewb@zip.com.au) on 4/3/02
- based on the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
-
- **************************************************************************/
-
- /* #warning "ns8390.c: FIXME: split ISA and PCI, clean up" */
-
- #if 1
-
- #if !defined(INCLUDE_NS8390) && !defined(INCLUDE_WD) && \
- !defined(INCLUDE_NE) && !defined(INCLUDE_3C503)
- /* The driver named ns8390 is the PCI driver, often called
- "PCI ne2000 clones". */
- # define INCLUDE_NS8390 1
- #endif
-
- #include "etherboot.h"
- #include "nic.h"
- #include "ns8390.h"
- #include <gpxe/ethernet.h>
- #ifdef INCLUDE_NS8390
- #include <gpxe/pci.h>
- #else
- #include <gpxe/isa.h>
- #endif
-
- static unsigned char eth_vendor, eth_flags;
- #ifdef INCLUDE_WD
- static unsigned char eth_laar;
- #endif
- static unsigned short eth_nic_base, eth_asic_base;
- static unsigned char eth_memsize, eth_rx_start, eth_tx_start;
- static Address eth_bmem, eth_rmem;
- static unsigned char eth_drain_receiver;
-
- #ifdef INCLUDE_WD
- static struct wd_board {
- const char *name;
- char id;
- char flags;
- char memsize;
- } wd_boards[] = {
- {"WD8003S", TYPE_WD8003S, 0, MEM_8192},
- {"WD8003E", TYPE_WD8003E, 0, MEM_8192},
- {"WD8013EBT", TYPE_WD8013EBT, FLAG_16BIT, MEM_16384},
- {"WD8003W", TYPE_WD8003W, 0, MEM_8192},
- {"WD8003EB", TYPE_WD8003EB, 0, MEM_8192},
- {"WD8013W", TYPE_WD8013W, FLAG_16BIT, MEM_16384},
- {"WD8003EP/WD8013EP",
- TYPE_WD8013EP, 0, MEM_8192},
- {"WD8013WC", TYPE_WD8013WC, FLAG_16BIT, MEM_16384},
- {"WD8013EPC", TYPE_WD8013EPC, FLAG_16BIT, MEM_16384},
- {"SMC8216T", TYPE_SMC8216T, FLAG_16BIT | FLAG_790, MEM_16384},
- {"SMC8216C", TYPE_SMC8216C, FLAG_16BIT | FLAG_790, MEM_16384},
- {"SMC8416T", TYPE_SMC8416T, FLAG_16BIT | FLAG_790, MEM_8192},
- {"SMC8416C/BT", TYPE_SMC8416C, FLAG_16BIT | FLAG_790, MEM_8192},
- {"SMC8013EBP", TYPE_SMC8013EBP,FLAG_16BIT, MEM_16384},
- {NULL, 0, 0, 0}
- };
- #endif
-
- #ifdef INCLUDE_3C503
- static unsigned char t503_output; /* AUI or internal xcvr (Thinnet) */
- #endif
-
- #if defined(INCLUDE_WD)
- #define ASIC_PIO WD_IAR
- #define eth_probe wd_probe
- #if defined(INCLUDE_3C503) || defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
- Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
- #endif
- #endif
-
- #if defined(INCLUDE_3C503)
- #define eth_probe t503_probe
- #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || defined(INCLUDE_WD)
- Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
- #endif
- #endif
-
- #if defined(INCLUDE_NE)
- #define eth_probe ne_probe
- #if defined(INCLUDE_NS8390) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
- Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
- #endif
- #endif
-
- #if defined(INCLUDE_NS8390)
- #define eth_probe nepci_probe
- #if defined(INCLUDE_NE) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
- Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
- #endif
- #endif
-
- #if defined(INCLUDE_3C503)
- #define ASIC_PIO _3COM_RFMSB
- #else
- #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
- #define ASIC_PIO NE_DATA
- #endif
- #endif
-
- #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM)) || (defined(INCLUDE_WD) && defined(WD_790_PIO))
- /**************************************************************************
- ETH_PIO_READ - Read a frame via Programmed I/O
- **************************************************************************/
- static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt)
- {
- #ifdef INCLUDE_WD
- outb(src & 0xff, eth_asic_base + WD_GP2);
- outb(src >> 8, eth_asic_base + WD_GP2);
- #else
- outb(D8390_COMMAND_RD2 |
- D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
- outb(cnt, eth_nic_base + D8390_P0_RBCR0);
- outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
- outb(src, eth_nic_base + D8390_P0_RSAR0);
- outb(src>>8, eth_nic_base + D8390_P0_RSAR1);
- outb(D8390_COMMAND_RD0 |
- D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
-
- #ifdef INCLUDE_3C503
- outb(src & 0xff, eth_asic_base + _3COM_DALSB);
- outb(src >> 8, eth_asic_base + _3COM_DAMSB);
- outb(t503_output | _3COM_CR_START, eth_asic_base + _3COM_CR);
- #endif
- #endif
-
- if (eth_flags & FLAG_16BIT)
- cnt = (cnt + 1) >> 1;
-
- while(cnt--) {
- #ifdef INCLUDE_3C503
- while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0)
- ;
- #endif
-
- if (eth_flags & FLAG_16BIT) {
- *((unsigned short *)dst) = inw(eth_asic_base + ASIC_PIO);
- dst += 2;
- }
- else
- *(dst++) = inb(eth_asic_base + ASIC_PIO);
- }
-
- #ifdef INCLUDE_3C503
- outb(t503_output, eth_asic_base + _3COM_CR);
- #endif
- }
-
- /**************************************************************************
- ETH_PIO_WRITE - Write a frame via Programmed I/O
- **************************************************************************/
- static void eth_pio_write(const unsigned char *src, unsigned int dst, unsigned int cnt)
- {
- #ifdef COMPEX_RL2000_FIX
- unsigned int x;
- #endif /* COMPEX_RL2000_FIX */
- #ifdef INCLUDE_WD
- outb(dst & 0xff, eth_asic_base + WD_GP2);
- outb(dst >> 8, eth_asic_base + WD_GP2);
- #else
- outb(D8390_COMMAND_RD2 |
- D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
- outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
- outb(cnt, eth_nic_base + D8390_P0_RBCR0);
- outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
- outb(dst, eth_nic_base + D8390_P0_RSAR0);
- outb(dst>>8, eth_nic_base + D8390_P0_RSAR1);
- outb(D8390_COMMAND_RD1 |
- D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
-
- #ifdef INCLUDE_3C503
- outb(dst & 0xff, eth_asic_base + _3COM_DALSB);
- outb(dst >> 8, eth_asic_base + _3COM_DAMSB);
-
- outb(t503_output | _3COM_CR_DDIR | _3COM_CR_START, eth_asic_base + _3COM_CR);
- #endif
- #endif
-
- if (eth_flags & FLAG_16BIT)
- cnt = (cnt + 1) >> 1;
-
- while(cnt--)
- {
- #ifdef INCLUDE_3C503
- while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0)
- ;
- #endif
-
- if (eth_flags & FLAG_16BIT) {
- outw(*((unsigned short *)src), eth_asic_base + ASIC_PIO);
- src += 2;
- }
- else
- outb(*(src++), eth_asic_base + ASIC_PIO);
- }
-
- #ifdef INCLUDE_3C503
- outb(t503_output, eth_asic_base + _3COM_CR);
- #else
- #ifdef COMPEX_RL2000_FIX
- for (x = 0;
- x < COMPEX_RL2000_TRIES &&
- (inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
- != D8390_ISR_RDC;
- ++x);
- if (x >= COMPEX_RL2000_TRIES)
- printf("Warning: Compex RL2000 aborted wait!\n");
- #endif /* COMPEX_RL2000_FIX */
- #ifndef INCLUDE_WD
- while((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
- != D8390_ISR_RDC);
- #endif
- #endif
- }
- #else
- /**************************************************************************
- ETH_PIO_READ - Dummy routine when NE2000 not compiled in
- **************************************************************************/
- static void eth_pio_read(unsigned int src __unused, unsigned char *dst __unused, unsigned int cnt __unused) {}
- #endif
-
-
- /**************************************************************************
- enable_multycast - Enable Multicast
- **************************************************************************/
- static void enable_multicast(unsigned short eth_nic_base)
- {
- unsigned char mcfilter[8];
- int i;
- memset(mcfilter, 0xFF, 8);
- outb(4, eth_nic_base+D8390_P0_RCR);
- outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1, eth_nic_base + D8390_P0_COMMAND);
- for(i=0;i<8;i++)
- {
- outb(mcfilter[i], eth_nic_base + 8 + i);
- if(inb(eth_nic_base + 8 + i)!=mcfilter[i])
- printf("Error SMC 83C690 Multicast filter read/write mishap %d\n",i);
- }
- outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0, eth_nic_base + D8390_P0_COMMAND);
- outb(4 | 0x08, eth_nic_base+D8390_P0_RCR);
- }
-
- /**************************************************************************
- NS8390_RESET - Reset adapter
- **************************************************************************/
- static void ns8390_reset(struct nic *nic)
- {
- int i;
-
- eth_drain_receiver = 0;
- #ifdef INCLUDE_WD
- if (eth_flags & FLAG_790)
- outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
- else
- #endif
- outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
- D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
- if (eth_flags & FLAG_16BIT)
- outb(0x49, eth_nic_base+D8390_P0_DCR);
- else
- outb(0x48, eth_nic_base+D8390_P0_DCR);
- outb(0, eth_nic_base+D8390_P0_RBCR0);
- outb(0, eth_nic_base+D8390_P0_RBCR1);
- outb(0x20, eth_nic_base+D8390_P0_RCR); /* monitor mode */
- outb(2, eth_nic_base+D8390_P0_TCR);
- outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
- outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART);
- #ifdef INCLUDE_WD
- if (eth_flags & FLAG_790) {
- #ifdef WD_790_PIO
- outb(0x10, eth_asic_base + 0x06); /* disable interrupts, enable PIO */
- outb(0x01, eth_nic_base + 0x09); /* enable ring read auto-wrap */
- #else
- outb(0, eth_nic_base + 0x09);
- #endif
- }
- #endif
- outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP);
- outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND);
- outb(0xFF, eth_nic_base+D8390_P0_ISR);
- outb(0, eth_nic_base+D8390_P0_IMR);
- #ifdef INCLUDE_WD
- if (eth_flags & FLAG_790)
- outb(D8390_COMMAND_PS1 |
- D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
- else
- #endif
- outb(D8390_COMMAND_PS1 |
- D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
- for (i=0; i<ETH_ALEN; i++)
- outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i);
- for (i=0; i<ETH_ALEN; i++)
- outb(0xFF, eth_nic_base+D8390_P1_MAR0+i);
- outb(eth_rx_start, eth_nic_base+D8390_P1_CURR);
- #ifdef INCLUDE_WD
- if (eth_flags & FLAG_790)
- outb(D8390_COMMAND_PS0 |
- D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
- else
- #endif
- outb(D8390_COMMAND_PS0 |
- D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
- outb(0xFF, eth_nic_base+D8390_P0_ISR);
- outb(0, eth_nic_base+D8390_P0_TCR); /* transmitter on */
- outb(4, eth_nic_base+D8390_P0_RCR); /* allow rx broadcast frames */
-
- enable_multicast(eth_nic_base);
-
- #ifdef INCLUDE_3C503
- /*
- * No way to tell whether or not we're supposed to use
- * the 3Com's transceiver unless the user tells us.
- * 'flags' should have some compile time default value
- * which can be changed from the command menu.
- */
- t503_output = (nic->flags) ? 0 : _3COM_CR_XSEL;
- outb(t503_output, eth_asic_base + _3COM_CR);
- #endif
- }
-
- static int ns8390_poll(struct nic *nic, int retrieve);
-
- #ifndef INCLUDE_3C503
- /**************************************************************************
- ETH_RX_OVERRUN - Bring adapter back to work after an RX overrun
- **************************************************************************/
- static void eth_rx_overrun(struct nic *nic)
- {
- int start_time;
-
- #ifdef INCLUDE_WD
- if (eth_flags & FLAG_790)
- outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
- else
- #endif
- outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
- D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
-
- /* wait for at least 1.6ms - we wait one timer tick */
- start_time = currticks();
- while (currticks() - start_time <= 1)
- /* Nothing */;
-
- outb(0, eth_nic_base+D8390_P0_RBCR0); /* reset byte counter */
- outb(0, eth_nic_base+D8390_P0_RBCR1);
-
- /*
- * Linux driver checks for interrupted TX here. This is not necessary,
- * because the transmit routine waits until the frame is sent.
- */
-
- /* enter loopback mode and restart NIC */
- outb(2, eth_nic_base+D8390_P0_TCR);
- #ifdef INCLUDE_WD
- if (eth_flags & FLAG_790)
- outb(D8390_COMMAND_PS0 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
- else
- #endif
- outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
- D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
-
- /* clear the RX ring, acknowledge overrun interrupt */
- eth_drain_receiver = 1;
- while (ns8390_poll(nic, 1))
- /* Nothing */;
- eth_drain_receiver = 0;
- outb(D8390_ISR_OVW, eth_nic_base+D8390_P0_ISR);
-
- /* leave loopback mode - no packets to be resent (see Linux driver) */
- outb(0, eth_nic_base+D8390_P0_TCR);
- }
- #endif /* INCLUDE_3C503 */
-
- /**************************************************************************
- NS8390_TRANSMIT - Transmit a frame
- **************************************************************************/
- static void ns8390_transmit(
- struct nic *nic,
- const char *d, /* Destination */
- unsigned int t, /* Type */
- unsigned int s, /* size */
- const char *p) /* Packet */
- {
- #if defined(INCLUDE_3C503) || (defined(INCLUDE_WD) && ! defined(WD_790_PIO))
- Address eth_vmem = bus_to_virt(eth_bmem);
- #endif
- #ifdef INCLUDE_3C503
- if (!(eth_flags & FLAG_PIO)) {
- memcpy((char *)eth_vmem, d, ETH_ALEN); /* dst */
- memcpy((char *)eth_vmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
- *((char *)eth_vmem+12) = t>>8; /* type */
- *((char *)eth_vmem+13) = t;
- memcpy((char *)eth_vmem+ETH_HLEN, p, s);
- s += ETH_HLEN;
- while (s < ETH_ZLEN) *((char *)eth_vmem+(s++)) = 0;
- }
- #endif
-
- #ifdef INCLUDE_WD
- if (eth_flags & FLAG_16BIT) {
- outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
- inb(0x84);
- }
- #ifndef WD_790_PIO
- /* Memory interface */
- if (eth_flags & FLAG_790) {
- outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
- inb(0x84);
- }
- inb(0x84);
- memcpy((char *)eth_vmem, d, ETH_ALEN); /* dst */
- memcpy((char *)eth_vmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
- *((char *)eth_vmem+12) = t>>8; /* type */
- *((char *)eth_vmem+13) = t;
- memcpy((char *)eth_vmem+ETH_HLEN, p, s);
- s += ETH_HLEN;
- while (s < ETH_ZLEN) *((char *)eth_vmem+(s++)) = 0;
- if (eth_flags & FLAG_790) {
- outb(0, eth_asic_base + WD_MSR);
- inb(0x84);
- }
- #else
- inb(0x84);
- #endif
- #endif
-
- #if defined(INCLUDE_3C503)
- if (eth_flags & FLAG_PIO)
- #endif
- #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM)) || (defined(INCLUDE_WD) && defined(WD_790_PIO))
- {
- /* Programmed I/O */
- unsigned short type;
- type = (t >> 8) | (t << 8);
- eth_pio_write( (unsigned char *) d, eth_tx_start<<8, ETH_ALEN);
- eth_pio_write(nic->node_addr, (eth_tx_start<<8)+ETH_ALEN, ETH_ALEN);
- /* bcc generates worse code without (const+const) below */
- eth_pio_write((unsigned char *)&type, (eth_tx_start<<8)+(ETH_ALEN+ETH_ALEN), 2);
- eth_pio_write( (unsigned char *) p, (eth_tx_start<<8)+ETH_HLEN, s);
- s += ETH_HLEN;
- if (s < ETH_ZLEN) s = ETH_ZLEN;
- }
- #endif
- #if defined(INCLUDE_3C503)
- #endif
-
- #ifdef INCLUDE_WD
- if (eth_flags & FLAG_16BIT) {
- outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
- inb(0x84);
- }
- if (eth_flags & FLAG_790)
- outb(D8390_COMMAND_PS0 |
- D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
- else
- #endif
- outb(D8390_COMMAND_PS0 |
- D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
- outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
- outb(s, eth_nic_base+D8390_P0_TBCR0);
- outb(s>>8, eth_nic_base+D8390_P0_TBCR1);
- #ifdef INCLUDE_WD
- if (eth_flags & FLAG_790)
- outb(D8390_COMMAND_PS0 |
- D8390_COMMAND_TXP | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
- else
- #endif
- outb(D8390_COMMAND_PS0 |
- D8390_COMMAND_TXP | D8390_COMMAND_RD2 |
- D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
- }
-
- /**************************************************************************
- NS8390_POLL - Wait for a frame
- **************************************************************************/
- static int ns8390_poll(struct nic *nic, int retrieve)
- {
- int ret = 0;
- unsigned char rstat, curr, next;
- unsigned short len, frag;
- unsigned short pktoff;
- unsigned char *p;
- struct ringbuffer pkthdr;
-
- #ifndef INCLUDE_3C503
- /* avoid infinite recursion: see eth_rx_overrun() */
- if (!eth_drain_receiver && (inb(eth_nic_base+D8390_P0_ISR) & D8390_ISR_OVW)) {
- eth_rx_overrun(nic);
- return(0);
- }
- #endif /* INCLUDE_3C503 */
- rstat = inb(eth_nic_base+D8390_P0_RSR);
- if (!(rstat & D8390_RSTAT_PRX)) return(0);
- next = inb(eth_nic_base+D8390_P0_BOUND)+1;
- if (next >= eth_memsize) next = eth_rx_start;
- outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND);
- curr = inb(eth_nic_base+D8390_P1_CURR);
- outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND);
- if (curr >= eth_memsize) curr=eth_rx_start;
- if (curr == next) return(0);
-
- if ( ! retrieve ) return 1;
-
- #ifdef INCLUDE_WD
- if (eth_flags & FLAG_16BIT) {
- outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
- inb(0x84);
- }
- #ifndef WD_790_PIO
- if (eth_flags & FLAG_790) {
- outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
- inb(0x84);
- }
- #endif
- inb(0x84);
- #endif
- pktoff = next << 8;
- if (eth_flags & FLAG_PIO)
- eth_pio_read(pktoff, (unsigned char *)&pkthdr, 4);
- else
- memcpy(&pkthdr, bus_to_virt(eth_rmem + pktoff), 4);
- pktoff += sizeof(pkthdr);
- /* incoming length includes FCS so must sub 4 */
- len = pkthdr.len - 4;
- if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN
- || len > ETH_FRAME_LEN) {
- printf("Bogus packet, ignoring\n");
- return (0);
- }
- else {
- p = nic->packet;
- nic->packetlen = len; /* available to caller */
- frag = (eth_memsize << 8) - pktoff;
- if (len > frag) { /* We have a wrap-around */
- /* read first part */
- if (eth_flags & FLAG_PIO)
- eth_pio_read(pktoff, p, frag);
- else
- memcpy(p, bus_to_virt(eth_rmem + pktoff), frag);
- pktoff = eth_rx_start << 8;
- p += frag;
- len -= frag;
- }
- /* read second part */
- if (eth_flags & FLAG_PIO)
- eth_pio_read(pktoff, p, len);
- else
- memcpy(p, bus_to_virt(eth_rmem + pktoff), len);
- ret = 1;
- }
- #ifdef INCLUDE_WD
- #ifndef WD_790_PIO
- if (eth_flags & FLAG_790) {
- outb(0, eth_asic_base + WD_MSR);
- inb(0x84);
- }
- #endif
- if (eth_flags & FLAG_16BIT) {
- outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
- inb(0x84);
- }
- inb(0x84);
- #endif
- next = pkthdr.next; /* frame number of next packet */
- if (next == eth_rx_start)
- next = eth_memsize;
- outb(next-1, eth_nic_base+D8390_P0_BOUND);
- return(ret);
- }
-
- /**************************************************************************
- NS8390_DISABLE - Turn off adapter
- **************************************************************************/
- static void ns8390_disable ( struct nic *nic ) {
- ns8390_reset(nic);
- }
-
- /**************************************************************************
- NS8390_IRQ - Enable, Disable, or Force interrupts
- **************************************************************************/
- static void ns8390_irq(struct nic *nic __unused, irq_action_t action __unused)
- {
- switch ( action ) {
- case DISABLE :
- break;
- case ENABLE :
- break;
- case FORCE :
- break;
- }
- }
-
- static struct nic_operations ns8390_operations;
- static struct nic_operations ns8390_operations = {
- .connect = dummy_connect,
- .poll = ns8390_poll,
- .transmit = ns8390_transmit,
- .irq = ns8390_irq,
- };
-
- /**************************************************************************
- ETH_PROBE - Look for an adapter
- **************************************************************************/
- #ifdef INCLUDE_NS8390
- static int eth_probe (struct nic *nic, struct pci_device *pci)
- #else
- static int eth_probe (struct dev *dev, unsigned short *probe_addrs __unused)
- #endif
- {
- int i;
- #ifdef INCLUDE_NS8390
- unsigned short pci_probe_addrs[] = { pci->ioaddr, 0 };
- unsigned short *probe_addrs = pci_probe_addrs;
- #endif
- eth_vendor = VENDOR_NONE;
- eth_drain_receiver = 0;
-
- nic->irqno = 0;
-
- #ifdef INCLUDE_WD
- {
- /******************************************************************
- Search for WD/SMC cards
- ******************************************************************/
- struct wd_board *brd;
- unsigned short chksum;
- unsigned char c;
- for (eth_asic_base = WD_LOW_BASE; eth_asic_base <= WD_HIGH_BASE;
- eth_asic_base += 0x20) {
- chksum = 0;
- for (i=8; i<16; i++)
- chksum += inb(eth_asic_base+i);
- /* Extra checks to avoid soundcard */
- if ((chksum & 0xFF) == 0xFF &&
- inb(eth_asic_base+8) != 0xFF &&
- inb(eth_asic_base+9) != 0xFF)
- break;
- }
- if (eth_asic_base > WD_HIGH_BASE)
- return (0);
- /* We've found a board */
- eth_vendor = VENDOR_WD;
- eth_nic_base = eth_asic_base + WD_NIC_ADDR;
-
- nic->ioaddr = eth_nic_base;
-
- c = inb(eth_asic_base+WD_BID); /* Get board id */
- for (brd = wd_boards; brd->name; brd++)
- if (brd->id == c) break;
- if (!brd->name) {
- printf("Unknown WD/SMC NIC type %hhX\n", c);
- return (0); /* Unknown type */
- }
- eth_flags = brd->flags;
- eth_memsize = brd->memsize;
- eth_tx_start = 0;
- eth_rx_start = D8390_TXBUF_SIZE;
- if ((c == TYPE_WD8013EP) &&
- (inb(eth_asic_base + WD_ICR) & WD_ICR_16BIT)) {
- eth_flags = FLAG_16BIT;
- eth_memsize = MEM_16384;
- }
- if ((c & WD_SOFTCONFIG) && (!(eth_flags & FLAG_790))) {
- eth_bmem = (0x80000 |
- ((inb(eth_asic_base + WD_MSR) & 0x3F) << 13));
- } else
- eth_bmem = WD_DEFAULT_MEM;
- if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) {
- /* from Linux driver, 8416BT detects as 8216 sometimes */
- unsigned int addr = inb(eth_asic_base + 0xb);
- if (((addr >> 4) & 3) == 0) {
- brd += 2;
- eth_memsize = brd->memsize;
- }
- }
- outb(0x80, eth_asic_base + WD_MSR); /* Reset */
- for (i=0; i<ETH_ALEN; i++) {
- nic->node_addr[i] = inb(i+eth_asic_base+WD_LAR);
- }
- DBG ( "\n%s base %4.4x", brd->name, eth_asic_base );
- if (eth_flags & FLAG_790) {
- #ifdef WD_790_PIO
- DBG ( ", PIO mode, addr %s\n", eth_ntoa ( nic->node_addr ) );
- eth_bmem = 0;
- eth_flags |= FLAG_PIO; /* force PIO mode */
- outb(0, eth_asic_base+WD_MSR);
- #else
- DBG ( ", Memory %x, MAC Addr %s\n", eth_bmem, eth_ntoa ( nic->node_addr) );
-
- outb(WD_MSR_MENB, eth_asic_base+WD_MSR);
- outb((inb(eth_asic_base+0x04) |
- 0x80), eth_asic_base+0x04);
- outb(((unsigned)(eth_bmem >> 13) & 0x0F) |
- ((unsigned)(eth_bmem >> 11) & 0x40) |
- (inb(eth_asic_base+0x0B) & 0xB0), eth_asic_base+0x0B);
- outb((inb(eth_asic_base+0x04) &
- ~0x80), eth_asic_base+0x04);
- #endif
- } else {
-
- DBG (", Memory %x, MAC Addr %s\n", eth_bmem, eth_ntoa ( nic->node_addr) );
-
- outb(((unsigned)(eth_bmem >> 13) & 0x3F) | 0x40, eth_asic_base+WD_MSR);
- }
- if (eth_flags & FLAG_16BIT) {
- if (eth_flags & FLAG_790) {
- eth_laar = inb(eth_asic_base + WD_LAAR);
- outb(WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
- } else {
- outb((eth_laar =
- WD_LAAR_L16EN | 1), eth_asic_base + WD_LAAR);
- /*
- The previous line used to be
- WD_LAAR_M16EN | WD_LAAR_L16EN | 1));
- jluke@deakin.edu.au reported that removing WD_LAAR_M16EN made
- it work for WD8013s. This seems to work for my 8013 boards. I
- don't know what is really happening. I wish I had data sheets
- or more time to decode the Linux driver. - Ken
- */
- }
- inb(0x84);
- }
- }
- #endif
- #ifdef INCLUDE_3C503
- #ifdef T503_AUI
- nic->flags = 1; /* aui */
- #else
- nic->flags = 0; /* no aui */
- #endif
- /******************************************************************
- Search for 3Com 3c503 if no WD/SMC cards
- ******************************************************************/
- if (eth_vendor == VENDOR_NONE) {
- int idx;
- int iobase_reg, membase_reg;
- static unsigned short base[] = {
- 0x300, 0x310, 0x330, 0x350,
- 0x250, 0x280, 0x2A0, 0x2E0, 0 };
-
- /* Loop through possible addresses checking each one */
-
- for (idx = 0; (eth_nic_base = base[idx]) != 0; ++idx) {
-
- eth_asic_base = eth_nic_base + _3COM_ASIC_OFFSET;
- /*
- * Note that we use the same settings for both 8 and 16 bit cards:
- * both have an 8K bank of memory at page 1 while only the 16 bit
- * cards have a bank at page 0.
- */
- eth_memsize = MEM_16384;
- eth_tx_start = 32;
- eth_rx_start = 32 + D8390_TXBUF_SIZE;
-
- /* Check our base address. iobase and membase should */
- /* both have a maximum of 1 bit set or be 0. */
-
- iobase_reg = inb(eth_asic_base + _3COM_BCFR);
- membase_reg = inb(eth_asic_base + _3COM_PCFR);
-
- if ((iobase_reg & (iobase_reg - 1)) ||
- (membase_reg & (membase_reg - 1)))
- continue; /* nope */
-
- /* Now get the shared memory address */
-
- eth_flags = 0;
-
- switch (membase_reg) {
- case _3COM_PCFR_DC000:
- eth_bmem = 0xdc000;
- break;
- case _3COM_PCFR_D8000:
- eth_bmem = 0xd8000;
- break;
- case _3COM_PCFR_CC000:
- eth_bmem = 0xcc000;
- break;
- case _3COM_PCFR_C8000:
- eth_bmem = 0xc8000;
- break;
- case _3COM_PCFR_PIO:
- eth_flags |= FLAG_PIO;
- eth_bmem = 0;
- break;
- default:
- continue; /* nope */
- }
- break;
- }
-
- if (base[idx] == 0) /* not found */
- return (0);
- #ifndef T503_SHMEM
- eth_flags |= FLAG_PIO; /* force PIO mode */
- eth_bmem = 0;
- #endif
- eth_vendor = VENDOR_3COM;
-
-
- /* Need this to make ns8390_poll() happy. */
-
- eth_rmem = eth_bmem - 0x2000;
-
- /* Reset NIC and ASIC */
-
- outb(_3COM_CR_RST | _3COM_CR_XSEL, eth_asic_base + _3COM_CR );
- outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR );
-
- /* Get our ethernet address */
-
- outb(_3COM_CR_EALO | _3COM_CR_XSEL, eth_asic_base + _3COM_CR);
- nic->ioaddr = eth_nic_base;
- DBG ( "\n3Com 3c503 base %4.4x, ", eth_nic_base );
- if (eth_flags & FLAG_PIO)
- DBG ( "PIO mode" );
- else
- DBG ( "memory %4.4x", eth_bmem );
- for (i=0; i<ETH_ALEN; i++) {
- nic->node_addr[i] = inb(eth_nic_base+i);
- }
- DBG ( ", %s, MAC Addr %s\n", nic->flags ? "AUI" : "internal xcvr",
- eth_ntoa ( nic->node_addr ) );
-
- outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR);
- /*
- * Initialize GA configuration register. Set bank and enable shared
- * mem. We always use bank 1. Disable interrupts.
- */
- outb(_3COM_GACFR_RSEL |
- _3COM_GACFR_MBS0 | _3COM_GACFR_TCM | _3COM_GACFR_NIM, eth_asic_base + _3COM_GACFR);
-
- outb(0xff, eth_asic_base + _3COM_VPTR2);
- outb(0xff, eth_asic_base + _3COM_VPTR1);
- outb(0x00, eth_asic_base + _3COM_VPTR0);
- /*
- * Clear memory and verify that it worked (we use only 8K)
- */
-
- if (!(eth_flags & FLAG_PIO)) {
- memset(bus_to_virt(eth_bmem), 0, 0x2000);
- for(i = 0; i < 0x2000; ++i)
- if (*((char *)(bus_to_virt(eth_bmem+i)))) {
- printf ("Failed to clear 3c503 shared mem.\n");
- return (0);
- }
- }
- /*
- * Initialize GA page/start/stop registers.
- */
- outb(eth_tx_start, eth_asic_base + _3COM_PSTR);
- outb(eth_memsize, eth_asic_base + _3COM_PSPR);
- }
- #endif
- #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
- {
- /******************************************************************
- Search for NE1000/2000 if no WD/SMC or 3com cards
- ******************************************************************/
- unsigned char c;
- if (eth_vendor == VENDOR_NONE) {
- unsigned char romdata[16];
- unsigned char testbuf[32];
- int idx;
- static unsigned char test[] = "NE*000 memory";
- static unsigned short base[] = {
- #ifdef NE_SCAN
- NE_SCAN,
- #endif
- 0 };
- /* if no addresses supplied, fall back on defaults */
- if (probe_addrs == 0 || probe_addrs[0] == 0)
- probe_addrs = base;
- eth_bmem = 0; /* No shared memory */
- for (idx = 0; (eth_nic_base = probe_addrs[idx]) != 0; ++idx) {
- eth_flags = FLAG_PIO;
- eth_asic_base = eth_nic_base + NE_ASIC_OFFSET;
- eth_memsize = MEM_16384;
- eth_tx_start = 32;
- eth_rx_start = 32 + D8390_TXBUF_SIZE;
- c = inb(eth_asic_base + NE_RESET);
- outb(c, eth_asic_base + NE_RESET);
- (void) inb(0x84);
- outb(D8390_COMMAND_STP |
- D8390_COMMAND_RD2, eth_nic_base + D8390_P0_COMMAND);
- outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
- outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
- outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
- outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
- #ifdef NS8390_FORCE_16BIT
- eth_flags |= FLAG_16BIT; /* force 16-bit mode */
- #endif
-
- eth_pio_write( (unsigned char *) test, 8192, sizeof(test));
- eth_pio_read(8192, testbuf, sizeof(test));
- if (!memcmp(test, testbuf, sizeof(test)))
- break;
- eth_flags |= FLAG_16BIT;
- eth_memsize = MEM_32768;
- eth_tx_start = 64;
- eth_rx_start = 64 + D8390_TXBUF_SIZE;
- outb(D8390_DCR_WTS |
- D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
- outb(MEM_16384, eth_nic_base + D8390_P0_PSTART);
- outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP);
- eth_pio_write( (unsigned char *) test, 16384, sizeof(test));
- eth_pio_read(16384, testbuf, sizeof(test));
- if (!memcmp(testbuf, test, sizeof(test)))
- break;
- }
- if (eth_nic_base == 0)
- return (0);
- if (eth_nic_base > ISA_MAX_ADDR) /* PCI probably */
- eth_flags |= FLAG_16BIT;
- eth_vendor = VENDOR_NOVELL;
- eth_pio_read(0, romdata, sizeof(romdata));
- for (i=0; i<ETH_ALEN; i++) {
- nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)];
- }
- nic->ioaddr = eth_nic_base;
- DBG ( "\nNE%c000 base %4.4x, MAC Addr %s\n",
- (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base,
- eth_ntoa ( nic->node_addr ) );
- }
- }
- #endif
- if (eth_vendor == VENDOR_NONE)
- return(0);
- if (eth_vendor != VENDOR_3COM)
- eth_rmem = eth_bmem;
- ns8390_reset(nic);
- nic->nic_op = &ns8390_operations;
-
- /* Based on PnP ISA map */
- #ifdef INCLUDE_WD
- dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
- dev->devid.device_id = htons(0x812a);
- #endif
- #ifdef INCLUDE_3C503
- dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
- dev->devid.device_id = htons(0x80f3);
- #endif
- #ifdef INCLUDE_NE
- dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
- dev->devid.device_id = htons(0x80d6);
- #endif
- return 1;
- }
-
- #ifdef INCLUDE_WD
- struct isa_driver wd_driver __isa_driver = {
- .type = NIC_DRIVER,
- .name = "WD",
- .probe = wd_probe,
- .ioaddrs = 0,
- };
- ISA_ROM("wd","WD8003/8013, SMC8216/8416, SMC 83c790 (EtherEZ)");
- #endif
-
- #ifdef INCLUDE_3C503
- struct isa_driver t503_driver __isa_driver = {
- .type = NIC_DRIVER,
- .name = "3C503",
- .probe = t503_probe,
- .ioaddrs = 0,
- };
- ISA_ROM("3c503","3Com503, Etherlink II[/16]");
- #endif
-
- #ifdef INCLUDE_NE
- struct isa_driver ne_driver __isa_driver = {
- .type = NIC_DRIVER,
- .name = "NE*000",
- .probe = ne_probe,
- .ioaddrs = 0,
- };
- ISA_ROM("ne","NE1000/2000 and clones");
- #endif
-
- #ifdef INCLUDE_NS8390
- static struct pci_device_id nepci_nics[] = {
- /* A few NE2000 PCI clones, list not exhaustive */
- PCI_ROM(0x10ec, 0x8029, "rtl8029", "Realtek 8029"),
- PCI_ROM(0x1186, 0x0300, "dlink-528", "D-Link DE-528"),
- PCI_ROM(0x1050, 0x0940, "winbond940", "Winbond NE2000-PCI"), /* Winbond 86C940 / 89C940 */
- PCI_ROM(0x1050, 0x5a5a, "winbond940f", "Winbond W89c940F"), /* Winbond 89C940F */
- PCI_ROM(0x11f6, 0x1401, "compexrl2000", "Compex ReadyLink 2000"),
- PCI_ROM(0x8e2e, 0x3000, "ktiet32p2", "KTI ET32P2"),
- PCI_ROM(0x4a14, 0x5000, "nv5000sc", "NetVin NV5000SC"),
- PCI_ROM(0x12c3, 0x0058, "holtek80232", "Holtek HT80232"),
- PCI_ROM(0x12c3, 0x5598, "holtek80229", "Holtek HT80229"),
- PCI_ROM(0x10bd, 0x0e34, "surecom-ne34", "Surecom NE34"),
- PCI_ROM(0x1106, 0x0926, "via86c926", "Via 86c926"),
- };
-
- PCI_DRIVER ( nepci_driver, nepci_nics, PCI_NO_CLASS );
-
- DRIVER ( "NE2000/PCI", nic_driver, pci_driver, nepci_driver,
- nepci_probe, ns8390_disable );
-
- #endif /* INCLUDE_NS8390 */
-
- #endif
-
- /*
- * Local variables:
- * c-basic-offset: 8
- * c-indent-level: 8
- * tab-width: 8
- * End:
- */
|