1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018 |
- /**************************************************************************
- 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)
-
- **************************************************************************/
-
- #include "etherboot.h"
- #include "nic.h"
- #include "ns8390.h"
- #ifdef INCLUDE_NS8390
- #include "pci.h"
- #else
- #include "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(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(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, (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 dev *dev)
- {
- struct nic *nic = (struct nic *)dev;
- /* reset and disable merge */
- 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;
- }
- }
-
- /**************************************************************************
- ETH_PROBE - Look for an adapter
- **************************************************************************/
- #ifdef INCLUDE_NS8390
- static int eth_probe (struct dev *dev, struct pci_device *pci)
- #else
- static int eth_probe (struct dev *dev, unsigned short *probe_addrs __unused)
- #endif
- {
- struct nic *nic = (struct nic *)dev;
- 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);
- }
- printf("\n%s base %#hx", brd->name, eth_asic_base);
- if (eth_flags & FLAG_790) {
- #ifdef WD_790_PIO
- printf(", PIO mode, addr %!\n", nic->node_addr);
- eth_bmem = 0;
- eth_flags |= FLAG_PIO; /* force PIO mode */
- outb(0, eth_asic_base+WD_MSR);
- #else
- printf(", memory %#x, addr %!\n", eth_bmem, 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 {
- printf(", memory %#x, addr %!\n", eth_bmem, 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;
- printf("\n3Com 3c503 base %#hx, ", eth_nic_base);
- if (eth_flags & FLAG_PIO)
- printf("PIO mode");
- else
- printf("memory %#x", eth_bmem);
- for (i=0; i<ETH_ALEN; i++) {
- nic->node_addr[i] = inb(eth_nic_base+i);
- }
- printf(", %s, addr %!\n", nic->flags ? "AUI" : "internal xcvr",
- 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) {
- char romdata[16], testbuf[32];
- int idx;
- static 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);
- 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(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(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;
- printf("\nNE%c000 base %#hx, addr %!\n",
- (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base,
- nic->node_addr);
- }
- }
- #endif
- if (eth_vendor == VENDOR_NONE)
- return(0);
- if (eth_vendor != VENDOR_3COM)
- eth_rmem = eth_bmem;
- ns8390_reset(nic);
-
- dev->disable = ns8390_disable;
- nic->poll = ns8390_poll;
- nic->transmit = ns8390_transmit;
- nic->irq = ns8390_irq;
-
- /* 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
- static 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
- static 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
- static 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_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"),
- };
-
- static struct pci_driver nepci_driver __pci_driver = {
- .type = NIC_DRIVER,
- .name = "NE2000/PCI",
- .probe = nepci_probe,
- .ids = nepci_nics,
- .id_count = sizeof(nepci_nics)/sizeof(nepci_nics[0]),
- .class = 0,
- };
-
- #endif /* INCLUDE_NS8390 */
-
- /*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
|