From: Francois Romieu One of the r8169 tester would like to try -mm SMT scheduler with an up-to-date r8169 driver wrt bug fixes. The patch above is a merge of the relevant patch of my r8169 serie. In its original version, this patch has been sent on netdev and tested against various kernel versions, including plain 2.4.2-rc1, without noticeable regression. In addition to this, nobody cared enough to say that the analysis of the problem was wrong (or even badly written :o) ). It is not a silver bullet against the bugs of the r8169 driver under load/SMP but this specific bug exists in any existing r8169 driver I have heard of. - possible tx descriptor index overflow (assume tp->dirty_tx = NUM_TX_DESC/2, tp->cur_tx = NUM_TX_DESC - 1 and watch TxDescArray for example); - the status of an inadequate descriptor is checked. NB: the bug will not necessarily noticed when tx_left == 1. --- drivers/net/r8169.c | 14 +++++++------- 1 files changed, 7 insertions(+), 7 deletions(-) diff -puN drivers/net/r8169.c~r8169-race-fix drivers/net/r8169.c --- 25/drivers/net/r8169.c~r8169-race-fix 2004-01-24 13:05:53.000000000 -0800 +++ 25-akpm/drivers/net/r8169.c 2004-01-24 13:05:53.000000000 -0800 @@ -1341,8 +1341,7 @@ static void rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp, void *ioaddr) { - unsigned long dirty_tx, tx_left = 0; - int entry = tp->cur_tx % NUM_TX_DESC; + unsigned long dirty_tx, tx_left; assert(dev != NULL); assert(tp != NULL); @@ -1352,20 +1351,21 @@ rtl8169_tx_interrupt(struct net_device * tx_left = tp->cur_tx - dirty_tx; while (tx_left > 0) { + int entry = dirty_tx % NUM_TX_DESC; + if (!(le32_to_cpu(tp->TxDescArray[entry].status) & OWNbit)) { - int cur = dirty_tx % NUM_TX_DESC; - struct sk_buff *skb = tp->Tx_skbuff[cur]; + struct sk_buff *skb = tp->Tx_skbuff[entry]; /* FIXME: is it really accurate for TxErr ? */ tp->stats.tx_bytes += skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN; tp->stats.tx_packets++; - rtl8169_unmap_tx_skb(tp->pci_dev, tp->Tx_skbuff + cur, - tp->TxDescArray + cur); + rtl8169_unmap_tx_skb(tp->pci_dev, tp->Tx_skbuff + entry, + tp->TxDescArray + entry); dev_kfree_skb_irq(skb); + tp->Tx_skbuff[entry] = NULL; dirty_tx++; tx_left--; - entry++; } } _