7275af06ea28cc073eb9937bbb8f895b9e5db91a
[librecmc/librecmc.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;