117 lines
3.7 KiB
Diff
117 lines
3.7 KiB
Diff
From 3811fa1f231f1a3e29759efef4992116604aab8b Mon Sep 17 00:00:00 2001
|
|
From: Sowmiya Sree Elavalagan <quic_ssreeela@quicinc.com>
|
|
Date: Tue, 11 Oct 2022 15:23:46 +0530
|
|
Subject: [PATCH] wifi: ath11k: Fix firmware crash on vdev delete race
|
|
condition
|
|
|
|
Current code does not wait for vdev delete completion on vdev create
|
|
failures and tries to send another vdev create followed by vdev set
|
|
param to firmware with same vdev id. This causes firmware crash.
|
|
Fix this crash by waiting for vdev delete completion on vdev
|
|
create failures.
|
|
|
|
Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.6.0.1-00905-QCAHKSWPL_SILICONZ-1
|
|
|
|
Signed-off-by: Sowmiya Sree Elavalagan <quic_ssreeela@quicinc.com>
|
|
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
|
|
Link: https://lore.kernel.org/r/20221011095346.3901-1-quic_ssreeela@quicinc.com
|
|
---
|
|
drivers/net/wireless/ath/ath11k/mac.c | 60 +++++++++++++++++----------
|
|
1 file changed, 37 insertions(+), 23 deletions(-)
|
|
|
|
--- a/drivers/net/wireless/ath/ath11k/mac.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/mac.c
|
|
@@ -6233,6 +6233,40 @@ void ath11k_mac_11d_scan_stop_all(struct
|
|
}
|
|
}
|
|
|
|
+static int ath11k_mac_vdev_delete(struct ath11k *ar, struct ath11k_vif *arvif)
|
|
+{
|
|
+ unsigned long time_left;
|
|
+ struct ieee80211_vif *vif = arvif->vif;
|
|
+ int ret = 0;
|
|
+
|
|
+ lockdep_assert_held(&ar->conf_mutex);
|
|
+
|
|
+ reinit_completion(&ar->vdev_delete_done);
|
|
+
|
|
+ ret = ath11k_wmi_vdev_delete(ar, arvif->vdev_id);
|
|
+ if (ret) {
|
|
+ ath11k_warn(ar->ab, "failed to delete WMI vdev %d: %d\n",
|
|
+ arvif->vdev_id, ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ time_left = wait_for_completion_timeout(&ar->vdev_delete_done,
|
|
+ ATH11K_VDEV_DELETE_TIMEOUT_HZ);
|
|
+ if (time_left == 0) {
|
|
+ ath11k_warn(ar->ab, "Timeout in receiving vdev delete response\n");
|
|
+ return -ETIMEDOUT;
|
|
+ }
|
|
+
|
|
+ ar->ab->free_vdev_map |= 1LL << (arvif->vdev_id);
|
|
+ ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
|
|
+ ar->num_created_vdevs--;
|
|
+
|
|
+ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n",
|
|
+ vif->addr, arvif->vdev_id);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
|
|
struct ieee80211_vif *vif)
|
|
{
|
|
@@ -6468,10 +6502,7 @@ err_peer_del:
|
|
}
|
|
|
|
err_vdev_del:
|
|
- ath11k_wmi_vdev_delete(ar, arvif->vdev_id);
|
|
- ar->num_created_vdevs--;
|
|
- ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
|
|
- ab->free_vdev_map |= 1LL << arvif->vdev_id;
|
|
+ ath11k_mac_vdev_delete(ar, arvif);
|
|
spin_lock_bh(&ar->data_lock);
|
|
list_del(&arvif->list);
|
|
spin_unlock_bh(&ar->data_lock);
|
|
@@ -6499,7 +6530,6 @@ static void ath11k_mac_op_remove_interfa
|
|
struct ath11k *ar = hw->priv;
|
|
struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
|
|
struct ath11k_base *ab = ar->ab;
|
|
- unsigned long time_left;
|
|
int ret;
|
|
int i;
|
|
|
|
@@ -6520,29 +6550,13 @@ static void ath11k_mac_op_remove_interfa
|
|
arvif->vdev_id, ret);
|
|
}
|
|
|
|
- reinit_completion(&ar->vdev_delete_done);
|
|
-
|
|
- ret = ath11k_wmi_vdev_delete(ar, arvif->vdev_id);
|
|
+ ret = ath11k_mac_vdev_delete(ar, arvif);
|
|
if (ret) {
|
|
- ath11k_warn(ab, "failed to delete WMI vdev %d: %d\n",
|
|
+ ath11k_warn(ab, "failed to delete vdev %d: %d\n",
|
|
arvif->vdev_id, ret);
|
|
goto err_vdev_del;
|
|
}
|
|
|
|
- time_left = wait_for_completion_timeout(&ar->vdev_delete_done,
|
|
- ATH11K_VDEV_DELETE_TIMEOUT_HZ);
|
|
- if (time_left == 0) {
|
|
- ath11k_warn(ab, "Timeout in receiving vdev delete response\n");
|
|
- goto err_vdev_del;
|
|
- }
|
|
-
|
|
- ab->free_vdev_map |= 1LL << (arvif->vdev_id);
|
|
- ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
|
|
- ar->num_created_vdevs--;
|
|
-
|
|
- ath11k_dbg(ab, ATH11K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n",
|
|
- vif->addr, arvif->vdev_id);
|
|
-
|
|
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
|
|
clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags);
|
|
ar->monitor_vdev_id = -1;
|