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