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