From 02f41c8aa643b0d329ee9fa3f3341919bf86b759 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Fri, 6 Dec 2024 13:45:52 +0800 Subject: [PATCH 01/60] wifi: ath12k: fix leaking michael_mic for non-primary links In ath12k_dp_rx_peer_frag_setup(), commit ea4192553850 ("wifi: ath12k: add primary link for data path operations") checks whether a link is the primary link, and returns directly if it isn't. In ML scenario where we have non-primary links created, this results in leaking the michael_mic info since it is allocated by default but could never be freed for a non-primary link. Note that we can not move the might-sleep allocation after primary link check since there we are in atomic context (due to spin lock). So keep the default allocation, and then free it before return to fix this issue. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Fixes: ea4192553850 ("wifi: ath12k: add primary link for data path operations") Signed-off-by: Baochen Qiang Acked-by: Kalle Valo Acked-by: Jeff Johnson Link: https://patch.msgid.link/20241206054552.177424-1-quic_bqiang@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/dp_rx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index b24d1de4aabb9..f8e79eff20894 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -2830,6 +2830,7 @@ int ath12k_dp_rx_peer_frag_setup(struct ath12k *ar, const u8 *peer_mac, int vdev if (!peer->primary_link) { spin_unlock_bh(&ab->base_lock); + crypto_free_shash(tfm); return 0; } From 58fa8109fa8dae2947567e8f56dbd55ad81bc35c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 6 Dec 2024 15:52:29 +0300 Subject: [PATCH 02/60] wifi: ath12k: Off by one in ath12k_wmi_process_csa_switch_count_event() The ahvif->vif->link_conf[] array has IEEE80211_MLD_MAX_NUM_LINKS elements so this should be >= instead of > to avoid an out of bounds access. Fixes: 3952657848c0 ("wifi: ath12k: Use mac80211 vif's link_conf instead of bss_conf") Signed-off-by: Dan Carpenter Acked-by: Kalle Valo Link: https://patch.msgid.link/755becb1-819b-484d-8fac-9a2db53ced1b@stanley.mountain Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 402ae477da61b..46c5027e4f1cf 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -6873,7 +6873,7 @@ ath12k_wmi_process_csa_switch_count_event(struct ath12k_base *ab, } ahvif = arvif->ahvif; - if (arvif->link_id > IEEE80211_MLD_MAX_NUM_LINKS) { + if (arvif->link_id >= IEEE80211_MLD_MAX_NUM_LINKS) { ath12k_warn(ab, "Invalid CSA switch count even link id: %d\n", arvif->link_id); continue; From 5a10971c7645a95f5d5dc23c26fbac4bf61801d0 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Tue, 10 Dec 2024 10:56:33 +0530 Subject: [PATCH 03/60] wifi: ath12k: fix read pointer after free in ath12k_mac_assign_vif_to_vdev() In ath12k_mac_assign_vif_to_vdev(), if arvif is created on a different radio, it gets deleted from that radio through a call to ath12k_mac_unassign_link_vif(). This action frees the arvif pointer. Subsequently, there is a check involving arvif, which will result in a read-after-free scenario. Fix this by moving this check after arvif is again assigned via call to ath12k_mac_assign_link_vif(). Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Closes: https://scan5.scan.coverity.com/#/project-view/63541/10063?selectedIssue=1636423 Fixes: b5068bc9180d ("wifi: ath12k: Cache vdev configs before vdev create") Signed-off-by: Aditya Kumar Singh Acked-by: Jeff Johnson Acked-by: Kalle Valo Link: https://patch.msgid.link/20241210-read_after_free-v1-1-969f69c7d66c@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index c4eab4c1c10e0..47a80d28d1d7f 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -8064,9 +8064,6 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw, ab = ar->ab; - if (arvif->is_created) - goto flush; - /* Assign arvif again here since previous radio switch block * would've unassigned and cleared it. */ @@ -8077,6 +8074,9 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw, goto unlock; } + if (arvif->is_created) + goto flush; + if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) { ath12k_warn(ab, "failed to create vdev, reached max vdev limit %d\n", TARGET_NUM_VDEVS); From f86e09fd393adfbbf078985e2cbf322e9892fbe3 Mon Sep 17 00:00:00 2001 From: Raj Kumar Bhagat Date: Wed, 11 Dec 2024 17:34:25 +0200 Subject: [PATCH 04/60] dt-bindings: net: wireless: Describe ath12k PCI module with WSI The QCN9274 WiFi device supports WSI (WLAN Serial Interface). WSI is used to exchange specific control information across radios using a doorbell mechanism. This WSI connection is essential for exchanging control information among these devices. The WSI interface in the QCN9274 includes TX and RX ports, which are used to connect multiple WSI-supported devices together, forming a WSI group. Describe QCN9274 PCI wifi device with WSI interface. Signed-off-by: Raj Kumar Bhagat Signed-off-by: Kalle Valo Reviewed-by: Conor Dooley Link: https://patch.msgid.link/20241211153432.775335-2-kvalo@kernel.org Signed-off-by: Jeff Johnson --- .../net/wireless/qcom,ath12k-wsi.yaml | 204 ++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/wireless/qcom,ath12k-wsi.yaml diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath12k-wsi.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath12k-wsi.yaml new file mode 100644 index 0000000000000..cbfb559f6b69b --- /dev/null +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath12k-wsi.yaml @@ -0,0 +1,204 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/wireless/qcom,ath12k-wsi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies ath12k wireless devices (PCIe) with WSI interface + +maintainers: + - Jeff Johnson + - Kalle Valo + +description: | + Qualcomm Technologies IEEE 802.11be PCIe devices with WSI interface. + + The ath12k devices (QCN9274) feature WSI support. WSI stands for + WLAN Serial Interface. It is used for the exchange of specific + control information across radios based on the doorbell mechanism. + This WSI connection is essential to exchange control information + among these devices. + + The WSI interface includes TX and RX ports, which are used to connect + multiple WSI-supported devices together, forming a WSI group. + + Diagram to represent one WSI connection (one WSI group) among + three devices. + + +-------+ +-------+ +-------+ + | pcie1 | | pcie2 | | pcie3 | + | | | | | | + +----->| wsi |------->| wsi |------->| wsi |-----+ + | | grp 0 | | grp 0 | | grp 0 | | + | +-------+ +-------+ +-------+ | + +------------------------------------------------------+ + + Diagram to represent two WSI connections (two separate WSI groups) + among four devices. + + +-------+ +-------+ +-------+ +-------+ + | pcie0 | | pcie1 | | pcie2 | | pcie3 | + | | | | | | | | + +-->| wsi |--->| wsi |--+ +-->| wsi |--->| wsi |--+ + | | grp 0 | | grp 0 | | | | grp 1 | | grp 1 | | + | +-------+ +-------+ | | +-------+ +-------+ | + +---------------------------+ +---------------------------+ + +properties: + compatible: + enum: + - pci17cb,1109 # QCN9274 + + reg: + maxItems: 1 + + qcom,ath12k-calibration-variant: + $ref: /schemas/types.yaml#/definitions/string + description: + String to uniquely identify variant of the calibration data for designs + with colliding bus and device ids + + qcom,wsi-controller: + $ref: /schemas/types.yaml#/definitions/flag + description: + The WSI controller device in the WSI group aids (is capable) to + synchronize the Timing Synchronization Function (TSF) clock across + all devices in the WSI group. + + ports: + $ref: /schemas/graph.yaml#/properties/ports + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: + This is the TX port of WSI interface. It is attached to the RX + port of the next device in the WSI connection. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + This is the RX port of WSI interface. It is attached to the TX + port of the previous device in the WSI connection. + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + pcie { + #address-cells = <3>; + #size-cells = <2>; + + pcie@0 { + device_type = "pci"; + reg = <0x0 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@0 { + compatible = "pci17cb,1109"; + reg = <0x0 0x0 0x0 0x0 0x0>; + + qcom,ath12k-calibration-variant = "RDP433_1"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + wifi1_wsi_tx: endpoint { + remote-endpoint = <&wifi2_wsi_rx>; + }; + }; + + port@1 { + reg = <1>; + + wifi1_wsi_rx: endpoint { + remote-endpoint = <&wifi3_wsi_tx>; + }; + }; + }; + }; + }; + + pcie@1 { + device_type = "pci"; + reg = <0x0 0x0 0x1 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@0 { + compatible = "pci17cb,1109"; + reg = <0x0 0x0 0x0 0x0 0x0>; + + qcom,ath12k-calibration-variant = "RDP433_2"; + qcom,wsi-controller; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + wifi2_wsi_tx: endpoint { + remote-endpoint = <&wifi3_wsi_rx>; + }; + }; + + port@1 { + reg = <1>; + + wifi2_wsi_rx: endpoint { + remote-endpoint = <&wifi1_wsi_tx>; + }; + }; + }; + }; + }; + + pcie@2 { + device_type = "pci"; + reg = <0x0 0x0 0x2 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@0 { + compatible = "pci17cb,1109"; + reg = <0x0 0x0 0x0 0x0 0x0>; + + qcom,ath12k-calibration-variant = "RDP433_3"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + wifi3_wsi_tx: endpoint { + remote-endpoint = <&wifi1_wsi_rx>; + }; + }; + + port@1 { + reg = <1>; + + wifi3_wsi_rx: endpoint { + remote-endpoint = <&wifi2_wsi_tx>; + }; + }; + }; + }; + }; + }; From 908c10c860e012f961bfb2b8e0823b23426beb9d Mon Sep 17 00:00:00 2001 From: Raj Kumar Bhagat Date: Wed, 11 Dec 2024 17:34:26 +0200 Subject: [PATCH 05/60] wifi: ath12k: parse multiple device information from Device Tree Currently, a single device is part of the device group abstraction. However, for multi-link operations, multiple devices need to be combined. This multi-device grouping is done via WSI (WLAN Serial Interface), which is described in the Device Tree. Information about different WSI groups and the number of devices involved in each group can be parsed from the Device Tree. Add changes to parse the Device Tree and determine WSI information, such as the different WSI groups and the number of devices per WSI group. Assign WSI index zero to the WSI controller device (to synchronize the clock among the devices within the WSI group), and increment the WSI index of each device in the order of the WSI connection. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Co-developed-by: Harshitha Prem Signed-off-by: Harshitha Prem Signed-off-by: Raj Kumar Bhagat Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241211153432.775335-3-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.c | 183 +++++++++++++++++++++++-- drivers/net/wireless/ath/ath12k/core.h | 8 ++ 2 files changed, 178 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 49d1ac15cb7a2..1a43e00cffb26 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "core.h" #include "dp_tx.h" #include "dp_rx.h" @@ -1383,20 +1384,24 @@ bool ath12k_core_hw_group_create_ready(struct ath12k_hw_group *ag) return (ag->num_probed == ag->num_devices); } -static struct ath12k_hw_group *ath12k_core_hw_group_alloc(u8 id, u8 max_devices) +static struct ath12k_hw_group *ath12k_core_hw_group_alloc(struct ath12k_base *ab) { struct ath12k_hw_group *ag; + int count = 0; lockdep_assert_held(&ath12k_hw_group_mutex); + list_for_each_entry(ag, &ath12k_hw_group_list, list) + count++; + ag = kzalloc(sizeof(*ag), GFP_KERNEL); if (!ag) return NULL; - ag->id = id; - ag->num_devices = max_devices; + ag->id = count; list_add(&ag->list, &ath12k_hw_group_list); mutex_init(&ag->mutex); + ag->mlo_capable = false; return ag; } @@ -1411,35 +1416,180 @@ static void ath12k_core_hw_group_free(struct ath12k_hw_group *ag) mutex_unlock(&ath12k_hw_group_mutex); } +static struct ath12k_hw_group *ath12k_core_hw_group_find_by_dt(struct ath12k_base *ab) +{ + struct ath12k_hw_group *ag; + int i; + + if (!ab->dev->of_node) + return NULL; + + list_for_each_entry(ag, &ath12k_hw_group_list, list) + for (i = 0; i < ag->num_devices; i++) + if (ag->wsi_node[i] == ab->dev->of_node) + return ag; + + return NULL; +} + +static int ath12k_core_get_wsi_info(struct ath12k_hw_group *ag, + struct ath12k_base *ab) +{ + struct device_node *wsi_dev = ab->dev->of_node, *next_wsi_dev; + struct device_node *tx_endpoint, *next_rx_endpoint; + int device_count = 0; + + next_wsi_dev = wsi_dev; + + if (!next_wsi_dev) + return -ENODEV; + + do { + ag->wsi_node[device_count] = next_wsi_dev; + + tx_endpoint = of_graph_get_endpoint_by_regs(next_wsi_dev, 0, -1); + if (!tx_endpoint) { + of_node_put(next_wsi_dev); + return -ENODEV; + } + + next_rx_endpoint = of_graph_get_remote_endpoint(tx_endpoint); + if (!next_rx_endpoint) { + of_node_put(next_wsi_dev); + of_node_put(tx_endpoint); + return -ENODEV; + } + + of_node_put(tx_endpoint); + of_node_put(next_wsi_dev); + + next_wsi_dev = of_graph_get_port_parent(next_rx_endpoint); + if (!next_wsi_dev) { + of_node_put(next_rx_endpoint); + return -ENODEV; + } + + of_node_put(next_rx_endpoint); + + device_count++; + if (device_count > ATH12K_MAX_SOCS) { + ath12k_warn(ab, "device count in DT %d is more than limit %d\n", + device_count, ATH12K_MAX_SOCS); + of_node_put(next_wsi_dev); + return -EINVAL; + } + } while (wsi_dev != next_wsi_dev); + + of_node_put(next_wsi_dev); + ag->num_devices = device_count; + + return 0; +} + +static int ath12k_core_get_wsi_index(struct ath12k_hw_group *ag, + struct ath12k_base *ab) +{ + int i, wsi_controller_index = -1, node_index = -1; + bool control; + + for (i = 0; i < ag->num_devices; i++) { + control = of_property_read_bool(ag->wsi_node[i], "qcom,wsi-controller"); + if (control) + wsi_controller_index = i; + + if (ag->wsi_node[i] == ab->dev->of_node) + node_index = i; + } + + if (wsi_controller_index == -1) { + ath12k_dbg(ab, ATH12K_DBG_BOOT, "wsi controller is not defined in dt"); + return -EINVAL; + } + + if (node_index == -1) { + ath12k_dbg(ab, ATH12K_DBG_BOOT, "unable to get WSI node index"); + return -EINVAL; + } + + ab->wsi_info.index = (ag->num_devices + node_index - wsi_controller_index) % + ag->num_devices; + + return 0; +} + static struct ath12k_hw_group *ath12k_core_hw_group_assign(struct ath12k_base *ab) { - u32 group_id = ATH12K_INVALID_GROUP_ID; + struct ath12k_wsi_info *wsi = &ab->wsi_info; struct ath12k_hw_group *ag; lockdep_assert_held(&ath12k_hw_group_mutex); /* The grouping of multiple devices will be done based on device tree file. - * TODO: device tree file parsing to know about the devices involved in group. - * - * The platforms that do not have any valid group information would have each - * device to be part of its own invalid group. + * The platforms that do not have any valid group information would have + * each device to be part of its own invalid group. * - * Currently, we are not parsing any device tree information and hence, grouping - * of multiple devices is not involved. Thus, single device is added to device - * group. + * We use group id ATH12K_INVALID_GROUP_ID for single device group + * which didn't have dt entry or wrong dt entry, there could be many + * groups with same group id, i.e ATH12K_INVALID_GROUP_ID. So + * default group id of ATH12K_INVALID_GROUP_ID combined with + * num devices in ath12k_hw_group determines if the group is + * multi device or single device group */ - ag = ath12k_core_hw_group_alloc(group_id, 1); + + ag = ath12k_core_hw_group_find_by_dt(ab); + if (!ag) { + ag = ath12k_core_hw_group_alloc(ab); + if (!ag) { + ath12k_warn(ab, "unable to create new hw group\n"); + return NULL; + } + + if (ath12k_core_get_wsi_info(ag, ab) || + ath12k_core_get_wsi_index(ag, ab)) { + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "unable to get wsi info from dt, grouping single device"); + ag->id = ATH12K_INVALID_GROUP_ID; + ag->num_devices = 1; + memset(ag->wsi_node, 0, sizeof(ag->wsi_node)); + wsi->index = 0; + } + + goto exit; + } else if (test_bit(ATH12K_GROUP_FLAG_UNREGISTER, &ag->flags)) { + ath12k_dbg(ab, ATH12K_DBG_BOOT, "group id %d in unregister state\n", + ag->id); + goto invalid_group; + } else { + if (ath12k_core_get_wsi_index(ag, ab)) + goto invalid_group; + goto exit; + } + +invalid_group: + ag = ath12k_core_hw_group_alloc(ab); if (!ag) { ath12k_warn(ab, "unable to create new hw group\n"); return NULL; } + ag->id = ATH12K_INVALID_GROUP_ID; + ag->num_devices = 1; + wsi->index = 0; + ath12k_dbg(ab, ATH12K_DBG_BOOT, "single device added to hardware group\n"); +exit: + if (ag->num_probed >= ag->num_devices) { + ath12k_warn(ab, "unable to add new device to group, max limit reached\n"); + goto invalid_group; + } + ab->device_id = ag->num_probed++; ag->ab[ab->device_id] = ab; ab->ag = ag; - ag->mlo_capable = false; + + ath12k_dbg(ab, ATH12K_DBG_BOOT, "wsi group-id %d num-devices %d index %d", + ag->id, ag->num_devices, wsi->index); return ag; } @@ -1507,6 +1657,13 @@ static void ath12k_core_hw_group_cleanup(struct ath12k_hw_group *ag) mutex_lock(&ag->mutex); + if (test_bit(ATH12K_GROUP_FLAG_UNREGISTER, &ag->flags)) { + mutex_unlock(&ag->mutex); + return; + } + + set_bit(ATH12K_GROUP_FLAG_UNREGISTER, &ag->flags); + ath12k_core_hw_group_stop(ag); for (i = 0; i < ag->num_devices; i++) { diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 458e3d0071a83..d0e4668190361 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -219,6 +219,7 @@ enum ath12k_scan_state { enum ath12k_hw_group_flags { ATH12K_GROUP_FLAG_REGISTERED, + ATH12K_GROUP_FLAG_UNREGISTER, }; enum ath12k_dev_flags { @@ -845,6 +846,12 @@ struct ath12k_hw_group { struct ath12k_hw *ah[ATH12K_GROUP_MAX_RADIO]; u8 num_hw; bool mlo_capable; + struct device_node *wsi_node[ATH12K_MAX_SOCS]; +}; + +/* Holds WSI info specific to each device, excluding WSI group info */ +struct ath12k_wsi_info { + u32 index; }; /* Master structure to hold the hw data which may be used in core module */ @@ -1028,6 +1035,7 @@ struct ath12k_base { struct notifier_block panic_nb; struct ath12k_hw_group *ag; + struct ath12k_wsi_info wsi_info; /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); From 08a4c51c6ea0790d8abcb713410833fcb0019a69 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Wed, 11 Dec 2024 17:34:27 +0200 Subject: [PATCH 06/60] wifi: ath12k: send partner device details in QMI MLO capability Currently, QMI MLO host capability is sent with the details of local links and hw_link id only for particular device. But in the case of multi device group abstraction, it has to include the details of hw_link_id, num_local_links of every partner device that is involved in the group during QMI MLO capability exchange. Add changes to send partner device details to the firmware in QMI MLO capability exchange. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Harshitha Prem Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241211153432.775335-4-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/qmi.c | 88 ++++++++++++++++++++++----- 1 file changed, 72 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index ba3cd23424654..2f10c83ef54ab 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -2016,17 +2016,19 @@ static const struct qmi_elem_info qmi_wlanfw_wlan_ini_resp_msg_v01_ei[] = { }, }; -static void ath12k_host_cap_parse_mlo(struct ath12k_base *ab, - struct qmi_wlanfw_host_cap_req_msg_v01 *req) +static int ath12k_host_cap_parse_mlo(struct ath12k_base *ab, + struct qmi_wlanfw_host_cap_req_msg_v01 *req) { struct wlfw_host_mlo_chip_info_s_v01 *info; + struct ath12k_hw_group *ag = ab->ag; + struct ath12k_base *partner_ab; u8 hw_link_id = 0; - int i; + int i, j, ret; - if (!ab->ag->mlo_capable) { + if (!ag->mlo_capable) { ath12k_dbg(ab, ATH12K_DBG_QMI, "MLO is disabled hence skip QMI MLO cap"); - return; + return 0; } if (!ab->qmi.num_radios || ab->qmi.num_radios == U8_MAX) { @@ -2035,7 +2037,12 @@ static void ath12k_host_cap_parse_mlo(struct ath12k_base *ab, ath12k_dbg(ab, ATH12K_DBG_QMI, "skip QMI MLO cap due to invalid num_radio %d\n", ab->qmi.num_radios); - return; + return 0; + } + + if (ab->device_id == ATH12K_INVALID_DEVICE_ID) { + ath12k_err(ab, "failed to send MLO cap due to invalid device id\n"); + return -EINVAL; } req->mlo_capable_valid = 1; @@ -2043,27 +2050,74 @@ static void ath12k_host_cap_parse_mlo(struct ath12k_base *ab, req->mlo_chip_id_valid = 1; req->mlo_chip_id = ab->device_id; req->mlo_group_id_valid = 1; - req->mlo_group_id = 0; + req->mlo_group_id = ag->id; req->max_mlo_peer_valid = 1; /* Max peer number generally won't change for the same device * but needs to be synced with host driver. */ req->max_mlo_peer = ab->hw_params->max_mlo_peer; req->mlo_num_chips_valid = 1; - req->mlo_num_chips = 1; + req->mlo_num_chips = ag->num_devices; - info = &req->mlo_chip_info[0]; - info->chip_id = ab->device_id; - info->num_local_links = ab->qmi.num_radios; + mutex_lock(&ag->mutex); - for (i = 0; i < info->num_local_links; i++) { - info->hw_link_id[i] = hw_link_id; - info->valid_mlo_link_id[i] = 1; + for (i = 0; i < ag->num_devices; i++) { + info = &req->mlo_chip_info[i]; + partner_ab = ag->ab[i]; - hw_link_id++; + if (partner_ab->device_id == ATH12K_INVALID_DEVICE_ID) { + ath12k_err(ab, "failed to send MLO cap due to invalid partner device id\n"); + ret = -EINVAL; + goto device_cleanup; + } + + info->chip_id = partner_ab->device_id; + info->num_local_links = partner_ab->qmi.num_radios; + + ath12k_dbg(ab, ATH12K_DBG_QMI, "mlo device id %d num_link %d\n", + info->chip_id, info->num_local_links); + + for (j = 0; j < info->num_local_links; j++) { + info->hw_link_id[j] = hw_link_id; + info->valid_mlo_link_id[j] = 1; + + hw_link_id++; + } } + if (hw_link_id <= 0) + ag->mlo_capable = false; + req->mlo_chip_info_valid = 1; + + mutex_unlock(&ag->mutex); + + return 0; + +device_cleanup: + for (i = i - 1; i >= 0; i--) { + info = &req->mlo_chip_info[i]; + + memset(info, 0, sizeof(*info)); + } + + req->mlo_num_chips = 0; + req->mlo_num_chips_valid = 0; + + req->max_mlo_peer = 0; + req->max_mlo_peer_valid = 0; + req->mlo_group_id = 0; + req->mlo_group_id_valid = 0; + req->mlo_chip_id = 0; + req->mlo_chip_id_valid = 0; + req->mlo_capable = 0; + req->mlo_capable_valid = 0; + + ag->mlo_capable = false; + + mutex_unlock(&ag->mutex); + + return ret; } /* clang stack usage explodes if this is inlined */ @@ -2113,7 +2167,9 @@ int ath12k_qmi_host_cap_send(struct ath12k_base *ab) req.nm_modem |= PLATFORM_CAP_PCIE_GLOBAL_RESET; } - ath12k_host_cap_parse_mlo(ab, &req); + ret = ath12k_host_cap_parse_mlo(ab, &req); + if (ret < 0) + goto out; ret = qmi_txn_init(&ab->qmi.handle, &txn, qmi_wlanfw_host_cap_resp_msg_v01_ei, &resp); From 786f34b5b4a408f466f762ca7785121ef3dbf540 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Wed, 11 Dec 2024 17:34:28 +0200 Subject: [PATCH 07/60] wifi: ath12k: refactor ath12k_qmi_alloc_target_mem_chunk() Currently, all QMI target memory types share the same allocation logic within ath12k_qmi_alloc_target_mem_chunk(). However, for Multi-Link Operation (MLO), the firmware requests a new MLO global memory region. This memory is shared across different firmware (SoC) participating in the MLO. To accommodate this logic change, refactor ath12k_qmi_alloc_target_mem_chunk() and introduce a helper function ath12k_qmi_alloc_chunk() for memory chunk allocation. Subsequent patch will add MLO global memory allocation logic. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00210-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Raj Kumar Bhagat Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241211153432.775335-5-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/qmi.c | 82 ++++++++++++++------------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 2f10c83ef54ab..7f3d5b269b9ec 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -2423,9 +2423,50 @@ static void ath12k_qmi_free_target_mem_chunk(struct ath12k_base *ab) } } +static int ath12k_qmi_alloc_chunk(struct ath12k_base *ab, + struct target_mem_chunk *chunk) +{ + /* Firmware reloads in recovery/resume. + * In such cases, no need to allocate memory for FW again. + */ + if (chunk->v.addr) { + if (chunk->prev_type == chunk->type && + chunk->prev_size == chunk->size) + goto this_chunk_done; + + /* cannot reuse the existing chunk */ + dma_free_coherent(ab->dev, chunk->prev_size, + chunk->v.addr, chunk->paddr); + chunk->v.addr = NULL; + } + + chunk->v.addr = dma_alloc_coherent(ab->dev, + chunk->size, + &chunk->paddr, + GFP_KERNEL | __GFP_NOWARN); + if (!chunk->v.addr) { + if (chunk->size > ATH12K_QMI_MAX_CHUNK_SIZE) { + ab->qmi.target_mem_delayed = true; + ath12k_warn(ab, + "qmi dma allocation failed (%d B type %u), will try later with small size\n", + chunk->size, + chunk->type); + ath12k_qmi_free_target_mem_chunk(ab); + return 0; + } + ath12k_warn(ab, "memory allocation failure for %u size: %d\n", + chunk->type, chunk->size); + return -ENOMEM; + } + chunk->prev_type = chunk->type; + chunk->prev_size = chunk->size; +this_chunk_done: + return 0; +} + static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab) { - int i; + int i, ret = 0; struct target_mem_chunk *chunk; ab->qmi.target_mem_delayed = false; @@ -2442,42 +2483,7 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab) case M3_DUMP_REGION_TYPE: case PAGEABLE_MEM_REGION_TYPE: case CALDB_MEM_REGION_TYPE: - /* Firmware reloads in recovery/resume. - * In such cases, no need to allocate memory for FW again. - */ - if (chunk->v.addr) { - if (chunk->prev_type == chunk->type && - chunk->prev_size == chunk->size) - goto this_chunk_done; - - /* cannot reuse the existing chunk */ - dma_free_coherent(ab->dev, chunk->prev_size, - chunk->v.addr, chunk->paddr); - chunk->v.addr = NULL; - } - - chunk->v.addr = dma_alloc_coherent(ab->dev, - chunk->size, - &chunk->paddr, - GFP_KERNEL | __GFP_NOWARN); - if (!chunk->v.addr) { - if (chunk->size > ATH12K_QMI_MAX_CHUNK_SIZE) { - ab->qmi.target_mem_delayed = true; - ath12k_warn(ab, - "qmi dma allocation failed (%d B type %u), will try later with small size\n", - chunk->size, - chunk->type); - ath12k_qmi_free_target_mem_chunk(ab); - return 0; - } - ath12k_warn(ab, "memory allocation failure for %u size: %d\n", - chunk->type, chunk->size); - return -ENOMEM; - } - - chunk->prev_type = chunk->type; - chunk->prev_size = chunk->size; -this_chunk_done: + ret = ath12k_qmi_alloc_chunk(ab, chunk); break; default: ath12k_warn(ab, "memory type %u not supported\n", @@ -2487,7 +2493,7 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab) break; } } - return 0; + return ret; } /* clang stack usage explodes if this is inlined */ From 48090fae676ecef4bb39cc6a2faa9765a248b4f8 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Wed, 11 Dec 2024 17:34:29 +0200 Subject: [PATCH 08/60] wifi: ath12k: add support to allocate MLO global memory region To enable Multi-Link Operation (MLO), QCN9274 firmware requests MLO global memory (MLO_GLOBAL_MEM_REGION_TYPE). This memory region is shared across all the firmware (SoC) that are participation in the MLO. Hence, add support to allocate and free MLO global memory region. Allocate one MLO global memory per struct ath12k_hw_group and assign the same memory to all firmware in the same struct ath12k_hw_group. WCN7850 firmware does not request this memory type, therefore this change will have no impact on WCN7850 device. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00210-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Co-developed-by: Raj Kumar Bhagat Signed-off-by: Raj Kumar Bhagat Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241211153432.775335-6-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.h | 7 ++ drivers/net/wireless/ath/ath12k/qmi.c | 127 +++++++++++++++++++++++-- drivers/net/wireless/ath/ath12k/qmi.h | 1 + 3 files changed, 125 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index d0e4668190361..bf310df3d8f71 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -822,6 +822,12 @@ struct ath12k_soc_dp_stats { struct ath12k_soc_dp_tx_err_stats tx_err; }; +struct ath12k_mlo_memory { + struct target_mem_chunk chunk[ATH12K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01]; + int mlo_mem_size; + bool init_done; +}; + /* Holds info on the group of devices that are registered as a single * wiphy, protected with struct ath12k_hw_group::mutex. */ @@ -847,6 +853,7 @@ struct ath12k_hw_group { u8 num_hw; bool mlo_capable; struct device_node *wsi_node[ATH12K_MAX_SOCS]; + struct ath12k_mlo_memory mlo_mem; }; /* Holds WSI info specific to each device, excluding WSI group info */ diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 7f3d5b269b9ec..e7846aaca10a5 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -2407,19 +2407,64 @@ int ath12k_qmi_respond_fw_mem_request(struct ath12k_base *ab) return ret; } +static void ath12k_qmi_free_mlo_mem_chunk(struct ath12k_base *ab, + struct target_mem_chunk *chunk, + int idx) +{ + struct ath12k_hw_group *ag = ab->ag; + struct target_mem_chunk *mlo_chunk; + + lockdep_assert_held(&ag->mutex); + + if (!ag->mlo_mem.init_done || ag->num_started) + return; + + if (idx >= ARRAY_SIZE(ag->mlo_mem.chunk)) { + ath12k_warn(ab, "invalid index for MLO memory chunk free: %d\n", idx); + return; + } + + mlo_chunk = &ag->mlo_mem.chunk[idx]; + if (mlo_chunk->v.addr) { + dma_free_coherent(ab->dev, + mlo_chunk->size, + mlo_chunk->v.addr, + mlo_chunk->paddr); + mlo_chunk->v.addr = NULL; + } + + mlo_chunk->paddr = 0; + mlo_chunk->size = 0; + chunk->v.addr = NULL; + chunk->paddr = 0; + chunk->size = 0; +} + static void ath12k_qmi_free_target_mem_chunk(struct ath12k_base *ab) { - int i; + struct ath12k_hw_group *ag = ab->ag; + int i, mlo_idx; - for (i = 0; i < ab->qmi.mem_seg_count; i++) { + for (i = 0, mlo_idx = 0; i < ab->qmi.mem_seg_count; i++) { if (!ab->qmi.target_mem[i].v.addr) continue; - dma_free_coherent(ab->dev, - ab->qmi.target_mem[i].prev_size, - ab->qmi.target_mem[i].v.addr, - ab->qmi.target_mem[i].paddr); - ab->qmi.target_mem[i].v.addr = NULL; + if (ab->qmi.target_mem[i].type == MLO_GLOBAL_MEM_REGION_TYPE) { + ath12k_qmi_free_mlo_mem_chunk(ab, + &ab->qmi.target_mem[i], + mlo_idx++); + } else { + dma_free_coherent(ab->dev, + ab->qmi.target_mem[i].prev_size, + ab->qmi.target_mem[i].v.addr, + ab->qmi.target_mem[i].paddr); + ab->qmi.target_mem[i].v.addr = NULL; + } + } + + if (!ag->num_started && ag->mlo_mem.init_done) { + ag->mlo_mem.init_done = false; + ag->mlo_mem.mlo_mem_size = 0; } } @@ -2466,12 +2511,21 @@ static int ath12k_qmi_alloc_chunk(struct ath12k_base *ab, static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab) { - int i, ret = 0; - struct target_mem_chunk *chunk; + struct target_mem_chunk *chunk, *mlo_chunk; + struct ath12k_hw_group *ag = ab->ag; + int i, mlo_idx, ret; + int mlo_size = 0; + + mutex_lock(&ag->mutex); + + if (!ag->mlo_mem.init_done) { + memset(ag->mlo_mem.chunk, 0, sizeof(ag->mlo_mem.chunk)); + ag->mlo_mem.init_done = true; + } ab->qmi.target_mem_delayed = false; - for (i = 0; i < ab->qmi.mem_seg_count; i++) { + for (i = 0, mlo_idx = 0; i < ab->qmi.mem_seg_count; i++) { chunk = &ab->qmi.target_mem[i]; /* Allocate memory for the region and the functionality supported @@ -2484,6 +2538,40 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab) case PAGEABLE_MEM_REGION_TYPE: case CALDB_MEM_REGION_TYPE: ret = ath12k_qmi_alloc_chunk(ab, chunk); + if (ret) + goto err; + break; + case MLO_GLOBAL_MEM_REGION_TYPE: + mlo_size += chunk->size; + if (ag->mlo_mem.mlo_mem_size && + mlo_size > ag->mlo_mem.mlo_mem_size) { + ath12k_err(ab, "QMI MLO memory allocation failure, requested size %d is more than allocated size %d", + mlo_size, ag->mlo_mem.mlo_mem_size); + ret = -EINVAL; + goto err; + } + + mlo_chunk = &ag->mlo_mem.chunk[mlo_idx]; + if (mlo_chunk->paddr) { + if (chunk->size != mlo_chunk->size) { + ath12k_err(ab, "QMI MLO chunk memory allocation failure for index %d, requested size %d is more than allocated size %d", + mlo_idx, chunk->size, mlo_chunk->size); + ret = -EINVAL; + goto err; + } + } else { + mlo_chunk->size = chunk->size; + mlo_chunk->type = chunk->type; + ret = ath12k_qmi_alloc_chunk(ab, mlo_chunk); + if (ret) + goto err; + memset(mlo_chunk->v.addr, 0, mlo_chunk->size); + } + + chunk->paddr = mlo_chunk->paddr; + chunk->v.addr = mlo_chunk->v.addr; + mlo_idx++; + break; default: ath12k_warn(ab, "memory type %u not supported\n", @@ -2493,6 +2581,25 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab) break; } } + + if (!ag->mlo_mem.mlo_mem_size) { + ag->mlo_mem.mlo_mem_size = mlo_size; + } else if (ag->mlo_mem.mlo_mem_size != mlo_size) { + ath12k_err(ab, "QMI MLO memory size error, expected size is %d but requestted size is %d", + ag->mlo_mem.mlo_mem_size, mlo_size); + ret = -EINVAL; + goto err; + } + + mutex_unlock(&ag->mutex); + + return 0; + +err: + ath12k_qmi_free_target_mem_chunk(ab); + + mutex_unlock(&ag->mutex); + return ret; } diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h index 98f6009ab21e3..45d7c3fcafdd7 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.h +++ b/drivers/net/wireless/ath/ath12k/qmi.h @@ -172,6 +172,7 @@ enum ath12k_qmi_target_mem { BDF_MEM_REGION_TYPE = 0x2, M3_DUMP_REGION_TYPE = 0x3, CALDB_MEM_REGION_TYPE = 0x4, + MLO_GLOBAL_MEM_REGION_TYPE = 0x8, PAGEABLE_MEM_REGION_TYPE = 0x9, }; From cc64deef0bdb52d6b2d6f1a2cd427ae680ed1936 Mon Sep 17 00:00:00 2001 From: Bhagavathi Perumal S Date: Wed, 11 Dec 2024 17:34:30 +0200 Subject: [PATCH 09/60] wifi: ath12k: Add MLO WMI setup and teardown functions In case of multi device group abstraction, host has to exchange the MLO commands such as setup, teardown and ready to firmware. Once multi device group is ready, host has to exchange MLO setup command with partner devices link information and followed by MLO ready command to firmware. During deinit, MLO teardown command should be sent to firmware. Firmware would send MLO setup complete and MLO teardown complete to host for MLO setup command and MLO teardown command respectively. Added WMI helper functions for the MLO setup, ready and teardown command and the handling for corresponding event from firmware. Add appropriate WMI tag, command id and event id to parse the event and send request. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Co-developed-by: Karthikeyan Periyasamy Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Bhagavathi Perumal S Signed-off-by: Harshitha Prem Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241211153432.775335-7-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/wmi.c | 177 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/wmi.h | 48 +++++++ 2 files changed, 225 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 46c5027e4f1cf..705e0973ebb0d 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -7327,6 +7327,76 @@ static void ath12k_wmi_gtk_offload_status_event(struct ath12k_base *ab, kfree(tb); } +static void ath12k_wmi_event_mlo_setup_complete(struct ath12k_base *ab, + struct sk_buff *skb) +{ + const struct wmi_mlo_setup_complete_event *ev; + struct ath12k *ar = NULL; + struct ath12k_pdev *pdev; + const void **tb; + int ret, i; + + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath12k_warn(ab, "failed to parse mlo setup complete event tlv: %d\n", + ret); + return; + } + + ev = tb[WMI_TAG_MLO_SETUP_COMPLETE_EVENT]; + if (!ev) { + ath12k_warn(ab, "failed to fetch mlo setup complete event\n"); + kfree(tb); + return; + } + + if (le32_to_cpu(ev->pdev_id) > ab->num_radios) + goto skip_lookup; + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + if (pdev && pdev->pdev_id == le32_to_cpu(ev->pdev_id)) { + ar = pdev->ar; + break; + } + } + +skip_lookup: + if (!ar) { + ath12k_warn(ab, "invalid pdev_id %d status %u in setup complete event\n", + ev->pdev_id, ev->status); + goto out; + } + +out: + kfree(tb); +} + +static void ath12k_wmi_event_teardown_complete(struct ath12k_base *ab, + struct sk_buff *skb) +{ + const struct wmi_mlo_teardown_complete_event *ev; + const void **tb; + int ret; + + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath12k_warn(ab, "failed to parse teardown complete event tlv: %d\n", ret); + return; + } + + ev = tb[WMI_TAG_MLO_TEARDOWN_COMPLETE]; + if (!ev) { + ath12k_warn(ab, "failed to fetch teardown complete event\n"); + kfree(tb); + return; + } + + kfree(tb); +} + static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; @@ -7453,6 +7523,12 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) case WMI_GTK_OFFLOAD_STATUS_EVENTID: ath12k_wmi_gtk_offload_status_event(ab, skb); break; + case WMI_MLO_SETUP_COMPLETE_EVENTID: + ath12k_wmi_event_mlo_setup_complete(ab, skb); + break; + case WMI_MLO_TEARDOWN_COMPLETE_EVENTID: + ath12k_wmi_event_teardown_complete(ab, skb); + break; /* TODO: Add remaining events */ default: ath12k_dbg(ab, ATH12K_DBG_WMI, "Unknown eventid: 0x%x\n", id); @@ -8269,3 +8345,104 @@ int ath12k_wmi_sta_keepalive(struct ath12k *ar, return ath12k_wmi_cmd_send(wmi, skb, WMI_STA_KEEPALIVE_CMDID); } + +int ath12k_wmi_mlo_setup(struct ath12k *ar, struct wmi_mlo_setup_arg *mlo_params) +{ + struct wmi_mlo_setup_cmd *cmd; + struct ath12k_wmi_pdev *wmi = ar->wmi; + u32 *partner_links, num_links; + int i, ret, buf_len, arg_len; + struct sk_buff *skb; + struct wmi_tlv *tlv; + void *ptr; + + num_links = mlo_params->num_partner_links; + arg_len = num_links * sizeof(u32); + buf_len = sizeof(*cmd) + TLV_HDR_SIZE + arg_len; + + skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, buf_len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_mlo_setup_cmd *)skb->data; + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_MLO_SETUP_CMD, + sizeof(*cmd)); + cmd->mld_group_id = mlo_params->group_id; + cmd->pdev_id = cpu_to_le32(ar->pdev->pdev_id); + ptr = skb->data + sizeof(*cmd); + + tlv = ptr; + tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, arg_len); + ptr += TLV_HDR_SIZE; + + partner_links = ptr; + for (i = 0; i < num_links; i++) + partner_links[i] = mlo_params->partner_link_id[i]; + + ret = ath12k_wmi_cmd_send(wmi, skb, WMI_MLO_SETUP_CMDID); + if (ret) { + ath12k_warn(ar->ab, "failed to submit WMI_MLO_SETUP_CMDID command: %d\n", + ret); + dev_kfree_skb(skb); + return ret; + } + + return 0; +} + +int ath12k_wmi_mlo_ready(struct ath12k *ar) +{ + struct wmi_mlo_ready_cmd *cmd; + struct ath12k_wmi_pdev *wmi = ar->wmi; + struct sk_buff *skb; + int ret, len; + + len = sizeof(*cmd); + skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_mlo_ready_cmd *)skb->data; + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_MLO_READY_CMD, + sizeof(*cmd)); + cmd->pdev_id = cpu_to_le32(ar->pdev->pdev_id); + + ret = ath12k_wmi_cmd_send(wmi, skb, WMI_MLO_READY_CMDID); + if (ret) { + ath12k_warn(ar->ab, "failed to submit WMI_MLO_READY_CMDID command: %d\n", + ret); + dev_kfree_skb(skb); + return ret; + } + + return 0; +} + +int ath12k_wmi_mlo_teardown(struct ath12k *ar) +{ + struct wmi_mlo_teardown_cmd *cmd; + struct ath12k_wmi_pdev *wmi = ar->wmi; + struct sk_buff *skb; + int ret, len; + + len = sizeof(*cmd); + skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_mlo_teardown_cmd *)skb->data; + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_MLO_TEARDOWN_CMD, + sizeof(*cmd)); + cmd->pdev_id = cpu_to_le32(ar->pdev->pdev_id); + cmd->reason_code = WMI_MLO_TEARDOWN_SSR_REASON; + + ret = ath12k_wmi_cmd_send(wmi, skb, WMI_MLO_TEARDOWN_CMDID); + if (ret) { + ath12k_warn(ar->ab, "failed to submit WMI MLO teardown command: %d\n", + ret); + dev_kfree_skb(skb); + return ret; + } + + return 0; +} diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 05aa9754118a0..640720b687821 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -285,6 +285,7 @@ enum wmi_cmd_group { WMI_GRP_TWT = 0x3e, WMI_GRP_MOTION_DET = 0x3f, WMI_GRP_SPATIAL_REUSE = 0x40, + WMI_GRP_MLO = 0x48, }; #define WMI_CMD_GRP(grp_id) (((grp_id) << 12) | 0x1) @@ -665,6 +666,10 @@ enum wmi_tlv_cmd_id { WMI_PDEV_OBSS_PD_SPATIAL_REUSE_CMDID = WMI_TLV_CMD(WMI_GRP_SPATIAL_REUSE), WMI_PDEV_OBSS_PD_SPATIAL_REUSE_SET_DEF_OBSS_THRESH_CMDID, + WMI_MLO_LINK_SET_ACTIVE_CMDID = WMI_TLV_CMD(WMI_GRP_MLO), + WMI_MLO_SETUP_CMDID, + WMI_MLO_READY_CMDID, + WMI_MLO_TEARDOWN_CMDID, }; enum wmi_tlv_event_id { @@ -874,6 +879,9 @@ enum wmi_tlv_event_id { WMI_TWT_DEL_DIALOG_EVENTID, WMI_TWT_PAUSE_DIALOG_EVENTID, WMI_TWT_RESUME_DIALOG_EVENTID, + WMI_MLO_LINK_SET_ACTIVE_RESP_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_MLO), + WMI_MLO_SETUP_COMPLETE_EVENTID, + WMI_MLO_TEARDOWN_COMPLETE_EVENTID, }; enum wmi_tlv_pdev_param { @@ -5026,6 +5034,43 @@ struct wmi_twt_disable_event { __le32 status; } __packed; +struct wmi_mlo_setup_cmd { + __le32 tlv_header; + __le32 mld_group_id; + __le32 pdev_id; +} __packed; + +struct wmi_mlo_setup_arg { + __le32 group_id; + u8 num_partner_links; + u8 *partner_link_id; +}; + +struct wmi_mlo_ready_cmd { + __le32 tlv_header; + __le32 pdev_id; +} __packed; + +enum wmi_mlo_tear_down_reason_code_type { + WMI_MLO_TEARDOWN_SSR_REASON, +}; + +struct wmi_mlo_teardown_cmd { + __le32 tlv_header; + __le32 pdev_id; + __le32 reason_code; +} __packed; + +struct wmi_mlo_setup_complete_event { + __le32 pdev_id; + __le32 status; +} __packed; + +struct wmi_mlo_teardown_complete_event { + __le32 pdev_id; + __le32 status; +} __packed; + /* WOW structures */ enum wmi_wow_wakeup_event { WOW_BMISS_EVENT = 0, @@ -5751,5 +5796,8 @@ int ath12k_wmi_gtk_rekey_getinfo(struct ath12k *ar, struct ath12k_link_vif *arvif); int ath12k_wmi_sta_keepalive(struct ath12k *ar, const struct wmi_sta_keepalive_arg *arg); +int ath12k_wmi_mlo_setup(struct ath12k *ar, struct wmi_mlo_setup_arg *mlo_params); +int ath12k_wmi_mlo_ready(struct ath12k *ar); +int ath12k_wmi_mlo_teardown(struct ath12k *ar); #endif From b716a10d99a287681fc5cef46a7f9399bec5f055 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Wed, 11 Dec 2024 17:34:31 +0200 Subject: [PATCH 10/60] wifi: ath12k: enable MLO setup and teardown from core In case of multi device group abstraction, host has to exchange the multi-link operation commands such as setup and ready to firmware before registering the device group to mac80211. The multi-link operation commands - setup, ready and teardown are necessary for many commands such as WMI_PEER_ASSOC_CMD, WMI_BCN_TMPL_CMD in case of multi-link interfaces. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Harshitha Prem Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241211153432.775335-8-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.c | 73 ++++++++++++- drivers/net/wireless/ath/ath12k/core.h | 3 + drivers/net/wireless/ath/ath12k/mac.c | 142 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/mac.h | 3 + drivers/net/wireless/ath/ath12k/wmi.c | 3 + drivers/net/wireless/ath/ath12k/wmi.h | 1 + 6 files changed, 224 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 1a43e00cffb26..af642b466ea0d 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -887,6 +887,70 @@ static void ath12k_core_hw_group_stop(struct ath12k_hw_group *ag) ath12k_mac_destroy(ag); } +static int __ath12k_mac_mlo_ready(struct ath12k *ar) +{ + int ret; + + ret = ath12k_wmi_mlo_ready(ar); + if (ret) { + ath12k_err(ar->ab, "MLO ready failed for pdev %d: %d\n", + ar->pdev_idx, ret); + return ret; + } + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mlo ready done for pdev %d\n", + ar->pdev_idx); + + return 0; +} + +int ath12k_mac_mlo_ready(struct ath12k_hw_group *ag) +{ + struct ath12k_hw *ah; + struct ath12k *ar; + int ret; + int i, j; + + for (i = 0; i < ag->num_hw; i++) { + ah = ag->ah[i]; + if (!ah) + continue; + + for_each_ar(ah, ar, j) { + ar = &ah->radio[j]; + ret = __ath12k_mac_mlo_ready(ar); + if (ret) + goto out; + } + } + +out: + return ret; +} + +static int ath12k_core_mlo_setup(struct ath12k_hw_group *ag) +{ + int ret; + + if (!ag->mlo_capable || ag->num_devices == 1) + return 0; + + ret = ath12k_mac_mlo_setup(ag); + if (ret) + return ret; + + ret = ath12k_mac_mlo_ready(ag); + if (ret) + goto err_mlo_teardown; + + return 0; + +err_mlo_teardown: + ath12k_mac_mlo_teardown(ag); + + return ret; +} + static int ath12k_core_hw_group_start(struct ath12k_hw_group *ag) { struct ath12k_base *ab; @@ -901,10 +965,14 @@ static int ath12k_core_hw_group_start(struct ath12k_hw_group *ag) if (WARN_ON(ret)) return ret; - ret = ath12k_mac_register(ag); + ret = ath12k_core_mlo_setup(ag); if (WARN_ON(ret)) goto err_mac_destroy; + ret = ath12k_mac_register(ag); + if (WARN_ON(ret)) + goto err_mlo_teardown; + set_bit(ATH12K_GROUP_FLAG_REGISTERED, &ag->flags); core_pdev_create: @@ -939,6 +1007,9 @@ static int ath12k_core_hw_group_start(struct ath12k_hw_group *ag) ath12k_core_hw_group_stop(ag); return ret; +err_mlo_teardown: + ath12k_mac_mlo_teardown(ag); + err_mac_destroy: ath12k_mac_destroy(ag); diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index bf310df3d8f71..dc01f7b3fd73f 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -715,6 +715,9 @@ struct ath12k { u32 freq_high; bool nlo_enabled; + + struct completion mlo_setup_done; + u32 mlo_setup_status; }; struct ath12k_hw { diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 47a80d28d1d7f..161cc018230f5 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -10810,6 +10810,7 @@ static void ath12k_mac_setup(struct ath12k *ar) init_completion(&ar->scan.started); init_completion(&ar->scan.completed); init_completion(&ar->scan.on_channel); + init_completion(&ar->mlo_setup_done); INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work); INIT_WORK(&ar->regd_update_work, ath12k_regd_update_work); @@ -10818,6 +10819,147 @@ static void ath12k_mac_setup(struct ath12k *ar) skb_queue_head_init(&ar->wmi_mgmt_tx_queue); } +static int __ath12k_mac_mlo_setup(struct ath12k *ar) +{ + u8 num_link = 0, partner_link_id[ATH12K_GROUP_MAX_RADIO] = {}; + struct ath12k_base *partner_ab, *ab = ar->ab; + struct ath12k_hw_group *ag = ab->ag; + struct wmi_mlo_setup_arg mlo = {}; + struct ath12k_pdev *pdev; + unsigned long time_left; + int i, j, ret; + + lockdep_assert_held(&ag->mutex); + + reinit_completion(&ar->mlo_setup_done); + + for (i = 0; i < ag->num_devices; i++) { + partner_ab = ag->ab[i]; + + for (j = 0; j < partner_ab->num_radios; j++) { + pdev = &partner_ab->pdevs[j]; + + /* Avoid the self link */ + if (ar == pdev->ar) + continue; + + partner_link_id[num_link] = pdev->hw_link_id; + num_link++; + + ath12k_dbg(ab, ATH12K_DBG_MAC, "device %d pdev %d hw_link_id %d num_link %d\n", + i, j, pdev->hw_link_id, num_link); + } + } + + mlo.group_id = cpu_to_le32(ag->id); + mlo.partner_link_id = partner_link_id; + mlo.num_partner_links = num_link; + ar->mlo_setup_status = 0; + + ath12k_dbg(ab, ATH12K_DBG_MAC, "group id %d num_link %d\n", ag->id, num_link); + + ret = ath12k_wmi_mlo_setup(ar, &mlo); + if (ret) { + ath12k_err(ab, "failed to send setup MLO WMI command for pdev %d: %d\n", + ar->pdev_idx, ret); + return ret; + } + + time_left = wait_for_completion_timeout(&ar->mlo_setup_done, + WMI_MLO_CMD_TIMEOUT_HZ); + + if (!time_left || ar->mlo_setup_status) + return ar->mlo_setup_status ? : -ETIMEDOUT; + + ath12k_dbg(ab, ATH12K_DBG_MAC, "mlo setup done for pdev %d\n", ar->pdev_idx); + + return 0; +} + +static int __ath12k_mac_mlo_teardown(struct ath12k *ar) +{ + struct ath12k_base *ab = ar->ab; + int ret; + + if (test_bit(ATH12K_FLAG_RECOVERY, &ab->dev_flags)) + return 0; + + ret = ath12k_wmi_mlo_teardown(ar); + if (ret) { + ath12k_warn(ab, "failed to send MLO teardown WMI command for pdev %d: %d\n", + ar->pdev_idx, ret); + return ret; + } + + ath12k_dbg(ab, ATH12K_DBG_MAC, "mlo teardown for pdev %d\n", ar->pdev_idx); + + return 0; +} + +int ath12k_mac_mlo_setup(struct ath12k_hw_group *ag) +{ + struct ath12k_hw *ah; + struct ath12k *ar; + int ret; + int i, j; + + for (i = 0; i < ag->num_hw; i++) { + ah = ag->ah[i]; + if (!ah) + continue; + + for_each_ar(ah, ar, j) { + ar = &ah->radio[j]; + ret = __ath12k_mac_mlo_setup(ar); + if (ret) { + ath12k_err(ar->ab, "failed to setup MLO: %d\n", ret); + goto err_setup; + } + } + } + + return 0; + +err_setup: + for (i = i - 1; i >= 0; i--) { + ah = ag->ah[i]; + if (!ah) + continue; + + for (j = j - 1; j >= 0; j--) { + ar = &ah->radio[j]; + if (!ar) + continue; + + __ath12k_mac_mlo_teardown(ar); + } + } + + return ret; +} + +void ath12k_mac_mlo_teardown(struct ath12k_hw_group *ag) +{ + struct ath12k_hw *ah; + struct ath12k *ar; + int ret, i, j; + + for (i = 0; i < ag->num_hw; i++) { + ah = ag->ah[i]; + if (!ah) + continue; + + for_each_ar(ah, ar, j) { + ar = &ah->radio[j]; + ret = __ath12k_mac_mlo_teardown(ar); + if (ret) { + ath12k_err(ar->ab, "failed to teardown MLO: %d\n", ret); + break; + } + } + } +} + int ath12k_mac_register(struct ath12k_hw_group *ag) { struct ath12k_base *ab = ag->ab[0]; diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h index ccfc215d83ffe..81cfb950e6cdd 100644 --- a/drivers/net/wireless/ath/ath12k/mac.h +++ b/drivers/net/wireless/ath/ath12k/mac.h @@ -96,6 +96,9 @@ int ath12k_mac_vif_set_keepalive(struct ath12k_link_vif *arvif, enum wmi_sta_keepalive_method method, u32 interval); u8 ath12k_mac_get_target_pdev_id(struct ath12k *ar); +int ath12k_mac_mlo_setup(struct ath12k_hw_group *ag); +int ath12k_mac_mlo_ready(struct ath12k_hw_group *ag); +void ath12k_mac_mlo_teardown(struct ath12k_hw_group *ag); int ath12k_mac_vdev_stop(struct ath12k_link_vif *arvif); #endif diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 705e0973ebb0d..892cc4846e4fa 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -7369,6 +7369,9 @@ static void ath12k_wmi_event_mlo_setup_complete(struct ath12k_base *ab, goto out; } + ar->mlo_setup_status = le32_to_cpu(ev->status); + complete(&ar->mlo_setup_done); + out: kfree(tb); } diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 640720b687821..270ed458302e5 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -4938,6 +4938,7 @@ struct wmi_probe_tmpl_cmd { #define MAX_RADIOS 2 +#define WMI_MLO_CMD_TIMEOUT_HZ (5 * HZ) #define WMI_SERVICE_READY_TIMEOUT_HZ (5 * HZ) #define WMI_SEND_TIMEOUT_HZ (3 * HZ) From 628bbaa551da94d879d7aa5abc3b9632ed743fbe Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Wed, 11 Dec 2024 17:34:32 +0200 Subject: [PATCH 11/60] wifi: ath12k: avoid redundant code in DP Rx error process Currently, in DP rx error processing, the MAC id is fetched redundantly from the same descriptor for each MSDU. To avoid this redundancy, move the fetch handling before the iteration. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241211153432.775335-9-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/dp_rx.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index f8e79eff20894..536a90ff9796f 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -3517,6 +3517,13 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, ret); continue; } + + mac_id = le32_get_bits(reo_desc->info0, + HAL_REO_DEST_RING_INFO0_SRC_LINK_ID); + + pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id); + ar = ab->pdevs[pdev_id].ar; + link_desc_va = link_desc_banks[desc_bank].vaddr + (paddr - link_desc_banks[desc_bank].paddr); ath12k_hal_rx_msdu_link_info_get(link_desc_va, &num_msdus, msdu_cookies, @@ -3545,12 +3552,6 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, } for (i = 0; i < num_msdus; i++) { - mac_id = le32_get_bits(reo_desc->info0, - HAL_REO_DEST_RING_INFO0_SRC_LINK_ID); - - pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id); - ar = ab->pdevs[pdev_id].ar; - if (!ath12k_dp_process_rx_err_buf(ar, reo_desc, &rx_desc_used_list, drop, From 1a73acb5fba4d85ab5eed1147282a07d56af8550 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Mon, 9 Dec 2024 20:54:13 +0200 Subject: [PATCH 12/60] wifi: ath12k: move to HW link id based receive handling Currently, all the rx processing treats the hardware link id as the MAC id. The HW link id is a unique identifier for all hardware links participating in the multi link group. Therefore, the current MAC id derivation is insufficient to process the partner rx buffer in the Multi-Link Operation. So derive the MAC id from the HW link id and implementing this change in rx processing will enable the scaling of partner buffer processing in Multi-Link Operation. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241209185421.376381-2-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.h | 8 +++- drivers/net/wireless/ath/ath12k/dp_rx.c | 49 +++++++++++++++---------- drivers/net/wireless/ath/ath12k/mac.c | 3 ++ 3 files changed, 39 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index dc01f7b3fd73f..9386e9592dff7 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -136,7 +136,7 @@ struct ath12k_skb_rxcb { struct hal_rx_desc *rx_desc; u8 err_rel_src; u8 err_code; - u8 mac_id; + u8 hw_link_id; u8 unmapped; u8 is_frag; u8 tid; @@ -831,6 +831,11 @@ struct ath12k_mlo_memory { bool init_done; }; +struct ath12k_hw_link { + u8 device_id; + u8 pdev_idx; +}; + /* Holds info on the group of devices that are registered as a single * wiphy, protected with struct ath12k_hw_group::mutex. */ @@ -857,6 +862,7 @@ struct ath12k_hw_group { bool mlo_capable; struct device_node *wsi_node[ATH12K_MAX_SOCS]; struct ath12k_mlo_memory mlo_mem; + struct ath12k_hw_link hw_links[ATH12K_GROUP_MAX_RADIO]; }; /* Holds WSI info specific to each device, excluding WSI group info */ diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 536a90ff9796f..b68ceb403866f 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -2595,11 +2595,13 @@ static void ath12k_dp_rx_process_received_packets(struct ath12k_base *ab, struct sk_buff_head *msdu_list, int ring_id) { + struct ath12k_hw_group *ag = ab->ag; struct ieee80211_rx_status rx_status = {0}; struct ath12k_skb_rxcb *rxcb; struct sk_buff *msdu; struct ath12k *ar; - u8 mac_id, pdev_id; + struct ath12k_hw_link *hw_links = ag->hw_links; + u8 hw_link_id, pdev_id; int ret; if (skb_queue_empty(msdu_list)) @@ -2609,8 +2611,10 @@ static void ath12k_dp_rx_process_received_packets(struct ath12k_base *ab, while ((msdu = __skb_dequeue(msdu_list))) { rxcb = ATH12K_SKB_RXCB(msdu); - mac_id = rxcb->mac_id; - pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id); + hw_link_id = rxcb->hw_link_id; + + pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, + hw_links[hw_link_id].pdev_idx); ar = ab->pdevs[pdev_id].ar; if (!rcu_dereference(ab->pdevs_active[pdev_id])) { dev_kfree_skb_any(msdu); @@ -2674,7 +2678,7 @@ int ath12k_dp_rx_process(struct ath12k_base *ab, int ring_id, struct hal_srng *srng; struct sk_buff *msdu; bool done = false; - int mac_id; + u8 hw_link_id; u64 desc_va; __skb_queue_head_init(&msdu_list); @@ -2695,8 +2699,8 @@ int ath12k_dp_rx_process(struct ath12k_base *ab, int ring_id, cookie = le32_get_bits(desc->buf_addr_info.info1, BUFFER_ADDR_INFO1_SW_COOKIE); - mac_id = le32_get_bits(desc->info0, - HAL_REO_DEST_RING_INFO0_SRC_LINK_ID); + hw_link_id = le32_get_bits(desc->info0, + HAL_REO_DEST_RING_INFO0_SRC_LINK_ID); desc_va = ((u64)le32_to_cpu(desc->buf_va_hi) << 32 | le32_to_cpu(desc->buf_va_lo)); @@ -2745,7 +2749,7 @@ int ath12k_dp_rx_process(struct ath12k_base *ab, int ring_id, RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU); rxcb->is_continuation = !!(le32_to_cpu(msdu_info->info0) & RX_MSDU_DESC_INFO0_MSDU_CONTINUATION); - rxcb->mac_id = mac_id; + rxcb->hw_link_id = hw_link_id; rxcb->peer_id = ath12k_dp_rx_get_peer_id(ab, dp->peer_metadata_ver, mpdu_info->peer_meta_data); rxcb->tid = le32_get_bits(mpdu_info->info0, @@ -3473,6 +3477,7 @@ ath12k_dp_process_rx_err_buf(struct ath12k *ar, struct hal_reo_dest_ring *desc, int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, int budget) { + struct ath12k_hw_group *ag = ab->ag; u32 msdu_cookies[HAL_NUM_RX_MSDUS_PER_LINK_DESC]; struct dp_link_desc_bank *link_desc_banks; enum hal_rx_buf_return_buf_manager rbm; @@ -3481,11 +3486,12 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, struct hal_reo_dest_ring *reo_desc; struct dp_rxdma_ring *rx_ring; struct dp_srng *reo_except; + struct ath12k_hw_link *hw_links = ag->hw_links; LIST_HEAD(rx_desc_used_list); u32 desc_bank, num_msdus; struct hal_srng *srng; struct ath12k_dp *dp; - int mac_id; + u8 hw_link_id; struct ath12k *ar; dma_addr_t paddr; bool is_frag; @@ -3518,10 +3524,11 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, continue; } - mac_id = le32_get_bits(reo_desc->info0, - HAL_REO_DEST_RING_INFO0_SRC_LINK_ID); + hw_link_id = le32_get_bits(reo_desc->info0, + HAL_REO_DEST_RING_INFO0_SRC_LINK_ID); - pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id); + pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, + hw_links[hw_link_id].pdev_idx); ar = ab->pdevs[pdev_id].ar; link_desc_va = link_desc_banks[desc_bank].vaddr + @@ -3802,9 +3809,10 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, struct sk_buff_head msdu_list, scatter_msdu_list; struct ath12k_skb_rxcb *rxcb; void *rx_desc; - u8 mac_id; + u8 hw_link_id; int num_buffs_reaped = 0; struct ath12k_rx_desc_info *desc_info; + struct ath12k_hw_link *hw_links = ab->ag->hw_links; int ret, pdev_id; struct hal_rx_desc *msdu_data; @@ -3879,9 +3887,9 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, continue; } - mac_id = ath12k_dp_rx_get_msdu_src_link(ab, - msdu_data); - if (mac_id >= MAX_RADIOS) { + hw_link_id = ath12k_dp_rx_get_msdu_src_link(ab, + msdu_data); + if (hw_link_id >= MAX_RADIOS) { dev_kfree_skb_any(msdu); /* In any case continuation bit is set @@ -3896,7 +3904,7 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, skb_queue_walk(&scatter_msdu_list, msdu) { rxcb = ATH12K_SKB_RXCB(msdu); - rxcb->mac_id = mac_id; + rxcb->hw_link_id = hw_link_id; } skb_queue_splice_tail_init(&scatter_msdu_list, @@ -3904,7 +3912,7 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, } rxcb = ATH12K_SKB_RXCB(msdu); - rxcb->mac_id = mac_id; + rxcb->hw_link_id = hw_link_id; __skb_queue_tail(&msdu_list, msdu); } @@ -3926,12 +3934,13 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, rcu_read_lock(); while ((msdu = __skb_dequeue(&msdu_list))) { rxcb = ATH12K_SKB_RXCB(msdu); - mac_id = rxcb->mac_id; + hw_link_id = rxcb->hw_link_id; - pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id); + pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, + hw_links[hw_link_id].pdev_idx); ar = ab->pdevs[pdev_id].ar; - if (!ar || !rcu_dereference(ar->ab->pdevs_active[mac_id])) { + if (!ar || !rcu_dereference(ar->ab->pdevs_active[hw_link_id])) { dev_kfree_skb_any(msdu); continue; } diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 161cc018230f5..b946f889c4fe3 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -11050,6 +11050,9 @@ static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_hw_group *ag, ar->pdev_idx = pdev_idx; pdev->ar = ar; + ag->hw_links[ar->hw_link_id].device_id = ab->device_id; + ag->hw_links[ar->hw_link_id].pdev_idx = pdev_idx; + ath12k_mac_setup(ar); ath12k_dp_pdev_pre_alloc(ar); } From 1d18b197bc4b9884c3b53945356afe054b5340f4 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Mon, 9 Dec 2024 20:54:14 +0200 Subject: [PATCH 13/60] wifi: ath12k: add partner device buffer support in receive data path Currently, partner device buffer is not handled in the receive data path. In Multi-Link Operation, the partner device buffer is reported to the primary upper MAC rings. Therefore, add partner device buffer processing in the REO and Exception ring handler. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241209185421.376381-3-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.h | 6 + drivers/net/wireless/ath/ath12k/dp.c | 1 + drivers/net/wireless/ath/ath12k/dp.h | 3 +- drivers/net/wireless/ath/ath12k/dp_rx.c | 179 +++++++++++++++++------- 4 files changed, 140 insertions(+), 49 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 9386e9592dff7..d7caa58bb262d 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -1229,4 +1229,10 @@ static inline void ath12k_core_stopped(struct ath12k_base *ab) ab->ag->num_started--; } +static inline struct ath12k_base *ath12k_ag_to_ab(struct ath12k_hw_group *ag, + u8 device_id) +{ + return ag->ab[device_id]; +} + #endif /* _CORE_H_ */ diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index 68abe9d4ab45c..9a7df54bf5709 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -1445,6 +1445,7 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) { rx_descs[j].cookie = ath12k_dp_cc_cookie_gen(cookie_ppt_idx, j); rx_descs[j].magic = ATH12K_DP_RX_DESC_MAGIC; + rx_descs[j].device_id = ab->device_id; list_add_tail(&rx_descs[j].list, &dp->rx_desc_free_list); /* Update descriptor VA in SPT */ diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index 021cd9e8ee1d3..d3f3d39a1cd0f 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -287,7 +287,8 @@ struct ath12k_rx_desc_info { u32 cookie; u32 magic; u8 in_use : 1, - reserved : 7; + device_id : 3, + reserved : 4; }; struct ath12k_tx_desc_info { diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index b68ceb403866f..899a25f5994db 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -2601,6 +2601,7 @@ static void ath12k_dp_rx_process_received_packets(struct ath12k_base *ab, struct sk_buff *msdu; struct ath12k *ar; struct ath12k_hw_link *hw_links = ag->hw_links; + struct ath12k_base *partner_ab; u8 hw_link_id, pdev_id; int ret; @@ -2612,11 +2613,12 @@ static void ath12k_dp_rx_process_received_packets(struct ath12k_base *ab, while ((msdu = __skb_dequeue(msdu_list))) { rxcb = ATH12K_SKB_RXCB(msdu); hw_link_id = rxcb->hw_link_id; - - pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, + partner_ab = ath12k_ag_to_ab(ag, + hw_links[hw_link_id].device_id); + pdev_id = ath12k_hw_mac_id_to_pdev_id(partner_ab->hw_params, hw_links[hw_link_id].pdev_idx); - ar = ab->pdevs[pdev_id].ar; - if (!rcu_dereference(ab->pdevs_active[pdev_id])) { + ar = partner_ab->pdevs[pdev_id].ar; + if (!rcu_dereference(partner_ab->pdevs_active[pdev_id])) { dev_kfree_skb_any(msdu); continue; } @@ -2666,23 +2668,29 @@ static u16 ath12k_dp_rx_get_peer_id(struct ath12k_base *ab, int ath12k_dp_rx_process(struct ath12k_base *ab, int ring_id, struct napi_struct *napi, int budget) { - LIST_HEAD(rx_desc_used_list); + struct ath12k_hw_group *ag = ab->ag; + struct list_head rx_desc_used_list[ATH12K_MAX_SOCS]; + struct ath12k_hw_link *hw_links = ag->hw_links; + int num_buffs_reaped[ATH12K_MAX_SOCS] = {}; struct ath12k_rx_desc_info *desc_info; struct ath12k_dp *dp = &ab->dp; struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; struct hal_reo_dest_ring *desc; - int num_buffs_reaped = 0; + struct ath12k_base *partner_ab; struct sk_buff_head msdu_list; struct ath12k_skb_rxcb *rxcb; int total_msdu_reaped = 0; + u8 hw_link_id, device_id; struct hal_srng *srng; struct sk_buff *msdu; bool done = false; - u8 hw_link_id; u64 desc_va; __skb_queue_head_init(&msdu_list); + for (device_id = 0; device_id < ATH12K_MAX_SOCS; device_id++) + INIT_LIST_HEAD(&rx_desc_used_list[device_id]); + srng = &ab->hal.srng_list[dp->reo_dst_ring[ring_id].ring_id]; spin_lock_bh(&srng->lock); @@ -2706,11 +2714,22 @@ int ath12k_dp_rx_process(struct ath12k_base *ab, int ring_id, le32_to_cpu(desc->buf_va_lo)); desc_info = (struct ath12k_rx_desc_info *)((unsigned long)desc_va); + device_id = hw_links[hw_link_id].device_id; + partner_ab = ath12k_ag_to_ab(ag, device_id); + if (unlikely(!partner_ab)) { + if (desc_info->skb) { + dev_kfree_skb_any(desc_info->skb); + desc_info->skb = NULL; + } + + continue; + } + /* retry manual desc retrieval */ if (!desc_info) { - desc_info = ath12k_dp_get_rx_desc(ab, cookie); + desc_info = ath12k_dp_get_rx_desc(partner_ab, cookie); if (!desc_info) { - ath12k_warn(ab, "Invalid cookie in manual descriptor retrieval: 0x%x\n", + ath12k_warn(partner_ab, "Invalid cookie in manual descriptor retrieval: 0x%x\n", cookie); continue; } @@ -2722,14 +2741,14 @@ int ath12k_dp_rx_process(struct ath12k_base *ab, int ring_id, msdu = desc_info->skb; desc_info->skb = NULL; - list_add_tail(&desc_info->list, &rx_desc_used_list); + list_add_tail(&desc_info->list, &rx_desc_used_list[device_id]); rxcb = ATH12K_SKB_RXCB(msdu); - dma_unmap_single(ab->dev, rxcb->paddr, + dma_unmap_single(partner_ab->dev, rxcb->paddr, msdu->len + skb_tailroom(msdu), DMA_FROM_DEVICE); - num_buffs_reaped++; + num_buffs_reaped[device_id]++; push_reason = le32_get_bits(desc->info0, HAL_REO_DEST_RING_INFO0_PUSH_REASON); @@ -2786,8 +2805,17 @@ int ath12k_dp_rx_process(struct ath12k_base *ab, int ring_id, if (!total_msdu_reaped) goto exit; - ath12k_dp_rx_bufs_replenish(ab, rx_ring, &rx_desc_used_list, - num_buffs_reaped); + for (device_id = 0; device_id < ATH12K_MAX_SOCS; device_id++) { + if (!num_buffs_reaped[device_id]) + continue; + + partner_ab = ath12k_ag_to_ab(ag, device_id); + rx_ring = &partner_ab->dp.rx_refill_buf_ring; + + ath12k_dp_rx_bufs_replenish(partner_ab, rx_ring, + &rx_desc_used_list[device_id], + num_buffs_reaped[device_id]); + } ath12k_dp_rx_process_received_packets(ab, napi, &msdu_list, ring_id); @@ -3478,7 +3506,9 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, int budget) { struct ath12k_hw_group *ag = ab->ag; + struct list_head rx_desc_used_list[ATH12K_MAX_SOCS]; u32 msdu_cookies[HAL_NUM_RX_MSDUS_PER_LINK_DESC]; + int num_buffs_reaped[ATH12K_MAX_SOCS] = {}; struct dp_link_desc_bank *link_desc_banks; enum hal_rx_buf_return_buf_manager rbm; struct hal_rx_msdu_link *link_desc_va; @@ -3487,11 +3517,10 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, struct dp_rxdma_ring *rx_ring; struct dp_srng *reo_except; struct ath12k_hw_link *hw_links = ag->hw_links; - LIST_HEAD(rx_desc_used_list); + struct ath12k_base *partner_ab; + u8 hw_link_id, device_id; u32 desc_bank, num_msdus; struct hal_srng *srng; - struct ath12k_dp *dp; - u8 hw_link_id; struct ath12k *ar; dma_addr_t paddr; bool is_frag; @@ -3501,9 +3530,10 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, tot_n_bufs_reaped = 0; quota = budget; - dp = &ab->dp; - reo_except = &dp->reo_except_ring; - link_desc_banks = dp->link_desc_banks; + for (device_id = 0; device_id < ATH12K_MAX_SOCS; device_id++) + INIT_LIST_HEAD(&rx_desc_used_list[device_id]); + + reo_except = &ab->dp.reo_except_ring; srng = &ab->hal.srng_list[reo_except->ring_id]; @@ -3526,21 +3556,24 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, hw_link_id = le32_get_bits(reo_desc->info0, HAL_REO_DEST_RING_INFO0_SRC_LINK_ID); + device_id = hw_links[hw_link_id].device_id; + partner_ab = ath12k_ag_to_ab(ag, device_id); - pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, + pdev_id = ath12k_hw_mac_id_to_pdev_id(partner_ab->hw_params, hw_links[hw_link_id].pdev_idx); - ar = ab->pdevs[pdev_id].ar; + ar = partner_ab->pdevs[pdev_id].ar; + link_desc_banks = partner_ab->dp.link_desc_banks; link_desc_va = link_desc_banks[desc_bank].vaddr + (paddr - link_desc_banks[desc_bank].paddr); ath12k_hal_rx_msdu_link_info_get(link_desc_va, &num_msdus, msdu_cookies, &rbm); - if (rbm != dp->idle_link_rbm && + if (rbm != partner_ab->dp.idle_link_rbm && rbm != HAL_RX_BUF_RBM_SW3_BM && - rbm != ab->hw_params->hal_params->rx_buf_rbm) { + rbm != partner_ab->hw_params->hal_params->rx_buf_rbm) { ab->soc_stats.invalid_rbm++; ath12k_warn(ab, "invalid return buffer manager %d\n", rbm); - ath12k_dp_rx_link_desc_return(ab, reo_desc, + ath12k_dp_rx_link_desc_return(partner_ab, reo_desc, HAL_WBM_REL_BM_ACT_REL_MSDU); continue; } @@ -3550,20 +3583,26 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, /* Process only rx fragments with one msdu per link desc below, and drop * msdu's indicated due to error reasons. + * Dynamic fragmentation not supported in Multi-link client, so drop the + * partner device buffers. */ - if (!is_frag || num_msdus > 1) { + if (!is_frag || num_msdus > 1 || + partner_ab->device_id != ab->device_id) { drop = true; + /* Return the link desc back to wbm idle list */ - ath12k_dp_rx_link_desc_return(ab, reo_desc, + ath12k_dp_rx_link_desc_return(partner_ab, reo_desc, HAL_WBM_REL_BM_ACT_PUT_IN_IDLE); } for (i = 0; i < num_msdus; i++) { if (!ath12k_dp_process_rx_err_buf(ar, reo_desc, - &rx_desc_used_list, + &rx_desc_used_list[device_id], drop, - msdu_cookies[i])) + msdu_cookies[i])) { + num_buffs_reaped[device_id]++; tot_n_bufs_reaped++; + } } if (tot_n_bufs_reaped >= quota) { @@ -3579,10 +3618,17 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, spin_unlock_bh(&srng->lock); - rx_ring = &dp->rx_refill_buf_ring; + for (device_id = 0; device_id < ATH12K_MAX_SOCS; device_id++) { + if (!num_buffs_reaped[device_id]) + continue; - ath12k_dp_rx_bufs_replenish(ab, rx_ring, &rx_desc_used_list, - tot_n_bufs_reaped); + partner_ab = ath12k_ag_to_ab(ag, device_id); + rx_ring = &partner_ab->dp.rx_refill_buf_ring; + + ath12k_dp_rx_bufs_replenish(partner_ab, rx_ring, + &rx_desc_used_list[device_id], + num_buffs_reaped[device_id]); + } return tot_n_bufs_reaped; } @@ -3799,7 +3845,8 @@ static void ath12k_dp_rx_wbm_err(struct ath12k *ar, int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, struct napi_struct *napi, int budget) { - LIST_HEAD(rx_desc_used_list); + struct list_head rx_desc_used_list[ATH12K_MAX_SOCS]; + struct ath12k_hw_group *ag = ab->ag; struct ath12k *ar; struct ath12k_dp *dp = &ab->dp; struct dp_rxdma_ring *rx_ring; @@ -3809,18 +3856,22 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, struct sk_buff_head msdu_list, scatter_msdu_list; struct ath12k_skb_rxcb *rxcb; void *rx_desc; - u8 hw_link_id; - int num_buffs_reaped = 0; + int num_buffs_reaped[ATH12K_MAX_SOCS] = {}; + int total_num_buffs_reaped = 0; struct ath12k_rx_desc_info *desc_info; - struct ath12k_hw_link *hw_links = ab->ag->hw_links; + struct ath12k_hw_link *hw_links = ag->hw_links; + struct ath12k_base *partner_ab; + u8 hw_link_id, device_id; int ret, pdev_id; struct hal_rx_desc *msdu_data; __skb_queue_head_init(&msdu_list); __skb_queue_head_init(&scatter_msdu_list); + for (device_id = 0; device_id < ATH12K_MAX_SOCS; device_id++) + INIT_LIST_HEAD(&rx_desc_used_list[device_id]); + srng = &ab->hal.srng_list[dp->rx_rel_ring.ring_id]; - rx_ring = &dp->rx_refill_buf_ring; spin_lock_bh(&srng->lock); ath12k_hal_srng_access_begin(ab, srng); @@ -3856,14 +3907,27 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, msdu = desc_info->skb; desc_info->skb = NULL; - list_add_tail(&desc_info->list, &rx_desc_used_list); + device_id = desc_info->device_id; + partner_ab = ath12k_ag_to_ab(ag, device_id); + if (unlikely(!partner_ab)) { + dev_kfree_skb_any(msdu); + + /* In any case continuation bit is set + * in the previous record, cleanup scatter_msdu_list + */ + ath12k_dp_clean_up_skb_list(&scatter_msdu_list); + continue; + } + + list_add_tail(&desc_info->list, &rx_desc_used_list[device_id]); rxcb = ATH12K_SKB_RXCB(msdu); - dma_unmap_single(ab->dev, rxcb->paddr, + dma_unmap_single(partner_ab->dev, rxcb->paddr, msdu->len + skb_tailroom(msdu), DMA_FROM_DEVICE); - num_buffs_reaped++; + num_buffs_reaped[device_id]++; + total_num_buffs_reaped++; if (!err_info.continuation) budget--; @@ -3887,9 +3951,9 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, continue; } - hw_link_id = ath12k_dp_rx_get_msdu_src_link(ab, + hw_link_id = ath12k_dp_rx_get_msdu_src_link(partner_ab, msdu_data); - if (hw_link_id >= MAX_RADIOS) { + if (hw_link_id >= ATH12K_GROUP_MAX_RADIO) { dev_kfree_skb_any(msdu); /* In any case continuation bit is set @@ -3925,20 +3989,39 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, spin_unlock_bh(&srng->lock); - if (!num_buffs_reaped) + if (!total_num_buffs_reaped) goto done; - ath12k_dp_rx_bufs_replenish(ab, rx_ring, &rx_desc_used_list, - num_buffs_reaped); + for (device_id = 0; device_id < ATH12K_MAX_SOCS; device_id++) { + if (!num_buffs_reaped[device_id]) + continue; + + partner_ab = ath12k_ag_to_ab(ag, device_id); + rx_ring = &partner_ab->dp.rx_refill_buf_ring; + + ath12k_dp_rx_bufs_replenish(ab, rx_ring, + &rx_desc_used_list[device_id], + num_buffs_reaped[device_id]); + } rcu_read_lock(); while ((msdu = __skb_dequeue(&msdu_list))) { rxcb = ATH12K_SKB_RXCB(msdu); hw_link_id = rxcb->hw_link_id; - pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, + device_id = hw_links[hw_link_id].device_id; + partner_ab = ath12k_ag_to_ab(ag, device_id); + if (unlikely(!partner_ab)) { + ath12k_dbg(ab, ATH12K_DBG_DATA, + "Unable to process WBM error msdu due to invalid hw link id %d device id %d\n", + hw_link_id, device_id); + dev_kfree_skb_any(msdu); + continue; + } + + pdev_id = ath12k_hw_mac_id_to_pdev_id(partner_ab->hw_params, hw_links[hw_link_id].pdev_idx); - ar = ab->pdevs[pdev_id].ar; + ar = partner_ab->pdevs[pdev_id].ar; if (!ar || !rcu_dereference(ar->ab->pdevs_active[hw_link_id])) { dev_kfree_skb_any(msdu); @@ -3953,7 +4036,7 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, } rcu_read_unlock(); done: - return num_buffs_reaped; + return total_num_buffs_reaped; } void ath12k_dp_rx_process_reo_status(struct ath12k_base *ab) From 555872c477958e1a12244e79f3ef9f976ca2a077 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Mon, 9 Dec 2024 20:54:15 +0200 Subject: [PATCH 14/60] wifi: ath12k: add helper function to init partner cmem configuration In the Inter Multi-Link Operation, the primary device is expected to receive the partner device buffer. Therefore, each device initializes the partner device buffer in their cmem configuration. So add a helper function to initialize the partner device buffer in their cmem configuration. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241209185421.376381-4-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.c | 5 ++++- drivers/net/wireless/ath/ath12k/dp.c | 13 +++++++++++++ drivers/net/wireless/ath/ath12k/dp.h | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index af642b466ea0d..ff79cb910523a 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -930,7 +930,7 @@ int ath12k_mac_mlo_ready(struct ath12k_hw_group *ag) static int ath12k_core_mlo_setup(struct ath12k_hw_group *ag) { - int ret; + int ret, i; if (!ag->mlo_capable || ag->num_devices == 1) return 0; @@ -939,6 +939,9 @@ static int ath12k_core_mlo_setup(struct ath12k_hw_group *ag) if (ret) return ret; + for (i = 0; i < ag->num_devices; i++) + ath12k_dp_partner_cc_init(ag->ab[i]); + ret = ath12k_mac_mlo_ready(ag); if (ret) goto err_mlo_teardown; diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index 9a7df54bf5709..9e5a4e75f2f62 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -1522,6 +1522,19 @@ static int ath12k_dp_cmem_init(struct ath12k_base *ab, return 0; } +void ath12k_dp_partner_cc_init(struct ath12k_base *ab) +{ + struct ath12k_hw_group *ag = ab->ag; + int i; + + for (i = 0; i < ag->num_devices; i++) { + if (ag->ab[i] == ab) + continue; + + ath12k_dp_cmem_init(ab, &ag->ab[i]->dp, ATH12K_DP_RX_DESC); + } +} + static int ath12k_dp_cc_init(struct ath12k_base *ab) { struct ath12k_dp *dp = &ab->dp; diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index d3f3d39a1cd0f..7700828375e3e 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -1806,6 +1806,7 @@ void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_link_vif *arvif); void ath12k_dp_free(struct ath12k_base *ab); int ath12k_dp_alloc(struct ath12k_base *ab); void ath12k_dp_cc_config(struct ath12k_base *ab); +void ath12k_dp_partner_cc_init(struct ath12k_base *ab); int ath12k_dp_pdev_alloc(struct ath12k_base *ab); void ath12k_dp_pdev_pre_alloc(struct ath12k *ar); void ath12k_dp_pdev_free(struct ath12k_base *ab); From 8fea0066b4b481bd604256f5359127837a5db7ce Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Mon, 9 Dec 2024 20:54:16 +0200 Subject: [PATCH 15/60] wifi: ath12k: introduce interface combination cleanup helper Introduce a cleanup helper function to avoid redundant code for interface combination cleanup. Remove the cleanup code from ath12k_mac_hw_unregister() and ath12k_mac_hw_register() and replace it with a new cleanup helper function. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Acked-by: Jeff Johnson Link: https://patch.msgid.link/20241209185421.376381-5-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index b946f889c4fe3..808af521c57c1 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -10351,6 +10351,14 @@ static bool ath12k_mac_is_iface_mode_enable(struct ath12k_hw *ah, return is_enable; } +static void ath12k_mac_cleanup_iface_combinations(struct ath12k_hw *ah) +{ + struct wiphy *wiphy = ah->hw->wiphy; + + kfree(wiphy->iface_combinations[0].limits); + kfree(wiphy->iface_combinations); +} + static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah) { struct wiphy *wiphy = ah->hw->wiphy; @@ -10479,7 +10487,6 @@ static void ath12k_mac_cleanup_unregister(struct ath12k *ar) static void ath12k_mac_hw_unregister(struct ath12k_hw *ah) { struct ieee80211_hw *hw = ah->hw; - struct wiphy *wiphy = hw->wiphy; struct ath12k *ar; int i; @@ -10493,8 +10500,7 @@ static void ath12k_mac_hw_unregister(struct ath12k_hw *ah) for_each_ar(ah, ar, i) ath12k_mac_cleanup_unregister(ar); - kfree(wiphy->iface_combinations[0].limits); - kfree(wiphy->iface_combinations); + ath12k_mac_cleanup_iface_combinations(ah); SET_IEEE80211_DEV(hw, NULL); } @@ -10724,13 +10730,13 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) ret = ath12k_wow_init(ar); if (ret) { ath12k_warn(ar->ab, "failed to init wow: %d\n", ret); - goto err_free_if_combs; + goto err_cleanup_if_combs; } ret = ieee80211_register_hw(hw); if (ret) { ath12k_err(ab, "ieee80211 registration failed: %d\n", ret); - goto err_free_if_combs; + goto err_cleanup_if_combs; } if (is_monitor_disable) @@ -10760,9 +10766,8 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) ieee80211_unregister_hw(hw); -err_free_if_combs: - kfree(wiphy->iface_combinations[0].limits); - kfree(wiphy->iface_combinations); +err_cleanup_if_combs: + ath12k_mac_cleanup_iface_combinations(ah); err_complete_cleanup_unregister: i = ah->num_radio; From 3c9bc818b8f192142280b722fa53e2389491a6d1 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Mon, 9 Dec 2024 20:54:17 +0200 Subject: [PATCH 16/60] wifi: ath12k: Refactor radio frequency information Currently, radio stores the low frequency and high frequency information as separate variables. However, cfg80211 already provides a suitable data structure struct wiphy_radio_freq_range to store this information efficiently. Additionally, for multi radio per wiphy infrastructure, this frequency range information is essential. In future patches using struct wiphy_radio_freq_range makes the code simpler. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241209185421.376381-6-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.h | 3 +-- drivers/net/wireless/ath/ath12k/mac.c | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index d7caa58bb262d..d09ebcdde94fd 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -711,8 +711,7 @@ struct ath12k { bool monitor_started; int monitor_vdev_id; - u32 freq_low; - u32 freq_high; + struct wiphy_radio_freq_range freq_range; bool nlo_enabled; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 808af521c57c1..504ad36caca9e 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -708,8 +708,8 @@ static struct ath12k *ath12k_mac_get_ar_by_chan(struct ieee80211_hw *hw, return ar; for_each_ar(ah, ar, i) { - if (channel->center_freq >= ar->freq_low && - channel->center_freq <= ar->freq_high) + if (channel->center_freq >= KHZ_TO_MHZ(ar->freq_range.start_freq) && + channel->center_freq <= KHZ_TO_MHZ(ar->freq_range.end_freq)) return ar; } return NULL; @@ -10203,8 +10203,8 @@ static void ath12k_mac_update_ch_list(struct ath12k *ar, band->channels[i].flags |= IEEE80211_CHAN_DISABLED; } - ar->freq_low = freq_low; - ar->freq_high = freq_high; + ar->freq_range.start_freq = MHZ_TO_KHZ(freq_low); + ar->freq_range.end_freq = MHZ_TO_KHZ(freq_high); } static u32 ath12k_get_phy_id(struct ath12k *ar, u32 band) From ae6b065282abd5cb097fbe96bfb96fa29a9fc321 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Mon, 9 Dec 2024 20:54:18 +0200 Subject: [PATCH 17/60] wifi: ath12k: advertise multi device interface combination The prerequisite for MLO support in cfg80211/mac80211 requires that all the links participating in MLO belong to the same wiphy/struct ieee80211_hw. The driver needs to group multiple discrete hardware components, each acting as a link in MLO, under one wiphy. Consequently, the driver advertises multi-hardware device interface combination capabilities specific to the radio, including supported frequencies. The global interface combination represent the combined interface capabilities. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241209185421.376381-7-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 222 +++++++++++++++++++++----- 1 file changed, 185 insertions(+), 37 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 504ad36caca9e..705e0b6734358 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -10336,14 +10336,20 @@ static bool ath12k_mac_is_iface_mode_enable(struct ath12k_hw *ah, { struct ath12k *ar; int i; - u16 interface_modes, mode; - bool is_enable = true; + u16 interface_modes, mode = 0; + bool is_enable = false; + + if (type == NL80211_IFTYPE_MESH_POINT) { + if (IS_ENABLED(CONFIG_MAC80211_MESH)) + mode = BIT(type); + } else { + mode = BIT(type); + } - mode = BIT(type); for_each_ar(ah, ar, i) { interface_modes = ar->ab->hw_params->interface_modes; - if (!(interface_modes & mode)) { - is_enable = false; + if (interface_modes & mode) { + is_enable = true; break; } } @@ -10351,31 +10357,20 @@ static bool ath12k_mac_is_iface_mode_enable(struct ath12k_hw *ah, return is_enable; } -static void ath12k_mac_cleanup_iface_combinations(struct ath12k_hw *ah) -{ - struct wiphy *wiphy = ah->hw->wiphy; - - kfree(wiphy->iface_combinations[0].limits); - kfree(wiphy->iface_combinations); -} - -static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah) +static int +ath12k_mac_setup_radio_iface_comb(struct ath12k *ar, + struct ieee80211_iface_combination *comb) { - struct wiphy *wiphy = ah->hw->wiphy; - struct ieee80211_iface_combination *combinations; + u16 interface_modes = ar->ab->hw_params->interface_modes; struct ieee80211_iface_limit *limits; int n_limits, max_interfaces; bool ap, mesh, p2p; - ap = ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_AP); - p2p = ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_P2P_DEVICE); + ap = interface_modes & BIT(NL80211_IFTYPE_AP); + p2p = interface_modes & BIT(NL80211_IFTYPE_P2P_DEVICE); mesh = IS_ENABLED(CONFIG_MAC80211_MESH) && - ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_MESH_POINT); - - combinations = kzalloc(sizeof(*combinations), GFP_KERNEL); - if (!combinations) - return -ENOMEM; + (interface_modes & BIT(NL80211_IFTYPE_MESH_POINT)); if ((ap || mesh) && !p2p) { n_limits = 2; @@ -10392,10 +10387,8 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah) } limits = kcalloc(n_limits, sizeof(*limits), GFP_KERNEL); - if (!limits) { - kfree(combinations); + if (!limits) return -ENOMEM; - } limits[0].max = 1; limits[0].types |= BIT(NL80211_IFTYPE_STATION); @@ -10411,26 +10404,181 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah) if (p2p) { limits[1].types |= BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_P2P_GO); + BIT(NL80211_IFTYPE_P2P_GO); limits[2].max = 1; limits[2].types |= BIT(NL80211_IFTYPE_P2P_DEVICE); } - combinations[0].limits = limits; - combinations[0].n_limits = n_limits; - combinations[0].max_interfaces = max_interfaces; - combinations[0].num_different_channels = 1; - combinations[0].beacon_int_infra_match = true; - combinations[0].beacon_int_min_gcd = 100; - combinations[0].radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | - BIT(NL80211_CHAN_WIDTH_20) | - BIT(NL80211_CHAN_WIDTH_40) | - BIT(NL80211_CHAN_WIDTH_80); + comb[0].limits = limits; + comb[0].n_limits = n_limits; + comb[0].max_interfaces = max_interfaces; + comb[0].num_different_channels = 1; + comb[0].beacon_int_infra_match = true; + comb[0].beacon_int_min_gcd = 100; + comb[0].radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80); + + return 0; +} + +static int +ath12k_mac_setup_global_iface_comb(struct ath12k_hw *ah, + struct wiphy_radio *radio, + u8 n_radio, + struct ieee80211_iface_combination *comb) +{ + const struct ieee80211_iface_combination *iter_comb; + struct ieee80211_iface_limit *limits; + int i, j, n_limits; + bool ap, mesh, p2p; + + if (!n_radio) + return 0; + + ap = ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_AP); + p2p = ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_P2P_DEVICE); + mesh = ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_MESH_POINT); + + if ((ap || mesh) && !p2p) + n_limits = 2; + else if (p2p) + n_limits = 3; + else + n_limits = 1; + + limits = kcalloc(n_limits, sizeof(*limits), GFP_KERNEL); + if (!limits) + return -ENOMEM; + + for (i = 0; i < n_radio; i++) { + iter_comb = radio[i].iface_combinations; + for (j = 0; j < iter_comb->n_limits && j < n_limits; j++) { + limits[j].types |= iter_comb->limits[j].types; + limits[j].max += iter_comb->limits[j].max; + } + + comb->max_interfaces += iter_comb->max_interfaces; + comb->num_different_channels += iter_comb->num_different_channels; + comb->radar_detect_widths |= iter_comb->radar_detect_widths; + } + + comb->limits = limits; + comb->n_limits = n_limits; + comb->beacon_int_infra_match = true; + comb->beacon_int_min_gcd = 100; + + return 0; +} + +static +void ath12k_mac_cleanup_iface_comb(const struct ieee80211_iface_combination *iface_comb) +{ + kfree(iface_comb[0].limits); + kfree(iface_comb); +} + +static void ath12k_mac_cleanup_iface_combinations(struct ath12k_hw *ah) +{ + struct wiphy *wiphy = ah->hw->wiphy; + const struct wiphy_radio *radio; + int i; + + if (wiphy->n_radio > 0) { + radio = wiphy->radio; + for (i = 0; i < wiphy->n_radio; i++) + ath12k_mac_cleanup_iface_comb(radio[i].iface_combinations); + + kfree(wiphy->radio); + } + + ath12k_mac_cleanup_iface_comb(wiphy->iface_combinations); +} + +static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah) +{ + struct ieee80211_iface_combination *combinations, *comb; + struct wiphy *wiphy = ah->hw->wiphy; + struct wiphy_radio *radio; + struct ath12k *ar; + int i, ret; + + combinations = kzalloc(sizeof(*combinations), GFP_KERNEL); + if (!combinations) + return -ENOMEM; + + if (ah->num_radio == 1) { + ret = ath12k_mac_setup_radio_iface_comb(&ah->radio[0], + combinations); + if (ret) { + ath12k_hw_warn(ah, "failed to setup radio interface combinations for one radio: %d", + ret); + goto err_free_combinations; + } + + goto out; + } + + /* there are multiple radios */ + radio = kcalloc(ah->num_radio, sizeof(*radio), GFP_KERNEL); + if (!radio) { + ret = -ENOMEM; + goto err_free_combinations; + } + + for_each_ar(ah, ar, i) { + comb = kzalloc(sizeof(*comb), GFP_KERNEL); + if (!comb) { + ret = -ENOMEM; + goto err_free_radios; + } + + ret = ath12k_mac_setup_radio_iface_comb(ar, comb); + if (ret) { + ath12k_hw_warn(ah, "failed to setup radio interface combinations for radio %d: %d", + i, ret); + kfree(comb); + goto err_free_radios; + } + + radio[i].freq_range = &ar->freq_range; + radio[i].n_freq_range = 1; + + radio[i].iface_combinations = comb; + radio[i].n_iface_combinations = 1; + } + + ret = ath12k_mac_setup_global_iface_comb(ah, radio, ah->num_radio, combinations); + if (ret) { + ath12k_hw_warn(ah, "failed to setup global interface combinations: %d", + ret); + goto err_free_all_radios; + } + + wiphy->radio = radio; + wiphy->n_radio = ah->num_radio; + +out: wiphy->iface_combinations = combinations; wiphy->n_iface_combinations = 1; return 0; + +err_free_all_radios: + i = ah->num_radio; + +err_free_radios: + while (i--) + ath12k_mac_cleanup_iface_comb(radio[i].iface_combinations); + + kfree(radio); + +err_free_combinations: + kfree(combinations); + + return ret; } static const u8 ath12k_if_types_ext_capa[] = { From 78cf6fd16572912fb3f39237fb29879ccefb5a17 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Mon, 9 Dec 2024 20:54:19 +0200 Subject: [PATCH 18/60] wifi: ath12k: fix ath12k_qmi_alloc_chunk() to handle too large allocations If the requested memory chunk is too large, an error message is logged, but the request continues to be processed. However, no actual memory is allocated to the firmware from this request. Instead, the firmware sends another request with smaller chunks, where memory will be allocated accordingly. Therefore, it is pointless to proceed with parsing the request if at least one of the requests cannot be fulfilled. Hence, return -EAGAIN immediately and proceed to process the new request. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Aditya Kumar Singh Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241209185421.376381-8-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/qmi.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index e7846aaca10a5..964d350be748a 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -2497,7 +2497,7 @@ static int ath12k_qmi_alloc_chunk(struct ath12k_base *ab, chunk->size, chunk->type); ath12k_qmi_free_target_mem_chunk(ab); - return 0; + return -EAGAIN; } ath12k_warn(ab, "memory allocation failure for %u size: %d\n", chunk->type, chunk->size); @@ -2600,6 +2600,14 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab) mutex_unlock(&ag->mutex); + /* The firmware will attempt to request memory in smaller chunks + * on the next try. However, the current caller should be notified + * that this instance of request parsing was successful. + * Therefore, return 0 only. + */ + if (ret == -EAGAIN) + ret = 0; + return ret; } From 72c24b1b779d78674842012f252913c0b5beda73 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Mon, 9 Dec 2024 20:54:20 +0200 Subject: [PATCH 19/60] wifi: ath12k: fix ar->supports_6ghz usage during hw register In the ath12k_mac_hw_register() function's context, ar is an iterator variable, and there is no assurance that the last ar will be the one with 6 GHz enabled. Therefore, checking directly ar->supports_6ghz outside the loop is not appropriate. Additionally, 6 GHz lacks HT capabilities. To obtain the super set of HT capabilities across all grouped radios, 6 GHz should be excluded. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Aditya Kumar Singh Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241209185421.376381-9-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 705e0b6734358..e3848485d029e 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -10723,7 +10723,10 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) if (ret) goto err_cleanup_unregister; - ht_cap &= ht_cap_info; + /* 6 GHz does not support HT Cap, hence do not consider it */ + if (!ar->supports_6ghz) + ht_cap &= ht_cap_info; + wiphy->max_ap_assoc_sta += ar->max_num_stations; /* Advertise the max antenna support of all radios, driver can handle @@ -10787,7 +10790,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) ieee80211_hw_set(hw, SUPPORTS_TX_FRAG); ieee80211_hw_set(hw, REPORTS_LOW_ACK); - if ((ht_cap & WMI_HT_CAP_ENABLED) || ar->supports_6ghz) { + if ((ht_cap & WMI_HT_CAP_ENABLED) || is_6ghz) { ieee80211_hw_set(hw, AMPDU_AGGREGATION); ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW); ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); @@ -10803,7 +10806,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) * handle it when the ht capability different for each band. */ if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS || - (ar->supports_6ghz && ab->hw_params->supports_dynamic_smps_6ghz)) + (is_6ghz && ab->hw_params->supports_dynamic_smps_6ghz)) wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS; wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID; From 7462d67c660f52396e0bc5b3e13cc5c3a4dc01c3 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Mon, 9 Dec 2024 20:54:21 +0200 Subject: [PATCH 20/60] wifi: ath12k: pass link ID during MLO while delivering skb mac80211 expects link_id in some scenarios or else the packet might get dropped. Hence, add link_id information before delivering the skb. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Aditya Kumar Singh Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241209185421.376381-10-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/dp_mon.c | 8 +++++++- drivers/net/wireless/ath/ath12k/dp_rx.c | 5 +++++ drivers/net/wireless/ath/ath12k/peer.c | 2 ++ drivers/net/wireless/ath/ath12k/peer.h | 3 +++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index 494984133a919..2d53404095d6b 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -1093,8 +1093,14 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct decap = ath12k_dp_rx_h_decap_type(ar->ab, rxcb->rx_desc); spin_lock_bh(&ar->ab->base_lock); peer = ath12k_dp_rx_h_find_peer(ar->ab, msdu); - if (peer && peer->sta) + if (peer && peer->sta) { pubsta = peer->sta; + if (pubsta->valid_links) { + status->link_valid = 1; + status->link_id = peer->link_id; + } + } + spin_unlock_bh(&ar->ab->base_lock); ath12k_dbg(ar->ab, ATH12K_DBG_DATA, diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 899a25f5994db..66367bfb4acc9 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -2474,6 +2474,11 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap pubsta = peer ? peer->sta : NULL; + if (pubsta && pubsta->valid_links) { + status->link_valid = 1; + status->link_id = peer->link_id; + } + spin_unlock_bh(&ab->base_lock); ath12k_dbg(ab, ATH12K_DBG_DATA, diff --git a/drivers/net/wireless/ath/ath12k/peer.c b/drivers/net/wireless/ath/ath12k/peer.c index 5763c5a40cfc3..792cca8a3fb1b 100644 --- a/drivers/net/wireless/ath/ath12k/peer.c +++ b/drivers/net/wireless/ath/ath12k/peer.c @@ -388,6 +388,8 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif, arsta = wiphy_dereference(ath12k_ar_to_hw(ar)->wiphy, ahsta->link[link_id]); + peer->link_id = arsta->link_id; + /* Fill ML info into created peer */ if (sta->mlo) { ml_peer_id = ahsta->ml_peer_id; diff --git a/drivers/net/wireless/ath/ath12k/peer.h b/drivers/net/wireless/ath/ath12k/peer.h index 7e6231cb2b529..5870ee11a8c7e 100644 --- a/drivers/net/wireless/ath/ath12k/peer.h +++ b/drivers/net/wireless/ath/ath12k/peer.h @@ -59,6 +59,9 @@ struct ath12k_peer { /* To ensure only certain work related to dp is done once */ bool primary_link; + + /* for reference to ath12k_link_sta */ + u8 link_id; }; struct ath12k_ml_peer { From 3863f014ad23f1f966b78e8fe6f4cbed97fd4737 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Wed, 11 Dec 2024 17:43:52 +0200 Subject: [PATCH 21/60] wifi: ath12k: symmetrize scan vdev creation and deletion during HW scan Currently, the hardware scan is initiated in the driver on scan link (15). After mapping to the appropriate radio based on the scan frequency, the vdev is created and the scan begins. However, the vdev is only deleted when channel assignment is about to occur after the scan. Additionally, it is also deleted if a new scan is requested on the same interface but the underlying radio differs in the new request. This imbalance leads to various hardware scan issues, especially when a non-MLO and MLO combination exists. In such cases, the latter tries to skip the scan and proceed with channel assignment while the former is still scanning, causing a firmware assert. To address this issue, symmetrize the scan vdev creation and deletion during hardware scan operations. This means creating a vdev when the scan starts and deleting it once the scan is completed or aborted. While at this, add a few debug prints in scan handling and a few empty lines for better code read. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Aditya Kumar Singh Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241211154358.776279-2-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.h | 3 +- drivers/net/wireless/ath/ath12k/mac.c | 120 +++++++++++++++++++------ drivers/net/wireless/ath/ath12k/wmi.c | 3 +- 3 files changed, 99 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index d09ebcdde94fd..9aed245975482 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -603,9 +603,10 @@ struct ath12k { struct delayed_work timeout; enum ath12k_scan_state state; bool is_roc; - int vdev_id; int roc_freq; bool roc_notify; + struct wiphy_work vdev_clean_wk; + struct ath12k_link_vif *arvif; } scan; struct { diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index e3848485d029e..1bd63b53408c8 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -4000,22 +4000,9 @@ void __ath12k_mac_scan_finish(struct ath12k *ar) ieee80211_remain_on_channel_expired(hw); fallthrough; case ATH12K_SCAN_STARTING: - if (!ar->scan.is_roc) { - struct cfg80211_scan_info info = { - .aborted = ((ar->scan.state == - ATH12K_SCAN_ABORTING) || - (ar->scan.state == - ATH12K_SCAN_STARTING)), - }; - - ieee80211_scan_completed(hw, &info); - } - - ar->scan.state = ATH12K_SCAN_IDLE; - ar->scan_channel = NULL; - ar->scan.roc_freq = 0; cancel_delayed_work(&ar->scan.timeout); complete(&ar->scan.completed); + wiphy_work_queue(ar->ah->hw->wiphy, &ar->scan.vdev_clean_wk); break; } } @@ -4056,15 +4043,15 @@ static int ath12k_scan_stop(struct ath12k *ar) } out: - /* Scan state should be updated upon scan completion but in case - * firmware fails to deliver the event (for whatever reason) it is - * desired to clean up scan state anyway. Firmware may have just - * dropped the scan completion event delivery due to transport pipe - * being overflown with data and/or it can recover on its own before - * next scan request is submitted. + /* Scan state should be updated in scan completion worker but in + * case firmware fails to deliver the event (for whatever reason) + * it is desired to clean up scan state anyway. Firmware may have + * just dropped the scan completion event delivery due to transport + * pipe being overflown with data and/or it can recover on its own + * before next scan request is submitted. */ spin_lock_bh(&ar->data_lock); - if (ar->scan.state != ATH12K_SCAN_IDLE) + if (ret) __ath12k_mac_scan_finish(ar); spin_unlock_bh(&ar->data_lock); @@ -4115,6 +4102,53 @@ static void ath12k_scan_timeout_work(struct work_struct *work) wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy); } +static void ath12k_scan_vdev_clean_work(struct wiphy *wiphy, struct wiphy_work *work) +{ + struct ath12k *ar = container_of(work, struct ath12k, + scan.vdev_clean_wk); + struct ath12k_hw *ah = ar->ah; + struct ath12k_link_vif *arvif; + + lockdep_assert_wiphy(wiphy); + + arvif = ar->scan.arvif; + + /* The scan vdev has already been deleted. This can occur when a + * new scan request is made on the same vif with a different + * frequency, causing the scan arvif to move from one radio to + * another. Or, scan was abrupted and via remove interface, the + * arvif is already deleted. Alternatively, if the scan vdev is not + * being used as an actual vdev, then do not delete it. + */ + if (!arvif || arvif->is_started) + goto work_complete; + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac clean scan vdev (link id %u)", + arvif->link_id); + + ath12k_mac_remove_link_interface(ah->hw, arvif); + ath12k_mac_unassign_link_vif(arvif); + +work_complete: + spin_lock_bh(&ar->data_lock); + ar->scan.arvif = NULL; + if (!ar->scan.is_roc) { + struct cfg80211_scan_info info = { + .aborted = ((ar->scan.state == + ATH12K_SCAN_ABORTING) || + (ar->scan.state == + ATH12K_SCAN_STARTING)), + }; + + ieee80211_scan_completed(ar->ah->hw, &info); + } + + ar->scan.state = ATH12K_SCAN_IDLE; + ar->scan_channel = NULL; + ar->scan.roc_freq = 0; + spin_unlock_bh(&ar->data_lock); +} + static int ath12k_start_scan(struct ath12k *ar, struct ath12k_wmi_scan_req_arg *arg) { @@ -4208,6 +4242,9 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, link_id = ath12k_mac_find_link_id_by_ar(ahvif, ar); arvif = ath12k_mac_assign_link_vif(ah, vif, link_id); + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac link ID %d selected for scan", + arvif->link_id); + /* If the vif is already assigned to a specific vdev of an ar, * check whether its already started, vdev which is started * are not allowed to switch to a new radio. @@ -4231,6 +4268,7 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, create = false; } } + if (create) { /* Previous arvif would've been cleared in radio switch block * above, assign arvif again for create. @@ -4251,7 +4289,7 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, reinit_completion(&ar->scan.completed); ar->scan.state = ATH12K_SCAN_STARTING; ar->scan.is_roc = false; - ar->scan.vdev_id = arvif->vdev_id; + ar->scan.arvif = arvif; ret = 0; break; case ATH12K_SCAN_STARTING: @@ -4313,6 +4351,8 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, spin_unlock_bh(&ar->data_lock); } + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac scan started"); + /* As per cfg80211/mac80211 scan design, it allows only one * scan at a time. Hence last_scan link id is used for * tracking the link id on which the scan is been done on @@ -4346,7 +4386,7 @@ static void ath12k_mac_op_cancel_hw_scan(struct ieee80211_hw *hw, lockdep_assert_wiphy(hw->wiphy); arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); - if (!arvif || !arvif->is_created) + if (!arvif || arvif->is_started) return; ar = arvif->ar; @@ -7404,6 +7444,7 @@ static void ath12k_mac_stop(struct ath12k *ar) clear_bit(ATH12K_CAC_RUNNING, &ar->dev_flags); cancel_delayed_work_sync(&ar->scan.timeout); + wiphy_work_cancel(ath12k_ar_to_hw(ar)->wiphy, &ar->scan.vdev_clean_wk); cancel_work_sync(&ar->regd_update_work); cancel_work_sync(&ar->ab->rfkill_work); @@ -8033,7 +8074,7 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw, scan_arvif = wiphy_dereference(hw->wiphy, ahvif->link[ATH12K_DEFAULT_SCAN_LINK]); if (scan_arvif && scan_arvif->ar == ar) { - ar->scan.vdev_id = -1; + ar->scan.arvif = NULL; ath12k_mac_remove_link_interface(hw, scan_arvif); ath12k_mac_unassign_link_vif(scan_arvif); } @@ -8234,6 +8275,7 @@ static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw, { struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); struct ath12k_link_vif *arvif; + struct ath12k *ar; u8 link_id; lockdep_assert_wiphy(hw->wiphy); @@ -8247,6 +8289,31 @@ static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw, if (!arvif || !arvif->is_created) continue; + ar = arvif->ar; + + /* Scan abortion is in progress since before this, cancel_hw_scan() + * is expected to be executed. Since link is anyways going to be removed + * now, just cancel the worker and send the scan aborted to user space + */ + if (ar->scan.arvif == arvif) { + wiphy_work_cancel(hw->wiphy, &ar->scan.vdev_clean_wk); + + spin_lock_bh(&ar->data_lock); + ar->scan.arvif = NULL; + if (!ar->scan.is_roc) { + struct cfg80211_scan_info info = { + .aborted = true, + }; + + ieee80211_scan_completed(ar->ah->hw, &info); + } + + ar->scan.state = ATH12K_SCAN_IDLE; + ar->scan_channel = NULL; + ar->scan.roc_freq = 0; + spin_unlock_bh(&ar->data_lock); + } + ath12k_mac_remove_link_interface(hw, arvif); ath12k_mac_unassign_link_vif(arvif); } @@ -9952,6 +10019,7 @@ static int ath12k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw, ath12k_scan_abort(ar); cancel_delayed_work_sync(&ar->scan.timeout); + wiphy_work_cancel(hw->wiphy, &ar->scan.vdev_clean_wk); return 0; } @@ -10035,7 +10103,7 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, reinit_completion(&ar->scan.on_channel); ar->scan.state = ATH12K_SCAN_STARTING; ar->scan.is_roc = true; - ar->scan.vdev_id = arvif->vdev_id; + ar->scan.arvif = arvif; ar->scan.roc_freq = chan->center_freq; ar->scan.roc_notify = true; ret = 0; @@ -10952,6 +11020,7 @@ static void ath12k_mac_setup(struct ath12k *ar) ar->cfg_rx_chainmask = pdev->cap.rx_chain_mask; ar->num_tx_chains = hweight32(pdev->cap.tx_chain_mask); ar->num_rx_chains = hweight32(pdev->cap.rx_chain_mask); + ar->scan.arvif = NULL; spin_lock_init(&ar->data_lock); INIT_LIST_HEAD(&ar->arvifs); @@ -10969,6 +11038,7 @@ static void ath12k_mac_setup(struct ath12k *ar) init_completion(&ar->mlo_setup_done); INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work); + wiphy_work_init(&ar->scan.vdev_clean_wk, ath12k_scan_vdev_clean_work); INIT_WORK(&ar->regd_update_work, ath12k_regd_update_work); wiphy_work_init(&ar->wmi_mgmt_tx_work, ath12k_mgmt_over_wmi_tx_work); diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 892cc4846e4fa..7bec414b0358a 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -6338,7 +6338,8 @@ static struct ath12k *ath12k_get_ar_on_scan_state(struct ath12k_base *ab, spin_lock_bh(&ar->data_lock); if (ar->scan.state == state && - ar->scan.vdev_id == vdev_id) { + ar->scan.arvif && + ar->scan.arvif->vdev_id == vdev_id) { spin_unlock_bh(&ar->data_lock); return ar; } From 6792b3ca14adb666a3c41628bac99227680eb871 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Wed, 11 Dec 2024 17:43:53 +0200 Subject: [PATCH 22/60] wifi: ath12k: add can_activate_links mac operation When operating as an ML station, mac80211 initially activates only one link in the driver until the peer is authorized. Once the state changes to authorized, the driver should call mac80211 API to activate all other partner links. Before doing so, mac80211 checks if the driver supports activating links via the can_activate_links mac80211_ops. Therefore, add support for this mac80211_ops and call the API to activate the links once the state changes to authorized. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Aditya Kumar Singh Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241211154358.776279-3-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 1bd63b53408c8..f7e505470f215 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5645,6 +5645,19 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, } } + /* In the ML station scenario, activate all partner links once the + * client is transitioning to the associated state. + * + * FIXME: Ideally, this activation should occur when the client + * transitions to the authorized state. However, there are some + * issues with handling this in the firmware. Until the firmware + * can manage it properly, activate the links when the client is + * about to move to the associated state. + */ + if (ieee80211_vif_is_mld(vif) && vif->type == NL80211_IFTYPE_STATION && + old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC) + ieee80211_set_active_links(vif, ieee80211_vif_usable_links(vif)); + /* Handle all the other state transitions in generic way */ valid_links = ahsta->links_map; for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) { @@ -5939,6 +5952,15 @@ static int ath12k_mac_op_change_sta_links(struct ieee80211_hw *hw, return 0; } +static bool ath12k_mac_op_can_activate_links(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u16 active_links) +{ + /* TODO: Handle recovery case */ + + return true; +} + static int ath12k_conf_tx_uapsd(struct ath12k_link_vif *arvif, u16 ac, bool enable) { @@ -10249,6 +10271,7 @@ static const struct ieee80211_ops ath12k_ops = { .remain_on_channel = ath12k_mac_op_remain_on_channel, .cancel_remain_on_channel = ath12k_mac_op_cancel_remain_on_channel, .change_sta_links = ath12k_mac_op_change_sta_links, + .can_activate_links = ath12k_mac_op_can_activate_links, #ifdef CONFIG_PM .suspend = ath12k_wow_op_suspend, .resume = ath12k_wow_op_resume, From 77478788c957d1d41462890f187c71f8babbd093 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Wed, 11 Dec 2024 17:43:54 +0200 Subject: [PATCH 23/60] wifi: ath12k: add no-op without debug print in WMI Rx event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, certain WMI events are frequently received by the host. Since the host lacks the logic to process these events, the console is flooded with ‘Unknown eventid:’ debug messages. To address this, handle these events gracefully without printing debug messages. There is already a block of event IDs that are ignored with a debug print. However, this new type of event occurs more frequently, so no debug print is necessary, and handling it should be a no-op. While at it, re-arrange the code so that all Unknown event IDs are towards the end of the switch block. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Aditya Kumar Singh Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241211154358.776279-4-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/wmi.c | 20 +++++++++++++------- drivers/net/wireless/ath/ath12k/wmi.h | 5 +++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 7bec414b0358a..3bc3ed29e4298 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -7505,13 +7505,6 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) case WMI_P2P_NOA_EVENTID: ath12k_wmi_p2p_noa_event(ab, skb); break; - /* add Unsupported events here */ - case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID: - case WMI_PEER_OPER_MODE_CHANGE_EVENTID: - case WMI_PDEV_DMA_RING_CFG_RSP_EVENTID: - ath12k_dbg(ab, ATH12K_DBG_WMI, - "ignoring unsupported event 0x%x\n", id); - break; case WMI_PDEV_DFS_RADAR_DETECTION_EVENTID: ath12k_wmi_pdev_dfs_radar_detected_event(ab, skb); break; @@ -7533,6 +7526,19 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) case WMI_MLO_TEARDOWN_COMPLETE_EVENTID: ath12k_wmi_event_teardown_complete(ab, skb); break; + /* add Unsupported events (rare) here */ + case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID: + case WMI_PEER_OPER_MODE_CHANGE_EVENTID: + case WMI_PDEV_DMA_RING_CFG_RSP_EVENTID: + ath12k_dbg(ab, ATH12K_DBG_WMI, + "ignoring unsupported event 0x%x\n", id); + break; + /* add Unsupported events (frequent) here */ + case WMI_PDEV_GET_HALPHY_CAL_STATUS_EVENTID: + case WMI_MGMT_RX_FW_CONSUMED_EVENTID: + case WMI_OBSS_COLOR_COLLISION_DETECTION_EVENTID: + /* debug might flood hence silently ignore (no-op) */ + break; /* TODO: Add remaining events */ default: ath12k_dbg(ab, ATH12K_DBG_WMI, "Unknown eventid: 0x%x\n", id); diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 270ed458302e5..cd3de0a655439 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -711,6 +711,8 @@ enum wmi_tlv_event_id { WMI_PDEV_RAP_INFO_EVENTID, WMI_CHAN_RF_CHARACTERIZATION_INFO_EVENTID, WMI_SERVICE_READY_EXT2_EVENTID, + WMI_PDEV_GET_HALPHY_CAL_STATUS_EVENTID = + WMI_SERVICE_READY_EXT2_EVENTID + 4, WMI_VDEV_START_RESP_EVENTID = WMI_TLV_CMD(WMI_GRP_VDEV), WMI_VDEV_STOPPED_EVENTID, WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID, @@ -752,6 +754,7 @@ enum wmi_tlv_event_id { WMI_TBTTOFFSET_EXT_UPDATE_EVENTID, WMI_OFFCHAN_DATA_TX_COMPLETION_EVENTID, WMI_HOST_FILS_DISCOVERY_EVENTID, + WMI_MGMT_RX_FW_CONSUMED_EVENTID = WMI_HOST_FILS_DISCOVERY_EVENTID + 3, WMI_TX_DELBA_COMPLETE_EVENTID = WMI_TLV_CMD(WMI_GRP_BA_NEG), WMI_TX_ADDBA_COMPLETE_EVENTID, WMI_BA_RSP_SSN_EVENTID, @@ -850,6 +853,8 @@ enum wmi_tlv_event_id { WMI_MDNS_STATS_EVENTID = WMI_TLV_CMD(WMI_GRP_MDNS_OFL), WMI_SAP_OFL_ADD_STA_EVENTID = WMI_TLV_CMD(WMI_GRP_SAP_OFL), WMI_SAP_OFL_DEL_STA_EVENTID, + WMI_OBSS_COLOR_COLLISION_DETECTION_EVENTID = + WMI_EVT_GRP_START_ID(WMI_GRP_OBSS_OFL), WMI_OCB_SET_CONFIG_RESP_EVENTID = WMI_TLV_CMD(WMI_GRP_OCB), WMI_OCB_GET_TSF_TIMER_RESP_EVENTID, WMI_DCC_GET_STATS_RESP_EVENTID, From 2c737079493d79ac340cb2b1b14c1a49645cdf61 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Wed, 11 Dec 2024 17:43:55 +0200 Subject: [PATCH 24/60] wifi: ath12k: remove warning print in htt mlo offset event message In the function ath12k_htt_mlo_offset_event_handler(), it is possible that the ar is not yet active (started). The function ath12k_mac_get_ar_by_pdev_id() only searches for active pdev, so a NULL return is possible. Therefore, there is no need to print a warning, instead, just silently discard the message. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Aditya Kumar Singh Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241211154358.776279-5-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/dp_rx.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 66367bfb4acc9..5c5a3aae393be 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -1697,7 +1697,11 @@ static void ath12k_htt_mlo_offset_event_handler(struct ath12k_base *ab, rcu_read_lock(); ar = ath12k_mac_get_ar_by_pdev_id(ab, pdev_id); if (!ar) { - ath12k_warn(ab, "invalid pdev id %d on htt mlo offset\n", pdev_id); + /* It is possible that the ar is not yet active (started). + * The above function will only look for the active pdev + * and hence %NULL return is possible. Just silently + * discard this message + */ goto exit; } From 043b473e3e02d4c371075956e9c72c32f17958fb Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Wed, 11 Dec 2024 17:43:56 +0200 Subject: [PATCH 25/60] wifi: ath12k: add ATH12K_FW_FEATURE_MLO capability firmware feature To maintain backward compatibility with older firmware versions, introduce a new feature bit, ATH12K_FW_FEATURE_MLO, to identify whether the firmware supports MLO. If the firmware-X.bin does not have this bit advertised in the feature, then MLO capability in the host will be disabled. This applies only for QCN9274 chipsets. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Aditya Kumar Singh Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241211154358.776279-6-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.c | 34 +++++++++++++++++++++++--- drivers/net/wireless/ath/ath12k/fw.h | 3 +++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index ff79cb910523a..0c6b35aac96eb 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1782,6 +1782,9 @@ static int ath12k_core_hw_group_create(struct ath12k_hw_group *ag) void ath12k_core_hw_group_set_mlo_capable(struct ath12k_hw_group *ag) { + struct ath12k_base *ab; + int i; + lockdep_assert_held(&ag->mutex); /* If more than one devices are grouped, then inter MLO @@ -1790,10 +1793,35 @@ void ath12k_core_hw_group_set_mlo_capable(struct ath12k_hw_group *ag) * Only when there is one device, then it depends whether the * device can support intra chip MLO or not */ - if (ag->num_devices > 1) + if (ag->num_devices > 1) { ag->mlo_capable = true; - else - ag->mlo_capable = ag->ab[0]->single_chip_mlo_supp; + } else { + ab = ag->ab[0]; + ag->mlo_capable = ab->single_chip_mlo_supp; + + /* WCN chipsets does not advertise in firmware features + * hence skip checking + */ + if (ab->hw_params->def_num_link) + return; + } + + if (!ag->mlo_capable) + return; + + for (i = 0; i < ag->num_devices; i++) { + ab = ag->ab[i]; + if (!ab) + continue; + + /* even if 1 device's firmware feature indicates MLO + * unsupported, make MLO unsupported for the whole group + */ + if (!test_bit(ATH12K_FW_FEATURE_MLO, ab->fw.fw_features)) { + ag->mlo_capable = false; + return; + } + } } int ath12k_core_init(struct ath12k_base *ab) diff --git a/drivers/net/wireless/ath/ath12k/fw.h b/drivers/net/wireless/ath/ath12k/fw.h index 3ff041f15fa0e..273c003eff3ba 100644 --- a/drivers/net/wireless/ath/ath12k/fw.h +++ b/drivers/net/wireless/ath/ath12k/fw.h @@ -23,6 +23,9 @@ enum ath12k_fw_features { */ ATH12K_FW_FEATURE_MULTI_QRTR_ID = 0, + /* The firmware supports MLO capability */ + ATH12K_FW_FEATURE_MLO, + /* keep last */ ATH12K_FW_FEATURE_COUNT, }; From 02213c21fb8dfe430e25e539153865eb846f1549 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Wed, 11 Dec 2024 17:43:57 +0200 Subject: [PATCH 26/60] wifi: ath12k: assign unique hardware link IDs during QMI host cap Currently, in the QMI host capability, the device index, the number of local links, and the corresponding hardware link IDs are sent. The hardware link ID assignment is based on the local variable `hw_link_id`, which starts from 0 and ranges up to `num_local_links` in the device. Starting from 0 is not ideal because it can result in the same link ID being assigned to different devices in certain scenarios (e.g., split MAC). Additionally, for multi link operations the firmware expects the hardware link IDs in the same order as the Wireless Serial Interface (WSI) connection. Hence, for MLO to function seamlessly, the hardware link IDs across devices need to be unique and should follow the order of the WSI connection. To address this, a previous change read the WSI index from the Device Tree (DT) and stored it. Use this WSI index to determine the starting hardware link IDs for each device, ensuring uniqueness and correct order across all devices. While at it, add debug prints to clearly show the MLO capability advertisement sent during QMI host capability exchange. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Aditya Kumar Singh Co-developed-by: Raj Kumar Bhagat Signed-off-by: Raj Kumar Bhagat Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241211154358.776279-7-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.h | 2 ++ drivers/net/wireless/ath/ath12k/qmi.c | 35 +++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 9aed245975482..d07b54f441c3e 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -863,11 +863,13 @@ struct ath12k_hw_group { struct device_node *wsi_node[ATH12K_MAX_SOCS]; struct ath12k_mlo_memory mlo_mem; struct ath12k_hw_link hw_links[ATH12K_GROUP_MAX_RADIO]; + bool hw_link_id_init_done; }; /* Holds WSI info specific to each device, excluding WSI group info */ struct ath12k_wsi_info { u32 index; + u32 hw_link_id_base; }; /* Master structure to hold the hw data which may be used in core module */ diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 964d350be748a..a8ed86a294c31 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -2016,6 +2016,30 @@ static const struct qmi_elem_info qmi_wlanfw_wlan_ini_resp_msg_v01_ei[] = { }, }; +static void ath12k_host_cap_hw_link_id_init(struct ath12k_hw_group *ag) +{ + struct ath12k_base *ab, *partner_ab; + int i, j, hw_id_base; + + for (i = 0; i < ag->num_devices; i++) { + hw_id_base = 0; + ab = ag->ab[i]; + + for (j = 0; j < ag->num_devices; j++) { + partner_ab = ag->ab[j]; + + if (partner_ab->wsi_info.index >= ab->wsi_info.index) + continue; + + hw_id_base += partner_ab->qmi.num_radios; + } + + ab->wsi_info.hw_link_id_base = hw_id_base; + } + + ag->hw_link_id_init_done = true; +} + static int ath12k_host_cap_parse_mlo(struct ath12k_base *ab, struct qmi_wlanfw_host_cap_req_msg_v01 *req) { @@ -2059,8 +2083,14 @@ static int ath12k_host_cap_parse_mlo(struct ath12k_base *ab, req->mlo_num_chips_valid = 1; req->mlo_num_chips = ag->num_devices; + ath12k_dbg(ab, ATH12K_DBG_QMI, "mlo capability advertisement device_id %d group_id %d num_devices %d", + req->mlo_chip_id, req->mlo_group_id, req->mlo_num_chips); + mutex_lock(&ag->mutex); + if (!ag->hw_link_id_init_done) + ath12k_host_cap_hw_link_id_init(ag); + for (i = 0; i < ag->num_devices; i++) { info = &req->mlo_chip_info[i]; partner_ab = ag->ab[i]; @@ -2078,9 +2108,12 @@ static int ath12k_host_cap_parse_mlo(struct ath12k_base *ab, info->chip_id, info->num_local_links); for (j = 0; j < info->num_local_links; j++) { - info->hw_link_id[j] = hw_link_id; + info->hw_link_id[j] = partner_ab->wsi_info.hw_link_id_base + j; info->valid_mlo_link_id[j] = 1; + ath12k_dbg(ab, ATH12K_DBG_QMI, "mlo hw_link_id %d\n", + info->hw_link_id[j]); + hw_link_id++; } } From d33bc467e8325be66b7209250e9829d199034ffe Mon Sep 17 00:00:00 2001 From: Rameshkumar Sundaram Date: Wed, 11 Dec 2024 17:43:58 +0200 Subject: [PATCH 27/60] wifi: ath12k: advertise MLO support and capabilities Now everything in ath12k is in place and we can enable Multi-Link Operation (MLO) in the driver. For now it's only enabled for QCN9274 with firmware having ATH12K_FW_FEATURE_MLO feature bit set. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Rameshkumar Sundaram Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241211154358.776279-8-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.h | 2 ++ drivers/net/wireless/ath/ath12k/mac.c | 13 ++++++++++++- drivers/net/wireless/ath/ath12k/wmi.c | 3 +++ drivers/net/wireless/ath/ath12k/wmi.h | 2 ++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index d07b54f441c3e..ec61ad3d82c3b 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -773,6 +773,8 @@ struct ath12k_pdev_cap { u32 tx_chain_mask_shift; u32 rx_chain_mask_shift; struct ath12k_band_cap band[NUM_NL80211_BANDS]; + u32 eml_cap; + u32 mld_cap; }; struct mlo_timestamp { diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index f7e505470f215..186765fa95f53 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -10693,7 +10693,7 @@ static const u8 ath12k_if_types_ext_capa_ap[] = { [10] = WLAN_EXT_CAPA11_EMA_SUPPORT, }; -static const struct wiphy_iftype_ext_capab ath12k_iftypes_ext_capa[] = { +static struct wiphy_iftype_ext_capab ath12k_iftypes_ext_capa[] = { { .extended_capabilities = ath12k_if_types_ext_capa, .extended_capabilities_mask = ath12k_if_types_ext_capa, @@ -10710,6 +10710,8 @@ static const struct wiphy_iftype_ext_capab ath12k_iftypes_ext_capa[] = { .extended_capabilities_mask = ath12k_if_types_ext_capa_ap, .extended_capabilities_len = sizeof(ath12k_if_types_ext_capa_ap), + .eml_capabilities = 0, + .mld_capa_and_ops = 0, }, }; @@ -10919,6 +10921,15 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) */ wiphy->flags |= WIPHY_FLAG_DISABLE_WEXT; + /* Copy over MLO related capabilities received from + * WMI_SERVICE_READY_EXT2_EVENT if single_chip_mlo_supp is set. + */ + if (ab->ag->mlo_capable) { + ath12k_iftypes_ext_capa[2].eml_capabilities = cap->eml_cap; + ath12k_iftypes_ext_capa[2].mld_capa_and_ops = cap->mld_cap; + wiphy->flags |= WIPHY_FLAG_SUPPORTS_MLO; + } + hw->queues = ATH12K_HW_MAX_QUEUES; wiphy->tx_queue_len = ATH12K_QUEUE_LEN; hw->offchannel_tx_hw_queue = ATH12K_HW_MAX_QUEUES - 1; diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 3bc3ed29e4298..562b0615ed065 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -4662,6 +4662,9 @@ ath12k_wmi_tlv_mac_phy_caps_ext_parse(struct ath12k_base *ab, caps->eht_cap_info_internal); } + pdev->cap.eml_cap = le32_to_cpu(caps->eml_capability); + pdev->cap.mld_cap = le32_to_cpu(caps->mld_capability); + return 0; } diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index cd3de0a655439..b6a197389277b 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2716,6 +2716,8 @@ struct ath12k_wmi_caps_ext_params { __le32 eht_cap_info_internal; __le32 eht_supp_mcs_ext_2ghz[WMI_MAX_EHT_SUPP_MCS_2G_SIZE]; __le32 eht_supp_mcs_ext_5ghz[WMI_MAX_EHT_SUPP_MCS_5G_SIZE]; + __le32 eml_capability; + __le32 mld_capability; } __packed; /* 2 word representation of MAC addr */ From 2a7e02fa9116d9b077983257774e6644af064857 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Mon, 9 Dec 2024 18:50:25 +0300 Subject: [PATCH 28/60] wifi: ath9k: cleanup ath_txq_skb_done() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 'txq' argument of 'ath_txq_skb_done()' is actually (mis|un)used, convert the former to local variable and adjust all related users. Compile tested only. Found by Linux Verification Center (linuxtesting.org) with SVACE. Signed-off-by: Dmitry Antipov Acked-by: Toke Høiland-Jørgensen Link: https://patch.msgid.link/20241209155027.636400-1-dmantipov@yandex.ru Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath9k/xmit.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 0a24439dd30d7..f41f03f55b07f 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -208,10 +208,10 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta, ARRAY_SIZE(bf->rates)); } -static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, - struct sk_buff *skb) +static void ath_txq_skb_done(struct ath_softc *sc, struct sk_buff *skb) { struct ath_frame_info *fi = get_frame_info(skb); + struct ath_txq *txq; int q = fi->txq; if (q < 0) @@ -294,7 +294,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) fi = get_frame_info(skb); bf = fi->bf; if (!bf) { - ath_txq_skb_done(sc, txq, skb); + ath_txq_skb_done(sc, skb); ieee80211_free_txskb(sc->hw, skb); continue; } @@ -962,7 +962,7 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, bf->bf_state.stale = false; if (!bf) { - ath_txq_skb_done(sc, txq, skb); + ath_txq_skb_done(sc, skb); ieee80211_free_txskb(sc->hw, skb); continue; } @@ -2379,7 +2379,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, bf = ath_tx_setup_buffer(sc, txq, tid, skb); if (!bf) { - ath_txq_skb_done(sc, txq, skb); + ath_txq_skb_done(sc, skb); if (txctl->paprd) dev_kfree_skb_any(skb); else @@ -2514,7 +2514,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, } spin_unlock_irqrestore(&sc->sc_pm_lock, flags); - ath_txq_skb_done(sc, txq, skb); + ath_txq_skb_done(sc, skb); tx_info->status.status_driver_data[0] = sta; __skb_queue_tail(&txq->complete_q, skb); } From d19ac7ef6ee997298a42335d0dd09b67c6cb19bf Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Mon, 9 Dec 2024 18:50:26 +0300 Subject: [PATCH 29/60] wifi: ath9k: cleanup a few (mostly) TX-related routines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unused 'struct ath_softc *' argument of 'ath_pkt_duration()', 'ath_tx_update_baw()', 'ath_get_skb_tid()', 'ath_tx_addto_baw()' and 'ath_tx_count_frames()', adjust related users. Compile tested only. Signed-off-by: Dmitry Antipov Acked-by: Toke Høiland-Jørgensen Link: https://patch.msgid.link/20241209155027.636400-2-dmantipov@yandex.ru Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath9k/ath9k.h | 4 +-- drivers/net/wireless/ath/ath9k/recv.c | 4 +-- drivers/net/wireless/ath/ath9k/xmit.c | 40 ++++++++++++-------------- 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index bcfc8df0efe5b..3e06a7e859419 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -592,8 +592,8 @@ void ath_txq_schedule_all(struct ath_softc *sc); int ath_tx_init(struct ath_softc *sc, int nbufs); int ath_txq_update(struct ath_softc *sc, int qnum, struct ath9k_tx_queue_info *q); -u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen, - int width, int half_gi, bool shortPreamble); +u32 ath_pkt_duration(u8 rix, int pktlen, int width, + int half_gi, bool shortPreamble); void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop); void ath_assign_seq(struct ath_common *common, struct sk_buff *skb); int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 0c0624a3b40d2..34c74ed99b7b5 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1042,8 +1042,8 @@ static void ath_rx_count_airtime(struct ath_softc *sc, if (!!(rxs->encoding == RX_ENC_HT)) { /* MCS rates */ - airtime += ath_pkt_duration(sc, rxs->rate_idx, len, - is_40, is_sgi, is_sp); + airtime += ath_pkt_duration(rxs->rate_idx, len, + is_40, is_sgi, is_sp); } else { phy = IS_CCK_RATE(rs->rs_rate) ? WLAN_RC_PHY_CCK : WLAN_RC_PHY_OFDM; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index f41f03f55b07f..db07ce6dbc080 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -67,8 +67,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, int nframes, int nbad, int txok); -static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, - struct ath_buf *bf); +static void ath_tx_update_baw(struct ath_atx_tid *tid, struct ath_buf *bf); static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, @@ -224,7 +223,7 @@ static void ath_txq_skb_done(struct ath_softc *sc, struct sk_buff *skb) } static struct ath_atx_tid * -ath_get_skb_tid(struct ath_softc *sc, struct ath_node *an, struct sk_buff *skb) +ath_get_skb_tid(struct ath_node *an, struct sk_buff *skb) { u8 tidno = skb->priority & IEEE80211_QOS_CTL_TID_MASK; return ATH_AN_2_TID(an, tidno); @@ -300,7 +299,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) } if (fi->baw_tracked) { - ath_tx_update_baw(sc, tid, bf); + ath_tx_update_baw(tid, bf); sendbar = true; } @@ -315,8 +314,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) } } -static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, - struct ath_buf *bf) +static void ath_tx_update_baw(struct ath_atx_tid *tid, struct ath_buf *bf) { struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); u16 seqno = bf->bf_state.seqno; @@ -338,8 +336,7 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, } } -static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid, - struct ath_buf *bf) +static void ath_tx_addto_baw(struct ath_atx_tid *tid, struct ath_buf *bf) { struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); u16 seqno = bf->bf_state.seqno; @@ -452,9 +449,8 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) return tbf; } -static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf, - struct ath_tx_status *ts, int txok, - int *nframes, int *nbad) +static void ath_tx_count_frames(struct ath_buf *bf, struct ath_tx_status *ts, + int txok, int *nframes, int *nbad) { u16 seq_st = 0; u32 ba[WME_BA_BMP_SIZE >> 5]; @@ -568,7 +564,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, __skb_queue_head_init(&bf_pending); - ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad); + ath_tx_count_frames(bf, ts, txok, &nframes, &nbad); while (bf) { u16 seqno = bf->bf_state.seqno; @@ -621,7 +617,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, * complete the acked-ones/xretried ones; update * block-ack window */ - ath_tx_update_baw(sc, tid, bf); + ath_tx_update_baw(tid, bf); if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { memcpy(tx_info->control.rates, rates, sizeof(rates)); @@ -651,7 +647,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, * run out of tx buf. */ if (!tbf) { - ath_tx_update_baw(sc, tid, bf); + ath_tx_update_baw(tid, bf); ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, ts, @@ -752,7 +748,7 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2); if (sta) { struct ath_node *an = (struct ath_node *)sta->drv_priv; - tid = ath_get_skb_tid(sc, an, bf->bf_mpdu); + tid = ath_get_skb_tid(an, bf->bf_mpdu); ath_tx_count_airtime(sc, sta, bf, ts, tid->tidno); if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY)) tid->clear_ps_filter = true; @@ -1012,13 +1008,13 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, INIT_LIST_HEAD(&bf_head); list_add(&bf->list, &bf_head); - ath_tx_update_baw(sc, tid, bf); + ath_tx_update_baw(tid, bf); ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0); continue; } if (bf_isampdu(bf)) - ath_tx_addto_baw(sc, tid, bf); + ath_tx_addto_baw(tid, bf); break; } @@ -1114,8 +1110,8 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq, * width - 0 for 20 MHz, 1 for 40 MHz * half_gi - to use 4us v/s 3.6 us for symbol time */ -u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen, - int width, int half_gi, bool shortPreamble) +u32 ath_pkt_duration(u8 rix, int pktlen, int width, + int half_gi, bool shortPreamble) { u32 nbits, nsymbits, duration, nsymbols; int streams; @@ -1327,7 +1323,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, info->rates[i].Rate = rix | 0x80; info->rates[i].ChSel = ath_txchainmask_reduction(sc, ah->txchainmask, info->rates[i].Rate); - info->rates[i].PktDuration = ath_pkt_duration(sc, rix, len, + info->rates[i].PktDuration = ath_pkt_duration(rix, len, is_40, is_sgi, is_sp); if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC)) info->rates[i].RateFlags |= ATH9K_RATESERIES_STBC; @@ -2122,7 +2118,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, bf->bf_state.bf_type = 0; if (tid && (tx_info->flags & IEEE80211_TX_CTL_AMPDU)) { bf->bf_state.bf_type = BUF_AMPDU; - ath_tx_addto_baw(sc, tid, bf); + ath_tx_addto_baw(tid, bf); } bf->bf_next = NULL; @@ -2368,7 +2364,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, if (txctl->sta) { an = (struct ath_node *) sta->drv_priv; - tid = ath_get_skb_tid(sc, an, skb); + tid = ath_get_skb_tid(an, skb); } ath_txq_lock(sc, txq); From 0cc6510ca4639a20c8921f223f05faa485795204 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Mon, 9 Dec 2024 18:50:27 +0300 Subject: [PATCH 30/60] wifi: ath9k: simplify internal time management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prefer 'ktime_t' over 'struct timespec64' for 'struct ath_chanctx' and 'struct ath_softc' timestamps, choose standard kernel time API over an ad-hoc math in 'chanctx_event_delta()' and 'ath9k_hw_get_tsf_offset()', adjust related users. Compile tested only. Signed-off-by: Dmitry Antipov Acked-by: Toke Høiland-Jørgensen Link: https://patch.msgid.link/20241209155027.636400-3-dmantipov@yandex.ru Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath9k/ath9k.h | 4 ++-- drivers/net/wireless/ath/ath9k/beacon.c | 2 +- drivers/net/wireless/ath/ath9k/channel.c | 29 ++++++++++-------------- drivers/net/wireless/ath/ath9k/hw.c | 25 +++++++------------- drivers/net/wireless/ath/ath9k/hw.h | 2 +- drivers/net/wireless/ath/ath9k/main.c | 9 ++++---- 6 files changed, 28 insertions(+), 43 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 3e06a7e859419..a728cc0387df8 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -338,7 +338,7 @@ struct ath_chanctx { struct ath_beacon_config beacon; struct ath9k_hw_cal_data caldata; - struct timespec64 tsf_ts; + ktime_t tsf_ts; u64 tsf_val; u32 last_beacon; @@ -1011,7 +1011,7 @@ struct ath_softc { struct ath_offchannel offchannel; struct ath_chanctx *next_chan; struct completion go_beacon; - struct timespec64 last_event_time; + ktime_t last_event_time; #endif unsigned long driver_data; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index b399a7926ef5d..4a27e3753c036 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -293,7 +293,7 @@ void ath9k_beacon_ensure_primary_slot(struct ath_softc *sc) /* Modify TSF as required and update the HW. */ avp->chanctx->tsf_val += tsfadjust; if (sc->cur_chan == avp->chanctx) { - offset = ath9k_hw_get_tsf_offset(&avp->chanctx->tsf_ts, NULL); + offset = ath9k_hw_get_tsf_offset(avp->chanctx->tsf_ts, 0); ath9k_hw_settsf64(sc->sc_ah, avp->chanctx->tsf_val + offset); } diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 02237d106f8c6..bae24e3d31689 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -232,16 +232,11 @@ static const char *chanctx_state_string(enum ath_chanctx_state state) static u32 chanctx_event_delta(struct ath_softc *sc) { - u64 ms; - struct timespec64 ts, *old; + ktime_t ts = ktime_get_raw(); + s64 ms = ktime_ms_delta(ts, sc->last_event_time); - ktime_get_raw_ts64(&ts); - old = &sc->last_event_time; - ms = ts.tv_sec * 1000 + ts.tv_nsec / 1000000; - ms -= old->tv_sec * 1000 + old->tv_nsec / 1000000; sc->last_event_time = ts; - - return (u32)ms; + return ms; } void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx) @@ -334,8 +329,8 @@ ath_chanctx_get_next(struct ath_softc *sc, struct ath_chanctx *ctx) static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc) { struct ath_chanctx *prev, *cur; - struct timespec64 ts; u32 cur_tsf, prev_tsf, beacon_int; + ktime_t ts; s32 offset; beacon_int = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); @@ -346,12 +341,12 @@ static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc) if (!prev->switch_after_beacon) return; - ktime_get_raw_ts64(&ts); + ts = ktime_get_raw(); cur_tsf = (u32) cur->tsf_val + - ath9k_hw_get_tsf_offset(&cur->tsf_ts, &ts); + ath9k_hw_get_tsf_offset(cur->tsf_ts, ts); prev_tsf = prev->last_beacon - (u32) prev->tsf_val + cur_tsf; - prev_tsf -= ath9k_hw_get_tsf_offset(&prev->tsf_ts, &ts); + prev_tsf -= ath9k_hw_get_tsf_offset(prev->tsf_ts, ts); /* Adjust the TSF time of the AP chanctx to keep its beacons * at half beacon interval offset relative to the STA chanctx. @@ -691,7 +686,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, */ tsf_time = sc->sched.switch_start_time; tsf_time -= (u32) sc->cur_chan->tsf_val + - ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, NULL); + ath9k_hw_get_tsf_offset(sc->cur_chan->tsf_ts, 0); tsf_time += ath9k_hw_gettsf32(ah); sc->sched.beacon_adjust = false; @@ -1230,10 +1225,10 @@ void ath_chanctx_set_next(struct ath_softc *sc, bool force) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_chanctx *old_ctx; - struct timespec64 ts; bool measure_time = false; bool send_ps = false; bool queues_stopped = false; + ktime_t ts; spin_lock_bh(&sc->chan_lock); if (!sc->next_chan) { @@ -1260,7 +1255,7 @@ void ath_chanctx_set_next(struct ath_softc *sc, bool force) spin_unlock_bh(&sc->chan_lock); if (sc->next_chan == &sc->offchannel.chan) { - ktime_get_raw_ts64(&ts); + ts = ktime_get_raw(); measure_time = true; } @@ -1277,7 +1272,7 @@ void ath_chanctx_set_next(struct ath_softc *sc, bool force) spin_lock_bh(&sc->chan_lock); if (sc->cur_chan != &sc->offchannel.chan) { - ktime_get_raw_ts64(&sc->cur_chan->tsf_ts); + sc->cur_chan->tsf_ts = ktime_get_raw(); sc->cur_chan->tsf_val = ath9k_hw_gettsf64(sc->sc_ah); } } @@ -1303,7 +1298,7 @@ void ath_chanctx_set_next(struct ath_softc *sc, bool force) ath_set_channel(sc); if (measure_time) sc->sched.channel_switch_time = - ath9k_hw_get_tsf_offset(&ts, NULL); + ath9k_hw_get_tsf_offset(ts, 0); /* * A reset will ensure that all queues are woken up, * so there is no need to awaken them again. diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index a25eacabc664a..f9a774bd0e139 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1847,20 +1847,11 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan) return -EINVAL; } -u32 ath9k_hw_get_tsf_offset(struct timespec64 *last, struct timespec64 *cur) +u32 ath9k_hw_get_tsf_offset(ktime_t last, ktime_t cur) { - struct timespec64 ts; - s64 usec; - - if (!cur) { - ktime_get_raw_ts64(&ts); - cur = &ts; - } - - usec = cur->tv_sec * 1000000ULL + cur->tv_nsec / 1000; - usec -= last->tv_sec * 1000000ULL + last->tv_nsec / 1000; - - return (u32) usec; + if (cur == 0) + cur = ktime_get_raw(); + return ktime_us_delta(cur, last); } EXPORT_SYMBOL(ath9k_hw_get_tsf_offset); @@ -1871,7 +1862,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, u32 saveLedState; u32 saveDefAntenna; u32 macStaId1; - struct timespec64 tsf_ts; + ktime_t tsf_ts; u32 tsf_offset; u64 tsf = 0; int r; @@ -1917,7 +1908,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B; /* Save TSF before chip reset, a cold reset clears it */ - ktime_get_raw_ts64(&tsf_ts); + tsf_ts = ktime_get_raw(); tsf = ath9k_hw_gettsf64(ah); saveLedState = REG_READ(ah, AR_CFG_LED) & @@ -1951,7 +1942,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, } /* Restore TSF */ - tsf_offset = ath9k_hw_get_tsf_offset(&tsf_ts, NULL); + tsf_offset = ath9k_hw_get_tsf_offset(tsf_ts, 0); ath9k_hw_settsf64(ah, tsf + tsf_offset); if (AR_SREV_9280_20_OR_LATER(ah)) @@ -1975,7 +1966,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, * value after the initvals have been applied. */ if (AR_SREV_9100(ah) && (ath9k_hw_gettsf64(ah) < tsf)) { - tsf_offset = ath9k_hw_get_tsf_offset(&tsf_ts, NULL); + tsf_offset = ath9k_hw_get_tsf_offset(tsf_ts, 0); ath9k_hw_settsf64(ah, tsf + tsf_offset); } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index e2cbf3f00da07..eaa07d6dbde00 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -1066,7 +1066,7 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah); u64 ath9k_hw_gettsf64(struct ath_hw *ah); void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); void ath9k_hw_reset_tsf(struct ath_hw *ah); -u32 ath9k_hw_get_tsf_offset(struct timespec64 *last, struct timespec64 *cur); +u32 ath9k_hw_get_tsf_offset(ktime_t last, ktime_t cur); void ath9k_hw_set_tsfadjust(struct ath_hw *ah, bool set); void ath9k_hw_init_global_settings(struct ath_hw *ah); u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 812e0c6bde3e3..a70c945648147 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -249,8 +249,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) if (sc->cur_chan->tsf_val) { u32 offset; - offset = ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, - NULL); + offset = ath9k_hw_get_tsf_offset(sc->cur_chan->tsf_ts, 0); ath9k_hw_settsf64(ah, sc->cur_chan->tsf_val + offset); } @@ -1956,7 +1955,7 @@ static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) tsf = ath9k_hw_gettsf64(sc->sc_ah); } else { tsf = sc->cur_chan->tsf_val + - ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, NULL); + ath9k_hw_get_tsf_offset(sc->cur_chan->tsf_ts, 0); } tsf += le64_to_cpu(avp->tsf_adjust); ath9k_ps_restore(sc); @@ -1975,7 +1974,7 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); tsf -= le64_to_cpu(avp->tsf_adjust); - ktime_get_raw_ts64(&avp->chanctx->tsf_ts); + avp->chanctx->tsf_ts = ktime_get_raw(); if (sc->cur_chan == avp->chanctx) ath9k_hw_settsf64(sc->sc_ah, tsf); avp->chanctx->tsf_val = tsf; @@ -1991,7 +1990,7 @@ static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); - ktime_get_raw_ts64(&avp->chanctx->tsf_ts); + avp->chanctx->tsf_ts = ktime_get_raw(); if (sc->cur_chan == avp->chanctx) ath9k_hw_reset_tsf(sc->sc_ah); avp->chanctx->tsf_val = 0; From be8d47f181fd4f341b8beee1ca11a96d296d2df2 Mon Sep 17 00:00:00 2001 From: P Praneesh Date: Tue, 17 Dec 2024 15:20:58 +0530 Subject: [PATCH 31/60] wifi: ath12k: Add support for parsing 64-bit TLVs There is mismatch between the format of monitor destination TLVs received and the expected format by the current implementation. The received TLVs are in 64-bit format, while the implementation is designed to handle 32-bit TLVs. This leads to incorrect parsing. Fix it by adding support for parsing 64-bit TLVs. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: P Praneesh Acked-by: Kalle Valo Acked-by: Jeff Johnson Link: https://patch.msgid.link/20241217095058.2725755-1-quic_ppranees@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/dp_mon.c | 14 +++++++------- drivers/net/wireless/ath/ath12k/hal_desc.h | 2 ++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index 2d53404095d6b..c6cc4a1a52304 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -1205,19 +1205,19 @@ ath12k_dp_mon_parse_rx_dest(struct ath12k_base *ab, struct ath12k_mon_data *pmon struct sk_buff *skb) { struct hal_rx_mon_ppdu_info *ppdu_info = &pmon->mon_ppdu_info; - struct hal_tlv_hdr *tlv; + struct hal_tlv_64_hdr *tlv; enum hal_rx_mon_status hal_status; - u32 tlv_userid = 0; + u32 tlv_userid; u16 tlv_tag, tlv_len; u8 *ptr = skb->data; memset(ppdu_info, 0, sizeof(struct hal_rx_mon_ppdu_info)); do { - tlv = (struct hal_tlv_hdr *)ptr; - tlv_tag = le32_get_bits(tlv->tl, HAL_TLV_HDR_TAG); - tlv_len = le32_get_bits(tlv->tl, HAL_TLV_HDR_LEN); - tlv_userid = le32_get_bits(tlv->tl, HAL_TLV_USR_ID); + tlv = (struct hal_tlv_64_hdr *)ptr; + tlv_tag = le64_get_bits(tlv->tl, HAL_TLV_64_HDR_TAG); + tlv_len = le64_get_bits(tlv->tl, HAL_TLV_64_HDR_LEN); + tlv_userid = le64_get_bits(tlv->tl, HAL_TLV_64_USR_ID); ptr += sizeof(*tlv); /* The actual length of PPDU_END is the combined length of many PHY @@ -1232,7 +1232,7 @@ ath12k_dp_mon_parse_rx_dest(struct ath12k_base *ab, struct ath12k_mon_data *pmon hal_status = ath12k_dp_mon_rx_parse_status_tlv(ab, pmon, tlv_tag, ptr, tlv_userid); ptr += tlv_len; - ptr = PTR_ALIGN(ptr, HAL_TLV_ALIGN); + ptr = PTR_ALIGN(ptr, HAL_TLV_64_ALIGN); if ((ptr - skb->data) >= DP_RX_BUFFER_SIZE) break; diff --git a/drivers/net/wireless/ath/ath12k/hal_desc.h b/drivers/net/wireless/ath/ath12k/hal_desc.h index a460d432288fa..b90a6da72e297 100644 --- a/drivers/net/wireless/ath/ath12k/hal_desc.h +++ b/drivers/net/wireless/ath/ath12k/hal_desc.h @@ -579,6 +579,8 @@ struct hal_tlv_hdr { #define HAL_TLV_64_HDR_TAG GENMASK(9, 1) #define HAL_TLV_64_HDR_LEN GENMASK(21, 10) +#define HAL_TLV_64_USR_ID GENMASK(31, 26) +#define HAL_TLV_64_ALIGN 8 struct hal_tlv_64_hdr { __le64 tl; From aa21668ab3c7c479998be11393e1a1c3c2624fce Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Tue, 17 Dec 2024 22:26:15 +0200 Subject: [PATCH 32/60] wifi: ath12k: Decrease ath12k_mac_op_remain_on_channel() stack usage Building the ath12k driver with llvm-18.1.7-x86_64 produces the warning: drivers/net/wireless/ath/ath12k/mac.c:10028:12: warning: stack frame size (1080) exceeds limit (1024) in 'ath12k_mac_op_remain_on_channel' [-Wframe-larger-than] A major contributor to the stack usage in this function is: struct ath12k_wmi_scan_req_arg arg; Avoid the excess stack usage by dynamically allocating arg instead of declaring it on the stack. As part of the effort use __free() for both this new allocation as well as the existing chan_list allocation, and since then no central cleanup is required, replace all cleanup gotos with returns. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241217202618.1329312-2-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 78 ++++++++++++--------------- 1 file changed, 34 insertions(+), 44 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 186765fa95f53..05d2c75e5df29 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -10054,7 +10054,6 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, { struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); struct ath12k_hw *ah = ath12k_hw_to_ah(hw); - struct ath12k_wmi_scan_req_arg arg; struct ath12k_link_vif *arvif; struct ath12k *ar; u32 scan_time_msec; @@ -10065,10 +10064,8 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, lockdep_assert_wiphy(hw->wiphy); ar = ath12k_mac_select_scan_device(hw, vif, chan->center_freq); - if (!ar) { - ret = -EINVAL; - goto exit; - } + if (!ar) + return -EINVAL; /* check if any of the links of ML VIF is already started on * radio(ar) correpsondig to given scan frequency and use it, @@ -10087,15 +10084,11 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, * always on the same band for the vif */ if (arvif->is_created) { - if (WARN_ON(!arvif->ar)) { - ret = -EINVAL; - goto exit; - } + if (WARN_ON(!arvif->ar)) + return -EINVAL; - if (ar != arvif->ar && arvif->is_started) { - ret = -EBUSY; - goto exit; - } + if (ar != arvif->ar && arvif->is_started) + return -EBUSY; if (ar != arvif->ar) { ath12k_mac_remove_link_interface(hw, arvif); @@ -10112,7 +10105,7 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, if (ret) { ath12k_warn(ar->ab, "unable to create scan vdev for roc: %d\n", ret); - goto exit; + return ret; } } @@ -10140,37 +10133,41 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, spin_unlock_bh(&ar->data_lock); if (ret) - goto exit; + return ret; scan_time_msec = hw->wiphy->max_remain_on_channel_duration * 2; - memset(&arg, 0, sizeof(arg)); - ath12k_wmi_start_scan_init(ar, &arg); - arg.num_chan = 1; - arg.chan_list = kcalloc(arg.num_chan, sizeof(*arg.chan_list), - GFP_KERNEL); - if (!arg.chan_list) { - ret = -ENOMEM; - goto exit; - } + struct ath12k_wmi_scan_req_arg *arg __free(kfree) = + kzalloc(sizeof(*arg), GFP_KERNEL); + if (!arg) + return -ENOMEM; - arg.vdev_id = arvif->vdev_id; - arg.scan_id = ATH12K_SCAN_ID; - arg.chan_list[0] = chan->center_freq; - arg.dwell_time_active = scan_time_msec; - arg.dwell_time_passive = scan_time_msec; - arg.max_scan_time = scan_time_msec; - arg.scan_f_passive = 1; - arg.burst_duration = duration; - - ret = ath12k_start_scan(ar, &arg); + ath12k_wmi_start_scan_init(ar, arg); + arg->num_chan = 1; + + u32 *chan_list __free(kfree) = kcalloc(arg->num_chan, sizeof(*chan_list), + GFP_KERNEL); + if (!chan_list) + return -ENOMEM; + + arg->chan_list = chan_list; + arg->vdev_id = arvif->vdev_id; + arg->scan_id = ATH12K_SCAN_ID; + arg->chan_list[0] = chan->center_freq; + arg->dwell_time_active = scan_time_msec; + arg->dwell_time_passive = scan_time_msec; + arg->max_scan_time = scan_time_msec; + arg->scan_f_passive = 1; + arg->burst_duration = duration; + + ret = ath12k_start_scan(ar, arg); if (ret) { ath12k_warn(ar->ab, "failed to start roc scan: %d\n", ret); spin_lock_bh(&ar->data_lock); ar->scan.state = ATH12K_SCAN_IDLE; spin_unlock_bh(&ar->data_lock); - goto free_chan_list; + return ret; } ret = wait_for_completion_timeout(&ar->scan.on_channel, 3 * HZ); @@ -10179,20 +10176,13 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, ret = ath12k_scan_stop(ar); if (ret) ath12k_warn(ar->ab, "failed to stop scan: %d\n", ret); - ret = -ETIMEDOUT; - goto free_chan_list; + return -ETIMEDOUT; } ieee80211_queue_delayed_work(hw, &ar->scan.timeout, msecs_to_jiffies(duration)); - ret = 0; - -free_chan_list: - kfree(arg.chan_list); - -exit: - return ret; + return 0; } static void ath12k_mac_op_set_rekey_data(struct ieee80211_hw *hw, From 445718c9958c8c160654068014c0e72505f59d63 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Tue, 17 Dec 2024 22:26:16 +0200 Subject: [PATCH 33/60] wifi: ath12k: Decrease ath12k_bss_assoc() stack usage Currently when building ath12k with gcc-14.2.0 the following warning is observed: drivers/net/wireless/ath/ath12k/mac.c: In function 'ath12k_bss_assoc': drivers/net/wireless/ath/ath12k/mac.c:3080:1: warning: the frame size of 1040 bytes is larger than 1024 bytes [-Wframe-larger-than=] A major contributor to the stack usage in this function is: struct ath12k_wmi_peer_assoc_arg peer_arg; Avoid the excess stack usage by dynamically allocating peer_arg instead of declaring it on the stack. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241217202618.1329312-3-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 05d2c75e5df29..2a30a11903c5f 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -3133,7 +3133,6 @@ static void ath12k_bss_assoc(struct ath12k *ar, struct ath12k_vif *ahvif = arvif->ahvif; struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); struct ath12k_wmi_vdev_up_params params = {}; - struct ath12k_wmi_peer_assoc_arg peer_arg = {}; struct ieee80211_link_sta *link_sta; u8 link_id = bss_conf->link_id; struct ath12k_link_sta *arsta; @@ -3145,6 +3144,11 @@ static void ath12k_bss_assoc(struct ath12k *ar, lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + struct ath12k_wmi_peer_assoc_arg *peer_arg __free(kfree) = + kzalloc(sizeof(*peer_arg), GFP_KERNEL); + if (!peer_arg) + return; + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev %i link id %u assoc bssid %pM aid %d\n", arvif->vdev_id, link_id, arvif->bssid, ahvif->aid); @@ -3177,11 +3181,11 @@ static void ath12k_bss_assoc(struct ath12k *ar, return; } - ath12k_peer_assoc_prepare(ar, arvif, arsta, &peer_arg, false); + ath12k_peer_assoc_prepare(ar, arvif, arsta, peer_arg, false); rcu_read_unlock(); - ret = ath12k_wmi_send_peer_assoc_cmd(ar, &peer_arg); + ret = ath12k_wmi_send_peer_assoc_cmd(ar, peer_arg); if (ret) { ath12k_warn(ar->ab, "failed to run peer assoc for %pM vdev %i: %d\n", bss_conf->bssid, arvif->vdev_id, ret); From 6ff412420e5ea1635385038a0bb4c77420862bc9 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Tue, 17 Dec 2024 22:26:17 +0200 Subject: [PATCH 34/60] wifi: ath12k: Decrease ath12k_sta_rc_update_wk() stack usage Currently when building ath12k with llvm-18.1.7-x86_64 the following warning is observed: drivers/net/wireless/ath/ath12k/mac.c:4946:13: warning: stack frame size (1112) exceeds limit (1024) in 'ath12k_sta_rc_update_wk' [-Wframe-larger-than] A major contributor to the stack usage in this function is: struct ath12k_wmi_peer_assoc_arg peer_arg; Avoid the excess stack usage by dynamically allocating peer_arg instead of declaring it on the stack. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241217202618.1329312-4-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 2a30a11903c5f..10293e9c1d490 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -4956,7 +4956,6 @@ static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk) u32 changed, bw, nss, smps, bw_prev; int err, num_vht_rates; const struct cfg80211_bitrate_mask *mask; - struct ath12k_wmi_peer_assoc_arg peer_arg; enum wmi_phy_mode peer_phymode; struct ath12k_link_sta *arsta; struct ieee80211_vif *vif; @@ -4992,9 +4991,14 @@ static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk) nss = min(nss, max(ath12k_mac_max_ht_nss(ht_mcs_mask), ath12k_mac_max_vht_nss(vht_mcs_mask))); + struct ath12k_wmi_peer_assoc_arg *peer_arg __free(kfree) = + kzalloc(sizeof(*peer_arg), GFP_KERNEL); + if (!peer_arg) + return; + if (changed & IEEE80211_RC_BW_CHANGED) { - ath12k_peer_assoc_h_phymode(ar, arvif, arsta, &peer_arg); - peer_phymode = peer_arg.peer_phymode; + ath12k_peer_assoc_h_phymode(ar, arvif, arsta, peer_arg); + peer_phymode = peer_arg->peer_phymode; if (bw > bw_prev) { /* Phymode shows maximum supported channel width, if we @@ -5096,9 +5100,9 @@ static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk) * other rates using peer_assoc command. */ ath12k_peer_assoc_prepare(ar, arvif, arsta, - &peer_arg, true); + peer_arg, true); - err = ath12k_wmi_send_peer_assoc_cmd(ar, &peer_arg); + err = ath12k_wmi_send_peer_assoc_cmd(ar, peer_arg); if (err) ath12k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n", arsta->addr, arvif->vdev_id, err); From bf2da5c4f5b576d45f5f0cc0f508b8255f7ab015 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Tue, 17 Dec 2024 22:26:18 +0200 Subject: [PATCH 35/60] wifi: ath12k: Decrease ath12k_mac_station_assoc() stack usage Building the ath12k driver with llvm-18.1.7-x86_64 produces the warning: drivers/net/wireless/ath/ath12k/mac.c:5606:12: warning: stack frame size (1176) exceeds limit (1024) in 'ath12k_mac_op_sta_state' [-Wframe-larger-than] ath12k_mac_op_sta_state() itself does not consume much stack, but it calls ath12k_mac_handle_link_sta_state() which in turn calls ath12k_mac_station_add(). Since those are both static functions with only one caller, it is suspected that these both get inlined, and their stack usage is reported for ath12k_mac_op_sta_state(). A major contributor to the ath12k_mac_station_assoc() stack usage is: struct ath12k_wmi_peer_assoc_arg peer_arg; Avoid the excess stack usage by dynamically allocating peer_arg instead of declaring it on the stack. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241217202618.1329312-5-kvalo@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 10293e9c1d490..6f10813d93782 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -4834,7 +4834,6 @@ static int ath12k_mac_station_assoc(struct ath12k *ar, { struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); - struct ath12k_wmi_peer_assoc_arg peer_arg; struct ieee80211_link_sta *link_sta; int ret; struct cfg80211_chan_def def; @@ -4854,14 +4853,19 @@ static int ath12k_mac_station_assoc(struct ath12k *ar, band = def.chan->band; mask = &arvif->bitrate_mask; - ath12k_peer_assoc_prepare(ar, arvif, arsta, &peer_arg, reassoc); + struct ath12k_wmi_peer_assoc_arg *peer_arg __free(kfree) = + kzalloc(sizeof(*peer_arg), GFP_KERNEL); + if (!peer_arg) + return -ENOMEM; - if (peer_arg.peer_nss < 1) { + ath12k_peer_assoc_prepare(ar, arvif, arsta, peer_arg, reassoc); + + if (peer_arg->peer_nss < 1) { ath12k_warn(ar->ab, - "invalid peer NSS %d\n", peer_arg.peer_nss); + "invalid peer NSS %d\n", peer_arg->peer_nss); return -EINVAL; } - ret = ath12k_wmi_send_peer_assoc_cmd(ar, &peer_arg); + ret = ath12k_wmi_send_peer_assoc_cmd(ar, peer_arg); if (ret) { ath12k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n", arsta->addr, arvif->vdev_id, ret); From d506e55fe39bcd6a78bd1f23210cbcd8cee4f844 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 17 Dec 2024 14:15:04 +0530 Subject: [PATCH 36/60] wifi: ath12k: Add documentation HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG Add missing field documentation for HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG command with indentation alignment. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Acked-by: Kalle Valo Link: https://patch.msgid.link/20241217084511.2981515-2-quic_periyasa@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/dp.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index 7700828375e3e..b178921aaf1d5 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -696,9 +696,9 @@ enum htt_stats_internal_ppdu_frametype { * * The message would appear as follows: * - * |31 26|25|24|23 16|15 8|7 0| - * |-----------------+----------------+----------------+---------------| - * | rsvd1 |PS|SS| ring_id | pdev_id | msg_type | + * |31 29|28|27|26|25|24|23 16|15 8|7 0| + * |-------+--+--+--+--+--+-----------+----------------+---------------| + * | rsvd1 |ED|DT|OV|PS|SS| ring_id | pdev_id | msg_type | * |-------------------------------------------------------------------| * | rsvd2 | ring_buffer_size | * |-------------------------------------------------------------------| @@ -725,7 +725,13 @@ enum htt_stats_internal_ppdu_frametype { * More details can be got from enum htt_srng_ring_id * b'24 - status_swap: 1 is to swap status TLV * b'25 - pkt_swap: 1 is to swap packet TLV - * b'26:31 - rsvd1: reserved for future use + * b'26 - rx_offset_valid (OV): flag to indicate rx offsets + * configuration fields are valid + * b'27 - drop_thresh_valid (DT): flag to indicate if the + * rx_drop_threshold field is valid + * b'28 - rx_mon_global_en: Enable/Disable global register + * configuration in Rx monitor module. + * b'29:31 - rsvd1: reserved for future use * dword1 - b'0:16 - ring_buffer_size: size of buffers referenced by rx ring, * in byte units. * Valid only for HW_TO_SW_RING and SW_TO_HW_RING From 61a0d9a879c3682391f88855220dd766bb9d6542 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 17 Dec 2024 14:15:05 +0530 Subject: [PATCH 37/60] wifi: ath12k: Refactor monitor status TLV structure The following TLV structures and bitmask definitions were inherited from the ath11k but were not updated for the ath12k 802.11be hardware. These data structure and bitmask will be used to parse the monitor status TLV data in the Rx path. 1. hal_rx_ppdu_end_user_stats_ext structure 2. hal_rx_ppdu_end_duration structure 3. HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_TXBF bitmask 4. HAL_RX_MPDU_START_INFO1_PEERID bitmask 5. HAL_INVALID_PEERID 6. hal_rx_ppdu_end_user_stats bitmask Currently, there is no issue since the monitor status Rx path is not enabled. However, in the future, the monitor status Rx path will be enabled. Therefore, update the above TLV structures and bitmask to align with the ath12k 802.11be hardware. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Acked-by: Kalle Valo Link: https://patch.msgid.link/20241217084511.2981515-3-quic_periyasa@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/hal_rx.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.h b/drivers/net/wireless/ath/ath12k/hal_rx.h index 2de7b0eba9f27..5cf3c5787ab72 100644 --- a/drivers/net/wireless/ath/ath12k/hal_rx.h +++ b/drivers/net/wireless/ath/ath12k/hal_rx.h @@ -19,7 +19,7 @@ struct hal_rx_wbm_rel_info { bool hw_cc_done; }; -#define HAL_INVALID_PEERID 0xffff +#define HAL_INVALID_PEERID 0x3fff #define VHT_SIG_SU_NSS_MASK 0x7 #define HAL_RX_MAX_MCS 12 @@ -245,6 +245,8 @@ struct hal_rx_ppdu_start { __le32 rsvd[2]; } __packed; +#define HAL_RX_PPDU_END_USER_STATS_INFO0_PEER_ID GENMASK(13, 0) +#define HAL_RX_PPDU_END_USER_STATS_INFO0_DEVICE_ID GENMASK(15, 14) #define HAL_RX_PPDU_END_USER_STATS_INFO0_MPDU_CNT_FCS_ERR GENMASK(26, 16) #define HAL_RX_PPDU_END_USER_STATS_INFO1_MPDU_CNT_FCS_OK GENMASK(10, 0) @@ -299,6 +301,7 @@ struct hal_rx_ppdu_end_user_stats_ext { __le32 info4; __le32 info5; __le32 info6; + __le32 rsvd; } __packed; #define HAL_RX_HT_SIG_INFO_INFO0_MCS GENMASK(6, 0) @@ -425,7 +428,7 @@ struct hal_rx_he_sig_b2_mu_info { #define HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_ID GENMASK(10, 0) #define HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_NSTS GENMASK(13, 11) -#define HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_TXBF BIT(19) +#define HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_TXBF BIT(14) #define HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_MCS GENMASK(18, 15) #define HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_DCM BIT(19) #define HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_CODING BIT(20) @@ -453,7 +456,8 @@ struct hal_rx_phyrx_rssi_legacy_info { } __packed; #define HAL_RX_MPDU_START_INFO0_PPDU_ID GENMASK(31, 16) -#define HAL_RX_MPDU_START_INFO1_PEERID GENMASK(31, 16) +#define HAL_RX_MPDU_START_INFO1_PEERID GENMASK(29, 16) +#define HAL_RX_MPDU_START_INFO1_DEVICE_ID GENMASK(31, 30) #define HAL_RX_MPDU_START_INFO2_MPDU_LEN GENMASK(13, 0) struct hal_rx_mpdu_start { __le32 rsvd0[9]; @@ -468,7 +472,7 @@ struct hal_rx_mpdu_start { struct hal_rx_ppdu_end_duration { __le32 rsvd0[9]; __le32 info0; - __le32 rsvd1[4]; + __le32 rsvd1[18]; } __packed; struct hal_rx_rxpcu_classification_overview { From 6a6d941a39947c359ed245fca490dcdb09551235 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 17 Dec 2024 14:15:06 +0530 Subject: [PATCH 38/60] wifi: ath12k: cleanup Rx peer statistics structure Currently, unused fields are present in the Rx peer statistics structure. These fields are already present in the same structure under the ath12k_rx_peer_rate_stats container structure. Therefore, remove the unused fields from the Rx peer statistics structure. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Acked-by: Kalle Valo Link: https://patch.msgid.link/20241217084511.2981515-4-quic_periyasa@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index ec61ad3d82c3b..b789b375b891c 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -381,10 +381,6 @@ struct ath12k_rx_peer_stats { u64 non_ampdu_msdu_count; u64 stbc_count; u64 beamformed_count; - u64 mcs_count[HAL_RX_MAX_MCS + 1]; - u64 nss_count[HAL_RX_MAX_NSS]; - u64 bw_count[HAL_RX_BW_MAX]; - u64 gi_count[HAL_RX_GI_MAX]; u64 coding_count[HAL_RX_SU_MU_CODING_MAX]; u64 tid_count[IEEE80211_NUM_TIDS + 1]; u64 pream_cnt[HAL_RX_PREAMBLE_MAX]; From b79462532cd56119fb409f81f50dc74b12724b5e Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 17 Dec 2024 14:15:07 +0530 Subject: [PATCH 39/60] wifi: ath12k: Fix the misspelled of hal TLV tag HAL_PHYRX_GENERICHT_SIG There is "HAL_PHYRX_GENERICHT_SIG" misspelled as "HAL_PHYRX_GENERIC_EHT_SIG" in the comments. Fix the spelling. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Acked-by: Kalle Valo Link: https://patch.msgid.link/20241217084511.2981515-5-quic_periyasa@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/hal_desc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/hal_desc.h b/drivers/net/wireless/ath/ath12k/hal_desc.h index b90a6da72e297..7b0403d245e59 100644 --- a/drivers/net/wireless/ath/ath12k/hal_desc.h +++ b/drivers/net/wireless/ath/ath12k/hal_desc.h @@ -522,7 +522,7 @@ enum hal_tlv_tag { HAL_PHYRXHT_SIG_USR_SU = 468 /* 0x1d4 */, HAL_PHYRXHT_SIG_USR_MU_MIMO = 469 /* 0x1d5 */, HAL_PHYRX_GENERIC_U_SIG = 470 /* 0x1d6 */, - HAL_PHYRX_GENERICHT_SIG = 471 /* 0x1d7 */, + HAL_PHYRX_GENERIC_EHT_SIG = 471 /* 0x1d7 */, HAL_OVERWRITE_RESP_START = 472 /* 0x1d8 */, HAL_OVERWRITE_RESP_PREAMBLE_INFO = 473 /* 0x1d9 */, HAL_OVERWRITE_RESP_FRAME_INFO = 474 /* 0x1da */, From ebee84cc961cd3947015efbf4a5dbea63b11c5d3 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 17 Dec 2024 14:15:08 +0530 Subject: [PATCH 40/60] wifi: ath12k: fix incorrect TID updation in DP monitor status path Currently, an incorrect TID value gets populated in the monitor status Rx path due to an incorrect bitmap value given to the ffs() built-in helper function. Therefore, avoid the decrement and directly provide the TID bitmap to the ffs() built-in helper function for the correct TID update in the monitor status Rx path. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Acked-by: Kalle Valo Link: https://patch.msgid.link/20241217084511.2981515-6-quic_periyasa@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/dp_mon.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index c6cc4a1a52304..d9b0087a7a25a 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -617,6 +617,7 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab, case HAL_RX_PPDU_END_USER_STATS: { struct hal_rx_ppdu_end_user_stats *eu_stats = (struct hal_rx_ppdu_end_user_stats *)tlv_data; + u32 tid_bitmap; info[0] = __le32_to_cpu(eu_stats->info0); info[1] = __le32_to_cpu(eu_stats->info1); @@ -629,10 +630,9 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab, u32_get_bits(info[2], HAL_RX_PPDU_END_USER_STATS_INFO2_AST_INDEX); ppdu_info->fc_valid = u32_get_bits(info[1], HAL_RX_PPDU_END_USER_STATS_INFO1_FC_VALID); - ppdu_info->tid = - ffs(u32_get_bits(info[6], - HAL_RX_PPDU_END_USER_STATS_INFO6_TID_BITMAP) - - 1); + tid_bitmap = u32_get_bits(info[6], + HAL_RX_PPDU_END_USER_STATS_INFO6_TID_BITMAP); + ppdu_info->tid = ffs(tid_bitmap) - 1; ppdu_info->tcp_msdu_count = u32_get_bits(info[4], HAL_RX_PPDU_END_USER_STATS_INFO4_TCP_MSDU_CNT); From 0345f28a122656a4703442a2a97d2dca370c27a0 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 17 Dec 2024 14:15:09 +0530 Subject: [PATCH 41/60] wifi: ath12k: Remove unused HAL Rx mask in DP monitor path Currently, CODING and TXBF are unused masks defined in the HAL Rx monitor status TLV parsing code path. Therefore, remove the unused masks to prevent incorrect assumptions for code readers. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Acked-by: Kalle Valo Link: https://patch.msgid.link/20241217084511.2981515-7-quic_periyasa@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/hal_rx.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.h b/drivers/net/wireless/ath/ath12k/hal_rx.h index 5cf3c5787ab72..b08aa2e79f411 100644 --- a/drivers/net/wireless/ath/ath12k/hal_rx.h +++ b/drivers/net/wireless/ath/ath12k/hal_rx.h @@ -398,11 +398,9 @@ struct hal_rx_he_sig_a_su_info { #define HAL_RX_HE_SIG_A_MU_DL_INFO0_DOPPLER_INDICATION BIT(25) #define HAL_RX_HE_SIG_A_MU_DL_INFO1_TXOP_DURATION GENMASK(6, 0) -#define HAL_RX_HE_SIG_A_MU_DL_INFO1_CODING BIT(7) #define HAL_RX_HE_SIG_A_MU_DL_INFO1_NUM_LTF_SYMB GENMASK(10, 8) #define HAL_RX_HE_SIG_A_MU_DL_INFO1_LDPC_EXTRA BIT(11) #define HAL_RX_HE_SIG_A_MU_DL_INFO1_STBC BIT(12) -#define HAL_RX_HE_SIG_A_MU_DL_INFO1_TXBF BIT(10) #define HAL_RX_HE_SIG_A_MU_DL_INFO1_PKT_EXT_FACTOR GENMASK(14, 13) #define HAL_RX_HE_SIG_A_MU_DL_INFO1_PKT_EXT_PE_DISAM BIT(15) From 61f247a06c3cdeb9093b3d90afd7d51168d089f4 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 17 Dec 2024 14:15:10 +0530 Subject: [PATCH 42/60] wifi: ath12k: Change the Tx monitor SRNG ring ID The Tx monitor SRNG ring ID does not align with the ath12k 802.11be hardware architecture. Currently, there is no issue since the Tx monitor is not enabled. However, in the future, the Tx monitor will be enabled. Therefore, change the HAL_SRNG_RING_ID_WMAC1_SW2TXMON_BUF0 SRNG ID and assign the correct start ring ID for the ring type HAL_TX_MONITOR_BUF. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Acked-by: Kalle Valo Link: https://patch.msgid.link/20241217084511.2981515-8-quic_periyasa@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/hal.c | 2 +- drivers/net/wireless/ath/ath12k/hal.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index fd98fac16dd5f..cd59ff8e6c7b0 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -181,7 +181,7 @@ static const struct hal_srng_config hw_srng_config_template[] = { .max_size = HAL_WBM2PPE_RELEASE_RING_BASE_MSB_RING_SIZE, }, [HAL_TX_MONITOR_BUF] = { - .start_ring_id = HAL_SRNG_SW2TXMON_BUF0, + .start_ring_id = HAL_SRNG_RING_ID_WMAC1_SW2TXMON_BUF0, .max_rings = 1, .entry_size = sizeof(struct hal_mon_buf_ring) >> 2, .mac_type = ATH12K_HAL_SRNG_PMAC, diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index 8a78bb9a10bc1..94e2e87359583 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -485,8 +485,8 @@ enum hal_srng_ring_id { HAL_SRNG_RING_ID_WMAC1_RXMON2SW0 = HAL_SRNG_RING_ID_WMAC1_RXDMA2SW1, HAL_SRNG_RING_ID_WMAC1_SW2RXDMA1_DESC, HAL_SRNG_RING_ID_RXDMA_DIR_BUF, - HAL_SRNG_RING_ID_WMAC1_SW2TXMON_BUF0, HAL_SRNG_RING_ID_WMAC1_TXMON2SW0_BUF0, + HAL_SRNG_RING_ID_WMAC1_SW2TXMON_BUF0, HAL_SRNG_RING_ID_PMAC1_ID_END, }; From 8534c42397ed8f05257dbddcd305a351ad40add1 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 17 Dec 2024 14:15:11 +0530 Subject: [PATCH 43/60] wifi: ath12k: Avoid explicit type cast in monitor status parse handler Currently, monitor status parse procedure handles all the supported TLV tags. Each TLV tag has its own data structure for parsing. Now, this handler is passed the tlv_data as a u8 pointer, so explicit type cast conversion happens for every TLV tag parsing. Therefore, avoid the explicit type conversion by changing the tlv_data type from a u8 pointer to a const void pointer. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Acked-by: Kalle Valo Link: https://patch.msgid.link/20241217084511.2981515-9-quic_periyasa@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/dp_mon.c | 126 +++++++++-------------- 1 file changed, 47 insertions(+), 79 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index d9b0087a7a25a..5a21961cfd465 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -10,11 +10,10 @@ #include "dp_tx.h" #include "peer.h" -static void ath12k_dp_mon_rx_handle_ofdma_info(void *rx_tlv, - struct hal_rx_user_status *rx_user_status) +static void +ath12k_dp_mon_rx_handle_ofdma_info(const struct hal_rx_ppdu_end_user_stats *ppdu_end_user, + struct hal_rx_user_status *rx_user_status) { - struct hal_rx_ppdu_end_user_stats *ppdu_end_user = rx_tlv; - rx_user_status->ul_ofdma_user_v0_word0 = __le32_to_cpu(ppdu_end_user->usr_resp_ref); rx_user_status->ul_ofdma_user_v0_word1 = @@ -35,7 +34,7 @@ ath12k_dp_mon_rx_populate_byte_count(const struct hal_rx_ppdu_end_user_stats *st } static void -ath12k_dp_mon_rx_populate_mu_user_info(void *rx_tlv, +ath12k_dp_mon_rx_populate_mu_user_info(const struct hal_rx_ppdu_end_user_stats *rx_tlv, struct hal_rx_mon_ppdu_info *ppdu_info, struct hal_rx_user_status *rx_user_status) { @@ -73,11 +72,9 @@ ath12k_dp_mon_rx_populate_mu_user_info(void *rx_tlv, ath12k_dp_mon_rx_populate_byte_count(rx_tlv, ppdu_info, rx_user_status); } -static void ath12k_dp_mon_parse_vht_sig_a(u8 *tlv_data, +static void ath12k_dp_mon_parse_vht_sig_a(const struct hal_rx_vht_sig_a_info *vht_sig, struct hal_rx_mon_ppdu_info *ppdu_info) { - struct hal_rx_vht_sig_a_info *vht_sig = - (struct hal_rx_vht_sig_a_info *)tlv_data; u32 nsts, group_id, info0, info1; u8 gi_setting; @@ -119,11 +116,9 @@ static void ath12k_dp_mon_parse_vht_sig_a(u8 *tlv_data, u32_get_bits(info1, HAL_RX_VHT_SIG_A_INFO_INFO1_SU_MU_CODING); } -static void ath12k_dp_mon_parse_ht_sig(u8 *tlv_data, +static void ath12k_dp_mon_parse_ht_sig(const struct hal_rx_ht_sig_info *ht_sig, struct hal_rx_mon_ppdu_info *ppdu_info) { - struct hal_rx_ht_sig_info *ht_sig = - (struct hal_rx_ht_sig_info *)tlv_data; u32 info0 = __le32_to_cpu(ht_sig->info0); u32 info1 = __le32_to_cpu(ht_sig->info1); @@ -136,11 +131,9 @@ static void ath12k_dp_mon_parse_ht_sig(u8 *tlv_data, ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_SU; } -static void ath12k_dp_mon_parse_l_sig_b(u8 *tlv_data, +static void ath12k_dp_mon_parse_l_sig_b(const struct hal_rx_lsig_b_info *lsigb, struct hal_rx_mon_ppdu_info *ppdu_info) { - struct hal_rx_lsig_b_info *lsigb = - (struct hal_rx_lsig_b_info *)tlv_data; u32 info0 = __le32_to_cpu(lsigb->info0); u8 rate; @@ -170,11 +163,9 @@ static void ath12k_dp_mon_parse_l_sig_b(u8 *tlv_data, ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_SU; } -static void ath12k_dp_mon_parse_l_sig_a(u8 *tlv_data, +static void ath12k_dp_mon_parse_l_sig_a(const struct hal_rx_lsig_a_info *lsiga, struct hal_rx_mon_ppdu_info *ppdu_info) { - struct hal_rx_lsig_a_info *lsiga = - (struct hal_rx_lsig_a_info *)tlv_data; u32 info0 = __le32_to_cpu(lsiga->info0); u8 rate; @@ -212,14 +203,13 @@ static void ath12k_dp_mon_parse_l_sig_a(u8 *tlv_data, ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_SU; } -static void ath12k_dp_mon_parse_he_sig_b2_ofdma(u8 *tlv_data, - struct hal_rx_mon_ppdu_info *ppdu_info) +static void +ath12k_dp_mon_parse_he_sig_b2_ofdma(const struct hal_rx_he_sig_b2_ofdma_info *ofdma, + struct hal_rx_mon_ppdu_info *ppdu_info) { - struct hal_rx_he_sig_b2_ofdma_info *he_sig_b2_ofdma = - (struct hal_rx_he_sig_b2_ofdma_info *)tlv_data; u32 info0, value; - info0 = __le32_to_cpu(he_sig_b2_ofdma->info0); + info0 = __le32_to_cpu(ofdma->info0); ppdu_info->he_data1 |= HE_MCS_KNOWN | HE_DCM_KNOWN | HE_CODING_KNOWN; @@ -250,11 +240,10 @@ static void ath12k_dp_mon_parse_he_sig_b2_ofdma(u8 *tlv_data, ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_OFDMA; } -static void ath12k_dp_mon_parse_he_sig_b2_mu(u8 *tlv_data, - struct hal_rx_mon_ppdu_info *ppdu_info) +static void +ath12k_dp_mon_parse_he_sig_b2_mu(const struct hal_rx_he_sig_b2_mu_info *he_sig_b2_mu, + struct hal_rx_mon_ppdu_info *ppdu_info) { - struct hal_rx_he_sig_b2_mu_info *he_sig_b2_mu = - (struct hal_rx_he_sig_b2_mu_info *)tlv_data; u32 info0, value; info0 = __le32_to_cpu(he_sig_b2_mu->info0); @@ -277,11 +266,10 @@ static void ath12k_dp_mon_parse_he_sig_b2_mu(u8 *tlv_data, ppdu_info->nss = u32_get_bits(info0, HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_NSTS); } -static void ath12k_dp_mon_parse_he_sig_b1_mu(u8 *tlv_data, - struct hal_rx_mon_ppdu_info *ppdu_info) +static void +ath12k_dp_mon_parse_he_sig_b1_mu(const struct hal_rx_he_sig_b1_mu_info *he_sig_b1_mu, + struct hal_rx_mon_ppdu_info *ppdu_info) { - struct hal_rx_he_sig_b1_mu_info *he_sig_b1_mu = - (struct hal_rx_he_sig_b1_mu_info *)tlv_data; u32 info0 = __le32_to_cpu(he_sig_b1_mu->info0); u16 ru_tones; @@ -292,11 +280,10 @@ static void ath12k_dp_mon_parse_he_sig_b1_mu(u8 *tlv_data, ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_MIMO; } -static void ath12k_dp_mon_parse_he_sig_mu(u8 *tlv_data, - struct hal_rx_mon_ppdu_info *ppdu_info) +static void +ath12k_dp_mon_parse_he_sig_mu(const struct hal_rx_he_sig_a_mu_dl_info *he_sig_a_mu_dl, + struct hal_rx_mon_ppdu_info *ppdu_info) { - struct hal_rx_he_sig_a_mu_dl_info *he_sig_a_mu_dl = - (struct hal_rx_he_sig_a_mu_dl_info *)tlv_data; u32 info0, info1, value; u16 he_gi = 0, he_ltf = 0; @@ -427,11 +414,9 @@ static void ath12k_dp_mon_parse_he_sig_mu(u8 *tlv_data, ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_MIMO; } -static void ath12k_dp_mon_parse_he_sig_su(u8 *tlv_data, +static void ath12k_dp_mon_parse_he_sig_su(const struct hal_rx_he_sig_a_su_info *he_sig_a, struct hal_rx_mon_ppdu_info *ppdu_info) { - struct hal_rx_he_sig_a_su_info *he_sig_a = - (struct hal_rx_he_sig_a_su_info *)tlv_data; u32 info0, info1, value; u32 dcm; u8 he_dcm = 0, he_stbc = 0; @@ -580,15 +565,15 @@ static void ath12k_dp_mon_parse_he_sig_su(u8 *tlv_data, static enum hal_rx_mon_status ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab, struct ath12k_mon_data *pmon, - u32 tlv_tag, u8 *tlv_data, u32 userid) + u32 tlv_tag, const void *tlv_data, + u32 userid) { struct hal_rx_mon_ppdu_info *ppdu_info = &pmon->mon_ppdu_info; u32 info[7]; switch (tlv_tag) { case HAL_RX_PPDU_START: { - struct hal_rx_ppdu_start *ppdu_start = - (struct hal_rx_ppdu_start *)tlv_data; + const struct hal_rx_ppdu_start *ppdu_start = tlv_data; u64 ppdu_ts = ath12k_le32hilo_to_u64(ppdu_start->ppdu_start_ts_63_32, ppdu_start->ppdu_start_ts_31_0); @@ -615,8 +600,7 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab, break; } case HAL_RX_PPDU_END_USER_STATS: { - struct hal_rx_ppdu_end_user_stats *eu_stats = - (struct hal_rx_ppdu_end_user_stats *)tlv_data; + const struct hal_rx_ppdu_end_user_stats *eu_stats = tlv_data; u32 tid_bitmap; info[0] = __le32_to_cpu(eu_stats->info0); @@ -673,8 +657,8 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab, &ppdu_info->userstats[userid]; ppdu_info->num_users += 1; - ath12k_dp_mon_rx_handle_ofdma_info(tlv_data, rxuser_stats); - ath12k_dp_mon_rx_populate_mu_user_info(tlv_data, ppdu_info, + ath12k_dp_mon_rx_handle_ofdma_info(eu_stats, rxuser_stats); + ath12k_dp_mon_rx_populate_mu_user_info(eu_stats, ppdu_info, rxuser_stats); } ppdu_info->mpdu_fcs_ok_bitmap[0] = __le32_to_cpu(eu_stats->rsvd1[0]); @@ -682,8 +666,8 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab, break; } case HAL_RX_PPDU_END_USER_STATS_EXT: { - struct hal_rx_ppdu_end_user_stats_ext *eu_stats = - (struct hal_rx_ppdu_end_user_stats_ext *)tlv_data; + const struct hal_rx_ppdu_end_user_stats_ext *eu_stats = tlv_data; + ppdu_info->mpdu_fcs_ok_bitmap[2] = __le32_to_cpu(eu_stats->info1); ppdu_info->mpdu_fcs_ok_bitmap[3] = __le32_to_cpu(eu_stats->info2); ppdu_info->mpdu_fcs_ok_bitmap[4] = __le32_to_cpu(eu_stats->info3); @@ -729,8 +713,7 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab, break; case HAL_PHYRX_RSSI_LEGACY: { - struct hal_rx_phyrx_rssi_legacy_info *rssi = - (struct hal_rx_phyrx_rssi_legacy_info *)tlv_data; + const struct hal_rx_phyrx_rssi_legacy_info *rssi = tlv_data; info[0] = __le32_to_cpu(rssi->info0); info[1] = __le32_to_cpu(rssi->info1); @@ -748,8 +731,7 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab, break; } case HAL_RXPCU_PPDU_END_INFO: { - struct hal_rx_ppdu_end_duration *ppdu_rx_duration = - (struct hal_rx_ppdu_end_duration *)tlv_data; + const struct hal_rx_ppdu_end_duration *ppdu_rx_duration = tlv_data; info[0] = __le32_to_cpu(ppdu_rx_duration->info0); ppdu_info->rx_duration = @@ -760,8 +742,7 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab, break; } case HAL_RX_MPDU_START: { - struct hal_rx_mpdu_start *mpdu_start = - (struct hal_rx_mpdu_start *)tlv_data; + const struct hal_rx_mpdu_start *mpdu_start = tlv_data; struct dp_mon_mpdu *mon_mpdu = pmon->mon_mpdu; u16 peer_id; @@ -790,8 +771,7 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab, break; case HAL_MON_BUF_ADDR: { struct dp_rxdma_mon_ring *buf_ring = &ab->dp.rxdma_mon_buf_ring; - struct dp_mon_packet_info *packet_info = - (struct dp_mon_packet_info *)tlv_data; + const struct dp_mon_packet_info *packet_info = tlv_data; int buf_id = u32_get_bits(packet_info->cookie, DP_RXDMA_BUF_COOKIE_BUF_ID); struct sk_buff *msdu; @@ -823,8 +803,7 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab, break; } case HAL_RX_MSDU_END: { - struct rx_msdu_end_qcn9274 *msdu_end = - (struct rx_msdu_end_qcn9274 *)tlv_data; + const struct rx_msdu_end_qcn9274 *msdu_end = tlv_data; bool is_first_msdu_in_mpdu; u16 msdu_end_info; @@ -1609,7 +1588,7 @@ ath12k_dp_mon_tx_gen_prot_frame(struct dp_mon_tx_ppdu_info *tx_ppdu_info) static enum dp_mon_tx_tlv_status ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab, struct ath12k_mon_data *pmon, - u16 tlv_tag, u8 *tlv_data, u32 userid) + u16 tlv_tag, const void *tlv_data, u32 userid) { struct dp_mon_tx_ppdu_info *tx_ppdu_info; enum dp_mon_tx_tlv_status status = DP_MON_TX_STATUS_PPDU_NOT_DONE; @@ -1619,8 +1598,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab, switch (tlv_tag) { case HAL_TX_FES_SETUP: { - struct hal_tx_fes_setup *tx_fes_setup = - (struct hal_tx_fes_setup *)tlv_data; + const struct hal_tx_fes_setup *tx_fes_setup = tlv_data; info[0] = __le32_to_cpu(tx_fes_setup->info0); tx_ppdu_info->ppdu_id = __le32_to_cpu(tx_fes_setup->schedule_id); @@ -1631,8 +1609,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab, } case HAL_TX_FES_STATUS_END: { - struct hal_tx_fes_status_end *tx_fes_status_end = - (struct hal_tx_fes_status_end *)tlv_data; + const struct hal_tx_fes_status_end *tx_fes_status_end = tlv_data; u32 tst_15_0, tst_31_16; info[0] = __le32_to_cpu(tx_fes_status_end->info0); @@ -1649,8 +1626,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab, } case HAL_RX_RESPONSE_REQUIRED_INFO: { - struct hal_rx_resp_req_info *rx_resp_req_info = - (struct hal_rx_resp_req_info *)tlv_data; + const struct hal_rx_resp_req_info *rx_resp_req_info = tlv_data; u32 addr_32; u16 addr_16; @@ -1695,8 +1671,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab, } case HAL_PCU_PPDU_SETUP_INIT: { - struct hal_tx_pcu_ppdu_setup_init *ppdu_setup = - (struct hal_tx_pcu_ppdu_setup_init *)tlv_data; + const struct hal_tx_pcu_ppdu_setup_init *ppdu_setup = tlv_data; u32 addr_32; u16 addr_16; @@ -1742,8 +1717,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab, } case HAL_TX_QUEUE_EXTENSION: { - struct hal_tx_queue_exten *tx_q_exten = - (struct hal_tx_queue_exten *)tlv_data; + const struct hal_tx_queue_exten *tx_q_exten = tlv_data; info[0] = __le32_to_cpu(tx_q_exten->info0); @@ -1755,8 +1729,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab, } case HAL_TX_FES_STATUS_START: { - struct hal_tx_fes_status_start *tx_fes_start = - (struct hal_tx_fes_status_start *)tlv_data; + const struct hal_tx_fes_status_start *tx_fes_start = tlv_data; info[0] = __le32_to_cpu(tx_fes_start->info0); @@ -1767,8 +1740,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab, } case HAL_TX_FES_STATUS_PROT: { - struct hal_tx_fes_status_prot *tx_fes_status = - (struct hal_tx_fes_status_prot *)tlv_data; + const struct hal_tx_fes_status_prot *tx_fes_status = tlv_data; u32 start_timestamp; u32 end_timestamp; @@ -1795,8 +1767,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab, case HAL_TX_FES_STATUS_START_PPDU: case HAL_TX_FES_STATUS_START_PROT: { - struct hal_tx_fes_status_start_prot *tx_fes_stat_start = - (struct hal_tx_fes_status_start_prot *)tlv_data; + const struct hal_tx_fes_status_start_prot *tx_fes_stat_start = tlv_data; u64 ppdu_ts; info[0] = __le32_to_cpu(tx_fes_stat_start->info0); @@ -1811,8 +1782,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab, } case HAL_TX_FES_STATUS_USER_PPDU: { - struct hal_tx_fes_status_user_ppdu *tx_fes_usr_ppdu = - (struct hal_tx_fes_status_user_ppdu *)tlv_data; + const struct hal_tx_fes_status_user_ppdu *tx_fes_usr_ppdu = tlv_data; info[0] = __le32_to_cpu(tx_fes_usr_ppdu->info0); @@ -1855,8 +1825,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab, break; case HAL_RX_FRAME_BITMAP_ACK: { - struct hal_rx_frame_bitmap_ack *fbm_ack = - (struct hal_rx_frame_bitmap_ack *)tlv_data; + const struct hal_rx_frame_bitmap_ack *fbm_ack = tlv_data; u32 addr_32; u16 addr_16; @@ -1874,8 +1843,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab, } case HAL_MACTX_PHY_DESC: { - struct hal_tx_phy_desc *tx_phy_desc = - (struct hal_tx_phy_desc *)tlv_data; + const struct hal_tx_phy_desc *tx_phy_desc = tlv_data; info[0] = __le32_to_cpu(tx_phy_desc->info0); info[1] = __le32_to_cpu(tx_phy_desc->info1); From 578f6fc55c2ced5f68a7f87edbf6db3663dc6b57 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 17 Dec 2024 10:55:05 +0000 Subject: [PATCH 44/60] wifi: ath12k: Fix spelling mistake "requestted" -> "requested" There is a spelling mistake in an ath12k_err error message. Fix it. Signed-off-by: Colin Ian King Acked-by: Kalle Valo Link: https://patch.msgid.link/20241217105505.306047-1-colin.i.king@gmail.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/qmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index a8ed86a294c31..5c3563383fabb 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -2618,7 +2618,7 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab) if (!ag->mlo_mem.mlo_mem_size) { ag->mlo_mem.mlo_mem_size = mlo_size; } else if (ag->mlo_mem.mlo_mem_size != mlo_size) { - ath12k_err(ab, "QMI MLO memory size error, expected size is %d but requestted size is %d", + ath12k_err(ab, "QMI MLO memory size error, expected size is %d but requested size is %d", ag->mlo_mem.mlo_mem_size, mlo_size); ret = -EINVAL; goto err; From d31241cbd9c5d74eb19192e57806e9c9ee3378f7 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Wed, 18 Dec 2024 09:11:32 +0530 Subject: [PATCH 45/60] wifi: ath12k: rename CAC_RUNNING flag Rename the flag ATH12K_CAC_RUNNING to ATH12K_FLAG_CAC_RUNNING to correct the naming inconsistency in the enum ath12k_dev_flags. No functionality changes. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aditya Kumar Singh Acked-by: Kalle Valo Link: https://patch.msgid.link/20241218-ath12k_mlo_dfs-v1-1-058e783bcfc7@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.h | 2 +- drivers/net/wireless/ath/ath12k/dp_rx.c | 6 +++--- drivers/net/wireless/ath/ath12k/mac.c | 8 ++++---- drivers/net/wireless/ath/ath12k/wmi.c | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index b789b375b891c..3dd01ad100c56 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -223,7 +223,7 @@ enum ath12k_hw_group_flags { }; enum ath12k_dev_flags { - ATH12K_CAC_RUNNING, + ATH12K_FLAG_CAC_RUNNING, ATH12K_FLAG_CRASH_FLUSH, ATH12K_FLAG_RAW_MODE, ATH12K_FLAG_HW_CRYPTO_DISABLED, diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 5c5a3aae393be..dad35bfd83f62 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -2632,7 +2632,7 @@ static void ath12k_dp_rx_process_received_packets(struct ath12k_base *ab, continue; } - if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) { + if (test_bit(ATH12K_FLAG_CAC_RUNNING, &ar->dev_flags)) { dev_kfree_skb_any(msdu); continue; } @@ -3484,7 +3484,7 @@ ath12k_dp_process_rx_err_buf(struct ath12k *ar, struct hal_reo_dest_ring *desc, goto exit; } - if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) { + if (test_bit(ATH12K_FLAG_CAC_RUNNING, &ar->dev_flags)) { dev_kfree_skb_any(msdu); goto exit; } @@ -4037,7 +4037,7 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, continue; } - if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) { + if (test_bit(ATH12K_FLAG_CAC_RUNNING, &ar->dev_flags)) { dev_kfree_skb_any(msdu); continue; } diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 6f10813d93782..095e9c91cc16b 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -1323,8 +1323,8 @@ int ath12k_mac_vdev_stop(struct ath12k_link_vif *arvif) ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "vdev %pM stopped, vdev_id %d\n", ahvif->vif->addr, arvif->vdev_id); - if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) { - clear_bit(ATH12K_CAC_RUNNING, &ar->dev_flags); + if (test_bit(ATH12K_FLAG_CAC_RUNNING, &ar->dev_flags)) { + clear_bit(ATH12K_FLAG_CAC_RUNNING, &ar->dev_flags); ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "CAC Stopped for vdev %d\n", arvif->vdev_id); } @@ -7475,7 +7475,7 @@ static void ath12k_mac_stop(struct ath12k *ar) ath12k_err(ar->ab, "failed to clear rx_filter for monitor status ring: (%d)\n", ret); - clear_bit(ATH12K_CAC_RUNNING, &ar->dev_flags); + clear_bit(ATH12K_FLAG_CAC_RUNNING, &ar->dev_flags); cancel_delayed_work_sync(&ar->scan.timeout); wiphy_work_cancel(ath12k_ar_to_hw(ar)->wiphy, &ar->scan.vdev_clean_wk); @@ -8794,7 +8794,7 @@ ath12k_mac_vdev_start_restart(struct ath12k_link_vif *arvif, if (arvif->ahvif->vdev_type == WMI_VDEV_TYPE_AP && chandef->chan->dfs_cac_ms && chandef->chan->dfs_state == NL80211_DFS_USABLE) { - set_bit(ATH12K_CAC_RUNNING, &ar->dev_flags); + set_bit(ATH12K_FLAG_CAC_RUNNING, &ar->dev_flags); ath12k_dbg(ab, ATH12K_DBG_MAC, "CAC Started in chan_freq %d for vdev %d\n", arg.freq, arg.vdev_id); diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 562b0615ed065..d0ae7f142c11a 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -6212,7 +6212,7 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb) goto exit; } - if ((test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) || + if ((test_bit(ATH12K_FLAG_CAC_RUNNING, &ar->dev_flags)) || (rx_ev.status & (WMI_RX_STATUS_ERR_DECRYPT | WMI_RX_STATUS_ERR_KEY_CACHE_MISS | WMI_RX_STATUS_ERR_CRC))) { From 11b86e2ce94278332af8da9c0b560a15c17efd26 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Wed, 18 Dec 2024 09:11:33 +0530 Subject: [PATCH 46/60] wifi: ath12k: fix CAC running state during virtual interface start Currently, the DFS CAC time and the usable state of the primary channel in the channel definition are used to set the CAC_RUNNING flag for the ath12k radio structure. However, this approach is flawed because there are channel definitions where the primary channel is not a DFS channel, but the secondary channel is. For example, in 5 GHz band, channel 36 with 160 MHz bandwidth. In such cases, the flag is not set correctly and hence places where this flag is tested will not operate as expected. For example, Rx packets will not be dropped. To fix this issue, use the cfg80211_chandef_dfs_usable() function from cfg80211, which returns true if at least one channel is in a usable state. This will ensure the CAC_RUNNING flag is set properly. Additionally, update the CAC running debug log message to include the CAC time in milliseconds and also print the center frequency segment 1. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aditya Kumar Singh Acked-by: Kalle Valo Link: https://patch.msgid.link/20241218-ath12k_mlo_dfs-v1-2-058e783bcfc7@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 095e9c91cc16b..7f1e39d9c3b4a 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5,6 +5,7 @@ */ #include +#include #include #include "mac.h" @@ -8682,11 +8683,13 @@ ath12k_mac_vdev_start_restart(struct ath12k_link_vif *arvif, struct ath12k_base *ab = ar->ab; struct wmi_vdev_start_req_arg arg = {}; const struct cfg80211_chan_def *chandef = &ctx->def; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); struct ath12k_vif *ahvif = arvif->ahvif; struct ieee80211_bss_conf *link_conf; + unsigned int dfs_cac_time; int ret; - lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + lockdep_assert_wiphy(hw->wiphy); link_conf = ath12k_mac_get_link_bss_conf(arvif); if (!link_conf) { @@ -8784,20 +8787,20 @@ ath12k_mac_vdev_start_restart(struct ath12k_link_vif *arvif, ath12k_dbg(ab, ATH12K_DBG_MAC, "vdev %pM started, vdev_id %d\n", ahvif->vif->addr, arvif->vdev_id); - /* Enable CAC Flag in the driver by checking the channel DFS cac time, - * i.e dfs_cac_ms value which will be valid only for radar channels - * and state as NL80211_DFS_USABLE which indicates CAC needs to be - * done before channel usage. This flags is used to drop rx packets. + /* Enable CAC Running Flag in the driver by checking all sub-channel's DFS + * state as NL80211_DFS_USABLE which indicates CAC needs to be + * done before channel usage. This flag is used to drop rx packets. * during CAC. */ /* TODO: Set the flag for other interface types as required */ - if (arvif->ahvif->vdev_type == WMI_VDEV_TYPE_AP && - chandef->chan->dfs_cac_ms && - chandef->chan->dfs_state == NL80211_DFS_USABLE) { + if (arvif->ahvif->vdev_type == WMI_VDEV_TYPE_AP && ctx->radar_enabled && + cfg80211_chandef_dfs_usable(hw->wiphy, chandef)) { set_bit(ATH12K_FLAG_CAC_RUNNING, &ar->dev_flags); + dfs_cac_time = cfg80211_chandef_dfs_cac_time(hw->wiphy, chandef); + ath12k_dbg(ab, ATH12K_DBG_MAC, - "CAC Started in chan_freq %d for vdev %d\n", - arg.freq, arg.vdev_id); + "CAC started dfs_cac_time %u center_freq %d center_freq1 %d for vdev %d\n", + dfs_cac_time, arg.freq, arg.band_center_freq1, arg.vdev_id); } ret = ath12k_mac_set_txbf_conf(arvif); From 40562e84e262dcc1c7226a0094761f6b5eec8153 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Wed, 18 Dec 2024 09:11:34 +0530 Subject: [PATCH 47/60] wifi: ath12k: handle radar detection with MLO ieee80211_radar_detected() expects the driver to pass a channel context configuration during MLO. This is used to identify exactly which link detected the radar. Add support to pass this to mac80211. Since the link arvif is not known in the WMI event, introduce a helper iterator API, ath12k_mac_get_any_chanctx_conf_iter(), to get the channel context configuration. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aditya Kumar Singh Acked-by: Kalle Valo Link: https://patch.msgid.link/20241218-ath12k_mlo_dfs-v1-3-058e783bcfc7@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 11 +++++++++++ drivers/net/wireless/ath/ath12k/mac.h | 8 ++++++++ drivers/net/wireless/ath/ath12k/wmi.c | 12 +++++++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 7f1e39d9c3b4a..9a5402803d72d 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -751,6 +751,17 @@ static struct ath12k *ath12k_get_ar_by_vif(struct ieee80211_hw *hw, return NULL; } +void ath12k_mac_get_any_chanctx_conf_iter(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf, + void *data) +{ + struct ath12k_mac_get_any_chanctx_conf_arg *arg = data; + struct ath12k *ctx_ar = ath12k_get_ar_by_ctx(hw, conf); + + if (ctx_ar == arg->ar) + arg->chanctx_conf = conf; +} + static struct ath12k_link_vif *ath12k_mac_get_vif_up(struct ath12k *ar) { struct ath12k_link_vif *arvif; diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h index 81cfb950e6cdd..3594729b63974 100644 --- a/drivers/net/wireless/ath/ath12k/mac.h +++ b/drivers/net/wireless/ath/ath12k/mac.h @@ -59,6 +59,11 @@ enum ath12k_supported_bw { ATH12K_BW_320 = 4, }; +struct ath12k_mac_get_any_chanctx_conf_arg { + struct ath12k *ar; + struct ieee80211_chanctx_conf *chanctx_conf; +}; + extern const struct htt_rx_ring_tlv_filter ath12k_mac_mon_status_filter_default; void ath12k_mac_destroy(struct ath12k_hw_group *ag); @@ -100,5 +105,8 @@ int ath12k_mac_mlo_setup(struct ath12k_hw_group *ag); int ath12k_mac_mlo_ready(struct ath12k_hw_group *ag); void ath12k_mac_mlo_teardown(struct ath12k_hw_group *ag); int ath12k_mac_vdev_stop(struct ath12k_link_vif *arvif); +void ath12k_mac_get_any_chanctx_conf_iter(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf, + void *data); #endif diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index d0ae7f142c11a..9a96c4d70e600 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -6935,6 +6935,7 @@ static void ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff *skb) { const void **tb; + struct ath12k_mac_get_any_chanctx_conf_arg arg; const struct ath12k_wmi_pdev_radar_event *ev; struct ath12k *ar; int ret; @@ -6970,13 +6971,22 @@ ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff goto exit; } + arg.ar = ar; + arg.chanctx_conf = NULL; + ieee80211_iter_chan_contexts_atomic(ath12k_ar_to_hw(ar), + ath12k_mac_get_any_chanctx_conf_iter, &arg); + if (!arg.chanctx_conf) { + ath12k_warn(ab, "failed to find valid chanctx_conf in radar detected event\n"); + goto exit; + } + ath12k_dbg(ar->ab, ATH12K_DBG_REG, "DFS Radar Detected in pdev %d\n", ev->pdev_id); if (ar->dfs_block_radar_events) ath12k_info(ab, "DFS Radar detected, but ignored as requested\n"); else - ieee80211_radar_detected(ath12k_ar_to_hw(ar), NULL); + ieee80211_radar_detected(ath12k_ar_to_hw(ar), arg.chanctx_conf); exit: rcu_read_unlock(); From 9035756c18852cf39eeb11b625db094a2c9a4bb9 Mon Sep 17 00:00:00 2001 From: Raj Kumar Bhagat Date: Wed, 18 Dec 2024 09:31:49 +0530 Subject: [PATCH 48/60] wifi: ath12k: Include MLO memory in firmware coredump collection The current firmware coredump collection in ath12k does not include the MLO_GLOBAL_MEM_REGION_TYPE memory. This memory region is essential for debugging issues related to Multi-Link Operation (MLO). Hence, add support to include MLO_GLOBAL_MEM_REGION_TYPE memory in firmware coredump collection. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Signed-off-by: Raj Kumar Bhagat Acked-by: Kalle Valo Link: https://patch.msgid.link/20241218040149.4041728-1-quic_rajkbhag@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/coredump.c | 3 +++ drivers/net/wireless/ath/ath12k/coredump.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/coredump.c b/drivers/net/wireless/ath/ath12k/coredump.c index 72d675d15e648..ce1beeb548366 100644 --- a/drivers/net/wireless/ath/ath12k/coredump.c +++ b/drivers/net/wireless/ath/ath12k/coredump.c @@ -27,6 +27,9 @@ ath12k_fw_crash_dump_type ath12k_coredump_get_dump_type(enum ath12k_qmi_target_m case CALDB_MEM_REGION_TYPE: dump_type = FW_CRASH_DUMP_NONE; break; + case MLO_GLOBAL_MEM_REGION_TYPE: + dump_type = FW_CRASH_DUMP_MLO_GLOBAL_DATA; + break; default: dump_type = FW_CRASH_DUMP_TYPE_MAX; break; diff --git a/drivers/net/wireless/ath/ath12k/coredump.h b/drivers/net/wireless/ath/ath12k/coredump.h index 5d6003b1c12dc..13f46a6051134 100644 --- a/drivers/net/wireless/ath/ath12k/coredump.h +++ b/drivers/net/wireless/ath/ath12k/coredump.h @@ -15,6 +15,7 @@ enum ath12k_fw_crash_dump_type { FW_CRASH_DUMP_PAGEABLE_DATA, FW_CRASH_DUMP_M3_DUMP, FW_CRASH_DUMP_NONE, + FW_CRASH_DUMP_MLO_GLOBAL_DATA, /* keep last */ FW_CRASH_DUMP_TYPE_MAX, From 2d64da9ed5d8cee44a11ed3872dbfa6a914ee2b2 Mon Sep 17 00:00:00 2001 From: Ramya Gnanasekar Date: Thu, 19 Dec 2024 11:08:45 -0800 Subject: [PATCH 49/60] wifi: ath12k: set flag for mgmt no-ack frames in Tx completion IEEE80211_TX_STAT_NOACK_TRANSMITTED flag signifies that frame was successfully transmitted without any errors when no-ack is requested. In WMI Tx management completion path, driver is not setting IEEE80211_TX_STAT_NOACK_TRANSMITTED flag for the frames with IEEE80211_TX_CTL_NO_ACK. Without this flag, the management frame statistics will not track such frames. Add IEEE80211_TX_STAT_NOACK_TRANSMITTED flag as part of the flags in skb transmit information when WMI is processing Tx completion for management frames. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Ramya Gnanasekar Signed-off-by: Muna Sinada Acked-by: Kalle Valo Link: https://patch.msgid.link/20241219190845.605116-1-quic_msinada@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/wmi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 9a96c4d70e600..4dd6cdf84571d 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -5362,6 +5362,9 @@ static int wmi_process_mgmt_tx_comp(struct ath12k *ar, u32 desc_id, if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) && !status) info->flags |= IEEE80211_TX_STAT_ACK; + if ((info->flags & IEEE80211_TX_CTL_NO_ACK) && !status) + info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; + ieee80211_tx_status_irqsafe(ath12k_ar_to_hw(ar), msdu); num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx); From 3540bba855b4b422e8b977d11aa8173ccb4f089d Mon Sep 17 00:00:00 2001 From: Sathishkumar Muruganandam Date: Mon, 9 Sep 2024 13:00:49 +0530 Subject: [PATCH 50/60] wifi: ath12k: fix tx power, max reg power update to firmware Currently, when the vdev start WMI cmd is sent from host, vdev related parameters such as max_reg_power, max_power, and max_antenna_gain are multiplied by 2 before being sent to the firmware. This is incorrect because the firmware uses 1 dBm steps for power calculations. This leads to incorrect power values being used in the firmware and radio, potentially causing incorrect behavior. Fix the update of max_reg_power, max_power, and max_antenna_gain values in the ath12k_mac_vdev_start_restart function, ensuring accurate power settings in the firmware by sending these values as-is, without multiplication. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00214-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Sathishkumar Muruganandam Signed-off-by: Santhosh Ramesh Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Acked-by: Kalle Valo Link: https://patch.msgid.link/20240909073049.3423035-1-quic_santrame@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 9a5402803d72d..48d110e2a7ded 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -8725,9 +8725,9 @@ ath12k_mac_vdev_start_restart(struct ath12k_link_vif *arvif, chandef->chan->band, ahvif->vif->type); arg.min_power = 0; - arg.max_power = chandef->chan->max_power * 2; - arg.max_reg_power = chandef->chan->max_reg_power * 2; - arg.max_antenna_gain = chandef->chan->max_antenna_gain * 2; + arg.max_power = chandef->chan->max_power; + arg.max_reg_power = chandef->chan->max_reg_power; + arg.max_antenna_gain = chandef->chan->max_antenna_gain; arg.pref_tx_streams = ar->num_tx_chains; arg.pref_rx_streams = ar->num_rx_chains; From c9f6ee2701d798c2b79b8557b842da7b106fcd5c Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Thu, 28 Nov 2024 16:39:48 +0530 Subject: [PATCH 51/60] wifi: ath12k: Support Transmit Rate Buffer Stats Add support to request transmit rate buffer stats from firmware through HTT stats type 31. These stats give information such as MCS, NSS and bandwidth of transmit and input buffer. Sample output: ------------- echo 31 > /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats_type cat /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats HTT_STATS_PDEV_TX_RATE_TXBF_STATS: Legacy OFDM Rates: 6 Mbps: 0, 9 Mbps: 0, 12 Mbps: 0, 18 Mbps: 0 24 Mbps: 0, 36 Mbps: 0, 48 Mbps: 0, 54 Mbps: 0 tx_ol_mcs = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:0, 12:0, 13:0 tx_ibf_mcs = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:0, 12:0, 13:0 tx_txbf_mcs = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:0, 12:0, 13:0 tx_ol_nss = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0 tx_ibf_nss = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0 tx_txbf_nss = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0 tx_ol_bw = 0:0, 1:0, 2:0, 3:0, 4:0 half_tx_ol_bw = 0:0, 1:0, 2:0, 3:0, 4:0 quarter_tx_ol_bw = 0:0, 1:0, 2:0, 3:0, 4:0 tx_ibf_bw = 0:0, 1:0, 2:0, 3:0, 4:0 half_tx_ibf_bw = 0:0, 1:0, 2:0, 3:0, 4:0 quarter_tx_ibf_bw = 0:0, 1:0, 2:0, 3:0, 4:0 tx_txbf_bw = 0:0, 1:0, 2:0, 3:0, 4:0 half_tx_txbf_bw = 0:0, 1:0, 2:0, 3:0, 4:0 quarter_tx_txbf_bw = 0:0, 1:0, 2:0, 3:0, 4:0 HTT_STATS_PDEV_TXBF_FLAG_RETURN_STATS: TXBF_reason_code_stats: 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00214-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Pradeep Kumar Chitrapu Signed-off-by: Roopni Devanathan Acked-by: Kalle Valo Acked-by: Jeff Johnson Link: https://patch.msgid.link/20241128110949.3672364-2-quic_rdevanat@quicinc.com Signed-off-by: Jeff Johnson --- .../wireless/ath/ath12k/debugfs_htt_stats.c | 95 +++++++++++++++++++ .../wireless/ath/ath12k/debugfs_htt_stats.h | 32 +++++++ 2 files changed, 127 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c index d8f137bfba7b8..d72eb22a719b4 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c @@ -2576,6 +2576,98 @@ ath12k_htt_print_pdev_obss_pd_stats_tlv(const void *tag_buf, u16 tag_len, stats_req->buf_len = len; } +static void +ath12k_htt_print_pdev_tx_rate_txbf_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_pdev_txrate_txbf_stats_tlv *htt_stats_buf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf; + u8 i; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, + "HTT_STATS_PDEV_TX_RATE_TXBF_STATS:\n"); + len += scnprintf(buf + len, buf_len - len, "Legacy OFDM Rates: 6 Mbps: %u, ", + le32_to_cpu(htt_stats_buf->tx_legacy_ofdm_rate[0])); + len += scnprintf(buf + len, buf_len - len, "9 Mbps: %u, 12 Mbps: %u, ", + le32_to_cpu(htt_stats_buf->tx_legacy_ofdm_rate[1]), + le32_to_cpu(htt_stats_buf->tx_legacy_ofdm_rate[2])); + len += scnprintf(buf + len, buf_len - len, "18 Mbps: %u\n", + le32_to_cpu(htt_stats_buf->tx_legacy_ofdm_rate[3])); + len += scnprintf(buf + len, buf_len - len, "24 Mbps: %u, 36 Mbps: %u, ", + le32_to_cpu(htt_stats_buf->tx_legacy_ofdm_rate[4]), + le32_to_cpu(htt_stats_buf->tx_legacy_ofdm_rate[5])); + len += scnprintf(buf + len, buf_len - len, "48 Mbps: %u, 54 Mbps: %u\n", + le32_to_cpu(htt_stats_buf->tx_legacy_ofdm_rate[6]), + le32_to_cpu(htt_stats_buf->tx_legacy_ofdm_rate[7])); + + len += print_array_to_buf(buf, len, "tx_ol_mcs", htt_stats_buf->tx_su_ol_mcs, + ATH12K_HTT_TX_BF_RATE_STATS_NUM_MCS_COUNTERS, "\n"); + len += print_array_to_buf(buf, len, "tx_ibf_mcs", htt_stats_buf->tx_su_ibf_mcs, + ATH12K_HTT_TX_BF_RATE_STATS_NUM_MCS_COUNTERS, "\n"); + len += print_array_to_buf(buf, len, "tx_txbf_mcs", htt_stats_buf->tx_su_txbf_mcs, + ATH12K_HTT_TX_BF_RATE_STATS_NUM_MCS_COUNTERS, "\n"); + len += print_array_to_buf_index(buf, len, "tx_ol_nss", 1, + htt_stats_buf->tx_su_ol_nss, + ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS, + "\n"); + len += print_array_to_buf_index(buf, len, "tx_ibf_nss", 1, + htt_stats_buf->tx_su_ibf_nss, + ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS, + "\n"); + len += print_array_to_buf_index(buf, len, "tx_txbf_nss", 1, + htt_stats_buf->tx_su_txbf_nss, + ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS, + "\n"); + len += print_array_to_buf(buf, len, "tx_ol_bw", htt_stats_buf->tx_su_ol_bw, + ATH12K_HTT_TXBF_NUM_BW_CNTRS, "\n"); + for (i = 0; i < ATH12K_HTT_TXBF_NUM_REDUCED_CHAN_TYPES; i++) + len += print_array_to_buf(buf, len, i ? "quarter_tx_ol_bw" : + "half_tx_ol_bw", + htt_stats_buf->ol[i], + ATH12K_HTT_TXBF_NUM_BW_CNTRS, + "\n"); + + len += print_array_to_buf(buf, len, "tx_ibf_bw", htt_stats_buf->tx_su_ibf_bw, + ATH12K_HTT_TXBF_NUM_BW_CNTRS, "\n"); + for (i = 0; i < ATH12K_HTT_TXBF_NUM_REDUCED_CHAN_TYPES; i++) + len += print_array_to_buf(buf, len, i ? "quarter_tx_ibf_bw" : + "half_tx_ibf_bw", + htt_stats_buf->ibf[i], + ATH12K_HTT_TXBF_NUM_BW_CNTRS, + "\n"); + + len += print_array_to_buf(buf, len, "tx_txbf_bw", htt_stats_buf->tx_su_txbf_bw, + ATH12K_HTT_TXBF_NUM_BW_CNTRS, "\n"); + for (i = 0; i < ATH12K_HTT_TXBF_NUM_REDUCED_CHAN_TYPES; i++) + len += print_array_to_buf(buf, len, i ? "quarter_tx_txbf_bw" : + "half_tx_txbf_bw", + htt_stats_buf->txbf[i], + ATH12K_HTT_TXBF_NUM_BW_CNTRS, + "\n"); + len += scnprintf(buf + len, buf_len - len, "\n"); + + len += scnprintf(buf + len, buf_len - len, + "HTT_STATS_PDEV_TXBF_FLAG_RETURN_STATS:\n"); + len += scnprintf(buf + len, buf_len - len, "TXBF_reason_code_stats: 0:%u, 1:%u,", + le32_to_cpu(htt_stats_buf->txbf_flag_set_mu_mode), + le32_to_cpu(htt_stats_buf->txbf_flag_set_final_status)); + len += scnprintf(buf + len, buf_len - len, " 2:%u, 3:%u, 4:%u, 5:%u, ", + le32_to_cpu(htt_stats_buf->txbf_flag_not_set_verified_txbf_mode), + le32_to_cpu(htt_stats_buf->txbf_flag_not_set_disable_p2p_access), + le32_to_cpu(htt_stats_buf->txbf_flag_not_set_max_nss_in_he160), + le32_to_cpu(htt_stats_buf->txbf_flag_not_set_disable_uldlofdma)); + len += scnprintf(buf + len, buf_len - len, "6:%u, 7:%u\n\n", + le32_to_cpu(htt_stats_buf->txbf_flag_not_set_mcs_threshold_val), + le32_to_cpu(htt_stats_buf->txbf_flag_not_set_final_status)); + + stats_req->buf_len = len; +} + static void ath12k_htt_print_dlpager_entry(const struct ath12k_htt_pgs_info *pg_info, int idx, char *str_buf) { @@ -3508,6 +3600,9 @@ static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab, case HTT_STATS_PDEV_OBSS_PD_TAG: ath12k_htt_print_pdev_obss_pd_stats_tlv(tag_buf, len, stats_req); break; + case HTT_STATS_PDEV_TX_RATE_TXBF_STATS_TAG: + ath12k_htt_print_pdev_tx_rate_txbf_stats_tlv(tag_buf, len, stats_req); + break; case HTT_STATS_DLPAGER_STATS_TAG: ath12k_htt_print_dlpager_stats_tlv(tag_buf, len, stats_req); break; diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h index cf3c88f8d1b24..859f5c8460160 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h @@ -135,6 +135,7 @@ enum ath12k_dbg_htt_ext_stats_type { ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_MU = 17, ATH12K_DBG_HTT_EXT_STATS_PDEV_CCA_STATS = 19, ATH12K_DBG_HTT_EXT_STATS_PDEV_OBSS_PD_STATS = 23, + ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_RATE_TXBF = 31, ATH12K_DBG_HTT_EXT_STATS_DLPAGER_STATS = 36, ATH12K_DBG_HTT_EXT_PHY_COUNTERS_AND_PHY_STATS = 37, ATH12K_DBG_HTT_EXT_VDEVS_TXRX_STATS = 38, @@ -197,6 +198,7 @@ enum ath12k_dbg_htt_tlv_tag { HTT_STATS_HW_WAR_TAG = 89, HTT_STATS_SCHED_TXQ_SUPERCYCLE_TRIGGER_TAG = 100, HTT_STATS_PDEV_CTRL_PATH_TX_STATS_TAG = 102, + HTT_STATS_PDEV_TX_RATE_TXBF_STATS_TAG = 108, HTT_STATS_TX_SELFGEN_AC_SCHED_STATUS_STATS_TAG = 111, HTT_STATS_TX_SELFGEN_AX_SCHED_STATUS_STATS_TAG = 112, HTT_STATS_DLPAGER_STATS_TAG = 120, @@ -1068,6 +1070,36 @@ struct ath12k_htt_pdev_obss_pd_stats_tlv { __le32 num_sr_ppdu_abort_flush_cnt; } __packed; +#define ATH12K_HTT_TX_BF_RATE_STATS_NUM_MCS_COUNTERS 14 +#define ATH12K_HTT_TX_PDEV_STATS_NUM_LEGACY_OFDM_STATS 8 +#define ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS 8 +#define ATH12K_HTT_TXBF_NUM_BW_CNTRS 5 +#define ATH12K_HTT_TXBF_NUM_REDUCED_CHAN_TYPES 2 + +struct ath12k_htt_pdev_txrate_txbf_stats_tlv { + __le32 tx_su_txbf_mcs[ATH12K_HTT_TX_BF_RATE_STATS_NUM_MCS_COUNTERS]; + __le32 tx_su_ibf_mcs[ATH12K_HTT_TX_BF_RATE_STATS_NUM_MCS_COUNTERS]; + __le32 tx_su_ol_mcs[ATH12K_HTT_TX_BF_RATE_STATS_NUM_MCS_COUNTERS]; + __le32 tx_su_txbf_nss[ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS]; + __le32 tx_su_ibf_nss[ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS]; + __le32 tx_su_ol_nss[ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS]; + __le32 tx_su_txbf_bw[ATH12K_HTT_TXBF_NUM_BW_CNTRS]; + __le32 tx_su_ibf_bw[ATH12K_HTT_TXBF_NUM_BW_CNTRS]; + __le32 tx_su_ol_bw[ATH12K_HTT_TXBF_NUM_BW_CNTRS]; + __le32 tx_legacy_ofdm_rate[ATH12K_HTT_TX_PDEV_STATS_NUM_LEGACY_OFDM_STATS]; + __le32 txbf[ATH12K_HTT_TXBF_NUM_REDUCED_CHAN_TYPES][ATH12K_HTT_TXBF_NUM_BW_CNTRS]; + __le32 ibf[ATH12K_HTT_TXBF_NUM_REDUCED_CHAN_TYPES][ATH12K_HTT_TXBF_NUM_BW_CNTRS]; + __le32 ol[ATH12K_HTT_TXBF_NUM_REDUCED_CHAN_TYPES][ATH12K_HTT_TXBF_NUM_BW_CNTRS]; + __le32 txbf_flag_set_mu_mode; + __le32 txbf_flag_set_final_status; + __le32 txbf_flag_not_set_verified_txbf_mode; + __le32 txbf_flag_not_set_disable_p2p_access; + __le32 txbf_flag_not_set_max_nss_in_he160; + __le32 txbf_flag_not_set_disable_uldlofdma; + __le32 txbf_flag_not_set_mcs_threshold_val; + __le32 txbf_flag_not_set_final_status; +} __packed; + enum ath12k_htt_stats_page_lock_state { ATH12K_HTT_STATS_PAGE_LOCKED = 0, ATH12K_HTT_STATS_PAGE_UNLOCKED = 1, From 3f482f2434753a0647dc8753a127f86878348458 Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Thu, 28 Nov 2024 16:39:49 +0530 Subject: [PATCH 52/60] wifi: ath12k: Support Transmit Buffer OFDMA Stats Add support to request OFDMA stats of transmit buffers from firmware through HTT stats type 32. These stats give information about NDPA, NDP, BRP and steering mechanisms. Note: WCN7850 firmware version - WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 does not support HTT stats type 32. Sample output: ------------- echo 32 > /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats_type cat /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats HTT_TXBF_OFDMA_AX_NDPA_STATS_TLV: ax_ofdma_ndpa_queued = 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:0, 12:0, 13:0, 14:0, 15:0, 16:0, 17:0, 18:0, 19:0, 20:0, 21:0, 22:0, 23:0, 24:0, 25:0, 26:0, 27:0, 28:0, 29:0, 30:0, 31:0, 32:0, 33:0, 34:0, 35:0, 36:0, 37:0 ax_ofdma_ndpa_tried = 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:0, 12:0, 13:0, 14:0, 15:0, 16:0, 17:0, 18:0, 19:0, 20:0, 21:0, 22:0, 23:0, 24:0, 25:0, 26:0, 27:0, 28:0, 29:0, 30:0, 31:0, 32:0, 33:0, 34:0, 35:0, 36:0, 37:0 ..... HTT_TXBF_OFDMA_AX_NDP_STATS_TLV: ax_ofdma_ndp_queued = 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:0, 12:0, 13:0, 14:0, 15:0, 16:0, 17:0, 18:0, 19:0, 20:0, 21:0, 22:0, 23:0, 24:0, 25:0, 26:0, 27:0, 28:0, 29:0, 30:0, 31:0, 32:0, 33:0, 34:0, 35:0, 36:0, 37:0 ax_ofdma_ndp_tried = 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:0, 12:0, 13:0, 14:0, 15:0, 16:0, 17:0, 18:0, 19:0, 20:0, 21:0, 22:0, 23:0, 24:0, 25:0, 26:0, 27:0, 28:0, 29:0, 30:0, 31:0, 32:0, 33:0, 34:0, 35:0, 36:0, 37:0 ..... HTT_TXBF_OFDMA_AX_BRP_STATS_TLV: ax_ofdma_brpoll_queued = 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:0, 12:0, 13:0, 14:0, 15:0, 16:0, 17:0, 18:0, 19:0, 20:0, 21:0, 22:0, 23:0, 24:0, 25:0, 26:0, 27:0, 28:0, 29:0, 30:0, 31:0, 32:0, 33:0, 34:0, 35:0, 36:0, 37:0 ax_ofdma_brpoll_tied = 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:0, 12:0, 13:0, 14:0, 15:0, 16:0, 17:0, 18:0, 19:0, 20:0, 21:0, 22:0, 23:0, 24:0, 25:0, 26:0, 27:0, 28:0, 29:0, 30:0, 31:0, 32:0, 33:0, 34:0, 35:0, 36:0, 37:0 ..... HTT_TXBF_OFDMA_AX_STEER_STATS_TLV: ax_ofdma_num_ppdu_steer = 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:0, 12:0, 13:0, 14:0, 15:0, 16:0, 17:0, 18:0, 19:0, 20:0, 21:0, 22:0, 23:0, 24:0, 25:0, 26:0, 27:0, 28:0, 29:0, 30:0, 31:0, 32:0, 33:0, 34:0, 35:0, 36:0, 37:0 ax_ofdma_num_usrs_prefetch = 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:0, 12:0, 13:0, 14:0, 15:0, 16:0, 17:0, 18:0, 19:0, 20:0, 21:0, 22:0, 23:0, 24:0, 25:0, 26:0, 27:0, 28:0, 29:0, 30:0, 31:0, 32:0, 33:0, 34:0, 35:0, 36:0, 37:0 ..... HTT_TXBF_OFDMA_AX_STEER_MPDU_STATS_TLV: rbo_steer_mpdus_tried = 0 rbo_steer_mpdus_failed = 0 sifs_steer_mpdus_tried = 0 sifs_steer_mpdus_failed = 0 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00214-QCAHKSWPL_SILICONZ-1 Signed-off-by: Pradeep Kumar Chitrapu Signed-off-by: Roopni Devanathan Acked-by: Jeff Johnson Link: https://patch.msgid.link/20241128110949.3672364-3-quic_rdevanat@quicinc.com Signed-off-by: Jeff Johnson --- .../wireless/ath/ath12k/debugfs_htt_stats.c | 250 ++++++++++++++++++ .../wireless/ath/ath12k/debugfs_htt_stats.h | 67 +++++ 2 files changed, 317 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c index d72eb22a719b4..c43bf032270f8 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c @@ -2668,6 +2668,240 @@ ath12k_htt_print_pdev_tx_rate_txbf_stats_tlv(const void *tag_buf, u16 tag_len, stats_req->buf_len = len; } +static void +ath12k_htt_print_txbf_ofdma_ax_ndpa_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_txbf_ofdma_ax_ndpa_stats_tlv *stats_buf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf; + u32 num_elements; + u8 i; + + if (tag_len < sizeof(*stats_buf)) + return; + + num_elements = le32_to_cpu(stats_buf->num_elems_ax_ndpa_arr); + + len += scnprintf(buf + len, buf_len - len, "HTT_TXBF_OFDMA_AX_NDPA_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "ax_ofdma_ndpa_queued ="); + for (i = 0; i < num_elements; i++) + len += scnprintf(buf + len, buf_len - len, " %u:%u,", i + 1, + le32_to_cpu(stats_buf->ax_ndpa[i].ax_ofdma_ndpa_queued)); + len--; + *(buf + len) = '\0'; + + len += scnprintf(buf + len, buf_len - len, "\nax_ofdma_ndpa_tried ="); + for (i = 0; i < num_elements; i++) + len += scnprintf(buf + len, buf_len - len, " %u:%u,", i + 1, + le32_to_cpu(stats_buf->ax_ndpa[i].ax_ofdma_ndpa_tried)); + len--; + *(buf + len) = '\0'; + + len += scnprintf(buf + len, buf_len - len, "\nax_ofdma_ndpa_flushed ="); + for (i = 0; i < num_elements; i++) + len += scnprintf(buf + len, buf_len - len, " %u:%u,", i + 1, + le32_to_cpu(stats_buf->ax_ndpa[i].ax_ofdma_ndpa_flush)); + len--; + *(buf + len) = '\0'; + + len += scnprintf(buf + len, buf_len - len, "\nax_ofdma_ndpa_err ="); + for (i = 0; i < num_elements; i++) + len += scnprintf(buf + len, buf_len - len, " %u:%u,", i + 1, + le32_to_cpu(stats_buf->ax_ndpa[i].ax_ofdma_ndpa_err)); + len--; + *(buf + len) = '\0'; + + len += scnprintf(buf + len, buf_len - len, "\n\n"); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_txbf_ofdma_ax_ndp_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_txbf_ofdma_ax_ndp_stats_tlv *stats_buf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf; + u32 num_elements; + u8 i; + + if (tag_len < sizeof(*stats_buf)) + return; + + num_elements = le32_to_cpu(stats_buf->num_elems_ax_ndp_arr); + + len += scnprintf(buf + len, buf_len - len, "HTT_TXBF_OFDMA_AX_NDP_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "ax_ofdma_ndp_queued ="); + for (i = 0; i < num_elements; i++) + len += scnprintf(buf + len, buf_len - len, " %u:%u,", i + 1, + le32_to_cpu(stats_buf->ax_ndp[i].ax_ofdma_ndp_queued)); + len--; + *(buf + len) = '\0'; + + len += scnprintf(buf + len, buf_len - len, "\nax_ofdma_ndp_tried ="); + for (i = 0; i < num_elements; i++) + len += scnprintf(buf + len, buf_len - len, " %u:%u,", i + 1, + le32_to_cpu(stats_buf->ax_ndp[i].ax_ofdma_ndp_tried)); + len--; + *(buf + len) = '\0'; + + len += scnprintf(buf + len, buf_len - len, "\nax_ofdma_ndp_flushed ="); + for (i = 0; i < num_elements; i++) + len += scnprintf(buf + len, buf_len - len, " %u:%u,", i + 1, + le32_to_cpu(stats_buf->ax_ndp[i].ax_ofdma_ndp_flush)); + len--; + *(buf + len) = '\0'; + + len += scnprintf(buf + len, buf_len - len, "\nax_ofdma_ndp_err ="); + for (i = 0; i < num_elements; i++) + len += scnprintf(buf + len, buf_len - len, " %u:%u,", i + 1, + le32_to_cpu(stats_buf->ax_ndp[i].ax_ofdma_ndp_err)); + len--; + *(buf + len) = '\0'; + + len += scnprintf(buf + len, buf_len - len, "\n\n"); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_txbf_ofdma_ax_brp_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_txbf_ofdma_ax_brp_stats_tlv *stats_buf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf; + u32 num_elements; + u8 i; + + if (tag_len < sizeof(*stats_buf)) + return; + + num_elements = le32_to_cpu(stats_buf->num_elems_ax_brp_arr); + + len += scnprintf(buf + len, buf_len - len, "HTT_TXBF_OFDMA_AX_BRP_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "ax_ofdma_brpoll_queued ="); + for (i = 0; i < num_elements; i++) + len += scnprintf(buf + len, buf_len - len, " %u:%u,", i + 1, + le32_to_cpu(stats_buf->ax_brp[i].ax_ofdma_brp_queued)); + len--; + *(buf + len) = '\0'; + + len += scnprintf(buf + len, buf_len - len, "\nax_ofdma_brpoll_tied ="); + for (i = 0; i < num_elements; i++) + len += scnprintf(buf + len, buf_len - len, " %u:%u,", i + 1, + le32_to_cpu(stats_buf->ax_brp[i].ax_ofdma_brp_tried)); + len--; + *(buf + len) = '\0'; + + len += scnprintf(buf + len, buf_len - len, "\nax_ofdma_brpoll_flushed ="); + for (i = 0; i < num_elements; i++) + len += scnprintf(buf + len, buf_len - len, " %u:%u,", i + 1, + le32_to_cpu(stats_buf->ax_brp[i].ax_ofdma_brp_flushed)); + len--; + *(buf + len) = '\0'; + + len += scnprintf(buf + len, buf_len - len, "\nax_ofdma_brp_err ="); + for (i = 0; i < num_elements; i++) + len += scnprintf(buf + len, buf_len - len, " %u:%u,", i + 1, + le32_to_cpu(stats_buf->ax_brp[i].ax_ofdma_brp_err)); + len--; + *(buf + len) = '\0'; + + len += scnprintf(buf + len, buf_len - len, "\nax_ofdma_brp_err_num_cbf_rcvd ="); + for (i = 0; i < num_elements; i++) + len += scnprintf(buf + len, buf_len - len, " %u:%u,", i + 1, + le32_to_cpu(stats_buf->ax_brp[i].ax_ofdma_num_cbf_rcvd)); + len--; + *(buf + len) = '\0'; + + len += scnprintf(buf + len, buf_len - len, "\n\n"); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_txbf_ofdma_ax_steer_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_txbf_ofdma_ax_steer_stats_tlv *stats_buf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf; + u32 num_elements; + u8 i; + + if (tag_len < sizeof(*stats_buf)) + return; + + num_elements = le32_to_cpu(stats_buf->num_elems_ax_steer_arr); + + len += scnprintf(buf + len, buf_len - len, + "HTT_TXBF_OFDMA_AX_STEER_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "ax_ofdma_num_ppdu_steer ="); + for (i = 0; i < num_elements; i++) + len += scnprintf(buf + len, buf_len - len, " %u:%u,", i + 1, + le32_to_cpu(stats_buf->ax_steer[i].num_ppdu_steer)); + len--; + *(buf + len) = '\0'; + + len += scnprintf(buf + len, buf_len - len, "\nax_ofdma_num_usrs_prefetch ="); + for (i = 0; i < num_elements; i++) + len += scnprintf(buf + len, buf_len - len, " %u:%u,", i + 1, + le32_to_cpu(stats_buf->ax_steer[i].num_usr_prefetch)); + len--; + *(buf + len) = '\0'; + + len += scnprintf(buf + len, buf_len - len, "\nax_ofdma_num_usrs_sound ="); + for (i = 0; i < num_elements; i++) + len += scnprintf(buf + len, buf_len - len, " %u:%u,", i + 1, + le32_to_cpu(stats_buf->ax_steer[i].num_usr_sound)); + len--; + *(buf + len) = '\0'; + + len += scnprintf(buf + len, buf_len - len, "\nax_ofdma_num_usrs_force_sound ="); + for (i = 0; i < num_elements; i++) + len += scnprintf(buf + len, buf_len - len, " %u:%u,", i + 1, + le32_to_cpu(stats_buf->ax_steer[i].num_usr_force_sound)); + len--; + *(buf + len) = '\0'; + + len += scnprintf(buf + len, buf_len - len, "\n\n"); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_txbf_ofdma_ax_steer_mpdu_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_txbf_ofdma_ax_steer_mpdu_stats_tlv *stats_buf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf; + + if (tag_len < sizeof(*stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, + "HTT_TXBF_OFDMA_AX_STEER_MPDU_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "rbo_steer_mpdus_tried = %u\n", + le32_to_cpu(stats_buf->ax_ofdma_rbo_steer_mpdus_tried)); + len += scnprintf(buf + len, buf_len - len, "rbo_steer_mpdus_failed = %u\n", + le32_to_cpu(stats_buf->ax_ofdma_rbo_steer_mpdus_failed)); + len += scnprintf(buf + len, buf_len - len, "sifs_steer_mpdus_tried = %u\n", + le32_to_cpu(stats_buf->ax_ofdma_sifs_steer_mpdus_tried)); + len += scnprintf(buf + len, buf_len - len, "sifs_steer_mpdus_failed = %u\n\n", + le32_to_cpu(stats_buf->ax_ofdma_sifs_steer_mpdus_failed)); + + stats_req->buf_len = len; +} + static void ath12k_htt_print_dlpager_entry(const struct ath12k_htt_pgs_info *pg_info, int idx, char *str_buf) { @@ -3603,6 +3837,22 @@ static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab, case HTT_STATS_PDEV_TX_RATE_TXBF_STATS_TAG: ath12k_htt_print_pdev_tx_rate_txbf_stats_tlv(tag_buf, len, stats_req); break; + case HTT_STATS_TXBF_OFDMA_AX_NDPA_STATS_TAG: + ath12k_htt_print_txbf_ofdma_ax_ndpa_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TXBF_OFDMA_AX_NDP_STATS_TAG: + ath12k_htt_print_txbf_ofdma_ax_ndp_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TXBF_OFDMA_AX_BRP_STATS_TAG: + ath12k_htt_print_txbf_ofdma_ax_brp_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TXBF_OFDMA_AX_STEER_STATS_TAG: + ath12k_htt_print_txbf_ofdma_ax_steer_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TXBF_OFDMA_AX_STEER_MPDU_STATS_TAG: + ath12k_htt_print_txbf_ofdma_ax_steer_mpdu_stats_tlv(tag_buf, len, + stats_req); + break; case HTT_STATS_DLPAGER_STATS_TAG: ath12k_htt_print_dlpager_stats_tlv(tag_buf, len, stats_req); break; diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h index 859f5c8460160..a718f8dfe321c 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h @@ -136,6 +136,7 @@ enum ath12k_dbg_htt_ext_stats_type { ATH12K_DBG_HTT_EXT_STATS_PDEV_CCA_STATS = 19, ATH12K_DBG_HTT_EXT_STATS_PDEV_OBSS_PD_STATS = 23, ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_RATE_TXBF = 31, + ATH12K_DBG_HTT_EXT_STATS_TXBF_OFDMA = 32, ATH12K_DBG_HTT_EXT_STATS_DLPAGER_STATS = 36, ATH12K_DBG_HTT_EXT_PHY_COUNTERS_AND_PHY_STATS = 37, ATH12K_DBG_HTT_EXT_VDEVS_TXRX_STATS = 38, @@ -214,9 +215,14 @@ enum ath12k_dbg_htt_tlv_tag { HTT_STATS_TX_SELFGEN_BE_ERR_STATS_TAG = 137, HTT_STATS_TX_SELFGEN_BE_STATS_TAG = 138, HTT_STATS_TX_SELFGEN_BE_SCHED_STATUS_STATS_TAG = 139, + HTT_STATS_TXBF_OFDMA_AX_NDPA_STATS_TAG = 147, + HTT_STATS_TXBF_OFDMA_AX_NDP_STATS_TAG = 148, + HTT_STATS_TXBF_OFDMA_AX_BRP_STATS_TAG = 149, + HTT_STATS_TXBF_OFDMA_AX_STEER_STATS_TAG = 150, HTT_STATS_DMAC_RESET_STATS_TAG = 155, HTT_STATS_PHY_TPC_STATS_TAG = 157, HTT_STATS_PDEV_SCHED_ALGO_OFDMA_STATS_TAG = 165, + HTT_STATS_TXBF_OFDMA_AX_STEER_MPDU_STATS_TAG = 172, HTT_STATS_PDEV_MBSSID_CTRL_FRAME_STATS_TAG = 176, HTT_STATS_MAX_TAG, @@ -1100,6 +1106,67 @@ struct ath12k_htt_pdev_txrate_txbf_stats_tlv { __le32 txbf_flag_not_set_final_status; } __packed; +struct ath12k_htt_txbf_ofdma_ax_ndpa_stats_elem_t { + __le32 ax_ofdma_ndpa_queued; + __le32 ax_ofdma_ndpa_tried; + __le32 ax_ofdma_ndpa_flush; + __le32 ax_ofdma_ndpa_err; +} __packed; + +struct ath12k_htt_txbf_ofdma_ax_ndpa_stats_tlv { + __le32 num_elems_ax_ndpa_arr; + __le32 arr_elem_size_ax_ndpa; + DECLARE_FLEX_ARRAY(struct ath12k_htt_txbf_ofdma_ax_ndpa_stats_elem_t, ax_ndpa); +} __packed; + +struct ath12k_htt_txbf_ofdma_ax_ndp_stats_elem_t { + __le32 ax_ofdma_ndp_queued; + __le32 ax_ofdma_ndp_tried; + __le32 ax_ofdma_ndp_flush; + __le32 ax_ofdma_ndp_err; +} __packed; + +struct ath12k_htt_txbf_ofdma_ax_ndp_stats_tlv { + __le32 num_elems_ax_ndp_arr; + __le32 arr_elem_size_ax_ndp; + DECLARE_FLEX_ARRAY(struct ath12k_htt_txbf_ofdma_ax_ndp_stats_elem_t, ax_ndp); +} __packed; + +struct ath12k_htt_txbf_ofdma_ax_brp_stats_elem_t { + __le32 ax_ofdma_brp_queued; + __le32 ax_ofdma_brp_tried; + __le32 ax_ofdma_brp_flushed; + __le32 ax_ofdma_brp_err; + __le32 ax_ofdma_num_cbf_rcvd; +} __packed; + +struct ath12k_htt_txbf_ofdma_ax_brp_stats_tlv { + __le32 num_elems_ax_brp_arr; + __le32 arr_elem_size_ax_brp; + DECLARE_FLEX_ARRAY(struct ath12k_htt_txbf_ofdma_ax_brp_stats_elem_t, ax_brp); +} __packed; + +struct ath12k_htt_txbf_ofdma_ax_steer_stats_elem_t { + __le32 num_ppdu_steer; + __le32 num_ppdu_ol; + __le32 num_usr_prefetch; + __le32 num_usr_sound; + __le32 num_usr_force_sound; +} __packed; + +struct ath12k_htt_txbf_ofdma_ax_steer_stats_tlv { + __le32 num_elems_ax_steer_arr; + __le32 arr_elem_size_ax_steer; + DECLARE_FLEX_ARRAY(struct ath12k_htt_txbf_ofdma_ax_steer_stats_elem_t, ax_steer); +} __packed; + +struct ath12k_htt_txbf_ofdma_ax_steer_mpdu_stats_tlv { + __le32 ax_ofdma_rbo_steer_mpdus_tried; + __le32 ax_ofdma_rbo_steer_mpdus_failed; + __le32 ax_ofdma_sifs_steer_mpdus_tried; + __le32 ax_ofdma_sifs_steer_mpdus_failed; +} __packed; + enum ath12k_htt_stats_page_lock_state { ATH12K_HTT_STATS_PAGE_LOCKED = 0, ATH12K_HTT_STATS_PAGE_UNLOCKED = 1, From 89699f029cd42ddf913a201c917ce4f7b213b068 Mon Sep 17 00:00:00 2001 From: Roopni Devanathan Date: Wed, 18 Dec 2024 09:27:10 +0530 Subject: [PATCH 53/60] wifi: ath12k: Support AST Entry Stats Add support to request Address Search Table(AST) entries stats from firmware through HTT stats type 41. These stats give AST entries related information such as software peer id, MAC address, pdev id, vdev, id, next hop, etc. Sample output: ------------- echo 41 > /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats_type cat /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats HTT_AST_ENTRY_TLV: ast_index = 10 mac_addr = 00:00:00:01:00:00 sw_peer_id = 0 pdev_id = 3 vdev_id = 255 next_hop = 0 mcast = 0 monitor_direct = 0 mesh_sta = 0 mec = 0 intra_bss = 0 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Roopni Devanathan Acked-by: Kalle Valo Link: https://patch.msgid.link/20241218035711.2573584-2-quic_rdevanat@quicinc.com Signed-off-by: Jeff Johnson --- .../wireless/ath/ath12k/debugfs_htt_stats.c | 56 +++++++++++++++++++ .../wireless/ath/ath12k/debugfs_htt_stats.h | 18 ++++++ drivers/net/wireless/ath/ath12k/dp.h | 12 ++++ 3 files changed, 86 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c index c43bf032270f8..9294ef41a169e 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c @@ -3469,6 +3469,59 @@ ath12k_htt_print_tx_per_rate_stats_tlv(const void *tag_buf, u16 tag_len, stats_req->buf_len = len; } +static void +ath12k_htt_print_ast_entry_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_ast_entry_tlv *htt_stats_buf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf; + u32 mac_addr_l32; + u32 mac_addr_h16; + u32 ast_info; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + mac_addr_l32 = le32_to_cpu(htt_stats_buf->mac_addr.mac_addr_l32); + mac_addr_h16 = le32_to_cpu(htt_stats_buf->mac_addr.mac_addr_h16); + ast_info = le32_to_cpu(htt_stats_buf->info); + + len += scnprintf(buf + len, buf_len - len, "HTT_AST_ENTRY_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "ast_index = %u\n", + le32_to_cpu(htt_stats_buf->ast_index)); + len += scnprintf(buf + len, buf_len - len, + "mac_addr = %02x:%02x:%02x:%02x:%02x:%02x\n", + u32_get_bits(mac_addr_l32, ATH12K_HTT_MAC_ADDR_L32_0), + u32_get_bits(mac_addr_l32, ATH12K_HTT_MAC_ADDR_L32_1), + u32_get_bits(mac_addr_l32, ATH12K_HTT_MAC_ADDR_L32_2), + u32_get_bits(mac_addr_l32, ATH12K_HTT_MAC_ADDR_L32_3), + u32_get_bits(mac_addr_h16, ATH12K_HTT_MAC_ADDR_H16_0), + u32_get_bits(mac_addr_h16, ATH12K_HTT_MAC_ADDR_H16_1)); + + len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %u\n", + le32_to_cpu(htt_stats_buf->sw_peer_id)); + len += scnprintf(buf + len, buf_len - len, "pdev_id = %u\n", + u32_get_bits(ast_info, ATH12K_HTT_AST_PDEV_ID_INFO)); + len += scnprintf(buf + len, buf_len - len, "vdev_id = %u\n", + u32_get_bits(ast_info, ATH12K_HTT_AST_VDEV_ID_INFO)); + len += scnprintf(buf + len, buf_len - len, "next_hop = %u\n", + u32_get_bits(ast_info, ATH12K_HTT_AST_NEXT_HOP_INFO)); + len += scnprintf(buf + len, buf_len - len, "mcast = %u\n", + u32_get_bits(ast_info, ATH12K_HTT_AST_MCAST_INFO)); + len += scnprintf(buf + len, buf_len - len, "monitor_direct = %u\n", + u32_get_bits(ast_info, ATH12K_HTT_AST_MONITOR_DIRECT_INFO)); + len += scnprintf(buf + len, buf_len - len, "mesh_sta = %u\n", + u32_get_bits(ast_info, ATH12K_HTT_AST_MESH_STA_INFO)); + len += scnprintf(buf + len, buf_len - len, "mec = %u\n", + u32_get_bits(ast_info, ATH12K_HTT_AST_MEC_INFO)); + len += scnprintf(buf + len, buf_len - len, "intra_bss = %u\n\n", + u32_get_bits(ast_info, ATH12K_HTT_AST_INTRA_BSS_INFO)); + + stats_req->buf_len = len; +} + static void ath12k_htt_print_dmac_reset_stats_tlv(const void *tag_buf, u16 tag_len, struct debug_htt_stats_req *stats_req) @@ -3877,6 +3930,9 @@ static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab, case HTT_STATS_PER_RATE_STATS_TAG: ath12k_htt_print_tx_per_rate_stats_tlv(tag_buf, len, stats_req); break; + case HTT_STATS_AST_ENTRY_TAG: + ath12k_htt_print_ast_entry_tlv(tag_buf, len, stats_req); + break; case HTT_STATS_DMAC_RESET_STATS_TAG: ath12k_htt_print_dmac_reset_stats_tlv(tag_buf, len, stats_req); break; diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h index a718f8dfe321c..9a9dd368c5d65 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h @@ -141,6 +141,7 @@ enum ath12k_dbg_htt_ext_stats_type { ATH12K_DBG_HTT_EXT_PHY_COUNTERS_AND_PHY_STATS = 37, ATH12K_DBG_HTT_EXT_VDEVS_TXRX_STATS = 38, ATH12K_DBG_HTT_EXT_PDEV_PER_STATS = 40, + ATH12K_DBG_HTT_EXT_AST_ENTRIES = 41, ATH12K_DBG_HTT_EXT_STATS_SOC_ERROR = 45, ATH12K_DBG_HTT_EXT_STATS_PDEV_SCHED_ALGO = 49, ATH12K_DBG_HTT_EXT_STATS_MANDATORY_MUOFDMA = 51, @@ -211,6 +212,7 @@ enum ath12k_dbg_htt_tlv_tag { HTT_STATS_PER_RATE_STATS_TAG = 128, HTT_STATS_MU_PPDU_DIST_TAG = 129, HTT_STATS_TX_PDEV_MUMIMO_GRP_STATS_TAG = 130, + HTT_STATS_AST_ENTRY_TAG = 132, HTT_STATS_TX_PDEV_RATE_STATS_BE_OFDMA_TAG = 135, HTT_STATS_TX_SELFGEN_BE_ERR_STATS_TAG = 137, HTT_STATS_TX_SELFGEN_BE_STATS_TAG = 138, @@ -1293,6 +1295,22 @@ struct ath12k_htt_t2h_soc_txrx_stats_common_tlv { __le32 inv_peers_msdu_drop_count_lo; } __packed; +#define ATH12K_HTT_AST_PDEV_ID_INFO GENMASK(1, 0) +#define ATH12K_HTT_AST_VDEV_ID_INFO GENMASK(9, 2) +#define ATH12K_HTT_AST_NEXT_HOP_INFO BIT(10) +#define ATH12K_HTT_AST_MCAST_INFO BIT(11) +#define ATH12K_HTT_AST_MONITOR_DIRECT_INFO BIT(12) +#define ATH12K_HTT_AST_MESH_STA_INFO BIT(13) +#define ATH12K_HTT_AST_MEC_INFO BIT(14) +#define ATH12K_HTT_AST_INTRA_BSS_INFO BIT(15) + +struct ath12k_htt_ast_entry_tlv { + __le32 sw_peer_id; + __le32 ast_index; + struct htt_mac_addr mac_addr; + __le32 info; +} __packed; + struct ath12k_htt_dmac_reset_stats_tlv { __le32 reset_count; __le32 reset_time_lo_ms; diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index b178921aaf1d5..7ac3143de0168 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -1798,6 +1798,18 @@ enum vdev_stats_offload_timer_duration { ATH12K_STATS_TIMER_DUR_2SEC = 3, }; +#define ATH12K_HTT_MAC_ADDR_L32_0 GENMASK(7, 0) +#define ATH12K_HTT_MAC_ADDR_L32_1 GENMASK(15, 8) +#define ATH12K_HTT_MAC_ADDR_L32_2 GENMASK(23, 16) +#define ATH12K_HTT_MAC_ADDR_L32_3 GENMASK(31, 24) +#define ATH12K_HTT_MAC_ADDR_H16_0 GENMASK(7, 0) +#define ATH12K_HTT_MAC_ADDR_H16_1 GENMASK(15, 8) + +struct htt_mac_addr { + __le32 mac_addr_l32; + __le32 mac_addr_h16; +} __packed; + static inline void ath12k_dp_get_mac_addr(u32 addr_l32, u16 addr_h16, u8 *addr) { memcpy(addr, &addr_l32, 4); From f647dc6512efa88bd1a3dc2444a9d1ea170f4045 Mon Sep 17 00:00:00 2001 From: Rajat Soni Date: Wed, 18 Dec 2024 09:27:11 +0530 Subject: [PATCH 54/60] wifi: ath12k: Support pdev Puncture Stats Add support to request pdev puncture stats from firmware through HTT stats type 46. These stats give the count of number of subbands used in different wifi standards. Sample output: ------------- echo 46 > /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats_type cat /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats HTT_PDEV_PUNCTURE_STATS_TLV: mac_id = 0 tx_ofdm_su_last_used_pattern_mask = 0x00000001 tx_ofdm_su_num_subbands_used_cnt_01 = 217 tx_ofdm_su_num_subbands_used_cnt_02 = 0 tx_ofdm_su_num_subbands_used_cnt_03 = 0 ..... HTT_PDEV_PUNCTURE_STATS_TLV: mac_id = 0 tx_ax_dl_mu_ofdma_last_used_pattern_mask = 0x00000000 tx_ax_dl_mu_ofdma_num_subbands_used_cnt_01 = 0 tx_ax_dl_mu_ofdma_num_subbands_used_cnt_02 = 0 tx_ax_dl_mu_ofdma_num_subbands_used_cnt_03 = 0 ..... HTT_PDEV_PUNCTURE_STATS_TLV: mac_id = 0 tx_be_dl_mu_ofdma_last_used_pattern_mask = 0x00000000 tx_be_dl_mu_ofdma_num_subbands_used_cnt_01 = 0 tx_be_dl_mu_ofdma_num_subbands_used_cnt_02 = 0 tx_be_dl_mu_ofdma_num_subbands_used_cnt_03 = 0 ..... HTT_PDEV_PUNCTURE_STATS_TLV: mac_id = 0 rx_ax_ul_mu_ofdma_last_used_pattern_mask = 0x00000000 rx_ax_ul_mu_ofdma_num_subbands_used_cnt_01 = 0 rx_ax_ul_mu_ofdma_num_subbands_used_cnt_02 = 0 rx_ax_ul_mu_ofdma_num_subbands_used_cnt_03 = 0 ..... HTT_PDEV_PUNCTURE_STATS_TLV: mac_id = 0 rx_be_ul_mu_ofdma_last_used_pattern_mask = 0x00000000 rx_be_ul_mu_ofdma_num_subbands_used_cnt_01 = 0 rx_be_ul_mu_ofdma_num_subbands_used_cnt_02 = 0 rx_be_ul_mu_ofdma_num_subbands_used_cnt_03 = 0 ..... Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Rajat Soni Signed-off-by: Roopni Devanathan Acked-by: Kalle Valo Link: https://patch.msgid.link/20241218035711.2573584-3-quic_rdevanat@quicinc.com Signed-off-by: Jeff Johnson --- .../wireless/ath/ath12k/debugfs_htt_stats.c | 101 ++++++++++++++++++ .../wireless/ath/ath12k/debugfs_htt_stats.h | 38 +++++++ 2 files changed, 139 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c index 9294ef41a169e..41e4ef2ef3af6 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c @@ -3522,6 +3522,104 @@ ath12k_htt_print_ast_entry_tlv(const void *tag_buf, u16 tag_len, stats_req->buf_len = len; } +static const char* +ath12k_htt_get_punct_dir_type_str(enum ath12k_htt_stats_direction direction) +{ + switch (direction) { + case ATH12K_HTT_STATS_DIRECTION_TX: + return "tx"; + case ATH12K_HTT_STATS_DIRECTION_RX: + return "rx"; + default: + return "unknown"; + } +} + +static const char* +ath12k_htt_get_punct_ppdu_type_str(enum ath12k_htt_stats_ppdu_type ppdu_type) +{ + switch (ppdu_type) { + case ATH12K_HTT_STATS_PPDU_TYPE_MODE_SU: + return "su"; + case ATH12K_HTT_STATS_PPDU_TYPE_DL_MU_MIMO: + return "dl_mu_mimo"; + case ATH12K_HTT_STATS_PPDU_TYPE_UL_MU_MIMO: + return "ul_mu_mimo"; + case ATH12K_HTT_STATS_PPDU_TYPE_DL_MU_OFDMA: + return "dl_mu_ofdma"; + case ATH12K_HTT_STATS_PPDU_TYPE_UL_MU_OFDMA: + return "ul_mu_ofdma"; + default: + return "unknown"; + } +} + +static const char* +ath12k_htt_get_punct_pream_type_str(enum ath12k_htt_stats_param_type pream_type) +{ + switch (pream_type) { + case ATH12K_HTT_STATS_PREAM_OFDM: + return "ofdm"; + case ATH12K_HTT_STATS_PREAM_CCK: + return "cck"; + case ATH12K_HTT_STATS_PREAM_HT: + return "ht"; + case ATH12K_HTT_STATS_PREAM_VHT: + return "ac"; + case ATH12K_HTT_STATS_PREAM_HE: + return "ax"; + case ATH12K_HTT_STATS_PREAM_EHT: + return "be"; + default: + return "unknown"; + } +} + +static void +ath12k_htt_print_puncture_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_pdev_puncture_stats_tlv *stats_buf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf; + const char *direction; + const char *ppdu_type; + const char *preamble; + u32 mac_id__word; + u32 subband_limit; + u8 i; + + if (tag_len < sizeof(*stats_buf)) + return; + + mac_id__word = le32_to_cpu(stats_buf->mac_id__word); + subband_limit = min(le32_to_cpu(stats_buf->subband_cnt), + ATH12K_HTT_PUNCT_STATS_MAX_SUBBAND_CNT); + + direction = ath12k_htt_get_punct_dir_type_str(le32_to_cpu(stats_buf->direction)); + ppdu_type = ath12k_htt_get_punct_ppdu_type_str(le32_to_cpu(stats_buf->ppdu_type)); + preamble = ath12k_htt_get_punct_pream_type_str(le32_to_cpu(stats_buf->preamble)); + + len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_PUNCTURE_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", + u32_get_bits(mac_id__word, ATH12K_HTT_STATS_MAC_ID)); + len += scnprintf(buf + len, buf_len - len, + "%s_%s_%s_last_used_pattern_mask = 0x%08x\n", + direction, preamble, ppdu_type, + le32_to_cpu(stats_buf->last_used_pattern_mask)); + + for (i = 0; i < subband_limit; i++) { + len += scnprintf(buf + len, buf_len - len, + "%s_%s_%s_num_subbands_used_cnt_%02d = %u\n", + direction, preamble, ppdu_type, i + 1, + le32_to_cpu(stats_buf->num_subbands_used_cnt[i])); + } + len += scnprintf(buf + len, buf_len - len, "\n"); + + stats_req->buf_len = len; +} + static void ath12k_htt_print_dmac_reset_stats_tlv(const void *tag_buf, u16 tag_len, struct debug_htt_stats_req *stats_req) @@ -3933,6 +4031,9 @@ static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab, case HTT_STATS_AST_ENTRY_TAG: ath12k_htt_print_ast_entry_tlv(tag_buf, len, stats_req); break; + case HTT_STATS_PDEV_PUNCTURE_STATS_TAG: + ath12k_htt_print_puncture_stats_tlv(tag_buf, len, stats_req); + break; case HTT_STATS_DMAC_RESET_STATS_TAG: ath12k_htt_print_dmac_reset_stats_tlv(tag_buf, len, stats_req); break; diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h index 9a9dd368c5d65..4b59976fbc350 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h @@ -143,6 +143,7 @@ enum ath12k_dbg_htt_ext_stats_type { ATH12K_DBG_HTT_EXT_PDEV_PER_STATS = 40, ATH12K_DBG_HTT_EXT_AST_ENTRIES = 41, ATH12K_DBG_HTT_EXT_STATS_SOC_ERROR = 45, + ATH12K_DBG_HTT_DBG_PDEV_PUNCTURE_STATS = 46, ATH12K_DBG_HTT_EXT_STATS_PDEV_SCHED_ALGO = 49, ATH12K_DBG_HTT_EXT_STATS_MANDATORY_MUOFDMA = 51, ATH12K_DGB_HTT_EXT_STATS_PDEV_MBSSID_CTRL_FRAME = 54, @@ -223,6 +224,7 @@ enum ath12k_dbg_htt_tlv_tag { HTT_STATS_TXBF_OFDMA_AX_STEER_STATS_TAG = 150, HTT_STATS_DMAC_RESET_STATS_TAG = 155, HTT_STATS_PHY_TPC_STATS_TAG = 157, + HTT_STATS_PDEV_PUNCTURE_STATS_TAG = 158, HTT_STATS_PDEV_SCHED_ALGO_OFDMA_STATS_TAG = 165, HTT_STATS_TXBF_OFDMA_AX_STEER_MPDU_STATS_TAG = 172, HTT_STATS_PDEV_MBSSID_CTRL_FRAME_STATS_TAG = 176, @@ -1311,6 +1313,42 @@ struct ath12k_htt_ast_entry_tlv { __le32 info; } __packed; +enum ath12k_htt_stats_direction { + ATH12K_HTT_STATS_DIRECTION_TX, + ATH12K_HTT_STATS_DIRECTION_RX +}; + +enum ath12k_htt_stats_ppdu_type { + ATH12K_HTT_STATS_PPDU_TYPE_MODE_SU, + ATH12K_HTT_STATS_PPDU_TYPE_DL_MU_MIMO, + ATH12K_HTT_STATS_PPDU_TYPE_UL_MU_MIMO, + ATH12K_HTT_STATS_PPDU_TYPE_DL_MU_OFDMA, + ATH12K_HTT_STATS_PPDU_TYPE_UL_MU_OFDMA +}; + +enum ath12k_htt_stats_param_type { + ATH12K_HTT_STATS_PREAM_OFDM, + ATH12K_HTT_STATS_PREAM_CCK, + ATH12K_HTT_STATS_PREAM_HT, + ATH12K_HTT_STATS_PREAM_VHT, + ATH12K_HTT_STATS_PREAM_HE, + ATH12K_HTT_STATS_PREAM_EHT, + ATH12K_HTT_STATS_PREAM_RSVD1, + ATH12K_HTT_STATS_PREAM_COUNT, +}; + +#define ATH12K_HTT_PUNCT_STATS_MAX_SUBBAND_CNT 32 + +struct ath12k_htt_pdev_puncture_stats_tlv { + __le32 mac_id__word; + __le32 direction; + __le32 preamble; + __le32 ppdu_type; + __le32 subband_cnt; + __le32 last_used_pattern_mask; + __le32 num_subbands_used_cnt[ATH12K_HTT_PUNCT_STATS_MAX_SUBBAND_CNT]; +} __packed; + struct ath12k_htt_dmac_reset_stats_tlv { __le32 reset_count; __le32 reset_time_lo_ms; From a72eaa175656836a32e94004ea05598409e2f2fd Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Thu, 9 Jan 2025 11:07:03 +0300 Subject: [PATCH 55/60] wifi: ath9k: cleanup ath9k_hw_get_nf_hist_mid() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In 'ath9k_hw_get_nf_hist_mid()', prefer 'memcpy()' and 'sort()' over an ad-hoc things. Briefly tested as a separate module. Found by Linux Verification Center (linuxtesting.org) with SVACE. Signed-off-by: Dmitry Antipov Acked-by: Toke Høiland-Jørgensen Link: https://patch.msgid.link/20250109080703.106692-1-dmantipov@yandex.ru Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath9k/calib.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 4b331c85509cf..b4ab85bd7895a 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -16,29 +16,25 @@ #include "hw.h" #include "hw-ops.h" +#include #include /* Common calibration code */ +static int rcmp_i16(const void *x, const void *y) +{ + /* Sort in reverse order. */ + return *(int16_t *)y - *(int16_t *)x; +} static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer) { - int16_t nfval; - int16_t sort[ATH9K_NF_CAL_HIST_MAX]; - int i, j; - - for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++) - sort[i] = nfCalBuffer[i]; + int16_t nfcal[ATH9K_NF_CAL_HIST_MAX]; - for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) { - for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) { - if (sort[j] > sort[j - 1]) - swap(sort[j], sort[j - 1]); - } - } - nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1]; + memcpy(nfcal, nfCalBuffer, sizeof(nfcal)); + sort(nfcal, ATH9K_NF_CAL_HIST_MAX, sizeof(int16_t), rcmp_i16, NULL); - return nfval; + return nfcal[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1]; } static struct ath_nf_limits *ath9k_hw_get_nf_limits(struct ath_hw *ah, From 21261e4d564e866bdae810b4fb5278a3a6a1a6ed Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 12 Jan 2025 12:46:27 +0530 Subject: [PATCH 56/60] wifi: ath12k: Refactor ath12k_hw set helper function argument Currently, ath12k_hw is placed inside the ath12k_hw_group. However, the ath12k_hw set helper function takes the device handle and the index as parameters. Here, the index parameter is specific to the group handle. Therefore, change this helper function argument from the device handle to the group handle. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Acked-by: Kalle Valo Link: https://patch.msgid.link/20250112071630.4059410-2-quic_periyasa@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.h | 4 ++-- drivers/net/wireless/ath/ath12k/mac.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 3dd01ad100c56..9eb4eb410af26 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -1199,10 +1199,10 @@ static inline struct ath12k_hw *ath12k_ab_to_ah(struct ath12k_base *ab, int idx) return ab->ag->ah[idx]; } -static inline void ath12k_ab_set_ah(struct ath12k_base *ab, int idx, +static inline void ath12k_ag_set_ah(struct ath12k_hw_group *ag, int idx, struct ath12k_hw *ah) { - ab->ag->ah[idx] = ah; + ag->ah[idx] = ah; } static inline int ath12k_get_num_hw(struct ath12k_base *ab) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 48d110e2a7ded..6a7a01c35f028 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -11362,7 +11362,7 @@ void ath12k_mac_destroy(struct ath12k_hw_group *ag) continue; ath12k_mac_hw_destroy(ah); - ath12k_ab_set_ah(ab, i, NULL); + ath12k_ag_set_ah(ag, i, NULL); } } @@ -11443,7 +11443,7 @@ int ath12k_mac_allocate(struct ath12k_hw_group *ag) continue; ath12k_mac_hw_destroy(ah); - ath12k_ab_set_ah(ab, i, NULL); + ath12k_ag_set_ah(ag, i, NULL); } return ret; From 812a30271d48cff5edc39aeb436b3bebd558f5cf Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 12 Jan 2025 12:46:28 +0530 Subject: [PATCH 57/60] wifi: ath12k: Refactor the ath12k_hw get helper function argument Currently, ath12k_hw is placed inside the ath12k_hw_group. However, the ath12k_hw get helper function takes the device handle and the index as parameters. Here, the index parameter is specific to the group handle. Therefore, change this helper function argument from the device handle to the group handle. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Acked-by: Kalle Valo Link: https://patch.msgid.link/20250112071630.4059410-3-quic_periyasa@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.c | 8 ++++---- drivers/net/wireless/ath/ath12k/core.h | 4 ++-- drivers/net/wireless/ath/ath12k/mac.c | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 0c6b35aac96eb..af49e7db4928d 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1184,7 +1184,7 @@ static void ath12k_rfkill_work(struct work_struct *work) spin_unlock_bh(&ab->base_lock); for (i = 0; i < ath12k_get_num_hw(ab); i++) { - ah = ath12k_ab_to_ah(ab, i); + ah = ath12k_ag_to_ah(ab->ag, i); if (!ah) continue; @@ -1236,7 +1236,7 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) set_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags); for (i = 0; i < ath12k_get_num_hw(ab); i++) { - ah = ath12k_ab_to_ah(ab, i); + ah = ath12k_ag_to_ah(ab->ag, i); if (!ah || ah->state == ATH12K_HW_STATE_OFF) continue; @@ -1275,7 +1275,7 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab) int i, j; for (i = 0; i < ath12k_get_num_hw(ab); i++) { - ah = ath12k_ab_to_ah(ab, i); + ah = ath12k_ag_to_ah(ab->ag, i); if (!ah || ah->state == ATH12K_HW_STATE_OFF) continue; @@ -1337,7 +1337,7 @@ static void ath12k_core_restart(struct work_struct *work) } for (i = 0; i < ath12k_get_num_hw(ab); i++) { - ah = ath12k_ab_to_ah(ab, i); + ah = ath12k_ag_to_ah(ab->ag, i); ieee80211_restart_hw(ah->hw); } } diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 9eb4eb410af26..4932bd1c20965 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -1194,9 +1194,9 @@ static inline struct ieee80211_hw *ath12k_ar_to_hw(struct ath12k *ar) for ((index) = 0; ((index) < (ah)->num_radio && \ ((ar) = &(ah)->radio[(index)])); (index)++) -static inline struct ath12k_hw *ath12k_ab_to_ah(struct ath12k_base *ab, int idx) +static inline struct ath12k_hw *ath12k_ag_to_ah(struct ath12k_hw_group *ag, int idx) { - return ab->ag->ah[idx]; + return ag->ah[idx]; } static inline void ath12k_ag_set_ah(struct ath12k_hw_group *ag, int idx, diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 6a7a01c35f028..285bb88acb900 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -11244,7 +11244,7 @@ int ath12k_mac_register(struct ath12k_hw_group *ag) int ret; for (i = 0; i < ath12k_get_num_hw(ab); i++) { - ah = ath12k_ab_to_ah(ab, i); + ah = ath12k_ag_to_ah(ag, i); ret = ath12k_mac_hw_register(ah); if (ret) @@ -11257,7 +11257,7 @@ int ath12k_mac_register(struct ath12k_hw_group *ag) err: for (i = i - 1; i >= 0; i--) { - ah = ath12k_ab_to_ah(ab, i); + ah = ath12k_ag_to_ah(ag, i); if (!ah) continue; @@ -11276,7 +11276,7 @@ void ath12k_mac_unregister(struct ath12k_hw_group *ag) clear_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags); for (i = ath12k_get_num_hw(ab) - 1; i >= 0; i--) { - ah = ath12k_ab_to_ah(ab, i); + ah = ath12k_ag_to_ah(ag, i); if (!ah) continue; @@ -11357,7 +11357,7 @@ void ath12k_mac_destroy(struct ath12k_hw_group *ag) } for (i = 0; i < ath12k_get_num_hw(ab); i++) { - ah = ath12k_ab_to_ah(ab, i); + ah = ath12k_ag_to_ah(ag, i); if (!ah) continue; @@ -11438,7 +11438,7 @@ int ath12k_mac_allocate(struct ath12k_hw_group *ag) err: for (i = i - 1; i >= 0; i--) { - ah = ath12k_ab_to_ah(ab, i); + ah = ath12k_ag_to_ah(ag, i); if (!ah) continue; From 54fcdcf07baa9cb34359094f1b829b29d0845cb6 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 12 Jan 2025 12:46:29 +0530 Subject: [PATCH 58/60] wifi: ath12k: Remove ath12k_get_num_hw() helper function Currently, the ath12k_get_num_hw() helper function takes the device handle as an argument. Here, the number of hardware is retrieved from the group handle. Demanding the device handle from the caller is unnecessary since in some cases the group handle is already available. Additionally, there is no longer a need for multiple indirections to get the number of hardware. Therefore, remove this helper function and directly use ag->num_hw. This change also fixes the below Smatch static checker warning. Smatch warning: ath12k_mac_destroy() error: we previously assumed 'ab' could be null Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Reported-by: Dan Carpenter Closes: https://lore.kernel.org/ath12k/3e705de0-67d1-4437-97ff-4828d83ae2af@stanley.mountain/ Closes: https://scan7.scan.coverity.com/#/project-view/52682/11354?selectedIssue=1602340 Fixes: a343d97f27f5 ("wifi: ath12k: move struct ath12k_hw from per device to group") Signed-off-by: Karthikeyan Periyasamy Acked-by: Kalle Valo Acked-by: Jeff Johnson Link: https://patch.msgid.link/20250112071630.4059410-4-quic_periyasa@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.c | 20 ++++++++++++-------- drivers/net/wireless/ath/ath12k/core.h | 7 +------ drivers/net/wireless/ath/ath12k/mac.c | 8 ++++---- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index af49e7db4928d..0606116d6b9c4 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -1173,6 +1173,7 @@ static int ath12k_core_reconfigure_on_crash(struct ath12k_base *ab) static void ath12k_rfkill_work(struct work_struct *work) { struct ath12k_base *ab = container_of(work, struct ath12k_base, rfkill_work); + struct ath12k_hw_group *ag = ab->ag; struct ath12k *ar; struct ath12k_hw *ah; struct ieee80211_hw *hw; @@ -1183,8 +1184,8 @@ static void ath12k_rfkill_work(struct work_struct *work) rfkill_radio_on = ab->rfkill_radio_on; spin_unlock_bh(&ab->base_lock); - for (i = 0; i < ath12k_get_num_hw(ab); i++) { - ah = ath12k_ag_to_ah(ab->ag, i); + for (i = 0; i < ag->num_hw; i++) { + ah = ath12k_ag_to_ah(ag, i); if (!ah) continue; @@ -1224,6 +1225,7 @@ void ath12k_core_halt(struct ath12k *ar) static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) { + struct ath12k_hw_group *ag = ab->ag; struct ath12k *ar; struct ath12k_hw *ah; int i, j; @@ -1235,8 +1237,8 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) if (ab->is_reset) set_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags); - for (i = 0; i < ath12k_get_num_hw(ab); i++) { - ah = ath12k_ag_to_ah(ab->ag, i); + for (i = 0; i < ag->num_hw; i++) { + ah = ath12k_ag_to_ah(ag, i); if (!ah || ah->state == ATH12K_HW_STATE_OFF) continue; @@ -1270,12 +1272,13 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab) { + struct ath12k_hw_group *ag = ab->ag; struct ath12k_hw *ah; struct ath12k *ar; int i, j; - for (i = 0; i < ath12k_get_num_hw(ab); i++) { - ah = ath12k_ag_to_ah(ab->ag, i); + for (i = 0; i < ag->num_hw; i++) { + ah = ath12k_ag_to_ah(ag, i); if (!ah || ah->state == ATH12K_HW_STATE_OFF) continue; @@ -1318,6 +1321,7 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab) static void ath12k_core_restart(struct work_struct *work) { struct ath12k_base *ab = container_of(work, struct ath12k_base, restart_work); + struct ath12k_hw_group *ag = ab->ag; struct ath12k_hw *ah; int ret, i; @@ -1336,7 +1340,7 @@ static void ath12k_core_restart(struct work_struct *work) ath12k_dbg(ab, ATH12K_DBG_BOOT, "reset success\n"); } - for (i = 0; i < ath12k_get_num_hw(ab); i++) { + for (i = 0; i < ag->num_hw; i++) { ah = ath12k_ag_to_ah(ab->ag, i); ieee80211_restart_hw(ah->hw); } diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 4932bd1c20965..ee595794a7aee 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_CORE_H @@ -1205,11 +1205,6 @@ static inline void ath12k_ag_set_ah(struct ath12k_hw_group *ag, int idx, ag->ah[idx] = ah; } -static inline int ath12k_get_num_hw(struct ath12k_base *ab) -{ - return ab->ag->num_hw; -} - static inline struct ath12k_hw_group *ath12k_ab_to_ag(struct ath12k_base *ab) { return ab->ag; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 285bb88acb900..08f340afb9709 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -11243,7 +11243,7 @@ int ath12k_mac_register(struct ath12k_hw_group *ag) int i; int ret; - for (i = 0; i < ath12k_get_num_hw(ab); i++) { + for (i = 0; i < ag->num_hw; i++) { ah = ath12k_ag_to_ah(ag, i); ret = ath12k_mac_hw_register(ah); @@ -11275,7 +11275,7 @@ void ath12k_mac_unregister(struct ath12k_hw_group *ag) clear_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags); - for (i = ath12k_get_num_hw(ab) - 1; i >= 0; i--) { + for (i = ag->num_hw - 1; i >= 0; i--) { ah = ath12k_ag_to_ah(ag, i); if (!ah) continue; @@ -11356,7 +11356,7 @@ void ath12k_mac_destroy(struct ath12k_hw_group *ag) } } - for (i = 0; i < ath12k_get_num_hw(ab); i++) { + for (i = 0; i < ag->num_hw; i++) { ah = ath12k_ag_to_ah(ag, i); if (!ah) continue; From 4aae869847ce50da902005ce4d84505d54e739c9 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 12 Jan 2025 12:46:30 +0530 Subject: [PATCH 59/60] wifi: ath12k: Fix uninitialized variable access in ath12k_mac_allocate() function Currently, the uninitialized variable 'ab' is accessed in the ath12k_mac_allocate() function. Initialize 'ab' with the first radio device present in the hardware abstraction handle (ah). Additionally, move the default setting procedure from the pdev mapping iteration to the total radio calculating iteration for better code readability. Perform the maximum radio validation check for total_radio to ensure that both num_hw and radio_per_hw are validated indirectly, as these variables are derived from total_radio. This also fixes the below Smatch static checker warning. Smatch warning: ath12k_mac_allocate() error: uninitialized symbol 'ab' Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Fixes: a343d97f27f5 ("wifi: ath12k: move struct ath12k_hw from per device to group") Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Acked-by: Kalle Valo Link: https://patch.msgid.link/20250112071630.4059410-5-quic_periyasa@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 08f340afb9709..af614b301c61c 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -11383,8 +11383,20 @@ int ath12k_mac_allocate(struct ath12k_hw_group *ag) u8 radio_per_hw; total_radio = 0; - for (i = 0; i < ag->num_devices; i++) - total_radio += ag->ab[i]->num_radios; + for (i = 0; i < ag->num_devices; i++) { + ab = ag->ab[i]; + if (!ab) + continue; + + ath12k_mac_set_device_defaults(ab); + total_radio += ab->num_radios; + } + + if (!total_radio) + return -EINVAL; + + if (WARN_ON(total_radio > ATH12K_GROUP_MAX_RADIO)) + return -ENOSPC; /* All pdev get combined and register as single wiphy based on * hardware group which participate in multi-link operation else @@ -11397,14 +11409,16 @@ int ath12k_mac_allocate(struct ath12k_hw_group *ag) num_hw = total_radio / radio_per_hw; - if (WARN_ON(num_hw >= ATH12K_GROUP_MAX_RADIO)) - return -ENOSPC; - ag->num_hw = 0; device_id = 0; mac_id = 0; for (i = 0; i < num_hw; i++) { for (j = 0; j < radio_per_hw; j++) { + if (device_id >= ag->num_devices || !ag->ab[device_id]) { + ret = -ENOSPC; + goto err; + } + ab = ag->ab[device_id]; pdev_map[j].ab = ab; pdev_map[j].pdev_idx = mac_id; @@ -11416,10 +11430,11 @@ int ath12k_mac_allocate(struct ath12k_hw_group *ag) if (mac_id >= ab->num_radios) { mac_id = 0; device_id++; - ath12k_mac_set_device_defaults(ab); } } + ab = pdev_map->ab; + ah = ath12k_mac_hw_allocate(ag, pdev_map, radio_per_hw); if (!ah) { ath12k_warn(ab, "failed to allocate mac80211 hw device for hw_idx %d\n", From 336097d74c284a7c928b723ce8690f28912da03d Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Sun, 12 Jan 2025 11:23:00 +0530 Subject: [PATCH 60/60] wifi: ath12k: fix key cache handling Currently, an interface is created in the driver during channel assignment. If mac80211 attempts to set a key for an interface before this assignment, the driver caches the key. Once the interface is created, the driver installs the cached key to the hardware. This sequence is exemplified in mesh mode operation where the group key is set before channel assignment. However, in ath12k_mac_update_key_cache(), after caching the key, due to incorrect logic, it is deleted from the cache during the subsequent loop iteration. As a result, after the interface is created, the driver does not find any cached key, and the key is not installed to the hardware which is wrong. This leads to issue in mesh, where broadcast traffic is not encrypted over the air. Fix this issue by adjusting the logic of ath12k_mac_update_key_cache() properly. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3-03253.1-QCAHKSWPL_SILICONZ-29 # Nicolas Escande Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 # Nicolas Escande Fixes: 25e18b9d6b4b ("wifi: ath12k: modify ath12k_mac_op_set_key() for MLO") Signed-off-by: Aditya Kumar Singh Acked-by: Kalle Valo Tested-by: Nicolas Escande Link: https://patch.msgid.link/20250112-fix_key_cache_handling-v2-1-70e142c6153e@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 30 ++++++++++++++++----------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index af614b301c61c..2d062b5904a8e 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -4657,7 +4657,23 @@ static int ath12k_mac_update_key_cache(struct ath12k_vif_cache *cache, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { - struct ath12k_key_conf *key_conf = NULL, *tmp; + struct ath12k_key_conf *key_conf, *tmp; + + list_for_each_entry_safe(key_conf, tmp, &cache->key_conf.list, list) { + if (key_conf->key != key) + continue; + + /* If SET key entry is already present in cache, nothing to do, + * just return + */ + if (cmd == SET_KEY) + return 0; + + /* DEL key for an old SET key which driver hasn't flushed yet. + */ + list_del(&key_conf->list); + kfree(key_conf); + } if (cmd == SET_KEY) { key_conf = kzalloc(sizeof(*key_conf), GFP_KERNEL); @@ -4671,17 +4687,7 @@ static int ath12k_mac_update_key_cache(struct ath12k_vif_cache *cache, list_add_tail(&key_conf->list, &cache->key_conf.list); } - if (list_empty(&cache->key_conf.list)) - return 0; - list_for_each_entry_safe(key_conf, tmp, &cache->key_conf.list, list) { - if (key_conf->key == key) { - /* DEL key for an old SET key which driver hasn't flushed yet. - */ - list_del(&key_conf->list); - kfree(key_conf); - break; - } - } + return 0; }