Commit bca94cff authored by Paul Gortmaker's avatar Paul Gortmaker

drivers/net: delete 8390 based EISA drivers.

The NS8390 chip was essentially the 1st widespread PC ethernet
chip, starting its life on 8 bit ISA cards in the late 1980s.
Even with better technologies available (bus mastering etc)
the 8390 managed to get used on a few rare EISA cards in the
early to mid 1990s.

The EISA bus in the x86 world was largely confined to systems
ranging from 486 to 586 (essentially 200MHz or lower, and less
than 100MB RAM) -- i.e. machines unlikely to be still in service,
and even less likely to be running a 3.9+ kernel.

On top of that, only one of the five really ever was considered
non-experimental; the smc-ultra32 was the one -- since it was
largely just an EISA version of the popular smc-ultra ISA card.
All the others had such a tiny user base that they simply never
could be considered anything more than experimental.
Signed-off-by: default avatarPaul Gortmaker <paul.gortmaker@windriver.com>
parent 483f7772
...@@ -6,7 +6,7 @@ config NET_VENDOR_8390 ...@@ -6,7 +6,7 @@ config NET_VENDOR_8390
bool "National Semi-conductor 8390 devices" bool "National Semi-conductor 8390 devices"
default y default y
depends on NET_VENDOR_NATSEMI && (AMIGA_PCMCIA || PCI || SUPERH || \ depends on NET_VENDOR_NATSEMI && (AMIGA_PCMCIA || PCI || SUPERH || \
ISA || EISA || MAC || M32R || MACH_TX49XX || \ ISA || MAC || M32R || MACH_TX49XX || \
H8300 || ARM || MIPS || ZORRO || PCMCIA || \ H8300 || ARM || MIPS || ZORRO || PCMCIA || \
EXPERIMENTAL) EXPERIMENTAL)
---help--- ---help---
...@@ -33,18 +33,6 @@ config EL2 ...@@ -33,18 +33,6 @@ config EL2
To compile this driver as a module, choose M here. The module To compile this driver as a module, choose M here. The module
will be called 3c503. will be called 3c503.
config AC3200
tristate "Ansel Communications EISA 3200 support (EXPERIMENTAL)"
depends on PCI && (ISA || EISA) && EXPERIMENTAL
select CRC32
---help---
If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
To compile this driver as a module, choose M here. The module
will be called ac3200.
config PCMCIA_AXNET config PCMCIA_AXNET
tristate "Asix AX88190 PCMCIA support" tristate "Asix AX88190 PCMCIA support"
depends on PCMCIA depends on PCMCIA
...@@ -86,18 +74,6 @@ config E2100 ...@@ -86,18 +74,6 @@ config E2100
To compile this driver as a module, choose M here. The module To compile this driver as a module, choose M here. The module
will be called e2100. will be called e2100.
config ES3210
tristate "Racal-Interlan EISA ES3210 support (EXPERIMENTAL)"
depends on PCI && EISA && EXPERIMENTAL
select CRC32
---help---
If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
To compile this driver as a module, choose M here. The module
will be called es3210.
config HPLAN_PLUS config HPLAN_PLUS
tristate "HP PCLAN+ (27247B and 27252A) support" tristate "HP PCLAN+ (27247B and 27252A) support"
depends on ISA depends on ISA
...@@ -140,18 +116,6 @@ config ARM_ETHERH ...@@ -140,18 +116,6 @@ config ARM_ETHERH
If you have an Acorn system with one of these network cards, you If you have an Acorn system with one of these network cards, you
should say Y to this option if you wish to use it with Linux. should say Y to this option if you wish to use it with Linux.
config LNE390
tristate "Mylex EISA LNE390A/B support (EXPERIMENTAL)"
depends on PCI && EISA && EXPERIMENTAL
select CRC32
---help---
If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
To compile this driver as a module, choose M here. The module
will be called lne390.
config MAC8390 config MAC8390
bool "Macintosh NS 8390 based ethernet cards" bool "Macintosh NS 8390 based ethernet cards"
depends on MAC depends on MAC
...@@ -187,8 +151,7 @@ config NE2000 ...@@ -187,8 +151,7 @@ config NE2000
without a specific driver are compatible with NE2000. without a specific driver are compatible with NE2000.
If you have a PCI NE2000 card however, say N here and Y to "PCI If you have a PCI NE2000 card however, say N here and Y to "PCI
NE2000 and clone support" under "EISA, VLB, PCI and on board NE2000 and clone support" below.
controllers" below.
To compile this driver as a module, choose M here. The module To compile this driver as a module, choose M here. The module
will be called ne. will be called ne.
...@@ -223,19 +186,6 @@ config APNE ...@@ -223,19 +186,6 @@ config APNE
To compile this driver as a module, choose M here: the module To compile this driver as a module, choose M here: the module
will be called apne. will be called apne.
config NE3210
tristate "Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)"
depends on PCI && EISA && EXPERIMENTAL
select CRC32
---help---
If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>. Note that this driver
will NOT WORK for NE3200 cards as they are completely different.
To compile this driver as a module, choose M here. The module
will be called ne3210.
config PCMCIA_PCNET config PCMCIA_PCNET
tristate "NE2000 compatible PCMCIA support" tristate "NE2000 compatible PCMCIA support"
depends on PCMCIA depends on PCMCIA
...@@ -285,18 +235,6 @@ config ULTRA ...@@ -285,18 +235,6 @@ config ULTRA
To compile this driver as a module, choose M here. The module To compile this driver as a module, choose M here. The module
will be called smc-ultra. will be called smc-ultra.
config ULTRA32
tristate "SMC Ultra32 EISA support"
depends on EISA
select CRC32
---help---
If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
To compile this driver as a module, choose M here. The module
will be called smc-ultra32.
config WD80x3 config WD80x3
tristate "WD80*3 support" tristate "WD80*3 support"
depends on ISA depends on ISA
......
...@@ -3,26 +3,21 @@ ...@@ -3,26 +3,21 @@
# #
obj-$(CONFIG_MAC8390) += mac8390.o obj-$(CONFIG_MAC8390) += mac8390.o
obj-$(CONFIG_AC3200) += ac3200.o 8390.o
obj-$(CONFIG_APNE) += apne.o 8390.o obj-$(CONFIG_APNE) += apne.o 8390.o
obj-$(CONFIG_ARM_ETHERH) += etherh.o obj-$(CONFIG_ARM_ETHERH) += etherh.o
obj-$(CONFIG_AX88796) += ax88796.o obj-$(CONFIG_AX88796) += ax88796.o
obj-$(CONFIG_E2100) += e2100.o 8390.o obj-$(CONFIG_E2100) += e2100.o 8390.o
obj-$(CONFIG_EL2) += 3c503.o 8390p.o obj-$(CONFIG_EL2) += 3c503.o 8390p.o
obj-$(CONFIG_ES3210) += es3210.o 8390.o
obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390p.o obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390p.o
obj-$(CONFIG_HPLAN) += hp.o 8390p.o obj-$(CONFIG_HPLAN) += hp.o 8390p.o
obj-$(CONFIG_HYDRA) += hydra.o 8390.o obj-$(CONFIG_HYDRA) += hydra.o 8390.o
obj-$(CONFIG_LNE390) += lne390.o 8390.o
obj-$(CONFIG_MCF8390) += mcf8390.o 8390.o obj-$(CONFIG_MCF8390) += mcf8390.o 8390.o
obj-$(CONFIG_NE2000) += ne.o 8390p.o obj-$(CONFIG_NE2000) += ne.o 8390p.o
obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
obj-$(CONFIG_NE3210) += ne3210.o 8390.o
obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o
obj-$(CONFIG_PCMCIA_AXNET) += axnet_cs.o 8390.o obj-$(CONFIG_PCMCIA_AXNET) += axnet_cs.o 8390.o
obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o 8390.o obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o 8390.o
obj-$(CONFIG_STNIC) += stnic.o 8390.o obj-$(CONFIG_STNIC) += stnic.o 8390.o
obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o
obj-$(CONFIG_ULTRA32) += smc-ultra32.o 8390.o
obj-$(CONFIG_WD80x3) += wd.o 8390.o obj-$(CONFIG_WD80x3) += wd.o 8390.o
obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o
/* ac3200.c: A driver for the Ansel Communications EISA ethernet adaptor. */
/*
Written 1993, 1994 by Donald Becker.
Copyright 1993 United States Government as represented by the Director,
National Security Agency. This software may only be used and distributed
according to the terms of the GNU General Public License as modified by SRC,
incorporated herein by reference.
The author may be reached as becker@scyld.com, or C/O
Scyld Computing Corporation
410 Severn Ave., Suite 210
Annapolis MD 21403
This is driver for the Ansel Communications Model 3200 EISA Ethernet LAN
Adapter. The programming information is from the users manual, as related
by glee@ardnassak.math.clemson.edu.
Changelog:
Paul Gortmaker 05/98 : add support for shared mem above 1MB.
*/
static const char version[] =
"ac3200.c:v1.01 7/1/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
#include <linux/module.h>
#include <linux/eisa.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/irq.h>
#include "8390.h"
#define DRV_NAME "ac3200"
/* Offsets from the base address. */
#define AC_NIC_BASE 0x00
#define AC_SA_PROM 0x16 /* The station address PROM. */
#define AC_ADDR0 0x00 /* Prefix station address values. */
#define AC_ADDR1 0x40
#define AC_ADDR2 0x90
#define AC_ID_PORT 0xC80
#define AC_EISA_ID 0x0110d305
#define AC_RESET_PORT 0xC84
#define AC_RESET 0x00
#define AC_ENABLE 0x01
#define AC_CONFIG 0xC90 /* The configuration port. */
#define AC_IO_EXTENT 0x20
/* Actually accessed is:
* AC_NIC_BASE (0-15)
* AC_SA_PROM (0-5)
* AC_ID_PORT (0-3)
* AC_RESET_PORT
* AC_CONFIG
*/
/* Decoding of the configuration register. */
static unsigned char config2irqmap[8] __initdata = {15, 12, 11, 10, 9, 7, 5, 3};
static int addrmap[8] =
{0xFF0000, 0xFE0000, 0xFD0000, 0xFFF0000, 0xFFE0000, 0xFFC0000, 0xD0000, 0 };
static const char *port_name[4] = { "10baseT", "invalid", "AUI", "10base2"};
#define config2irq(configval) config2irqmap[((configval) >> 3) & 7]
#define config2mem(configval) addrmap[(configval) & 7]
#define config2name(configval) port_name[((configval) >> 6) & 3]
/* First and last 8390 pages. */
#define AC_START_PG 0x00 /* First page of 8390 TX buffer */
#define AC_STOP_PG 0x80 /* Last page +1 of the 8390 RX ring */
static int ac_probe1(int ioaddr, struct net_device *dev);
static int ac_open(struct net_device *dev);
static void ac_reset_8390(struct net_device *dev);
static void ac_block_input(struct net_device *dev, int count,
struct sk_buff *skb, int ring_offset);
static void ac_block_output(struct net_device *dev, const int count,
const unsigned char *buf, const int start_page);
static void ac_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
int ring_page);
static int ac_close_card(struct net_device *dev);
/* Probe for the AC3200.
The AC3200 can be identified by either the EISA configuration registers,
or the unique value in the station address PROM.
*/
static int __init do_ac3200_probe(struct net_device *dev)
{
unsigned short ioaddr = dev->base_addr;
int irq = dev->irq;
int mem_start = dev->mem_start;
if (ioaddr > 0x1ff) /* Check a single specified location. */
return ac_probe1(ioaddr, dev);
else if (ioaddr > 0) /* Don't probe at all. */
return -ENXIO;
if ( ! EISA_bus)
return -ENXIO;
for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
if (ac_probe1(ioaddr, dev) == 0)
return 0;
dev->irq = irq;
dev->mem_start = mem_start;
}
return -ENODEV;
}
#ifndef MODULE
struct net_device * __init ac3200_probe(int unit)
{
struct net_device *dev = alloc_ei_netdev();
int err;
if (!dev)
return ERR_PTR(-ENOMEM);
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
err = do_ac3200_probe(dev);
if (err)
goto out;
return dev;
out:
free_netdev(dev);
return ERR_PTR(err);
}
#endif
static const struct net_device_ops ac_netdev_ops = {
.ndo_open = ac_open,
.ndo_stop = ac_close_card,
.ndo_start_xmit = ei_start_xmit,
.ndo_tx_timeout = ei_tx_timeout,
.ndo_get_stats = ei_get_stats,
.ndo_set_rx_mode = ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ei_poll,
#endif
};
static int __init ac_probe1(int ioaddr, struct net_device *dev)
{
int i, retval;
if (!request_region(ioaddr, AC_IO_EXTENT, DRV_NAME))
return -EBUSY;
if (inb_p(ioaddr + AC_ID_PORT) == 0xff) {
retval = -ENODEV;
goto out;
}
if (inl(ioaddr + AC_ID_PORT) != AC_EISA_ID) {
retval = -ENODEV;
goto out;
}
#ifndef final_version
printk(KERN_DEBUG "AC3200 ethercard configuration register is %#02x,"
" EISA ID %02x %02x %02x %02x.\n", inb(ioaddr + AC_CONFIG),
inb(ioaddr + AC_ID_PORT + 0), inb(ioaddr + AC_ID_PORT + 1),
inb(ioaddr + AC_ID_PORT + 2), inb(ioaddr + AC_ID_PORT + 3));
#endif
for (i = 0; i < 6; i++)
dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i);
printk(KERN_DEBUG "AC3200 in EISA slot %d, node %pM",
ioaddr/0x1000, dev->dev_addr);
#if 0
/* Check the vendor ID/prefix. Redundant after checking the EISA ID */
if (inb(ioaddr + AC_SA_PROM + 0) != AC_ADDR0
|| inb(ioaddr + AC_SA_PROM + 1) != AC_ADDR1
|| inb(ioaddr + AC_SA_PROM + 2) != AC_ADDR2 ) {
printk(", not found (invalid prefix).\n");
retval = -ENODEV;
goto out;
}
#endif
/* Assign and allocate the interrupt now. */
if (dev->irq == 0) {
dev->irq = config2irq(inb(ioaddr + AC_CONFIG));
printk(", using");
} else {
dev->irq = irq_canonicalize(dev->irq);
printk(", assigning");
}
retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
if (retval) {
printk (" nothing! Unable to get IRQ %d.\n", dev->irq);
goto out;
}
printk(" IRQ %d, %s port\n", dev->irq, port_name[dev->if_port]);
dev->base_addr = ioaddr;
#ifdef notyet
if (dev->mem_start) { /* Override the value from the board. */
for (i = 0; i < 7; i++)
if (addrmap[i] == dev->mem_start)
break;
if (i >= 7)
i = 0;
outb((inb(ioaddr + AC_CONFIG) & ~7) | i, ioaddr + AC_CONFIG);
}
#endif
dev->if_port = inb(ioaddr + AC_CONFIG) >> 6;
dev->mem_start = config2mem(inb(ioaddr + AC_CONFIG));
printk("%s: AC3200 at %#3x with %dkB memory at physical address %#lx.\n",
dev->name, ioaddr, AC_STOP_PG/4, dev->mem_start);
/*
* BEWARE!! Some dain-bramaged EISA SCUs will allow you to put
* the card mem within the region covered by `normal' RAM !!!
*
* ioremap() will fail in that case.
*/
ei_status.mem = ioremap(dev->mem_start, AC_STOP_PG*0x100);
if (!ei_status.mem) {
printk(KERN_ERR "ac3200.c: Unable to remap card memory above 1MB !!\n");
printk(KERN_ERR "ac3200.c: Try using EISA SCU to set memory below 1MB.\n");
printk(KERN_ERR "ac3200.c: Driver NOT installed.\n");
retval = -EINVAL;
goto out1;
}
printk("ac3200.c: remapped %dkB card memory to virtual address %p\n",
AC_STOP_PG/4, ei_status.mem);
dev->mem_start = (unsigned long)ei_status.mem;
dev->mem_end = dev->mem_start + (AC_STOP_PG - AC_START_PG)*256;
ei_status.name = "AC3200";
ei_status.tx_start_page = AC_START_PG;
ei_status.rx_start_page = AC_START_PG + TX_PAGES;
ei_status.stop_page = AC_STOP_PG;
ei_status.word16 = 1;
if (ei_debug > 0)
printk(version);
ei_status.reset_8390 = &ac_reset_8390;
ei_status.block_input = &ac_block_input;
ei_status.block_output = &ac_block_output;
ei_status.get_8390_hdr = &ac_get_8390_hdr;
dev->netdev_ops = &ac_netdev_ops;
NS8390_init(dev, 0);
retval = register_netdev(dev);
if (retval)
goto out2;
return 0;
out2:
if (ei_status.reg0)
iounmap(ei_status.mem);
out1:
free_irq(dev->irq, dev);
out:
release_region(ioaddr, AC_IO_EXTENT);
return retval;
}
static int ac_open(struct net_device *dev)
{
#ifdef notyet
/* Someday we may enable the IRQ and shared memory here. */
int ioaddr = dev->base_addr;
#endif
ei_open(dev);
return 0;
}
static void ac_reset_8390(struct net_device *dev)
{
ushort ioaddr = dev->base_addr;
outb(AC_RESET, ioaddr + AC_RESET_PORT);
if (ei_debug > 1) printk("resetting AC3200, t=%ld...", jiffies);
ei_status.txing = 0;
outb(AC_ENABLE, ioaddr + AC_RESET_PORT);
if (ei_debug > 1) printk("reset done\n");
}
/* Grab the 8390 specific header. Similar to the block_input routine, but
we don't need to be concerned with ring wrap as the header will be at
the start of a page, so we optimize accordingly. */
static void
ac_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
{
void __iomem *hdr_start = ei_status.mem + ((ring_page - AC_START_PG)<<8);
memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
}
/* Block input and output are easy on shared memory ethercards, the only
complication is when the ring buffer wraps. */
static void ac_block_input(struct net_device *dev, int count, struct sk_buff *skb,
int ring_offset)
{
void __iomem *start = ei_status.mem + ring_offset - AC_START_PG*256;
if (ring_offset + count > AC_STOP_PG*256) {
/* We must wrap the input move. */
int semi_count = AC_STOP_PG*256 - ring_offset;
memcpy_fromio(skb->data, start, semi_count);
count -= semi_count;
memcpy_fromio(skb->data + semi_count,
ei_status.mem + TX_PAGES*256, count);
} else {
memcpy_fromio(skb->data, start, count);
}
}
static void ac_block_output(struct net_device *dev, int count,
const unsigned char *buf, int start_page)
{
void __iomem *shmem = ei_status.mem + ((start_page - AC_START_PG)<<8);
memcpy_toio(shmem, buf, count);
}
static int ac_close_card(struct net_device *dev)
{
if (ei_debug > 1)
printk("%s: Shutting down ethercard.\n", dev->name);
#ifdef notyet
/* We should someday disable shared memory and interrupts. */
outb(0x00, ioaddr + 6); /* Disable interrupts. */
free_irq(dev->irq, dev);
#endif
ei_close(dev);
return 0;
}
#ifdef MODULE
#define MAX_AC32_CARDS 4 /* Max number of AC32 cards per module */
static struct net_device *dev_ac32[MAX_AC32_CARDS];
static int io[MAX_AC32_CARDS];
static int irq[MAX_AC32_CARDS];
static int mem[MAX_AC32_CARDS];
module_param_array(io, int, NULL, 0);
module_param_array(irq, int, NULL, 0);
module_param_array(mem, int, NULL, 0);
MODULE_PARM_DESC(io, "I/O base address(es)");
MODULE_PARM_DESC(irq, "IRQ number(s)");
MODULE_PARM_DESC(mem, "Memory base address(es)");
MODULE_DESCRIPTION("Ansel AC3200 EISA ethernet driver");
MODULE_LICENSE("GPL");
static int __init ac3200_module_init(void)
{
struct net_device *dev;
int this_dev, found = 0;
for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) {
if (io[this_dev] == 0 && this_dev != 0)
break;
dev = alloc_ei_netdev();
if (!dev)
break;
dev->irq = irq[this_dev];
dev->base_addr = io[this_dev];
dev->mem_start = mem[this_dev]; /* Currently ignored by driver */
if (do_ac3200_probe(dev) == 0) {
dev_ac32[found++] = dev;
continue;
}
free_netdev(dev);
printk(KERN_WARNING "ac3200.c: No ac3200 card found (i/o = 0x%x).\n", io[this_dev]);
break;
}
if (found)
return 0;
return -ENXIO;
}
static void cleanup_card(struct net_device *dev)
{
/* Someday free_irq may be in ac_close_card() */
free_irq(dev->irq, dev);
release_region(dev->base_addr, AC_IO_EXTENT);
iounmap(ei_status.mem);
}
static void __exit ac3200_module_exit(void)
{
int this_dev;
for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) {
struct net_device *dev = dev_ac32[this_dev];
if (dev) {
unregister_netdev(dev);
cleanup_card(dev);
free_netdev(dev);
}
}
}
module_init(ac3200_module_init);
module_exit(ac3200_module_exit);
#endif /* MODULE */
/*
es3210.c
Linux driver for Racal-Interlan ES3210 EISA Network Adapter
Copyright (C) 1996, Paul Gortmaker.
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
Information and Code Sources:
1) The existing myriad of Linux 8390 drivers written by Donald Becker.
2) Once again Russ Nelson's asm packet driver provided additional info.
3) Info for getting IRQ and sh-mem gleaned from the EISA cfg files.
Too bad it doesn't work -- see below.
The ES3210 is an EISA shared memory NS8390 implementation. Note
that all memory copies to/from the board must be 32bit transfers.
Which rules out using eth_io_copy_and_sum() in this driver.
Apparently there are two slightly different revisions of the
card, since there are two distinct EISA cfg files (!rii0101.cfg
and !rii0102.cfg) One has media select in the cfg file and the
other doesn't. Hopefully this will work with either.
That is about all I can tell you about it, having never actually
even seen one of these cards. :) Try http://www.interlan.com
if you want more info.
Thanks go to Mark Salazar for testing v0.02 of this driver.
Bugs, to-fix, etc:
1) The EISA cfg ports that are *supposed* to have the IRQ and shared
mem values just read 0xff all the time. Hrrmpf. Apparently the
same happens with the packet driver as the code for reading
these registers is disabled there. In the meantime, boot with:
ether=<IRQ>,0,0x<shared_mem_addr>,eth0 to override the IRQ and
shared memory detection. (The i/o port detection is okay.)
2) Module support currently untested. Probably works though.
*/
static const char version[] =
"es3210.c: Driver revision v0.03, 14/09/96\n";
#include <linux/module.h>
#include <linux/eisa.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <asm/io.h>
#include "8390.h"
static int es_probe1(struct net_device *dev, int ioaddr);
static void es_reset_8390(struct net_device *dev);
static void es_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page);
static void es_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset);
static void es_block_output(struct net_device *dev, int count, const unsigned char *buf, int start_page);
#define ES_START_PG 0x00 /* First page of TX buffer */
#define ES_STOP_PG 0x40 /* Last page +1 of RX ring */
#define ES_IO_EXTENT 0x37 /* The cfg file says 0xc90 -> 0xcc7 */
#define ES_ID_PORT 0xc80 /* Same for all EISA cards */
#define ES_SA_PROM 0xc90 /* Start of e'net addr. */
#define ES_RESET_PORT 0xc84 /* From the packet driver source */
#define ES_NIC_OFFSET 0xca0 /* Hello, the 8390 is *here* */
#define ES_ADDR0 0x02 /* 3 byte vendor prefix */
#define ES_ADDR1 0x07
#define ES_ADDR2 0x01
/*
* Two card revisions. EISA ID's are always rev. minor, rev. major,, and
* then the three vendor letters stored in 5 bits each, with an "a" = 1.
* For eg: "rii" = 10010 01001 01001 = 0x4929, which is how the EISA
* config utility determines automagically what config file(s) to use.
*/
#define ES_EISA_ID1 0x01012949 /* !rii0101.cfg */
#define ES_EISA_ID2 0x02012949 /* !rii0102.cfg */
#define ES_CFG1 0xcc0 /* IOPORT(1) --> IOPORT(6) in cfg file */
#define ES_CFG2 0xcc1
#define ES_CFG3 0xcc2
#define ES_CFG4 0xcc3
#define ES_CFG5 0xcc4
#define ES_CFG6 0xc84 /* NB: 0xc84 is also "reset" port. */
/*
* You can OR any of the following bits together and assign it
* to ES_DEBUG to get verbose driver info during operation.
* Some of these don't do anything yet.
*/
#define ES_D_PROBE 0x01
#define ES_D_RX_PKT 0x02
#define ES_D_TX_PKT 0x04
#define ED_D_IRQ 0x08
#define ES_DEBUG 0
static unsigned char lo_irq_map[] __initdata = {3, 4, 5, 6, 7, 9, 10};
static unsigned char hi_irq_map[] __initdata = {11, 12, 0, 14, 0, 0, 0, 15};
/*
* Probe for the card. The best way is to read the EISA ID if it
* is known. Then we check the prefix of the station address
* PROM for a match against the Racal-Interlan assigned value.
*/
static int __init do_es_probe(struct net_device *dev)
{
unsigned short ioaddr = dev->base_addr;
int irq = dev->irq;
int mem_start = dev->mem_start;
if (ioaddr > 0x1ff) /* Check a single specified location. */
return es_probe1(dev, ioaddr);
else if (ioaddr > 0) /* Don't probe at all. */
return -ENXIO;
if (!EISA_bus) {
#if ES_DEBUG & ES_D_PROBE
printk("es3210.c: Not EISA bus. Not probing high ports.\n");
#endif
return -ENXIO;
}
/* EISA spec allows for up to 16 slots, but 8 is typical. */
for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
if (es_probe1(dev, ioaddr) == 0)
return 0;
dev->irq = irq;
dev->mem_start = mem_start;
}
return -ENODEV;
}
#ifndef MODULE
struct net_device * __init es_probe(int unit)
{
struct net_device *dev = alloc_ei_netdev();
int err;
if (!dev)
return ERR_PTR(-ENOMEM);
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
err = do_es_probe(dev);
if (err)
goto out;
return dev;
out:
free_netdev(dev);
return ERR_PTR(err);
}
#endif
static int __init es_probe1(struct net_device *dev, int ioaddr)
{
int i, retval;
unsigned long eisa_id;
if (!request_region(ioaddr + ES_SA_PROM, ES_IO_EXTENT, "es3210"))
return -ENODEV;
#if ES_DEBUG & ES_D_PROBE
printk("es3210.c: probe at %#x, ID %#8x\n", ioaddr, inl(ioaddr + ES_ID_PORT));
printk("es3210.c: config regs: %#x %#x %#x %#x %#x %#x\n",
inb(ioaddr + ES_CFG1), inb(ioaddr + ES_CFG2), inb(ioaddr + ES_CFG3),
inb(ioaddr + ES_CFG4), inb(ioaddr + ES_CFG5), inb(ioaddr + ES_CFG6));
#endif
/* Check the EISA ID of the card. */
eisa_id = inl(ioaddr + ES_ID_PORT);
if ((eisa_id != ES_EISA_ID1) && (eisa_id != ES_EISA_ID2)) {
retval = -ENODEV;
goto out;
}
for (i = 0; i < ETH_ALEN ; i++)
dev->dev_addr[i] = inb(ioaddr + ES_SA_PROM + i);
/* Check the Racal vendor ID as well. */
if (dev->dev_addr[0] != ES_ADDR0 ||
dev->dev_addr[1] != ES_ADDR1 ||
dev->dev_addr[2] != ES_ADDR2) {
printk("es3210.c: card not found %pM (invalid_prefix).\n",
dev->dev_addr);
retval = -ENODEV;
goto out;
}
printk("es3210.c: ES3210 rev. %ld at %#x, node %pM",
eisa_id>>24, ioaddr, dev->dev_addr);
/* Snarf the interrupt now. */
if (dev->irq == 0) {
unsigned char hi_irq = inb(ioaddr + ES_CFG2) & 0x07;
unsigned char lo_irq = inb(ioaddr + ES_CFG1) & 0xfe;
if (hi_irq != 0) {
dev->irq = hi_irq_map[hi_irq - 1];
} else {
int i = 0;
while (lo_irq > (1<<i)) i++;
dev->irq = lo_irq_map[i];
}
printk(" using IRQ %d", dev->irq);
#if ES_DEBUG & ES_D_PROBE
printk("es3210.c: hi_irq %#x, lo_irq %#x, dev->irq = %d\n",
hi_irq, lo_irq, dev->irq);
#endif
} else {
if (dev->irq == 2)
dev->irq = 9; /* Doh! */
printk(" assigning IRQ %d", dev->irq);
}
if (request_irq(dev->irq, ei_interrupt, 0, "es3210", dev)) {
printk (" unable to get IRQ %d.\n", dev->irq);
retval = -EAGAIN;
goto out;
}
if (dev->mem_start == 0) {
unsigned char mem_enabled = inb(ioaddr + ES_CFG2) & 0xc0;
unsigned char mem_bits = inb(ioaddr + ES_CFG3) & 0x07;
if (mem_enabled != 0x80) {
printk(" shared mem disabled - giving up\n");
retval = -ENXIO;
goto out1;
}
dev->mem_start = 0xC0000 + mem_bits*0x4000;
printk(" using ");
} else {
printk(" assigning ");
}
ei_status.mem = ioremap(dev->mem_start, (ES_STOP_PG - ES_START_PG)*256);
if (!ei_status.mem) {
printk("ioremap failed - giving up\n");
retval = -ENXIO;
goto out1;
}
dev->mem_end = dev->mem_start + (ES_STOP_PG - ES_START_PG)*256;
printk("mem %#lx-%#lx\n", dev->mem_start, dev->mem_end-1);
#if ES_DEBUG & ES_D_PROBE
if (inb(ioaddr + ES_CFG5))
printk("es3210: Warning - DMA channel enabled, but not used here.\n");
#endif
/* Note, point at the 8390, and not the card... */
dev->base_addr = ioaddr + ES_NIC_OFFSET;
ei_status.name = "ES3210";
ei_status.tx_start_page = ES_START_PG;
ei_status.rx_start_page = ES_START_PG + TX_PAGES;
ei_status.stop_page = ES_STOP_PG;
ei_status.word16 = 1;
if (ei_debug > 0)
printk(version);
ei_status.reset_8390 = &es_reset_8390;
ei_status.block_input = &es_block_input;
ei_status.block_output = &es_block_output;
ei_status.get_8390_hdr = &es_get_8390_hdr;
dev->netdev_ops = &ei_netdev_ops;
NS8390_init(dev, 0);
retval = register_netdev(dev);
if (retval)
goto out1;
return 0;
out1:
free_irq(dev->irq, dev);
out:
release_region(ioaddr + ES_SA_PROM, ES_IO_EXTENT);
return retval;
}
/*
* Reset as per the packet driver method. Judging by the EISA cfg
* file, this just toggles the "Board Enable" bits (bit 2 and 0).
*/
static void es_reset_8390(struct net_device *dev)
{
unsigned short ioaddr = dev->base_addr;
unsigned long end;
outb(0x04, ioaddr + ES_RESET_PORT);
if (ei_debug > 1) printk("%s: resetting the ES3210...", dev->name);
end = jiffies + 2*HZ/100;
while ((signed)(end - jiffies) > 0) continue;
ei_status.txing = 0;
outb(0x01, ioaddr + ES_RESET_PORT);
if (ei_debug > 1) printk("reset done\n");
}
/*
* Note: In the following three functions is the implicit assumption
* that the associated memcpy will only use "rep; movsl" as long as
* we keep the counts as some multiple of doublewords. This is a
* requirement of the hardware, and also prevents us from using
* eth_io_copy_and_sum() since we can't guarantee it will limit
* itself to doubleword access.
*/
/*
* Grab the 8390 specific header. Similar to the block_input routine, but
* we don't need to be concerned with ring wrap as the header will be at
* the start of a page, so we optimize accordingly. (A single doubleword.)
*/
static void
es_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
{
void __iomem *hdr_start = ei_status.mem + ((ring_page - ES_START_PG)<<8);
memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */
}
/*
* Block input and output are easy on shared memory ethercards, the only
* complication is when the ring buffer wraps. The count will already
* be rounded up to a doubleword value via es_get_8390_hdr() above.
*/
static void es_block_input(struct net_device *dev, int count, struct sk_buff *skb,
int ring_offset)
{
void __iomem *xfer_start = ei_status.mem + ring_offset - ES_START_PG*256;
if (ring_offset + count > ES_STOP_PG*256) {
/* Packet wraps over end of ring buffer. */
int semi_count = ES_STOP_PG*256 - ring_offset;
memcpy_fromio(skb->data, xfer_start, semi_count);
count -= semi_count;
memcpy_fromio(skb->data + semi_count, ei_status.mem, count);
} else {
/* Packet is in one chunk. */
memcpy_fromio(skb->data, xfer_start, count);
}
}
static void es_block_output(struct net_device *dev, int count,
const unsigned char *buf, int start_page)
{
void __iomem *shmem = ei_status.mem + ((start_page - ES_START_PG)<<8);
count = (count + 3) & ~3; /* Round up to doubleword */
memcpy_toio(shmem, buf, count);
}
#ifdef MODULE
#define MAX_ES_CARDS 4 /* Max number of ES3210 cards per module */
#define NAMELEN 8 /* # of chars for storing dev->name */
static struct net_device *dev_es3210[MAX_ES_CARDS];
static int io[MAX_ES_CARDS];
static int irq[MAX_ES_CARDS];
static int mem[MAX_ES_CARDS];
module_param_array(io, int, NULL, 0);
module_param_array(irq, int, NULL, 0);
module_param_array(mem, int, NULL, 0);
MODULE_PARM_DESC(io, "I/O base address(es)");
MODULE_PARM_DESC(irq, "IRQ number(s)");
MODULE_PARM_DESC(mem, "memory base address(es)");
MODULE_DESCRIPTION("Racal-Interlan ES3210 EISA ethernet driver");
MODULE_LICENSE("GPL");
int __init init_module(void)
{
struct net_device *dev;
int this_dev, found = 0;
for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) {
if (io[this_dev] == 0 && this_dev != 0)
break;
dev = alloc_ei_netdev();
if (!dev)
break;
dev->irq = irq[this_dev];
dev->base_addr = io[this_dev];
dev->mem_start = mem[this_dev];
if (do_es_probe(dev) == 0) {
dev_es3210[found++] = dev;
continue;
}
free_netdev(dev);
printk(KERN_WARNING "es3210.c: No es3210 card found (i/o = 0x%x).\n", io[this_dev]);
break;
}
if (found)
return 0;
return -ENXIO;
}
static void cleanup_card(struct net_device *dev)
{
free_irq(dev->irq, dev);
release_region(dev->base_addr, ES_IO_EXTENT);
iounmap(ei_status.mem);
}
void __exit
cleanup_module(void)
{
int this_dev;
for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) {
struct net_device *dev = dev_es3210[this_dev];
if (dev) {
unregister_netdev(dev);
cleanup_card(dev);
free_netdev(dev);
}
}
}
#endif /* MODULE */
/*
lne390.c
Linux driver for Mylex LNE390 EISA Network Adapter
Copyright (C) 1996-1998, Paul Gortmaker.
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
Information and Code Sources:
1) Based upon framework of es3210 driver.
2) The existing myriad of other Linux 8390 drivers by Donald Becker.
3) Russ Nelson's asm packet driver provided additional info.
4) Info for getting IRQ and sh-mem gleaned from the EISA cfg files.
The LNE390 is an EISA shared memory NS8390 implementation. Note
that all memory copies to/from the board must be 32bit transfers.
There are two versions of the card: the lne390a and the lne390b.
Going by the EISA cfg files, the "a" has jumpers to select between
BNC/AUI, but the "b" also has RJ-45 and selection is via the SCU.
The shared memory address selection is also slightly different.
Note that shared memory address > 1MB are supported with this driver.
You can try <http://www.mylex.com> if you want more info, as I've
never even seen one of these cards. :)
Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 2000/09/01
- get rid of check_region
- no need to check if dev == NULL in lne390_probe1
*/
static const char *version =
"lne390.c: Driver revision v0.99.1, 01/09/2000\n";
#include <linux/module.h>
#include <linux/eisa.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <asm/io.h>
#include "8390.h"
#define DRV_NAME "lne390"
static int lne390_probe1(struct net_device *dev, int ioaddr);
static void lne390_reset_8390(struct net_device *dev);
static void lne390_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page);
static void lne390_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset);
static void lne390_block_output(struct net_device *dev, int count, const unsigned char *buf, const int start_page);
#define LNE390_START_PG 0x00 /* First page of TX buffer */
#define LNE390_STOP_PG 0x80 /* Last page +1 of RX ring */
#define LNE390_ID_PORT 0xc80 /* Same for all EISA cards */
#define LNE390_IO_EXTENT 0x20
#define LNE390_SA_PROM 0x16 /* Start of e'net addr. */
#define LNE390_RESET_PORT 0xc84 /* From the pkt driver source */
#define LNE390_NIC_OFFSET 0x00 /* Hello, the 8390 is *here* */
#define LNE390_ADDR0 0x00 /* 3 byte vendor prefix */
#define LNE390_ADDR1 0x80
#define LNE390_ADDR2 0xe5
#define LNE390_ID0 0x10009835 /* 0x3598 = 01101 01100 11000 = mlx */
#define LNE390_ID1 0x11009835 /* above is the 390A, this is 390B */
#define LNE390_CFG1 0xc84 /* NB: 0xc84 is also "reset" port. */
#define LNE390_CFG2 0xc90
/*
* You can OR any of the following bits together and assign it
* to LNE390_DEBUG to get verbose driver info during operation.
* Currently only the probe one is implemented.
*/
#define LNE390_D_PROBE 0x01
#define LNE390_D_RX_PKT 0x02
#define LNE390_D_TX_PKT 0x04
#define LNE390_D_IRQ 0x08
#define LNE390_DEBUG 0
static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3};
static unsigned int shmem_mapA[] __initdata = {0xff, 0xfe, 0xfd, 0xfff, 0xffe, 0xffc, 0x0d, 0x0};
static unsigned int shmem_mapB[] __initdata = {0xff, 0xfe, 0x0e, 0xfff, 0xffe, 0xffc, 0x0d, 0x0};
/*
* Probe for the card. The best way is to read the EISA ID if it
* is known. Then we can check the prefix of the station address
* PROM for a match against the value assigned to Mylex.
*/
static int __init do_lne390_probe(struct net_device *dev)
{
unsigned short ioaddr = dev->base_addr;
int irq = dev->irq;
int mem_start = dev->mem_start;
int ret;
if (ioaddr > 0x1ff) { /* Check a single specified location. */
if (!request_region(ioaddr, LNE390_IO_EXTENT, DRV_NAME))
return -EBUSY;
ret = lne390_probe1(dev, ioaddr);
if (ret)
release_region(ioaddr, LNE390_IO_EXTENT);
return ret;
}
else if (ioaddr > 0) /* Don't probe at all. */
return -ENXIO;
if (!EISA_bus) {
#if LNE390_DEBUG & LNE390_D_PROBE
printk("lne390-debug: Not an EISA bus. Not probing high ports.\n");
#endif
return -ENXIO;
}
/* EISA spec allows for up to 16 slots, but 8 is typical. */
for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
if (!request_region(ioaddr, LNE390_IO_EXTENT, DRV_NAME))
continue;
if (lne390_probe1(dev, ioaddr) == 0)
return 0;
release_region(ioaddr, LNE390_IO_EXTENT);
dev->irq = irq;
dev->mem_start = mem_start;
}
return -ENODEV;
}
#ifndef MODULE
struct net_device * __init lne390_probe(int unit)
{
struct net_device *dev = alloc_ei_netdev();
int err;
if (!dev)
return ERR_PTR(-ENOMEM);
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
err = do_lne390_probe(dev);
if (err)
goto out;
return dev;
out:
free_netdev(dev);
return ERR_PTR(err);
}
#endif
static int __init lne390_probe1(struct net_device *dev, int ioaddr)
{
int i, revision, ret;
unsigned long eisa_id;
if (inb_p(ioaddr + LNE390_ID_PORT) == 0xff) return -ENODEV;
#if LNE390_DEBUG & LNE390_D_PROBE
printk("lne390-debug: probe at %#x, ID %#8x\n", ioaddr, inl(ioaddr + LNE390_ID_PORT));
printk("lne390-debug: config regs: %#x %#x\n",
inb(ioaddr + LNE390_CFG1), inb(ioaddr + LNE390_CFG2));
#endif
/* Check the EISA ID of the card. */
eisa_id = inl(ioaddr + LNE390_ID_PORT);
if ((eisa_id != LNE390_ID0) && (eisa_id != LNE390_ID1)) {
return -ENODEV;
}
revision = (eisa_id >> 24) & 0x01; /* 0 = rev A, 1 rev B */
#if 0
/* Check the Mylex vendor ID as well. Not really required. */
if (inb(ioaddr + LNE390_SA_PROM + 0) != LNE390_ADDR0
|| inb(ioaddr + LNE390_SA_PROM + 1) != LNE390_ADDR1
|| inb(ioaddr + LNE390_SA_PROM + 2) != LNE390_ADDR2 ) {
printk("lne390.c: card not found");
for (i = 0; i < ETH_ALEN; i++)
printk(" %02x", inb(ioaddr + LNE390_SA_PROM + i));
printk(" (invalid prefix).\n");
return -ENODEV;
}
#endif
for (i = 0; i < ETH_ALEN; i++)
dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i);
printk("lne390.c: LNE390%X in EISA slot %d, address %pM.\n",
0xa+revision, ioaddr/0x1000, dev->dev_addr);
printk("lne390.c: ");
/* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
if (dev->irq == 0) {
unsigned char irq_reg = inb(ioaddr + LNE390_CFG2) >> 3;
dev->irq = irq_map[irq_reg & 0x07];
printk("using");
} else {
/* This is useless unless we reprogram the card here too */
if (dev->irq == 2) dev->irq = 9; /* Doh! */
printk("assigning");
}
printk(" IRQ %d,", dev->irq);
if ((ret = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev))) {
printk (" unable to get IRQ %d.\n", dev->irq);
return ret;
}
if (dev->mem_start == 0) {
unsigned char mem_reg = inb(ioaddr + LNE390_CFG2) & 0x07;
if (revision) /* LNE390B */
dev->mem_start = shmem_mapB[mem_reg] * 0x10000;
else /* LNE390A */
dev->mem_start = shmem_mapA[mem_reg] * 0x10000;
printk(" using ");
} else {
/* Should check for value in shmem_map and reprogram the card to use it */
dev->mem_start &= 0xfff0000;
printk(" assigning ");
}
printk("%dkB memory at physical address %#lx\n",
LNE390_STOP_PG/4, dev->mem_start);
/*
BEWARE!! Some dain-bramaged EISA SCUs will allow you to put
the card mem within the region covered by `normal' RAM !!!
ioremap() will fail in that case.
*/
ei_status.mem = ioremap(dev->mem_start, LNE390_STOP_PG*0x100);
if (!ei_status.mem) {
printk(KERN_ERR "lne390.c: Unable to remap card memory above 1MB !!\n");
printk(KERN_ERR "lne390.c: Try using EISA SCU to set memory below 1MB.\n");
printk(KERN_ERR "lne390.c: Driver NOT installed.\n");
ret = -EAGAIN;
goto cleanup;
}
printk("lne390.c: remapped %dkB card memory to virtual address %p\n",
LNE390_STOP_PG/4, ei_status.mem);
dev->mem_start = (unsigned long)ei_status.mem;
dev->mem_end = dev->mem_start + (LNE390_STOP_PG - LNE390_START_PG)*256;
/* The 8390 offset is zero for the LNE390 */
dev->base_addr = ioaddr;
ei_status.name = "LNE390";
ei_status.tx_start_page = LNE390_START_PG;
ei_status.rx_start_page = LNE390_START_PG + TX_PAGES;
ei_status.stop_page = LNE390_STOP_PG;
ei_status.word16 = 1;
if (ei_debug > 0)
printk(version);
ei_status.reset_8390 = &lne390_reset_8390;
ei_status.block_input = &lne390_block_input;
ei_status.block_output = &lne390_block_output;
ei_status.get_8390_hdr = &lne390_get_8390_hdr;
dev->netdev_ops = &ei_netdev_ops;
NS8390_init(dev, 0);
ret = register_netdev(dev);
if (ret)
goto unmap;
return 0;
unmap:
if (ei_status.reg0)
iounmap(ei_status.mem);
cleanup:
free_irq(dev->irq, dev);
return ret;
}
/*
* Reset as per the packet driver method. Judging by the EISA cfg
* file, this just toggles the "Board Enable" bits (bit 2 and 0).
*/
static void lne390_reset_8390(struct net_device *dev)
{
unsigned short ioaddr = dev->base_addr;
outb(0x04, ioaddr + LNE390_RESET_PORT);
if (ei_debug > 1) printk("%s: resetting the LNE390...", dev->name);
mdelay(2);
ei_status.txing = 0;
outb(0x01, ioaddr + LNE390_RESET_PORT);
if (ei_debug > 1) printk("reset done\n");
}
/*
* Note: In the following three functions is the implicit assumption
* that the associated memcpy will only use "rep; movsl" as long as
* we keep the counts as some multiple of doublewords. This is a
* requirement of the hardware, and also prevents us from using
* eth_io_copy_and_sum() since we can't guarantee it will limit
* itself to doubleword access.
*/
/*
* Grab the 8390 specific header. Similar to the block_input routine, but
* we don't need to be concerned with ring wrap as the header will be at
* the start of a page, so we optimize accordingly. (A single doubleword.)
*/
static void
lne390_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
{
void __iomem *hdr_start = ei_status.mem + ((ring_page - LNE390_START_PG)<<8);
memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */
}
/*
* Block input and output are easy on shared memory ethercards, the only
* complication is when the ring buffer wraps. The count will already
* be rounded up to a doubleword value via lne390_get_8390_hdr() above.
*/
static void lne390_block_input(struct net_device *dev, int count, struct sk_buff *skb,
int ring_offset)
{
void __iomem *xfer_start = ei_status.mem + ring_offset - (LNE390_START_PG<<8);
if (ring_offset + count > (LNE390_STOP_PG<<8)) {
/* Packet wraps over end of ring buffer. */
int semi_count = (LNE390_STOP_PG<<8) - ring_offset;
memcpy_fromio(skb->data, xfer_start, semi_count);
count -= semi_count;
memcpy_fromio(skb->data + semi_count,
ei_status.mem + (TX_PAGES<<8), count);
} else {
/* Packet is in one chunk. */
memcpy_fromio(skb->data, xfer_start, count);
}
}
static void lne390_block_output(struct net_device *dev, int count,
const unsigned char *buf, int start_page)
{
void __iomem *shmem = ei_status.mem + ((start_page - LNE390_START_PG)<<8);
count = (count + 3) & ~3; /* Round up to doubleword */
memcpy_toio(shmem, buf, count);
}
#ifdef MODULE
#define MAX_LNE_CARDS 4 /* Max number of LNE390 cards per module */
static struct net_device *dev_lne[MAX_LNE_CARDS];
static int io[MAX_LNE_CARDS];
static int irq[MAX_LNE_CARDS];
static int mem[MAX_LNE_CARDS];
module_param_array(io, int, NULL, 0);
module_param_array(irq, int, NULL, 0);
module_param_array(mem, int, NULL, 0);
MODULE_PARM_DESC(io, "I/O base address(es)");
MODULE_PARM_DESC(irq, "IRQ number(s)");
MODULE_PARM_DESC(mem, "memory base address(es)");
MODULE_DESCRIPTION("Mylex LNE390A/B EISA Ethernet driver");
MODULE_LICENSE("GPL");
int __init init_module(void)
{
struct net_device *dev;
int this_dev, found = 0;
for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) {
if (io[this_dev] == 0 && this_dev != 0)
break;
dev = alloc_ei_netdev();
if (!dev)
break;
dev->irq = irq[this_dev];
dev->base_addr = io[this_dev];
dev->mem_start = mem[this_dev];
if (do_lne390_probe(dev) == 0) {
dev_lne[found++] = dev;
continue;
}
free_netdev(dev);
printk(KERN_WARNING "lne390.c: No LNE390 card found (i/o = 0x%x).\n", io[this_dev]);
break;
}
if (found)
return 0;
return -ENXIO;
}
static void cleanup_card(struct net_device *dev)
{
free_irq(dev->irq, dev);
release_region(dev->base_addr, LNE390_IO_EXTENT);
iounmap(ei_status.mem);
}
void __exit cleanup_module(void)
{
int this_dev;
for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) {
struct net_device *dev = dev_lne[this_dev];
if (dev) {
unregister_netdev(dev);
cleanup_card(dev);
free_netdev(dev);
}
}
}
#endif /* MODULE */
/*
ne3210.c
Linux driver for Novell NE3210 EISA Network Adapter
Copyright (C) 1998, Paul Gortmaker.
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
Information and Code Sources:
1) Based upon my other EISA 8390 drivers (lne390, es3210, smc-ultra32)
2) The existing myriad of other Linux 8390 drivers by Donald Becker.
3) Info for getting IRQ and sh-mem gleaned from the EISA cfg file
The NE3210 is an EISA shared memory NS8390 implementation. Shared
memory address > 1MB should work with this driver.
Note that the .cfg file (3/11/93, v1.0) has AUI and BNC switched
around (or perhaps there are some defective/backwards cards ???)
This driver WILL NOT WORK FOR THE NE3200 - it is completely different
and does not use an 8390 at all.
Updated to EISA probing API 5/2003 by Marc Zyngier.
*/
#include <linux/module.h>
#include <linux/eisa.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/mm.h>
#include <asm/io.h>
#include "8390.h"
#define DRV_NAME "ne3210"
static void ne3210_reset_8390(struct net_device *dev);
static void ne3210_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page);
static void ne3210_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset);
static void ne3210_block_output(struct net_device *dev, int count, const unsigned char *buf, const int start_page);
#define NE3210_START_PG 0x00 /* First page of TX buffer */
#define NE3210_STOP_PG 0x80 /* Last page +1 of RX ring */
#define NE3210_IO_EXTENT 0x20
#define NE3210_SA_PROM 0x16 /* Start of e'net addr. */
#define NE3210_RESET_PORT 0xc84
#define NE3210_NIC_OFFSET 0x00 /* Hello, the 8390 is *here* */
#define NE3210_ADDR0 0x00 /* 3 byte vendor prefix */
#define NE3210_ADDR1 0x00
#define NE3210_ADDR2 0x1b
#define NE3210_CFG1 0xc84 /* NB: 0xc84 is also "reset" port. */
#define NE3210_CFG2 0xc90
#define NE3210_CFG_EXTENT (NE3210_CFG2 - NE3210_CFG1 + 1)
/*
* You can OR any of the following bits together and assign it
* to NE3210_DEBUG to get verbose driver info during operation.
* Currently only the probe one is implemented.
*/
#define NE3210_D_PROBE 0x01
#define NE3210_D_RX_PKT 0x02
#define NE3210_D_TX_PKT 0x04
#define NE3210_D_IRQ 0x08
#define NE3210_DEBUG 0x0
static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3};
static unsigned int shmem_map[] __initdata = {0xff0, 0xfe0, 0xfff0, 0xd8, 0xffe0, 0xffc0, 0xd0, 0x0};
static const char * const ifmap[] __initconst = {"UTP", "?", "BNC", "AUI"};
static int ifmap_val[] __initdata = {
IF_PORT_10BASET,
IF_PORT_UNKNOWN,
IF_PORT_10BASE2,
IF_PORT_AUI,
};
static int __init ne3210_eisa_probe (struct device *device)
{
unsigned long ioaddr, phys_mem;
int i, retval, port_index;
struct eisa_device *edev = to_eisa_device (device);
struct net_device *dev;
/* Allocate dev->priv and fill in 8390 specific dev fields. */
if (!(dev = alloc_ei_netdev ())) {
printk ("ne3210.c: unable to allocate memory for dev!\n");
return -ENOMEM;
}
SET_NETDEV_DEV(dev, device);
dev_set_drvdata(device, dev);
ioaddr = edev->base_addr;
if (!request_region(ioaddr, NE3210_IO_EXTENT, DRV_NAME)) {
retval = -EBUSY;
goto out;
}
if (!request_region(ioaddr + NE3210_CFG1,
NE3210_CFG_EXTENT, DRV_NAME)) {
retval = -EBUSY;
goto out1;
}
#if NE3210_DEBUG & NE3210_D_PROBE
printk("ne3210-debug: probe at %#x, ID %s\n", ioaddr, edev->id.sig);
printk("ne3210-debug: config regs: %#x %#x\n",
inb(ioaddr + NE3210_CFG1), inb(ioaddr + NE3210_CFG2));
#endif
port_index = inb(ioaddr + NE3210_CFG2) >> 6;
for (i = 0; i < ETH_ALEN; i++)
dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i);
printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr: %pM.\n",
edev->slot, ifmap[port_index], dev->dev_addr);
/* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
dev->irq = irq_map[(inb(ioaddr + NE3210_CFG2) >> 3) & 0x07];
printk("ne3210.c: using IRQ %d, ", dev->irq);
retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
if (retval) {
printk (" unable to get IRQ %d.\n", dev->irq);
goto out2;
}
phys_mem = shmem_map[inb(ioaddr + NE3210_CFG2) & 0x07] * 0x1000;
/*
BEWARE!! Some dain-bramaged EISA SCUs will allow you to put
the card mem within the region covered by `normal' RAM !!!
*/
if (phys_mem > 1024*1024) { /* phys addr > 1MB */
if (phys_mem < virt_to_phys(high_memory)) {
printk(KERN_CRIT "ne3210.c: Card RAM overlaps with normal memory!!!\n");
printk(KERN_CRIT "ne3210.c: Use EISA SCU to set card memory below 1MB,\n");
printk(KERN_CRIT "ne3210.c: or to an address above 0x%llx.\n",
(u64)virt_to_phys(high_memory));
printk(KERN_CRIT "ne3210.c: Driver NOT installed.\n");
retval = -EINVAL;
goto out3;
}
}
if (!request_mem_region (phys_mem, NE3210_STOP_PG*0x100, DRV_NAME)) {
printk ("ne3210.c: Unable to request shared memory at physical address %#lx\n",
phys_mem);
goto out3;
}
printk("%dkB memory at physical address %#lx\n",
NE3210_STOP_PG/4, phys_mem);
ei_status.mem = ioremap(phys_mem, NE3210_STOP_PG*0x100);
if (!ei_status.mem) {
printk(KERN_ERR "ne3210.c: Unable to remap card memory !!\n");
printk(KERN_ERR "ne3210.c: Driver NOT installed.\n");
retval = -EAGAIN;
goto out4;
}
printk("ne3210.c: remapped %dkB card memory to virtual address %p\n",
NE3210_STOP_PG/4, ei_status.mem);
dev->mem_start = (unsigned long)ei_status.mem;
dev->mem_end = dev->mem_start + (NE3210_STOP_PG - NE3210_START_PG)*256;
/* The 8390 offset is zero for the NE3210 */
dev->base_addr = ioaddr;
ei_status.name = "NE3210";
ei_status.tx_start_page = NE3210_START_PG;
ei_status.rx_start_page = NE3210_START_PG + TX_PAGES;
ei_status.stop_page = NE3210_STOP_PG;
ei_status.word16 = 1;
ei_status.priv = phys_mem;
if (ei_debug > 0)
printk("ne3210 loaded.\n");
ei_status.reset_8390 = &ne3210_reset_8390;
ei_status.block_input = &ne3210_block_input;
ei_status.block_output = &ne3210_block_output;
ei_status.get_8390_hdr = &ne3210_get_8390_hdr;
dev->netdev_ops = &ei_netdev_ops;
dev->if_port = ifmap_val[port_index];
if ((retval = register_netdev (dev)))
goto out5;
NS8390_init(dev, 0);
return 0;
out5:
iounmap(ei_status.mem);
out4:
release_mem_region (phys_mem, NE3210_STOP_PG*0x100);
out3:
free_irq (dev->irq, dev);
out2:
release_region (ioaddr + NE3210_CFG1, NE3210_CFG_EXTENT);
out1:
release_region (ioaddr, NE3210_IO_EXTENT);
out:
free_netdev (dev);
return retval;
}
static int ne3210_eisa_remove(struct device *device)
{
struct net_device *dev = dev_get_drvdata(device);
unsigned long ioaddr = to_eisa_device (device)->base_addr;
unregister_netdev (dev);
iounmap(ei_status.mem);
release_mem_region (ei_status.priv, NE3210_STOP_PG*0x100);
free_irq (dev->irq, dev);
release_region (ioaddr + NE3210_CFG1, NE3210_CFG_EXTENT);
release_region (ioaddr, NE3210_IO_EXTENT);
free_netdev (dev);
return 0;
}
/*
* Reset by toggling the "Board Enable" bits (bit 2 and 0).
*/
static void ne3210_reset_8390(struct net_device *dev)
{
unsigned short ioaddr = dev->base_addr;
outb(0x04, ioaddr + NE3210_RESET_PORT);
if (ei_debug > 1) printk("%s: resetting the NE3210...", dev->name);
mdelay(2);
ei_status.txing = 0;
outb(0x01, ioaddr + NE3210_RESET_PORT);
if (ei_debug > 1) printk("reset done\n");
}
/*
* Note: In the following three functions is the implicit assumption
* that the associated memcpy will only use "rep; movsl" as long as
* we keep the counts as some multiple of doublewords. This is a
* requirement of the hardware, and also prevents us from using
* eth_io_copy_and_sum() since we can't guarantee it will limit
* itself to doubleword access.
*/
/*
* Grab the 8390 specific header. Similar to the block_input routine, but
* we don't need to be concerned with ring wrap as the header will be at
* the start of a page, so we optimize accordingly. (A single doubleword.)
*/
static void
ne3210_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
{
void __iomem *hdr_start = ei_status.mem + ((ring_page - NE3210_START_PG)<<8);
memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */
}
/*
* Block input and output are easy on shared memory ethercards, the only
* complication is when the ring buffer wraps. The count will already
* be rounded up to a doubleword value via ne3210_get_8390_hdr() above.
*/
static void ne3210_block_input(struct net_device *dev, int count, struct sk_buff *skb,
int ring_offset)
{
void __iomem *start = ei_status.mem + ring_offset - NE3210_START_PG*256;
if (ring_offset + count > NE3210_STOP_PG*256) {
/* Packet wraps over end of ring buffer. */
int semi_count = NE3210_STOP_PG*256 - ring_offset;
memcpy_fromio(skb->data, start, semi_count);
count -= semi_count;
memcpy_fromio(skb->data + semi_count,
ei_status.mem + TX_PAGES*256, count);
} else {
/* Packet is in one chunk. */
memcpy_fromio(skb->data, start, count);
}
}
static void ne3210_block_output(struct net_device *dev, int count,
const unsigned char *buf, int start_page)
{
void __iomem *shmem = ei_status.mem + ((start_page - NE3210_START_PG)<<8);
count = (count + 3) & ~3; /* Round up to doubleword */
memcpy_toio(shmem, buf, count);
}
static struct eisa_device_id ne3210_ids[] = {
{ "EGL0101" },
{ "NVL1801" },
{ "" },
};
MODULE_DEVICE_TABLE(eisa, ne3210_ids);
static struct eisa_driver ne3210_eisa_driver = {
.id_table = ne3210_ids,
.driver = {
.name = "ne3210",
.probe = ne3210_eisa_probe,
.remove = ne3210_eisa_remove,
},
};
MODULE_DESCRIPTION("NE3210 EISA Ethernet driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(eisa, ne3210_ids);
static int ne3210_init(void)
{
return eisa_driver_register (&ne3210_eisa_driver);
}
static void ne3210_cleanup(void)
{
eisa_driver_unregister (&ne3210_eisa_driver);
}
module_init (ne3210_init);
module_exit (ne3210_cleanup);
/* smc-ultra32.c: An SMC Ultra32 EISA ethernet driver for linux.
Sources:
This driver is based on (cloned from) the ISA SMC Ultra driver
written by Donald Becker. Modifications to support the EISA
version of the card by Paul Gortmaker and Leonard N. Zubkoff.
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
Theory of Operation:
The SMC Ultra32C card uses the SMC 83c790 chip which is also
found on the ISA SMC Ultra cards. It has a shared memory mode of
operation that makes it similar to the ISA version of the card.
The main difference is that the EISA card has 32KB of RAM, but
only an 8KB window into that memory. The EISA card also can be
set for a bus-mastering mode of operation via the ECU, but that
is not (and probably will never be) supported by this driver.
The ECU should be run to enable shared memory and to disable the
bus-mastering feature for use with linux.
By programming the 8390 to use only 8KB RAM, the modifications
to the ISA driver can be limited to the probe and initialization
code. This allows easy integration of EISA support into the ISA
driver. However, the driver development kit from SMC provided the
register information for sliding the 8KB window, and hence the 8390
is programmed to use the full 32KB RAM.
Unfortunately this required code changes outside the probe/init
routines, and thus we decided to separate the EISA driver from
the ISA one. In this way, ISA users don't end up with a larger
driver due to the EISA code, and EISA users don't end up with a
larger driver due to the ISA EtherEZ PIO code. The driver is
similar to the 3c503/16 driver, in that the window must be set
back to the 1st 8KB of space for access to the two 8390 Tx slots.
In testing, using only 8KB RAM (3 Tx / 5 Rx) didn't appear to
be a limiting factor, since the EISA bus could get packets off
the card fast enough, but having the use of lots of RAM as Rx
space is extra insurance if interrupt latencies become excessive.
*/
static const char *version = "smc-ultra32.c: 06/97 v1.00\n";
#include <linux/module.h>
#include <linux/eisa.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <asm/io.h>
#include "8390.h"
#define DRV_NAME "smc-ultra32"
static int ultra32_probe1(struct net_device *dev, int ioaddr);
static int ultra32_open(struct net_device *dev);
static void ultra32_reset_8390(struct net_device *dev);
static void ultra32_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
int ring_page);
static void ultra32_block_input(struct net_device *dev, int count,
struct sk_buff *skb, int ring_offset);
static void ultra32_block_output(struct net_device *dev, int count,
const unsigned char *buf,
const int start_page);
static int ultra32_close(struct net_device *dev);
#define ULTRA32_CMDREG 0 /* Offset to ASIC command register. */
#define ULTRA32_RESET 0x80 /* Board reset, in ULTRA32_CMDREG. */
#define ULTRA32_MEMENB 0x40 /* Enable the shared memory. */
#define ULTRA32_NIC_OFFSET 16 /* NIC register offset from the base_addr. */
#define ULTRA32_IO_EXTENT 32
#define EN0_ERWCNT 0x08 /* Early receive warning count. */
/*
* Defines that apply only to the Ultra32 EISA card. Note that
* "smc" = 10011 01101 00011 = 0x4da3, and hence !smc8010.cfg translates
* into an EISA ID of 0x1080A34D
*/
#define ULTRA32_BASE 0xca0
#define ULTRA32_ID 0x1080a34d
#define ULTRA32_IDPORT (-0x20) /* 0xc80 */
/* Config regs 1->7 from the EISA !SMC8010.CFG file. */
#define ULTRA32_CFG1 0x04 /* 0xca4 */
#define ULTRA32_CFG2 0x05 /* 0xca5 */
#define ULTRA32_CFG3 (-0x18) /* 0xc88 */
#define ULTRA32_CFG4 (-0x17) /* 0xc89 */
#define ULTRA32_CFG5 (-0x16) /* 0xc8a */
#define ULTRA32_CFG6 (-0x15) /* 0xc8b */
#define ULTRA32_CFG7 0x0d /* 0xcad */
static void cleanup_card(struct net_device *dev)
{
int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET;
/* NB: ultra32_close_card() does free_irq */
release_region(ioaddr, ULTRA32_IO_EXTENT);
iounmap(ei_status.mem);
}
/* Probe for the Ultra32. This looks like a 8013 with the station
address PROM at I/O ports <base>+8 to <base>+13, with a checksum
following.
*/
struct net_device * __init ultra32_probe(int unit)
{
struct net_device *dev;
int base;
int irq;
int err = -ENODEV;
if (!EISA_bus)
return ERR_PTR(-ENODEV);
dev = alloc_ei_netdev();
if (!dev)
return ERR_PTR(-ENOMEM);
if (unit >= 0) {
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
}
irq = dev->irq;
/* EISA spec allows for up to 16 slots, but 8 is typical. */
for (base = 0x1000 + ULTRA32_BASE; base < 0x9000; base += 0x1000) {
if (ultra32_probe1(dev, base) == 0)
break;
dev->irq = irq;
}
if (base >= 0x9000)
goto out;
err = register_netdev(dev);
if (err)
goto out1;
return dev;
out1:
cleanup_card(dev);
out:
free_netdev(dev);
return ERR_PTR(err);
}
static const struct net_device_ops ultra32_netdev_ops = {
.ndo_open = ultra32_open,
.ndo_stop = ultra32_close,
.ndo_start_xmit = ei_start_xmit,
.ndo_tx_timeout = ei_tx_timeout,
.ndo_get_stats = ei_get_stats,
.ndo_set_rx_mode = ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ei_poll,
#endif
};
static int __init ultra32_probe1(struct net_device *dev, int ioaddr)
{
int i, edge, media, retval;
int checksum = 0;
const char *model_name;
static unsigned version_printed;
/* Values from various config regs. */
unsigned char idreg;
unsigned char reg4;
const char *ifmap[] = {"UTP No Link", "", "UTP/AUI", "UTP/BNC"};
if (!request_region(ioaddr, ULTRA32_IO_EXTENT, DRV_NAME))
return -EBUSY;
if (inb(ioaddr + ULTRA32_IDPORT) == 0xff ||
inl(ioaddr + ULTRA32_IDPORT) != ULTRA32_ID) {
retval = -ENODEV;
goto out;
}
media = inb(ioaddr + ULTRA32_CFG7) & 0x03;
edge = inb(ioaddr + ULTRA32_CFG5) & 0x08;
printk("SMC Ultra32 in EISA Slot %d, Media: %s, %s IRQs.\n",
ioaddr >> 12, ifmap[media],
(edge ? "Edge Triggered" : "Level Sensitive"));
idreg = inb(ioaddr + 7);
reg4 = inb(ioaddr + 4) & 0x7f;
/* Check the ID nibble. */
if ((idreg & 0xf0) != 0x20) { /* SMC Ultra */
retval = -ENODEV;
goto out;
}
/* Select the station address register set. */
outb(reg4, ioaddr + 4);
for (i = 0; i < 8; i++)
checksum += inb(ioaddr + 8 + i);
if ((checksum & 0xff) != 0xff) {
retval = -ENODEV;
goto out;
}
if (ei_debug && version_printed++ == 0)
printk(version);
model_name = "SMC Ultra32";
for (i = 0; i < 6; i++)
dev->dev_addr[i] = inb(ioaddr + 8 + i);
printk("%s: %s at 0x%X, %pM",
dev->name, model_name, ioaddr, dev->dev_addr);
/* Switch from the station address to the alternate register set and
read the useful registers there. */
outb(0x80 | reg4, ioaddr + 4);
/* Enable FINE16 mode to avoid BIOS ROM width mismatches @ reboot. */
outb(0x80 | inb(ioaddr + 0x0c), ioaddr + 0x0c);
/* Reset RAM addr. */
outb(0x00, ioaddr + 0x0b);
/* Switch back to the station address register set so that the
MS-DOS driver can find the card after a warm boot. */
outb(reg4, ioaddr + 4);
if ((inb(ioaddr + ULTRA32_CFG5) & 0x40) == 0) {
printk("\nsmc-ultra32: Card RAM is disabled! "
"Run EISA config utility.\n");
retval = -ENODEV;
goto out;
}
if ((inb(ioaddr + ULTRA32_CFG2) & 0x04) == 0)
printk("\nsmc-ultra32: Ignoring Bus-Master enable bit. "
"Run EISA config utility.\n");
if (dev->irq < 2) {
unsigned char irqmap[] = {0, 9, 3, 5, 7, 10, 11, 15};
int irq = irqmap[inb(ioaddr + ULTRA32_CFG5) & 0x07];
if (irq == 0) {
printk(", failed to detect IRQ line.\n");
retval = -EAGAIN;
goto out;
}
dev->irq = irq;
}
/* The 8390 isn't at the base address, so fake the offset */
dev->base_addr = ioaddr + ULTRA32_NIC_OFFSET;
/* Save RAM address in the unused reg0 to avoid excess inb's. */
ei_status.reg0 = inb(ioaddr + ULTRA32_CFG3) & 0xfc;
dev->mem_start = 0xc0000 + ((ei_status.reg0 & 0x7c) << 11);
ei_status.name = model_name;
ei_status.word16 = 1;
ei_status.tx_start_page = 0;
ei_status.rx_start_page = TX_PAGES;
/* All Ultra32 cards have 32KB memory with an 8KB window. */
ei_status.stop_page = 128;
ei_status.mem = ioremap(dev->mem_start, 0x2000);
if (!ei_status.mem) {
printk(", failed to ioremap.\n");
retval = -ENOMEM;
goto out;
}
dev->mem_end = dev->mem_start + 0x1fff;
printk(", IRQ %d, 32KB memory, 8KB window at 0x%lx-0x%lx.\n",
dev->irq, dev->mem_start, dev->mem_end);
ei_status.block_input = &ultra32_block_input;
ei_status.block_output = &ultra32_block_output;
ei_status.get_8390_hdr = &ultra32_get_8390_hdr;
ei_status.reset_8390 = &ultra32_reset_8390;
dev->netdev_ops = &ultra32_netdev_ops;
NS8390_init(dev, 0);
return 0;
out:
release_region(ioaddr, ULTRA32_IO_EXTENT);
return retval;
}
static int ultra32_open(struct net_device *dev)
{
int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* ASIC addr */
int irq_flags = (inb(ioaddr + ULTRA32_CFG5) & 0x08) ? 0 : IRQF_SHARED;
int retval;
retval = request_irq(dev->irq, ei_interrupt, irq_flags, dev->name, dev);
if (retval)
return retval;
outb(ULTRA32_MEMENB, ioaddr); /* Enable Shared Memory. */
outb(0x80, ioaddr + ULTRA32_CFG6); /* Enable Interrupts. */
outb(0x84, ioaddr + 5); /* Enable MEM16 & Disable Bus Master. */
outb(0x01, ioaddr + 6); /* Enable Interrupts. */
/* Set the early receive warning level in window 0 high enough not
to receive ERW interrupts. */
outb_p(E8390_NODMA+E8390_PAGE0, dev->base_addr);
outb(0xff, dev->base_addr + EN0_ERWCNT);
ei_open(dev);
return 0;
}
static int ultra32_close(struct net_device *dev)
{
int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* CMDREG */
netif_stop_queue(dev);
if (ei_debug > 1)
printk("%s: Shutting down ethercard.\n", dev->name);
outb(0x00, ioaddr + ULTRA32_CFG6); /* Disable Interrupts. */
outb(0x00, ioaddr + 6); /* Disable interrupts. */
free_irq(dev->irq, dev);
NS8390_init(dev, 0);
return 0;
}
static void ultra32_reset_8390(struct net_device *dev)
{
int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* ASIC base addr */
outb(ULTRA32_RESET, ioaddr);
if (ei_debug > 1) printk("resetting Ultra32, t=%ld...", jiffies);
ei_status.txing = 0;
outb(ULTRA32_MEMENB, ioaddr); /* Enable Shared Memory. */
outb(0x80, ioaddr + ULTRA32_CFG6); /* Enable Interrupts. */
outb(0x84, ioaddr + 5); /* Enable MEM16 & Disable Bus Master. */
outb(0x01, ioaddr + 6); /* Enable Interrupts. */
if (ei_debug > 1) printk("reset done\n");
}
/* Grab the 8390 specific header. Similar to the block_input routine, but
we don't need to be concerned with ring wrap as the header will be at
the start of a page, so we optimize accordingly. */
static void ultra32_get_8390_hdr(struct net_device *dev,
struct e8390_pkt_hdr *hdr,
int ring_page)
{
void __iomem *hdr_start = ei_status.mem + ((ring_page & 0x1f) << 8);
unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3;
/* Select correct 8KB Window. */
outb(ei_status.reg0 | ((ring_page & 0x60) >> 5), RamReg);
#ifdef __BIG_ENDIAN
/* Officially this is what we are doing, but the readl() is faster */
/* unfortunately it isn't endian aware of the struct */
memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
hdr->count = le16_to_cpu(hdr->count);
#else
((unsigned int*)hdr)[0] = readl(hdr_start);
#endif
}
/* Block input and output are easy on shared memory ethercards, the only
complication is when the ring buffer wraps, or in this case, when a
packet spans an 8KB boundary. Note that the current 8KB segment is
already set by the get_8390_hdr routine. */
static void ultra32_block_input(struct net_device *dev,
int count,
struct sk_buff *skb,
int ring_offset)
{
void __iomem *xfer_start = ei_status.mem + (ring_offset & 0x1fff);
unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3;
if ((ring_offset & ~0x1fff) != ((ring_offset + count - 1) & ~0x1fff)) {
int semi_count = 8192 - (ring_offset & 0x1FFF);
memcpy_fromio(skb->data, xfer_start, semi_count);
count -= semi_count;
if (ring_offset < 96*256) {
/* Select next 8KB Window. */
ring_offset += semi_count;
outb(ei_status.reg0 | ((ring_offset & 0x6000) >> 13), RamReg);
memcpy_fromio(skb->data + semi_count, ei_status.mem, count);
} else {
/* Select first 8KB Window. */
outb(ei_status.reg0, RamReg);
memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
}
} else {
memcpy_fromio(skb->data, xfer_start, count);
}
}
static void ultra32_block_output(struct net_device *dev,
int count,
const unsigned char *buf,
int start_page)
{
void __iomem *xfer_start = ei_status.mem + (start_page<<8);
unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3;
/* Select first 8KB Window. */
outb(ei_status.reg0, RamReg);
memcpy_toio(xfer_start, buf, count);
}
#ifdef MODULE
#define MAX_ULTRA32_CARDS 4 /* Max number of Ultra cards per module */
static struct net_device *dev_ultra[MAX_ULTRA32_CARDS];
MODULE_DESCRIPTION("SMC Ultra32 EISA ethernet driver");
MODULE_LICENSE("GPL");
int __init init_module(void)
{
int this_dev, found = 0;
for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) {
struct net_device *dev = ultra32_probe(-1);
if (IS_ERR(dev))
break;
dev_ultra[found++] = dev;
}
if (found)
return 0;
printk(KERN_WARNING "smc-ultra32.c: No SMC Ultra32 found.\n");
return -ENXIO;
}
void __exit cleanup_module(void)
{
int this_dev;
for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) {
struct net_device *dev = dev_ultra[this_dev];
if (dev) {
unregister_netdev(dev);
cleanup_card(dev);
free_netdev(dev);
}
}
}
#endif /* MODULE */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment