Skip to content

Commit

Permalink
[PATCH] ep93xx_eth: fix RX/TXstatus ring full handling
Browse files Browse the repository at this point in the history
Ray Lehtiniemi reported that an incoming UDP packet flood can lock up
the ep93xx ethernet driver.  Herbert Valerio Riedel noted that due to
the way ep93xx_eth manages the RX/TXstatus rings, it cannot distinguish
a full ring from an empty one, and correctly suggested that this was
likely to be causing this lockup to occur.

Instead of looking at the hardware's RX/TXstatus ring write pointers
to determine when to stop reading from those rings, we should just check
every individual RX/TXstatus descriptor's valid bit instead, since there
is no other way to distinguish an empty ring from a full ring, and if
there is a descriptor waiting, we take the hit of reading the descriptor
from memory anyway.

Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
  • Loading branch information
Lennert Buytenhek authored and Jeff Garzik committed Nov 1, 2006
1 parent d5b9b78 commit 2d38cab
Showing 1 changed file with 9 additions and 26 deletions.
35 changes: 9 additions & 26 deletions drivers/net/arm/ep93xx_eth.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,12 +193,9 @@ static struct net_device_stats *ep93xx_get_stats(struct net_device *dev)
static int ep93xx_rx(struct net_device *dev, int *budget)
{
struct ep93xx_priv *ep = netdev_priv(dev);
int tail_offset;
int rx_done;
int processed;

tail_offset = rdl(ep, REG_RXSTSQCURADD) - ep->descs_dma_addr;

rx_done = 0;
processed = 0;
while (*budget > 0) {
Expand All @@ -211,28 +208,23 @@ static int ep93xx_rx(struct net_device *dev, int *budget)

entry = ep->rx_pointer;
rstat = ep->descs->rstat + entry;
if ((void *)rstat - (void *)ep->descs == tail_offset) {

rstat0 = rstat->rstat0;
rstat1 = rstat->rstat1;
if (!(rstat0 & RSTAT0_RFP) || !(rstat1 & RSTAT1_RFP)) {
rx_done = 1;
break;
}

rstat0 = rstat->rstat0;
rstat1 = rstat->rstat1;
rstat->rstat0 = 0;
rstat->rstat1 = 0;

if (!(rstat0 & RSTAT0_RFP))
printk(KERN_CRIT "ep93xx_rx: buffer not done "
" %.8x %.8x\n", rstat0, rstat1);
if (!(rstat0 & RSTAT0_EOF))
printk(KERN_CRIT "ep93xx_rx: not end-of-frame "
" %.8x %.8x\n", rstat0, rstat1);
if (!(rstat0 & RSTAT0_EOB))
printk(KERN_CRIT "ep93xx_rx: not end-of-buffer "
" %.8x %.8x\n", rstat0, rstat1);
if (!(rstat1 & RSTAT1_RFP))
printk(KERN_CRIT "ep93xx_rx: buffer1 not done "
" %.8x %.8x\n", rstat0, rstat1);
if ((rstat1 & RSTAT1_BUFFER_INDEX) >> 16 != entry)
printk(KERN_CRIT "ep93xx_rx: entry mismatch "
" %.8x %.8x\n", rstat0, rstat1);
Expand Down Expand Up @@ -301,13 +293,8 @@ static int ep93xx_rx(struct net_device *dev, int *budget)

static int ep93xx_have_more_rx(struct ep93xx_priv *ep)
{
struct ep93xx_rstat *rstat;
int tail_offset;

rstat = ep->descs->rstat + ep->rx_pointer;
tail_offset = rdl(ep, REG_RXSTSQCURADD) - ep->descs_dma_addr;

return !((void *)rstat - (void *)ep->descs == tail_offset);
struct ep93xx_rstat *rstat = ep->descs->rstat + ep->rx_pointer;
return !!((rstat->rstat0 & RSTAT0_RFP) && (rstat->rstat1 & RSTAT1_RFP));
}

static int ep93xx_poll(struct net_device *dev, int *budget)
Expand Down Expand Up @@ -379,10 +366,8 @@ static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev)
static void ep93xx_tx_complete(struct net_device *dev)
{
struct ep93xx_priv *ep = netdev_priv(dev);
int tail_offset;
int wake;

tail_offset = rdl(ep, REG_TXSTSQCURADD) - ep->descs_dma_addr;
wake = 0;

spin_lock(&ep->tx_pending_lock);
Expand All @@ -393,15 +378,13 @@ static void ep93xx_tx_complete(struct net_device *dev)

entry = ep->tx_clean_pointer;
tstat = ep->descs->tstat + entry;
if ((void *)tstat - (void *)ep->descs == tail_offset)
break;

tstat0 = tstat->tstat0;
if (!(tstat0 & TSTAT0_TXFP))
break;

tstat->tstat0 = 0;

if (!(tstat0 & TSTAT0_TXFP))
printk(KERN_CRIT "ep93xx_tx_complete: buffer not done "
" %.8x\n", tstat0);
if (tstat0 & TSTAT0_FA)
printk(KERN_CRIT "ep93xx_tx_complete: frame aborted "
" %.8x\n", tstat0);
Expand Down

0 comments on commit 2d38cab

Please sign in to comment.