Root/drivers/net/hp-plus.c

1/* hp-plus.c: A HP PCLAN/plus ethernet driver for linux. */
2/*
3    Written 1994 by Donald Becker.
4
5    This driver is for the Hewlett Packard PC LAN (27***) plus ethercards.
6    These cards are sold under several model numbers, usually 2724*.
7
8    This software may be used and distributed according to the terms
9    of the GNU General Public License, incorporated herein by reference.
10
11    The author may be reached as becker@scyld.com, or C/O
12    Scyld Computing Corporation
13    410 Severn Ave., Suite 210
14    Annapolis MD 21403
15
16    As is often the case, a great deal of credit is owed to Russ Nelson.
17    The Crynwr packet driver was my primary source of HP-specific
18    programming information.
19*/
20
21static const char version[] =
22"hp-plus.c:v1.10 9/24/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
23
24#include <linux/module.h>
25
26#include <linux/string.h> /* Important -- this inlines word moves. */
27#include <linux/kernel.h>
28#include <linux/errno.h>
29#include <linux/ioport.h>
30#include <linux/netdevice.h>
31#include <linux/etherdevice.h>
32#include <linux/init.h>
33#include <linux/delay.h>
34
35#include <asm/system.h>
36#include <asm/io.h>
37
38#include "8390.h"
39
40#define DRV_NAME "hp-plus"
41
42/* A zero-terminated list of I/O addresses to be probed. */
43static unsigned int hpplus_portlist[] __initdata =
44{0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0};
45
46/*
47   The HP EtherTwist chip implementation is a fairly routine DP8390
48   implementation. It allows both shared memory and programmed-I/O buffer
49   access, using a custom interface for both. The programmed-I/O mode is
50   entirely implemented in the HP EtherTwist chip, bypassing the problem
51   ridden built-in 8390 facilities used on NE2000 designs. The shared
52   memory mode is likewise special, with an offset register used to make
53   packets appear at the shared memory base. Both modes use a base and bounds
54   page register to hide the Rx ring buffer wrap -- a packet that spans the
55   end of physical buffer memory appears continuous to the driver. (c.f. the
56   3c503 and Cabletron E2100)
57
58   A special note: the internal buffer of the board is only 8 bits wide.
59   This lays several nasty traps for the unaware:
60   - the 8390 must be programmed for byte-wide operations
61   - all I/O and memory operations must work on whole words (the access
62     latches are serially preloaded and have no byte-swapping ability).
63
64   This board is laid out in I/O space much like the earlier HP boards:
65   the first 16 locations are for the board registers, and the second 16 are
66   for the 8390. The board is easy to identify, with both a dedicated 16 bit
67   ID register and a constant 0x530* value in the upper bits of the paging
68   register.
69*/
70
71#define HP_ID 0x00 /* ID register, always 0x4850. */
72#define HP_PAGING 0x02 /* Registers visible @ 8-f, see PageName. */
73#define HPP_OPTION 0x04 /* Bitmapped options, see HP_Option. */
74#define HPP_OUT_ADDR 0x08 /* I/O output location in Perf_Page. */
75#define HPP_IN_ADDR 0x0A /* I/O input location in Perf_Page. */
76#define HP_DATAPORT 0x0c /* I/O data transfer in Perf_Page. */
77#define NIC_OFFSET 0x10 /* Offset to the 8390 registers. */
78#define HP_IO_EXTENT 32
79
80#define HP_START_PG 0x00 /* First page of TX buffer */
81#define HP_STOP_PG 0x80 /* Last page +1 of RX ring */
82
83/* The register set selected in HP_PAGING. */
84enum PageName {
85    Perf_Page = 0, /* Normal operation. */
86    MAC_Page = 1, /* The ethernet address (+checksum). */
87    HW_Page = 2, /* EEPROM-loaded hardware parameters. */
88    LAN_Page = 4, /* Transceiver selection, testing, etc. */
89    ID_Page = 6 };
90
91/* The bit definitions for the HPP_OPTION register. */
92enum HP_Option {
93    NICReset = 1, ChipReset = 2, /* Active low, really UNreset. */
94    EnableIRQ = 4, FakeIntr = 8, BootROMEnb = 0x10, IOEnb = 0x20,
95    MemEnable = 0x40, ZeroWait = 0x80, MemDisable = 0x1000, };
96
97static int hpp_probe1(struct net_device *dev, int ioaddr);
98
99static void hpp_reset_8390(struct net_device *dev);
100static int hpp_open(struct net_device *dev);
101static int hpp_close(struct net_device *dev);
102static void hpp_mem_block_input(struct net_device *dev, int count,
103                          struct sk_buff *skb, int ring_offset);
104static void hpp_mem_block_output(struct net_device *dev, int count,
105                            const unsigned char *buf, int start_page);
106static void hpp_mem_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
107                          int ring_page);
108static void hpp_io_block_input(struct net_device *dev, int count,
109                          struct sk_buff *skb, int ring_offset);
110static void hpp_io_block_output(struct net_device *dev, int count,
111                            const unsigned char *buf, int start_page);
112static void hpp_io_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
113                          int ring_page);
114
115
116/* Probe a list of addresses for an HP LAN+ adaptor.
117    This routine is almost boilerplate. */
118
119static int __init do_hpp_probe(struct net_device *dev)
120{
121    int i;
122    int base_addr = dev->base_addr;
123    int irq = dev->irq;
124
125    if (base_addr > 0x1ff) /* Check a single specified location. */
126        return hpp_probe1(dev, base_addr);
127    else if (base_addr != 0) /* Don't probe at all. */
128        return -ENXIO;
129
130    for (i = 0; hpplus_portlist[i]; i++) {
131        if (hpp_probe1(dev, hpplus_portlist[i]) == 0)
132            return 0;
133        dev->irq = irq;
134    }
135
136    return -ENODEV;
137}
138
139#ifndef MODULE
140struct net_device * __init hp_plus_probe(int unit)
141{
142    struct net_device *dev = alloc_eip_netdev();
143    int err;
144
145    if (!dev)
146        return ERR_PTR(-ENOMEM);
147
148    sprintf(dev->name, "eth%d", unit);
149    netdev_boot_setup_check(dev);
150
151    err = do_hpp_probe(dev);
152    if (err)
153        goto out;
154    return dev;
155out:
156    free_netdev(dev);
157    return ERR_PTR(err);
158}
159#endif
160
161static const struct net_device_ops hpp_netdev_ops = {
162    .ndo_open = hpp_open,
163    .ndo_stop = hpp_close,
164    .ndo_start_xmit = eip_start_xmit,
165    .ndo_tx_timeout = eip_tx_timeout,
166    .ndo_get_stats = eip_get_stats,
167    .ndo_set_multicast_list = eip_set_multicast_list,
168    .ndo_validate_addr = eth_validate_addr,
169    .ndo_set_mac_address = eth_mac_addr,
170    .ndo_change_mtu = eth_change_mtu,
171#ifdef CONFIG_NET_POLL_CONTROLLER
172    .ndo_poll_controller = eip_poll,
173#endif
174};
175
176
177/* Do the interesting part of the probe at a single address. */
178static int __init hpp_probe1(struct net_device *dev, int ioaddr)
179{
180    int i, retval;
181    unsigned char checksum = 0;
182    const char name[] = "HP-PC-LAN+";
183    int mem_start;
184    static unsigned version_printed;
185
186    if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME))
187        return -EBUSY;
188
189    /* Check for the HP+ signature, 50 48 0x 53. */
190    if (inw(ioaddr + HP_ID) != 0x4850
191        || (inw(ioaddr + HP_PAGING) & 0xfff0) != 0x5300) {
192        retval = -ENODEV;
193        goto out;
194    }
195
196    if (ei_debug && version_printed++ == 0)
197        printk(version);
198
199    printk("%s: %s at %#3x, ", dev->name, name, ioaddr);
200
201    /* Retrieve and checksum the station address. */
202    outw(MAC_Page, ioaddr + HP_PAGING);
203
204    for(i = 0; i < ETHER_ADDR_LEN; i++) {
205        unsigned char inval = inb(ioaddr + 8 + i);
206        dev->dev_addr[i] = inval;
207        checksum += inval;
208    }
209    checksum += inb(ioaddr + 14);
210
211    printk("%pM", dev->dev_addr);
212
213    if (checksum != 0xff) {
214        printk(" bad checksum %2.2x.\n", checksum);
215        retval = -ENODEV;
216        goto out;
217    } else {
218        /* Point at the Software Configuration Flags. */
219        outw(ID_Page, ioaddr + HP_PAGING);
220        printk(" ID %4.4x", inw(ioaddr + 12));
221    }
222
223    /* Read the IRQ line. */
224    outw(HW_Page, ioaddr + HP_PAGING);
225    {
226        int irq = inb(ioaddr + 13) & 0x0f;
227        int option = inw(ioaddr + HPP_OPTION);
228
229        dev->irq = irq;
230        if (option & MemEnable) {
231            mem_start = inw(ioaddr + 9) << 8;
232            printk(", IRQ %d, memory address %#x.\n", irq, mem_start);
233        } else {
234            mem_start = 0;
235            printk(", IRQ %d, programmed-I/O mode.\n", irq);
236        }
237    }
238
239    /* Set the wrap registers for string I/O reads. */
240    outw((HP_START_PG + TX_PAGES/2) | ((HP_STOP_PG - 1) << 8), ioaddr + 14);
241
242    /* Set the base address to point to the NIC, not the "real" base! */
243    dev->base_addr = ioaddr + NIC_OFFSET;
244
245    dev->netdev_ops = &hpp_netdev_ops;
246
247    ei_status.name = name;
248    ei_status.word16 = 0; /* Agggghhhhh! Debug time: 2 days! */
249    ei_status.tx_start_page = HP_START_PG;
250    ei_status.rx_start_page = HP_START_PG + TX_PAGES/2;
251    ei_status.stop_page = HP_STOP_PG;
252
253    ei_status.reset_8390 = &hpp_reset_8390;
254    ei_status.block_input = &hpp_io_block_input;
255    ei_status.block_output = &hpp_io_block_output;
256    ei_status.get_8390_hdr = &hpp_io_get_8390_hdr;
257
258    /* Check if the memory_enable flag is set in the option register. */
259    if (mem_start) {
260        ei_status.block_input = &hpp_mem_block_input;
261        ei_status.block_output = &hpp_mem_block_output;
262        ei_status.get_8390_hdr = &hpp_mem_get_8390_hdr;
263        dev->mem_start = mem_start;
264        ei_status.mem = ioremap(mem_start,
265                    (HP_STOP_PG - HP_START_PG)*256);
266        if (!ei_status.mem) {
267            retval = -ENOMEM;
268            goto out;
269        }
270        ei_status.rmem_start = dev->mem_start + TX_PAGES/2*256;
271        dev->mem_end = ei_status.rmem_end
272            = dev->mem_start + (HP_STOP_PG - HP_START_PG)*256;
273    }
274
275    outw(Perf_Page, ioaddr + HP_PAGING);
276    NS8390p_init(dev, 0);
277    /* Leave the 8390 and HP chip reset. */
278    outw(inw(ioaddr + HPP_OPTION) & ~EnableIRQ, ioaddr + HPP_OPTION);
279
280    retval = register_netdev(dev);
281    if (retval)
282        goto out1;
283    return 0;
284out1:
285    iounmap(ei_status.mem);
286out:
287    release_region(ioaddr, HP_IO_EXTENT);
288    return retval;
289}
290
291static int
292hpp_open(struct net_device *dev)
293{
294    int ioaddr = dev->base_addr - NIC_OFFSET;
295    int option_reg;
296    int retval;
297
298    if ((retval = request_irq(dev->irq, eip_interrupt, 0, dev->name, dev))) {
299        return retval;
300    }
301
302    /* Reset the 8390 and HP chip. */
303    option_reg = inw(ioaddr + HPP_OPTION);
304    outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION);
305    udelay(5);
306    /* Unreset the board and enable interrupts. */
307    outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION);
308
309    /* Set the wrap registers for programmed-I/O operation. */
310    outw(HW_Page, ioaddr + HP_PAGING);
311    outw((HP_START_PG + TX_PAGES/2) | ((HP_STOP_PG - 1) << 8), ioaddr + 14);
312
313    /* Select the operational page. */
314    outw(Perf_Page, ioaddr + HP_PAGING);
315
316    return eip_open(dev);
317}
318
319static int
320hpp_close(struct net_device *dev)
321{
322    int ioaddr = dev->base_addr - NIC_OFFSET;
323    int option_reg = inw(ioaddr + HPP_OPTION);
324
325    free_irq(dev->irq, dev);
326    eip_close(dev);
327    outw((option_reg & ~EnableIRQ) | MemDisable | NICReset | ChipReset,
328         ioaddr + HPP_OPTION);
329
330    return 0;
331}
332
333static void
334hpp_reset_8390(struct net_device *dev)
335{
336    int ioaddr = dev->base_addr - NIC_OFFSET;
337    int option_reg = inw(ioaddr + HPP_OPTION);
338
339    if (ei_debug > 1) printk("resetting the 8390 time=%ld...", jiffies);
340
341    outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION);
342    /* Pause a few cycles for the hardware reset to take place. */
343    udelay(5);
344    ei_status.txing = 0;
345    outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION);
346
347    udelay(5);
348
349
350    if ((inb_p(ioaddr+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0)
351        printk("%s: hp_reset_8390() did not complete.\n", dev->name);
352
353    if (ei_debug > 1) printk("8390 reset done (%ld).", jiffies);
354    return;
355}
356
357/* The programmed-I/O version of reading the 4 byte 8390 specific header.
358   Note that transfer with the EtherTwist+ must be on word boundaries. */
359
360static void
361hpp_io_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
362{
363    int ioaddr = dev->base_addr - NIC_OFFSET;
364
365    outw((ring_page<<8), ioaddr + HPP_IN_ADDR);
366    insw(ioaddr + HP_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
367}
368
369/* Block input and output, similar to the Crynwr packet driver. */
370
371static void
372hpp_io_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
373{
374    int ioaddr = dev->base_addr - NIC_OFFSET;
375    char *buf = skb->data;
376
377    outw(ring_offset, ioaddr + HPP_IN_ADDR);
378    insw(ioaddr + HP_DATAPORT, buf, count>>1);
379    if (count & 0x01)
380        buf[count-1] = inw(ioaddr + HP_DATAPORT);
381}
382
383/* The corresponding shared memory versions of the above 2 functions. */
384
385static void
386hpp_mem_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
387{
388    int ioaddr = dev->base_addr - NIC_OFFSET;
389    int option_reg = inw(ioaddr + HPP_OPTION);
390
391    outw((ring_page<<8), ioaddr + HPP_IN_ADDR);
392    outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
393    memcpy_fromio(hdr, ei_status.mem, sizeof(struct e8390_pkt_hdr));
394    outw(option_reg, ioaddr + HPP_OPTION);
395    hdr->count = (le16_to_cpu(hdr->count) + 3) & ~3; /* Round up allocation. */
396}
397
398static void
399hpp_mem_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
400{
401    int ioaddr = dev->base_addr - NIC_OFFSET;
402    int option_reg = inw(ioaddr + HPP_OPTION);
403
404    outw(ring_offset, ioaddr + HPP_IN_ADDR);
405
406    outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
407
408    /* Caution: this relies on get_8390_hdr() rounding up count!
409       Also note that we *can't* use eth_io_copy_and_sum() because
410       it will not always copy "count" bytes (e.g. padded IP). */
411
412    memcpy_fromio(skb->data, ei_status.mem, count);
413    outw(option_reg, ioaddr + HPP_OPTION);
414}
415
416/* A special note: we *must* always transfer >=16 bit words.
417   It's always safe to round up, so we do. */
418static void
419hpp_io_block_output(struct net_device *dev, int count,
420                    const unsigned char *buf, int start_page)
421{
422    int ioaddr = dev->base_addr - NIC_OFFSET;
423    outw(start_page << 8, ioaddr + HPP_OUT_ADDR);
424    outsl(ioaddr + HP_DATAPORT, buf, (count+3)>>2);
425    return;
426}
427
428static void
429hpp_mem_block_output(struct net_device *dev, int count,
430                const unsigned char *buf, int start_page)
431{
432    int ioaddr = dev->base_addr - NIC_OFFSET;
433    int option_reg = inw(ioaddr + HPP_OPTION);
434
435    outw(start_page << 8, ioaddr + HPP_OUT_ADDR);
436    outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
437    memcpy_toio(ei_status.mem, buf, (count + 3) & ~3);
438    outw(option_reg, ioaddr + HPP_OPTION);
439
440    return;
441}
442
443
444#ifdef MODULE
445#define MAX_HPP_CARDS 4 /* Max number of HPP cards per module */
446static struct net_device *dev_hpp[MAX_HPP_CARDS];
447static int io[MAX_HPP_CARDS];
448static int irq[MAX_HPP_CARDS];
449
450module_param_array(io, int, NULL, 0);
451module_param_array(irq, int, NULL, 0);
452MODULE_PARM_DESC(io, "I/O port address(es)");
453MODULE_PARM_DESC(irq, "IRQ number(s); ignored if properly detected");
454MODULE_DESCRIPTION("HP PC-LAN+ ISA ethernet driver");
455MODULE_LICENSE("GPL");
456
457/* This is set up so that only a single autoprobe takes place per call.
458ISA device autoprobes on a running machine are not recommended. */
459int __init
460init_module(void)
461{
462    struct net_device *dev;
463    int this_dev, found = 0;
464
465    for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) {
466        if (io[this_dev] == 0) {
467            if (this_dev != 0) break; /* only autoprobe 1st one */
468            printk(KERN_NOTICE "hp-plus.c: Presently autoprobing (not recommended) for a single card.\n");
469        }
470        dev = alloc_eip_netdev();
471        if (!dev)
472            break;
473        dev->irq = irq[this_dev];
474        dev->base_addr = io[this_dev];
475        if (do_hpp_probe(dev) == 0) {
476            dev_hpp[found++] = dev;
477            continue;
478        }
479        free_netdev(dev);
480        printk(KERN_WARNING "hp-plus.c: No HP-Plus card found (i/o = 0x%x).\n", io[this_dev]);
481        break;
482    }
483    if (found)
484        return 0;
485    return -ENXIO;
486}
487
488static void cleanup_card(struct net_device *dev)
489{
490    /* NB: hpp_close() handles free_irq */
491    iounmap(ei_status.mem);
492    release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
493}
494
495void __exit
496cleanup_module(void)
497{
498    int this_dev;
499
500    for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) {
501        struct net_device *dev = dev_hpp[this_dev];
502        if (dev) {
503            unregister_netdev(dev);
504            cleanup_card(dev);
505            free_netdev(dev);
506        }
507    }
508}
509#endif /* MODULE */
510

Archive Download this file



interactive