source: bootcd/isolinux/syslinux-6.03/gpxe/src/drivers/net/ns8390.c

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 31.4 KB
RevLine 
[e16e8f2]1/**************************************************************************
2ETHERBOOT -  BOOTP/TFTP Bootstrap Program
3
4Author: 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
16Multicast support added by Timothy Legge (timlegge@users.sourceforge.net) 09/28/2003
17Relocation support added by Ken Yap (ken_yap@users.sourceforge.net) 28/12/02
183c503 support added by Bill Paul (wpaul@ctr.columbia.edu) on 11/15/94
19SMC8416 support added by Bill Paul (wpaul@ctr.columbia.edu) on 12/25/94
203c503 PIO support added by Jim Hague (jim.hague@acm.org) on 2/17/98
21RX 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)
23SMC8416 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
28FILE_LICENCE ( BSD2 );
29
30/* #warning "ns8390.c: FIXME: split ISA and PCI, clean up" */
31
32#if 1
33
34#if !defined(INCLUDE_NS8390) && !defined(INCLUDE_WD) && \
35    !defined(INCLUDE_NE) && !defined(INCLUDE_3C503)
36  /* The driver named ns8390 is the PCI driver, often called
37     "PCI ne2000 clones". */
38# define INCLUDE_NS8390 1
39#endif
40
41#include "etherboot.h"
42#include "nic.h"
43#include "ns8390.h"
44#include <gpxe/ethernet.h>
45#ifdef  INCLUDE_NS8390
46#include <gpxe/pci.h>
47#else
48#include <gpxe/isa.h>
49#endif
50
51static unsigned char    eth_vendor, eth_flags;
52#ifdef  INCLUDE_WD
53static unsigned char    eth_laar;
54#endif
55static unsigned short   eth_nic_base, eth_asic_base;
56static unsigned char    eth_memsize, eth_rx_start, eth_tx_start;
57static Address          eth_bmem, eth_rmem;
58static unsigned char    eth_drain_receiver;
59
60#ifdef  INCLUDE_WD
61static 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
87static 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)
94Error 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)
101Error 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)
108Error 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)
115Error 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/**************************************************************************
129ETH_PIO_READ - Read a frame via Programmed I/O
130**************************************************************************/
131static 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/**************************************************************************
176ETH_PIO_WRITE - Write a frame via Programmed I/O
177**************************************************************************/
178static 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/**************************************************************************
243ETH_PIO_READ - Dummy routine when NE2000 not compiled in
244**************************************************************************/
245static void eth_pio_read(unsigned int src __unused, unsigned char *dst  __unused, unsigned int cnt __unused) {}
246#endif
247
248
249/**************************************************************************
250enable_multycast - Enable Multicast
251**************************************************************************/
252static 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/**************************************************************************
270NS8390_RESET - Reset adapter
271**************************************************************************/
272static 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
347static int ns8390_poll(struct nic *nic, int retrieve);
348
349#ifndef INCLUDE_3C503
350/**************************************************************************
351ETH_RX_OVERRUN - Bring adapter back to work after an RX overrun
352**************************************************************************/
353static 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/**************************************************************************
401NS8390_TRANSMIT - Transmit a frame
402**************************************************************************/
403static 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/**************************************************************************
500NS8390_POLL - Wait for a frame
501**************************************************************************/
502static 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/**************************************************************************
598NS8390_DISABLE - Turn off adapter
599**************************************************************************/
600static void ns8390_disable ( struct nic *nic ) {
601        ns8390_reset(nic);
602}
603
604/**************************************************************************
605NS8390_IRQ - Enable, Disable, or Force interrupts
606**************************************************************************/
607static 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
619static struct nic_operations ns8390_operations;
620static struct nic_operations ns8390_operations = {
621        .connect        = dummy_connect,
622        .poll           = ns8390_poll,
623        .transmit       = ns8390_transmit,
624        .irq            = ns8390_irq,
625};
626
627/**************************************************************************
628ETH_PROBE - Look for an adapter
629**************************************************************************/
630#ifdef  INCLUDE_NS8390
631static int eth_probe (struct nic *nic, struct pci_device *pci)
632#else
633static 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
977struct isa_driver wd_driver __isa_driver = {
978        .type    = NIC_DRIVER,
979        .name    = "WD",
980        .probe   = wd_probe,
981        .ioaddrs = 0,
982};
983ISA_ROM("wd","WD8003/8013, SMC8216/8416, SMC 83c790 (EtherEZ)");
984#endif
985
986#ifdef  INCLUDE_3C503
987struct isa_driver t503_driver __isa_driver = {
988        .type    = NIC_DRIVER,
989        .name    = "3C503",
990        .probe   = t503_probe,
991        .ioaddrs = 0,
992};
993ISA_ROM("3c503","3Com503, Etherlink II[/16]");
994#endif
995
996#ifdef  INCLUDE_NE
997struct isa_driver ne_driver __isa_driver = {
998        .type    = NIC_DRIVER,
999        .name    = "NE*000",
1000        .probe   = ne_probe,
1001        .ioaddrs = 0,
1002};
1003ISA_ROM("ne","NE1000/2000 and clones");
1004#endif
1005
1006#ifdef  INCLUDE_NS8390
1007static struct pci_device_id nepci_nics[] = {
1008/* A few NE2000 PCI clones, list not exhaustive */
1009PCI_ROM(0x10ec, 0x8029, "rtl8029",      "Realtek 8029", 0),
1010PCI_ROM(0x1186, 0x0300, "dlink-528",    "D-Link DE-528", 0),
1011PCI_ROM(0x1050, 0x0940, "winbond940",   "Winbond NE2000-PCI", 0),               /* Winbond 86C940 / 89C940 */
1012PCI_ROM(0x1050, 0x5a5a, "winbond940f",  "Winbond W89c940F", 0),         /* Winbond 89C940F */
1013PCI_ROM(0x11f6, 0x1401, "compexrl2000", "Compex ReadyLink 2000", 0),
1014PCI_ROM(0x8e2e, 0x3000, "ktiet32p2",    "KTI ET32P2", 0),
1015PCI_ROM(0x4a14, 0x5000, "nv5000sc",     "NetVin NV5000SC", 0),
1016PCI_ROM(0x12c3, 0x0058, "holtek80232",  "Holtek HT80232", 0),
1017PCI_ROM(0x12c3, 0x5598, "holtek80229",  "Holtek HT80229", 0),
1018PCI_ROM(0x10bd, 0x0e34, "surecom-ne34", "Surecom NE34", 0),
1019PCI_ROM(0x1106, 0x0926, "via86c926",    "Via 86c926", 0),
1020};
1021
1022PCI_DRIVER ( nepci_driver, nepci_nics, PCI_NO_CLASS );
1023
1024DRIVER ( "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 */
Note: See TracBrowser for help on using the repository browser.