7275af06ea28cc073eb9937bbb8f895b9e5db91a
[openwrt/staging/pepe2k.git] /
1 From 3811fa1f231f1a3e29759efef4992116604aab8b Mon Sep 17 00:00:00 2001
2 From: Sowmiya Sree Elavalagan <quic_ssreeela@quicinc.com>
3 Date: Tue, 11 Oct 2022 15:23:46 +0530
4 Subject: [PATCH] wifi: ath11k: Fix firmware crash on vdev delete race
5 condition
6
7 Current code does not wait for vdev delete completion on vdev create
8 failures and tries to send another vdev create followed by vdev set
9 param to firmware with same vdev id. This causes firmware crash.
10 Fix this crash by waiting for vdev delete completion on vdev
11 create failures.
12
13 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.6.0.1-00905-QCAHKSWPL_SILICONZ-1
14
15 Signed-off-by: Sowmiya Sree Elavalagan <quic_ssreeela@quicinc.com>
16 Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
17 Link: https://lore.kernel.org/r/20221011095346.3901-1-quic_ssreeela@quicinc.com
18 ---
19 drivers/net/wireless/ath/ath11k/mac.c | 60 +++++++++++++++++----------
20 1 file changed, 37 insertions(+), 23 deletions(-)
21
22 --- a/drivers/net/wireless/ath/ath11k/mac.c
23 +++ b/drivers/net/wireless/ath/ath11k/mac.c
24 @@ -6233,6 +6233,40 @@ void ath11k_mac_11d_scan_stop_all(struct
25 }
26 }
27
28 +static int ath11k_mac_vdev_delete(struct ath11k *ar, struct ath11k_vif *arvif)
29 +{
30 + unsigned long time_left;
31 + struct ieee80211_vif *vif = arvif->vif;
32 + int ret = 0;
33 +
34 + lockdep_assert_held(&ar->conf_mutex);
35 +
36 + reinit_completion(&ar->vdev_delete_done);
37 +
38 + ret = ath11k_wmi_vdev_delete(ar, arvif->vdev_id);
39 + if (ret) {
40 + ath11k_warn(ar->ab, "failed to delete WMI vdev %d: %d\n",
41 + arvif->vdev_id, ret);
42 + return ret;
43 + }
44 +
45 + time_left = wait_for_completion_timeout(&ar->vdev_delete_done,
46 + ATH11K_VDEV_DELETE_TIMEOUT_HZ);
47 + if (time_left == 0) {
48 + ath11k_warn(ar->ab, "Timeout in receiving vdev delete response\n");
49 + return -ETIMEDOUT;
50 + }
51 +
52 + ar->ab->free_vdev_map |= 1LL << (arvif->vdev_id);
53 + ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
54 + ar->num_created_vdevs--;
55 +
56 + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n",
57 + vif->addr, arvif->vdev_id);
58 +
59 + return ret;
60 +}
61 +
62 static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
63 struct ieee80211_vif *vif)
64 {
65 @@ -6468,10 +6502,7 @@ err_peer_del:
66 }
67
68 err_vdev_del:
69 - ath11k_wmi_vdev_delete(ar, arvif->vdev_id);
70 - ar->num_created_vdevs--;
71 - ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
72 - ab->free_vdev_map |= 1LL << arvif->vdev_id;
73 + ath11k_mac_vdev_delete(ar, arvif);
74 spin_lock_bh(&ar->data_lock);
75 list_del(&arvif->list);
76 spin_unlock_bh(&ar->data_lock);
77 @@ -6499,7 +6530,6 @@ static void ath11k_mac_op_remove_interfa
78 struct ath11k *ar = hw->priv;
79 struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
80 struct ath11k_base *ab = ar->ab;
81 - unsigned long time_left;
82 int ret;
83 int i;
84
85 @@ -6520,29 +6550,13 @@ static void ath11k_mac_op_remove_interfa
86 arvif->vdev_id, ret);
87 }
88
89 - reinit_completion(&ar->vdev_delete_done);
90 -
91 - ret = ath11k_wmi_vdev_delete(ar, arvif->vdev_id);
92 + ret = ath11k_mac_vdev_delete(ar, arvif);
93 if (ret) {
94 - ath11k_warn(ab, "failed to delete WMI vdev %d: %d\n",
95 + ath11k_warn(ab, "failed to delete vdev %d: %d\n",
96 arvif->vdev_id, ret);
97 goto err_vdev_del;
98 }
99
100 - time_left = wait_for_completion_timeout(&ar->vdev_delete_done,
101 - ATH11K_VDEV_DELETE_TIMEOUT_HZ);
102 - if (time_left == 0) {
103 - ath11k_warn(ab, "Timeout in receiving vdev delete response\n");
104 - goto err_vdev_del;
105 - }
106 -
107 - ab->free_vdev_map |= 1LL << (arvif->vdev_id);
108 - ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
109 - ar->num_created_vdevs--;
110 -
111 - ath11k_dbg(ab, ATH11K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n",
112 - vif->addr, arvif->vdev_id);
113 -
114 if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
115 clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags);
116 ar->monitor_vdev_id = -1;