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 **************************************************************************/
eth_pio_write(const unsigned char * src,unsigned int dst,unsigned int cnt)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 **************************************************************************/
enable_multicast(unsigned short eth_nic_base)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 **************************************************************************/
ns8390_reset(struct nic * nic)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 **************************************************************************/
eth_rx_overrun(struct nic * nic)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 **************************************************************************/
ns8390_transmit(struct nic * nic,const char * d,unsigned int t,unsigned int s,const char * p)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 **************************************************************************/
ns8390_poll(struct nic * nic,int retrieve)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 **************************************************************************/
ns8390_disable(struct nic * nic)600 static void ns8390_disable ( struct nic *nic ) {
601 ns8390_reset(nic);
602 }
603
604 /**************************************************************************
605 NS8390_IRQ - Enable, Disable, or Force interrupts
606 **************************************************************************/
ns8390_irq(struct nic * nic __unused,irq_action_t action __unused)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
eth_probe(struct nic * nic,struct pci_device * pci)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 */
1038