Commit baf33d7a authored by Hayes Wang's avatar Hayes Wang Committed by David S. Miller

r8152: avoid to resubmit rx immediately

For the situation that the disconnect event comes very late when the
device is unplugged, the driver would resubmit the RX bulk transfer
after getting the callback with -EPROTO immediately and continually.
Finally, soft lockup occurs.

This patch avoids to resubmit RX immediately. It uses a workqueue to
schedule the RX NAPI. And the NAPI would resubmit the RX. It let the
disconnect event have opportunity to stop the submission before soft
lockup.
Reported-by: default avatarJason-ch Chen <jason-ch.chen@mediatek.com>
Tested-by: default avatarJason-ch Chen <jason-ch.chen@mediatek.com>
Signed-off-by: default avatarHayes Wang <hayeswang@realtek.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3f6cffb8
...@@ -767,6 +767,7 @@ enum rtl8152_flags { ...@@ -767,6 +767,7 @@ enum rtl8152_flags {
PHY_RESET, PHY_RESET,
SCHEDULE_TASKLET, SCHEDULE_TASKLET,
GREEN_ETHERNET, GREEN_ETHERNET,
RX_EPROTO,
}; };
#define DEVICE_ID_THINKPAD_THUNDERBOLT3_DOCK_GEN2 0x3082 #define DEVICE_ID_THINKPAD_THUNDERBOLT3_DOCK_GEN2 0x3082
...@@ -1770,6 +1771,14 @@ static void read_bulk_callback(struct urb *urb) ...@@ -1770,6 +1771,14 @@ static void read_bulk_callback(struct urb *urb)
rtl_set_unplug(tp); rtl_set_unplug(tp);
netif_device_detach(tp->netdev); netif_device_detach(tp->netdev);
return; return;
case -EPROTO:
urb->actual_length = 0;
spin_lock_irqsave(&tp->rx_lock, flags);
list_add_tail(&agg->list, &tp->rx_done);
spin_unlock_irqrestore(&tp->rx_lock, flags);
set_bit(RX_EPROTO, &tp->flags);
schedule_delayed_work(&tp->schedule, 1);
return;
case -ENOENT: case -ENOENT:
return; /* the urb is in unlink state */ return; /* the urb is in unlink state */
case -ETIME: case -ETIME:
...@@ -2425,6 +2434,7 @@ static int rx_bottom(struct r8152 *tp, int budget) ...@@ -2425,6 +2434,7 @@ static int rx_bottom(struct r8152 *tp, int budget)
if (list_empty(&tp->rx_done)) if (list_empty(&tp->rx_done))
goto out1; goto out1;
clear_bit(RX_EPROTO, &tp->flags);
INIT_LIST_HEAD(&rx_queue); INIT_LIST_HEAD(&rx_queue);
spin_lock_irqsave(&tp->rx_lock, flags); spin_lock_irqsave(&tp->rx_lock, flags);
list_splice_init(&tp->rx_done, &rx_queue); list_splice_init(&tp->rx_done, &rx_queue);
...@@ -2441,7 +2451,7 @@ static int rx_bottom(struct r8152 *tp, int budget) ...@@ -2441,7 +2451,7 @@ static int rx_bottom(struct r8152 *tp, int budget)
agg = list_entry(cursor, struct rx_agg, list); agg = list_entry(cursor, struct rx_agg, list);
urb = agg->urb; urb = agg->urb;
if (urb->actual_length < ETH_ZLEN) if (urb->status != 0 || urb->actual_length < ETH_ZLEN)
goto submit; goto submit;
agg_free = rtl_get_free_rx(tp, GFP_ATOMIC); agg_free = rtl_get_free_rx(tp, GFP_ATOMIC);
...@@ -6643,6 +6653,10 @@ static void rtl_work_func_t(struct work_struct *work) ...@@ -6643,6 +6653,10 @@ static void rtl_work_func_t(struct work_struct *work)
netif_carrier_ok(tp->netdev)) netif_carrier_ok(tp->netdev))
tasklet_schedule(&tp->tx_tl); tasklet_schedule(&tp->tx_tl);
if (test_and_clear_bit(RX_EPROTO, &tp->flags) &&
!list_empty(&tp->rx_done))
napi_schedule(&tp->napi);
mutex_unlock(&tp->control); mutex_unlock(&tp->control);
out1: out1:
......
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