Commit d3f25fbf authored by Stephen Hemminger's avatar Stephen Hemminger

[PATCH] (21/42) sk_mca

NE45-sk_mca
	* switched sk-mca to dynamic allocation
	* sk-mca: switched to embedded ->priv
	* sk-mca: fixed order of freeing bugs
	* sk-mca: fixed resource leaks on failure exits
parent 1d07e29e
...@@ -61,7 +61,7 @@ extern struct net_device *wavelan_probe(int unit); ...@@ -61,7 +61,7 @@ extern struct net_device *wavelan_probe(int unit);
extern struct net_device *arlan_probe(int unit); extern struct net_device *arlan_probe(int unit);
extern struct net_device *el16_probe(int unit); extern struct net_device *el16_probe(int unit);
extern int elmc_probe(struct net_device *); extern int elmc_probe(struct net_device *);
extern int skmca_probe(struct net_device *); extern struct net_device *skmca_probe(int unit);
extern struct net_device *elplus_probe(int unit); extern struct net_device *elplus_probe(int unit);
extern int ac3200_probe(struct net_device *); extern int ac3200_probe(struct net_device *);
extern int es_probe(struct net_device *); extern int es_probe(struct net_device *);
...@@ -187,6 +187,10 @@ static struct devprobe mca_probes[] __initdata = { ...@@ -187,6 +187,10 @@ static struct devprobe mca_probes[] __initdata = {
#ifdef CONFIG_ELMC_II /* 3c527 */ #ifdef CONFIG_ELMC_II /* 3c527 */
{mc32_probe, 0}, {mc32_probe, 0},
#endif #endif
{NULL, 0},
};
static struct devprobe2 mca_probes2[] __initdata = {
#ifdef CONFIG_SKMC /* SKnet Microchannel */ #ifdef CONFIG_SKMC /* SKnet Microchannel */
{skmca_probe, 0}, {skmca_probe, 0},
#endif #endif
...@@ -394,6 +398,7 @@ static void __init ethif_probe2(int unit) ...@@ -394,6 +398,7 @@ static void __init ethif_probe2(int unit)
if (base_addr == 1) if (base_addr == 1)
return; return;
probe_list2(unit, mca_probes2, base_addr == 0) &&
probe_list2(unit, isa_probes2, base_addr == 0) && probe_list2(unit, isa_probes2, base_addr == 0) &&
probe_list2(unit, parport_probes, base_addr == 0); probe_list2(unit, parport_probes, base_addr == 0);
} }
......
...@@ -1022,18 +1022,39 @@ static void skmca_set_multicast_list(struct net_device *dev) ...@@ -1022,18 +1022,39 @@ static void skmca_set_multicast_list(struct net_device *dev)
static int startslot; /* counts through slots when probing multiple devices */ static int startslot; /* counts through slots when probing multiple devices */
int __init skmca_probe(struct net_device *dev) static void cleanup_card(struct net_device *dev)
{ {
skmca_priv *priv = dev->priv;
DeinitBoard(dev);
if (dev->irq != 0)
free_irq(dev->irq, dev);
mca_mark_as_unused(priv->slot);
mca_set_adapter_procfn(priv->slot, NULL, NULL);
}
struct net_device * __init skmca_probe(int unit)
{
struct net_device *dev;
int force_detect = 0; int force_detect = 0;
int junior, slot, i; int junior, slot, i;
int base = 0, irq = 0; int base = 0, irq = 0;
skmca_priv *priv; skmca_priv *priv;
skmca_medium medium; skmca_medium medium;
int err;
/* can't work without an MCA bus ;-) */ /* can't work without an MCA bus ;-) */
if (MCA_bus == 0) if (MCA_bus == 0)
return -ENODEV; return ERR_PTR(-ENODEV);
dev = alloc_etherdev(sizeof(skmca_priv));
if (!dev)
return ERR_PTR(-ENOMEM);
if (unit >= 0) {
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
}
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
...@@ -1044,37 +1065,24 @@ int __init skmca_probe(struct net_device *dev) ...@@ -1044,37 +1065,24 @@ int __init skmca_probe(struct net_device *dev)
/* search through slots */ /* search through slots */
if (dev != NULL) { base = dev->mem_start;
base = dev->mem_start; irq = dev->base_addr;
irq = dev->irq; for (slot = startslot; (slot = dofind(&junior, slot)) != -1; slot++) {
}
slot = dofind(&junior, startslot);
while (slot != -1) {
/* deduce card addresses */ /* deduce card addresses */
getaddrs(slot, junior, &base, &irq, &medium); getaddrs(slot, junior, &base, &irq, &medium);
/* slot already in use ? */ /* slot already in use ? */
if (mca_is_adapter_used(slot)) { if (mca_is_adapter_used(slot))
slot = dofind(&junior, slot + 1);
continue; continue;
}
/* were we looking for something different ? */ /* were we looking for something different ? */
if ((dev->irq != 0) || (dev->mem_start != 0)) { if (dev->irq && dev->irq != irq)
if ((dev->irq != 0) && (dev->irq != irq)) { continue;
slot = dofind(&junior, slot + 1); if (dev->mem_start && dev->mem_start != base)
continue; continue;
}
if ((dev->mem_start != 0)
&& (dev->mem_start != base)) {
slot = dofind(&junior, slot + 1);
continue;
}
}
/* found something that matches */ /* found something that matches */
...@@ -1083,8 +1091,10 @@ int __init skmca_probe(struct net_device *dev) ...@@ -1083,8 +1091,10 @@ int __init skmca_probe(struct net_device *dev)
/* nothing found ? */ /* nothing found ? */
if (slot == -1) if (slot == -1) {
return ((base != 0) || (irq != 0)) ? ENXIO : ENODEV; free_netdev(dev);
return (base || irq) ? ERR_PTR(-ENXIO) : ERR_PTR(-ENODEV);
}
/* make procfs entries */ /* make procfs entries */
...@@ -1102,17 +1112,14 @@ int __init skmca_probe(struct net_device *dev) ...@@ -1102,17 +1112,14 @@ int __init skmca_probe(struct net_device *dev)
junior ? "Junior MC2" : "MC2+", slot + 1); junior ? "Junior MC2" : "MC2+", slot + 1);
/* allocate structure */ /* allocate structure */
priv = dev->priv = priv = dev->priv;
(skmca_priv *) kmalloc(sizeof(skmca_priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->slot = slot; priv->slot = slot;
priv->macbase = base + 0x3fc0; priv->macbase = base + 0x3fc0;
priv->ioregaddr = base + 0x3ff0; priv->ioregaddr = base + 0x3ff0;
priv->ctrladdr = base + 0x3ff2; priv->ctrladdr = base + 0x3ff2;
priv->cmdaddr = base + 0x3ff3; priv->cmdaddr = base + 0x3ff3;
priv->medium = medium; priv->medium = medium;
memset(&(priv->stat), 0, sizeof(struct net_device_stats)); memset(&priv->stat, 0, sizeof(struct net_device_stats));
spin_lock_init(&priv->lock); spin_lock_init(&priv->lock);
/* set base + irq for this device (irq not allocated so far) */ /* set base + irq for this device (irq not allocated so far) */
...@@ -1146,9 +1153,6 @@ int __init skmca_probe(struct net_device *dev) ...@@ -1146,9 +1153,6 @@ int __init skmca_probe(struct net_device *dev)
dev->set_multicast_list = skmca_set_multicast_list; dev->set_multicast_list = skmca_set_multicast_list;
dev->flags |= IFF_MULTICAST; dev->flags |= IFF_MULTICAST;
/* generic setup */
ether_setup(dev);
/* copy out MAC address */ /* copy out MAC address */
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++)
dev->dev_addr[i] = SKMCA_READB(priv->macbase + (i << 1)); dev->dev_addr[i] = SKMCA_READB(priv->macbase + (i << 1));
...@@ -1167,7 +1171,13 @@ int __init skmca_probe(struct net_device *dev) ...@@ -1167,7 +1171,13 @@ int __init skmca_probe(struct net_device *dev)
startslot = slot + 1; startslot = slot + 1;
return 0; err = register_netdev(dev);
if (err) {
cleanup_card(dev);
free_netdev(dev);
dev = ERR_PTR(err);
}
return dev;
} }
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
...@@ -1179,51 +1189,34 @@ MODULE_LICENSE("GPL"); ...@@ -1179,51 +1189,34 @@ MODULE_LICENSE("GPL");
#define DEVMAX 5 #define DEVMAX 5
static struct net_device moddevs[DEVMAX] = { static struct net_device *moddevs[DEVMAX];
{ .name = " ", .init = skmca_probe },
{ .name = " ", .init = skmca_probe },
{ .name = " ", .init = skmca_probe },
{ .name = " ", .init = skmca_probe },
{ .name = " ", .init = skmca_probe }
};
int irq;
int io;
int init_module(void) int init_module(void)
{ {
int z, res; int z;
startslot = 0; startslot = 0;
for (z = 0; z < DEVMAX; z++) { for (z = 0; z < DEVMAX; z++) {
strcpy(moddevs[z].name, " "); struct net_device *dev = skmca_probe(-1);
res = register_netdev(moddevs + z); if (IS_ERR(dev))
if (res != 0) break;
return (z > 0) ? 0 : -EIO; moddevs[z] = dev;
} }
if (!z)
return -EIO;
return 0; return 0;
} }
void cleanup_module(void) void cleanup_module(void)
{ {
struct net_device *dev;
skmca_priv *priv;
int z; int z;
for (z = 0; z < DEVMAX; z++) { for (z = 0; z < DEVMAX; z++) {
dev = moddevs + z; struct net_device *dev = moddevs[z];
if (dev->priv != NULL) { if (dev) {
priv = (skmca_priv *) dev->priv;
DeinitBoard(dev);
if (dev->irq != 0)
free_irq(dev->irq, dev);
dev->irq = 0;
unregister_netdev(dev); unregister_netdev(dev);
mca_mark_as_unused(priv->slot); cleanup_card(dev);
mca_set_adapter_procfn(priv->slot, NULL, NULL); free_netdev(dev);
kfree(dev->priv);
dev->priv = NULL;
} }
} }
} }
......
...@@ -178,7 +178,4 @@ typedef struct { /* LANCE Rx descriptor */ ...@@ -178,7 +178,4 @@ typedef struct { /* LANCE Rx descriptor */
#endif /* _SK_MCA_DRIVER_ */ #endif /* _SK_MCA_DRIVER_ */
extern int skmca_probe(struct net_device *);
#endif /* _SK_MCA_INCLUDE_ */ #endif /* _SK_MCA_INCLUDE_ */
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