mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-20 10:51:27 +00:00
200 lines
5.8 KiB
Diff
200 lines
5.8 KiB
Diff
From 07ce203ddee206785244a083ba030ed99af07392 Mon Sep 17 00:00:00 2001
|
|
From: Anilkumar Kolli <akolli@codeaurora.org>
|
|
Date: Wed, 9 Sep 2020 19:53:01 +0530
|
|
Subject: [PATCH 13/15] ath11k: ath11k: add support for device recovery
|
|
|
|
Test command:
|
|
echo assert > /sys/kernel/debug/ath11k/qca6390/simulate_fw_crash
|
|
|
|
Then ath11k_mhi_notify_status receive MHI_CB_EE_RDDM notify and start
|
|
to do recovery process.
|
|
|
|
It need add workqueue_aux, because ab->workqueue is used when receive
|
|
ATH11K_QMI_EVENT_FW_READY in recovery process(queue_work(ab->workqueue,
|
|
&ab->restart_work;)), and ath11k_core_reset will wait for max
|
|
ATH11K_RESET_TIMEOUT_HZ for the previous restart_work finished, if
|
|
ath11k_core_reset also queued in ab->workqueue, then it will delay
|
|
restart_work of previous recovery and lead previous recovery fail.
|
|
|
|
With this patch, ath11k recovery success
|
|
|
|
Signed-off-by: Wen Gong <wgong@codeaurora.org>
|
|
---
|
|
drivers/net/wireless/ath/ath11k/core.c | 48 ++++++++++++++++++++++++++++++++++
|
|
drivers/net/wireless/ath/ath11k/core.h | 6 +++++
|
|
drivers/net/wireless/ath/ath11k/mhi.c | 31 ++++++++++++++++++++++
|
|
drivers/net/wireless/ath/ath11k/pci.c | 1 +
|
|
4 files changed, 86 insertions(+)
|
|
|
|
--- a/drivers/net/wireless/ath/ath11k/core.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/core.c
|
|
@@ -1075,9 +1075,49 @@ static void ath11k_core_restart(struct w
|
|
}
|
|
mutex_unlock(&ar->conf_mutex);
|
|
}
|
|
+
|
|
+ if (ab->is_reset) {
|
|
+ atomic_dec(&ab->reset_count);
|
|
+ complete(&ab->reset_complete);
|
|
+ ab->is_reset = false;
|
|
+ }
|
|
+
|
|
complete(&ab->driver_recovery);
|
|
}
|
|
|
|
+static void ath11k_core_reset(struct work_struct *work)
|
|
+{
|
|
+ struct ath11k_base *ab = container_of(work, struct ath11k_base, reset_work);
|
|
+ int reset_count;
|
|
+ long time_left;
|
|
+
|
|
+ reset_count = atomic_add_return(1, &ab->reset_count);
|
|
+
|
|
+ if (reset_count > 1) {
|
|
+ ath11k_warn(ab, "already reseting count %d\n", reset_count);
|
|
+
|
|
+ reinit_completion(&ab->reset_complete);
|
|
+ time_left = wait_for_completion_timeout(&ab->reset_complete,
|
|
+ ATH11K_RESET_TIMEOUT_HZ);
|
|
+ ath11k_info(ab, "reset wait time left %ld\n", time_left);
|
|
+
|
|
+ if (time_left) {
|
|
+ ath11k_info(ab, "to skip reset\n");
|
|
+ atomic_dec(&ab->reset_count);
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ath11k_info(ab, "reset starting\n");
|
|
+
|
|
+ ab->is_reset = true;
|
|
+
|
|
+ ath11k_hif_power_down(ab);
|
|
+ ath11k_hif_power_up(ab);
|
|
+
|
|
+ ath11k_info(ab, "reset started\n");
|
|
+}
|
|
+
|
|
static int ath11k_init_hw_params(struct ath11k_base *ab)
|
|
{
|
|
const struct ath11k_hw_params *hw_params = NULL;
|
|
@@ -1179,14 +1219,20 @@ struct ath11k_base *ath11k_core_alloc(st
|
|
if (!ab->workqueue)
|
|
goto err_sc_free;
|
|
|
|
+ ab->workqueue_aux = create_singlethread_workqueue("ath11k_aux_wq");
|
|
+ if (!ab->workqueue_aux)
|
|
+ goto err_free_wq;
|
|
+
|
|
mutex_init(&ab->core_lock);
|
|
spin_lock_init(&ab->base_lock);
|
|
+ init_completion(&ab->reset_complete);
|
|
|
|
INIT_LIST_HEAD(&ab->peers);
|
|
init_waitqueue_head(&ab->peer_mapping_wq);
|
|
init_waitqueue_head(&ab->wmi_ab.tx_credits_wq);
|
|
init_waitqueue_head(&ab->qmi.cold_boot_waitq);
|
|
INIT_WORK(&ab->restart_work, ath11k_core_restart);
|
|
+ INIT_WORK(&ab->reset_work, ath11k_core_reset);
|
|
timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0);
|
|
init_completion(&ab->htc_suspend);
|
|
init_completion(&ab->wow.wakeup_completed);
|
|
@@ -1197,6 +1243,8 @@ struct ath11k_base *ath11k_core_alloc(st
|
|
|
|
return ab;
|
|
|
|
+err_free_wq:
|
|
+ destroy_workqueue(ab->workqueue);
|
|
err_sc_free:
|
|
kfree(ab);
|
|
return NULL;
|
|
--- a/drivers/net/wireless/ath/ath11k/core.h
|
|
+++ b/drivers/net/wireless/ath/ath11k/core.h
|
|
@@ -36,6 +36,7 @@
|
|
/* Pending management packets threshold for dropping probe responses */
|
|
#define ATH11K_PRB_RSP_DROP_THRESHOLD ((ATH11K_TX_MGMT_TARGET_MAX_SUPPORT_WMI * 3) / 4)
|
|
|
|
+#define ATH11K_RESET_TIMEOUT_HZ (10 * HZ)
|
|
#define ATH11K_INVALID_HW_MAC_ID 0xFF
|
|
#define ATH11K_RX_RATE_TABLE_NUM 320
|
|
#define ATH11K_RX_RATE_TABLE_11AX_NUM 576
|
|
@@ -819,6 +820,11 @@ struct ath11k_base {
|
|
struct completion driver_recovery;
|
|
struct workqueue_struct *workqueue;
|
|
struct work_struct restart_work;
|
|
+ struct workqueue_struct *workqueue_aux;
|
|
+ struct work_struct reset_work;
|
|
+ atomic_t reset_count;
|
|
+ bool is_reset;
|
|
+ struct completion reset_complete;
|
|
struct {
|
|
/* protected by data_lock */
|
|
u32 fw_crash_counter;
|
|
--- a/drivers/net/wireless/ath/ath11k/mhi.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/mhi.c
|
|
@@ -281,6 +281,29 @@ static int ath11k_mhi_get_msi(struct ath
|
|
return 0;
|
|
}
|
|
|
|
+static char *ath11k_mhi_callback_to_str(int reason)
|
|
+{
|
|
+ switch (reason) {
|
|
+ case MHI_CB_IDLE:
|
|
+ return "MHI_CB_IDLE";
|
|
+ case MHI_CB_PENDING_DATA:
|
|
+ return "MHI_CB_PENDING_DATA";
|
|
+ case MHI_CB_LPM_ENTER:
|
|
+ return "MHI_CB_LPM_ENTER";
|
|
+ case MHI_CB_LPM_EXIT:
|
|
+ return "MHI_CB_LPM_EXIT";
|
|
+ case MHI_CB_EE_RDDM:
|
|
+ return "MHI_CB_EE_RDDM";
|
|
+ case MHI_CB_SYS_ERROR:
|
|
+ return "MHI_CB_SYS_ERROR";
|
|
+ case MHI_CB_FATAL_ERROR:
|
|
+ return "MHI_CB_FATAL_ERROR";
|
|
+ default:
|
|
+ return "UNKNOWN";
|
|
+ }
|
|
+};
|
|
+
|
|
+
|
|
static int ath11k_mhi_op_runtime_get(struct mhi_controller *mhi_cntrl)
|
|
{
|
|
return 0;
|
|
@@ -288,6 +311,7 @@ static int ath11k_mhi_op_runtime_get(str
|
|
|
|
static void ath11k_mhi_op_runtime_put(struct mhi_controller *mhi_cntrl)
|
|
{
|
|
+
|
|
}
|
|
|
|
static void ath11k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl,
|
|
@@ -295,10 +319,16 @@ static void ath11k_mhi_op_status_cb(stru
|
|
{
|
|
struct ath11k_base *ab = dev_get_drvdata(mhi_cntrl->cntrl_dev);
|
|
|
|
+ ath11k_info(ab, "mhi notify status reason %s\n",
|
|
+ ath11k_mhi_callback_to_str(cb));
|
|
+
|
|
switch (cb) {
|
|
case MHI_CB_SYS_ERROR:
|
|
ath11k_warn(ab, "firmware crashed: MHI_CB_SYS_ERROR\n");
|
|
break;
|
|
+ case MHI_CB_EE_RDDM:
|
|
+ queue_work(ab->workqueue_aux, &ab->reset_work);
|
|
+ break;
|
|
default:
|
|
break;
|
|
}
|
|
--- a/drivers/net/wireless/ath/ath11k/pci.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/pci.c
|
|
@@ -1334,6 +1334,7 @@ static void ath11k_pci_remove(struct pci
|
|
}
|
|
|
|
set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
|
|
+ cancel_work_sync(&ab->reset_work);
|
|
|
|
ath11k_core_deinit(ab);
|
|
|