-/*
+/*
net-3-driver for the IBM LAN Adapter/A
This is an extension to the Linux operating system, and is covered by the
SK_G16 and 3C523 driver.
paper sources:
- 'PC Hardware: Aufbau, Funktionsweise, Programmierung' by
+ 'PC Hardware: Aufbau, Funktionsweise, Programmierung' by
Hans-Peter Messmer for the basic Microchannel stuff
-
+
'Linux Geraetetreiber' by Allesandro Rubini, Kalle Dalheimer
for help on Ethernet driver programming
special acknowledgements to:
- Bob Eager for helping me out with documentation from IBM
- - Jim Shorney for his endless patience with me while I was using
+ - Jim Shorney for his endless patience with me while I was using
him as a beta tester to trace down the address filter bug ;-)
Missing things:
-> set debug level via ioctl instead of compile-time switches
-> I didn't follow the development of the 2.1.x kernels, so my
- assumptions about which things changed with which kernel version
+ assumptions about which things changed with which kernel version
are probably nonsense
History:
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+#include <linux/bitops.h>
#include <asm/processor.h>
-#include <asm/bitops.h>
#include <asm/io.h>
#define _IBM_LANA_DRIVER_
static void dumpmem(struct net_device *dev, u32 start, u32 len)
{
+ ibmlana_priv *priv = netdev_priv(dev);
int z;
printk("Address %04x:\n", start);
for (z = 0; z < len; z++) {
if ((z & 15) == 0)
printk("%04x:", z);
- printk(" %02x", isa_readb(dev->mem_start + start + z));
+ printk(" %02x", readb(priv->base + start + z));
if ((z & 15) == 15)
printk("\n");
}
static void InitDscrs(struct net_device *dev)
{
- ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+ ibmlana_priv *priv = netdev_priv(dev);
u32 addr, baddr, raddr;
int z;
tda_t tda;
/* initialize RAM */
- isa_memset_io(dev->mem_start, 0xaa,
- dev->mem_start - dev->mem_start);
+ memset_io(priv->base, 0xaa,
+ dev->mem_start - dev->mem_start); /* XXX: typo? */
/* setup n TX descriptors - independent of RAM size */
else
tda.link = addr + sizeof(tda_t);
tda.link |= 1;
- isa_memcpy_toio(dev->mem_start + addr, &tda, sizeof(tda_t));
+ memcpy_toio(priv->base + addr, &tda, sizeof(tda_t));
addr += sizeof(tda_t);
baddr += PKTSIZE;
}
priv->rrastart = raddr = priv->txbufstart + (TXBUFCNT * PKTSIZE);
priv->rdastart = addr = priv->rrastart + (priv->rxbufcnt * sizeof(rra_t));
priv->rxbufstart = baddr = priv->rdastart + (priv->rxbufcnt * sizeof(rda_t));
-
+
for (z = 0; z < priv->rxbufcnt; z++) {
rra.startlo = baddr;
rra.starthi = 0;
rra.cntlo = PKTSIZE >> 1;
rra.cnthi = 0;
- isa_memcpy_toio(dev->mem_start + raddr, &rra, sizeof(rra_t));
+ memcpy_toio(priv->base + raddr, &rra, sizeof(rra_t));
rda.status = 0;
rda.length = 0;
else
rda.link = 1;
rda.inuse = 1;
- isa_memcpy_toio(dev->mem_start + addr, &rda, sizeof(rda_t));
+ memcpy_toio(priv->base + addr, &rda, sizeof(rda_t));
baddr += PKTSIZE;
raddr += sizeof(rra_t);
static int InitSONIC(struct net_device *dev)
{
- ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+ ibmlana_priv *priv = netdev_priv(dev);
/* set up start & end of resource area */
static void InitBoard(struct net_device *dev)
{
+ ibmlana_priv *priv = netdev_priv(dev);
int camcnt;
camentry_t cams[16];
u32 cammask;
/* feed CDA into SONIC, initialize RCR value (always get broadcasts) */
- isa_memcpy_toio(dev->mem_start, cams, sizeof(camentry_t) * camcnt);
- isa_memcpy_toio(dev->mem_start + (sizeof(camentry_t) * camcnt), &cammask, sizeof(cammask));
+ memcpy_toio(priv->base, cams, sizeof(camentry_t) * camcnt);
+ memcpy_toio(priv->base + (sizeof(camentry_t) * camcnt), &cammask, sizeof(cammask));
#ifdef DEBUG
printk("CAM setup:\n");
static void StartTx(struct net_device *dev, int descr)
{
- ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+ ibmlana_priv *priv = netdev_priv(dev);
int addr;
addr = priv->tdastart + (descr * sizeof(tda_t));
static void irqrbe_handler(struct net_device *dev)
{
- ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+ ibmlana_priv *priv = netdev_priv(dev);
/* point the SONIC back to the RRA start */
static void irqrx_handler(struct net_device *dev)
{
- ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+ ibmlana_priv *priv = netdev_priv(dev);
rda_t rda;
u32 rdaaddr, lrdaaddr;
rdaaddr = priv->rdastart + (priv->nextrxdescr * sizeof(rda_t));
lrdaaddr = priv->rdastart + (priv->lastrxdescr * sizeof(rda_t));
- isa_memcpy_fromio(&rda, dev->mem_start + rdaaddr, sizeof(rda_t));
+ memcpy_fromio(&rda, priv->base + rdaaddr, sizeof(rda_t));
- /* iron out upper word halves of fields we use - SONIC will duplicate
+ /* iron out upper word halves of fields we use - SONIC will duplicate
bits 0..15 to 16..31 */
rda.status &= 0xffff;
else {
/* copy out data */
- isa_memcpy_fromio(skb_put(skb, rda.length),
- dev->mem_start +
+ memcpy_fromio(skb_put(skb, rda.length),
+ priv->base +
rda.startlo, rda.length);
/* set up skb fields */
rda.link = 1;
rda.inuse = 1;
- isa_memcpy_toio(dev->mem_start + rdaaddr, &rda,
+ memcpy_toio(priv->base + rdaaddr, &rda,
sizeof(rda_t));
/* set up link and EOL = 0 in currently last descriptor. Only write
the link field since the SONIC may currently already access the
other fields. */
- isa_memcpy_toio(dev->mem_start + lrdaaddr + 20, &rdaaddr, 4);
+ memcpy_toio(priv->base + lrdaaddr + 20, &rdaaddr, 4);
/* advance indices */
static void irqtx_handler(struct net_device *dev)
{
- ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+ ibmlana_priv *priv = netdev_priv(dev);
tda_t tda;
/* fetch descriptor (we forgot the size ;-) */
- isa_memcpy_fromio(&tda, dev->mem_start + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
+ memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
/* update statistics */
priv->stat.tx_packets++;
static void irqtxerr_handler(struct net_device *dev)
{
- ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+ ibmlana_priv *priv = netdev_priv(dev);
tda_t tda;
/* fetch descriptor to check status */
- isa_memcpy_fromio(&tda, dev->mem_start + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
+ memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
/* update statistics */
priv->stat.tx_errors++;
/* general interrupt entry */
-static irqreturn_t irq_handler(int irq, void *device, struct pt_regs *regs)
+static irqreturn_t irq_handler(int irq, void *device)
{
struct net_device *dev = (struct net_device *) device;
u16 ival;
if (dev == NULL)
return len;
- if (dev->priv == NULL)
- return len;
- priv = (ibmlana_priv *) dev->priv;
+ priv = netdev_priv(dev);
/* print info */
static int ibmlana_open(struct net_device *dev)
{
int result;
- ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+ ibmlana_priv *priv = netdev_priv(dev);
/* register resources - only necessary for IRQ */
- result = request_irq(priv->realirq, irq_handler, SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev);
+ result = request_irq(priv->realirq, irq_handler, IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev);
if (result != 0) {
printk(KERN_ERR "%s: failed to register irq %d\n", dev->name, dev->irq);
return result;
static int ibmlana_tx(struct sk_buff *skb, struct net_device *dev)
{
- ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+ ibmlana_priv *priv = netdev_priv(dev);
int retval = 0, tmplen, addr;
unsigned long flags;
tda_t tda;
if (tmplen < 60)
tmplen = 60;
baddr = priv->txbufstart + (priv->nexttxdescr * PKTSIZE);
- isa_memcpy_toio(dev->mem_start + baddr, skb->data, skb->len);
+ memcpy_toio(priv->base + baddr, skb->data, skb->len);
- /* copy filler into RAM - in case we're filling up...
+ /* copy filler into RAM - in case we're filling up...
we're filling a bit more than necessary, but that doesn't harm
- since the buffer is far larger...
+ since the buffer is far larger...
Sorry Linus for the filler string but I couldn't resist ;-) */
if (tmplen > skb->len) {
unsigned int destoffs = skb->len, l = strlen(fill);
while (destoffs < tmplen) {
- isa_memcpy_toio(dev->mem_start + baddr + destoffs, fill, l);
+ memcpy_toio(priv->base + baddr + destoffs, fill, l);
destoffs += l;
}
}
/* set up the new frame descriptor */
addr = priv->tdastart + (priv->nexttxdescr * sizeof(tda_t));
- isa_memcpy_fromio(&tda, dev->mem_start + addr, sizeof(tda_t));
+ memcpy_fromio(&tda, priv->base + addr, sizeof(tda_t));
tda.length = tda.fraglength = tmplen;
- isa_memcpy_toio(dev->mem_start + addr, &tda, sizeof(tda_t));
+ memcpy_toio(priv->base + addr, &tda, sizeof(tda_t));
/* if there were no active descriptors, trigger the SONIC */
spin_lock_irqsave(&priv->lock, flags);
static struct net_device_stats *ibmlana_stats(struct net_device *dev)
{
- ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+ ibmlana_priv *priv = netdev_priv(dev);
return &priv->stat;
}
-/* we don't support runtime reconfiguration, since am MCA card can
- be unambigously identified by its POS registers. */
-
-static int ibmlana_config(struct net_device *dev, struct ifmap *map)
-{
- return 0;
-}
-
/* switch receiver mode. */
static void ibmlana_set_multicast_list(struct net_device *dev)
static int ibmlana_probe(struct net_device *dev)
{
- int force_detect = 0;
int slot, z;
int base = 0, irq = 0, iobase = 0, memlen = 0;
ibmlana_priv *priv;
if (MCA_bus == 0)
return -ENODEV;
- /* start address of 1 --> forced detection */
- if (dev->mem_start == 1)
- force_detect = 1;
-
base = dev->mem_start;
irq = dev->irq;
return -EBUSY;
}
- /* make procfs entries */
- mca_set_adapter_name(slot, "IBM LAN Adapter/A");
- mca_set_adapter_procfn(slot, (MCA_ProcFn) ibmlana_getinfo, dev);
-
- mca_mark_as_used(slot);
-
- /* allocate structure */
- priv = dev->priv;
+ priv = netdev_priv(dev);
priv->slot = slot;
priv->realirq = irq;
priv->medium = medium;
spin_lock_init(&priv->lock);
+
/* set base + irq for this device (irq not allocated so far) */
dev->irq = 0;
dev->mem_end = base + memlen;
dev->base_addr = iobase;
+ priv->base = ioremap(base, memlen);
+ if (!priv->base) {
+ printk(KERN_ERR "%s: cannot remap memory!\n", DRV_NAME);
+ startslot = slot + 1;
+ release_region(iobase, IBM_LANA_IORANGE);
+ return -EBUSY;
+ }
+
+ /* make procfs entries */
+ mca_set_adapter_name(slot, "IBM LAN Adapter/A");
+ mca_set_adapter_procfn(slot, (MCA_ProcFn) ibmlana_getinfo, dev);
+
+ mca_mark_as_used(slot);
+
/* set methods */
dev->open = ibmlana_open;
dev->stop = ibmlana_close;
- dev->set_config = ibmlana_config;
dev->hard_start_xmit = ibmlana_tx;
dev->do_ioctl = NULL;
dev->get_stats = ibmlana_stats;
static int irq;
static int io;
-MODULE_PARM(irq, "i");
-MODULE_PARM(io, "i");
+module_param(irq, int, 0);
+module_param(io, int, 0);
MODULE_PARM_DESC(irq, "IBM LAN/A IRQ number");
MODULE_PARM_DESC(io, "IBM LAN/A I/O base address");
MODULE_LICENSE("GPL");
break;
}
if (register_netdev(dev)) {
- ibmlana_priv *priv = dev->priv;
+ ibmlana_priv *priv = netdev_priv(dev);
release_region(dev->base_addr, IBM_LANA_IORANGE);
mca_mark_as_unused(priv->slot);
mca_set_adapter_name(priv->slot, "");
mca_set_adapter_procfn(priv->slot, NULL, NULL);
+ iounmap(priv->base);
free_netdev(dev);
break;
}
for (z = 0; z < DEVMAX; z++) {
struct net_device *dev = moddevs[z];
if (dev) {
- ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+ ibmlana_priv *priv = netdev_priv(dev);
unregister_netdev(dev);
/*DeinitBoard(dev); */
release_region(dev->base_addr, IBM_LANA_IORANGE);
mca_mark_as_unused(priv->slot);
mca_set_adapter_name(priv->slot, "");
mca_set_adapter_procfn(priv->slot, NULL, NULL);
+ iounmap(priv->base);
free_netdev(dev);
}
}