wlan-ap-Telecominfraproject/feeds/ipq807x/mac80211/patches/026-ath11k-add-peer-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

277 lines
8.4 KiB
Diff

--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -521,6 +521,7 @@ struct ath11k {
u8 lmac_id;
struct completion peer_assoc_done;
+ struct completion peer_delete_done;
int install_key_status;
struct completion install_key_done;
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -364,7 +364,7 @@ static u8 ath11k_mac_bitrate_to_rate(int
(ath11k_mac_bitrate_is_cck(bitrate) ? BIT(7) : 0);
}
-static void ath11k_get_arvif_iter(void *data, u8 *mac,
+static void ath11k_mac_get_arvif_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
struct ath11k_vif_iter *arvif_iter = data;
@@ -385,7 +385,7 @@ struct ath11k_vif *ath11k_mac_get_arvif(
flags = IEEE80211_IFACE_ITER_RESUME_ALL;
ieee80211_iterate_active_interfaces_atomic(ar->hw,
flags,
- ath11k_get_arvif_iter,
+ ath11k_mac_get_arvif_iter,
&arvif_iter);
if (!arvif_iter.arvif) {
ath11k_warn(ar->ab, "No VIF found for vdev %d\n", vdev_id);
@@ -479,6 +479,36 @@ struct ath11k *ath11k_mac_get_ar_vdev_st
return NULL;
}
+struct ath11k *ath11k_mac_get_ar_peer_delete_status(struct ath11k_base *ab, u8 *peer_addr,
+ u32 vdev_id)
+{
+ int i;
+ struct ath11k_pdev *pdev;
+ struct ath11k *ar;
+ struct ath11k_vif *arvif;
+
+ for (i = 0; i < ab->num_radios; i++) {
+ pdev = rcu_dereference(ab->pdevs_active[i]);
+ if (pdev && pdev->ar) {
+ ar = pdev->ar;
+
+ spin_lock_bh(&ar->data_lock);
+ if (ether_addr_equal(ar->mac_addr, peer_addr)) {
+ spin_unlock_bh(&ar->data_lock);
+ return ar;
+ } else {
+ arvif = ath11k_mac_get_arvif(pdev->ar, vdev_id);
+ if (arvif) {
+ spin_unlock_bh(&ar->data_lock);
+ return arvif->ar;
+ }
+ }
+ spin_unlock_bh(&ar->data_lock);
+ }
+ }
+ return NULL;
+}
+
static void ath11k_pdev_caps_update(struct ath11k *ar)
{
struct ath11k_base *ab = ar->ab;
@@ -673,6 +703,28 @@ static int ath11k_monitor_vdev_up(struct
return 0;
}
+int ath11k_wait_for_peer_delete_done(struct ath11k *ar, u32 vdev_id,
+ const u8 *addr)
+{
+ int ret;
+ unsigned long time_left;
+
+ ret = ath11k_wait_for_peer_deleted(ar, vdev_id, addr);
+ if(ret) {
+ ath11k_warn(ar->ab, "failed wait for peer deleted");
+ return ret;
+ }
+
+ time_left = wait_for_completion_timeout(&ar->peer_delete_done,
+ 3 * HZ);
+ if(time_left == 0) {
+ ath11k_warn(ar->ab, "Timeout in receiving peer delete response\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
static int ath11k_mac_op_config(struct ieee80211_hw *hw, u32 changed)
{
struct ath11k *ar = hw->priv;
@@ -4386,8 +4438,25 @@ static int ath11k_mac_op_add_interface(s
err_peer_del:
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
+ reinit_completion(&ar->peer_delete_done);
+
+ ret = ath11k_wmi_send_peer_delete_cmd(ar, vif->addr,
+ arvif->vdev_id);
+ if (ret) {
+ ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n",
+ arvif->vdev_id, vif->addr);
+ return ret;
+ }
+ ret = ath11k_wait_for_peer_delete_done(ar, arvif->vdev_id,
+ vif->addr);
+ if (ret)
+ return ret;
+
+ ret = ath11k_wait_for_peer_delete_done(ar, arvif->vdev_id, vif->addr);
+ if (ret)
+ return ret;
+
ar->num_peers--;
- ath11k_wmi_send_peer_delete_cmd(ar, vif->addr, arvif->vdev_id);
}
err_vdev_del:
@@ -6194,6 +6263,7 @@ int ath11k_mac_allocate(struct ath11k_ba
init_completion(&ar->vdev_setup_done);
init_completion(&ar->vdev_delete_done);
init_completion(&ar->peer_assoc_done);
+ init_completion(&ar->peer_delete_done);
init_completion(&ar->install_key_done);
init_completion(&ar->bss_survey_done);
init_completion(&ar->scan.started);
--- a/drivers/net/wireless/ath/ath11k/peer.c
+++ b/drivers/net/wireless/ath/ath11k/peer.c
@@ -153,17 +153,41 @@ void ath11k_peer_cleanup(struct ath11k *
spin_unlock_bh(&ab->base_lock);
}
-static int ath11k_wait_for_peer_deleted(struct ath11k *ar, int vdev_id, const u8 *addr)
+int ath11k_wait_for_peer_deleted(struct ath11k *ar, int vdev_id, const u8 *addr)
{
return ath11k_wait_for_peer_common(ar->ab, vdev_id, addr, false);
}
+int ath11k_wait_for_peer_delete_done(struct ath11k *ar, u32 vdev_id,
+ const u8 *addr)
+{
+ int ret;
+ unsigned long time_left;
+
+ ret = ath11k_wait_for_peer_deleted(ar, vdev_id, addr);
+ if (ret) {
+ ath11k_warn(ar->ab, "failed wait for peer deleted");
+ return ret;
+ }
+
+ time_left = wait_for_completion_timeout(&ar->peer_delete_done,
+ 3 * HZ);
+ if (time_left == 0) {
+ ath11k_warn(ar->ab, "Timeout in receiving peer delete response\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr)
{
int ret;
lockdep_assert_held(&ar->conf_mutex);
+ reinit_completion(&ar->peer_delete_done);
+
ret = ath11k_wmi_send_peer_delete_cmd(ar, addr, vdev_id);
if (ret) {
ath11k_warn(ar->ab,
@@ -172,7 +196,7 @@ int ath11k_peer_delete(struct ath11k *ar
return ret;
}
- ret = ath11k_wait_for_peer_deleted(ar, vdev_id, addr);
+ ret = ath11k_wait_for_peer_delete_done(ar, vdev_id, addr);
if (ret)
return ret;
@@ -220,8 +244,22 @@ int ath11k_peer_create(struct ath11k *ar
spin_unlock_bh(&ar->ab->base_lock);
ath11k_warn(ar->ab, "failed to find peer %pM on vdev %i after creation\n",
param->peer_addr, param->vdev_id);
- ath11k_wmi_send_peer_delete_cmd(ar, param->peer_addr,
- param->vdev_id);
+
+ reinit_completion(&ar->peer_delete_done);
+
+ ret = ath11k_wmi_send_peer_delete_cmd(ar, param->peer_addr,
+ param->vdev_id);
+ if(ret) {
+ ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n",
+ param->vdev_id, param->peer_addr);
+ return ret;
+ }
+
+ ret = ath11k_wait_for_peer_delete_done(ar, param->vdev_id,
+ param->peer_addr);
+ if(ret)
+ return ret;
+
return -ENOENT;
}
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -5569,15 +5569,29 @@ static int ath11k_ready_event(struct ath
static void ath11k_peer_delete_resp_event(struct ath11k_base *ab, struct sk_buff *skb)
{
struct wmi_peer_delete_resp_event peer_del_resp;
+ struct ath11k *ar;
if (ath11k_pull_peer_del_resp_ev(ab, skb, &peer_del_resp) != 0) {
ath11k_warn(ab, "failed to extract peer delete resp");
return;
}
- /* TODO: Do we need to validate whether ath11k_peer_find() return NULL
- * Why this is needed when there is HTT event for peer delete
- */
+ rcu_read_lock();
+ ar = ath11k_mac_get_ar_by_vdev_id(ab, peer_del_resp.vdev_id);
+ if (!ar) {
+ ath11k_warn(ab, "invalid vdev id in peer delete resp ev %d",
+ peer_del_resp.vdev_id);
+ rcu_read_unlock();
+ return;
+ }
+
+ complete(&ar->peer_delete_done);
+
+ rcu_read_unlock();
+
+ ath11k_dbg(ab, ATH11K_DBG_WMI, "peer delete resp for vdev id %d addr %pM\n",
+ peer_del_resp.vdev_id, peer_del_resp.peer_macaddr.addr);
+
}
static void ath11k_vdev_delete_resp_event(struct ath11k_base *ab, struct sk_buff *skb)
--- a/drivers/net/wireless/ath/ath11k/mac.h
+++ b/drivers/net/wireless/ath/ath11k/mac.h
@@ -147,6 +147,8 @@ void ath11k_mac_drain_tx(struct ath11k *
void ath11k_mac_peer_cleanup_all(struct ath11k *ar);
int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx);
u8 ath11k_mac_bw_to_mac80211_bw(u8 bw);
+struct ath11k *ath11k_mac_get_ar_peer_delete_status(struct ath11k_base *ab, u8 *peer_addr,
+ u32 vdev_id);
enum ath11k_supported_bw ath11k_mac_mac80211_bw_to_ath11k_bw(enum rate_info_bw bw);
enum hal_encrypt_type ath11k_dp_tx_get_encrypt_type(u32 cipher);
#endif
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -686,6 +686,7 @@ static void ath11k_core_restart(struct w
complete(&ar->scan.started);
complete(&ar->scan.completed);
complete(&ar->peer_assoc_done);
+ complete(&ar->peer_delete_done);
complete(&ar->install_key_done);
complete(&ar->vdev_setup_done);
complete(&ar->vdev_delete_done);
--- a/drivers/net/wireless/ath/ath11k/peer.h
+++ b/drivers/net/wireless/ath/ath11k/peer.h
@@ -40,5 +40,7 @@ void ath11k_peer_cleanup(struct ath11k *
int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr);
int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
struct ieee80211_sta *sta, struct peer_create_params *param);
+int ath11k_wait_for_peer_deleted(struct ath11k *ar, int vdev_id, const u8 *addr);
+int ath11k_wait_for_peer_delete_done(struct ath11k *ar, u32 vdev_id, const u8 *addr);
#endif /* _PEER_H_ */