Commit c7c2c39b authored by françois romieu's avatar françois romieu Committed by David S. Miller

r8169: fix Rx index race between FIFO overflow recovery and NAPI handler.

Since 92fc43b4, 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: default avatarFrancois Romieu <romieu@fr.zoreil.com>
Cc: hayeswang <hayeswang@realtek.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 811fd301
...@@ -3935,8 +3935,6 @@ static void rtl_hw_reset(struct rtl8169_private *tp) ...@@ -3935,8 +3935,6 @@ static void rtl_hw_reset(struct rtl8169_private *tp)
break; break;
udelay(100); udelay(100);
} }
rtl8169_init_ring_indexes(tp);
} }
static int __devinit static int __devinit
...@@ -5395,14 +5393,16 @@ static void rtl8169_reset_task(struct work_struct *work) ...@@ -5395,14 +5393,16 @@ static void rtl8169_reset_task(struct work_struct *work)
if (!netif_running(dev)) if (!netif_running(dev))
goto out_unlock; goto out_unlock;
rtl8169_hw_reset(tp);
rtl8169_wait_for_quiescence(dev); rtl8169_wait_for_quiescence(dev);
for (i = 0; i < NUM_RX_DESC; i++) for (i = 0; i < NUM_RX_DESC; i++)
rtl8169_mark_to_asic(tp->RxDescArray + i, rx_buf_sz); rtl8169_mark_to_asic(tp->RxDescArray + i, rx_buf_sz);
rtl8169_tx_clear(tp); rtl8169_tx_clear(tp);
rtl8169_init_ring_indexes(tp);
rtl8169_hw_reset(tp);
rtl_hw_start(dev); rtl_hw_start(dev);
netif_wake_queue(dev); netif_wake_queue(dev);
rtl8169_check_link_status(dev, tp, tp->mmio_addr); rtl8169_check_link_status(dev, tp, tp->mmio_addr);
...@@ -5413,11 +5413,6 @@ static void rtl8169_reset_task(struct work_struct *work) ...@@ -5413,11 +5413,6 @@ static void rtl8169_reset_task(struct work_struct *work)
static void rtl8169_tx_timeout(struct net_device *dev) static void rtl8169_tx_timeout(struct net_device *dev)
{ {
struct rtl8169_private *tp = netdev_priv(dev);
rtl8169_hw_reset(tp);
/* Let's wait a bit while any (async) irq lands on */
rtl8169_schedule_work(dev, rtl8169_reset_task); rtl8169_schedule_work(dev, rtl8169_reset_task);
} }
......
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