aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfrançois romieu <romieu@fr.zoreil.com>2011-12-04 15:30:52 -0500
committerDavid S. Miller <davem@davemloft.net>2011-12-05 18:31:42 -0500
commitc7c2c39be8ed4e503e987151f4599455060e219a (patch)
tree19104da1775a78e824ff50bda26495797af77553
parent811fd3010cf512f2e23e6c4c912aad54516dc706 (diff)
r8169: fix Rx index race between FIFO overflow recovery and NAPI handler.
Since 92fc43b4159b518f5baae57301f26d770b0834c9, rtl8169_tx_timeout ends up resetting Rx and Tx indexes and thus racing with the NAPI handler via -> rtl8169_hw_reset -> rtl_hw_reset -> rtl8169_init_ring_indexes What about returning to the original state ? rtl_hw_reset is only used by rtl8169_hw_reset and rtl8169_init_one. The latter does not need rtl8169_init_ring_indexes because the indexes still contain their original values from the newly allocated network device private data area (i.e. 0). rtl8169_hw_reset is used by: 1. rtl8169_down Helper for rtl8169_close. rtl8169_open explicitely inits the indexes anyway. 2. rtl8169_pcierr_interrupt Indexes are set by rtl8169_reinit_task. 3. rtl8169_interrupt rtl8169_hw_reset is needed when the device goes down. See 1. 4. rtl_shutdown System shutdown handler. Indexes are irrelevant. 5. rtl8169_reset_task Indexes must be set before rtl_hw_start is called. 6. rtl8169_tx_timeout Indexes should not be set. This is the job of rtl8169_reset_task anyway. The removal of rtl8169_hw_reset in rtl8169_tx_timeout and its move in rtl8169_reset_task do not change the analysis. Signed-off-by: Francois Romieu <romieu@fr.zoreil.com> Cc: hayeswang <hayeswang@realtek.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/realtek/r8169.c11
1 files changed, 3 insertions, 8 deletions
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 7a1e3a69f19..67bf0781999 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -3935,8 +3935,6 @@ static void rtl_hw_reset(struct rtl8169_private *tp)
3935 break; 3935 break;
3936 udelay(100); 3936 udelay(100);
3937 } 3937 }
3938
3939 rtl8169_init_ring_indexes(tp);
3940} 3938}
3941 3939
3942static int __devinit 3940static int __devinit
@@ -5395,14 +5393,16 @@ static void rtl8169_reset_task(struct work_struct *work)
5395 if (!netif_running(dev)) 5393 if (!netif_running(dev))
5396 goto out_unlock; 5394 goto out_unlock;
5397 5395
5396 rtl8169_hw_reset(tp);
5397
5398 rtl8169_wait_for_quiescence(dev); 5398 rtl8169_wait_for_quiescence(dev);
5399 5399
5400 for (i = 0; i < NUM_RX_DESC; i++) 5400 for (i = 0; i < NUM_RX_DESC; i++)
5401 rtl8169_mark_to_asic(tp->RxDescArray + i, rx_buf_sz); 5401 rtl8169_mark_to_asic(tp->RxDescArray + i, rx_buf_sz);
5402 5402
5403 rtl8169_tx_clear(tp); 5403 rtl8169_tx_clear(tp);
5404 rtl8169_init_ring_indexes(tp);
5404 5405
5405 rtl8169_hw_reset(tp);
5406 rtl_hw_start(dev); 5406 rtl_hw_start(dev);
5407 netif_wake_queue(dev); 5407 netif_wake_queue(dev);
5408 rtl8169_check_link_status(dev, tp, tp->mmio_addr); 5408 rtl8169_check_link_status(dev, tp, tp->mmio_addr);
@@ -5413,11 +5413,6 @@ out_unlock:
5413 5413
5414static void rtl8169_tx_timeout(struct net_device *dev) 5414static void rtl8169_tx_timeout(struct net_device *dev)
5415{ 5415{
5416 struct rtl8169_private *tp = netdev_priv(dev);
5417
5418 rtl8169_hw_reset(tp);
5419
5420 /* Let's wait a bit while any (async) irq lands on */
5421 rtl8169_schedule_work(dev, rtl8169_reset_task); 5416 rtl8169_schedule_work(dev, rtl8169_reset_task);
5422} 5417}
5423 5418