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