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