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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [net/] [e2100.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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