At the next opportunity to add new code to 2.6.6, please apply the following:
This patch uses an on-chip timer to free completed transmit skb's for the
79C971 and 972 versions which currently will leave completed transmit
skb's on the transmit ring until new transmit traffic occurs.
--- linux-2.6.6-rc1-bk5/drivers/net/dump.pcnet32.c Tue Apr 20 15:47:47 2004
+++ linux-2.6.6-rc1-bk5/drivers/net/pcnet32.c Tue Apr 20 15:48:49 2004
@@ -237,6 +237,8 @@
* Thomas Munck Steenholdt <tmus@xxxxxxx> non-mii ioctl corrections.
* v1.29 6 Apr 2004 Jim Lewis <jklewis@xxxxxxxxxx> added physical
* identification code (blink led's) and register dump.
+ * Don Fry added timer for 971/972 so skbufs don't remain on tx ring
+ * forever.
*/
@@ -497,9 +499,9 @@
#ifdef CONFIG_NET_POLL_CONTROLLER
static void pcnet32_poll_controller(struct net_device *dev)
{
- disable_irq(dev->irq);
- pcnet32_interrupt(0, dev, NULL);
- enable_irq(dev->irq);
+ disable_irq(dev->irq);
+ pcnet32_interrupt(0, dev, NULL);
+ enable_irq(dev->irq);
}
#endif
@@ -1105,6 +1107,13 @@
ltint = 1;
}
+ if (ltint) {
+ /* Enable timer to prevent skbuffs from remaining on the tx ring
+ * forever if no other tx being done. Set timer period to about
+ * 122 ms */
+ a->write_bcr(ioaddr, 31, 0x253b);
+ }
+
dev = alloc_etherdev(0);
if (!dev) {
if (pcnet32_debug & NETIF_MSG_PROBE)
@@ -1451,6 +1460,11 @@
lp->a.write_csr (ioaddr, 4, 0x0915);
lp->a.write_csr (ioaddr, 0, 0x0001);
+ if (lp->ltint) {
+ /* start the software timer */
+ lp->a.write_csr(ioaddr, 7, 0x0400); /* set STINTE */
+ }
+
netif_start_queue(dev);
/* If we have mii, print the link status and start the watchdog */
@@ -1652,13 +1666,13 @@
int entry;
unsigned long flags;
+ spin_lock_irqsave(&lp->lock, flags);
+
if (netif_msg_tx_queued(lp)) {
printk(KERN_DEBUG "%s: pcnet32_start_xmit() called, csr0 %4.4x.\n",
dev->name, lp->a.read_csr(ioaddr, 0));
}
- spin_lock_irqsave(&lp->lock, flags);
-
/* Default status -- will not enable Successful-TxDone
* interrupt when that option is available to us.
*/
@@ -1719,7 +1733,7 @@
struct net_device *dev = dev_id;
struct pcnet32_private *lp;
unsigned long ioaddr;
- u16 csr0,rap;
+ u16 csr0, csr7, rap;
int boguscnt = max_interrupt_work;
int must_restart;
@@ -1736,13 +1750,19 @@
spin_lock(&lp->lock);
rap = lp->a.read_rap(ioaddr);
- while ((csr0 = lp->a.read_csr (ioaddr, 0)) & 0x8600 && --boguscnt >= 0) {
+ csr0 = lp->a.read_csr (ioaddr, 0);
+ csr7 = lp->ltint ? lp->a.read_csr(ioaddr, 7) : 0;
+
+ while ((csr0 & 0x8600 || csr7 & 0x0800) && --boguscnt >= 0) {
if (csr0 == 0xffff) {
break; /* PCMCIA remove happened */
}
/* Acknowledge all of the current interrupt sources ASAP. */
lp->a.write_csr (ioaddr, 0, csr0 & ~0x004f);
+ if (csr7 & 0x0800)
+ lp->a.write_csr(ioaddr, 7, csr7);
+
must_restart = 0;
if (netif_msg_intr(lp))
@@ -1752,7 +1772,7 @@
if (csr0 & 0x0400) /* Rx interrupt */
pcnet32_rx(dev);
- if (csr0 & 0x0200) { /* Tx-done interrupt */
+ if (csr0 & 0x0200 || csr7 & 0x0800) { /* Tx-done or Timer interrupt */
unsigned int dirty_tx = lp->dirty_tx;
int delta;
@@ -1859,6 +1879,9 @@
lp->a.write_csr (ioaddr, 0, 0x0004);
pcnet32_restart(dev, 0x0002);
}
+
+ csr0 = lp->a.read_csr (ioaddr, 0);
+ csr7 = lp->ltint ? lp->a.read_csr(ioaddr, 7) : 0;
}
/* Clear any other interrupt, and set interrupt enable. */
@@ -1945,6 +1968,7 @@
if (i > RX_RING_SIZE -2) {
lp->stats.rx_dropped++;
lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
+ wmb(); /* Make sure adapter sees owner change */
lp->cur_rx++;
}
break;
@@ -2008,6 +2032,10 @@
/* We stop the PCNET32 here -- it occasionally polls memory if we don't. */
lp->a.write_csr (ioaddr, 0, 0x0004);
+ if (lp->ltint) { /* Disable timer interrupts */
+ lp->a.write_csr(ioaddr, 7, 0x0000);
+ }
+
/*
* Switch back to 16bit mode to avoid problems with dumb
* DOS packet driver after a warm reboot
@@ -2018,9 +2046,12 @@
free_irq(dev->irq, dev);
+ spin_lock_irqsave(&lp->lock, flags);
+
/* free all allocated skbuffs */
for (i = 0; i < RX_RING_SIZE; i++) {
lp->rx_ring[i].status = 0;
+ wmb(); /* Make sure adapter sees owner change */
if (lp->rx_skbuff[i]) {
pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], PKT_BUF_SZ-2,
PCI_DMA_FROMDEVICE);
@@ -2031,6 +2062,8 @@
}
for (i = 0; i < TX_RING_SIZE; i++) {
+ lp->tx_ring[i].status = 0; /* CPU owns buffer */
+ wmb(); /* Make sure adapter sees owner change */
if (lp->tx_skbuff[i]) {
pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i],
lp->tx_skbuff[i]->len, PCI_DMA_TODEVICE);
@@ -2040,6 +2073,8 @@
lp->tx_dma_addr[i] = 0;
}
+ spin_unlock_irqrestore(&lp->lock, flags);
+
return 0;
}
--
Don Fry
brazilnut@xxxxxxxxxx
|