aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorLennert Buytenhek <buytenh@wantstofly.org>2006-10-30 13:52:31 -0500
committerJeff Garzik <jeff@garzik.org>2006-10-31 20:22:05 -0500
commit2d38caba5fd148976f54930782e8209fa45879a0 (patch)
tree7f8bc1ee29d9bfc79ecb9a609084526a874df492 /drivers/net
parentd5b9b787b5e1618dfe82a2c2a6972374e85b02db (diff)
[PATCH] ep93xx_eth: fix RX/TXstatus ring full handling
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>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/arm/ep93xx_eth.c35
1 files changed, 9 insertions, 26 deletions
diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c
index 127561c782fd..2fc8b2a1a023 100644
--- a/drivers/net/arm/ep93xx_eth.c
+++ b/drivers/net/arm/ep93xx_eth.c
@@ -193,12 +193,9 @@ static struct net_device_stats *ep93xx_get_stats(struct net_device *dev)
193static int ep93xx_rx(struct net_device *dev, int *budget) 193static int ep93xx_rx(struct net_device *dev, int *budget)
194{ 194{
195 struct ep93xx_priv *ep = netdev_priv(dev); 195 struct ep93xx_priv *ep = netdev_priv(dev);
196 int tail_offset;
197 int rx_done; 196 int rx_done;
198 int processed; 197 int processed;
199 198
200 tail_offset = rdl(ep, REG_RXSTSQCURADD) - ep->descs_dma_addr;
201
202 rx_done = 0; 199 rx_done = 0;
203 processed = 0; 200 processed = 0;
204 while (*budget > 0) { 201 while (*budget > 0) {
@@ -211,28 +208,23 @@ static int ep93xx_rx(struct net_device *dev, int *budget)
211 208
212 entry = ep->rx_pointer; 209 entry = ep->rx_pointer;
213 rstat = ep->descs->rstat + entry; 210 rstat = ep->descs->rstat + entry;
214 if ((void *)rstat - (void *)ep->descs == tail_offset) { 211
212 rstat0 = rstat->rstat0;
213 rstat1 = rstat->rstat1;
214 if (!(rstat0 & RSTAT0_RFP) || !(rstat1 & RSTAT1_RFP)) {
215 rx_done = 1; 215 rx_done = 1;
216 break; 216 break;
217 } 217 }
218 218
219 rstat0 = rstat->rstat0;
220 rstat1 = rstat->rstat1;
221 rstat->rstat0 = 0; 219 rstat->rstat0 = 0;
222 rstat->rstat1 = 0; 220 rstat->rstat1 = 0;
223 221
224 if (!(rstat0 & RSTAT0_RFP))
225 printk(KERN_CRIT "ep93xx_rx: buffer not done "
226 " %.8x %.8x\n", rstat0, rstat1);
227 if (!(rstat0 & RSTAT0_EOF)) 222 if (!(rstat0 & RSTAT0_EOF))
228 printk(KERN_CRIT "ep93xx_rx: not end-of-frame " 223 printk(KERN_CRIT "ep93xx_rx: not end-of-frame "
229 " %.8x %.8x\n", rstat0, rstat1); 224 " %.8x %.8x\n", rstat0, rstat1);
230 if (!(rstat0 & RSTAT0_EOB)) 225 if (!(rstat0 & RSTAT0_EOB))
231 printk(KERN_CRIT "ep93xx_rx: not end-of-buffer " 226 printk(KERN_CRIT "ep93xx_rx: not end-of-buffer "
232 " %.8x %.8x\n", rstat0, rstat1); 227 " %.8x %.8x\n", rstat0, rstat1);
233 if (!(rstat1 & RSTAT1_RFP))
234 printk(KERN_CRIT "ep93xx_rx: buffer1 not done "
235 " %.8x %.8x\n", rstat0, rstat1);
236 if ((rstat1 & RSTAT1_BUFFER_INDEX) >> 16 != entry) 228 if ((rstat1 & RSTAT1_BUFFER_INDEX) >> 16 != entry)
237 printk(KERN_CRIT "ep93xx_rx: entry mismatch " 229 printk(KERN_CRIT "ep93xx_rx: entry mismatch "
238 " %.8x %.8x\n", rstat0, rstat1); 230 " %.8x %.8x\n", rstat0, rstat1);
@@ -301,13 +293,8 @@ err:
301 293
302static int ep93xx_have_more_rx(struct ep93xx_priv *ep) 294static int ep93xx_have_more_rx(struct ep93xx_priv *ep)
303{ 295{
304 struct ep93xx_rstat *rstat; 296 struct ep93xx_rstat *rstat = ep->descs->rstat + ep->rx_pointer;
305 int tail_offset; 297 return !!((rstat->rstat0 & RSTAT0_RFP) && (rstat->rstat1 & RSTAT1_RFP));
306
307 rstat = ep->descs->rstat + ep->rx_pointer;
308 tail_offset = rdl(ep, REG_RXSTSQCURADD) - ep->descs_dma_addr;
309
310 return !((void *)rstat - (void *)ep->descs == tail_offset);
311} 298}
312 299
313static int ep93xx_poll(struct net_device *dev, int *budget) 300static int ep93xx_poll(struct net_device *dev, int *budget)
@@ -379,10 +366,8 @@ static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev)
379static void ep93xx_tx_complete(struct net_device *dev) 366static void ep93xx_tx_complete(struct net_device *dev)
380{ 367{
381 struct ep93xx_priv *ep = netdev_priv(dev); 368 struct ep93xx_priv *ep = netdev_priv(dev);
382 int tail_offset;
383 int wake; 369 int wake;
384 370
385 tail_offset = rdl(ep, REG_TXSTSQCURADD) - ep->descs_dma_addr;
386 wake = 0; 371 wake = 0;
387 372
388 spin_lock(&ep->tx_pending_lock); 373 spin_lock(&ep->tx_pending_lock);
@@ -393,15 +378,13 @@ static void ep93xx_tx_complete(struct net_device *dev)
393 378
394 entry = ep->tx_clean_pointer; 379 entry = ep->tx_clean_pointer;
395 tstat = ep->descs->tstat + entry; 380 tstat = ep->descs->tstat + entry;
396 if ((void *)tstat - (void *)ep->descs == tail_offset)
397 break;
398 381
399 tstat0 = tstat->tstat0; 382 tstat0 = tstat->tstat0;
383 if (!(tstat0 & TSTAT0_TXFP))
384 break;
385
400 tstat->tstat0 = 0; 386 tstat->tstat0 = 0;
401 387
402 if (!(tstat0 & TSTAT0_TXFP))
403 printk(KERN_CRIT "ep93xx_tx_complete: buffer not done "
404 " %.8x\n", tstat0);
405 if (tstat0 & TSTAT0_FA) 388 if (tstat0 & TSTAT0_FA)
406 printk(KERN_CRIT "ep93xx_tx_complete: frame aborted " 389 printk(KERN_CRIT "ep93xx_tx_complete: frame aborted "
407 " %.8x\n", tstat0); 390 " %.8x\n", tstat0);