~ubuntu-branches/ubuntu/utopic/grub/utopic

« back to all changes in this revision

Viewing changes to netboot/ns8390.c

  • Committer: Bazaar Package Importer
  • Author(s): Jason Thomas
  • Date: 2002-02-04 15:35:01 UTC
  • Revision ID: james.westby@ubuntu.com-20020204153501-neulkag77r3a2m0v
Tags: upstream-0.91
ImportĀ upstreamĀ versionĀ 0.91

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
3c503 support added by Bill Paul (wpaul@ctr.columbia.edu) on 11/15/94
 
17
SMC8416 support added by Bill Paul (wpaul@ctr.columbia.edu) on 12/25/94
 
18
3c503 PIO support added by Jim Hague (jim.hague@acm.org) on 2/17/98
 
19
RX overrun by Klaus Espenlaub (espenlaub@informatik.uni-ulm.de) on 3/10/99
 
20
  parts taken from the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
 
21
 
 
22
**************************************************************************/
 
23
 
 
24
#include "etherboot.h"
 
25
#include "nic.h"
 
26
#include "ns8390.h"
 
27
#ifdef  INCLUDE_NS8390
 
28
#include "pci.h"
 
29
#endif
 
30
#include "cards.h"
 
31
 
 
32
static unsigned char    eth_vendor, eth_flags, eth_laar;
 
33
static unsigned short   eth_nic_base, eth_asic_base;
 
34
static unsigned char    eth_memsize, eth_rx_start, eth_tx_start;
 
35
static Address          eth_bmem, eth_rmem;
 
36
static unsigned char    eth_drain_receiver;
 
37
 
 
38
#ifdef  INCLUDE_WD
 
39
static struct wd_board {
 
40
        const char *name;
 
41
        char id;
 
42
        char flags;
 
43
        char memsize;
 
44
} wd_boards[] = {
 
45
        {"WD8003S",     TYPE_WD8003S,   0,                      MEM_8192},
 
46
        {"WD8003E",     TYPE_WD8003E,   0,                      MEM_8192},
 
47
        {"WD8013EBT",   TYPE_WD8013EBT, FLAG_16BIT,             MEM_16384},
 
48
        {"WD8003W",     TYPE_WD8003W,   0,                      MEM_8192},
 
49
        {"WD8003EB",    TYPE_WD8003EB,  0,                      MEM_8192},
 
50
        {"WD8013W",     TYPE_WD8013W,   FLAG_16BIT,             MEM_16384},
 
51
        {"WD8003EP/WD8013EP",
 
52
                        TYPE_WD8013EP,  0,                      MEM_8192},
 
53
        {"WD8013WC",    TYPE_WD8013WC,  FLAG_16BIT,             MEM_16384},
 
54
        {"WD8013EPC",   TYPE_WD8013EPC, FLAG_16BIT,             MEM_16384},
 
55
        {"SMC8216T",    TYPE_SMC8216T,  FLAG_16BIT | FLAG_790,  MEM_16384},
 
56
        {"SMC8216C",    TYPE_SMC8216C,  FLAG_16BIT | FLAG_790,  MEM_16384},
 
57
        {"SMC8416T",    TYPE_SMC8416T,  FLAG_16BIT | FLAG_790,  MEM_8192},
 
58
        {"SMC8416C/BT", TYPE_SMC8416C,  FLAG_16BIT | FLAG_790,  MEM_8192},
 
59
        {"SMC8013EBP",  TYPE_SMC8013EBP,FLAG_16BIT,             MEM_16384},
 
60
        {NULL,          0,              0,                      0}
 
61
};
 
62
#endif
 
63
 
 
64
#ifdef  INCLUDE_3C503
 
65
static unsigned char    t503_output;    /* AUI or internal xcvr (Thinnet) */
 
66
#endif
 
67
 
 
68
#if     defined(INCLUDE_WD)
 
69
#define eth_probe       wd_probe
 
70
#if     defined(INCLUDE_3C503) || defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
 
71
Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
 
72
#endif
 
73
#endif
 
74
 
 
75
#if     defined(INCLUDE_3C503)
 
76
#define eth_probe       t503_probe
 
77
#if     defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || defined(INCLUDE_WD)
 
78
Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
 
79
#endif
 
80
#endif
 
81
 
 
82
#if     defined(INCLUDE_NE)
 
83
#define eth_probe       ne_probe
 
84
#if     defined(INCLUDE_NS8390) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
 
85
Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
 
86
#endif
 
87
#endif
 
88
 
 
89
#if     defined(INCLUDE_NS8390)
 
90
#define eth_probe       nepci_probe
 
91
#if     defined(INCLUDE_NE) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
 
92
Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
 
93
#endif
 
94
#endif
 
95
 
 
96
#if     defined(INCLUDE_3C503)
 
97
#define ASIC_PIO        _3COM_RFMSB
 
98
#else
 
99
#if     defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
 
100
#define ASIC_PIO        NE_DATA
 
101
#endif
 
102
#endif
 
103
 
 
104
#if     defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM))
 
105
/**************************************************************************
 
106
ETH_PIO_READ - Read a frame via Programmed I/O
 
107
**************************************************************************/
 
108
static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt)
 
109
{
 
110
        if (eth_flags & FLAG_16BIT) { ++cnt; cnt &= ~1; }
 
111
        outb(D8390_COMMAND_RD2 |
 
112
                D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
 
113
        outb(cnt, eth_nic_base + D8390_P0_RBCR0);
 
114
        outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
 
115
        outb(src, eth_nic_base + D8390_P0_RSAR0);
 
116
        outb(src>>8, eth_nic_base + D8390_P0_RSAR1);
 
117
        outb(D8390_COMMAND_RD0 |
 
118
                D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
 
119
 
 
120
#ifdef  INCLUDE_3C503
 
121
        outb(src & 0xff, eth_asic_base + _3COM_DALSB);
 
122
        outb(src >> 8, eth_asic_base + _3COM_DAMSB);
 
123
        outb(t503_output | _3COM_CR_START, eth_asic_base + _3COM_CR);
 
124
#endif
 
125
 
 
126
        if (eth_flags & FLAG_16BIT)
 
127
                cnt >>= 1;
 
128
 
 
129
        while(cnt--) {
 
130
#ifdef  INCLUDE_3C503
 
131
                while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0)
 
132
                        ;
 
133
#endif
 
134
 
 
135
                if (eth_flags & FLAG_16BIT) {
 
136
                        *((unsigned short *)dst) = inw(eth_asic_base + ASIC_PIO);
 
137
                        dst += 2;
 
138
                }
 
139
                else
 
140
                        *(dst++) = inb(eth_asic_base + ASIC_PIO);
 
141
        }
 
142
 
 
143
#ifdef  INCLUDE_3C503
 
144
        outb(t503_output, eth_asic_base + _3COM_CR);
 
145
#endif
 
146
}
 
147
 
 
148
/**************************************************************************
 
149
ETH_PIO_WRITE - Write a frame via Programmed I/O
 
150
**************************************************************************/
 
151
static void eth_pio_write(const unsigned char *src, unsigned int dst, unsigned int cnt)
 
152
{
 
153
#ifdef  COMPEX_RL2000_FIX
 
154
        unsigned int x;
 
155
#endif  /* COMPEX_RL2000_FIX */
 
156
        if (eth_flags & FLAG_16BIT) { ++cnt; cnt &= ~1; }
 
157
        outb(D8390_COMMAND_RD2 |
 
158
                D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
 
159
        outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
 
160
        outb(cnt, eth_nic_base + D8390_P0_RBCR0);
 
161
        outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
 
162
        outb(dst, eth_nic_base + D8390_P0_RSAR0);
 
163
        outb(dst>>8, eth_nic_base + D8390_P0_RSAR1);
 
164
        outb(D8390_COMMAND_RD1 |
 
165
                D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
 
166
 
 
167
#ifdef  INCLUDE_3C503
 
168
        outb(dst & 0xff, eth_asic_base + _3COM_DALSB);
 
169
        outb(dst >> 8, eth_asic_base + _3COM_DAMSB);
 
170
 
 
171
        outb(t503_output | _3COM_CR_DDIR | _3COM_CR_START, eth_asic_base + _3COM_CR);
 
172
#endif
 
173
 
 
174
        if (eth_flags & FLAG_16BIT)
 
175
                cnt >>= 1;
 
176
 
 
177
        while(cnt--)
 
178
        {
 
179
#ifdef  INCLUDE_3C503
 
180
                while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0)
 
181
                        ;
 
182
#endif
 
183
 
 
184
                if (eth_flags & FLAG_16BIT) {
 
185
                        outw(*((unsigned short *)src), eth_asic_base + ASIC_PIO);
 
186
                        src += 2;
 
187
                }
 
188
                else
 
189
                        outb(*(src++), eth_asic_base + ASIC_PIO);
 
190
        }
 
191
 
 
192
#ifdef  INCLUDE_3C503
 
193
        outb(t503_output, eth_asic_base + _3COM_CR);
 
194
#else
 
195
#ifdef  COMPEX_RL2000_FIX
 
196
        for (x = 0;
 
197
                x < COMPEX_RL2000_TRIES &&
 
198
                (inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
 
199
                != D8390_ISR_RDC;
 
200
                ++x);
 
201
        if (x >= COMPEX_RL2000_TRIES)
 
202
                printf("Warning: Compex RL2000 aborted wait!\n");
 
203
#endif  /* COMPEX_RL2000_FIX */
 
204
        while((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
 
205
                != D8390_ISR_RDC);
 
206
#endif
 
207
}
 
208
#else
 
209
/**************************************************************************
 
210
ETH_PIO_READ - Dummy routine when NE2000 not compiled in
 
211
**************************************************************************/
 
212
static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt) {}
 
213
#endif
 
214
 
 
215
/**************************************************************************
 
216
NS8390_RESET - Reset adapter
 
217
**************************************************************************/
 
218
static void ns8390_reset(struct nic *nic)
 
219
{
 
220
        int i;
 
221
 
 
222
        eth_drain_receiver = 0;
 
223
#ifdef  INCLUDE_WD
 
224
        if (eth_flags & FLAG_790)
 
225
                outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
 
226
        else
 
227
#endif
 
228
                outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
 
229
                        D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
 
230
        if (eth_flags & FLAG_16BIT)
 
231
                outb(0x49, eth_nic_base+D8390_P0_DCR);
 
232
        else
 
233
                outb(0x48, eth_nic_base+D8390_P0_DCR);
 
234
        outb(0, eth_nic_base+D8390_P0_RBCR0);
 
235
        outb(0, eth_nic_base+D8390_P0_RBCR1);
 
236
        outb(0x20, eth_nic_base+D8390_P0_RCR);  /* monitor mode */
 
237
        outb(2, eth_nic_base+D8390_P0_TCR);
 
238
        outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
 
239
        outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART);
 
240
#ifdef  INCLUDE_WD
 
241
        if (eth_flags & FLAG_790) outb(0, eth_nic_base + 0x09);
 
242
#endif
 
243
        outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP);
 
244
        outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND);
 
245
        outb(0xFF, eth_nic_base+D8390_P0_ISR);
 
246
        outb(0, eth_nic_base+D8390_P0_IMR);
 
247
#ifdef  INCLUDE_WD
 
248
        if (eth_flags & FLAG_790)
 
249
                outb(D8390_COMMAND_PS1 |
 
250
                        D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
 
251
        else
 
252
#endif
 
253
                outb(D8390_COMMAND_PS1 |
 
254
                        D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
 
255
        for (i=0; i<ETH_ALEN; i++)
 
256
                outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i);
 
257
        for (i=0; i<ETH_ALEN; i++)
 
258
                outb(0xFF, eth_nic_base+D8390_P1_MAR0+i);
 
259
        outb(eth_rx_start, eth_nic_base+D8390_P1_CURR);
 
260
#ifdef  INCLUDE_WD
 
261
        if (eth_flags & FLAG_790)
 
262
                outb(D8390_COMMAND_PS0 |
 
263
                        D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
 
264
        else
 
265
#endif
 
266
                outb(D8390_COMMAND_PS0 |
 
267
                        D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
 
268
        outb(0xFF, eth_nic_base+D8390_P0_ISR);
 
269
        outb(0, eth_nic_base+D8390_P0_TCR);
 
270
        outb(4, eth_nic_base+D8390_P0_RCR);     /* allow broadcast frames */
 
271
 
 
272
#ifdef  INCLUDE_3C503
 
273
        /*
 
274
         * No way to tell whether or not we're supposed to use
 
275
         * the 3Com's transceiver unless the user tells us.
 
276
         * 'flags' should have some compile time default value
 
277
         * which can be changed from the command menu.
 
278
         */
 
279
        t503_output = (nic->flags) ? 0 : _3COM_CR_XSEL;
 
280
        outb(t503_output, eth_asic_base + _3COM_CR);
 
281
#endif
 
282
}
 
283
 
 
284
static int ns8390_poll(struct nic *nic);
 
285
 
 
286
#ifndef INCLUDE_3C503
 
287
/**************************************************************************
 
288
ETH_RX_OVERRUN - Bring adapter back to work after an RX overrun
 
289
**************************************************************************/
 
290
static void eth_rx_overrun(struct nic *nic)
 
291
{
 
292
        int start_time;
 
293
 
 
294
#ifdef  INCLUDE_WD
 
295
        if (eth_flags & FLAG_790)
 
296
                outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
 
297
        else
 
298
#endif
 
299
                outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
 
300
                        D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
 
301
 
 
302
        /* wait for at least 1.6ms - we wait one timer tick */
 
303
        start_time = currticks();
 
304
        while (currticks() - start_time <= 1)
 
305
                /* Nothing */;
 
306
 
 
307
        outb(0, eth_nic_base+D8390_P0_RBCR0);   /* reset byte counter */
 
308
        outb(0, eth_nic_base+D8390_P0_RBCR1);
 
309
 
 
310
        /*
 
311
         * Linux driver checks for interrupted TX here. This is not necessary,
 
312
         * because the transmit routine waits until the frame is sent.
 
313
         */
 
314
 
 
315
        /* enter loopback mode and restart NIC */
 
316
        outb(2, eth_nic_base+D8390_P0_TCR);
 
317
#ifdef  INCLUDE_WD
 
318
        if (eth_flags & FLAG_790)
 
319
                outb(D8390_COMMAND_PS0 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
 
320
        else
 
321
#endif
 
322
                outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
 
323
                        D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
 
324
 
 
325
        /* clear the RX ring, acknowledge overrun interrupt */
 
326
        eth_drain_receiver = 1;
 
327
        while (ns8390_poll(nic))
 
328
                /* Nothing */;
 
329
        eth_drain_receiver = 0;
 
330
        outb(D8390_ISR_OVW, eth_nic_base+D8390_P0_ISR);
 
331
 
 
332
        /* leave loopback mode - no packets to be resent (see Linux driver) */
 
333
        outb(0, eth_nic_base+D8390_P0_TCR);
 
334
}
 
335
#endif  /* INCLUDE_3C503 */
 
336
 
 
337
/**************************************************************************
 
338
NS8390_TRANSMIT - Transmit a frame
 
339
**************************************************************************/
 
340
static void ns8390_transmit(
 
341
        struct nic *nic,
 
342
        const char *d,                  /* Destination */
 
343
        unsigned int t,                 /* Type */
 
344
        unsigned int s,                 /* size */
 
345
        const char *p)                  /* Packet */
 
346
{
 
347
#ifdef  INCLUDE_3C503
 
348
        if (!(eth_flags & FLAG_PIO)) {
 
349
                memcpy((char *)eth_bmem, d, ETH_ALEN);  /* dst */
 
350
                memcpy((char *)eth_bmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
 
351
                *((char *)eth_bmem+12) = t>>8;          /* type */
 
352
                *((char *)eth_bmem+13) = t;
 
353
                memcpy((char *)eth_bmem+ETH_HLEN, p, s);
 
354
                s += ETH_HLEN;
 
355
                while (s < ETH_ZLEN) *((char *)eth_bmem+(s++)) = 0;
 
356
        }
 
357
#endif
 
358
 
 
359
#ifdef  INCLUDE_WD
 
360
        /* Memory interface */
 
361
        if (eth_flags & FLAG_16BIT) {
 
362
                outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
 
363
                inb(0x84);
 
364
        }
 
365
        if (eth_flags & FLAG_790) {
 
366
                outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
 
367
                inb(0x84);
 
368
        }
 
369
        inb(0x84);
 
370
        memcpy((char *)eth_bmem, d, ETH_ALEN);  /* dst */
 
371
        memcpy((char *)eth_bmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
 
372
        *((char *)eth_bmem+12) = t>>8;          /* type */
 
373
        *((char *)eth_bmem+13) = t;
 
374
        memcpy((char *)eth_bmem+ETH_HLEN, p, s);
 
375
        s += ETH_HLEN;
 
376
        while (s < ETH_ZLEN) *((char *)eth_bmem+(s++)) = 0;
 
377
        if (eth_flags & FLAG_790) {
 
378
                outb(0, eth_asic_base + WD_MSR);
 
379
                inb(0x84);
 
380
        }
 
381
        if (eth_flags & FLAG_16BIT) {
 
382
                outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
 
383
                inb(0x84);
 
384
        }
 
385
#endif
 
386
 
 
387
#if     defined(INCLUDE_3C503)
 
388
        if (eth_flags & FLAG_PIO) {
 
389
#endif
 
390
#if     defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM))
 
391
                /* Programmed I/O */
 
392
                unsigned short type;
 
393
                type = (t >> 8) | (t << 8);
 
394
                eth_pio_write(d, eth_tx_start<<8, ETH_ALEN);
 
395
                eth_pio_write(nic->node_addr, (eth_tx_start<<8)+ETH_ALEN, ETH_ALEN);
 
396
                /* bcc generates worse code without (const+const) below */
 
397
                eth_pio_write((unsigned char *)&type, (eth_tx_start<<8)+(ETH_ALEN+ETH_ALEN), 2);
 
398
                eth_pio_write(p, (eth_tx_start<<8)+ETH_HLEN, s);
 
399
                s += ETH_HLEN;
 
400
                if (s < ETH_ZLEN) s = ETH_ZLEN;
 
401
#endif
 
402
#if     defined(INCLUDE_3C503)
 
403
        }
 
404
#endif
 
405
 
 
406
#ifdef  INCLUDE_WD
 
407
        if (eth_flags & FLAG_790)
 
408
                outb(D8390_COMMAND_PS0 |
 
409
                        D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
 
410
        else
 
411
#endif
 
412
                outb(D8390_COMMAND_PS0 |
 
413
                        D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
 
414
        outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
 
415
        outb(s, eth_nic_base+D8390_P0_TBCR0);
 
416
        outb(s>>8, eth_nic_base+D8390_P0_TBCR1);
 
417
#ifdef  INCLUDE_WD
 
418
        if (eth_flags & FLAG_790)
 
419
                outb(D8390_COMMAND_PS0 |
 
420
                        D8390_COMMAND_TXP | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
 
421
        else
 
422
#endif
 
423
                outb(D8390_COMMAND_PS0 |
 
424
                        D8390_COMMAND_TXP | D8390_COMMAND_RD2 |
 
425
                        D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
 
426
}
 
427
 
 
428
/**************************************************************************
 
429
NS8390_POLL - Wait for a frame
 
430
**************************************************************************/
 
431
static int ns8390_poll(struct nic *nic)
 
432
{
 
433
        int ret = 0;
 
434
        unsigned char rstat, curr, next;
 
435
        unsigned short len, frag;
 
436
        unsigned short pktoff;
 
437
        unsigned char *p;
 
438
        struct ringbuffer pkthdr;
 
439
 
 
440
#ifndef INCLUDE_3C503
 
441
        /* avoid infinite recursion: see eth_rx_overrun() */
 
442
        if (!eth_drain_receiver && (inb(eth_nic_base+D8390_P0_ISR) & D8390_ISR_OVW)) {
 
443
                eth_rx_overrun(nic);
 
444
                return(0);
 
445
        }
 
446
#endif  /* INCLUDE_3C503 */
 
447
        rstat = inb(eth_nic_base+D8390_P0_RSR);
 
448
        if (!(rstat & D8390_RSTAT_PRX)) return(0);
 
449
        next = inb(eth_nic_base+D8390_P0_BOUND)+1;
 
450
        if (next >= eth_memsize) next = eth_rx_start;
 
451
        outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND);
 
452
        curr = inb(eth_nic_base+D8390_P1_CURR);
 
453
        outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND);
 
454
        if (curr >= eth_memsize) curr=eth_rx_start;
 
455
        if (curr == next) return(0);
 
456
#ifdef  INCLUDE_WD
 
457
        if (eth_flags & FLAG_16BIT) {
 
458
                outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
 
459
                inb(0x84);
 
460
        }
 
461
        if (eth_flags & FLAG_790) {
 
462
                outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
 
463
                inb(0x84);
 
464
        }
 
465
        inb(0x84);
 
466
#endif
 
467
        pktoff = next << 8;
 
468
        if (eth_flags & FLAG_PIO)
 
469
                eth_pio_read(pktoff, (char *)&pkthdr, 4);
 
470
        else
 
471
                memcpy(&pkthdr, (char *)eth_rmem + pktoff, 4);
 
472
        pktoff += sizeof(pkthdr);
 
473
        /* incoming length includes FCS so must sub 4 */
 
474
        len = pkthdr.len - 4;
 
475
        if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN
 
476
                || len > ETH_FRAME_LEN) {
 
477
                printf("Bogus packet, ignoring\n");
 
478
                return (0);
 
479
        }
 
480
        else {
 
481
                p = nic->packet;
 
482
                nic->packetlen = len;           /* available to caller */
 
483
                frag = (eth_memsize << 8) - pktoff;
 
484
                if (len > frag) {               /* We have a wrap-around */
 
485
                        /* read first part */
 
486
                        if (eth_flags & FLAG_PIO)
 
487
                                eth_pio_read(pktoff, p, frag);
 
488
                        else
 
489
                                memcpy(p, (char *)eth_rmem + pktoff, frag);
 
490
                        pktoff = eth_rx_start << 8;
 
491
                        p += frag;
 
492
                        len -= frag;
 
493
                }
 
494
                /* read second part */
 
495
                if (eth_flags & FLAG_PIO)
 
496
                        eth_pio_read(pktoff, p, len);
 
497
                else
 
498
                        memcpy(p, (char *)eth_rmem + pktoff, len);
 
499
                ret = 1;
 
500
        }
 
501
#ifdef  INCLUDE_WD
 
502
        if (eth_flags & FLAG_790) {
 
503
                outb(0, eth_asic_base + WD_MSR);
 
504
                inb(0x84);
 
505
        }
 
506
        if (eth_flags & FLAG_16BIT) {
 
507
                outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
 
508
                inb(0x84);
 
509
        }
 
510
        inb(0x84);
 
511
#endif
 
512
        next = pkthdr.next;             /* frame number of next packet */
 
513
        if (next == eth_rx_start)
 
514
                next = eth_memsize;
 
515
        outb(next-1, eth_nic_base+D8390_P0_BOUND);
 
516
        return(ret);
 
517
}
 
518
 
 
519
/**************************************************************************
 
520
NS8390_DISABLE - Turn off adapter
 
521
**************************************************************************/
 
522
static void ns8390_disable(struct nic *nic)
 
523
{
 
524
}
 
525
 
 
526
/**************************************************************************
 
527
ETH_PROBE - Look for an adapter
 
528
**************************************************************************/
 
529
#ifdef  INCLUDE_NS8390
 
530
struct nic *eth_probe(struct nic *nic, unsigned short *probe_addrs,
 
531
                      struct pci_device *pci)
 
532
#else
 
533
struct nic *eth_probe(struct nic *nic, unsigned short *probe_addrs)
 
534
#endif
 
535
{
 
536
        int i;
 
537
        struct wd_board *brd;
 
538
        unsigned short chksum;
 
539
        unsigned char c;
 
540
        eth_vendor = VENDOR_NONE;
 
541
        eth_drain_receiver = 0;
 
542
 
 
543
#ifdef  INCLUDE_WD
 
544
        /******************************************************************
 
545
        Search for WD/SMC cards
 
546
        ******************************************************************/
 
547
        for (eth_asic_base = WD_LOW_BASE; eth_asic_base <= WD_HIGH_BASE;
 
548
                eth_asic_base += 0x20) {
 
549
                chksum = 0;
 
550
                for (i=8; i<16; i++)
 
551
                        chksum += inb(eth_asic_base+i);
 
552
                /* Extra checks to avoid soundcard */
 
553
                if ((chksum & 0xFF) == 0xFF &&
 
554
                        inb(eth_asic_base+8) != 0xFF &&
 
555
                        inb(eth_asic_base+9) != 0xFF)
 
556
                        break;
 
557
        }
 
558
        if (eth_asic_base > WD_HIGH_BASE)
 
559
                return (0);
 
560
        /* We've found a board */
 
561
        eth_vendor = VENDOR_WD;
 
562
        eth_nic_base = eth_asic_base + WD_NIC_ADDR;
 
563
        c = inb(eth_asic_base+WD_BID);  /* Get board id */
 
564
        for (brd = wd_boards; brd->name; brd++)
 
565
                if (brd->id == c) break;
 
566
        if (!brd->name) {
 
567
                printf("Unknown WD/SMC NIC type %hhX\n", c);
 
568
                return (0);     /* Unknown type */
 
569
        }
 
570
        eth_flags = brd->flags;
 
571
        eth_memsize = brd->memsize;
 
572
        eth_tx_start = 0;
 
573
        eth_rx_start = D8390_TXBUF_SIZE;
 
574
        if ((c == TYPE_WD8013EP) &&
 
575
                (inb(eth_asic_base + WD_ICR) & WD_ICR_16BIT)) {
 
576
                        eth_flags = FLAG_16BIT;
 
577
                        eth_memsize = MEM_16384;
 
578
        }
 
579
        if ((c & WD_SOFTCONFIG) && (!(eth_flags & FLAG_790))) {
 
580
                eth_bmem = (0x80000 |
 
581
                 ((inb(eth_asic_base + WD_MSR) & 0x3F) << 13));
 
582
        } else
 
583
                eth_bmem = WD_DEFAULT_MEM;
 
584
        if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) {
 
585
                *((unsigned int *)(eth_bmem + 8192)) = (unsigned int)0;
 
586
                if (*((unsigned int *)(eth_bmem + 8192))) {
 
587
                        brd += 2;
 
588
                        eth_memsize = brd->memsize;
 
589
                }
 
590
        }
 
591
        outb(0x80, eth_asic_base + WD_MSR);     /* Reset */
 
592
        for (i=0; i<ETH_ALEN; i++) {
 
593
                nic->node_addr[i] = inb(i+eth_asic_base+WD_LAR);
 
594
        }
 
595
        printf("\n%s base %#hx, memory %#hx, addr %!\n",
 
596
                brd->name, eth_asic_base, eth_bmem, nic->node_addr);
 
597
        if (eth_flags & FLAG_790) {
 
598
                outb(WD_MSR_MENB, eth_asic_base+WD_MSR);
 
599
                outb((inb(eth_asic_base+0x04) |
 
600
                        0x80), eth_asic_base+0x04);
 
601
                outb((((unsigned)eth_bmem >> 13) & 0x0F) |
 
602
                        (((unsigned)eth_bmem >> 11) & 0x40) |
 
603
                        (inb(eth_asic_base+0x0B) & 0xB0), eth_asic_base+0x0B);
 
604
                outb((inb(eth_asic_base+0x04) &
 
605
                        ~0x80), eth_asic_base+0x04);
 
606
        } else {
 
607
                outb((((unsigned)eth_bmem >> 13) & 0x3F) | 0x40, eth_asic_base+WD_MSR);
 
608
        }
 
609
        if (eth_flags & FLAG_16BIT) {
 
610
                if (eth_flags & FLAG_790) {
 
611
                        eth_laar = inb(eth_asic_base + WD_LAAR);
 
612
                        outb(WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
 
613
                } else {
 
614
                        outb((eth_laar =
 
615
                                WD_LAAR_L16EN | 1), eth_asic_base + WD_LAAR);
 
616
/*
 
617
        The previous line used to be
 
618
                                WD_LAAR_M16EN | WD_LAAR_L16EN | 1));
 
619
        jluke@deakin.edu.au reported that removing WD_LAAR_M16EN made
 
620
        it work for WD8013s.  This seems to work for my 8013 boards. I
 
621
        don't know what is really happening.  I wish I had data sheets
 
622
        or more time to decode the Linux driver. - Ken
 
623
*/
 
624
                }
 
625
                inb(0x84);
 
626
        }
 
627
#endif
 
628
#ifdef  INCLUDE_3C503
 
629
        /******************************************************************
 
630
        Search for 3Com 3c503 if no WD/SMC cards
 
631
        ******************************************************************/
 
632
        if (eth_vendor == VENDOR_NONE) {
 
633
                int     idx;
 
634
                int     iobase_reg, membase_reg;
 
635
                static unsigned short   base[] = {
 
636
                        0x300, 0x310, 0x330, 0x350,
 
637
                        0x250, 0x280, 0x2A0, 0x2E0, 0 };
 
638
 
 
639
                /* Loop through possible addresses checking each one */
 
640
 
 
641
                for (idx = 0; (eth_nic_base = base[idx]) != 0; ++idx) {
 
642
 
 
643
                        eth_asic_base = eth_nic_base + _3COM_ASIC_OFFSET;
 
644
/*
 
645
 * Note that we use the same settings for both 8 and 16 bit cards:
 
646
 * both have an 8K bank of memory at page 1 while only the 16 bit
 
647
 * cards have a bank at page 0.
 
648
 */
 
649
                        eth_memsize = MEM_16384;
 
650
                        eth_tx_start = 32;
 
651
                        eth_rx_start = 32 + D8390_TXBUF_SIZE;
 
652
 
 
653
                /* Check our base address. iobase and membase should */
 
654
                /* both have a maximum of 1 bit set or be 0. */
 
655
 
 
656
                        iobase_reg = inb(eth_asic_base + _3COM_BCFR);
 
657
                        membase_reg = inb(eth_asic_base + _3COM_PCFR);
 
658
 
 
659
                        if ((iobase_reg & (iobase_reg - 1)) ||
 
660
                                (membase_reg & (membase_reg - 1)))
 
661
                                continue;               /* nope */
 
662
 
 
663
                /* Now get the shared memory address */
 
664
 
 
665
                        eth_flags = 0;
 
666
 
 
667
                        switch (membase_reg) {
 
668
                                case _3COM_PCFR_DC000:
 
669
                                        eth_bmem = 0xdc000;
 
670
                                        break;
 
671
                                case _3COM_PCFR_D8000:
 
672
                                        eth_bmem = 0xd8000;
 
673
                                        break;
 
674
                                case _3COM_PCFR_CC000:
 
675
                                        eth_bmem = 0xcc000;
 
676
                                        break;
 
677
                                case _3COM_PCFR_C8000:
 
678
                                        eth_bmem = 0xc8000;
 
679
                                        break;
 
680
                                case _3COM_PCFR_PIO:
 
681
                                        eth_flags |= FLAG_PIO;
 
682
                                        eth_bmem = 0;
 
683
                                        break;
 
684
                                default:
 
685
                                        continue;       /* nope */
 
686
                                }
 
687
                        break;
 
688
                }
 
689
 
 
690
                if (base[idx] == 0)             /* not found */
 
691
                        return (0);
 
692
#ifndef T503_SHMEM
 
693
                eth_flags |= FLAG_PIO;          /* force PIO mode */
 
694
                eth_bmem = 0;
 
695
#endif
 
696
                eth_vendor = VENDOR_3COM;
 
697
 
 
698
 
 
699
        /* Need this to make ns8390_poll() happy. */
 
700
 
 
701
                eth_rmem = eth_bmem - 0x2000;
 
702
 
 
703
        /* Reset NIC and ASIC */
 
704
 
 
705
                outb(_3COM_CR_RST | _3COM_CR_XSEL, eth_asic_base + _3COM_CR );
 
706
                outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR );
 
707
 
 
708
        /* Get our ethernet address */
 
709
 
 
710
                outb(_3COM_CR_EALO | _3COM_CR_XSEL, eth_asic_base + _3COM_CR);
 
711
                printf("\n3Com 3c503 base %#hx, ", eth_nic_base);
 
712
                if (eth_flags & FLAG_PIO)
 
713
                        printf("PIO mode");
 
714
                else
 
715
                        printf("memory %#hx", eth_bmem);
 
716
                for (i=0; i<ETH_ALEN; i++) {
 
717
                        nic->node_addr[i] = inb(eth_nic_base+i);
 
718
                }
 
719
                printf(", %s, addr %!\n", nic->flags ? "AUI" : "internal xcvr",
 
720
                        nic->node_addr);
 
721
                outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR);
 
722
        /*
 
723
         * Initialize GA configuration register. Set bank and enable shared
 
724
         * mem. We always use bank 1. Disable interrupts.
 
725
         */
 
726
                outb(_3COM_GACFR_RSEL |
 
727
                        _3COM_GACFR_MBS0 | _3COM_GACFR_TCM | _3COM_GACFR_NIM, eth_asic_base + _3COM_GACFR);
 
728
 
 
729
                outb(0xff, eth_asic_base + _3COM_VPTR2);
 
730
                outb(0xff, eth_asic_base + _3COM_VPTR1);
 
731
                outb(0x00, eth_asic_base + _3COM_VPTR0);
 
732
        /*
 
733
         * Clear memory and verify that it worked (we use only 8K)
 
734
         */
 
735
 
 
736
                if (!(eth_flags & FLAG_PIO)) {
 
737
                        memset((char *)eth_bmem, 0, 0x2000);
 
738
                        for(i = 0; i < 0x2000; ++i)
 
739
                                if (*(((char *)eth_bmem)+i)) {
 
740
                                        printf ("Failed to clear 3c503 shared mem.\n");
 
741
                                        return (0);
 
742
                                }
 
743
                }
 
744
        /*
 
745
         * Initialize GA page/start/stop registers.
 
746
         */
 
747
                outb(eth_tx_start, eth_asic_base + _3COM_PSTR);
 
748
                outb(eth_memsize, eth_asic_base + _3COM_PSPR);
 
749
        }
 
750
#endif
 
751
#if     defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
 
752
        /******************************************************************
 
753
        Search for NE1000/2000 if no WD/SMC or 3com cards
 
754
        ******************************************************************/
 
755
        if (eth_vendor == VENDOR_NONE) {
 
756
                char romdata[16], testbuf[32];
 
757
                int idx;
 
758
                static char test[] = "NE*000 memory";
 
759
                static unsigned short base[] = {
 
760
#ifdef  NE_SCAN
 
761
                        NE_SCAN,
 
762
#endif
 
763
                        0 };
 
764
                /* if no addresses supplied, fall back on defaults */
 
765
                if (probe_addrs == 0 || probe_addrs[0] == 0)
 
766
                        probe_addrs = base;
 
767
                eth_bmem = 0;           /* No shared memory */
 
768
                for (idx = 0; (eth_nic_base = probe_addrs[idx]) != 0; ++idx) {
 
769
                        eth_flags = FLAG_PIO;
 
770
                        eth_asic_base = eth_nic_base + NE_ASIC_OFFSET;
 
771
                        eth_memsize = MEM_16384;
 
772
                        eth_tx_start = 32;
 
773
                        eth_rx_start = 32 + D8390_TXBUF_SIZE;
 
774
                        c = inb(eth_asic_base + NE_RESET);
 
775
                        outb(c, eth_asic_base + NE_RESET);
 
776
                        inb(0x84);
 
777
                        outb(D8390_COMMAND_STP |
 
778
                                D8390_COMMAND_RD2, eth_nic_base + D8390_P0_COMMAND);
 
779
                        outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
 
780
                        outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
 
781
                        outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
 
782
                        outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
 
783
#ifdef  NS8390_FORCE_16BIT
 
784
                        eth_flags |= FLAG_16BIT;        /* force 16-bit mode */
 
785
#endif
 
786
 
 
787
                        eth_pio_write(test, 8192, sizeof(test));
 
788
                        eth_pio_read(8192, testbuf, sizeof(test));
 
789
                        if (!memcmp(test, testbuf, sizeof(test)))
 
790
                                break;
 
791
                        eth_flags |= FLAG_16BIT;
 
792
                        eth_memsize = MEM_32768;
 
793
                        eth_tx_start = 64;
 
794
                        eth_rx_start = 64 + D8390_TXBUF_SIZE;
 
795
                        outb(D8390_DCR_WTS |
 
796
                                D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
 
797
                        outb(MEM_16384, eth_nic_base + D8390_P0_PSTART);
 
798
                        outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP);
 
799
                        eth_pio_write(test, 16384, sizeof(test));
 
800
                        eth_pio_read(16384, testbuf, sizeof(test));
 
801
                        if (!memcmp(testbuf, test, sizeof(test)))
 
802
                                break;
 
803
                }
 
804
                if (eth_nic_base == 0)
 
805
                        return (0);
 
806
                if (eth_nic_base > ISA_MAX_ADDR)        /* PCI probably */
 
807
                        eth_flags |= FLAG_16BIT;
 
808
                eth_vendor = VENDOR_NOVELL;
 
809
                eth_pio_read(0, romdata, sizeof(romdata));
 
810
                for (i=0; i<ETH_ALEN; i++) {
 
811
                        nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)];
 
812
                }
 
813
                printf("\nNE%c000 base %#hx, addr %!\n",
 
814
                        (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base,
 
815
                        nic->node_addr);
 
816
        }
 
817
#endif
 
818
        if (eth_vendor == VENDOR_NONE)
 
819
                return(0);
 
820
        if (eth_vendor != VENDOR_3COM)
 
821
                eth_rmem = eth_bmem;
 
822
        ns8390_reset(nic);
 
823
        nic->reset = ns8390_reset;
 
824
        nic->poll = ns8390_poll;
 
825
        nic->transmit = ns8390_transmit;
 
826
        nic->disable = ns8390_disable;
 
827
        return(nic);
 
828
}
 
829
 
 
830
/*
 
831
 * Local variables:
 
832
 *  c-basic-offset: 8
 
833
 * End:
 
834
 */
 
835