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

« back to all changes in this revision

Viewing changes to netboot/i82586.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
i82586 NIC driver for Etherboot
 
4
Ken Yap, January 1998
 
5
***************************************************************************/
 
6
 
 
7
/*
 
8
 * This program is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU General Public License as
 
10
 * published by the Free Software Foundation; either version 2, or (at
 
11
 * your option) any later version.
 
12
 */
 
13
 
 
14
#include "etherboot.h"
 
15
#include "nic.h"
 
16
#include "cards.h"
 
17
#include "timer.h"
 
18
 
 
19
#define udelay(n)       waiton_timer2(((n)*TICKS_PER_MS)/1000)
 
20
 
 
21
/* Sources of information:
 
22
 
 
23
   Donald Becker's excellent 3c507 driver in Linux
 
24
   Intel 82596 data sheet (yes, 82596; it has a 586 compatibility mode)
 
25
*/
 
26
 
 
27
/* Code below mostly stolen wholesale from 3c507.c driver in Linux */
 
28
 
 
29
/*
 
30
                Details of the i82586.
 
31
 
 
32
   You'll really need the databook to understand the details of this part,
 
33
   but the outline is that the i82586 has two separate processing units.
 
34
   Both are started from a list of three configuration tables, of which only
 
35
   the last, the System Control Block (SCB), is used after reset-time.  The SCB
 
36
   has the following fields:
 
37
                Status word
 
38
                Command word
 
39
                Tx/Command block addr.
 
40
                Rx block addr.
 
41
   The command word accepts the following controls for the Tx and Rx units:
 
42
  */
 
43
 
 
44
#define CUC_START       0x0100
 
45
#define CUC_RESUME      0x0200
 
46
#define CUC_SUSPEND     0x0300
 
47
#define RX_START        0x0010
 
48
#define RX_RESUME       0x0020
 
49
#define RX_SUSPEND      0x0030
 
50
 
 
51
/* The Rx unit uses a list of frame descriptors and a list of data buffer
 
52
   descriptors.  We use full-sized (1518 byte) data buffers, so there is
 
53
   a one-to-one pairing of frame descriptors to buffer descriptors.
 
54
 
 
55
   The Tx ("command") unit executes a list of commands that look like:
 
56
        Status word     Written by the 82586 when the command is done.
 
57
        Command word    Command in lower 3 bits, post-command action in upper 3
 
58
        Link word       The address of the next command.
 
59
        Parameters      (as needed).
 
60
 
 
61
        Some definitions related to the Command Word are:
 
62
 */
 
63
#define CMD_EOL         0x8000          /* The last command of the list, stop. */
 
64
#define CMD_SUSP        0x4000          /* Suspend after doing cmd. */
 
65
#define CMD_INTR        0x2000          /* Interrupt after doing cmd. */
 
66
 
 
67
enum commands {
 
68
        CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
 
69
        CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7};
 
70
 
 
71
/*
 
72
                Details of the EtherLink16 Implementation
 
73
 
 
74
  The 3c507 and NI5210 are generic shared-memory i82586 implementations.
 
75
  3c507: The host can map 16K, 32K, 48K, or 64K of the 64K memory into
 
76
  0x0[CD][08]0000, or all 64K into 0xF[02468]0000.
 
77
  NI5210: The host can map 8k or 16k at 0x[CDE][048C]000 but we
 
78
  assume 8k because to have 16k you cannot put a ROM on the NIC.
 
79
  */
 
80
 
 
81
/* Offsets from the base I/O address. */
 
82
 
 
83
#ifdef  INCLUDE_3C507
 
84
 
 
85
#define SA_DATA         0       /* Station address data, or 3Com signature. */
 
86
#define MISC_CTRL       6       /* Switch the SA_DATA banks, and bus config bits. */
 
87
#define RESET_IRQ       10      /* Reset the latched IRQ line. */
 
88
#define I82586_ATTN     11      /* Frob the 82586 Channel Attention line. */
 
89
#define ROM_CONFIG      13
 
90
#define MEM_CONFIG      14
 
91
#define IRQ_CONFIG      15
 
92
#define EL16_IO_EXTENT  16
 
93
 
 
94
/* The ID port is used at boot-time to locate the ethercard. */
 
95
#define ID_PORT         0x100
 
96
 
 
97
#endif
 
98
 
 
99
#ifdef  INCLUDE_NI5210
 
100
 
 
101
#define NI52_RESET      0  /* writing to this address, resets the i82586 */
 
102
#define I82586_ATTN     1  /* channel attention, kick the 586 */
 
103
 
 
104
#endif
 
105
 
 
106
#ifdef  INCLUDE_EXOS205
 
107
 
 
108
#define EXOS205_RESET   0  /* writing to this address, resets the i82586 */
 
109
#define I82586_ATTN     1  /* channel attention, kick the 586 */
 
110
 
 
111
#endif
 
112
 
 
113
/* Offsets to registers in the mailbox (SCB). */
 
114
#define iSCB_STATUS     0x8
 
115
#define iSCB_CMD        0xA
 
116
#define iSCB_CBL        0xC     /* Command BLock offset. */
 
117
#define iSCB_RFA        0xE     /* Rx Frame Area offset. */
 
118
 
 
119
/*  Since the 3c507 maps the shared memory window so that the last byte is
 
120
at 82586 address FFFF, the first byte is at 82586 address 0, 16K, 32K, or
 
121
48K corresponding to window sizes of 64K, 48K, 32K and 16K respectively.
 
122
We can account for this be setting the 'SBC Base' entry in the ISCP table
 
123
below for all the 16 bit offset addresses, and also adding the 'SCB Base'
 
124
value to all 24 bit physical addresses (in the SCP table and the TX and RX
 
125
Buffer Descriptors).
 
126
                                -Mark
 
127
*/
 
128
 
 
129
/*
 
130
  What follows in 'init_words[]' is the "program" that is downloaded to the
 
131
  82586 memory.  It's mostly tables and command blocks, and starts at the
 
132
  reset address 0xfffff6.  This is designed to be similar to the EtherExpress,
 
133
  thus the unusual location of the SCB at 0x0008.
 
134
 
 
135
  Even with the additional "don't care" values, doing it this way takes less
 
136
  program space than initializing the individual tables, and I feel it's much
 
137
  cleaner.
 
138
 
 
139
  The databook is particularly useless for the first two structures, I had
 
140
  to use the Crynwr driver as an example.
 
141
 
 
142
  The memory setup is as follows:
 
143
*/
 
144
 
 
145
#define CONFIG_CMD      0x18
 
146
#define SET_SA_CMD      0x24
 
147
#define SA_OFFSET       0x2A
 
148
#define IDLELOOP        0x30
 
149
#define TDR_CMD         0x38
 
150
#define TDR_TIME        0x3C
 
151
#define DUMP_CMD        0x40
 
152
#define DIAG_CMD        0x48
 
153
#define SET_MC_CMD      0x4E
 
154
#define DUMP_DATA       0x56    /* A 170 byte buffer for dump and Set-MC into. */
 
155
 
 
156
#define TX_BUF_START    0x0100
 
157
#define TX_BUF_SIZE     (1518+14+20+16) /* packet+header+TBD */
 
158
 
 
159
#define RX_BUF_START    0x1000
 
160
#define RX_BUF_SIZE     (1518+14+18)    /* packet+header+RBD */
 
161
#define RX_BUF_END      (mem_end - mem_start - 20)
 
162
 
 
163
/*
 
164
  That's it: only 86 bytes to set up the beast, including every extra
 
165
  command available.  The 170 byte buffer at DUMP_DATA is shared between the
 
166
  Dump command (called only by the diagnostic program) and the SetMulticastList
 
167
  command.
 
168
 
 
169
  To complete the memory setup you only have to write the station address at
 
170
  SA_OFFSET and create the Tx & Rx buffer lists.
 
171
 
 
172
  The Tx command chain and buffer list is setup as follows:
 
173
  A Tx command table, with the data buffer pointing to...
 
174
  A Tx data buffer descriptor.  The packet is in a single buffer, rather than
 
175
        chaining together several smaller buffers.
 
176
  A NoOp command, which initially points to itself,
 
177
  And the packet data.
 
178
 
 
179
  A transmit is done by filling in the Tx command table and data buffer,
 
180
  re-writing the NoOp command, and finally changing the offset of the last
 
181
  command to point to the current Tx command.  When the Tx command is finished,
 
182
  it jumps to the NoOp, when it loops until the next Tx command changes the
 
183
  "link offset" in the NoOp.  This way the 82586 never has to go through the
 
184
  slow restart sequence.
 
185
 
 
186
  The Rx buffer list is set up in the obvious ring structure.  We have enough
 
187
  memory (and low enough interrupt latency) that we can avoid the complicated
 
188
  Rx buffer linked lists by alway associating a full-size Rx data buffer with
 
189
  each Rx data frame.
 
190
 
 
191
  I currently use one transmit buffer starting at TX_BUF_START (0x0100), and
 
192
  use the rest of memory, from RX_BUF_START to RX_BUF_END, for Rx buffers.
 
193
 
 
194
  */
 
195
 
 
196
static unsigned short init_words[] = {
 
197
        /*      System Configuration Pointer (SCP). */
 
198
#if     defined(INCLUDE_3C507)
 
199
        0x0000,                                 /* Set bus size to 16 bits. */
 
200
#else
 
201
        0x0001,                                 /* Set bus size to 8 bits */
 
202
#endif
 
203
        0,0,                                    /* pad words. */
 
204
        0x0000,0x0000,                          /* ISCP phys addr, set in init_82586_mem(). */
 
205
 
 
206
        /*      Intermediate System Configuration Pointer (ISCP). */
 
207
        0x0001,                                 /* Status word that's cleared when init is done. */
 
208
        0x0008,0,0,                             /* SCB offset, (skip, skip) */
 
209
 
 
210
        /* System Control Block (SCB). */
 
211
        0,0xf000|RX_START|CUC_START,            /* SCB status and cmd. */
 
212
        CONFIG_CMD,                             /* Command list pointer, points to Configure. */
 
213
        RX_BUF_START,                           /* Rx block list. */
 
214
        0,0,0,0,                                /* Error count: CRC, align, buffer, overrun. */
 
215
 
 
216
        /* 0x0018: Configure command.  Change to put MAC data with packet. */
 
217
        0, CmdConfigure,                        /* Status, command. */
 
218
        SET_SA_CMD,                             /* Next command is Set Station Addr. */
 
219
        0x0804,                                 /* "4" bytes of config data, 8 byte FIFO. */
 
220
        0x2e40,                                 /* Magic values, including MAC data location. */
 
221
        0,                                      /* Unused pad word. */
 
222
 
 
223
        /* 0x0024: Setup station address command. */
 
224
        0, CmdSASetup,
 
225
        SET_MC_CMD,                             /* Next command. */
 
226
        0xaa00,0xb000,0x0bad,   /* Station address (to be filled in) */
 
227
 
 
228
        /* 0x0030: NOP, looping back to itself.  Point to first Tx buffer to Tx. */
 
229
        0, CmdNOp, IDLELOOP, 0 /* pad */,
 
230
 
 
231
        /* 0x0038: A unused Time-Domain Reflectometer command. */
 
232
        0, CmdTDR, IDLELOOP, 0,
 
233
 
 
234
        /* 0x0040: An unused Dump State command. */
 
235
        0, CmdDump, IDLELOOP, DUMP_DATA,
 
236
 
 
237
        /* 0x0048: An unused Diagnose command. */
 
238
        0, CmdDiagnose, IDLELOOP,
 
239
 
 
240
        /* 0x004E: An empty set-multicast-list command. */
 
241
        0, CmdMulticastList, IDLELOOP, 0,
 
242
};
 
243
 
 
244
/* NIC specific static variables go here */
 
245
 
 
246
static unsigned short           ioaddr, irq, scb_base;
 
247
static Address                  mem_start, mem_end;
 
248
static unsigned short           rx_head, rx_tail;
 
249
 
 
250
#define read_mem(m,s)   fmemcpy((char *)s, m, sizeof(s))
 
251
 
 
252
static void setup_rx_buffers(struct nic *nic)
 
253
{
 
254
        Address                 write_ptr;
 
255
        unsigned short          cur_rx_buf;
 
256
        static unsigned short   rx_cmd[16] = {
 
257
                0x0000,                 /* Rx status */
 
258
                0x0000,                 /* Rx command, only and last */
 
259
                RX_BUF_START,           /* Link (will be adjusted) */
 
260
                RX_BUF_START + 22,      /* Buffer offset (will be adjusted) */
 
261
                0x0000, 0x0000, 0x0000, /* Pad for dest addr */
 
262
                0x0000, 0x0000, 0x0000, /* Pad for source addr */
 
263
                0x0000,                 /* Pad for protocol */
 
264
                0x0000,                 /* Buffer: Actual count */
 
265
                -1,                     /* Buffer: Next (none) */
 
266
                RX_BUF_START + 0x20,    /* Buffer: Address low (+ scb_base) (will be adjusted) */
 
267
                0x0000,                 /* Buffer: Address high */
 
268
                0x8000 | (RX_BUF_SIZE - 0x20)
 
269
        };
 
270
 
 
271
        cur_rx_buf = rx_head = RX_BUF_START;
 
272
        do {            /* While there is room for one more buffer */
 
273
                write_ptr = mem_start + cur_rx_buf;
 
274
                /* adjust some contents */
 
275
                rx_cmd[1] = 0x0000;
 
276
                rx_cmd[2] = cur_rx_buf + RX_BUF_SIZE;
 
277
                rx_cmd[3] = cur_rx_buf + 22;
 
278
                rx_cmd[13] = cur_rx_buf + 0x20 + scb_base;
 
279
                memcpy((char *)write_ptr, (char *)rx_cmd, sizeof(rx_cmd));
 
280
                rx_tail = cur_rx_buf;
 
281
                cur_rx_buf += RX_BUF_SIZE;
 
282
        } while (cur_rx_buf <= RX_BUF_END - RX_BUF_SIZE);
 
283
        /* Terminate the list by setting the EOL bit and wrap ther pointer
 
284
           to make the list a ring. */
 
285
        write_ptr = mem_start + rx_tail;
 
286
        rx_cmd[1] = 0xC000;
 
287
        rx_cmd[2] = rx_head;
 
288
        memcpy((char *)write_ptr, (char *)rx_cmd, sizeof(unsigned short) * 3);
 
289
}
 
290
 
 
291
static void ack_status(void)
 
292
{
 
293
        unsigned short  cmd, status;
 
294
        unsigned short  *shmem = (short *)mem_start;
 
295
 
 
296
        cmd = (status = shmem[iSCB_STATUS>>1]) & 0xf000;
 
297
        if (status & 0x100)             /* CU suspended? */
 
298
                cmd |= CUC_RESUME;
 
299
        if ((status & 0x200) == 0)      /* CU not active? */
 
300
                cmd |= CUC_START;
 
301
        if (status & 0x010)             /* RU suspended? */
 
302
                cmd |= RX_RESUME;
 
303
        else if ((status & 0x040) == 0) /* RU not active? */
 
304
                cmd |= RX_START;
 
305
        if (cmd == 0)                   /* Nothing to do */
 
306
                return;
 
307
        shmem[iSCB_CMD>>1] = cmd;
 
308
#if     defined(DEBUG)
 
309
        printf("Status %hX Command %hX\n", status, cmd);
 
310
#endif
 
311
        outb(0, ioaddr + I82586_ATTN);
 
312
}
 
313
 
 
314
/**************************************************************************
 
315
RESET - Reset adapter
 
316
***************************************************************************/
 
317
 
 
318
static void i82586_reset(struct nic *nic)
 
319
{
 
320
        unsigned long   time;
 
321
        unsigned short  *shmem = (short *)mem_start;
 
322
 
 
323
        /* put the card in its initial state */
 
324
 
 
325
#ifdef  INCLUDE_3C507
 
326
        /* Enable loopback to protect the wire while starting up,
 
327
           and hold the 586 in reset during the memory initialisation. */
 
328
        outb(0x20, ioaddr + MISC_CTRL);
 
329
#endif
 
330
 
 
331
        /* Fix the ISCP address and base. */
 
332
        init_words[3] = scb_base;
 
333
        init_words[7] = scb_base;
 
334
 
 
335
        /* Write the words at 0xfff6. */
 
336
        /* Write the words at 0x0000. */
 
337
        /* Fill in the station address. */
 
338
        memcpy((char *)(mem_end - 10), (char *)init_words, 10);
 
339
        memcpy((char *)mem_start, (char *)&init_words[5], sizeof(init_words) - 10);
 
340
        memcpy((char *)mem_start + SA_OFFSET, nic->node_addr, ETH_ALEN);
 
341
        setup_rx_buffers(nic);
 
342
 
 
343
#ifdef  INCLUDE_3C507
 
344
        /* Start the 586 by releasing the reset line, but leave loopback. */
 
345
        outb(0xA0, ioaddr + MISC_CTRL);
 
346
#endif
 
347
 
 
348
        /* This was time consuming to track down; you need to give two channel
 
349
           attention signals to reliably start up the i82586. */
 
350
        outb(0, ioaddr + I82586_ATTN);
 
351
        time = currticks() + TICKS_PER_SEC;     /* allow 1 second to init */
 
352
        while (
 
353
                        shmem[iSCB_STATUS>>1] == 0)
 
354
        {
 
355
                if (currticks() > time)
 
356
                {
 
357
                        printf("i82586 initialisation timed out with status %hX, cmd %hX\n",
 
358
                                        shmem[iSCB_STATUS>>1], shmem[iSCB_CMD>>1]);
 
359
                        break;
 
360
                }
 
361
        }
 
362
        /* Issue channel-attn -- the 82586 won't start. */
 
363
        outb(0, ioaddr + I82586_ATTN);
 
364
 
 
365
#ifdef  INCLUDE_3C507
 
366
        /* Disable loopback. */
 
367
        outb(0x80, ioaddr + MISC_CTRL);
 
368
#endif
 
369
#if     defined(DEBUG)
 
370
        printf("i82586 status %hX, cmd %hX\n",
 
371
                        shmem[iSCB_STATUS>>1], shmem[iSCB_CMD>>1]);
 
372
#endif
 
373
}
 
374
 
 
375
/**************************************************************************
 
376
  POLL - Wait for a frame
 
377
 ***************************************************************************/
 
378
static int i82586_poll(struct nic *nic)
 
379
{
 
380
        int             status;
 
381
        unsigned short  rfd_cmd, next_rx_frame, data_buffer_addr,
 
382
        frame_status, pkt_len;
 
383
        unsigned short  *shmem = (short *)mem_start + rx_head;
 
384
 
 
385
        /* return true if there's an ethernet packet ready to read */
 
386
        if (
 
387
                        ((frame_status = shmem[0]) & 0x8000) == 0)
 
388
                return (0);             /* nope */
 
389
        rfd_cmd = shmem[1];
 
390
        next_rx_frame = shmem[2];
 
391
        data_buffer_addr = shmem[3];
 
392
        pkt_len = shmem[11];
 
393
        status = 0;
 
394
        if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22
 
395
                        || (pkt_len & 0xC000) != 0xC000)
 
396
                printf("\nRx frame corrupt, discarded");
 
397
        else if ((frame_status & 0x2000) == 0)
 
398
                printf("\nRx frame had error");
 
399
        else
 
400
        {
 
401
                /* We have a frame, copy it to our buffer */
 
402
                pkt_len &= 0x3FFF;
 
403
                memcpy(nic->packet, (char *)mem_start + rx_head + 0x20, pkt_len);
 
404
                /* Only packets not from ourself */
 
405
                if (memcmp(nic->packet + ETH_ALEN, nic->node_addr, ETH_ALEN) != 0)
 
406
                {
 
407
                        nic->packetlen = pkt_len;
 
408
                        status = 1;
 
409
                }
 
410
        }
 
411
        /* Clear the status word and set EOL on Rx frame */
 
412
        shmem[0] = 0;
 
413
        shmem[1] = 0xC000;
 
414
        *(short *)(mem_start + rx_tail + 2) = 0;
 
415
        rx_tail = rx_head;
 
416
        rx_head = next_rx_frame;
 
417
        ack_status();
 
418
        return (status);
 
419
}
 
420
 
 
421
/**************************************************************************
 
422
  TRANSMIT - Transmit a frame
 
423
 ***************************************************************************/
 
424
static void i82586_transmit(
 
425
                struct nic *nic,
 
426
                const char *d,                  /* Destination */
 
427
                unsigned int t,                 /* Type */
 
428
                unsigned int s,                 /* size */
 
429
                const char *p)                  /* Packet */
 
430
{
 
431
        Address                 bptr;
 
432
        unsigned short          type, z;
 
433
        static unsigned short   tx_cmd[11] = {
 
434
                0x0,                    /* Tx status */
 
435
                CmdTx,                  /* Tx command */
 
436
                TX_BUF_START+16,        /* Next command is a NoOp */
 
437
                TX_BUF_START+8,         /* Data Buffer offset */
 
438
                0x8000,                 /* | with size */
 
439
                0xffff,                 /* No next data buffer */
 
440
                TX_BUF_START+22,        /* + scb_base */
 
441
                0x0,                    /* Buffer address high bits (always zero) */
 
442
                0x0,                    /* Nop status */
 
443
                CmdNOp,                 /* Nop command */
 
444
                TX_BUF_START+16         /* Next is myself */
 
445
        };
 
446
        unsigned short  *shmem = (short *)mem_start + TX_BUF_START;
 
447
 
 
448
        /* send the packet to destination */
 
449
        /* adjust some contents */
 
450
        type = htons(t);
 
451
        if (s < ETH_ZLEN)
 
452
                s = ETH_ZLEN;
 
453
        tx_cmd[4] = (s + ETH_HLEN) | 0x8000;
 
454
        tx_cmd[6] = TX_BUF_START + 22 + scb_base;
 
455
        bptr = mem_start + TX_BUF_START;
 
456
        memcpy((char *)bptr, (char *)tx_cmd, sizeof(tx_cmd));
 
457
        bptr += sizeof(tx_cmd);
 
458
        memcpy((char *)bptr, d, ETH_ALEN);
 
459
        bptr += ETH_ALEN;
 
460
        memcpy((char *)bptr, nic->node_addr, ETH_ALEN);
 
461
        bptr += ETH_ALEN;
 
462
        memcpy((char *)bptr, (char *)&type, sizeof(type));
 
463
        bptr += sizeof(type);
 
464
        memcpy((char *)bptr, p, s);
 
465
        /* Change the offset in the IDLELOOP */
 
466
        *(unsigned short *)(mem_start + IDLELOOP + 4) = TX_BUF_START;
 
467
        /* Wait for transmit completion */
 
468
        while (
 
469
                        (shmem[0] & 0x2000) == 0)
 
470
                ;
 
471
        /* Change the offset in the IDLELOOP back and
 
472
           change the final loop to point here */
 
473
        *(unsigned short *)(mem_start + IDLELOOP + 4) = IDLELOOP;
 
474
        *(unsigned short *)(mem_start + TX_BUF_START + 20) = IDLELOOP;
 
475
        ack_status();
 
476
}
 
477
 
 
478
/**************************************************************************
 
479
  DISABLE - Turn off ethernet interface
 
480
 ***************************************************************************/
 
481
static void i82586_disable(struct nic *nic)
 
482
{
 
483
        unsigned short  *shmem = (short *)mem_start;
 
484
 
 
485
#if     0
 
486
        /* Flush the Tx and disable Rx. */
 
487
        shmem[iSCB_CMD>>1] = RX_SUSPEND | CUC_SUSPEND;
 
488
        outb(0, ioaddr + I82586_ATTN);
 
489
#ifdef  INCLUDE_NI5210
 
490
        outb(0, ioaddr + NI52_RESET);
 
491
#endif
 
492
#endif  /* 0 */
 
493
}
 
494
 
 
495
#ifdef  INCLUDE_3C507
 
496
 
 
497
static int t507_probe1(struct nic *nic, unsigned short ioaddr)
 
498
{
 
499
        int                     i;
 
500
        Address                 size;
 
501
        char                    mem_config;
 
502
        char                    if_port;
 
503
 
 
504
        if (inb(ioaddr) != '*' || inb(ioaddr+1) != '3'
 
505
                || inb(ioaddr+2) != 'C' || inb(ioaddr+3) != 'O')
 
506
                return (0);
 
507
        irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
 
508
        mem_config = inb(ioaddr + MEM_CONFIG);
 
509
        if (mem_config & 0x20)
 
510
        {
 
511
                size = 65536L;
 
512
                mem_start = 0xf00000L + (mem_config & 0x08 ? 0x080000L
 
513
                        : (((Address)mem_config & 0x3) << 17));
 
514
        }
 
515
        else
 
516
        {
 
517
                size = ((((Address)mem_config & 0x3) + 1) << 14);
 
518
                mem_start = 0x0c0000L + (((Address)mem_config & 0x18) << 12);
 
519
        }
 
520
        mem_end = mem_start + size;
 
521
        scb_base = 65536L - size;
 
522
        if_port = inb(ioaddr + ROM_CONFIG) & 0x80;
 
523
        /* Get station address */
 
524
        outb(0x01, ioaddr + MISC_CTRL);
 
525
        for (i = 0; i < ETH_ALEN; ++i)
 
526
        {
 
527
                nic->node_addr[i] = inb(ioaddr+i);
 
528
        }
 
529
        printf("\n3c507 ioaddr %#hX, IRQ %d, mem [%#X-%#X], %sternal xcvr, addr %!\n",
 
530
                ioaddr, irq, mem_start, mem_end, if_port ? "in" : "ex", nic->node_addr);
 
531
        return (1);
 
532
}
 
533
 
 
534
/**************************************************************************
 
535
PROBE - Look for an adapter, this routine's visible to the outside
 
536
***************************************************************************/
 
537
 
 
538
struct nic *t507_probe(struct nic *nic, unsigned short *probe_addrs)
 
539
{
 
540
        static unsigned char    init_ID_done = 0;
 
541
        unsigned short          lrs_state = 0xff;
 
542
        static unsigned short   io_addrs[] = { 0x300, 0x320, 0x340, 0x280, 0 };
 
543
        unsigned short          *p;
 
544
        int                     i;
 
545
 
 
546
        if (init_ID_done == 0)
 
547
        {
 
548
                /* Send the ID sequence to the ID_PORT to enable the board */
 
549
                outb(0x00, ID_PORT);
 
550
                for (i = 0; i < 255; ++i)
 
551
                {
 
552
                        outb(lrs_state, ID_PORT);
 
553
                        lrs_state <<= 1;
 
554
                        if (lrs_state & 0x100)
 
555
                                lrs_state ^= 0xe7;
 
556
                }
 
557
                outb(0x00, ID_PORT);
 
558
                init_ID_done = 1;
 
559
        }
 
560
        /* if probe_addrs is 0, then routine can use a hardwired default */
 
561
        if (probe_addrs == 0)
 
562
                probe_addrs = io_addrs;
 
563
        for (p = probe_addrs; (ioaddr = *p) != 0; ++p)
 
564
                if (t507_probe1(nic, ioaddr))
 
565
                        break;
 
566
        if (ioaddr != 0)
 
567
        {
 
568
                /* point to NIC specific routines */
 
569
                i82586_reset(nic);
 
570
                nic->reset = i82586_reset;
 
571
                nic->poll = i82586_poll;
 
572
                nic->transmit = i82586_transmit;
 
573
                nic->disable = i82586_disable;
 
574
                return nic;
 
575
        }
 
576
        /* else */
 
577
        {
 
578
                return 0;
 
579
        }
 
580
}
 
581
 
 
582
#endif
 
583
 
 
584
#ifdef  INCLUDE_NI5210
 
585
 
 
586
static int ni5210_probe2(void)
 
587
{
 
588
        unsigned short          i;
 
589
        unsigned short          shmem[10];
 
590
 
 
591
        /* Fix the ISCP address and base. */
 
592
        init_words[3] = scb_base;
 
593
        init_words[7] = scb_base;
 
594
 
 
595
        /* Write the words at 0xfff6. */
 
596
        /* Write the words at 0x0000. */
 
597
        memcpy((char *)(mem_end - 10), (char *)init_words, 10);
 
598
        memcpy((char *)mem_start, (char *)&init_words[5], sizeof(init_words) - 10);
 
599
        if (*(unsigned short *)mem_start != 1)
 
600
                return (0);
 
601
        outb(0, ioaddr + NI52_RESET);
 
602
        outb(0, ioaddr + I82586_ATTN);
 
603
        udelay(32);
 
604
        i = 50;
 
605
        while (
 
606
                shmem[iSCB_STATUS>>1] == 0)
 
607
        {
 
608
                if (--i == 0)
 
609
                {
 
610
                        printf("i82586 initialisation timed out with status %hX, cmd %hX\n",
 
611
                                shmem[iSCB_STATUS>>1], shmem[iSCB_CMD>>1]);
 
612
                        break;
 
613
                }
 
614
        }
 
615
        /* Issue channel-attn -- the 82586 won't start. */
 
616
        outb(0, ioaddr + I82586_ATTN);
 
617
        if (*(unsigned short *)mem_start != 0)
 
618
                return (0);
 
619
        return (1);
 
620
}
 
621
 
 
622
static int ni5210_probe1(struct nic *nic)
 
623
{
 
624
        int                     i;
 
625
        static Address          mem_addrs[] = {
 
626
                0xc0000, 0xc4000, 0xc8000, 0xcc000,
 
627
                0xd0000, 0xd4000, 0xd8000, 0xdc000,
 
628
                0xe0000, 0xe4000, 0xe8000, 0xec000,
 
629
                0 };
 
630
        Address                 *p;
 
631
 
 
632
        if (inb(ioaddr + 6) != 0x0 || inb(ioaddr + 7) != 0x55)
 
633
                return (0);
 
634
        scb_base = -8192;               /* assume 8k memory */
 
635
        for (p = mem_addrs; (mem_start = *p) != 0; ++p)
 
636
                if (mem_end = mem_start + 8192, ni5210_probe2())
 
637
                        break;
 
638
        if (mem_start == 0)
 
639
                return (0);
 
640
        /* Get station address */
 
641
        for (i = 0; i < ETH_ALEN; ++i)
 
642
        {
 
643
                nic->node_addr[i] = inb(ioaddr+i);
 
644
        }
 
645
        printf("\nNI5210 ioaddr %#hX, mem [%#X-%#X], addr %!\n",
 
646
                ioaddr, mem_start, mem_end, nic->node_addr);
 
647
        return (1);
 
648
}
 
649
 
 
650
struct nic *ni5210_probe(struct nic *nic, unsigned short *probe_addrs)
 
651
{
 
652
        /* missing entries are addresses usually already used */
 
653
        static unsigned short   io_addrs[] = {
 
654
                0x200, 0x208, 0x210, 0x218, 0x220, 0x228, 0x230, 0x238,
 
655
                0x240, 0x248, 0x250, 0x258, 0x260, 0x268, 0x270, /*Par*/
 
656
                0x280, 0x288, 0x290, 0x298, 0x2A0, 0x2A8, 0x2B0, 0x2B8,
 
657
                0x2C0, 0x2C8, 0x2D0, 0x2D8, 0x2E0, 0x2E8, 0x2F0, /*Ser*/
 
658
                0x300, 0x308, 0x310, 0x318, 0x320, 0x328, 0x330, 0x338,
 
659
                0x340, 0x348, 0x350, 0x358, 0x360, 0x368, 0x370, /*Par*/
 
660
                0x380, 0x388, 0x390, 0x398, 0x3A0, 0x3A8, /*Vid,Par*/
 
661
                0x3C0, 0x3C8, 0x3D0, 0x3D8, 0x3E0, 0x3E8, /*Ser*/
 
662
                0x0
 
663
        };
 
664
        unsigned short          *p;
 
665
        int                     i;
 
666
 
 
667
        /* if probe_addrs is 0, then routine can use a hardwired default */
 
668
        if (probe_addrs == 0)
 
669
                probe_addrs = io_addrs;
 
670
        for (p = probe_addrs; (ioaddr = *p) != 0; ++p)
 
671
                if (ni5210_probe1(nic))
 
672
                        break;
 
673
        if (ioaddr != 0)
 
674
        {
 
675
                /* point to NIC specific routines */
 
676
                i82586_reset(nic);
 
677
                nic->reset = i82586_reset;
 
678
                nic->poll = i82586_poll;
 
679
                nic->transmit = i82586_transmit;
 
680
                nic->disable = i82586_disable;
 
681
                return nic;
 
682
        }
 
683
        /* else */
 
684
        {
 
685
                return 0;
 
686
        }
 
687
}
 
688
#endif
 
689
 
 
690
#ifdef  INCLUDE_EXOS205
 
691
 
 
692
/*
 
693
 * Code to download to I186 in EXOS205
 
694
 */
 
695
 
 
696
static unsigned char exos_i186_init[] =
 
697
{
 
698
0x08,0x00,0x14,0x00,0x00,0x00,0xaa,0xfa,0x33,0xc0,0xba,0xfe,0xff,0xef,0xb8,0xf8,
 
699
0xff,0xe7,0xa0,0xb8,0x7c,0x00,0xe7,0xa4,0xb8,0xbc,0x80,0xe7,0xa8,0x8c,0xc8,0x8e,
 
700
0xd8,0xbb,0x2f,0x0e,0xc6,0x07,0xa5,0x33,0xc9,0xeb,0x00,0xeb,0x00,0xeb,0x00,0xe2,
 
701
0xf8,0xbe,0x2c,0x0e,0xba,0x02,0x05,0x33,0xdb,0xb9,0x03,0x00,0xec,0x24,0x0f,0x8a,
 
702
0xe0,0x02,0xd8,0x42,0x42,0xec,0x02,0xd8,0xd0,0xe0,0xd0,0xe0,0xd0,0xe0,0xd0,0xe0,
 
703
0x0a,0xc4,0x88,0x04,0x42,0x42,0x46,0xe2,0xe3,0x8a,0xe3,0xd0,0xec,0xd0,0xec,0xd0,
 
704
0xec,0xd0,0xec,0x80,0xe3,0x0f,0x02,0xe3,0x80,0xf4,0x05,0xec,0x3a,0xe0,0x74,0x05,
 
705
0xc6,0x04,0x5a,0xeb,0xfe,0xc6,0x04,0x55,0x33,0xc0,0x8e,0xd8,0xbe,0x38,0x00,0xc7,
 
706
0x04,0xce,0x0e,0x46,0x46,0xc7,0x04,0x00,0xff,0xfb,0xba,0x3c,0x00,0xb8,0x03,0x00,
 
707
0xef,0x33,0xdb,0x33,0xc9,0xbd,0x04,0x0f,0x90,0x90,0x90,0x90,0xe2,0xfa,0x43,0x2e,
 
708
0x89,0x5e,0x00,0xeb,0xf3,0x52,0xba,0x00,0x06,0xef,0x50,0x53,0x55,0xbd,0xf8,0x0e,
 
709
0x2e,0x8b,0x5e,0x00,0x43,0x2e,0x89,0x5e,0x00,0xba,0x22,0x00,0xb8,0x00,0x80,0xef,
 
710
0x5d,0x5b,0x58,0x5a,0xcf,0x49,0x4e,0x54,0x52,0x20,0x63,0x6e,0x74,0x2d,0x3e,0x00,
 
711
0x00,0x4c,0x4f,0x4f,0x50,0x20,0x63,0x6e,0x74,0x2d,0x3e,0x00,0x00,0x00,0x00,0x00,
 
712
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
713
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
714
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
715
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
716
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
717
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
718
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
719
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
720
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
721
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
722
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
723
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
724
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
725
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
726
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xea,0x30,0x0e,0x00,0xff,0x00,0x00,0x00,0x00,
 
727
0x00,0x00,0x00,0x00,0x00,0x00,00
 
728
};
 
729
 
 
730
/* These offsets are from the end of the i186 download code */
 
731
 
 
732
#define OFFSET_SEMA             0x1D1
 
733
#define OFFSET_ADDR             0x1D7
 
734
 
 
735
static int exos205_probe2(void)
 
736
{
 
737
        unsigned short          i;
 
738
        unsigned short          shmem[10];
 
739
 
 
740
        /* Fix the ISCP address and base. */
 
741
        init_words[3] = scb_base;
 
742
        init_words[7] = scb_base;
 
743
 
 
744
        /* Write the words at 0xfff6. */
 
745
        /* Write the words at 0x0000. */
 
746
        memcpy((char *)(mem_end - 10), (char *)init_words, 10);
 
747
        memcpy((char *)mem_start, (char *)&init_words[5], sizeof(init_words) - 10);
 
748
        if (*(unsigned short *)mem_start != 1)
 
749
                return (0);
 
750
        outb(0, ioaddr + EXOS205_RESET);
 
751
        outb(0, ioaddr + I82586_ATTN);
 
752
        i = 50;
 
753
        while (
 
754
                shmem[iSCB_STATUS>>1] == 0)
 
755
        {
 
756
                if (--i == 0)
 
757
                {
 
758
                        printf("i82586 initialisation timed out with status %hX, cmd %hX\n",
 
759
                                shmem[iSCB_STATUS>>1], shmem[iSCB_CMD>>1]);
 
760
                        break;
 
761
                }
 
762
        }
 
763
        /* Issue channel-attn -- the 82586 won't start. */
 
764
        outb(0, ioaddr + I82586_ATTN);
 
765
        if (*(unsigned short *)mem_start != 0)
 
766
                return (0);
 
767
        return (1);
 
768
}
 
769
 
 
770
static int exos205_probe1(struct nic *nic)
 
771
{
 
772
        int                     i;
 
773
        /* If you know the other addresses please let me know */
 
774
        static Address          mem_addrs[] = {
 
775
                0xcc000, 0 };
 
776
        Address                 *p;
 
777
 
 
778
        scb_base = -16384;              /* assume 8k memory */
 
779
        for (p = mem_addrs; (mem_start = *p) != 0; ++p)
 
780
                if (mem_end = mem_start + 16384, exos205_probe2())
 
781
                        break;
 
782
        if (mem_start == 0)
 
783
                return (0);
 
784
        /* Get station address */
 
785
        for (i = 0; i < ETH_ALEN; ++i)
 
786
        {
 
787
                nic->node_addr[i] = inb(ioaddr+i);
 
788
        }
 
789
        printf("\nEXOS205 ioaddr %#hX, mem [%#X-%#X], addr %!\n",
 
790
                ioaddr, mem_start, mem_end, nic->node_addr);
 
791
        return (1);
 
792
}
 
793
 
 
794
struct nic *exos205_probe(struct nic *nic, unsigned short *probe_addrs)
 
795
{
 
796
        /* If you know the other addresses, please let me know */
 
797
        static unsigned short   io_addrs[] = {
 
798
                0x310, 0x0
 
799
        };
 
800
        unsigned short          *p;
 
801
        int                     i;
 
802
 
 
803
        /* if probe_addrs is 0, then routine can use a hardwired default */
 
804
        if (probe_addrs == 0)
 
805
                probe_addrs = io_addrs;
 
806
        for (p = probe_addrs; (ioaddr = *p) != 0; ++p)
 
807
                if (exos205_probe1(nic))
 
808
                        break;
 
809
        if (ioaddr != 0)
 
810
        {
 
811
                /* point to NIC specific routines */
 
812
                i82586_reset(nic);
 
813
                nic->reset = i82586_reset;
 
814
                nic->poll = i82586_poll;
 
815
                nic->transmit = i82586_transmit;
 
816
                nic->disable = i82586_disable;
 
817
                return nic;
 
818
        }
 
819
        /* else */
 
820
        {
 
821
                return 0;
 
822
        }
 
823
}
 
824
 
 
825
#endif