WCN7850/QCC2072 hardware/firmware report only the logical link id to identify the link on which a packet is received. The host, however, needs the IEEE80211 link id. So a mapping between them needs to be established. Add support for the HTT_T2H_MSG_TYPE_PEER_EXTENDED event, which reports the logical link id for a given link peer. Find the link peer and populate ath12k_dp_peer::link_id_map, mapping the logical link id to the IEEE80211 link id. This map is later used in the data path to derive the IEEE80211 link id. The firmware sends this event after each peer assoc, but only when it advertises WMI_TLV_SERVICE_PER_LINK_STATS_SUPPORT. On such devices, block in ath12k_mac_peer_assoc() until the event arrives. The event arrives before the MLO_RX_PEER_MAP event, so wait for it first. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c7-00108-QCAHMTSWPL_V1.0_V2.0_SILICONZ_UPSTREAM-3 Tested-on: QCC2072 hw1.0 PCI WLAN.COL.1.0.c2-00068-QCACOLSWPL_V1_TO_SILICONZ-1 Signed-off-by: Baochen Qiang --- drivers/net/wireless/ath/ath12k/core.c | 1 + drivers/net/wireless/ath/ath12k/core.h | 1 + drivers/net/wireless/ath/ath12k/dp_htt.c | 17 ++++++++ drivers/net/wireless/ath/ath12k/dp_htt.h | 15 +++++++ drivers/net/wireless/ath/ath12k/dp_peer.c | 66 ++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath12k/dp_peer.h | 3 ++ drivers/net/wireless/ath/ath12k/mac.c | 13 ++++++ drivers/net/wireless/ath/ath12k/wmi.h | 1 + 8 files changed, 115 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 353fb9c5a69d..1bd26e82a6ec 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1562,6 +1562,7 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) complete_all(&ar->scan.completed); complete(&ar->scan.on_channel); complete(&ar->peer_assoc_done); + complete(&ar->peer_ext_event_done); ath12k_peer_delete_wait_flush(ar); complete(&ar->install_key_done); complete(&ar->vdev_setup_done); diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index f1929997a35a..478b51ea1f7c 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -682,6 +682,7 @@ struct ath12k { u8 radio_idx; struct completion peer_assoc_done; + struct completion peer_ext_event_done; struct list_head peer_delete_waits; int install_key_status; diff --git a/drivers/net/wireless/ath/ath12k/dp_htt.c b/drivers/net/wireless/ath/ath12k/dp_htt.c index 72069640bd38..25c1f915defd 100644 --- a/drivers/net/wireless/ath/ath12k/dp_htt.c +++ b/drivers/net/wireless/ath/ath12k/dp_htt.c @@ -627,6 +627,7 @@ void ath12k_dp_htt_htc_t2h_msg_handler(struct ath12k_base *ab, struct ath12k_dp *dp = ath12k_ab_to_dp(ab); struct htt_resp_msg *resp = (struct htt_resp_msg *)skb->data; enum htt_t2h_msg_type type; + u8 logical_link_id, valid; u16 peer_id; u8 vdev_id; u8 mac_addr[ETH_ALEN]; @@ -708,6 +709,22 @@ void ath12k_dp_htt_htc_t2h_msg_handler(struct ath12k_base *ab, case HTT_T2H_MSG_TYPE_MLO_RX_PEER_MAP: ath12k_dp_htt_mlo_peer_map_handler(ab, skb); break; + case HTT_T2H_MSG_TYPE_PEER_EXTENDED: + peer_id = le32_get_bits(resp->peer_extended_ev.info, + HTT_T2H_PEER_EXT_INFO_PEER_ID); + vdev_id = le32_get_bits(resp->peer_extended_ev.info, + HTT_T2H_PEER_EXT_INFO_VDEV_ID); + peer_mac_h16 = le32_get_bits(resp->peer_extended_ev.info1, + HTT_T2H_PEER_EXT_INFO1_MAC_ADDR_H16); + ath12k_dp_get_mac_addr(le32_to_cpu(resp->peer_extended_ev.mac_addr_l32), + peer_mac_h16, mac_addr); + logical_link_id = le32_get_bits(resp->peer_extended_ev.info1, + HTT_T2H_PEER_EXT_INFO1_LOGICAL_LINK_ID); + valid = le32_get_bits(resp->peer_extended_ev.info1, + HTT_T2H_PEER_EXT_INFO1_LOGICAL_LINK_ID_VALID); + ath12k_dp_link_peer_extended_event(ab, vdev_id, peer_id, mac_addr, + logical_link_id, valid); + break; default: ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "dp_htt event %d not handled\n", type); diff --git a/drivers/net/wireless/ath/ath12k/dp_htt.h b/drivers/net/wireless/ath/ath12k/dp_htt.h index 2db7fb27c036..1d192bde0c29 100644 --- a/drivers/net/wireless/ath/ath12k/dp_htt.h +++ b/drivers/net/wireless/ath/ath12k/dp_htt.h @@ -933,6 +933,7 @@ enum htt_t2h_msg_type { HTT_T2H_MSG_TYPE_MLO_RX_PEER_MAP = 0x29, HTT_T2H_MSG_TYPE_PEER_MAP3 = 0x2b, HTT_T2H_MSG_TYPE_VDEV_TXRX_STATS_PERIODIC_IND = 0x2c, + HTT_T2H_MSG_TYPE_PEER_EXTENDED = 0x39, }; #define HTT_TARGET_VERSION_MAJOR 3 @@ -985,12 +986,26 @@ struct htt_t2h_mlo_peer_map_event { __le32 reserved[5]; } __packed; +#define HTT_T2H_PEER_EXT_INFO_PEER_ID GENMASK(23, 8) +#define HTT_T2H_PEER_EXT_INFO_VDEV_ID GENMASK(31, 24) +#define HTT_T2H_PEER_EXT_INFO1_MAC_ADDR_H16 GENMASK(15, 0) +#define HTT_T2H_PEER_EXT_INFO1_LOGICAL_LINK_ID GENMASK(18, 16) +#define HTT_T2H_PEER_EXT_INFO1_LOGICAL_LINK_ID_VALID BIT(19) + +struct htt_t2h_peer_extended_event { + __le32 info; + __le32 mac_addr_l32; + __le32 info1; + __le32 info2; +} __packed; + struct htt_resp_msg { union { struct htt_t2h_version_conf_msg version_msg; struct htt_t2h_peer_map_event peer_map_ev; struct htt_t2h_peer_unmap_event peer_unmap_ev; struct htt_t2h_mlo_peer_map_event mlo_peer_map_ev; + struct htt_t2h_peer_extended_event peer_extended_ev; }; } __packed; diff --git a/drivers/net/wireless/ath/ath12k/dp_peer.c b/drivers/net/wireless/ath/ath12k/dp_peer.c index f73dad49e42b..1e84b9b817f3 100644 --- a/drivers/net/wireless/ath/ath12k/dp_peer.c +++ b/drivers/net/wireless/ath/ath12k/dp_peer.c @@ -8,6 +8,7 @@ #include "dp_peer.h" #include "debug.h" #include "debugfs.h" +#include "mac.h" void ath12k_dp_link_peer_free(struct ath12k_dp_link_peer *peer) { @@ -195,6 +196,60 @@ void ath12k_dp_link_peer_map_event(struct ath12k_base *ab, u8 vdev_id, u16 peer_ spin_unlock_bh(&dp->dp_lock); } +void ath12k_dp_link_peer_extended_event(struct ath12k_base *ab, u8 vdev_id, + u16 peer_id, u8 *mac_addr, + u8 logical_link_id, u8 valid) +{ + struct ath12k_dp *dp = ath12k_ab_to_dp(ab); + struct ath12k_dp_link_peer *peer; + struct ath12k_dp_peer *dp_peer; + struct ath12k *ar; + + if (!valid || logical_link_id >= ATH12K_GROUP_MAX_RADIO) { + ath12k_warn(ab, "invalid logical link id %u valid %u\n", + logical_link_id, valid); + goto exit; + } + + spin_lock_bh(&dp->dp_lock); + + peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, mac_addr); + if (!peer) { + ath12k_warn(ab, "failed to find link peer with vdev id %u addr %pM\n", + vdev_id, mac_addr); + goto unlock; + } + + if (peer->peer_id != peer_id) { + ath12k_warn(ab, "link peer id mismatch, expected %u got %u\n", + peer->peer_id, peer_id); + goto unlock; + } + + dp_peer = peer->dp_peer; + + peer->drv_link_id = logical_link_id; + dp_peer->link_id_map[peer->drv_link_id] = peer->link_id; + + ath12k_dbg(ab, ATH12K_DBG_DP_HTT, + "htt peer extended vdev %d peer %pM id %d logical_link_id %u link_id %u\n", + vdev_id, mac_addr, peer_id, logical_link_id, peer->link_id); + +unlock: + spin_unlock_bh(&dp->dp_lock); + +exit: + rcu_read_lock(); + + ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id); + if (ar) + complete(&ar->peer_ext_event_done); + else + ath12k_warn(ab, "failed to get ar with vdev id %u\n", vdev_id); + + rcu_read_unlock(); +} + static int ath12k_dp_link_peer_rhash_addr_tbl_init(struct ath12k_dp *dp) { struct ath12k_base *ab = dp->ab; @@ -544,9 +599,16 @@ int ath12k_dp_link_peer_assign(struct ath12k_dp *dp, struct ath12k_dp_hw *dp_hw, dp_peer->peer_id = peer->peer_id; peer->dp_peer = dp_peer; - peer->drv_link_id = hw_link_id; - dp_peer->link_id_map[peer->drv_link_id] = link_id; + /* + * Only devices that use hw_link_id can map it to the IEEE80211 + * link id here. Devices that do not support hw_link_id fill + * link_id_map later from the PEER_EXTENDED HTT event. + */ + if (dp->hw_params->support_hw_link_id) { + peer->drv_link_id = hw_link_id; + dp_peer->link_id_map[peer->drv_link_id] = link_id; + } peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id); diff --git a/drivers/net/wireless/ath/ath12k/dp_peer.h b/drivers/net/wireless/ath/ath12k/dp_peer.h index d2752b35ba0f..ea36947d1707 100644 --- a/drivers/net/wireless/ath/ath12k/dp_peer.h +++ b/drivers/net/wireless/ath/ath12k/dp_peer.h @@ -122,6 +122,9 @@ struct ath12k_dp_link_peer { void ath12k_dp_link_peer_unmap_event(struct ath12k_base *ab, u16 peer_id); void ath12k_dp_link_peer_map_event(struct ath12k_base *ab, u8 vdev_id, u16 peer_id, u8 *mac_addr, u16 ast_hash, u16 hw_peer_id); +void ath12k_dp_link_peer_extended_event(struct ath12k_base *ab, u8 vdev_id, + u16 peer_id, u8 *mac_addr, + u8 logical_link_id, u8 valid); struct ath12k_dp_peer { struct list_head list; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 87c52ddfe279..1e539388c003 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -3864,6 +3864,7 @@ static int ath12k_mac_peer_assoc(struct ath12k *ar, int ret; reinit_completion(&ar->peer_assoc_done); + reinit_completion(&ar->peer_ext_event_done); reinit_completion(&ah->peer_ml_id_done); ret = ath12k_wmi_send_peer_assoc_cmd(ar, peer_arg); @@ -3879,6 +3880,17 @@ static int ath12k_mac_peer_assoc(struct ath12k *ar, return -ETIMEDOUT; } + if (!ar->ab->hw_params->support_hw_link_id && + test_bit(WMI_TLV_SERVICE_PER_LINK_STATS_SUPPORT, + ar->ab->wmi_ab.svc_map) && + peer_arg->ml.enabled && + peer_arg->is_assoc && + !wait_for_completion_timeout(&ar->peer_ext_event_done, 1 * HZ)) { + ath12k_warn(ar->ab, "failed to get peer extended event for %pM vdev %u\n", + peer_arg->peer_mac, peer_arg->vdev_id); + return -ETIMEDOUT; + } + /* * For devices where the firmware allocates the MLD peer ID, the host * learns the real ID only from the MLO_RX_PEER_MAP HTT event, which is @@ -15203,6 +15215,7 @@ static void ath12k_mac_setup(struct ath12k *ar) init_completion(&ar->vdev_setup_done); init_completion(&ar->vdev_delete_done); init_completion(&ar->peer_assoc_done); + init_completion(&ar->peer_ext_event_done); init_completion(&ar->install_key_done); init_completion(&ar->bss_survey_done); init_completion(&ar->scan.started); diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 5d0afbf0bd0c..94c5def03137 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2278,6 +2278,7 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_WMSK_COMPACTION_RX_TLVS = 361, WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT = 365, + WMI_TLV_SERVICE_PER_LINK_STATS_SUPPORT = 380, WMI_TLV_SERVICE_THERM_THROT_POUT_REDUCTION = 410, WMI_TLV_SERVICE_WDS_NULL_FRAME_SUPPORT = 421, WMI_TLV_SERVICE_IS_TARGET_IPA = 425, -- 2.25.1