123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- 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;
|