Commit b513c765 authored by Stephen Hemminger's avatar Stephen Hemminger

[PATCH] (11/42) lance

Based on viro NE35-lance
	* switched lance to dynamic allocation
	* lance: fixed init_etherdev races
	* lance: fixed resource leaks on failure exits
	* NB: probing code is, to put it mildly, odd.  It _always_ does
	  autoprobe, modular or not.  WTF is going on there?
parent 1953882a
...@@ -85,7 +85,7 @@ extern int hplance_probe(struct net_device *dev); ...@@ -85,7 +85,7 @@ extern int hplance_probe(struct net_device *dev);
extern int bagetlance_probe(struct net_device *); extern int bagetlance_probe(struct net_device *);
extern int mvme147lance_probe(struct net_device *dev); extern int mvme147lance_probe(struct net_device *dev);
extern int tc515_probe(struct net_device *dev); extern int tc515_probe(struct net_device *dev);
extern int lance_probe(struct net_device *dev); extern struct net_device *lance_probe(int unit);
extern int mace_probe(struct net_device *dev); extern int mace_probe(struct net_device *dev);
extern int macsonic_probe(struct net_device *dev); extern int macsonic_probe(struct net_device *dev);
extern int mac8390_probe(struct net_device *dev); extern int mac8390_probe(struct net_device *dev);
...@@ -224,14 +224,14 @@ static struct devprobe isa_probes[] __initdata = { ...@@ -224,14 +224,14 @@ static struct devprobe isa_probes[] __initdata = {
#endif #endif
#if defined(CONFIG_NE2000) || defined(CONFIG_NE2K_CBUS) /* ISA & PC-9800 CBUS (use ne2k-pci for PCI cards) */ #if defined(CONFIG_NE2000) || defined(CONFIG_NE2K_CBUS) /* ISA & PC-9800 CBUS (use ne2k-pci for PCI cards) */
{ne_probe, 0}, {ne_probe, 0},
#endif
#ifdef CONFIG_LANCE /* ISA/VLB (use pcnet32 for PCI cards) */
{lance_probe, 0},
#endif #endif
{NULL, 0}, {NULL, 0},
}; };
static struct devprobe2 isa_probes2[] __initdata = { static struct devprobe2 isa_probes2[] __initdata = {
#ifdef CONFIG_LANCE /* ISA/VLB (use pcnet32 for PCI cards) */
{lance_probe, 0},
#endif
#ifdef CONFIG_SMC9194 #ifdef CONFIG_SMC9194
{smc_init, 0}, {smc_init, 0},
#endif #endif
......
...@@ -59,8 +59,8 @@ static const char version[] = "lance.c:v1.15ac 1999/11/13 dplatt@3do.com, becker ...@@ -59,8 +59,8 @@ static const char version[] = "lance.c:v1.15ac 1999/11/13 dplatt@3do.com, becker
#include <asm/dma.h> #include <asm/dma.h>
static unsigned int lance_portlist[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0}; static unsigned int lance_portlist[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0};
int lance_probe(struct net_device *dev);
static int lance_probe1(struct net_device *dev, int ioaddr, int irq, int options); static int lance_probe1(struct net_device *dev, int ioaddr, int irq, int options);
static int __init do_lance_probe(struct net_device *dev);
#ifdef LANCE_DEBUG #ifdef LANCE_DEBUG
static int lance_debug = LANCE_DEBUG; static int lance_debug = LANCE_DEBUG;
...@@ -274,7 +274,6 @@ enum {OLD_LANCE = 0, PCNET_ISA=1, PCNET_ISAP=2, PCNET_PCI=3, PCNET_VLB=4, PCNET_ ...@@ -274,7 +274,6 @@ enum {OLD_LANCE = 0, PCNET_ISA=1, PCNET_ISAP=2, PCNET_PCI=3, PCNET_VLB=4, PCNET_
static unsigned char lance_need_isa_bounce_buffers = 1; static unsigned char lance_need_isa_bounce_buffers = 1;
static int lance_open(struct net_device *dev); static int lance_open(struct net_device *dev);
static int lance_open_fail(struct net_device *dev);
static void lance_init_ring(struct net_device *dev, int mode); static void lance_init_ring(struct net_device *dev, int mode);
static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev); static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int lance_rx(struct net_device *dev); static int lance_rx(struct net_device *dev);
...@@ -286,10 +285,21 @@ static void lance_tx_timeout (struct net_device *dev); ...@@ -286,10 +285,21 @@ static void lance_tx_timeout (struct net_device *dev);
static void cleanup_card(struct net_device *dev)
{
struct lance_private *lp = dev->priv;
if (dev->dma != 4)
free_dma(dev->dma);
release_region(dev->base_addr, LANCE_TOTAL_SIZE);
kfree(lp->tx_bounce_buffs);
kfree((void*)lp->rx_buffs);
kfree(lp);
}
#ifdef MODULE #ifdef MODULE
#define MAX_CARDS 8 /* Max number of interfaces (cards) per module */ #define MAX_CARDS 8 /* Max number of interfaces (cards) per module */
static struct net_device dev_lance[MAX_CARDS]; static struct net_device *dev_lance[MAX_CARDS];
static int io[MAX_CARDS]; static int io[MAX_CARDS];
static int dma[MAX_CARDS]; static int dma[MAX_CARDS];
static int irq[MAX_CARDS]; static int irq[MAX_CARDS];
...@@ -305,28 +315,35 @@ MODULE_PARM_DESC(lance_debug, "LANCE/PCnet debug level (0-7)"); ...@@ -305,28 +315,35 @@ MODULE_PARM_DESC(lance_debug, "LANCE/PCnet debug level (0-7)");
int init_module(void) int init_module(void)
{ {
struct net_device *dev;
int this_dev, found = 0; int this_dev, found = 0;
for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) { for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) {
struct net_device *dev = &dev_lance[this_dev];
dev->irq = irq[this_dev];
dev->base_addr = io[this_dev];
dev->dma = dma[this_dev];
dev->init = lance_probe;
if (io[this_dev] == 0) { if (io[this_dev] == 0) {
if (this_dev != 0) break; /* only complain once */ if (this_dev != 0) /* only complain once */
break;
printk(KERN_NOTICE "lance.c: Module autoprobing not allowed. Append \"io=0xNNN\" value(s).\n"); printk(KERN_NOTICE "lance.c: Module autoprobing not allowed. Append \"io=0xNNN\" value(s).\n");
return -EPERM; return -EPERM;
} }
if (register_netdev(dev) != 0) { dev = alloc_etherdev(0);
printk(KERN_WARNING "lance.c: No PCnet/LANCE card found (i/o = 0x%x).\n", io[this_dev]); if (!dev)
if (found != 0) return 0; /* Got at least one. */ break;
return -ENXIO; dev->irq = irq[this_dev];
dev->base_addr = io[this_dev];
dev->dma = dma[this_dev];
if (do_lance_probe(dev) == 0) {
if (register_netdev(dev) == 0) {
dev_lance[found++] = dev;
continue;
}
cleanup_card(dev);
} }
found++; free_netdev(dev);
break;
} }
if (found != 0)
return 0; return 0;
return -ENXIO;
} }
void cleanup_module(void) void cleanup_module(void)
...@@ -334,13 +351,11 @@ void cleanup_module(void) ...@@ -334,13 +351,11 @@ void cleanup_module(void)
int this_dev; int this_dev;
for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) { for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) {
struct net_device *dev = &dev_lance[this_dev]; struct net_device *dev = dev_lance[this_dev];
if (dev->priv != NULL) { if (dev) {
unregister_netdev(dev); unregister_netdev(dev);
free_dma(dev->dma); cleanup_card(dev);
release_region(dev->base_addr, LANCE_TOTAL_SIZE); free_netdev(dev);
kfree(dev->priv);
dev->priv = NULL;
} }
} }
} }
...@@ -352,7 +367,7 @@ MODULE_LICENSE("GPL"); ...@@ -352,7 +367,7 @@ MODULE_LICENSE("GPL");
board probes now that kmalloc() can allocate ISA DMA-able regions. board probes now that kmalloc() can allocate ISA DMA-able regions.
This also allows the LANCE driver to be used as a module. This also allows the LANCE driver to be used as a module.
*/ */
int __init lance_probe(struct net_device *dev) static int __init do_lance_probe(struct net_device *dev)
{ {
int *port, result; int *port, result;
...@@ -387,6 +402,31 @@ int __init lance_probe(struct net_device *dev) ...@@ -387,6 +402,31 @@ int __init lance_probe(struct net_device *dev)
return -ENODEV; return -ENODEV;
} }
struct net_device * __init lance_probe(int unit)
{
struct net_device *dev = alloc_etherdev(0);
int err;
if (!dev)
return ERR_PTR(-ENODEV);
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
err = do_lance_probe(dev);
if (err)
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 int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int options) static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int options)
{ {
struct lance_private *lp; struct lance_private *lp;
...@@ -398,6 +438,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int ...@@ -398,6 +438,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
int hp_builtin = 0; /* HP on-board ethernet. */ int hp_builtin = 0; /* HP on-board ethernet. */
static int did_version; /* Already printed version info. */ static int did_version; /* Already printed version info. */
unsigned long flags; unsigned long flags;
int err = -ENOMEM;
/* First we look for special cases. /* First we look for special cases.
Check for HP's on-board ethernet by looking for 'HP' in the BIOS. Check for HP's on-board ethernet by looking for 'HP' in the BIOS.
...@@ -432,7 +473,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int ...@@ -432,7 +473,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
outw(88, ioaddr+LANCE_ADDR); outw(88, ioaddr+LANCE_ADDR);
if (inw(ioaddr+LANCE_ADDR) != 88) { if (inw(ioaddr+LANCE_ADDR) != 88) {
lance_version = 0; lance_version = 0;
} else { /* Good, it's a newer chip. */ } else { /* Good, it's a newer chip. */
int chip_version = inw(ioaddr+LANCE_DATA); int chip_version = inw(ioaddr+LANCE_DATA);
outw(89, ioaddr+LANCE_ADDR); outw(89, ioaddr+LANCE_ADDR);
chip_version |= inw(ioaddr+LANCE_DATA) << 16; chip_version |= inw(ioaddr+LANCE_DATA) << 16;
...@@ -447,13 +488,9 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int ...@@ -447,13 +488,9 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
} }
} }
/* We can't use init_etherdev() to allocate dev->priv because it must /* We can't allocate dev->priv from alloc_etherdev() because it must
a ISA DMA-able region. */ a ISA DMA-able region. */
dev = init_etherdev(dev, 0);
if (!dev)
return -ENOMEM;
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
dev->open = lance_open_fail;
chipname = chip_table[lance_version].name; chipname = chip_table[lance_version].name;
printk("%s: %s at %#3x,", dev->name, chipname, ioaddr); printk("%s: %s at %#3x,", dev->name, chipname, ioaddr);
...@@ -465,8 +502,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int ...@@ -465,8 +502,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
dev->base_addr = ioaddr; dev->base_addr = ioaddr;
/* Make certain the data structures used by the LANCE are aligned and DMAble. */ /* Make certain the data structures used by the LANCE are aligned and DMAble. */
lp = (struct lance_private *)(((unsigned long)kmalloc(sizeof(*lp)+7, lp = kmalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL);
GFP_DMA | GFP_KERNEL)+7) & ~7);
if(lp==NULL) if(lp==NULL)
return -ENODEV; return -ENODEV;
if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp); if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp);
...@@ -486,7 +522,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int ...@@ -486,7 +522,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
lp->tx_bounce_buffs = NULL; lp->tx_bounce_buffs = NULL;
lp->chip_version = lance_version; lp->chip_version = lance_version;
lp->devlock = SPIN_LOCK_UNLOCKED; spin_lock_init(&lp->devlock);
lp->init_block.mode = 0x0003; /* Disable Rx and Tx. */ lp->init_block.mode = 0x0003; /* Disable Rx and Tx. */
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++)
...@@ -540,6 +576,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int ...@@ -540,6 +576,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) | dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) |
(inb(DMA2_STAT_REG) & 0xf0); (inb(DMA2_STAT_REG) & 0xf0);
} }
err = -ENODEV;
if (dev->irq >= 2) if (dev->irq >= 2)
printk(" assigned IRQ %d", dev->irq); printk(" assigned IRQ %d", dev->irq);
else if (lance_version != 0) { /* 7990 boards need DMA detection first. */ else if (lance_version != 0) { /* 7990 boards need DMA detection first. */
...@@ -559,7 +596,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int ...@@ -559,7 +596,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
printk(", probed IRQ %d", dev->irq); printk(", probed IRQ %d", dev->irq);
else { else {
printk(", failed to detect IRQ line.\n"); printk(", failed to detect IRQ line.\n");
return -ENODEV; goto out_tx;
} }
/* Check for the initialization done bit, 0x0100, which means /* Check for the initialization done bit, 0x0100, which means
...@@ -573,7 +610,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int ...@@ -573,7 +610,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
} else if (dev->dma) { } else if (dev->dma) {
if (request_dma(dev->dma, chipname)) { if (request_dma(dev->dma, chipname)) {
printk("DMA %d allocation failed.\n", dev->dma); printk("DMA %d allocation failed.\n", dev->dma);
return -ENODEV; goto out_tx;
} else } else
printk(", assigned DMA %d.\n", dev->dma); printk(", assigned DMA %d.\n", dev->dma);
} else { /* OK, we have to auto-DMA. */ } else { /* OK, we have to auto-DMA. */
...@@ -613,7 +650,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int ...@@ -613,7 +650,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
} }
if (i == 4) { /* Failure: bail. */ if (i == 4) { /* Failure: bail. */
printk("DMA detection failed.\n"); printk("DMA detection failed.\n");
return -ENODEV; goto out_tx;
} }
} }
...@@ -629,7 +666,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int ...@@ -629,7 +666,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
dev->irq = probe_irq_off(irq_mask); dev->irq = probe_irq_off(irq_mask);
if (dev->irq == 0) { if (dev->irq == 0) {
printk(" Failed to detect the 7990 IRQ line.\n"); printk(" Failed to detect the 7990 IRQ line.\n");
return -ENODEV; goto out_dma;
} }
printk(" Auto-IRQ detected IRQ%d.\n", dev->irq); printk(" Auto-IRQ detected IRQ%d.\n", dev->irq);
} }
...@@ -655,18 +692,18 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int ...@@ -655,18 +692,18 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
dev->watchdog_timeo = TX_TIMEOUT; dev->watchdog_timeo = TX_TIMEOUT;
return 0; return 0;
out_rx: kfree((void*)lp->rx_buffs); out_dma:
out_lp: kfree(lp); if (dev->dma != 4)
return -ENOMEM; free_dma(dev->dma);
} out_tx:
kfree(lp->tx_bounce_buffs);
static int out_rx:
lance_open_fail(struct net_device *dev) kfree((void*)lp->rx_buffs);
{ out_lp:
return -ENODEV; kfree(lp);
return err;
} }
static int static int
lance_open(struct net_device *dev) lance_open(struct net_device *dev)
......
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