iPXE - Open Source Boot Firmware

[build] Rename gPXE to iPXE
[ipxe.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 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 <ipxe/ethernet.h>
45 #ifdef  INCLUDE_NS8390
46 #include <ipxe/pci.h>
47 #else
48 #include <ipxe/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 **************************************************************************/
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 **************************************************************************/
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 **************************************************************************/
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 **************************************************************************/
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 **************************************************************************/
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 **************************************************************************/
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 **************************************************************************/
600 static void ns8390_disable ( struct nic *nic ) {
601         ns8390_reset(nic);
602 }
603
604 /**************************************************************************
605 NS8390_IRQ - Enable, Disable, or Force interrupts
606 **************************************************************************/
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
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  */