wlan-ap-Telecominfraproject/feeds/ipq807x/mac80211/patches/025-ath11k-add-vdev-delete-synchro-with-firmware.patch
John Crispin 3affbc1cad QualComm/AX: add Hawkeye and Cypress support
This series is based on
* 2020-07-10 ipq6018-ilq-11-0_qca_oem-034672b0676c37b1f4519e5720e18e95fe6236ef

Add support for
* qsdk kernel/v4.4
* qsdk ethernet subsystem
* v5.7 ath11k backport + QualComm staging patches (wlan_ap_1.0)
* ath11k-firmware
* hostapd/iw/...

Feature support
* full boot, system detection
* sysupgrade to nand
* HE support via latest hostapd
* driver support for usb, crypto, hwmon, cpufreq, ...

Missing
* NSS/HW flow offloading - FW blob is not redistributable

Using the qsdk v4.4 is an intermediate solution while the vanilla is being
tested. Vanilla kernel is almost on feature par. Work has already started
to upstream the ethernet and switch drivers. Once complete the target will
be fully upstream.

Signed-off-by: John Crispin <john@phrozen.org>
2020-07-23 18:54:03 +02:00

292 lines
8.9 KiB
Diff

--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -688,6 +688,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
@@ -430,9 +430,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;
};
@@ -524,8 +526,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
@@ -448,8 +448,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;
@@ -461,9 +461,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;
}
@@ -4416,6 +4422,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;
@@ -4424,10 +4431,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)
@@ -4435,14 +4438,29 @@ 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--;
- ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
- ab->free_vdev_map |= 1LL << (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");
+ } else {
+ 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);
@@ -4640,6 +4658,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;
@@ -4740,11 +4759,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);
@@ -4775,7 +4795,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;
@@ -6172,6 +6192,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_) \
@@ -4207,6 +4209,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)
@@ -5551,6 +5580,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) {
@@ -5627,7 +5682,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);
@@ -6521,7 +6576,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:
@@ -6532,6 +6586,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
@@ -3919,6 +3919,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);