summaryrefslogtreecommitdiffstats
path: root/drivers/net/pcnet32.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-09-19 19:15:08 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-09-19 19:15:08 +0000
commit03ba4131783cc9e872f8bb26a03f15bc11f27564 (patch)
tree88db8dba75ae06ba3bad08e42c5e52efc162535c /drivers/net/pcnet32.c
parent257730f99381dd26e10b832fce4c94cae7ac1176 (diff)
- Merge with Linux 2.1.121.
- Bugfixes.
Diffstat (limited to 'drivers/net/pcnet32.c')
-rw-r--r--drivers/net/pcnet32.c44
1 files changed, 24 insertions, 20 deletions
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index db00ab8c5..a80d460d0 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -13,7 +13,7 @@
* This driver is for PCnet32 and PCnetPCI based ethercards
*/
-static const char *version = "pcnet32.c:v1.00 30.5.98 tsbogend@alpha.franken.de\n";
+static const char *version = "pcnet32.c:v1.02 3.9.98 tsbogend@alpha.franken.de\n";
#include <linux/config.h>
#include <linux/module.h>
@@ -103,6 +103,9 @@ static const int rx_copybreak = 200;
* back port to 2.0.x
* v1.00: added some stuff from Donald Becker's 2.0.34 version
* added support for byte counters in net_dev_stats
+ * v1.01: do ring dumps, only when debugging the driver
+ * increased the transmit timeout
+ * v1.02: fixed memory leak in pcnet32_init_ring()
*/
@@ -188,7 +191,7 @@ struct pcnet32_private {
int pcnet32_probe(struct device *dev);
static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, unsigned char irq_line, int shared);
static int pcnet32_open(struct device *dev);
-static void pcnet32_init_ring(struct device *dev);
+static int pcnet32_init_ring(struct device *dev);
static int pcnet32_start_xmit(struct sk_buff *skb, struct device *dev);
static int pcnet32_rx(struct device *dev);
static void pcnet32_interrupt(int irq, void *dev_id, struct pt_regs *regs);
@@ -460,7 +463,8 @@ pcnet32_open(struct device *dev)
lp->init_block.mode = 0x0000;
lp->init_block.filter[0] = 0x00000000;
lp->init_block.filter[1] = 0x00000000;
- pcnet32_init_ring(dev);
+ if (pcnet32_init_ring(dev))
+ return -ENOMEM;
/* Re-initialize the PCNET32, and start it when done. */
outw(0x0001, ioaddr+PCNET32_ADDR);
@@ -525,28 +529,28 @@ pcnet32_purge_tx_ring(struct device *dev)
/* Initialize the PCNET32 Rx and Tx rings. */
-static void
+static int
pcnet32_init_ring(struct device *dev)
{
struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
int i;
- struct sk_buff *skb;
lp->lock = 0, lp->tx_full = 0;
lp->cur_rx = lp->cur_tx = 0;
lp->dirty_rx = lp->dirty_tx = 0;
for (i = 0; i < RX_RING_SIZE; i++) {
- skb = dev_alloc_skb (PKT_BUF_SZ);
- if (skb) {
- lp->rx_skbuff[i] = skb;
- skb_reserve (skb, 2);
- lp->rx_ring[i].base = (u32)le32_to_cpu(virt_to_bus(skb->tail));
- lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ);
- lp->rx_ring[i].status = le16_to_cpu(0x8000);
+ if (lp->rx_skbuff[i] == NULL) {
+ if (!(lp->rx_skbuff[i] = dev_alloc_skb (PKT_BUF_SZ))) {
+ /* there is not much, we can do at this point */
+ printk ("%s: pcnet32_init_ring dev_alloc_skb failed.\n",dev->name);
+ return -1;
+ }
+ skb_reserve (lp->rx_skbuff[i], 2);
}
- else
- break;
+ lp->rx_ring[i].base = (u32)le32_to_cpu(virt_to_bus(lp->rx_skbuff[i]->tail));
+ lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ);
+ lp->rx_ring[i].status = le16_to_cpu(0x8000);
}
/* The Tx buffer address is filled in as needed, but we do need to clear
the upper ownership bit. */
@@ -560,6 +564,7 @@ pcnet32_init_ring(struct device *dev)
lp->init_block.phys_addr[i] = dev->dev_addr[i];
lp->init_block.rx_ring = (u32)le32_to_cpu(virt_to_bus(lp->rx_ring));
lp->init_block.tx_ring = (u32)le32_to_cpu(virt_to_bus(lp->tx_ring));
+ return 0;
}
static void
@@ -569,7 +574,8 @@ pcnet32_restart(struct device *dev, unsigned int csr0_bits)
unsigned int ioaddr = dev->base_addr;
pcnet32_purge_tx_ring(dev);
- pcnet32_init_ring(dev);
+ if (pcnet32_init_ring(dev))
+ return;
outw(0x0000, ioaddr + PCNET32_ADDR);
/* ReInit Ring */
@@ -593,15 +599,14 @@ pcnet32_start_xmit(struct sk_buff *skb, struct device *dev)
/* Transmitter timeout, serious problems. */
if (dev->tbusy) {
int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 20)
+ if (tickssofar < HZ/2)
return 1;
outw(0, ioaddr+PCNET32_ADDR);
printk("%s: transmit timed out, status %4.4x, resetting.\n",
dev->name, inw(ioaddr+PCNET32_DATA));
outw(0x0004, ioaddr+PCNET32_DATA);
lp->stats.tx_errors++;
-#ifndef final_version
- {
+ if (pcnet32_debug > 2) {
int i;
printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",
@@ -616,12 +621,11 @@ pcnet32_start_xmit(struct sk_buff *skb, struct device *dev)
lp->tx_ring[i].misc, (unsigned)lp->tx_ring[i].status);
printk("\n");
}
-#endif
pcnet32_restart(dev, 0x0042);
dev->tbusy = 0;
dev->trans_start = jiffies;
-
+ dev_kfree_skb(skb);
return 0;
}