summaryrefslogtreecommitdiffstats
path: root/drivers/net/lance.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-02-15 02:15:32 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-02-15 02:15:32 +0000
commit86464aed71025541805e7b1515541aee89879e33 (patch)
treee01a457a4912a8553bc65524aa3125d51f29f810 /drivers/net/lance.c
parent88f99939ecc6a95a79614574cb7d95ffccfc3466 (diff)
Merge with Linux 2.2.1.
Diffstat (limited to 'drivers/net/lance.c')
-rw-r--r--drivers/net/lance.c284
1 files changed, 177 insertions, 107 deletions
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index 15f7f9ad7..659983655 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -1,6 +1,6 @@
-/* lance.c: An AMD LANCE ethernet driver for linux. */
+/* lance.c: An AMD LANCE/PCnet ethernet driver for Linux. */
/*
- Written 1993,1994,1995 by Donald Becker.
+ Written/copyright 1993-1998 by Donald Becker.
Copyright 1993 United States Government as represented by the
Director, National Security Agency.
@@ -8,13 +8,12 @@
of the GNU Public License, incorporated herein by reference.
This driver is for the Allied Telesis AT1500 and HP J2405A, and should work
- with most other LANCE-based bus-master (NE2100 clone) ethercards.
+ with most other LANCE-based bus-master (NE2100/NE2500) ethercards.
The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
Center of Excellence in Space Data and Information Sciences
Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
-
Fixing alignment problem with 1.3.* kernel and some minor changes
by Andrey V. Savochkin, 1996.
@@ -28,14 +27,28 @@
But I should to inform you that I'm not an expert in the LANCE card
and it may occurs that you will receive no answer on your mail
to Donald Becker. I didn't receive any answer on all my letters
- to him. Who knows why... But may be you are more lucky? ;-)
+ to him. Who knows why... But may be you are more lucky? ;->
SAW
- Fixed 7990 autoIRQ failure and reversed unneeded alignment. 8/20/96 djb
+
+ Thomas Bogendoerfer (tsbogend@bigbug.franken.de):
+ - added support for Linux/Alpha, but removed most of it, because
+ it worked only for the PCI chip.
+ - added hook for the 32bit lance driver
+ - added PCnetPCI II (79C970A) to chip table
+ Paul Gortmaker (gpg109@rsphy1.anu.edu.au):
+ - hopefully fix above so Linux/Alpha can use ISA cards too.
+ 8/20/96 Fixed 7990 autoIRQ failure and reversed unneeded alignment -djb
+ v1.12 10/27/97 Module support -djb
+ v1.14 2/3/98 Module support modified, made PCI support optional -djb
+
+ Forward ported v1.14 to 2.1.129, merged the PCI and misc changes from
+ the 2.1 version of the old driver - Alan Cox
*/
-static const char *version = "lance.c:v1.09 Aug 20 1996 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
+static const char *version = "lance.c:v1.14ac 1998/11/20 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
#include <linux/config.h>
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -54,13 +67,9 @@ static const char *version = "lance.c:v1.09 Aug 20 1996 dplatt@3do.com, becker@c
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-static unsigned int lance_portlist[] __initdata = {0x300, 0x320, 0x340, 0x360, 0};
-void lance_probe1(int ioaddr);
-
-#ifdef HAVE_DEVLIST
-struct netdev_entry lance_drv =
-{"lance", lance_probe1, LANCE_TOTAL_SIZE, lance_portlist};
-#endif
+static unsigned int lance_portlist[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0};
+int lance_probe(struct device *dev);
+int lance_probe1(struct device *dev, int ioaddr, int irq, int options);
#ifdef LANCE_DEBUG
int lance_debug = LANCE_DEBUG;
@@ -96,7 +105,7 @@ of the otherwise-unused dev->mem_start value (aka PARAM1). If unset it is
probed for by enabling each free DMA channel in turn and checking if
initialization succeeds.
-The HP-J2405A board is an exception: with this board it's easy to read the
+The HP-J2405A board is an exception: with this board it is easy to read the
EEPROM-set values for the base, IRQ, and DMA. (Of course you must already
_know_ the base address -- that field is for writing the EEPROM.)
@@ -147,36 +156,19 @@ queue slot is empty, it clears the tbusy flag when finished otherwise it sets
the 'lp->tx_full' flag.
The interrupt handler has exclusive control over the Rx ring and records stats
-from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so
+from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so
we can't avoid the interrupt overhead by having the Tx routine reap the Tx
stats.) After reaping the stats, it marks the queue entry as empty by setting
-the 'base' to zero. Iff the 'lp->tx_full' flag is set, it clears both the
+the 'base' to zero. Iff the 'lp->tx_full' flag is set, it clears both the
tx_full and tbusy flags.
*/
-/* Memory accessed from LANCE card must be aligned on 8-byte boundaries.
- But we can't believe that kmalloc()'ed memory satisfies it. -- SAW */
-#define LANCE_KMALLOC(x) \
- ((void *) (((unsigned long)kmalloc((x)+7, GFP_DMA | GFP_KERNEL)+7) & ~7))
-
-/*
- * Changes:
- * Thomas Bogendoerfer (tsbogend@alpha.franken.de):
- * - added support for Linux/Alpha, but removed most of it, because
- * it worked only for the PCI chip.
- * - added hook for the 32bit lance driver
- * - added PCnetPCI II (79C970A) to chip table
- * - made 32bit driver standalone
- * - changed setting of autoselect bit
- *
- * Paul Gortmaker (gpg109@rsphy1.anu.edu.au):
- * - hopefully fix above so Linux/Alpha can use ISA cards too.
- */
-
/* Set the number of Tx and Rx buffers, using Log_2(# buffers).
Reasonable default values are 16 Tx buffers, and 16 Rx buffers.
- That translates to 4 and 4 (16 == 2^^4). */
+ That translates to 4 and 4 (16 == 2^^4).
+ This is a compile-time option for efficiency.
+ */
#ifndef LANCE_LOG_TX_BUFFERS
#define LANCE_LOG_TX_BUFFERS 4
#define LANCE_LOG_RX_BUFFERS 4
@@ -230,6 +222,8 @@ struct lance_private {
const char *name;
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
struct sk_buff* tx_skbuff[TX_RING_SIZE];
+ /* The addresses of receive-in-place skbuffs. */
+ struct sk_buff* rx_skbuff[RX_RING_SIZE];
unsigned long rx_buffs; /* Address of Rx and Tx buffers. */
/* Tx low-memory "bounce buffer" address. */
char (*tx_bounce_buffs)[PKT_BUF_SZ];
@@ -247,7 +241,6 @@ struct lance_private {
#define LANCE_MUST_REINIT_RING 0x00000004
#define LANCE_MUST_UNRESET 0x00000008
#define LANCE_HAS_MISSED_FRAME 0x00000010
-#define PCNET32_POSSIBLE 0x00000020
/* A mapping from the chip ID number to the part number and features.
These are from the datasheets -- in real life the '970 version
@@ -267,21 +260,15 @@ static struct lance_chip_type {
LANCE_HAS_MISSED_FRAME},
{0x2420, "PCnet/PCI 79C970", /* 79C970 or 79C974 PCnet-SCSI, PCI. */
LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
- LANCE_HAS_MISSED_FRAME + PCNET32_POSSIBLE},
+ LANCE_HAS_MISSED_FRAME},
/* Bug: the PCnet/PCI actually uses the PCnet/VLB ID number, so just call
it the PCnet32. */
{0x2430, "PCnet32", /* 79C965 PCnet for VL bus. */
LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
- LANCE_HAS_MISSED_FRAME + PCNET32_POSSIBLE},
+ LANCE_HAS_MISSED_FRAME},
{0x2621, "PCnet/PCI-II 79C970A", /* 79C970A PCInetPCI II. */
LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
- LANCE_HAS_MISSED_FRAME + PCNET32_POSSIBLE},
- {0x2623, "PCnet/FAST 79C971", /* 79C971 PCInetFAST. */
- LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
- LANCE_HAS_MISSED_FRAME + PCNET32_POSSIBLE},
- {0x2624, "PCnet/FAST+ 79C972", /* 79C972 PCInetFAST+. */
- LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
- LANCE_HAS_MISSED_FRAME + PCNET32_POSSIBLE},
+ LANCE_HAS_MISSED_FRAME},
{0x0, "PCnet (unknown)",
LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
LANCE_HAS_MISSED_FRAME},
@@ -298,7 +285,7 @@ static unsigned char lance_need_isa_bounce_buffers = 1;
static int lance_open(struct device *dev);
static int lance_open_fail(struct device *dev);
-static void lance_init_ring(struct device *dev);
+static void lance_init_ring(struct device *dev, int mode);
static int lance_start_xmit(struct sk_buff *skb, struct device *dev);
static int lance_rx(struct device *dev);
static void lance_interrupt(int irq, void *dev_id, struct pt_regs *regs);
@@ -308,24 +295,88 @@ static void set_multicast_list(struct device *dev);
-/* This lance probe is unlike the other board probes in 1.0.*. The LANCE may
- have to allocate a contiguous low-memory region for bounce buffers.
- This requirement is satisfied by having the lance initialization occur
- before the memory management system is started, and thus well before the
- other probes. */
+#ifdef MODULE
+#define MAX_CARDS 8 /* Max number of interfaces (cards) per module */
+#define IF_NAMELEN 8 /* # of chars for storing dev->name */
+
+static int io[MAX_CARDS] = { 0, };
+static int dma[MAX_CARDS] = { 0, };
+static int irq[MAX_CARDS] = { 0, };
-__initfunc(int lance_init(void))
+MODULE_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i");
+MODULE_PARM(dma, "1-" __MODULE_STRING(MAX_CARDS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CARDS) "i");
+
+static char ifnames[MAX_CARDS][IF_NAMELEN] = { {0, }, };
+static struct device dev_lance[MAX_CARDS] =
+{{
+ 0, /* device name is inserted by linux/drivers/net/net_init.c */
+ 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, NULL, NULL}};
+
+int init_module(void)
+{
+ int this_dev, found = 0;
+
+ for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) {
+ struct device *dev = &dev_lance[this_dev];
+ dev->name = ifnames[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 (this_dev != 0) break; /* only complain once */
+ printk(KERN_NOTICE "lance.c: Module autoprobing not allowed. Append \"io=0xNNN\" value(s).\n");
+ return -EPERM;
+ }
+ if (register_netdev(dev) != 0) {
+ printk(KERN_WARNING "lance.c: No PCnet/LANCE card found (i/o = 0x%x).\n", io[this_dev]);
+ if (found != 0) return 0; /* Got at least one. */
+ return -ENXIO;
+ }
+ found++;
+ }
+
+ return 0;
+}
+
+void cleanup_module(void)
{
- int *port;
+ int this_dev;
+
+ for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) {
+ struct device *dev = &dev_lance[this_dev];
+ if (dev->priv != NULL) {
+ kfree(dev->priv);
+ dev->priv = NULL;
+ free_dma(dev->dma);
+ release_region(dev->base_addr, LANCE_TOTAL_SIZE);
+ unregister_netdev(dev);
+ }
+ }
+}
+#endif /* MODULE */
- if (virt_to_bus(high_memory) <= 16*1024*1024)
+/* Starting in v2.1.*, the LANCE/PCnet probe is now similar to the other
+ board probes now that kmalloc() can allocate ISA DMA-able regions.
+ This also allows the LANCE driver to be used as a module.
+ */
+int lance_probe(struct device *dev)
+{
+ int *port, result;
+
+ if (high_memory <= phys_to_virt(16*1024*1024))
lance_need_isa_bounce_buffers = 0;
-#if defined(CONFIG_PCI) && !(defined(CONFIG_PCNET32) || defined(CONFIG_PCNET32_MODULE))
- if (pci_present()) {
- struct pci_dev *pdev = NULL;
+#if defined(CONFIG_PCI)
+ if (pci_present())
+ {
+ struct pci_dev *pdev = NULL;
if (lance_debug > 1)
- printk("lance.c: PCI is present, checking for devices...\n");
+ printk("lance.c: PCI bios is present, checking for devices...\n");
+
while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, pdev))) {
unsigned int pci_ioaddr;
unsigned short pci_command;
@@ -344,8 +395,9 @@ __initfunc(int lance_init(void))
}
printk("Found PCnet/PCI at %#x, irq %d.\n",
pci_ioaddr, pci_irq_line);
- lance_probe1(pci_ioaddr);
+ result = lance_probe1(dev, pci_ioaddr, pci_irq_line, 0);
pci_irq_line = 0;
+ if (!result) return 0;
}
}
#endif /* defined(CONFIG_PCI) */
@@ -359,16 +411,17 @@ __initfunc(int lance_init(void))
char offset15, offset14 = inb(ioaddr + 14);
if ((offset14 == 0x52 || offset14 == 0x57) &&
- ((offset15 = inb(ioaddr + 15)) == 0x57 || offset15 == 0x44))
- lance_probe1(ioaddr);
+ ((offset15 = inb(ioaddr + 15)) == 0x57 || offset15 == 0x44)) {
+ result = lance_probe1(dev, ioaddr, 0, 0);
+ if ( !result ) return 0;
+ }
}
}
- return 0;
+ return -ENODEV;
}
-__initfunc(void lance_probe1(int ioaddr))
+__initfunc(int lance_probe1(struct device *dev, int ioaddr, int irq, int options))
{
- struct device *dev;
struct lance_private *lp;
short dma_channels; /* Mark spuriously-busy DMA channels */
int i, reset_val, lance_version;
@@ -406,7 +459,7 @@ __initfunc(void lance_probe1(int ioaddr))
outw(0x0000, ioaddr+LANCE_ADDR); /* Switch to window 0 */
if (inw(ioaddr+LANCE_DATA) != 0x0004)
- return;
+ return -ENODEV;
/* Get the version of the chip. */
outw(88, ioaddr+LANCE_ADDR);
@@ -419,24 +472,17 @@ __initfunc(void lance_probe1(int ioaddr))
if (lance_debug > 2)
printk(" LANCE chip version is %#x.\n", chip_version);
if ((chip_version & 0xfff) != 0x003)
- return;
+ return -ENODEV;
chip_version = (chip_version >> 12) & 0xffff;
for (lance_version = 1; chip_table[lance_version].id_number; lance_version++) {
if (chip_table[lance_version].id_number == chip_version)
break;
}
}
-
-#if defined(CONFIG_PCNET32) || defined (CONFIG_PCNET32_MODULE)
- /*
- * if pcnet32 is configured and the chip is capable of 32bit mode
- * leave the card alone
- */
- if (chip_table[lance_version].flags & PCNET32_POSSIBLE)
- return;
-#endif
- dev = init_etherdev(0, 0);
+ /* We can't use init_etherdev() to allocate dev->priv because it must
+ a ISA DMA-able region. */
+ dev = init_etherdev(dev, 0);
dev->open = lance_open_fail;
chipname = chip_table[lance_version].name;
printk("%s: %s at %#3x,", dev->name, chipname, ioaddr);
@@ -450,6 +496,7 @@ __initfunc(void lance_probe1(int ioaddr))
request_region(ioaddr, LANCE_TOTAL_SIZE, chip_table[lance_version].name);
/* Make certain the data structures used by the LANCE are aligned and DMAble. */
+
lp = (struct lance_private *)(((unsigned long)kmalloc(sizeof(*lp)+7,
GFP_DMA | GFP_KERNEL)+7) & ~7);
if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp);
@@ -483,9 +530,9 @@ __initfunc(void lance_probe1(int ioaddr))
outw(0x0000, ioaddr+LANCE_ADDR);
inw(ioaddr+LANCE_ADDR);
- if (pci_irq_line) {
+ if (irq) { /* Set iff PCI card. */
dev->dma = 4; /* Native bus-master, no DMA channel needed. */
- dev->irq = pci_irq_line;
+ dev->irq = irq;
} else if (hp_builtin) {
static const char dma_tbl[4] = {3, 5, 6, 0};
static const char irq_tbl[4] = {3, 4, 5, 9};
@@ -534,7 +581,7 @@ __initfunc(void lance_probe1(int ioaddr))
printk(", probed IRQ %d", dev->irq);
else {
printk(", failed to detect IRQ line.\n");
- return;
+ return -ENODEV;
}
/* Check for the initialization done bit, 0x0100, which means
@@ -548,7 +595,7 @@ __initfunc(void lance_probe1(int ioaddr))
} else if (dev->dma) {
if (request_dma(dev->dma, chipname)) {
printk("DMA %d allocation failed.\n", dev->dma);
- return;
+ return -ENODEV;
} else
printk(", assigned DMA %d.\n", dev->dma);
} else { /* OK, we have to auto-DMA. */
@@ -588,7 +635,7 @@ __initfunc(void lance_probe1(int ioaddr))
}
if (i == 4) { /* Failure: bail. */
printk("DMA detection failed.\n");
- return;
+ return -ENODEV;
}
}
@@ -601,7 +648,7 @@ __initfunc(void lance_probe1(int ioaddr))
dev->irq = autoirq_report(4);
if (dev->irq == 0) {
printk(" Failed to detect the 7990 IRQ line.\n");
- return;
+ return -ENODEV;
}
printk(" Auto-IRQ detected IRQ%d.\n", dev->irq);
}
@@ -610,8 +657,8 @@ __initfunc(void lance_probe1(int ioaddr))
/* Turn on auto-select of media (10baseT or BNC) so that the user
can watch the LEDs even if the board isn't opened. */
outw(0x0002, ioaddr+LANCE_ADDR);
- /* set autoselect and clean xmausel */
- outw((inw(ioaddr+LANCE_BUS_IF) & 0xfffe) | 0x0002, ioaddr+LANCE_BUS_IF);
+ /* Don't touch 10base2 power bit. */
+ outw(inw(ioaddr+LANCE_BUS_IF) | 0x0002, ioaddr+LANCE_BUS_IF);
}
if (lance_debug > 0 && did_version++ == 0)
@@ -624,7 +671,7 @@ __initfunc(void lance_probe1(int ioaddr))
dev->get_stats = lance_get_stats;
dev->set_multicast_list = set_multicast_list;
- return;
+ return 0;
}
static int
@@ -647,6 +694,8 @@ lance_open(struct device *dev)
return -EAGAIN;
}
+ MOD_INC_USE_COUNT;
+
/* We used to allocate DMA here, but that was silly.
DMA lines can't be shared! We now permanently allocate them. */
@@ -668,9 +717,9 @@ lance_open(struct device *dev)
if (chip_table[lp->chip_version].flags & LANCE_ENABLE_AUTOSELECT) {
/* This is 79C960-specific: Turn on auto-select of media (AUI, BNC). */
outw(0x0002, ioaddr+LANCE_ADDR);
- /* set autoselect and clean xmausel */
- outw((inw(ioaddr+LANCE_BUS_IF) & 0xfffe) | 0x0002, ioaddr+LANCE_BUS_IF);
- }
+ /* Only touch autoselect bit. */
+ outw(inw(ioaddr+LANCE_BUS_IF) | 0x0002, ioaddr+LANCE_BUS_IF);
+ }
if (lance_debug > 1)
printk("%s: lance_open() irq %d dma %d tx/rx rings %#x/%#x init %#x.\n",
@@ -679,7 +728,7 @@ lance_open(struct device *dev)
(u32) virt_to_bus(lp->rx_ring),
(u32) virt_to_bus(&lp->init_block));
- lance_init_ring(dev);
+ lance_init_ring(dev, GFP_KERNEL);
/* Re-initialize the LANCE, and start it when done. */
outw(0x0001, ioaddr+LANCE_ADDR);
outw((short) (u32) virt_to_bus(&lp->init_block), ioaddr+LANCE_DATA);
@@ -741,7 +790,7 @@ lance_purge_tx_ring(struct device *dev)
/* Initialize the LANCE Rx and Tx rings. */
static void
-lance_init_ring(struct device *dev)
+lance_init_ring(struct device *dev, int gfp)
{
struct lance_private *lp = (struct lance_private *)dev->priv;
int i;
@@ -751,12 +800,26 @@ lance_init_ring(struct device *dev)
lp->dirty_rx = lp->dirty_tx = 0;
for (i = 0; i < RX_RING_SIZE; i++) {
- lp->rx_ring[i].base = (u32)virt_to_bus((char *)lp->rx_buffs + i*PKT_BUF_SZ) | 0x80000000;
+ struct sk_buff *skb;
+ void *rx_buff;
+
+ skb = alloc_skb(PKT_BUF_SZ, GFP_DMA | gfp);
+ lp->rx_skbuff[i] = skb;
+ if (skb) {
+ skb->dev = dev;
+ rx_buff = skb->tail;
+ } else
+ rx_buff = kmalloc(PKT_BUF_SZ, GFP_DMA | gfp);
+ if (rx_buff == NULL)
+ lp->rx_ring[i].base = 0;
+ else
+ lp->rx_ring[i].base = (u32)virt_to_bus(rx_buff) | 0x80000000;
lp->rx_ring[i].buf_length = -PKT_BUF_SZ;
}
/* The Tx buffer address is filled in as needed, but we do need to clear
the upper ownership bit. */
for (i = 0; i < TX_RING_SIZE; i++) {
+ lp->tx_skbuff[i] = 0;
lp->tx_ring[i].base = 0;
}
@@ -777,7 +840,7 @@ lance_restart(struct device *dev, unsigned int csr0_bits, int must_reinit)
if (must_reinit ||
(chip_table[lp->chip_version].flags & LANCE_MUST_REINIT_RING)) {
lance_purge_tx_ring(dev);
- lance_init_ring(dev);
+ lance_init_ring(dev, GFP_ATOMIC);
}
outw(0x0000, dev->base_addr + LANCE_ADDR);
outw(csr0_bits, dev->base_addr + LANCE_DATA);
@@ -872,14 +935,14 @@ static int lance_start_xmit(struct sk_buff *skb, struct device *dev)
memcpy(&lp->tx_bounce_buffs[entry], skb->data, skb->len);
lp->tx_ring[entry].base =
((u32)virt_to_bus((lp->tx_bounce_buffs + entry)) & 0xffffff) | 0x83000000;
- dev_kfree_skb (skb);
+ dev_kfree_skb(skb);
} else {
lp->tx_skbuff[entry] = skb;
lp->tx_ring[entry].base = ((u32)virt_to_bus(skb->data) & 0xffffff) | 0x83000000;
}
lp->cur_tx++;
- lp->stats.tx_bytes+=skb->len;
-
+ lp->stats.tx_bytes += skb->len;
+
/* Trigger an immediate send poll. */
outw(0x0000, ioaddr+LANCE_ADDR);
outw(0x0048, ioaddr+LANCE_DATA);
@@ -915,7 +978,7 @@ lance_interrupt(int irq, void *dev_id, struct pt_regs * regs)
ioaddr = dev->base_addr;
lp = (struct lance_private *)dev->priv;
if (dev->interrupt)
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
+ printk(KERN_WARNING "%s: Re-entering the interrupt handler.\n", dev->name);
dev->interrupt = 1;
@@ -1110,6 +1173,7 @@ lance_close(struct device *dev)
{
int ioaddr = dev->base_addr;
struct lance_private *lp = (struct lance_private *)dev->priv;
+ int i;
dev->start = 0;
dev->tbusy = 1;
@@ -1134,9 +1198,23 @@ lance_close(struct device *dev)
disable_dma(dev->dma);
release_dma_lock(flags);
}
-
free_irq(dev->irq, dev);
+ /* Free all the skbuffs in the Rx and Tx queues. */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ struct sk_buff *skb = lp->rx_skbuff[i];
+ lp->rx_skbuff[i] = 0;
+ lp->rx_ring[i].base = 0; /* Not owned by LANCE chip. */
+ if (skb)
+ dev_kfree_skb(skb);
+ }
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ if (lp->tx_skbuff[i])
+ dev_kfree_skb(lp->tx_skbuff[i]);
+ lp->tx_skbuff[i] = 0;
+ }
+
+ MOD_DEC_USE_COUNT;
return 0;
}
@@ -1195,11 +1273,3 @@ static void set_multicast_list(struct device *dev)
}
-
-/*
- * Local variables:
- * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c lance.c"
- * c-indent-level: 4
- * tab-width: 4
- * End:
- */