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