^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* wd.c: A WD80x3 ethernet driver for linux. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) Written 1993-94 by Donald Becker.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) Copyright 1993 United States Government as represented by the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) Director, National Security Agency.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) This software may be used and distributed according to the terms
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) of the GNU General Public License, incorporated herein by reference.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) The author may be reached as becker@scyld.com, or C/O
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) Scyld Computing Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) 410 Severn Ave., Suite 210
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) Annapolis MD 21403
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) This is a driver for WD8003 and WD8013 "compatible" ethercards.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) Thanks to Russ Nelson (nelson@crnwyr.com) for loaning me a WD8013.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) Changelog:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) Paul Gortmaker : multiple card support for module users, support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) for non-standard memory sizes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static const char version[] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) "wd.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <linux/netdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <linux/etherdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #include "8390.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define DRV_NAME "wd"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) /* A zero-terminated list of I/O addresses to be probed. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static unsigned int wd_portlist[] __initdata =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {0x300, 0x280, 0x380, 0x240, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static int wd_probe1(struct net_device *dev, int ioaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static int wd_open(struct net_device *dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) static void wd_reset_8390(struct net_device *dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static void wd_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) int ring_page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static void wd_block_input(struct net_device *dev, int count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) struct sk_buff *skb, int ring_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static void wd_block_output(struct net_device *dev, int count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) const unsigned char *buf, int start_page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static int wd_close(struct net_device *dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static u32 wd_msg_enable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define WD_START_PG 0x00 /* First page of TX buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define WD03_STOP_PG 0x20 /* Last page +1 of RX ring */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define WD13_STOP_PG 0x40 /* Last page +1 of RX ring */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define WD_CMDREG 0 /* Offset to ASIC command register. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define WD_RESET 0x80 /* Board reset, in WD_CMDREG. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #define WD_MEMENB 0x40 /* Enable the shared memory. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #define WD_CMDREG5 5 /* Offset to 16-bit-only ASIC register 5. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #define ISA16 0x80 /* Enable 16 bit access from the ISA bus. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) #define NIC16 0x40 /* Enable 16 bit access from the 8390. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) #define WD_NIC_OFFSET 16 /* Offset to the 8390 from the base_addr. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) #define WD_IO_EXTENT 32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) /* Probe for the WD8003 and WD8013. These cards have the station
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) address PROM at I/O ports <base>+8 to <base>+13, with a checksum
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) following. A Soundblaster can have the same checksum as an WDethercard,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) so we have an extra exclusionary check for it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) The wd_probe1() routine initializes the card and fills the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) station address field. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static int __init do_wd_probe(struct net_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct resource *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) int base_addr = dev->base_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) int irq = dev->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) int mem_start = dev->mem_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) int mem_end = dev->mem_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (base_addr > 0x1ff) { /* Check a user specified location. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) r = request_region(base_addr, WD_IO_EXTENT, "wd-probe");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if ( r == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) i = wd_probe1(dev, base_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if (i != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) release_region(base_addr, WD_IO_EXTENT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) r->name = dev->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) else if (base_addr != 0) /* Don't probe at all. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) for (i = 0; wd_portlist[i]; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) int ioaddr = wd_portlist[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) r = request_region(ioaddr, WD_IO_EXTENT, "wd-probe");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (r == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (wd_probe1(dev, ioaddr) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) r->name = dev->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) release_region(ioaddr, WD_IO_EXTENT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) dev->irq = irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) dev->mem_start = mem_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) dev->mem_end = mem_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) #ifndef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) struct net_device * __init wd_probe(int unit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct net_device *dev = alloc_ei_netdev();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if (!dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) sprintf(dev->name, "eth%d", unit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) netdev_boot_setup_check(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) err = do_wd_probe(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) return dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) free_netdev(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return ERR_PTR(err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) static const struct net_device_ops wd_netdev_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) .ndo_open = wd_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) .ndo_stop = wd_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) .ndo_start_xmit = ei_start_xmit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) .ndo_tx_timeout = ei_tx_timeout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) .ndo_get_stats = ei_get_stats,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) .ndo_set_rx_mode = ei_set_multicast_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) .ndo_validate_addr = eth_validate_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) .ndo_set_mac_address = eth_mac_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) #ifdef CONFIG_NET_POLL_CONTROLLER
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) .ndo_poll_controller = ei_poll,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) static int __init wd_probe1(struct net_device *dev, int ioaddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) int checksum = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) int ancient = 0; /* An old card without config registers. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) int word16 = 0; /* 0 = 8 bit, 1 = 16 bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) const char *model_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) static unsigned version_printed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) struct ei_device *ei_local = netdev_priv(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) for (i = 0; i < 8; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) checksum += inb(ioaddr + 8 + i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if (inb(ioaddr + 8) == 0xff /* Extra check to avoid soundcard. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) || inb(ioaddr + 9) == 0xff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) || (checksum & 0xff) != 0xFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) /* Check for semi-valid mem_start/end values if supplied. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) if ((dev->mem_start % 0x2000) || (dev->mem_end % 0x2000)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) netdev_warn(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) "wd.c: user supplied mem_start or mem_end not on 8kB boundary - ignored.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) dev->mem_start = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) dev->mem_end = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if ((wd_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) netdev_info(dev, version);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) for (i = 0; i < 6; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) dev->dev_addr[i] = inb(ioaddr + 8 + i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) netdev_info(dev, "WD80x3 at %#3x, %pM", ioaddr, dev->dev_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) /* The following PureData probe code was contributed by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) Mike Jagdis <jaggy@purplet.demon.co.uk>. Puredata does software
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) configuration differently from others so we have to check for them.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) This detects an 8 bit, 16 bit or dumb (Toshiba, jumpered) card.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (inb(ioaddr+0) == 'P' && inb(ioaddr+1) == 'D') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) unsigned char reg5 = inb(ioaddr+5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) switch (inb(ioaddr+2)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) case 0x03: word16 = 0; model_name = "PDI8023-8"; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) case 0x05: word16 = 0; model_name = "PDUC8023"; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) case 0x0a: word16 = 1; model_name = "PDI8023-16"; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) /* Either 0x01 (dumb) or they've released a new version. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) default: word16 = 0; model_name = "PDI8023"; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) dev->mem_start = ((reg5 & 0x1c) + 0xc0) << 12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) dev->irq = (reg5 & 0xe0) == 0xe0 ? 10 : (reg5 >> 5) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) } else { /* End of PureData probe */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) /* This method of checking for a 16-bit board is borrowed from the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) we.c driver. A simpler method is just to look in ASIC reg. 0x03.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) I'm comparing the two method in alpha test to make certain they
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) return the same result. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) /* Check for the old 8 bit board - it has register 0/8 aliasing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) Do NOT check i>=6 here -- it hangs the old 8003 boards! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) for (i = 0; i < 6; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if (inb(ioaddr+i) != inb(ioaddr+8+i))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (i >= 6) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) ancient = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) model_name = "WD8003-old";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) word16 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) int tmp = inb(ioaddr+1); /* fiddle with 16bit bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) outb( tmp ^ 0x01, ioaddr+1 ); /* attempt to clear 16bit bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) if (((inb( ioaddr+1) & 0x01) == 0x01) /* A 16 bit card */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) && (tmp & 0x01) == 0x01 ) { /* In a 16 slot. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) int asic_reg5 = inb(ioaddr+WD_CMDREG5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) /* Magic to set ASIC to word-wide mode. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) outb( NIC16 | (asic_reg5&0x1f), ioaddr+WD_CMDREG5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) outb(tmp, ioaddr+1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) model_name = "WD8013";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) word16 = 1; /* We have a 16bit board here! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) model_name = "WD8003";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) word16 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) outb(tmp, ioaddr+1); /* Restore original reg1 value. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) #ifndef final_version
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) if ( !ancient && (inb(ioaddr+1) & 0x01) != (word16 & 0x01))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) pr_cont("\nWD80?3: Bus width conflict, %d (probe) != %d (reg report).",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) word16 ? 16 : 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) (inb(ioaddr+1) & 0x01) ? 16 : 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) #if defined(WD_SHMEM) && WD_SHMEM > 0x80000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) /* Allow a compile-time override. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) dev->mem_start = WD_SHMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (dev->mem_start == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) /* Sanity and old 8003 check */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) int reg0 = inb(ioaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) if (reg0 == 0xff || reg0 == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) /* Future plan: this could check a few likely locations first. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) dev->mem_start = 0xd0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) pr_cont(" assigning address %#lx", dev->mem_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) int high_addr_bits = inb(ioaddr+WD_CMDREG5) & 0x1f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) /* Some boards don't have the register 5 -- it returns 0xff. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) if (high_addr_bits == 0x1f || word16 == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) high_addr_bits = 0x01;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) dev->mem_start = ((reg0&0x3f) << 13) + (high_addr_bits << 19);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) /* The 8390 isn't at the base address -- the ASIC regs are there! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) dev->base_addr = ioaddr+WD_NIC_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (dev->irq < 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) static const int irqmap[] = {9, 3, 5, 7, 10, 11, 15, 4};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) int reg1 = inb(ioaddr+1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) int reg4 = inb(ioaddr+4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if (ancient || reg1 == 0xff) { /* Ack!! No way to read the IRQ! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) short nic_addr = ioaddr+WD_NIC_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) unsigned long irq_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) /* We have an old-style ethercard that doesn't report its IRQ
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) line. Do autoirq to find the IRQ line. Note that this IS NOT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) a reliable way to trigger an interrupt. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) outb_p(E8390_NODMA + E8390_STOP, nic_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) outb(0x00, nic_addr+EN0_IMR); /* Disable all intrs. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) irq_mask = probe_irq_on();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) outb_p(0xff, nic_addr + EN0_IMR); /* Enable all interrupts. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) outb_p(0x00, nic_addr + EN0_RCNTLO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) outb_p(0x00, nic_addr + EN0_RCNTHI);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) outb(E8390_RREAD+E8390_START, nic_addr); /* Trigger it... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) mdelay(20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) dev->irq = probe_irq_off(irq_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) outb_p(0x00, nic_addr+EN0_IMR); /* Mask all intrs. again. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) if (wd_msg_enable & NETIF_MSG_PROBE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) pr_cont(" autoirq is %d", dev->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) if (dev->irq < 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) dev->irq = word16 ? 10 : 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) dev->irq = irqmap[((reg4 >> 5) & 0x03) + (reg1 & 0x04)];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) } else if (dev->irq == 2) /* Fixup bogosity: IRQ2 is really IRQ9 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) dev->irq = 9;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) /* Snarf the interrupt now. There's no point in waiting since we cannot
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) share and the board will usually be enabled. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) i = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) if (i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) pr_cont(" unable to get IRQ %d.\n", dev->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) /* OK, were are certain this is going to work. Setup the device. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) ei_status.name = model_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) ei_status.word16 = word16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) ei_status.tx_start_page = WD_START_PG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) ei_status.rx_start_page = WD_START_PG + TX_PAGES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) /* Don't map in the shared memory until the board is actually opened. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) /* Some cards (eg WD8003EBT) can be jumpered for more (32k!) memory. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) if (dev->mem_end != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) ei_status.priv = dev->mem_end - dev->mem_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) ei_status.stop_page = word16 ? WD13_STOP_PG : WD03_STOP_PG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) dev->mem_end = dev->mem_start + (ei_status.stop_page - WD_START_PG)*256;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) ei_status.priv = (ei_status.stop_page - WD_START_PG)*256;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) ei_status.mem = ioremap(dev->mem_start, ei_status.priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) if (!ei_status.mem) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) free_irq(dev->irq, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) pr_cont(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) model_name, dev->irq, dev->mem_start, dev->mem_end-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) ei_status.reset_8390 = wd_reset_8390;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) ei_status.block_input = wd_block_input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) ei_status.block_output = wd_block_output;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) ei_status.get_8390_hdr = wd_get_8390_hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) dev->netdev_ops = &wd_netdev_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) NS8390_init(dev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) ei_local->msg_enable = wd_msg_enable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) #if 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) /* Enable interrupt generation on softconfig cards -- M.U */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) /* .. but possibly potentially unsafe - Donald */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) if (inb(ioaddr+14) & 0x20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) outb(inb(ioaddr+4)|0x80, ioaddr+4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) err = register_netdev(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) free_irq(dev->irq, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) iounmap(ei_status.mem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) wd_open(struct net_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) int ioaddr = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) /* Map in the shared memory. Always set register 0 last to remain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) compatible with very old boards. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) ei_status.reg0 = ((dev->mem_start>>13) & 0x3f) | WD_MEMENB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) ei_status.reg5 = ((dev->mem_start>>19) & 0x1f) | NIC16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) if (ei_status.word16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) outb(ei_status.reg5, ioaddr+WD_CMDREG5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) outb(ei_status.reg0, ioaddr); /* WD_CMDREG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) return ei_open(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) wd_reset_8390(struct net_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) int wd_cmd_port = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) struct ei_device *ei_local = netdev_priv(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) outb(WD_RESET, wd_cmd_port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) netif_dbg(ei_local, hw, dev, "resetting the WD80x3 t=%lu...\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) jiffies);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) ei_status.txing = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) /* Set up the ASIC registers, just in case something changed them. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) outb((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), wd_cmd_port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) if (ei_status.word16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) outb(NIC16 | ((dev->mem_start>>19) & 0x1f), wd_cmd_port+WD_CMDREG5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) netif_dbg(ei_local, hw, dev, "reset done\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) /* Grab the 8390 specific header. Similar to the block_input routine, but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) we don't need to be concerned with ring wrap as the header will be at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) the start of a page, so we optimize accordingly. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) wd_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) void __iomem *hdr_start = ei_status.mem + ((ring_page - WD_START_PG)<<8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) /* We'll always get a 4 byte header read followed by a packet read, so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) we enable 16 bit mode before the header, and disable after the body. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) if (ei_status.word16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) #ifdef __BIG_ENDIAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) /* Officially this is what we are doing, but the readl() is faster */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) /* unfortunately it isn't endian aware of the struct */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) hdr->count = le16_to_cpu(hdr->count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) ((unsigned int*)hdr)[0] = readl(hdr_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) /* Block input and output are easy on shared memory ethercards, and trivial
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) on the Western digital card where there is no choice of how to do it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) The only complications are that the ring buffer wraps, and need to map
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) switch between 8- and 16-bit modes. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) wd_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) unsigned long offset = ring_offset - (WD_START_PG<<8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) void __iomem *xfer_start = ei_status.mem + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) if (offset + count > ei_status.priv) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) /* We must wrap the input move. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) int semi_count = ei_status.priv - offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) memcpy_fromio(skb->data, xfer_start, semi_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) count -= semi_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) /* Packet is in one chunk -- we can copy + cksum. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) memcpy_fromio(skb->data, xfer_start, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) /* Turn off 16 bit access so that reboot works. ISA brain-damage */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) if (ei_status.word16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) wd_block_output(struct net_device *dev, int count, const unsigned char *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) int start_page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) void __iomem *shmem = ei_status.mem + ((start_page - WD_START_PG)<<8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) if (ei_status.word16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) /* Turn on and off 16 bit access so that reboot works. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) memcpy_toio(shmem, buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) memcpy_toio(shmem, buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) wd_close(struct net_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) struct ei_device *ei_local = netdev_priv(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) netif_dbg(ei_local, ifdown, dev, "Shutting down ethercard.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) ei_close(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) /* Change from 16-bit to 8-bit shared memory so reboot works. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) if (ei_status.word16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) outb(ei_status.reg5, wd_cmdreg + WD_CMDREG5 );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) /* And disable the shared memory. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) outb(ei_status.reg0 & ~WD_MEMENB, wd_cmdreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) #ifdef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) #define MAX_WD_CARDS 4 /* Max number of wd cards per module */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) static struct net_device *dev_wd[MAX_WD_CARDS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) static int io[MAX_WD_CARDS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) static int irq[MAX_WD_CARDS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) static int mem[MAX_WD_CARDS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) static int mem_end[MAX_WD_CARDS]; /* for non std. mem size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) module_param_hw_array(io, int, ioport, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) module_param_hw_array(irq, int, irq, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) module_param_hw_array(mem, int, iomem, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) module_param_hw_array(mem_end, int, iomem, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) module_param_named(msg_enable, wd_msg_enable, uint, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) MODULE_PARM_DESC(io, "I/O base address(es)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) MODULE_PARM_DESC(irq, "IRQ number(s) (ignored for PureData boards)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) MODULE_PARM_DESC(mem, "memory base address(es)(ignored for PureData boards)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) MODULE_PARM_DESC(mem_end, "memory end address(es)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) MODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) MODULE_DESCRIPTION("ISA Western Digital wd8003/wd8013 ; SMC Elite, Elite16 ethernet driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) /* This is set up so that only a single autoprobe takes place per call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) ISA device autoprobes on a running machine are not recommended. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) int __init init_module(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) struct net_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) int this_dev, found = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) if (io[this_dev] == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) if (this_dev != 0) break; /* only autoprobe 1st one */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) printk(KERN_NOTICE "wd.c: Presently autoprobing (not recommended) for a single card.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) dev = alloc_ei_netdev();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) if (!dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) dev->irq = irq[this_dev];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) dev->base_addr = io[this_dev];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) dev->mem_start = mem[this_dev];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) dev->mem_end = mem_end[this_dev];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) if (do_wd_probe(dev) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) dev_wd[found++] = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) free_netdev(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) printk(KERN_WARNING "wd.c: No wd80x3 card found (i/o = 0x%x).\n", io[this_dev]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) if (found)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) static void cleanup_card(struct net_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) free_irq(dev->irq, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) iounmap(ei_status.mem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) void __exit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) cleanup_module(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) int this_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) struct net_device *dev = dev_wd[this_dev];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) if (dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) unregister_netdev(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) cleanup_card(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) free_netdev(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) #endif /* MODULE */