Commit 3cbbdfbe authored by Ritesh Singh's avatar Ritesh Singh Committed by Kalle Valo

ath11k: vdev delete synchronization with firmware

When the interface is added immediately after removing the
interface, vdev deletion in firmware might not have been
completed.

Hence, add vdev_delete_resp_event and wait_event_timeout
to synchronize with firmware.
Signed-off-by: default avatarRitesh Singh <ritesi@codeaurora.org>
Signed-off-by: default avatarMaharaja Kennadyrajan <mkenna@codeaurora.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/1605514143-17652-2-git-send-email-mkenna@codeaurora.org
parent 526740b4
......@@ -810,6 +810,7 @@ static void ath11k_core_restart(struct work_struct *work)
complete(&ar->peer_assoc_done);
complete(&ar->install_key_done);
complete(&ar->vdev_setup_done);
complete(&ar->vdev_delete_done);
complete(&ar->bss_survey_done);
complete(&ar->thermal.wmi_sync);
......
......@@ -430,6 +430,7 @@ struct ath11k_per_peer_tx_stats {
};
#define ATH11K_FLUSH_TIMEOUT (5 * HZ)
#define ATH11K_VDEV_DELETE_TIMEOUT_HZ (5 * HZ)
struct ath11k_vdev_stop_status {
bool stop_in_progress;
......@@ -512,6 +513,7 @@ struct ath11k {
int last_wmi_vdev_start_status;
struct ath11k_vdev_stop_status vdev_stop_status;
struct completion vdev_setup_done;
struct completion vdev_delete_done;
int num_peers;
int max_num_peers;
......
......@@ -4660,6 +4660,7 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw,
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;
......@@ -4668,10 +4669,6 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw,
ath11k_dbg(ab, ATH11K_DBG_MAC, "mac remove interface (vdev %d)\n",
arvif->vdev_id);
spin_lock_bh(&ar->data_lock);
list_del(&arvif->list);
spin_unlock_bh(&ar->data_lock);
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
ret = ath11k_peer_delete(ar, arvif->vdev_id, vif->addr);
if (ret)
......@@ -4679,16 +4676,33 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw,
arvif->vdev_id, ret);
}
reinit_completion(&ar->vdev_delete_done);
ret = ath11k_wmi_vdev_delete(ar, arvif->vdev_id);
if (ret)
if (ret) {
ath11k_warn(ab, "failed to delete WMI 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);
ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
ab->free_vdev_map |= 1LL << (arvif->vdev_id);
err_vdev_del:
spin_lock_bh(&ar->data_lock);
list_del(&arvif->list);
spin_unlock_bh(&ar->data_lock);
ath11k_peer_cleanup(ar, arvif->vdev_id);
......@@ -6454,6 +6468,7 @@ int ath11k_mac_allocate(struct ath11k_base *ab)
INIT_LIST_HEAD(&ar->ppdu_stats_info);
mutex_init(&ar->conf_mutex);
init_completion(&ar->vdev_setup_done);
init_completion(&ar->vdev_delete_done);
init_completion(&ar->peer_assoc_done);
init_completion(&ar->install_key_done);
init_completion(&ar->bss_survey_done);
......
......@@ -126,6 +126,8 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = {
.min_len = sizeof(struct wmi_fils_discovery_event) },
[WMI_TAG_OFFLOAD_PRB_RSP_TX_STATUS_EVENT] = {
.min_len = sizeof(struct wmi_probe_resp_tx_status_event) },
[WMI_TAG_VDEV_DELETE_RESP_EVENT] = {
.min_len = sizeof(struct wmi_vdev_delete_resp_event) },
};
#define PRIMAP(_hw_mode_) \
......@@ -4379,6 +4381,34 @@ static int ath11k_pull_peer_del_resp_ev(struct ath11k_base *ab, struct sk_buff *
return 0;
}
static int ath11k_pull_vdev_del_resp_ev(struct ath11k_base *ab,
struct sk_buff *skb,
u32 *vdev_id)
{
const void **tb;
const struct wmi_vdev_delete_resp_event *ev;
int ret;
tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
if (IS_ERR(tb)) {
ret = PTR_ERR(tb);
ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
return ret;
}
ev = tb[WMI_TAG_VDEV_DELETE_RESP_EVENT];
if (!ev) {
ath11k_warn(ab, "failed to fetch vdev delete resp ev");
kfree(tb);
return -EPROTO;
}
*vdev_id = ev->vdev_id;
kfree(tb);
return 0;
}
static int ath11k_pull_bcn_tx_status_ev(struct ath11k_base *ab, void *evt_buf,
u32 len, u32 *vdev_id,
u32 *tx_status)
......@@ -5711,6 +5741,34 @@ static void ath11k_peer_delete_resp_event(struct ath11k_base *ab, struct sk_buff
*/
}
static void ath11k_vdev_delete_resp_event(struct ath11k_base *ab,
struct sk_buff *skb)
{
struct ath11k *ar;
u32 vdev_id = 0;
if (ath11k_pull_vdev_del_resp_ev(ab, skb, &vdev_id) != 0) {
ath11k_warn(ab, "failed to extract vdev delete resp");
return;
}
rcu_read_lock();
ar = ath11k_mac_get_ar_by_vdev_id(ab, vdev_id);
if (!ar) {
ath11k_warn(ab, "invalid vdev id in vdev delete resp ev %d",
vdev_id);
rcu_read_unlock();
return;
}
complete(&ar->vdev_delete_done);
rcu_read_unlock();
ath11k_dbg(ab, ATH11K_DBG_WMI, "vdev delete resp for vdev id %d\n",
vdev_id);
}
static inline const char *ath11k_wmi_vdev_resp_print(u32 vdev_resp_status)
{
switch (vdev_resp_status) {
......@@ -6722,7 +6780,6 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)
break;
/* add Unsupported events here */
case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID:
case WMI_VDEV_DELETE_RESP_EVENTID:
case WMI_PEER_OPER_MODE_CHANGE_EVENTID:
case WMI_TWT_ENABLE_EVENTID:
case WMI_TWT_DISABLE_EVENTID:
......@@ -6733,6 +6790,9 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)
case WMI_PDEV_DFS_RADAR_DETECTION_EVENTID:
ath11k_wmi_pdev_dfs_radar_detected_event(ab, skb);
break;
case WMI_VDEV_DELETE_RESP_EVENTID:
ath11k_vdev_delete_resp_event(ab, skb);
break;
/* TODO: Add remaining events */
default:
ath11k_dbg(ab, ATH11K_DBG_WMI, "Unknown eventid: 0x%x\n", id);
......
......@@ -4018,6 +4018,10 @@ struct wmi_regulatory_rule_struct {
u32 flag_info;
};
struct wmi_vdev_delete_resp_event {
u32 vdev_id;
} __packed;
struct wmi_peer_delete_resp_event {
u32 vdev_id;
struct wmi_mac_addr peer_macaddr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment