ath10k: Add peer delete response event
authorDundi Raviteja <dundi@codeaurora.org>
Mon, 3 Jun 2019 14:41:51 +0000 (17:41 +0300)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 25 Jun 2019 13:12:24 +0000 (16:12 +0300)
Peer creation in firmware fails if last peer deletion is still
in progress.

The firmware sends a peer delete response event if it advertises
the service WMI_SERVICE_SYNC_DELETE_CMDS. This peer delete response
event is used to synchronize the peer deletion.

Add peer delete response event and wait for the event after
deleting every peer from host driver to synchronize with firmware.

Tested HW: WCN3990
Tested FW: WLAN.HL.2.0-01188-QCAHLSWMTPLZ-1

Signed-off-by: Dundi Raviteja <dundi@codeaurora.org>
Signed-off-by: Rakesh Pillai <pillair@codeaurora.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath10k/wmi-tlv.c
drivers/net/wireless/ath/ath10k/wmi-tlv.h
drivers/net/wireless/ath/ath10k/wmi.h

index c9aa90e1e56552e74f70bac07ce96356b6b10912..a26e6cb9fea874e9f3c21a4d5ef68a83fa628245 100644 (file)
@@ -3167,6 +3167,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
        init_completion(&ar->vdev_delete_done);
        init_completion(&ar->thermal.wmi_sync);
        init_completion(&ar->bss_survey_done);
+       init_completion(&ar->peer_delete_done);
 
        INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work);
 
index 872f13d0ba6458727da9565e9ef5a2bc9ae52ab5..4443f8732d2f910e118980cf0803e69ed5552d9a 100644 (file)
@@ -1208,6 +1208,7 @@ struct ath10k {
        struct ath10k_radar_found_info last_radar_info;
        struct work_struct radar_confirmation_work;
        struct ath10k_bus_params bus_param;
+       struct completion peer_delete_done;
 
        /* must be last */
        u8 drv_priv[0] __aligned(sizeof(void *));
index 572c03667110778492c525c0ae7d39b65617ed4a..24ac525df3189b19be16841a5feb31d6cf2afa9e 100644 (file)
@@ -693,6 +693,26 @@ ath10k_mac_get_any_chandef_iter(struct ieee80211_hw *hw,
        *def = &conf->def;
 }
 
+static void ath10k_wait_for_peer_delete_done(struct ath10k *ar, u32 vdev_id,
+                                            const u8 *addr)
+{
+       unsigned long time_left;
+       int ret;
+
+       if (test_bit(WMI_SERVICE_SYNC_DELETE_CMDS, ar->wmi.svc_map)) {
+               ret = ath10k_wait_for_peer_deleted(ar, vdev_id, addr);
+               if (ret) {
+                       ath10k_warn(ar, "failed wait for peer deleted");
+                       return;
+               }
+
+               time_left = wait_for_completion_timeout(&ar->peer_delete_done,
+                                                       5 * HZ);
+               if (!time_left)
+                       ath10k_warn(ar, "Timeout in receiving peer delete response\n");
+       }
+}
+
 static int ath10k_peer_create(struct ath10k *ar,
                              struct ieee80211_vif *vif,
                              struct ieee80211_sta *sta,
@@ -737,7 +757,7 @@ static int ath10k_peer_create(struct ath10k *ar,
                spin_unlock_bh(&ar->data_lock);
                ath10k_warn(ar, "failed to find peer %pM on vdev %i after creation\n",
                            addr, vdev_id);
-               ath10k_wmi_peer_delete(ar, vdev_id, addr);
+               ath10k_wait_for_peer_delete_done(ar, vdev_id, addr);
                return -ENOENT;
        }
 
@@ -819,6 +839,18 @@ static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr)
        if (ret)
                return ret;
 
+       if (test_bit(WMI_SERVICE_SYNC_DELETE_CMDS, ar->wmi.svc_map)) {
+               unsigned long time_left;
+
+               time_left = wait_for_completion_timeout
+                           (&ar->peer_delete_done, 5 * HZ);
+
+               if (!time_left) {
+                       ath10k_warn(ar, "Timeout in receiving peer delete response\n");
+                       return -ETIMEDOUT;
+               }
+       }
+
        ar->num_peers--;
 
        return 0;
@@ -5423,8 +5455,11 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
 
 err_peer_delete:
        if (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
-           arvif->vdev_type == WMI_VDEV_TYPE_IBSS)
+           arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
                ath10k_wmi_peer_delete(ar, arvif->vdev_id, vif->addr);
+               ath10k_wait_for_peer_delete_done(ar, arvif->vdev_id,
+                                                vif->addr);
+       }
 
 err_vdev_delete:
        ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
@@ -5490,6 +5525,8 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
                        ath10k_warn(ar, "failed to submit AP/IBSS self-peer removal on vdev %i: %d\n",
                                    arvif->vdev_id, ret);
 
+               ath10k_wait_for_peer_delete_done(ar, arvif->vdev_id,
+                                                vif->addr);
                kfree(arvif->u.ap.noa_data);
        }
 
index 13d66638dbb4ac7894bcc95ca8a3143fffd8802b..2985bb17decdebe6adf4da42546dc4c720c92791 100644 (file)
@@ -465,6 +465,24 @@ static void ath10k_wmi_event_tdls_peer(struct ath10k *ar, struct sk_buff *skb)
        kfree(tb);
 }
 
+static int ath10k_wmi_tlv_event_peer_delete_resp(struct ath10k *ar,
+                                                struct sk_buff *skb)
+{
+       struct wmi_peer_delete_resp_ev_arg *arg;
+       struct wmi_tlv *tlv_hdr;
+
+       tlv_hdr = (struct wmi_tlv *)skb->data;
+       arg = (struct wmi_peer_delete_resp_ev_arg *)tlv_hdr->value;
+
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "vdev id %d", arg->vdev_id);
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "peer mac addr %pM", &arg->peer_addr);
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer delete response\n");
+
+       complete(&ar->peer_delete_done);
+
+       return 0;
+}
+
 /***********/
 /* TLV ops */
 /***********/
@@ -617,6 +635,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
        case WMI_TLV_TDLS_PEER_EVENTID:
                ath10k_wmi_event_tdls_peer(ar, skb);
                break;
+       case WMI_TLV_PEER_DELETE_RESP_EVENTID:
+               ath10k_wmi_tlv_event_peer_delete_resp(ar, skb);
+               break;
        case WMI_TLV_MGMT_TX_COMPLETION_EVENTID:
                ath10k_wmi_event_mgmt_tx_compl(ar, skb);
                break;
index a4b1a1477e047ff8a1ff88643f313ddbcbe1df0d..d691f06e58f226e2e79b20ef18617e36af2a5c34 100644 (file)
@@ -308,6 +308,8 @@ enum wmi_tlv_event_id {
        WMI_TLV_PEER_TX_FAIL_CNT_THR_EVENTID,
        WMI_TLV_PEER_ESTIMATED_LINKSPEED_EVENTID,
        WMI_TLV_PEER_STATE_EVENTID,
+       WMI_TLV_PEER_ASSOC_CONF_EVENTID,
+       WMI_TLV_PEER_DELETE_RESP_EVENTID,
        WMI_TLV_MGMT_RX_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_MGMT),
        WMI_TLV_HOST_SWBA_EVENTID,
        WMI_TLV_TBTTOFFSET_UPDATE_EVENTID,
index 8b869c289039ad392dcc3f836cde81948ac78a12..cc87a0dff416ba54fa54bb7f25fcadd2e06a02dd 100644 (file)
@@ -6760,6 +6760,11 @@ struct wmi_tlv_mgmt_tx_bundle_compl_ev_arg {
        const __le32 *ack_rssi;
 };
 
+struct wmi_peer_delete_resp_ev_arg {
+       __le32 vdev_id;
+       struct wmi_mac_addr peer_addr;
+};
+
 struct wmi_mgmt_rx_ev_arg {
        __le32 channel;
        __le32 snr;