From: Yan-Hsuan Chuang <yhchuang@xxxxxxxxxxx> Driver could possibly be dead-locked while canceling works with *_sync() with mutex lock held. Those cancel_delayed_work_sync() functions will wait until the work is done, but if we hold the lock, they will never acquire the lock. To prevent this, simply release the lock and acquire again after the works have been canceled. And to avoid the works being queued again, check if the device is at RTW_FLAG_RUNNING state, otherwise just return and do nothing. Signed-off-by: Yan-Hsuan Chuang <yhchuang@xxxxxxxxxxx> --- drivers/net/wireless/realtek/rtw88/coex.c | 3 +++ drivers/net/wireless/realtek/rtw88/fw.c | 4 ++++ drivers/net/wireless/realtek/rtw88/main.c | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c index 4dfb2ec395ee..f91dc21a8bf1 100644 --- a/drivers/net/wireless/realtek/rtw88/coex.c +++ b/drivers/net/wireless/realtek/rtw88/coex.c @@ -1904,6 +1904,9 @@ static void rtw_coex_run_coex(struct rtw_dev *rtwdev, u8 reason) lockdep_assert_held(&rtwdev->mutex); + if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags)) + return; + coex_dm->reason = reason; /* update wifi_link_info_ext variable */ diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index b765b26b6926..b36928470fc0 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -136,6 +136,9 @@ void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb) mutex_lock(&rtwdev->mutex); + if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags)) + goto unlock; + switch (c2h->id) { case C2H_BT_INFO: rtw_coex_bt_info_notify(rtwdev, c2h->payload, len); @@ -153,6 +156,7 @@ void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb) break; } +unlock: mutex_unlock(&rtwdev->mutex); } diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 2845d2838f7b..edecc7d7ea56 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -909,11 +909,16 @@ void rtw_core_stop(struct rtw_dev *rtwdev) clear_bit(RTW_FLAG_RUNNING, rtwdev->flags); clear_bit(RTW_FLAG_FW_RUNNING, rtwdev->flags); + mutex_unlock(&rtwdev->mutex); + + cancel_work_sync(&rtwdev->c2h_work); cancel_delayed_work_sync(&rtwdev->watch_dog_work); cancel_delayed_work_sync(&coex->bt_relink_work); cancel_delayed_work_sync(&coex->bt_reenable_work); cancel_delayed_work_sync(&coex->defreeze_work); + mutex_lock(&rtwdev->mutex); + rtw_power_off(rtwdev); } -- 2.17.1