If there are errors in the open routine, the driver does not correctly clean
up and free resources.
This also removes an unnecessary netif_wake_queue, correctly supports the
debug parameter, and updates the version and date.
--- linux-2.4.25/drivers/net/tool.pcnet32.c Thu Feb 19 16:17:21 2004
+++ linux-2.4.25/drivers/net/pcnet32.c Fri Feb 20 10:45:30 2004
@@ -22,8 +22,8 @@
*************************************************************************/
#define DRV_NAME "pcnet32"
-#define DRV_VERSION "1.27a"
-#define DRV_RELDATE "10.02.2002"
+#define DRV_VERSION "1.28"
+#define DRV_RELDATE "02.20.2004"
#define PFX DRV_NAME ": "
static const char *version =
@@ -218,6 +218,11 @@
* fix pci probe not increment cards_found
* FD auto negotiate error workaround for xSeries250
* clean up and using new mii module
+ * v1.28 20 Feb 2004 Don Fry <brazilnut@xxxxxxxxxx>
+ * Jon Lewis <jonmason@xxxxxxxxxx>, Chinmay Albal <albal@xxxxxxxxxx>
+ * Now uses ethtool_ops, netif_msg_* and generic_mii_ioctl.
+ * Fixes bogus 'Bus master arbitration failure', pci_[un]map_single
+ * length errors, and transmit hangs. Cleans up after errors in open.
*/
@@ -638,8 +643,10 @@
chip_version = a->read_csr(ioaddr, 88) | (a->read_csr(ioaddr,89) << 16);
if (pcnet32_debug & NETIF_MSG_PROBE)
printk(KERN_INFO " PCnet chip version is %#x.\n", chip_version);
- if ((chip_version & 0xfff) != 0x003)
+ if ((chip_version & 0xfff) != 0x003) {
+ printk(KERN_INFO PFX "Unsupported chip version.\n");
return -ENODEV;
+ }
/* initialize variables */
fdx = mii = fset = dxsuflo = ltint = 0;
@@ -720,8 +727,10 @@
}
dev = alloc_etherdev(0);
- if(!dev)
+ if (!dev) {
+ printk(KERN_ERR PFX "Memory allocation failed.\n");
return -ENOMEM;
+ }
printk(KERN_INFO PFX "%s at %#3lx,", chipname, ioaddr);
@@ -794,6 +803,7 @@
/* pci_alloc_consistent returns page-aligned memory, so we do not have to
check the alignment */
if ((lp = pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) {
+ printk(KERN_ERR PFX "Consistent memory allocation failed.\n");
release_region(ioaddr, PCNET32_TOTAL_SIZE);
return -ENOMEM;
}
@@ -915,6 +925,7 @@
unsigned long ioaddr = dev->base_addr;
u16 val;
int i;
+ int rc;
if (dev->irq == 0 ||
request_irq(dev->irq, &pcnet32_interrupt,
@@ -923,8 +934,10 @@
}
/* Check for a valid station address */
- if( !is_valid_ether_addr(dev->dev_addr) )
- return -EINVAL;
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+ rc = -EINVAL;
+ goto err_free_irq;
+ }
/* Reset the PCNET32 */
lp->a.reset (ioaddr);
@@ -998,8 +1011,10 @@
lp->init_block.mode = le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) <<
7);
lp->init_block.filter[0] = 0x00000000;
lp->init_block.filter[1] = 0x00000000;
- if (pcnet32_init_ring(dev))
- return -ENOMEM;
+ if (pcnet32_init_ring(dev)) {
+ rc = -ENOMEM;
+ goto err_free_ring;
+ }
/* Re-initialize the PCNET32, and start it when done. */
lp->a.write_csr (ioaddr, 1, (lp->dma_addr + offsetof(struct
pcnet32_private, init_block)) &0xffff);
@@ -1029,6 +1044,28 @@
MOD_INC_USE_COUNT;
return 0; /* Always succeed */
+
+err_free_ring:
+ /* free any allocated skbuffs */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ lp->rx_ring[i].status = 0;
+ if (lp->rx_skbuff[i]) {
+ pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], PKT_BUF_SZ-2,
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(lp->rx_skbuff[i]);
+ }
+ lp->rx_skbuff[i] = NULL;
+ lp->rx_dma_addr[i] = 0;
+ }
+ /*
+ * Switch back to 16bit mode to avoid problems with dumb
+ * DOS packet driver after a warm reboot
+ */
+ lp->a.write_bcr (ioaddr, 20, 4);
+
+err_free_irq:
+ free_irq(dev->irq, dev);
+ return rc;
}
/*
@@ -1097,6 +1134,7 @@
lp->tx_ring[i].status = 0;
lp->tx_dma_addr[i] = 0;
}
+ wmb(); /* Make sure all changes are visible */
lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS |
RX_RING_LEN_BITS);
for (i = 0; i < 6; i++)
@@ -1223,9 +1261,7 @@
dev->trans_start = jiffies;
- if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0)
- netif_wake_queue(dev);
- else {
+ if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base != 0) {
lp->tx_full = 1;
netif_stop_queue(dev);
}
@@ -1479,6 +1515,7 @@
* of QNX reports that some revs of the 79C965 clear it.
*/
lp->rx_ring[entry].buf_length = le16_to_cpu(2-PKT_BUF_SZ);
+ wmb(); /* Make sure owner changes after all others are visible */
lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
}
@@ -1678,7 +1715,7 @@
};
MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, DRV_NAME " debug level (0-6)");
+MODULE_PARM_DESC(debug, DRV_NAME " debug level");
MODULE_PARM(max_interrupt_work, "i");
MODULE_PARM_DESC(max_interrupt_work, DRV_NAME " maximum events handled per
interrupt");
MODULE_PARM(rx_copybreak, "i");
@@ -1705,8 +1742,8 @@
{
printk(KERN_INFO "%s", version);
- if (debug > 0)
- pcnet32_debug = debug;
+ if (debug >= 0 && debug < (sizeof(int) - 1))
+ pcnet32_debug = 1 << debug;
if ((tx_start_pt >= 0) && (tx_start_pt <= 3))
tx_start = tx_start_pt;
--
Don Fry
brazilnut@xxxxxxxxxx
|