1 /**************************************************************************
2 ETHERBOOT - BOOTP/TFTP Bootstrap Program
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 FILE_LICENCE ( BSD2
);
30 /* #warning "ns8390.c: FIXME: split ISA and PCI, clean up" */
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
41 #include "etherboot.h"
44 #include <gpxe/ethernet.h>
51 static unsigned char eth_vendor
, eth_flags
;
53 static unsigned char eth_laar
;
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
;
61 static struct wd_board
{
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
},
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
},
87 static unsigned char t503_output
; /* AUI or internal xcvr (Thinnet) */
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
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
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
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
119 #if defined(INCLUDE_3C503)
120 #define ASIC_PIO _3COM_RFMSB
122 #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
123 #define ASIC_PIO NE_DATA
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
)
134 outb(src
& 0xff, eth_asic_base
+ WD_GP2
);
135 outb(src
>> 8, eth_asic_base
+ WD_GP2
);
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
);
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
);
153 if (eth_flags
& FLAG_16BIT
)
154 cnt
= (cnt
+ 1) >> 1;
158 while((inb(eth_asic_base
+ _3COM_STREG
) & _3COM_STREG_DPRDY
) == 0)
162 if (eth_flags
& FLAG_16BIT
) {
163 *((unsigned short *)dst
) = inw(eth_asic_base
+ ASIC_PIO
);
167 *(dst
++) = inb(eth_asic_base
+ ASIC_PIO
);
171 outb(t503_output
, eth_asic_base
+ _3COM_CR
);
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
)
180 #ifdef COMPEX_RL2000_FIX
182 #endif /* COMPEX_RL2000_FIX */
184 outb(dst
& 0xff, eth_asic_base
+ WD_GP2
);
185 outb(dst
>> 8, eth_asic_base
+ WD_GP2
);
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
);
198 outb(dst
& 0xff, eth_asic_base
+ _3COM_DALSB
);
199 outb(dst
>> 8, eth_asic_base
+ _3COM_DAMSB
);
201 outb(t503_output
| _3COM_CR_DDIR
| _3COM_CR_START
, eth_asic_base
+ _3COM_CR
);
205 if (eth_flags
& FLAG_16BIT
)
206 cnt
= (cnt
+ 1) >> 1;
211 while((inb(eth_asic_base
+ _3COM_STREG
) & _3COM_STREG_DPRDY
) == 0)
215 if (eth_flags
& FLAG_16BIT
) {
216 outw(*((unsigned short *)src
), eth_asic_base
+ ASIC_PIO
);
220 outb(*(src
++), eth_asic_base
+ ASIC_PIO
);
224 outb(t503_output
, eth_asic_base
+ _3COM_CR
);
226 #ifdef COMPEX_RL2000_FIX
228 x
< COMPEX_RL2000_TRIES
&&
229 (inb(eth_nic_base
+ D8390_P0_ISR
) & D8390_ISR_RDC
)
232 if (x
>= COMPEX_RL2000_TRIES
)
233 printf("Warning: Compex RL2000 aborted wait!\n");
234 #endif /* COMPEX_RL2000_FIX */
236 while((inb(eth_nic_base
+ D8390_P0_ISR
) & D8390_ISR_RDC
)
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
) {}
249 /**************************************************************************
250 enable_multycast - Enable Multicast
251 **************************************************************************/
252 static void enable_multicast(unsigned short eth_nic_base
)
254 unsigned char mcfilter
[8];
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
);
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
);
265 outb(D8390_COMMAND_RD2
+ D8390_COMMAND_PS0
, eth_nic_base
+ D8390_P0_COMMAND
);
266 outb(4 | 0x08, eth_nic_base
+D8390_P0_RCR
);
269 /**************************************************************************
270 NS8390_RESET - Reset adapter
271 **************************************************************************/
272 static void ns8390_reset(struct nic
*nic
)
276 eth_drain_receiver
= 0;
278 if (eth_flags
& FLAG_790
)
279 outb(D8390_COMMAND_PS0
| D8390_COMMAND_STP
, eth_nic_base
+D8390_P0_COMMAND
);
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
);
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
);
295 if (eth_flags
& FLAG_790
) {
297 outb(0x10, eth_asic_base
+ 0x06); /* disable interrupts, enable PIO */
298 outb(0x01, eth_nic_base
+ 0x09); /* enable ring read auto-wrap */
300 outb(0, eth_nic_base
+ 0x09);
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
);
309 if (eth_flags
& FLAG_790
)
310 outb(D8390_COMMAND_PS1
|
311 D8390_COMMAND_STP
, eth_nic_base
+D8390_P0_COMMAND
);
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
);
322 if (eth_flags
& FLAG_790
)
323 outb(D8390_COMMAND_PS0
|
324 D8390_COMMAND_STA
, eth_nic_base
+D8390_P0_COMMAND
);
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 */
333 enable_multicast(eth_nic_base
);
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.
342 t503_output
= (nic
->flags
) ? 0 : _3COM_CR_XSEL
;
343 outb(t503_output
, eth_asic_base
+ _3COM_CR
);
347 static int ns8390_poll(struct nic
*nic
, int retrieve
);
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
)
358 if (eth_flags
& FLAG_790
)
359 outb(D8390_COMMAND_PS0
| D8390_COMMAND_STP
, eth_nic_base
+D8390_P0_COMMAND
);
362 outb(D8390_COMMAND_PS0
| D8390_COMMAND_RD2
|
363 D8390_COMMAND_STP
, eth_nic_base
+D8390_P0_COMMAND
);
365 /* wait for at least 1.6ms - we wait one timer tick */
366 start_time
= currticks();
367 while (currticks() - start_time
<= 1)
370 outb(0, eth_nic_base
+D8390_P0_RBCR0
); /* reset byte counter */
371 outb(0, eth_nic_base
+D8390_P0_RBCR1
);
374 * Linux driver checks for interrupted TX here. This is not necessary,
375 * because the transmit routine waits until the frame is sent.
378 /* enter loopback mode and restart NIC */
379 outb(2, eth_nic_base
+D8390_P0_TCR
);
381 if (eth_flags
& FLAG_790
)
382 outb(D8390_COMMAND_PS0
| D8390_COMMAND_STA
, eth_nic_base
+D8390_P0_COMMAND
);
385 outb(D8390_COMMAND_PS0
| D8390_COMMAND_RD2
|
386 D8390_COMMAND_STA
, eth_nic_base
+D8390_P0_COMMAND
);
388 /* clear the RX ring, acknowledge overrun interrupt */
389 eth_drain_receiver
= 1;
390 while (ns8390_poll(nic
, 1))
392 eth_drain_receiver
= 0;
393 outb(D8390_ISR_OVW
, eth_nic_base
+D8390_P0_ISR
);
395 /* leave loopback mode - no packets to be resent (see Linux driver) */
396 outb(0, eth_nic_base
+D8390_P0_TCR
);
398 #endif /* INCLUDE_3C503 */
400 /**************************************************************************
401 NS8390_TRANSMIT - Transmit a frame
402 **************************************************************************/
403 static void ns8390_transmit(
405 const char *d
, /* Destination */
406 unsigned int t
, /* Type */
407 unsigned int s
, /* size */
408 const char *p
) /* Packet */
410 #if defined(INCLUDE_3C503) || (defined(INCLUDE_WD) && ! defined(WD_790_PIO))
411 Address eth_vmem
= bus_to_virt(eth_bmem
);
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
);
421 while (s
< ETH_ZLEN
) *((char *)eth_vmem
+(s
++)) = 0;
426 if (eth_flags
& FLAG_16BIT
) {
427 outb(eth_laar
| WD_LAAR_M16EN
, eth_asic_base
+ WD_LAAR
);
431 /* Memory interface */
432 if (eth_flags
& FLAG_790
) {
433 outb(WD_MSR_MENB
, eth_asic_base
+ WD_MSR
);
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
);
443 while (s
< ETH_ZLEN
) *((char *)eth_vmem
+(s
++)) = 0;
444 if (eth_flags
& FLAG_790
) {
445 outb(0, eth_asic_base
+ WD_MSR
);
453 #if defined(INCLUDE_3C503)
454 if (eth_flags
& FLAG_PIO
)
456 #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM)) || (defined(INCLUDE_WD) && defined(WD_790_PIO))
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
);
467 if (s
< ETH_ZLEN
) s
= ETH_ZLEN
;
470 #if defined(INCLUDE_3C503)
474 if (eth_flags
& FLAG_16BIT
) {
475 outb(eth_laar
& ~WD_LAAR_M16EN
, eth_asic_base
+ WD_LAAR
);
478 if (eth_flags
& FLAG_790
)
479 outb(D8390_COMMAND_PS0
|
480 D8390_COMMAND_STA
, eth_nic_base
+D8390_P0_COMMAND
);
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
);
489 if (eth_flags
& FLAG_790
)
490 outb(D8390_COMMAND_PS0
|
491 D8390_COMMAND_TXP
| D8390_COMMAND_STA
, eth_nic_base
+D8390_P0_COMMAND
);
494 outb(D8390_COMMAND_PS0
|
495 D8390_COMMAND_TXP
| D8390_COMMAND_RD2
|
496 D8390_COMMAND_STA
, eth_nic_base
+D8390_P0_COMMAND
);
499 /**************************************************************************
500 NS8390_POLL - Wait for a frame
501 **************************************************************************/
502 static int ns8390_poll(struct nic
*nic
, int retrieve
)
505 unsigned char rstat
, curr
, next
;
506 unsigned short len
, frag
;
507 unsigned short pktoff
;
509 struct ringbuffer pkthdr
;
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
)) {
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);
528 if ( ! retrieve
) return 1;
531 if (eth_flags
& FLAG_16BIT
) {
532 outb(eth_laar
| WD_LAAR_M16EN
, eth_asic_base
+ WD_LAAR
);
536 if (eth_flags
& FLAG_790
) {
537 outb(WD_MSR_MENB
, eth_asic_base
+ WD_MSR
);
544 if (eth_flags
& FLAG_PIO
)
545 eth_pio_read(pktoff
, (unsigned char *)&pkthdr
, 4);
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");
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
);
565 memcpy(p
, bus_to_virt(eth_rmem
+ pktoff
), frag
);
566 pktoff
= eth_rx_start
<< 8;
570 /* read second part */
571 if (eth_flags
& FLAG_PIO
)
572 eth_pio_read(pktoff
, p
, len
);
574 memcpy(p
, bus_to_virt(eth_rmem
+ pktoff
), len
);
579 if (eth_flags
& FLAG_790
) {
580 outb(0, eth_asic_base
+ WD_MSR
);
584 if (eth_flags
& FLAG_16BIT
) {
585 outb(eth_laar
& ~WD_LAAR_M16EN
, eth_asic_base
+ WD_LAAR
);
590 next
= pkthdr
.next
; /* frame number of next packet */
591 if (next
== eth_rx_start
)
593 outb(next
-1, eth_nic_base
+D8390_P0_BOUND
);
597 /**************************************************************************
598 NS8390_DISABLE - Turn off adapter
599 **************************************************************************/
600 static void ns8390_disable ( struct nic
*nic
) {
604 /**************************************************************************
605 NS8390_IRQ - Enable, Disable, or Force interrupts
606 **************************************************************************/
607 static void ns8390_irq(struct nic
*nic __unused
, irq_action_t action __unused
)
619 static struct nic_operations ns8390_operations
;
620 static struct nic_operations ns8390_operations
= {
621 .connect
= dummy_connect
,
623 .transmit
= ns8390_transmit
,
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
)
633 static int eth_probe (struct dev
*dev
, unsigned short *probe_addrs __unused
)
637 #ifdef INCLUDE_NS8390
638 unsigned short pci_probe_addrs
[] = { pci
->ioaddr
, 0 };
639 unsigned short *probe_addrs
= pci_probe_addrs
;
641 eth_vendor
= VENDOR_NONE
;
642 eth_drain_receiver
= 0;
648 /******************************************************************
649 Search for WD/SMC cards
650 ******************************************************************/
651 struct wd_board
*brd
;
652 unsigned short chksum
;
654 for (eth_asic_base
= WD_LOW_BASE
; eth_asic_base
<= WD_HIGH_BASE
;
655 eth_asic_base
+= 0x20) {
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)
665 if (eth_asic_base
> WD_HIGH_BASE
)
667 /* We've found a board */
668 eth_vendor
= VENDOR_WD
;
669 eth_nic_base
= eth_asic_base
+ WD_NIC_ADDR
;
671 nic
->ioaddr
= eth_nic_base
;
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;
677 printf("Unknown WD/SMC NIC type %hhX\n", c
);
678 return (0); /* Unknown type */
680 eth_flags
= brd
->flags
;
681 eth_memsize
= brd
->memsize
;
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
;
689 if ((c
& WD_SOFTCONFIG
) && (!(eth_flags
& FLAG_790
))) {
690 eth_bmem
= (0x80000 |
691 ((inb(eth_asic_base
+ WD_MSR
) & 0x3F) << 13));
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) {
699 eth_memsize
= brd
->memsize
;
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
);
706 DBG ( "\n%s base %4.4x", brd
->name
, eth_asic_base
);
707 if (eth_flags
& FLAG_790
) {
709 DBG ( ", PIO mode, addr %s\n", eth_ntoa ( nic
->node_addr
) );
711 eth_flags
|= FLAG_PIO
; /* force PIO mode */
712 outb(0, eth_asic_base
+WD_MSR
);
714 DBG ( ", Memory %x, MAC Addr %s\n", eth_bmem
, eth_ntoa ( nic
->node_addr
) );
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);
727 DBG (", Memory %x, MAC Addr %s\n", eth_bmem
, eth_ntoa ( nic
->node_addr
) );
729 outb(((unsigned)(eth_bmem
>> 13) & 0x3F) | 0x40, eth_asic_base
+WD_MSR
);
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
);
737 WD_LAAR_L16EN
| 1), eth_asic_base
+ WD_LAAR
);
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
753 nic
->flags
= 1; /* aui */
755 nic
->flags
= 0; /* no aui */
757 /******************************************************************
758 Search for 3Com 3c503 if no WD/SMC cards
759 ******************************************************************/
760 if (eth_vendor
== VENDOR_NONE
) {
762 int iobase_reg
, membase_reg
;
763 static unsigned short base
[] = {
764 0x300, 0x310, 0x330, 0x350,
765 0x250, 0x280, 0x2A0, 0x2E0, 0 };
767 /* Loop through possible addresses checking each one */
769 for (idx
= 0; (eth_nic_base
= base
[idx
]) != 0; ++idx
) {
771 eth_asic_base
= eth_nic_base
+ _3COM_ASIC_OFFSET
;
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.
777 eth_memsize
= MEM_16384
;
779 eth_rx_start
= 32 + D8390_TXBUF_SIZE
;
781 /* Check our base address. iobase and membase should */
782 /* both have a maximum of 1 bit set or be 0. */
784 iobase_reg
= inb(eth_asic_base
+ _3COM_BCFR
);
785 membase_reg
= inb(eth_asic_base
+ _3COM_PCFR
);
787 if ((iobase_reg
& (iobase_reg
- 1)) ||
788 (membase_reg
& (membase_reg
- 1)))
791 /* Now get the shared memory address */
795 switch (membase_reg
) {
796 case _3COM_PCFR_DC000
:
799 case _3COM_PCFR_D8000
:
802 case _3COM_PCFR_CC000
:
805 case _3COM_PCFR_C8000
:
809 eth_flags
|= FLAG_PIO
;
818 if (base
[idx
] == 0) /* not found */
821 eth_flags
|= FLAG_PIO
; /* force PIO mode */
824 eth_vendor
= VENDOR_3COM
;
827 /* Need this to make ns8390_poll() happy. */
829 eth_rmem
= eth_bmem
- 0x2000;
831 /* Reset NIC and ASIC */
833 outb(_3COM_CR_RST
| _3COM_CR_XSEL
, eth_asic_base
+ _3COM_CR
);
834 outb(_3COM_CR_XSEL
, eth_asic_base
+ _3COM_CR
);
836 /* Get our ethernet address */
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
)
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
);
848 DBG ( ", %s, MAC Addr %s\n", nic
->flags
? "AUI" : "internal xcvr",
849 eth_ntoa ( nic
->node_addr
) );
851 outb(_3COM_CR_XSEL
, eth_asic_base
+ _3COM_CR
);
853 * Initialize GA configuration register. Set bank and enable shared
854 * mem. We always use bank 1. Disable interrupts.
856 outb(_3COM_GACFR_RSEL
|
857 _3COM_GACFR_MBS0
| _3COM_GACFR_TCM
| _3COM_GACFR_NIM
, eth_asic_base
+ _3COM_GACFR
);
859 outb(0xff, eth_asic_base
+ _3COM_VPTR2
);
860 outb(0xff, eth_asic_base
+ _3COM_VPTR1
);
861 outb(0x00, eth_asic_base
+ _3COM_VPTR0
);
863 * Clear memory and verify that it worked (we use only 8K)
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");
875 * Initialize GA page/start/stop registers.
877 outb(eth_tx_start
, eth_asic_base
+ _3COM_PSTR
);
878 outb(eth_memsize
, eth_asic_base
+ _3COM_PSPR
);
881 #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
883 /******************************************************************
884 Search for NE1000/2000 if no WD/SMC or 3com cards
885 ******************************************************************/
887 if (eth_vendor
== VENDOR_NONE
) {
888 unsigned char romdata
[16];
889 unsigned char testbuf
[32];
891 static unsigned char test
[] = "NE*000 memory";
892 static unsigned short base
[] = {
897 /* if no addresses supplied, fall back on defaults */
898 if (probe_addrs
== 0 || probe_addrs
[0] == 0)
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
;
906 eth_rx_start
= 32 + D8390_TXBUF_SIZE
;
907 c
= inb(eth_asic_base
+ NE_RESET
);
908 outb(c
, eth_asic_base
+ NE_RESET
);
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 */
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
)))
924 eth_flags
|= FLAG_16BIT
;
925 eth_memsize
= MEM_32768
;
927 eth_rx_start
= 64 + D8390_TXBUF_SIZE
;
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
)))
937 if (eth_nic_base
== 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)];
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
) );
953 if (eth_vendor
== VENDOR_NONE
)
955 if (eth_vendor
!= VENDOR_3COM
)
958 nic
->nic_op
= &ns8390_operations
;
960 /* Based on PnP ISA map */
962 dev
->devid
.vendor_id
= htons(GENERIC_ISAPNP_VENDOR
);
963 dev
->devid
.device_id
= htons(0x812a);
966 dev
->devid
.vendor_id
= htons(GENERIC_ISAPNP_VENDOR
);
967 dev
->devid
.device_id
= htons(0x80f3);
970 dev
->devid
.vendor_id
= htons(GENERIC_ISAPNP_VENDOR
);
971 dev
->devid
.device_id
= htons(0x80d6);
977 struct isa_driver wd_driver __isa_driver
= {
983 ISA_ROM("wd","WD8003/8013, SMC8216/8416, SMC 83c790 (EtherEZ)");
987 struct isa_driver t503_driver __isa_driver
= {
993 ISA_ROM("3c503","3Com503, Etherlink II[/16]");
997 struct isa_driver ne_driver __isa_driver
= {
1003 ISA_ROM("ne","NE1000/2000 and clones");
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),
1022 PCI_DRIVER ( nepci_driver
, nepci_nics
, PCI_NO_CLASS
);
1024 DRIVER ( "NE2000/PCI", nic_driver
, pci_driver
, nepci_driver
,
1025 nepci_probe
, ns8390_disable
);
1027 #endif /* INCLUDE_NS8390 */