ath11k: peer delete synchronization with firmware
authorRitesh Singh <ritesi@codeaurora.org>
Tue, 24 Nov 2020 15:59:14 +0000 (17:59 +0200)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 24 Nov 2020 16:04:34 +0000 (18:04 +0200)
Peer creation in firmware fails, if last peer deletion
is still in progress.
Hence, add wait for the event after deleting every peer
from host driver to synchronize with firmware.

Signed-off-by: Ritesh Singh <ritesi@codeaurora.org>
Signed-off-by: Maharaja Kennadyrajan <mkenna@codeaurora.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/1605514143-17652-3-git-send-email-mkenna@codeaurora.org
drivers/net/wireless/ath/ath11k/core.c
drivers/net/wireless/ath/ath11k/core.h
drivers/net/wireless/ath/ath11k/mac.c
drivers/net/wireless/ath/ath11k/peer.c
drivers/net/wireless/ath/ath11k/peer.h
drivers/net/wireless/ath/ath11k/wmi.c

index f792825850b81620f393f33ddcfa2c3dfda78303..da20ed752ca5936d6fe5f30f7d18ffdb33c85a3a 100644 (file)
@@ -808,6 +808,7 @@ static void ath11k_core_restart(struct work_struct *work)
                complete(&ar->scan.started);
                complete(&ar->scan.completed);
                complete(&ar->peer_assoc_done);
+               complete(&ar->peer_delete_done);
                complete(&ar->install_key_done);
                complete(&ar->vdev_setup_done);
                complete(&ar->vdev_delete_done);
index b1b8afecec3a42564282908b5b1e56fa72796256..88e5a9b9f52da21b3101370b739565fd0424a00b 100644 (file)
@@ -506,6 +506,7 @@ struct ath11k {
        u8 lmac_id;
 
        struct completion peer_assoc_done;
+       struct completion peer_delete_done;
 
        int install_key_status;
        struct completion install_key_done;
index 566e2a498a82d17eb7f01b6042131f8840d3227e..f97d22d7f9237ad764481a9fa7a5e4c4f8c4c486 100644 (file)
@@ -4624,8 +4624,22 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
 
 err_peer_del:
        if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
+               reinit_completion(&ar->peer_delete_done);
+
+               ret = ath11k_wmi_send_peer_delete_cmd(ar, vif->addr,
+                                                     arvif->vdev_id);
+               if (ret) {
+                       ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n",
+                                   arvif->vdev_id, vif->addr);
+                       return ret;
+               }
+
+               ret = ath11k_wait_for_peer_delete_done(ar, arvif->vdev_id,
+                                                      vif->addr);
+               if (ret)
+                       return ret;
+
                ar->num_peers--;
-               ath11k_wmi_send_peer_delete_cmd(ar, vif->addr, arvif->vdev_id);
        }
 
 err_vdev_del:
@@ -6470,6 +6484,7 @@ int ath11k_mac_allocate(struct ath11k_base *ab)
                init_completion(&ar->vdev_setup_done);
                init_completion(&ar->vdev_delete_done);
                init_completion(&ar->peer_assoc_done);
+               init_completion(&ar->peer_delete_done);
                init_completion(&ar->install_key_done);
                init_completion(&ar->bss_survey_done);
                init_completion(&ar->scan.started);
index 61ad9300eafb10a2cbb98c0955c0ee169f56d143..1866d82678fa9fc981cfea09946f0825111c3738 100644 (file)
@@ -177,12 +177,36 @@ static int ath11k_wait_for_peer_deleted(struct ath11k *ar, int vdev_id, const u8
        return ath11k_wait_for_peer_common(ar->ab, vdev_id, addr, false);
 }
 
+int ath11k_wait_for_peer_delete_done(struct ath11k *ar, u32 vdev_id,
+                                    const u8 *addr)
+{
+       int ret;
+       unsigned long time_left;
+
+       ret = ath11k_wait_for_peer_deleted(ar, vdev_id, addr);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed wait for peer deleted");
+               return ret;
+       }
+
+       time_left = wait_for_completion_timeout(&ar->peer_delete_done,
+                                               3 * HZ);
+       if (time_left == 0) {
+               ath11k_warn(ar->ab, "Timeout in receiving peer delete response\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
 int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr)
 {
        int ret;
 
        lockdep_assert_held(&ar->conf_mutex);
 
+       reinit_completion(&ar->peer_delete_done);
+
        ret = ath11k_wmi_send_peer_delete_cmd(ar, addr, vdev_id);
        if (ret) {
                ath11k_warn(ar->ab,
@@ -191,7 +215,7 @@ int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr)
                return ret;
        }
 
-       ret = ath11k_wait_for_peer_deleted(ar, vdev_id, addr);
+       ret = ath11k_wait_for_peer_delete_done(ar, vdev_id, addr);
        if (ret)
                return ret;
 
@@ -247,8 +271,22 @@ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
                spin_unlock_bh(&ar->ab->base_lock);
                ath11k_warn(ar->ab, "failed to find peer %pM on vdev %i after creation\n",
                            param->peer_addr, param->vdev_id);
-               ath11k_wmi_send_peer_delete_cmd(ar, param->peer_addr,
-                                               param->vdev_id);
+
+               reinit_completion(&ar->peer_delete_done);
+
+               ret = ath11k_wmi_send_peer_delete_cmd(ar, param->peer_addr,
+                                                     param->vdev_id);
+               if (ret) {
+                       ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n",
+                                   param->vdev_id, param->peer_addr);
+                       return ret;
+               }
+
+               ret = ath11k_wait_for_peer_delete_done(ar, param->vdev_id,
+                                                      param->peer_addr);
+               if (ret)
+                       return ret;
+
                return -ENOENT;
        }
 
index 5d125ce8984e3b495784dd214ae6e8ec749f871e..bba2e00b6944aeb00c31f4b80341512528bb52ab 100644 (file)
@@ -41,5 +41,7 @@ void ath11k_peer_cleanup(struct ath11k *ar, u32 vdev_id);
 int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr);
 int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
                       struct ieee80211_sta *sta, struct peer_create_params *param);
+int ath11k_wait_for_peer_delete_done(struct ath11k *ar, u32 vdev_id,
+                                    const u8 *addr);
 
 #endif /* _PEER_H_ */
index d1175a1c4de39f10103dd27aeb8cdc81cbcd1701..e374270b693771cc9b707dc8879f7eeb7961bd80 100644 (file)
@@ -5730,15 +5730,26 @@ static int ath11k_ready_event(struct ath11k_base *ab, struct sk_buff *skb)
 static void ath11k_peer_delete_resp_event(struct ath11k_base *ab, struct sk_buff *skb)
 {
        struct wmi_peer_delete_resp_event peer_del_resp;
+       struct ath11k *ar;
 
        if (ath11k_pull_peer_del_resp_ev(ab, skb, &peer_del_resp) != 0) {
                ath11k_warn(ab, "failed to extract peer delete resp");
                return;
        }
 
-       /* TODO: Do we need to validate whether ath11k_peer_find() return NULL
-        *       Why this is needed when there is HTT event for peer delete
-        */
+       rcu_read_lock();
+       ar = ath11k_mac_get_ar_by_vdev_id(ab, peer_del_resp.vdev_id);
+       if (!ar) {
+               ath11k_warn(ab, "invalid vdev id in peer delete resp ev %d",
+                           peer_del_resp.vdev_id);
+               rcu_read_unlock();
+               return;
+       }
+
+       complete(&ar->peer_delete_done);
+       rcu_read_unlock();
+       ath11k_dbg(ab, ATH11K_DBG_WMI, "peer delete resp for vdev id %d addr %pM\n",
+                  peer_del_resp.vdev_id, peer_del_resp.peer_macaddr.addr);
 }
 
 static void ath11k_vdev_delete_resp_event(struct ath11k_base *ab,