wlan-ap-Telecominfraproject/feeds/wifi-ax/mac80211/patches/qca/025-ath11k-add-vdev-delete-synchro-with-firmware.patch
John Crispin 04f6078da6 ipq807x: update AX support
Signed-off-by: John Crispin <john@phrozen.org>
2020-10-04 14:28:57 +02:00

292 lines
8.9 KiB
Diff

--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -689,6 +689,7 @@ static void ath11k_core_restart(struct w
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);
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -446,9 +446,11 @@ 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 {
+struct ath11k_vdev_stop_delete_status {
bool stop_in_progress;
+ bool delete_in_progress;
u32 vdev_id;
};
@@ -541,8 +543,9 @@ struct ath11k {
struct completion install_key_done;
int last_wmi_vdev_start_status;
- struct ath11k_vdev_stop_status vdev_stop_status;
+ struct ath11k_vdev_stop_delete_status vdev_stop_delete_status;
struct completion vdev_setup_done;
+ struct completion vdev_delete_done;
int num_peers;
int max_num_peers;
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -536,8 +536,8 @@ struct ath11k *ath11k_mac_get_ar_by_pdev
return NULL;
}
-struct ath11k *ath11k_mac_get_ar_vdev_stop_status(struct ath11k_base *ab,
- u32 vdev_id)
+struct ath11k *ath11k_mac_get_ar_vdev_stop_delete_status(struct ath11k_base *ab,
+ u32 vdev_id)
{
int i;
struct ath11k_pdev *pdev;
@@ -549,9 +549,15 @@ struct ath11k *ath11k_mac_get_ar_vdev_st
ar = pdev->ar;
spin_lock_bh(&ar->data_lock);
- if (ar->vdev_stop_status.stop_in_progress &&
- ar->vdev_stop_status.vdev_id == vdev_id) {
- ar->vdev_stop_status.stop_in_progress = false;
+ if (ar->vdev_stop_delete_status.stop_in_progress &&
+ ar->vdev_stop_delete_status.vdev_id == vdev_id) {
+ ar->vdev_stop_delete_status.stop_in_progress = false;
+ spin_unlock_bh(&ar->data_lock);
+ return ar;
+ }
+ if (ar->vdev_stop_delete_status.delete_in_progress &&
+ ar->vdev_stop_delete_status.vdev_id == vdev_id) {
+ ar->vdev_stop_delete_status.delete_in_progress = false;
spin_unlock_bh(&ar->data_lock);
return ar;
}
@@ -4619,6 +4625,7 @@ 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;
@@ -4627,10 +4634,6 @@ static void ath11k_mac_op_remove_interfa
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)
@@ -4638,16 +4641,31 @@ 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);
- if (ret)
+ if (ret) {
ath11k_warn(ab, "failed to delete WMI vdev %d: %d\n",
arvif->vdev_id, ret);
+ goto err_vdev_del;
+ }
- ar->num_created_vdevs--;
ath11k_dbg(ab, ATH11K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n",
vif->addr, arvif->vdev_id);
+ 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;
+ }
ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
ab->free_vdev_map |= 1LL << (arvif->vdev_id);
+ ar->num_created_vdevs--;
+
+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);
@@ -4845,6 +4863,7 @@ ath11k_mac_vdev_start_restart(struct ath
lockdep_assert_held(&ar->conf_mutex);
reinit_completion(&ar->vdev_setup_done);
+ reinit_completion(&ar->vdev_delete_done);
arg.vdev_id = arvif->vdev_id;
arg.dtim_period = arvif->dtim_period;
@@ -4947,11 +4966,12 @@ static int ath11k_mac_vdev_stop(struct a
lockdep_assert_held(&ar->conf_mutex);
reinit_completion(&ar->vdev_setup_done);
+ reinit_completion(&ar->vdev_delete_done);
spin_lock_bh(&ar->data_lock);
- ar->vdev_stop_status.stop_in_progress = true;
- ar->vdev_stop_status.vdev_id = arvif->vdev_id;
+ ar->vdev_stop_delete_status.stop_in_progress = true;
+ ar->vdev_stop_delete_status.vdev_id = arvif->vdev_id;
spin_unlock_bh(&ar->data_lock);
@@ -4984,7 +5004,7 @@ static int ath11k_mac_vdev_stop(struct a
return 0;
err:
spin_lock_bh(&ar->data_lock);
- ar->vdev_stop_status.stop_in_progress = false;
+ ar->vdev_stop_delete_status.stop_in_progress = false;
spin_unlock_bh(&ar->data_lock);
return ret;
@@ -6412,6 +6432,7 @@ int ath11k_mac_allocate(struct ath11k_ba
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);
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -123,6 +123,8 @@ static const struct wmi_tlv_policy wmi_t
= { .min_len = sizeof(struct wmi_stats_event) },
[WMI_TAG_PDEV_CTL_FAILSAFE_CHECK_EVENT]
= { .min_len = sizeof(struct wmi_pdev_ctl_failsafe_chk_event) },
+ [WMI_TAG_VDEV_DELETE_RESP_EVENT]
+ = { .min_len = sizeof(struct wmi_vdev_delete_resp_event) },
};
#define PRIMAP(_hw_mode_) \
@@ -4363,6 +4365,33 @@ static int ath11k_pull_peer_del_resp_ev(
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)
@@ -5686,6 +5715,32 @@ static void ath11k_peer_delete_resp_even
*/
}
+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_vdev_stop_delete_status(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", vdev_id);
+}
+
static inline const char *ath11k_wmi_vdev_resp_print(u32 vdev_resp_status)
{
switch (vdev_resp_status) {
@@ -5762,7 +5817,7 @@ static void ath11k_vdev_stopped_event(st
}
rcu_read_lock();
- ar = ath11k_mac_get_ar_vdev_stop_status(ab, vdev_id);
+ ar = ath11k_mac_get_ar_vdev_stop_delete_status(ab, vdev_id);
if (!ar) {
ath11k_warn(ab, "invalid vdev id in vdev stopped ev %d",
vdev_id);
@@ -6632,7 +6687,6 @@ static void ath11k_wmi_tlv_op_rx(struct
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:
@@ -6643,6 +6697,9 @@ static void ath11k_wmi_tlv_op_rx(struct
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_warn(ab, "Unknown eventid: 0x%x\n", id);
--- a/drivers/net/wireless/ath/ath11k/wmi.h
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
@@ -4024,6 +4024,10 @@ struct wmi_peer_delete_resp_event {
struct wmi_mac_addr peer_macaddr;
} __packed;
+struct wmi_vdev_delete_resp_event {
+ u32 vdev_id;
+} __packed;
+
struct wmi_bcn_tx_status_event {
u32 vdev_id;
u32 tx_status;
--- a/drivers/net/wireless/ath/ath11k/mac.h
+++ b/drivers/net/wireless/ath/ath11k/mac.h
@@ -141,7 +141,8 @@ struct ath11k *ath11k_mac_get_ar_by_vdev
struct ath11k *ath11k_mac_get_ar_by_pdev_id(struct ath11k_base *ab, u32 pdev_id);
struct ath11k *ath11k_mac_get_ar_vdev_stop_status(struct ath11k_base *ab,
u32 vdev_id);
-
+struct ath11k *ath11k_mac_get_ar_vdev_stop_delete_status(struct ath11k_base *ab,
+ u32 vdev_id);
void ath11k_mac_drain_tx(struct ath11k *ar);
void ath11k_mac_peer_cleanup_all(struct ath11k *ar);
int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx);