mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-18 09:51:26 +00:00
334 lines
9.9 KiB
Diff
334 lines
9.9 KiB
Diff
--- a/drivers/net/wireless/ath/ath11k/core.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/core.c
|
|
@@ -712,6 +712,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
|
|
@@ -439,9 +439,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;
|
|
};
|
|
|
|
@@ -534,8 +536,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
|
|
@@ -547,8 +547,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;
|
|
@@ -560,9 +560,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;
|
|
}
|
|
@@ -4375,6 +4381,37 @@ static int ath11k_set_he_mu_sounding_mod
|
|
return ret;
|
|
}
|
|
|
|
+static int ath11k_mac_vdev_delete(struct ath11k_vif *arvif)
|
|
+{
|
|
+ struct ath11k *ar = arvif->ar;
|
|
+ unsigned long time_left;
|
|
+ int ret;
|
|
+
|
|
+ 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\n", ret);
|
|
+ return ret;
|
|
+ } else {
|
|
+ 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;
|
|
+ } else {
|
|
+ ar->num_created_vdevs--;
|
|
+ ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
|
|
+ ar->ab->free_vdev_map |= 1LL << arvif->vdev_id;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
|
|
struct ieee80211_vif *vif)
|
|
{
|
|
@@ -4387,7 +4424,7 @@ static int ath11k_mac_op_add_interface(s
|
|
int hw_encap = 0;
|
|
u16 nss;
|
|
int i;
|
|
- int ret;
|
|
+ int ret, free_err;
|
|
int bit;
|
|
|
|
vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
|
|
@@ -4606,10 +4643,8 @@ 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(arvif);
|
|
+
|
|
spin_lock_bh(&ar->data_lock);
|
|
list_del(&arvif->list);
|
|
spin_unlock_bh(&ar->data_lock);
|
|
@@ -4645,10 +4680,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)
|
|
@@ -4656,16 +4687,17 @@ static void ath11k_mac_op_remove_interfa
|
|
arvif->vdev_id, ret);
|
|
}
|
|
|
|
- ret = ath11k_wmi_vdev_delete(ar, arvif->vdev_id);
|
|
+ ret = ath11k_mac_vdev_delete(arvif);
|
|
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);
|
|
- 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);
|
|
|
|
@@ -4863,6 +4895,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;
|
|
@@ -4965,11 +4998,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);
|
|
|
|
@@ -5002,7 +5036,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;
|
|
@@ -6498,6 +6532,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_) \
|
|
@@ -4396,6 +4398,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)
|
|
@@ -5728,6 +5757,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) {
|
|
@@ -5804,7 +5859,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);
|
|
@@ -6674,7 +6729,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:
|
|
@@ -6685,6 +6739,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
|
|
@@ -4025,6 +4025,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);
|