OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [net/] [e2100.c] - Blame information for rev 1777

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1626 jcastillo
/* e2100.c: A Cabletron E2100 series ethernet driver for linux. */
2
/*
3
        Written 1993-1994 by Donald Becker.
4
 
5
        Copyright 1994 by Donald Becker.
6
        Copyright 1993 United States Government as represented by the
7
        Director, National Security Agency.  This software may be used and
8
        distributed according to the terms of the GNU Public License,
9
        incorporated herein by reference.
10
 
11
        This is a driver for the Cabletron E2100 series ethercards.
12
 
13
        The Author may be reached as becker@cesdis.gsfc.nasa.gov, or
14
        C/O Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
15
 
16
        The E2100 series ethercard is a fairly generic shared memory 8390
17
        implementation.  The only unusual aspect is the way the shared memory
18
        registers are set: first you do an inb() in what is normally the
19
        station address region, and the low three bits of next outb() *address*
20
        is used as the write value for that register.  Either someone wasn't
21
        too used to dem bit en bites, or they were trying to obfuscate the
22
        programming interface.
23
 
24
        There is an additional complication when setting the window on the packet
25
        buffer.  You must first do a read into the packet buffer region with the
26
        low 8 address bits the address setting the page for the start of the packet
27
        buffer window, and then do the above operation.  See mem_on() for details.
28
 
29
        One bug on the chip is that even a hard reset won't disable the memory
30
        window, usually resulting in a hung machine if mem_off() isn't called.
31
        If this happens, you must power down the machine for about 30 seconds.
32
*/
33
 
34
static const char *version =
35
        "e2100.c:v1.01 7/21/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
36
 
37
#include <linux/module.h>
38
 
39
#include <linux/kernel.h>
40
#include <linux/sched.h>
41
#include <linux/errno.h>
42
#include <linux/string.h>
43
#include <linux/ioport.h>
44
#include <linux/netdevice.h>
45
#include <linux/etherdevice.h>
46
 
47
#include <asm/io.h>
48
#include <asm/system.h>
49
 
50
#include "8390.h"
51
 
52
static int e21_probe_list[] = {0x300, 0x280, 0x380, 0x220, 0};
53
 
54
/* Offsets from the base_addr.
55
   Read from the ASIC register, and the low three bits of the next outb()
56
   address is used to set the corresponding register. */
57
#define E21_NIC_OFFSET  0               /* Offset to the 8390 NIC. */
58
#define E21_ASIC                0x10
59
#define E21_MEM_ENABLE  0x10
60
#define  E21_MEM_ON             0x05    /* Enable memory in 16 bit mode. */
61
#define  E21_MEM_ON_8   0x07    /* Enable memory in  8 bit mode. */
62
#define E21_MEM_BASE    0x11    
63
#define E21_IRQ_LOW             0x12    /* The low three bits of the IRQ number. */
64
#define E21_IRQ_HIGH    0x14    /* The high IRQ bit and media select ...  */
65
#define E21_MEDIA               0x14    /* (alias). */
66
#define  E21_ALT_IFPORT 0x02    /* Set to use the other (BNC,AUI) port. */
67
#define  E21_BIG_MEM    0x04    /* Use a bigger (64K) buffer (we don't) */
68
#define E21_SAPROM              0x10    /* Offset to station address data. */
69
#define E21_IO_EXTENT    0x20
70
 
71
extern inline void mem_on(short port, volatile char *mem_base,
72
                                                  unsigned char start_page )
73
{
74
        /* This is a little weird: set the shared memory window by doing a
75
           read.  The low address bits specify the starting page. */
76
        mem_base[start_page];
77
        inb(port + E21_MEM_ENABLE);
78
        outb(E21_MEM_ON, port + E21_MEM_ENABLE + E21_MEM_ON);
79
}
80
 
81
extern inline void mem_off(short port)
82
{
83
        inb(port + E21_MEM_ENABLE);
84
        outb(0x00, port + E21_MEM_ENABLE);
85
}
86
 
87
/* In other drivers I put the TX pages first, but the E2100 window circuitry
88
   is designed to have a 4K Tx region last. The windowing circuitry wraps the
89
   window at 0x2fff->0x0000 so that the packets at e.g. 0x2f00 in the RX ring
90
   appear contiguously in the window. */
91
#define E21_RX_START_PG         0x00    /* First page of RX buffer */
92
#define E21_RX_STOP_PG          0x30    /* Last page +1 of RX ring */
93
#define E21_BIG_RX_STOP_PG      0xF0    /* Last page +1 of RX ring */
94
#define E21_TX_START_PG         E21_RX_STOP_PG  /* First page of TX buffer */
95
 
96
int e2100_probe(struct device *dev);
97
int e21_probe1(struct device *dev, int ioaddr);
98
 
99
static int e21_open(struct device *dev);
100
static void e21_reset_8390(struct device *dev);
101
static void e21_block_input(struct device *dev, int count,
102
                                                   struct sk_buff *skb, int ring_offset);
103
static void e21_block_output(struct device *dev, int count,
104
                                                         const unsigned char *buf, const int start_page);
105
static void e21_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
106
                                                        int ring_page);
107
 
108
static int e21_close(struct device *dev);
109
 
110
 
111
/*  Probe for the E2100 series ethercards.  These cards have an 8390 at the
112
        base address and the station address at both offset 0x10 and 0x18.  I read
113
        the station address from offset 0x18 to avoid the dataport of NE2000
114
        ethercards, and look for Ctron's unique ID (first three octets of the
115
        station address).
116
 */
117
 
118
int e2100_probe(struct device *dev)
119
{
120
        int *port;
121
        int base_addr = dev->base_addr;
122
 
123
        if (base_addr > 0x1ff)          /* Check a single specified location. */
124
                return e21_probe1(dev, base_addr);
125
        else if (base_addr != 0) /* Don't probe at all. */
126
                return ENXIO;
127
 
128
        for (port = e21_probe_list; *port; port++) {
129
                if (check_region(*port, E21_IO_EXTENT))
130
                        continue;
131
                if (e21_probe1(dev, *port) == 0)
132
                        return 0;
133
        }
134
 
135
        return ENODEV;
136
}
137
 
138
int e21_probe1(struct device *dev, int ioaddr)
139
{
140
        int i, status;
141
        unsigned char *station_addr = dev->dev_addr;
142
        static unsigned version_printed = 0;
143
 
144
        /* First check the station address for the Ctron prefix. */
145
        if (inb(ioaddr + E21_SAPROM + 0) != 0x00
146
                || inb(ioaddr + E21_SAPROM + 1) != 0x00
147
                || inb(ioaddr + E21_SAPROM + 2) != 0x1d)
148
                return ENODEV;
149
 
150
        /* Verify by making certain that there is a 8390 at there. */
151
        outb(E8390_NODMA + E8390_STOP, ioaddr);
152
        SLOW_DOWN_IO;
153
        status = inb(ioaddr);
154
        if (status != 0x21 && status != 0x23)
155
                return ENODEV;
156
 
157
        /* Read the station address PROM.  */
158
        for (i = 0; i < 6; i++)
159
                station_addr[i] = inb(ioaddr + E21_SAPROM + i);
160
 
161
        inb(ioaddr + E21_MEDIA);                /* Point to media selection. */
162
        outb(0, ioaddr + E21_ASIC);      /* and disable the secondary interface. */
163
 
164
        if (ei_debug  &&  version_printed++ == 0)
165
                printk(version);
166
 
167
        /* We should have a "dev" from Space.c or the static module table. */
168
        if (dev == NULL) {
169
                printk("e2100.c: Passed a NULL device.\n");
170
                dev = init_etherdev(0, 0);
171
        }
172
 
173
        printk("%s: E21** at %#3x,", dev->name, ioaddr);
174
        for (i = 0; i < 6; i++)
175
                printk(" %02X", station_addr[i]);
176
 
177
        if (dev->irq < 2) {
178
                int irqlist[] = {15,11,10,12,5,9,3,4}, i;
179
                for (i = 0; i < 8; i++)
180
                        if (request_irq (irqlist[i], NULL, 0, "bogus", NULL) != -EBUSY) {
181
                                dev->irq = irqlist[i];
182
                                break;
183
                        }
184
                if (i >= 8) {
185
                        printk(" unable to get IRQ %d.\n", dev->irq);
186
                        return EAGAIN;
187
                }
188
        } else if (dev->irq == 2)       /* Fixup luser bogosity: IRQ2 is really IRQ9 */
189
                dev->irq = 9;
190
 
191
        /* Allocate dev->priv and fill in 8390 specific dev fields. */
192
        if (ethdev_init(dev)) {
193
                printk (" unable to get memory for dev->priv.\n");
194
                return -ENOMEM;
195
        }
196
 
197
        /* Grab the region so we can find a different board if IRQ select fails. */
198
        request_region(ioaddr, E21_IO_EXTENT, "e2100");
199
 
200
        /* The 8390 is at the base address. */
201
        dev->base_addr = ioaddr;
202
 
203
        ei_status.name = "E2100";
204
        ei_status.word16 = 1;
205
        ei_status.tx_start_page = E21_TX_START_PG;
206
        ei_status.rx_start_page = E21_RX_START_PG;
207
        ei_status.stop_page = E21_RX_STOP_PG;
208
        ei_status.saved_irq = dev->irq;
209
 
210
        /* Check the media port used.  The port can be passed in on the
211
           low mem_end bits. */
212
        if (dev->mem_end & 15)
213
                dev->if_port = dev->mem_end & 7;
214
        else {
215
                dev->if_port = 0;
216
                inb(ioaddr + E21_MEDIA);        /* Turn automatic media detection on. */
217
                for(i = 0; i < 6; i++)
218
                        if (station_addr[i] != inb(ioaddr + E21_SAPROM + 8 + i)) {
219
                                dev->if_port = 1;
220
                                break;
221
                        }
222
        }
223
 
224
        /* Never map in the E21 shared memory unless you are actively using it.
225
           Also, the shared memory has effective only one setting -- spread all
226
           over the 128K region! */
227
        if (dev->mem_start == 0)
228
                dev->mem_start = 0xd0000;
229
 
230
#ifdef notdef
231
        /* These values are unused.  The E2100 has a 2K window into the packet
232
           buffer.  The window can be set to start on any page boundary. */
233
        dev->rmem_start = dev->mem_start + TX_PAGES*256;
234
        dev->mem_end = dev->rmem_end = dev->mem_start + 2*1024;
235
#endif
236
 
237
        printk(", IRQ %d, %s media, memory @ %#lx.\n", dev->irq,
238
                   dev->if_port ? "secondary" : "primary", dev->mem_start);
239
 
240
        ei_status.reset_8390 = &e21_reset_8390;
241
        ei_status.block_input = &e21_block_input;
242
        ei_status.block_output = &e21_block_output;
243
        ei_status.get_8390_hdr = &e21_get_8390_hdr;
244
        dev->open = &e21_open;
245
        dev->stop = &e21_close;
246
        NS8390_init(dev, 0);
247
 
248
        return 0;
249
}
250
 
251
static int
252
e21_open(struct device *dev)
253
{
254
        short ioaddr = dev->base_addr;
255
 
256
        if (request_irq(dev->irq, ei_interrupt, 0, "e2100", NULL)) {
257
                return EBUSY;
258
        }
259
        irq2dev_map[dev->irq] = dev;
260
 
261
        /* Set the interrupt line and memory base on the hardware. */
262
        inb(ioaddr + E21_IRQ_LOW);
263
        outb(0, ioaddr + E21_ASIC + (dev->irq & 7));
264
        inb(ioaddr + E21_IRQ_HIGH);                     /* High IRQ bit, and if_port. */
265
        outb(0, ioaddr + E21_ASIC + (dev->irq > 7 ? 1:0)
266
                   + (dev->if_port ? E21_ALT_IFPORT : 0));
267
        inb(ioaddr + E21_MEM_BASE);
268
        outb(0, ioaddr + E21_ASIC + ((dev->mem_start >> 17) & 7));
269
 
270
        ei_open(dev);
271
        MOD_INC_USE_COUNT;
272
        return 0;
273
}
274
 
275
static void
276
e21_reset_8390(struct device *dev)
277
{
278
        short ioaddr = dev->base_addr;
279
 
280
        outb(0x01, ioaddr);
281
        if (ei_debug > 1) printk("resetting the E2180x3 t=%ld...", jiffies);
282
        ei_status.txing = 0;
283
 
284
        /* Set up the ASIC registers, just in case something changed them. */
285
 
286
        if (ei_debug > 1) printk("reset done\n");
287
        return;
288
}
289
 
290
/* Grab the 8390 specific header. We put the 2k window so the header page
291
   appears at the start of the shared memory. */
292
 
293
static void
294
e21_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
295
{
296
 
297
        short ioaddr = dev->base_addr;
298
        char *shared_mem = (char *)dev->mem_start;
299
 
300
        mem_on(ioaddr, shared_mem, ring_page);
301
 
302
#ifdef notdef
303
        /* Officially this is what we are doing, but the readl() is faster */
304
        memcpy_fromio(hdr, shared_mem, sizeof(struct e8390_pkt_hdr));
305
#else
306
        ((unsigned int*)hdr)[0] = readl(shared_mem);
307
#endif
308
 
309
        /* Turn off memory access: we would need to reprogram the window anyway. */
310
        mem_off(ioaddr);
311
 
312
}
313
 
314
/*  Block input and output are easy on shared memory ethercards.
315
        The E21xx makes block_input() especially easy by wrapping the top
316
        ring buffer to the bottom automatically. */
317
static void
318
e21_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
319
{
320
        short ioaddr = dev->base_addr;
321
        char *shared_mem = (char *)dev->mem_start;
322
 
323
        mem_on(ioaddr, shared_mem, (ring_offset>>8));
324
 
325
        /* Packet is always in one chunk -- we can copy + cksum. */
326
        eth_io_copy_and_sum(skb, dev->mem_start + (ring_offset & 0xff), count, 0);
327
 
328
        mem_off(ioaddr);
329
}
330
 
331
static void
332
e21_block_output(struct device *dev, int count, const unsigned char *buf,
333
                                 const int start_page)
334
{
335
        short ioaddr = dev->base_addr;
336
        volatile char *shared_mem = (char *)dev->mem_start;
337
 
338
        /* Set the shared memory window start by doing a read, with the low address
339
           bits specifying the starting page. */
340
        readb(shared_mem + start_page);
341
        mem_on(ioaddr, shared_mem, start_page);
342
 
343
        memcpy_toio(shared_mem, buf, count);
344
        mem_off(ioaddr);
345
}
346
 
347
static int
348
e21_close(struct device *dev)
349
{
350
        short ioaddr = dev->base_addr;
351
 
352
        if (ei_debug > 1)
353
                printk("%s: Shutting down ethercard.\n", dev->name);
354
 
355
        free_irq(dev->irq, NULL);
356
        dev->irq = ei_status.saved_irq;
357
 
358
        /* Shut off the interrupt line and secondary interface. */
359
        inb(ioaddr + E21_IRQ_LOW);
360
        outb(0, ioaddr + E21_ASIC);
361
        inb(ioaddr + E21_IRQ_HIGH);                     /* High IRQ bit, and if_port. */
362
        outb(0, ioaddr + E21_ASIC);
363
 
364
        irq2dev_map[dev->irq] = NULL;
365
 
366
        ei_close(dev);
367
 
368
        /* Double-check that the memory has been turned off, because really
369
           really bad things happen if it isn't. */
370
        mem_off(ioaddr);
371
 
372
        MOD_DEC_USE_COUNT;
373
 
374
        return 0;
375
}
376
 
377
#ifdef HAVE_DEVLIST
378
struct netdev_entry e21_drv =
379
{"e21", e21_probe1, E21_IO_EXTENT, e21_probe_list};
380
#endif
381
 
382
 
383
#ifdef MODULE
384
#define MAX_E21_CARDS   4       /* Max number of E21 cards per module */
385
#define NAMELEN         8       /* # of chars for storing dev->name */
386
static char namelist[NAMELEN * MAX_E21_CARDS] = { 0, };
387
static struct device dev_e21[MAX_E21_CARDS] = {
388
        {
389
                NULL,           /* assign a chunk of namelist[] below */
390
                0, 0, 0, 0,
391
                0, 0,
392
                0, 0, 0, NULL, NULL
393
        },
394
};
395
 
396
static int io[MAX_E21_CARDS] = { 0, };
397
static int irq[MAX_E21_CARDS]  = { 0, };
398
static int mem[MAX_E21_CARDS] = { 0, };
399
static int xcvr[MAX_E21_CARDS] = { 0, };         /* choose int. or ext. xcvr */
400
 
401
/* This is set up so that only a single autoprobe takes place per call.
402
ISA device autoprobes on a running machine are not recommended. */
403
int
404
init_module(void)
405
{
406
        int this_dev, found = 0;
407
 
408
        for (this_dev = 0; this_dev < MAX_E21_CARDS; this_dev++) {
409
                struct device *dev = &dev_e21[this_dev];
410
                dev->name = namelist+(NAMELEN*this_dev);
411
                dev->irq = irq[this_dev];
412
                dev->base_addr = io[this_dev];
413
                dev->mem_start = mem[this_dev];
414
                dev->mem_end = xcvr[this_dev];  /* low 4bits = xcvr sel. */
415
                dev->init = e2100_probe;
416
                if (io[this_dev] == 0)  {
417
                        if (this_dev != 0) break; /* only autoprobe 1st one */
418
                        printk(KERN_NOTICE "e2100.c: Presently autoprobing (not recommended) for a single card.\n");
419
                }
420
                if (register_netdev(dev) != 0) {
421
                        printk(KERN_WARNING "e2100.c: No E2100 card found (i/o = 0x%x).\n", io[this_dev]);
422
                        if (found != 0) return 0; /* Got at least one. */
423
                        return -ENXIO;
424
                }
425
                found++;
426
        }
427
 
428
        return 0;
429
}
430
 
431
void
432
cleanup_module(void)
433
{
434
        int this_dev;
435
 
436
        for (this_dev = 0; this_dev < MAX_E21_CARDS; this_dev++) {
437
                struct device *dev = &dev_e21[this_dev];
438
                if (dev->priv != NULL) {
439
                        /* NB: e21_close() handles free_irq + irq2dev map */
440
                        kfree(dev->priv);
441
                        dev->priv = NULL;
442
                        release_region(dev->base_addr, E21_IO_EXTENT);
443
                        unregister_netdev(dev);
444
                }
445
        }
446
}
447
#endif /* MODULE */
448
 
449
/*
450
 * Local variables:
451
 *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c e2100.c"
452
 *  version-control: t
453
 *  tab-width: 4
454
 *  kept-new-versions: 5
455
 * End:
456
 */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.