diff options
author | Lennert Buytenhek <buytenh@wantstofly.org> | 2006-10-30 13:52:31 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-10-31 20:22:05 -0500 |
commit | 2d38caba5fd148976f54930782e8209fa45879a0 (patch) | |
tree | 7f8bc1ee29d9bfc79ecb9a609084526a874df492 /drivers | |
parent | d5b9b787b5e1618dfe82a2c2a6972374e85b02db (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')
-rw-r--r-- | drivers/net/arm/ep93xx_eth.c | 35 |
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) | |||
193 | static int ep93xx_rx(struct net_device *dev, int *budget) | 193 | static 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 | ||
302 | static int ep93xx_have_more_rx(struct ep93xx_priv *ep) | 294 | static 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 | ||
313 | static int ep93xx_poll(struct net_device *dev, int *budget) | 300 | static 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) | |||
379 | static void ep93xx_tx_complete(struct net_device *dev) | 366 | static 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); |