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