Skip to content

Commit 12dfa2f

Browse files
Ping-Ke ShihKalle Valo
authored andcommitted
rtlwifi: Fix kernel Oops "Fw download fail!!"
When connecting to AP, mac80211 asks driver to enter and leave PS quickly, but driver deinit doesn't wait for delayed work complete when entering PS, then driver reinit procedure and delay work are running simultaneously. This will cause unpredictable kernel oops or crash like rtl8723be: error H2C cmd because of Fw download fail!!! WARNING: CPU: 3 PID: 159 at drivers/net/wireless/realtek/rtlwifi/ rtl8723be/fw.c:227 rtl8723be_fill_h2c_cmd+0x182/0x510 [rtl8723be] CPU: 3 PID: 159 Comm: kworker/3:2 Tainted: G O 4.16.13-2-ARCH #1 Hardware name: ASUSTeK COMPUTER INC. X556UF/X556UF, BIOS X556UF.406 10/21/2016 Workqueue: rtl8723be_pci rtl_c2hcmd_wq_callback [rtlwifi] RIP: 0010:rtl8723be_fill_h2c_cmd+0x182/0x510 [rtl8723be] RSP: 0018:ffffa6ab01e1bd70 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffffa26069071520 RCX: 0000000000000001 RDX: 0000000080000001 RSI: ffffffff8be70e9c RDI: 00000000ffffffff RBP: 0000000000000000 R08: 0000000000000048 R09: 0000000000000348 R10: 0000000000000000 R11: 0000000000000001 R12: 0000000000000000 R13: ffffa26069071520 R14: 0000000000000000 R15: ffffa2607d205f70 FS: 0000000000000000(0000) GS:ffffa26081d80000(0000) knlGS:000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000443b39d3000 CR3: 000000037700a005 CR4: 00000000003606e0 Call Trace: ? halbtc_send_bt_mp_operation.constprop.17+0xd5/0xe0 [btcoexist] ? ex_btc8723b1ant_bt_info_notify+0x3b8/0x820 [btcoexist] ? rtl_c2hcmd_launcher+0xab/0x110 [rtlwifi] ? process_one_work+0x1d1/0x3b0 ? worker_thread+0x2b/0x3d0 ? process_one_work+0x3b0/0x3b0 ? kthread+0x112/0x130 ? kthread_create_on_node+0x60/0x60 ? ret_from_fork+0x35/0x40 Code: 00 76 b4 e9 e2 fe ff ff 4c 89 ee 4c 89 e7 e8 56 22 86 ca e9 5e ... This patch ensures all delayed works done before entering PS to satisfy our expectation, so use cancel_delayed_work_sync() instead. An exception is delayed work ips_nic_off_wq because running task may be itself, so add a parameter ips_wq to deinit function to handle this case. This issue is reported and fixed in below threads: https://github.com/lwfinger/rtlwifi_new/issues/367 https://github.com/lwfinger/rtlwifi_new/issues/366 Tested-by: Evgeny Kapun <[email protected]> # 8723DE Tested-by: Shivam Kakkar <[email protected]> # 8723BE on 4.18-rc1 Signed-off-by: Ping-Ke Shih <[email protected]> Fixes: cceb0a5 ("rtlwifi: Add work queue for c2h cmd.") Cc: Stable <[email protected]> # 4.11+ Reviewed-by: Larry Finger <[email protected]> Signed-off-by: Kalle Valo <[email protected]>
1 parent 755abd2 commit 12dfa2f

File tree

6 files changed

+16
-13
lines changed

6 files changed

+16
-13
lines changed

drivers/net/wireless/realtek/rtlwifi/base.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -484,18 +484,21 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw)
484484

485485
}
486486

487-
void rtl_deinit_deferred_work(struct ieee80211_hw *hw)
487+
void rtl_deinit_deferred_work(struct ieee80211_hw *hw, bool ips_wq)
488488
{
489489
struct rtl_priv *rtlpriv = rtl_priv(hw);
490490

491491
del_timer_sync(&rtlpriv->works.watchdog_timer);
492492

493-
cancel_delayed_work(&rtlpriv->works.watchdog_wq);
494-
cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
495-
cancel_delayed_work(&rtlpriv->works.ps_work);
496-
cancel_delayed_work(&rtlpriv->works.ps_rfon_wq);
497-
cancel_delayed_work(&rtlpriv->works.fwevt_wq);
498-
cancel_delayed_work(&rtlpriv->works.c2hcmd_wq);
493+
cancel_delayed_work_sync(&rtlpriv->works.watchdog_wq);
494+
if (ips_wq)
495+
cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
496+
else
497+
cancel_delayed_work_sync(&rtlpriv->works.ips_nic_off_wq);
498+
cancel_delayed_work_sync(&rtlpriv->works.ps_work);
499+
cancel_delayed_work_sync(&rtlpriv->works.ps_rfon_wq);
500+
cancel_delayed_work_sync(&rtlpriv->works.fwevt_wq);
501+
cancel_delayed_work_sync(&rtlpriv->works.c2hcmd_wq);
499502
}
500503
EXPORT_SYMBOL_GPL(rtl_deinit_deferred_work);
501504

drivers/net/wireless/realtek/rtlwifi/base.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ void rtl_init_rfkill(struct ieee80211_hw *hw);
121121
void rtl_deinit_rfkill(struct ieee80211_hw *hw);
122122

123123
void rtl_watch_dog_timer_callback(struct timer_list *t);
124-
void rtl_deinit_deferred_work(struct ieee80211_hw *hw);
124+
void rtl_deinit_deferred_work(struct ieee80211_hw *hw, bool ips_wq);
125125

126126
bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx);
127127
int rtlwifi_rate_mapping(struct ieee80211_hw *hw, bool isht,

drivers/net/wireless/realtek/rtlwifi/core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ static void rtl_op_stop(struct ieee80211_hw *hw)
196196
/* reset sec info */
197197
rtl_cam_reset_sec_info(hw);
198198

199-
rtl_deinit_deferred_work(hw);
199+
rtl_deinit_deferred_work(hw, false);
200200
}
201201
rtlpriv->intf_ops->adapter_stop(hw);
202202

drivers/net/wireless/realtek/rtlwifi/pci.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2377,7 +2377,7 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
23772377
ieee80211_unregister_hw(hw);
23782378
rtlmac->mac80211_registered = 0;
23792379
} else {
2380-
rtl_deinit_deferred_work(hw);
2380+
rtl_deinit_deferred_work(hw, false);
23812381
rtlpriv->intf_ops->adapter_stop(hw);
23822382
}
23832383
rtlpriv->cfg->ops->disable_interrupt(hw);

drivers/net/wireless/realtek/rtlwifi/ps.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ bool rtl_ps_disable_nic(struct ieee80211_hw *hw)
7171
struct rtl_priv *rtlpriv = rtl_priv(hw);
7272

7373
/*<1> Stop all timer */
74-
rtl_deinit_deferred_work(hw);
74+
rtl_deinit_deferred_work(hw, true);
7575

7676
/*<2> Disable Interrupt */
7777
rtlpriv->cfg->ops->disable_interrupt(hw);
@@ -292,7 +292,7 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw)
292292
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
293293
enum rf_pwrstate rtstate;
294294

295-
cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
295+
cancel_delayed_work_sync(&rtlpriv->works.ips_nic_off_wq);
296296

297297
mutex_lock(&rtlpriv->locks.ips_mutex);
298298
if (ppsc->inactiveps) {

drivers/net/wireless/realtek/rtlwifi/usb.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1132,7 +1132,7 @@ void rtl_usb_disconnect(struct usb_interface *intf)
11321132
ieee80211_unregister_hw(hw);
11331133
rtlmac->mac80211_registered = 0;
11341134
} else {
1135-
rtl_deinit_deferred_work(hw);
1135+
rtl_deinit_deferred_work(hw, false);
11361136
rtlpriv->intf_ops->adapter_stop(hw);
11371137
}
11381138
/*deinit rfkill */

0 commit comments

Comments
 (0)