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