From: Francois Romieu 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. --- 25-akpm/drivers/net/r8169.c | 25 ++++++++++++++++--------- 1 files changed, 16 insertions(+), 9 deletions(-) diff -puN drivers/net/r8169.c~r8169-rx-wrap-fix drivers/net/r8169.c --- 25/drivers/net/r8169.c~r8169-rx-wrap-fix Thu Feb 12 16:07:38 2004 +++ 25-akpm/drivers/net/r8169.c Thu Feb 12 16:07:38 2004 @@ -1402,17 +1402,22 @@ static void rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, void *ioaddr) { - int cur_rx, delta; + unsigned long cur_rx, rx_left; + int delta; assert(dev != NULL); assert(tp != 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)) { - u32 status = le32_to_cpu(tp->RxDescArray[cur_rx].status); + while (rx_left > 0) { + int entry = cur_rx % NUM_RX_DESC; + u32 status = le32_to_cpu(tp->RxDescArray[entry].status); + if (status & OWNbit) + break; if (status & RxRES) { printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name); tp->stats.rx_errors++; @@ -1421,8 +1426,8 @@ rtl8169_rx_interrupt(struct net_device * if (status & RxCRC) tp->stats.rx_crc_errors++; } else { - struct RxDesc *desc = tp->RxDescArray + cur_rx; - struct sk_buff *skb = tp->Rx_skbuff[cur_rx]; + struct RxDesc *desc = tp->RxDescArray + entry; + struct sk_buff *skb = tp->Rx_skbuff[entry]; int pkt_size = (status & 0x00001FFF) - 4; pci_dma_sync_single(tp->pci_dev, @@ -1434,7 +1439,7 @@ rtl8169_rx_interrupt(struct net_device * le32_to_cpu(desc->buf_addr), RX_BUF_SIZE, PCI_DMA_FROMDEVICE); - tp->Rx_skbuff[cur_rx] = NULL; + tp->Rx_skbuff[entry] = NULL; } skb_put(skb, pkt_size); @@ -1446,10 +1451,12 @@ rtl8169_rx_interrupt(struct net_device * tp->stats.rx_packets++; } - tp->cur_rx++; - cur_rx = tp->cur_rx % NUM_RX_DESC; + cur_rx++; + rx_left--; } + tp->cur_rx = cur_rx; + delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx); if (delta > 0) tp->dirty_rx += delta; _