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