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