Commit 7b29c58b authored by Don Fry's avatar Don Fry Committed by Jeff Garzik

[PATCH] pcnet32 timer to free tx skbs for 79C971/972

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.
parent 991eb379
......@@ -237,6 +237,8 @@ static int full_duplex[MAX_UNITS];
* Thomas Munck Steenholdt <tmus@tmus.dk> non-mii ioctl corrections.
* v1.29 6 Apr 2004 Jim Lewis <jklewis@us.ibm.com> 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 @@ static struct pcnet32_access pcnet32_dwio = {
#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 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
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 @@ pcnet32_open(struct net_device *dev)
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 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
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 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
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 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
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 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
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 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
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 @@ pcnet32_rx(struct net_device *dev)
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 @@ pcnet32_close(struct net_device *dev)
/* 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 @@ pcnet32_close(struct net_device *dev)
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 @@ pcnet32_close(struct net_device *dev)
}
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 @@ pcnet32_close(struct net_device *dev)
lp->tx_dma_addr[i] = 0;
}
spin_unlock_irqrestore(&lp->lock, flags);
return 0;
}
......
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