Skip to content

Commit

Permalink
[PATCH] natsemi: NAPI and a bugfix
Browse files Browse the repository at this point in the history
As documented in National application note 1287 the RX state machine on
the natsemi chip can lock up under some conditions (mostly related to
heavy load).  When this happens a series of bogus packets are reported
by the chip including some oversized frames prior to the final lockup.

This patch implements the fix from the application note: when an
oversized packet is reported it resets the RX state machine, dropping
any currently pending packets.

Signed-off-by: Mark Brown <broonie@sirena.org.uk>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
  • Loading branch information
Mark Brown authored and Jeff Garzik committed Mar 4, 2006
1 parent b27a16b commit e72fd96
Showing 1 changed file with 42 additions and 0 deletions.
42 changes: 42 additions & 0 deletions drivers/net/natsemi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1498,6 +1498,31 @@ static void natsemi_reset(struct net_device *dev)
writel(rfcr, ioaddr + RxFilterAddr);
}

static void reset_rx(struct net_device *dev)
{
int i;
struct netdev_private *np = netdev_priv(dev);
void __iomem *ioaddr = ns_ioaddr(dev);

np->intr_status &= ~RxResetDone;

writel(RxReset, ioaddr + ChipCmd);

for (i=0;i<NATSEMI_HW_TIMEOUT;i++) {
np->intr_status |= readl(ioaddr + IntrStatus);
if (np->intr_status & RxResetDone)
break;
udelay(15);
}
if (i==NATSEMI_HW_TIMEOUT) {
printk(KERN_WARNING "%s: RX reset did not complete in %d usec.\n",
dev->name, i*15);
} else if (netif_msg_hw(np)) {
printk(KERN_WARNING "%s: RX reset took %d usec.\n",
dev->name, i*15);
}
}

static void natsemi_reload_eeprom(struct net_device *dev)
{
struct netdev_private *np = netdev_priv(dev);
Expand Down Expand Up @@ -2292,6 +2317,23 @@ static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do)
"status %#08x.\n", dev->name,
np->cur_rx, desc_status);
np->stats.rx_length_errors++;

/* The RX state machine has probably
* locked up beneath us. Follow the
* reset procedure documented in
* AN-1287. */

spin_lock_irq(&np->lock);
reset_rx(dev);
reinit_rx(dev);
writel(np->ring_dma, ioaddr + RxRingPtr);
check_link(dev);
spin_unlock_irq(&np->lock);

/* We'll enable RX on exit from this
* function. */
break;

} else {
/* There was an error. */
np->stats.rx_errors++;
Expand Down

0 comments on commit e72fd96

Please sign in to comment.