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