Skip to content

Commit ee8d2e7

Browse files
Ping-Ke Shihgregkh
authored andcommitted
rtlwifi: Fix kernel Oops "Fw download fail!!"
commit 12dfa2f upstream. 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]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 3caea51 commit ee8d2e7

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
@@ -483,18 +483,21 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw)
483483

484484
}
485485

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

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

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

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(unsigned long data);
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
@@ -2359,7 +2359,7 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
23592359
ieee80211_unregister_hw(hw);
23602360
rtlmac->mac80211_registered = 0;
23612361
} else {
2362-
rtl_deinit_deferred_work(hw);
2362+
rtl_deinit_deferred_work(hw, false);
23632363
rtlpriv->intf_ops->adapter_stop(hw);
23642364
}
23652365
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
@@ -66,7 +66,7 @@ bool rtl_ps_disable_nic(struct ieee80211_hw *hw)
6666
struct rtl_priv *rtlpriv = rtl_priv(hw);
6767

6868
/*<1> Stop all timer */
69-
rtl_deinit_deferred_work(hw);
69+
rtl_deinit_deferred_work(hw, true);
7070

7171
/*<2> Disable Interrupt */
7272
rtlpriv->cfg->ops->disable_interrupt(hw);
@@ -287,7 +287,7 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw)
287287
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
288288
enum rf_pwrstate rtstate;
289289

290-
cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
290+
cancel_delayed_work_sync(&rtlpriv->works.ips_nic_off_wq);
291291

292292
spin_lock(&rtlpriv->locks.ips_lock);
293293
if (ppsc->inactiveps) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1150,7 +1150,7 @@ void rtl_usb_disconnect(struct usb_interface *intf)
11501150
ieee80211_unregister_hw(hw);
11511151
rtlmac->mac80211_registered = 0;
11521152
} else {
1153-
rtl_deinit_deferred_work(hw);
1153+
rtl_deinit_deferred_work(hw, false);
11541154
rtlpriv->intf_ops->adapter_stop(hw);
11551155
}
11561156
/*deinit rfkill */

0 commit comments

Comments
 (0)