[PATCH] pcnet32: Cleanup rx buffers after loopback test.

More cleanup to pcnet32_loopback_test to release receive buffers if
device is not up.  Created common routine to free rx buffers.

Tested ia32 and ppc64

Signed-off-by:  Don Fry <brazilnut@us.ibm.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
Don Fry 2006-06-29 13:55:27 -07:00 committed by Jeff Garzik
parent df27f4a610
commit ac5bfe40f9
1 changed files with 43 additions and 59 deletions

View File

@ -645,6 +645,25 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
return;
}
static void pcnet32_purge_rx_ring(struct net_device *dev)
{
struct pcnet32_private *lp = dev->priv;
int i;
/* free all allocated skbuffs */
for (i = 0; i < lp->rx_ring_size; i++) {
lp->rx_ring[i].status = 0; /* CPU owns buffer */
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);
dev_kfree_skb_any(lp->rx_skbuff[i]);
}
lp->rx_skbuff[i] = NULL;
lp->rx_dma_addr[i] = 0;
}
}
#ifdef CONFIG_NET_POLL_CONTROLLER
static void pcnet32_poll_controller(struct net_device *dev)
{
@ -856,29 +875,27 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
unsigned long flags;
unsigned long ticks;
*data1 = 1; /* status of test, default to fail */
rc = 1; /* default to fail */
if (netif_running(dev))
pcnet32_close(dev);
spin_lock_irqsave(&lp->lock, flags);
lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
numbuffs = min(numbuffs, (int)min(lp->rx_ring_size, lp->tx_ring_size));
/* Reset the PCNET32 */
lp->a.reset(ioaddr);
lp->a.write_csr(ioaddr, CSR4, 0x0915);
/* switch pcnet32 to 32bit mode */
lp->a.write_bcr(ioaddr, 20, 2);
lp->init_block.mode =
le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
lp->init_block.filter[0] = 0;
lp->init_block.filter[1] = 0;
/* purge & init rings but don't actually restart */
pcnet32_restart(dev, 0x0000);
lp->a.write_csr(ioaddr, 0, 0x0004); /* Set STOP bit */
lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* Set STOP bit */
/* Initialize Transmit buffers. */
size = data_len + 15;
@ -920,14 +937,15 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
}
}
x = a->read_bcr(ioaddr, 32); /* set internal loopback in BSR32 */
x = x | 0x0002;
a->write_bcr(ioaddr, 32, x);
x = a->read_bcr(ioaddr, 32); /* set internal loopback in BCR32 */
a->write_bcr(ioaddr, 32, x | 0x0002);
lp->a.write_csr(ioaddr, 15, 0x0044); /* set int loopback in CSR15 */
/* set int loopback in CSR15 */
x = a->read_csr(ioaddr, CSR15) & 0xfffc;
lp->a.write_csr(ioaddr, CSR15, x | 0x0044);
teststatus = le16_to_cpu(0x8000);
lp->a.write_csr(ioaddr, 0, 0x0002); /* Set STRT bit */
lp->a.write_csr(ioaddr, CSR0, CSR0_START); /* Set STRT bit */
/* Check status of descriptors */
for (x = 0; x < numbuffs; x++) {
@ -935,7 +953,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
rmb();
while ((lp->rx_ring[x].status & teststatus) && (ticks < 200)) {
spin_unlock_irqrestore(&lp->lock, flags);
mdelay(1);
msleep(1);
spin_lock_irqsave(&lp->lock, flags);
rmb();
ticks++;
@ -948,7 +966,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
}
}
lp->a.write_csr(ioaddr, 0, 0x0004); /* Set STOP bit */
lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* Set STOP bit */
wmb();
if (netif_msg_hw(lp) && netif_msg_pktdata(lp)) {
printk(KERN_DEBUG "%s: RX loopback packets:\n", dev->name);
@ -981,25 +999,24 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
}
x++;
}
if (!rc) {
*data1 = 0;
}
clean_up:
*data1 = rc;
pcnet32_purge_tx_ring(dev);
x = a->read_csr(ioaddr, 15) & 0xFFFF;
a->write_csr(ioaddr, 15, (x & ~0x0044)); /* reset bits 6 and 2 */
x = a->read_csr(ioaddr, CSR15);
a->write_csr(ioaddr, CSR15, (x & ~0x0044)); /* reset bits 6 and 2 */
x = a->read_bcr(ioaddr, 32); /* reset internal loopback */
x = x & ~0x0002;
a->write_bcr(ioaddr, 32, x);
spin_unlock_irqrestore(&lp->lock, flags);
a->write_bcr(ioaddr, 32, (x & ~0x0002));
if (netif_running(dev)) {
spin_unlock_irqrestore(&lp->lock, flags);
pcnet32_open(dev);
} else {
pcnet32_purge_rx_ring(dev);
lp->a.write_bcr(ioaddr, 20, 4); /* return to 16bit mode */
spin_unlock_irqrestore(&lp->lock, flags);
}
return (rc);
@ -1997,16 +2014,7 @@ static int pcnet32_open(struct net_device *dev)
err_free_ring:
/* free any allocated skbuffs */
for (i = 0; i < lp->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;
}
pcnet32_purge_rx_ring(dev);
/*
* Switch back to 16bit mode to avoid problems with dumb
@ -2588,7 +2596,6 @@ static int pcnet32_close(struct net_device *dev)
{
unsigned long ioaddr = dev->base_addr;
struct pcnet32_private *lp = dev->priv;
int i;
unsigned long flags;
del_timer_sync(&lp->watchdog_timer);
@ -2619,31 +2626,8 @@ static int pcnet32_close(struct net_device *dev)
spin_lock_irqsave(&lp->lock, flags);
/* free all allocated skbuffs */
for (i = 0; i < lp->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);
dev_kfree_skb(lp->rx_skbuff[i]);
}
lp->rx_skbuff[i] = NULL;
lp->rx_dma_addr[i] = 0;
}
for (i = 0; i < lp->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);
dev_kfree_skb(lp->tx_skbuff[i]);
}
lp->tx_skbuff[i] = NULL;
lp->tx_dma_addr[i] = 0;
}
pcnet32_purge_rx_ring(dev);
pcnet32_purge_tx_ring(dev);
spin_unlock_irqrestore(&lp->lock, flags);