1/**************************************************************************
2ETHERBOOT -  BOOTP/TFTP Bootstrap Program
3
4Author: 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
16Multicast support added by Timothy Legge (timlegge@users.sourceforge.net) 09/28/2003
17Relocation support added by Ken Yap (ken_yap@users.sourceforge.net) 28/12/02
183c503 support added by Bill Paul (wpaul@ctr.columbia.edu) on 11/15/94
19SMC8416 support added by Bill Paul (wpaul@ctr.columbia.edu) on 12/25/94
203c503 PIO support added by Jim Hague (jim.hague@acm.org) on 2/17/98
21RX 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)
23SMC8416 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
28FILE_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
51static unsigned char	eth_vendor, eth_flags;
52#ifdef	INCLUDE_WD
53static unsigned char	eth_laar;
54#endif
55static unsigned short	eth_nic_base, eth_asic_base;
56static unsigned char	eth_memsize, eth_rx_start, eth_tx_start;
57static Address		eth_bmem, eth_rmem;
58static unsigned char	eth_drain_receiver;
59
60#ifdef	INCLUDE_WD
61static 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
87static 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)
94Error 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)
101Error 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)
108Error 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)
115Error 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/**************************************************************************
129ETH_PIO_READ - Read a frame via Programmed I/O
130**************************************************************************/
131static 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/**************************************************************************
176ETH_PIO_WRITE - Write a frame via Programmed I/O
177**************************************************************************/
178static 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/**************************************************************************
243ETH_PIO_READ - Dummy routine when NE2000 not compiled in
244**************************************************************************/
245static void eth_pio_read(unsigned int src __unused, unsigned char *dst  __unused, unsigned int cnt __unused) {}
246#endif
247
248
249/**************************************************************************
250enable_multycast - Enable Multicast
251**************************************************************************/
252static 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/**************************************************************************
270NS8390_RESET - Reset adapter
271**************************************************************************/
272static 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
347static int ns8390_poll(struct nic *nic, int retrieve);
348
349#ifndef	INCLUDE_3C503
350/**************************************************************************
351ETH_RX_OVERRUN - Bring adapter back to work after an RX overrun
352**************************************************************************/
353static 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/**************************************************************************
401NS8390_TRANSMIT - Transmit a frame
402**************************************************************************/
403static 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/**************************************************************************
500NS8390_POLL - Wait for a frame
501**************************************************************************/
502static 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/**************************************************************************
598NS8390_DISABLE - Turn off adapter
599**************************************************************************/
600static void ns8390_disable ( struct nic *nic ) {
601	ns8390_reset(nic);
602}
603
604/**************************************************************************
605NS8390_IRQ - Enable, Disable, or Force interrupts
606**************************************************************************/
607static 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
619static struct nic_operations ns8390_operations;
620static struct nic_operations ns8390_operations = {
621	.connect	= dummy_connect,
622	.poll		= ns8390_poll,
623	.transmit	= ns8390_transmit,
624	.irq		= ns8390_irq,
625};
626
627/**************************************************************************
628ETH_PROBE - Look for an adapter
629**************************************************************************/
630#ifdef	INCLUDE_NS8390
631static int eth_probe (struct nic *nic, struct pci_device *pci)
632#else
633static 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
977struct isa_driver wd_driver __isa_driver = {
978	.type    = NIC_DRIVER,
979	.name    = "WD",
980	.probe   = wd_probe,
981	.ioaddrs = 0,
982};
983ISA_ROM("wd","WD8003/8013, SMC8216/8416, SMC 83c790 (EtherEZ)");
984#endif
985
986#ifdef	INCLUDE_3C503
987struct isa_driver t503_driver __isa_driver = {
988	.type    = NIC_DRIVER,
989	.name    = "3C503",
990	.probe   = t503_probe,
991	.ioaddrs = 0,
992};
993ISA_ROM("3c503","3Com503, Etherlink II[/16]");
994#endif
995
996#ifdef	INCLUDE_NE
997struct isa_driver ne_driver __isa_driver = {
998	.type    = NIC_DRIVER,
999	.name    = "NE*000",
1000	.probe   = ne_probe,
1001	.ioaddrs = 0,
1002};
1003ISA_ROM("ne","NE1000/2000 and clones");
1004#endif
1005
1006#ifdef	INCLUDE_NS8390
1007static struct pci_device_id nepci_nics[] = {
1008/* A few NE2000 PCI clones, list not exhaustive */
1009PCI_ROM(0x10ec, 0x8029, "rtl8029",      "Realtek 8029", 0),
1010PCI_ROM(0x1186, 0x0300, "dlink-528",    "D-Link DE-528", 0),
1011PCI_ROM(0x1050, 0x0940, "winbond940",   "Winbond NE2000-PCI", 0),		/* Winbond 86C940 / 89C940 */
1012PCI_ROM(0x1050, 0x5a5a, "winbond940f",  "Winbond W89c940F", 0),		/* Winbond 89C940F */
1013PCI_ROM(0x11f6, 0x1401, "compexrl2000", "Compex ReadyLink 2000", 0),
1014PCI_ROM(0x8e2e, 0x3000, "ktiet32p2",    "KTI ET32P2", 0),
1015PCI_ROM(0x4a14, 0x5000, "nv5000sc",     "NetVin NV5000SC", 0),
1016PCI_ROM(0x12c3, 0x0058, "holtek80232",  "Holtek HT80232", 0),
1017PCI_ROM(0x12c3, 0x5598, "holtek80229",  "Holtek HT80229", 0),
1018PCI_ROM(0x10bd, 0x0e34, "surecom-ne34", "Surecom NE34", 0),
1019PCI_ROM(0x1106, 0x0926, "via86c926",    "Via 86c926", 0),
1020};
1021
1022PCI_DRIVER ( nepci_driver, nepci_nics, PCI_NO_CLASS );
1023
1024DRIVER ( "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