Commit 11a7756b authored by François Romieu's avatar François Romieu Committed by Jeff Garzik

[netdrvr r8169] Rx wrap bug:

- rtl8169_rx_interrupt() can wrap and process an Rx descriptor that it has
  invalidated a few iterations before. The patch limits the number of
  allowed descriptors between two invocations of the Rx refill function;
- rtl8169_rx_interrupt() now looks similar to rtl8169_tx_interrupt to
  highlight the issue.
parent e24666bb
...@@ -1402,17 +1402,22 @@ static void ...@@ -1402,17 +1402,22 @@ static void
rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
void *ioaddr) void *ioaddr)
{ {
int cur_rx, delta; unsigned long cur_rx, rx_left;
int delta;
assert(dev != NULL); assert(dev != NULL);
assert(tp != NULL); assert(tp != NULL);
assert(ioaddr != NULL); assert(ioaddr != NULL);
cur_rx = tp->cur_rx % NUM_RX_DESC; cur_rx = tp->cur_rx;
rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
while (!(le32_to_cpu(tp->RxDescArray[cur_rx].status) & OWNbit)) { while (rx_left > 0) {
u32 status = le32_to_cpu(tp->RxDescArray[cur_rx].status); int entry = cur_rx % NUM_RX_DESC;
u32 status = le32_to_cpu(tp->RxDescArray[entry].status);
if (status & OWNbit)
break;
if (status & RxRES) { if (status & RxRES) {
printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name); printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name);
tp->stats.rx_errors++; tp->stats.rx_errors++;
...@@ -1421,8 +1426,8 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, ...@@ -1421,8 +1426,8 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
if (status & RxCRC) if (status & RxCRC)
tp->stats.rx_crc_errors++; tp->stats.rx_crc_errors++;
} else { } else {
struct RxDesc *desc = tp->RxDescArray + cur_rx; struct RxDesc *desc = tp->RxDescArray + entry;
struct sk_buff *skb = tp->Rx_skbuff[cur_rx]; struct sk_buff *skb = tp->Rx_skbuff[entry];
int pkt_size = (status & 0x00001FFF) - 4; int pkt_size = (status & 0x00001FFF) - 4;
pci_dma_sync_single(tp->pci_dev, pci_dma_sync_single(tp->pci_dev,
...@@ -1434,7 +1439,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, ...@@ -1434,7 +1439,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
le32_to_cpu(desc->buf_addr), le32_to_cpu(desc->buf_addr),
RX_BUF_SIZE, RX_BUF_SIZE,
PCI_DMA_FROMDEVICE); PCI_DMA_FROMDEVICE);
tp->Rx_skbuff[cur_rx] = NULL; tp->Rx_skbuff[entry] = NULL;
} }
skb_put(skb, pkt_size); skb_put(skb, pkt_size);
...@@ -1446,10 +1451,12 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, ...@@ -1446,10 +1451,12 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
tp->stats.rx_packets++; tp->stats.rx_packets++;
} }
tp->cur_rx++; cur_rx++;
cur_rx = tp->cur_rx % NUM_RX_DESC; rx_left--;
} }
tp->cur_rx = cur_rx;
delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx); delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx);
if (delta > 0) if (delta > 0)
tp->dirty_rx += delta; tp->dirty_rx += delta;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment