mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
wifi: ath10k: move recovery check logic into a new work
Currently, ath10k has a recovery check logic. It will wait for the
last recovery to finish by wait_for_completion_timeout();
But in SDIO scenarios, the recovery function may be invoked from
interrupt context, where long blocking waits are undesirable and can
lead to system instability.
Additionally, Linux’s ordered workqueue processes one task at a time.
If a previous recovery is still queued or executing, new triggers are
ignored. This prevents accurate tracking of consecutive failures and
delays transition to the WEDGED state.
To address this, move the recovery check logic into a different
workqueue.
Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00288-QCARMSWPZ-1
Tested-on: QCA6174 hw3.2 SDIO WLAN.RMH.4.4.1-00189
Fixes: c256a94d1b ("wifi: ath10k: shutdown driver when hardware is unreliable")
Signed-off-by: Kang Yang <kang.yang@oss.qualcomm.com>
Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Link: https://patch.msgid.link/20251014110757.155-1-kang.yang@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
@@ -2493,8 +2492,9 @@ static int ath10k_init_hw_params(struct ath10k *ar)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ath10k_core_needs_recovery(struct ath10k *ar)
|
||||
static void ath10k_core_recovery_check_work(struct work_struct *work)
|
||||
{
|
||||
struct ath10k *ar = container_of(work, struct ath10k, recovery_check_work);
|
||||
long time_left;
|
||||
|
||||
/* Sometimes the recovery will fail and then the next all recovery fail,
|
||||
@@ -2504,7 +2504,7 @@ static bool ath10k_core_needs_recovery(struct ath10k *ar)
|
||||
ath10k_err(ar, "consecutive fail %d times, will shutdown driver!",
|
||||
atomic_read(&ar->fail_cont_count));
|
||||
ar->state = ATH10K_STATE_WEDGED;
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "total recovery count: %d", ++ar->recovery_count);
|
||||
@@ -2518,27 +2518,24 @@ static bool ath10k_core_needs_recovery(struct ath10k *ar)
|
||||
ATH10K_RECOVERY_TIMEOUT_HZ);
|
||||
if (time_left) {
|
||||
ath10k_warn(ar, "previous recovery succeeded, skip this!\n");
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Record the continuous recovery fail count when recovery failed. */
|
||||
atomic_inc(&ar->fail_cont_count);
|
||||
|
||||
/* Avoid having multiple recoveries at the same time. */
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
atomic_inc(&ar->pending_recovery);
|
||||
|
||||
return true;
|
||||
queue_work(ar->workqueue, &ar->restart_work);
|
||||
}
|
||||
|
||||
void ath10k_core_start_recovery(struct ath10k *ar)
|
||||
{
|
||||
if (!ath10k_core_needs_recovery(ar))
|
||||
return;
|
||||
|
||||
queue_work(ar->workqueue, &ar->restart_work);
|
||||
/* Use workqueue_aux to avoid blocking recovery tracking */
|
||||
queue_work(ar->workqueue_aux, &ar->recovery_check_work);
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_start_recovery);
|
||||
|
||||
@@ -3734,6 +3731,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
|
||||
|
||||
INIT_WORK(&ar->register_work, ath10k_core_register_work);
|
||||
INIT_WORK(&ar->restart_work, ath10k_core_restart);
|
||||
INIT_WORK(&ar->recovery_check_work, ath10k_core_recovery_check_work);
|
||||
INIT_WORK(&ar->set_coverage_class_work,
|
||||
ath10k_core_set_coverage_class_work);
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
@@ -1208,6 +1207,7 @@ struct ath10k {
|
||||
|
||||
struct work_struct register_work;
|
||||
struct work_struct restart_work;
|
||||
struct work_struct recovery_check_work;
|
||||
struct work_struct bundle_tx_work;
|
||||
struct work_struct tx_complete_work;
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
@@ -5428,6 +5427,7 @@ static void ath10k_stop(struct ieee80211_hw *hw, bool suspend)
|
||||
cancel_work_sync(&ar->set_coverage_class_work);
|
||||
cancel_delayed_work_sync(&ar->scan.timeout);
|
||||
cancel_work_sync(&ar->restart_work);
|
||||
cancel_work_sync(&ar->recovery_check_work);
|
||||
}
|
||||
|
||||
static int ath10k_config_ps(struct ath10k *ar)
|
||||
|
||||
Reference in New Issue
Block a user