From 08d82175bfbbbf7fc2bfca391877abed320b5e29 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 16 Jan 2024 15:54:52 +0000 Subject: wifi: ath9k: remove redundant assignment to variable ret MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The variable ret is being assigned a value but it isn't being read afterwards. The assignment is redundant and so ret can be removed. Cleans up clang scan build warning: warning: Although the value stored to 'ret' is used in the enclosing expression, the value is never actually read from 'ret' [deadcode.DeadStores] Signed-off-by: Colin Ian King Acked-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://msgid.link/20240116155452.2315351-1-colin.i.king@gmail.com --- drivers/net/wireless/ath/ath9k/xmit.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index f15684379b03..d519b676a109 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -369,12 +369,11 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, struct list_head bf_head; struct ath_tx_status ts; struct ath_frame_info *fi; - int ret; memset(&ts, 0, sizeof(ts)); INIT_LIST_HEAD(&bf_head); - while ((ret = ath_tid_dequeue(tid, &skb)) == 0) { + while (ath_tid_dequeue(tid, &skb) == 0) { fi = get_frame_info(skb); bf = fi->bf; -- cgit From 24355fcb0d4cbcb6ddda262596558e8cfba70f11 Mon Sep 17 00:00:00 2001 From: Toke Høiland-Jørgensen Date: Fri, 26 Jan 2024 15:02:17 +0100 Subject: wifi: ath9k: delay all of ath9k_wmi_event_tasklet() until init is complete MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ath9k_wmi_event_tasklet() used in ath9k_htc assumes that all the data structures have been fully initialised by the time it runs. However, because of the order in which things are initialised, this is not guaranteed to be the case, because the device is exposed to the USB subsystem before the ath9k driver initialisation is completed. We already committed a partial fix for this in commit: 8b3046abc99e ("ath9k_htc: fix NULL pointer dereference at ath9k_htc_tx_get_packet()") However, that commit only aborted the WMI_TXSTATUS_EVENTID command in the event tasklet, pairing it with an "initialisation complete" bit in the TX struct. It seems syzbot managed to trigger the race for one of the other commands as well, so let's just move the existing synchronisation bit to cover the whole tasklet (setting it at the end of ath9k_htc_probe_device() instead of inside ath9k_tx_init()). Link: https://lore.kernel.org/r/ed1d2c66-1193-4c81-9542-d514c29ba8b8.bugreport@ubisectech.com Fixes: 8b3046abc99e ("ath9k_htc: fix NULL pointer dereference at ath9k_htc_tx_get_packet()") Reported-by: Ubisectech Sirius Signed-off-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://msgid.link/20240126140218.1033443-1-toke@toke.dk --- drivers/net/wireless/ath/ath9k/htc.h | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 4 ++++ drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 4 ---- drivers/net/wireless/ath/ath9k/wmi.c | 10 ++++++---- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 237f4ec2cffd..6c33e898b300 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -306,7 +306,6 @@ struct ath9k_htc_tx { DECLARE_BITMAP(tx_slot, MAX_TX_BUF_NUM); struct timer_list cleanup_timer; spinlock_t tx_lock; - bool initialized; }; struct ath9k_htc_tx_ctl { @@ -515,6 +514,7 @@ struct ath9k_htc_priv { unsigned long ps_usecount; bool ps_enabled; bool ps_idle; + bool initialized; #ifdef CONFIG_MAC80211_LEDS enum led_brightness brightness; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 0aa5bdeb44a1..3633f9eb2c55 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -966,6 +966,10 @@ int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, htc_handle->drv_priv = priv; + /* Allow ath9k_wmi_event_tasklet() to operate. */ + smp_wmb(); + priv->initialized = true; + return 0; err_init: diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index efcaeccb055a..ce9c04e418b8 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -815,10 +815,6 @@ int ath9k_tx_init(struct ath9k_htc_priv *priv) skb_queue_head_init(&priv->tx.data_vo_queue); skb_queue_head_init(&priv->tx.tx_failed); - /* Allow ath9k_wmi_event_tasklet(WMI_TXSTATUS_EVENTID) to operate. */ - smp_wmb(); - priv->tx.initialized = true; - return 0; } diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 1476b42b52a9..805ad31edba2 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -155,6 +155,12 @@ void ath9k_wmi_event_tasklet(struct tasklet_struct *t) } spin_unlock_irqrestore(&wmi->wmi_lock, flags); + /* Check if ath9k_htc_probe_device() completed. */ + if (!data_race(priv->initialized)) { + kfree_skb(skb); + continue; + } + hdr = (struct wmi_cmd_hdr *) skb->data; cmd_id = be16_to_cpu(hdr->command_id); wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr)); @@ -169,10 +175,6 @@ void ath9k_wmi_event_tasklet(struct tasklet_struct *t) &wmi->drv_priv->fatal_work); break; case WMI_TXSTATUS_EVENTID: - /* Check if ath9k_tx_init() completed. */ - if (!data_race(priv->tx.initialized)) - break; - spin_lock_bh(&priv->tx.tx_lock); if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) { spin_unlock_bh(&priv->tx.tx_lock); -- cgit From 413e20e82ee78f142cb5194fd317db514f012602 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Wed, 31 Jan 2024 10:18:32 +0800 Subject: wifi: ath11k: change to move WMI_VDEV_PARAM_SET_HEMU_MODE before WMI_PEER_ASSOC_CMDID Currently when connecting to an AP with 11AX-HE phy mode, host sends WMI_VDEV_PARAM_SET_HEMU_MODE parameter to firmware after WMI_PEER_ASSOC_CMDID command. This results in TXBF not working, because firmware calculates TXBF values while handling WMI_PEER_ASSOC_CMDID, however at that time WMI_VDEV_PARAM_SET_HEMU_MODE has not been sent yet. See below log: AP sends "VHT/HE/EHT NDP Announcement" to station, and station sends "Action no Ack" of category code HE to AP, the "Nc Index" and "Codebook Information" are wrong: Issued action: IEEE 802.11 Action No Ack, Flags: ........ IEEE 802.11 wireless LAN Fixed parameters Category code: HE (30) HE Action: HE Compressed Beamforming And CQI (0) Total length: 152 HE MIMO Control: 0x0004008018 .... .... .... .... .... .... .... .... .... .000 = Nc Index: 1 Column (0) .... .... .... .... .... .... .... ..0. .... .... = Codebook Information: 0 Change to send WMI_VDEV_PARAM_SET_HEMU_MODE before WMI_PEER_ASSOC_CMDID, then firmware will calculate the TXBF values with valid parameters instead of empty values. TXBF works well and throughput performance is improved from 80 Mbps to 130 Mbps with this patch. Good action after this patch: IEEE 802.11 Action No Ack, Flags: ........ IEEE 802.11 wireless LAN Fixed parameters Category code: HE (30) HE Action: HE Compressed Beamforming And CQI (0) Total length: 409 HE MIMO Control: 0x0004008219 .... .... .... .... .... .... .... .... .... .001 = Nc Index: 2 Columns (1) .... .... .... .... .... .... .... ..1. .... .... = Codebook Information: 1 This change applies to all chipsets. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Fixes: 38dfe775d0ab ("wifi: ath11k: push MU-MIMO params from hostapd to hardware") Signed-off-by: Wen Gong Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240131021832.17298-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index bbf4d1f4d310..df1b1ee71881 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -3023,7 +3023,14 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, rcu_read_unlock(); + if (!ath11k_mac_vif_recalc_sta_he_txbf(ar, vif, &he_cap)) { + ath11k_warn(ar->ab, "failed to recalc he txbf for vdev %i on bss %pM\n", + arvif->vdev_id, bss_conf->bssid); + return; + } + peer_arg.is_assoc = true; + ret = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg); if (ret) { ath11k_warn(ar->ab, "failed to run peer assoc for %pM vdev %i: %d\n", @@ -3046,12 +3053,6 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, return; } - if (!ath11k_mac_vif_recalc_sta_he_txbf(ar, vif, &he_cap)) { - ath11k_warn(ar->ab, "failed to recalc he txbf for vdev %i on bss %pM\n", - arvif->vdev_id, bss_conf->bssid); - return; - } - WARN_ON(arvif->is_up); arvif->aid = vif->cfg.aid; -- cgit From 12f491cd6d812559e2d986b7836e9062d2efde96 Mon Sep 17 00:00:00 2001 From: Raj Kumar Bhagat Date: Tue, 23 Jan 2024 17:58:12 +0530 Subject: wifi: ath12k: add firmware-2.bin support Firmware IE containers can dynamically provide various information what firmware supports. Also it can embed more than one image so updating firmware is easy, user just needs to update one file in /lib/firmware/. The firmware API 2 or higher will use the IE container format, the current API 1 will not use the new format but it still is supported for some time. Firmware API 2 files are named as firmware-2.bin (which contains both amss.bin and m3.bin images) and API 1 files are amss.bin and m3.bin. Currently ath12k PCI driver provides firmware binary (amss.bin) path to MHI driver, MHI driver reads firmware from filesystem and boots it. Add provision to read firmware files from ath12k driver and provide the amss.bin firmware data and size to MHI using a pointer. Currently enum ath12k_fw_features is empty, the patches adding features will add the flags. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240123122812.3811251-1-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/Makefile | 3 +- drivers/net/wireless/ath/ath12k/core.c | 4 + drivers/net/wireless/ath/ath12k/core.h | 14 +++ drivers/net/wireless/ath/ath12k/fw.c | 164 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/fw.h | 27 +++++ drivers/net/wireless/ath/ath12k/mhi.c | 20 ++-- drivers/net/wireless/ath/ath12k/qmi.c | 49 ++++++--- 7 files changed, 259 insertions(+), 22 deletions(-) create mode 100644 drivers/net/wireless/ath/ath12k/fw.c create mode 100644 drivers/net/wireless/ath/ath12k/fw.h diff --git a/drivers/net/wireless/ath/ath12k/Makefile b/drivers/net/wireless/ath/ath12k/Makefile index 62c52e733b5e..0d723e85cf6b 100644 --- a/drivers/net/wireless/ath/ath12k/Makefile +++ b/drivers/net/wireless/ath/ath12k/Makefile @@ -19,7 +19,8 @@ ath12k-y += core.o \ hw.o \ mhi.o \ pci.o \ - dp_mon.o + dp_mon.o \ + fw.o ath12k-$(CONFIG_ATH12K_TRACING) += trace.o diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 1baad3302157..634a9ddc2fe5 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -14,6 +14,7 @@ #include "dp_rx.h" #include "debug.h" #include "hif.h" +#include "fw.h" unsigned int ath12k_debug_mask; module_param_named(debug_mask, ath12k_debug_mask, uint, 0644); @@ -1109,6 +1110,8 @@ int ath12k_core_pre_init(struct ath12k_base *ab) return ret; } + ath12k_fw_map(ab); + return 0; } @@ -1137,6 +1140,7 @@ void ath12k_core_deinit(struct ath12k_base *ab) ath12k_hif_power_down(ab); ath12k_mac_destroy(ab); ath12k_core_soc_destroy(ab); + ath12k_fw_unmap(ab); } void ath12k_core_free(struct ath12k_base *ab) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 5c6c1e2eddb6..fc906d7acd42 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "qmi.h" #include "htc.h" #include "wmi.h" @@ -24,6 +25,7 @@ #include "hal_rx.h" #include "reg.h" #include "dbring.h" +#include "fw.h" #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) @@ -824,6 +826,18 @@ struct ath12k_base { u32 subsystem_device; } id; + struct { + u32 api_version; + + const struct firmware *fw; + const u8 *amss_data; + size_t amss_len; + const u8 *m3_data; + size_t m3_len; + + DECLARE_BITMAP(fw_features, ATH12K_FW_FEATURE_COUNT); + } fw; + /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath12k/fw.c b/drivers/net/wireless/ath/ath12k/fw.c new file mode 100644 index 000000000000..fbcf40c97792 --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/fw.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "core.h" + +#include "debug.h" + +static int ath12k_fw_request_firmware_api_n(struct ath12k_base *ab, + const char *name) +{ + size_t magic_len, len, ie_len; + int ie_id, i, index, bit, ret; + struct ath12k_fw_ie *hdr; + const u8 *data; + __le32 *timestamp; + + ab->fw.fw = ath12k_core_firmware_request(ab, name); + if (IS_ERR(ab->fw.fw)) { + ret = PTR_ERR(ab->fw.fw); + ath12k_dbg(ab, ATH12K_DBG_BOOT, "failed to load %s: %d\n", name, ret); + ab->fw.fw = NULL; + return ret; + } + + data = ab->fw.fw->data; + len = ab->fw.fw->size; + + /* magic also includes the null byte, check that as well */ + magic_len = strlen(ATH12K_FIRMWARE_MAGIC) + 1; + + if (len < magic_len) { + ath12k_err(ab, "firmware image too small to contain magic: %zu\n", + len); + ret = -EINVAL; + goto err; + } + + if (memcmp(data, ATH12K_FIRMWARE_MAGIC, magic_len) != 0) { + ath12k_err(ab, "Invalid firmware magic\n"); + ret = -EINVAL; + goto err; + } + + /* jump over the padding */ + magic_len = ALIGN(magic_len, 4); + + /* make sure there's space for padding */ + if (magic_len > len) { + ath12k_err(ab, "No space for padding after magic\n"); + ret = -EINVAL; + goto err; + } + + len -= magic_len; + data += magic_len; + + /* loop elements */ + while (len > sizeof(struct ath12k_fw_ie)) { + hdr = (struct ath12k_fw_ie *)data; + + ie_id = le32_to_cpu(hdr->id); + ie_len = le32_to_cpu(hdr->len); + + len -= sizeof(*hdr); + data += sizeof(*hdr); + + if (len < ie_len) { + ath12k_err(ab, "Invalid length for FW IE %d (%zu < %zu)\n", + ie_id, len, ie_len); + ret = -EINVAL; + goto err; + } + + switch (ie_id) { + case ATH12K_FW_IE_TIMESTAMP: + if (ie_len != sizeof(u32)) + break; + + timestamp = (__le32 *)data; + + ath12k_dbg(ab, ATH12K_DBG_BOOT, "found fw timestamp %d\n", + le32_to_cpup(timestamp)); + break; + case ATH12K_FW_IE_FEATURES: + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "found firmware features ie (%zd B)\n", + ie_len); + + for (i = 0; i < ATH12K_FW_FEATURE_COUNT; i++) { + index = i / 8; + bit = i % 8; + + if (index == ie_len) + break; + + if (data[index] & (1 << bit)) + __set_bit(i, ab->fw.fw_features); + } + + ath12k_dbg_dump(ab, ATH12K_DBG_BOOT, "features", "", + ab->fw.fw_features, + sizeof(ab->fw.fw_features)); + break; + case ATH12K_FW_IE_AMSS_IMAGE: + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "found fw image ie (%zd B)\n", + ie_len); + + ab->fw.amss_data = data; + ab->fw.amss_len = ie_len; + break; + case ATH12K_FW_IE_M3_IMAGE: + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "found m3 image ie (%zd B)\n", + ie_len); + + ab->fw.m3_data = data; + ab->fw.m3_len = ie_len; + break; + default: + ath12k_warn(ab, "Unknown FW IE: %u\n", ie_id); + break; + } + + /* jump over the padding */ + ie_len = ALIGN(ie_len, 4); + + /* make sure there's space for padding */ + if (ie_len > len) + break; + + len -= ie_len; + data += ie_len; + } + + return 0; + +err: + release_firmware(ab->fw.fw); + ab->fw.fw = NULL; + return ret; +} + +void ath12k_fw_map(struct ath12k_base *ab) +{ + int ret; + + ret = ath12k_fw_request_firmware_api_n(ab, ATH12K_FW_API2_FILE); + if (ret == 0) + ab->fw.api_version = 2; + else + ab->fw.api_version = 1; + + ath12k_dbg(ab, ATH12K_DBG_BOOT, "using fw api %d\n", + ab->fw.api_version); +} + +void ath12k_fw_unmap(struct ath12k_base *ab) +{ + release_firmware(ab->fw.fw); + memset(&ab->fw, 0, sizeof(ab->fw)); +} diff --git a/drivers/net/wireless/ath/ath12k/fw.h b/drivers/net/wireless/ath/ath12k/fw.h new file mode 100644 index 000000000000..d91d95fc5740 --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/fw.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef ATH12K_FW_H +#define ATH12K_FW_H + +#define ATH12K_FW_API2_FILE "firmware-2.bin" +#define ATH12K_FIRMWARE_MAGIC "QCOM-ATH12K-FW" + +enum ath12k_fw_ie_type { + ATH12K_FW_IE_TIMESTAMP = 0, + ATH12K_FW_IE_FEATURES = 1, + ATH12K_FW_IE_AMSS_IMAGE = 2, + ATH12K_FW_IE_M3_IMAGE = 3, +}; + +enum ath12k_fw_features { + /* keep last */ + ATH12K_FW_FEATURE_COUNT, +}; + +void ath12k_fw_map(struct ath12k_base *ab); +void ath12k_fw_unmap(struct ath12k_base *ab); + +#endif /* ATH12K_FW_H */ diff --git a/drivers/net/wireless/ath/ath12k/mhi.c b/drivers/net/wireless/ath/ath12k/mhi.c index d5441ddb374b..b7b31978a434 100644 --- a/drivers/net/wireless/ath/ath12k/mhi.c +++ b/drivers/net/wireless/ath/ath12k/mhi.c @@ -1,11 +1,12 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include +#include #include "core.h" #include "debug.h" @@ -364,17 +365,24 @@ int ath12k_mhi_register(struct ath12k_pci *ab_pci) if (!mhi_ctrl) return -ENOMEM; - ath12k_core_create_firmware_path(ab, ATH12K_AMSS_FILE, - ab_pci->amss_path, - sizeof(ab_pci->amss_path)); - ab_pci->mhi_ctrl = mhi_ctrl; mhi_ctrl->cntrl_dev = ab->dev; - mhi_ctrl->fw_image = ab_pci->amss_path; mhi_ctrl->regs = ab->mem; mhi_ctrl->reg_len = ab->mem_len; mhi_ctrl->rddm_size = ab->hw_params->rddm_size; + if (ab->fw.amss_data && ab->fw.amss_len > 0) { + /* use MHI firmware file from firmware-N.bin */ + mhi_ctrl->fw_data = ab->fw.amss_data; + mhi_ctrl->fw_sz = ab->fw.amss_len; + } else { + /* use the old separate mhi.bin MHI firmware file */ + ath12k_core_create_firmware_path(ab, ATH12K_AMSS_FILE, + ab_pci->amss_path, + sizeof(ab_pci->amss_path)); + mhi_ctrl->fw_image = ab_pci->amss_path; + } + ret = ath12k_mhi_get_msi(ab_pci); if (ret) { ath12k_err(ab, "failed to get msi for mhi\n"); diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 69f56400367c..0f0eaadc8418 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -2666,37 +2666,56 @@ out: static int ath12k_qmi_m3_load(struct ath12k_base *ab) { struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; - const struct firmware *fw; + const struct firmware *fw = NULL; + const void *m3_data; char path[100]; + size_t m3_len; int ret; - if (m3_mem->vaddr || m3_mem->size) + if (m3_mem->vaddr) + /* m3 firmware buffer is already available in the DMA buffer */ return 0; - fw = ath12k_core_firmware_request(ab, ATH12K_M3_FILE); - if (IS_ERR(fw)) { - ret = PTR_ERR(fw); - ath12k_core_create_firmware_path(ab, ATH12K_M3_FILE, - path, sizeof(path)); - ath12k_err(ab, "failed to load %s: %d\n", path, ret); - return ret; + if (ab->fw.m3_data && ab->fw.m3_len > 0) { + /* firmware-N.bin had a m3 firmware file so use that */ + m3_data = ab->fw.m3_data; + m3_len = ab->fw.m3_len; + } else { + /* No m3 file in firmware-N.bin so try to request old + * separate m3.bin. + */ + fw = ath12k_core_firmware_request(ab, ATH12K_M3_FILE); + if (IS_ERR(fw)) { + ret = PTR_ERR(fw); + ath12k_core_create_firmware_path(ab, ATH12K_M3_FILE, + path, sizeof(path)); + ath12k_err(ab, "failed to load %s: %d\n", path, ret); + return ret; + } + + m3_data = fw->data; + m3_len = fw->size; } m3_mem->vaddr = dma_alloc_coherent(ab->dev, - fw->size, &m3_mem->paddr, + m3_len, &m3_mem->paddr, GFP_KERNEL); if (!m3_mem->vaddr) { ath12k_err(ab, "failed to allocate memory for M3 with size %zu\n", fw->size); - release_firmware(fw); - return -ENOMEM; + ret = -ENOMEM; + goto out; } - memcpy(m3_mem->vaddr, fw->data, fw->size); - m3_mem->size = fw->size; + memcpy(m3_mem->vaddr, m3_data, m3_len); + m3_mem->size = m3_len; + + ret = 0; + +out: release_firmware(fw); - return 0; + return ret; } static void ath12k_qmi_m3_free(struct ath12k_base *ab) -- cgit From 6925eba532e1e9a30ae0f6807dba07f596ba0cd6 Mon Sep 17 00:00:00 2001 From: Sriram R Date: Mon, 29 Jan 2024 12:27:12 +0530 Subject: wifi: ath12k: indicate NON MBSSID vdev by default during vdev start When any VDEV is started, MBSSID flags are passed to firmware to indicate if its a MBSSID/EMA AP vdev. If the interface is not an AP or if the AP doesn't support MBSSID, the vdev needs to be brought up as a non MBSSID vdev. Set these flags as a non MBSSID AP by default which can be updated as and when MBSSID support is added in ath12k. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Sriram R Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-2-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 5 +++++ drivers/net/wireless/ath/ath12k/wmi.c | 1 + drivers/net/wireless/ath/ath12k/wmi.h | 8 ++++++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index a27480a69b27..672c9d347097 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -6153,6 +6153,11 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, arg.pref_tx_streams = ar->num_tx_chains; arg.pref_rx_streams = ar->num_rx_chains; + /* Fill the MBSSID flags to indicate AP is non MBSSID by default + * Corresponding flags would be updated with MBSSID support. + */ + arg.mbssid_flags = WMI_VDEV_MBSSID_FLAGS_NON_MBSSID_AP; + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { arg.ssid = arvif->u.ap.ssid; arg.ssid_len = arvif->u.ap.ssid_len; diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 2fa724e5851a..5f1cce16589f 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -1024,6 +1024,7 @@ int ath12k_wmi_vdev_start(struct ath12k *ar, struct wmi_vdev_start_req_arg *arg, cmd->regdomain = cpu_to_le32(arg->regdomain); cmd->he_ops = cpu_to_le32(arg->he_ops); cmd->punct_bitmap = cpu_to_le32(arg->punct_bitmap); + cmd->mbssid_flags = cpu_to_le32(arg->mbssid_flags); if (!restart) { if (arg->ssid) { diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 06e5b9b4049b..d8481c710021 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_WMI_H @@ -2764,6 +2764,10 @@ struct ath12k_wmi_ssid_params { #define ATH12K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ) +enum wmi_vdev_mbssid_flags { + WMI_VDEV_MBSSID_FLAGS_NON_MBSSID_AP = BIT(0), +}; + struct wmi_vdev_start_request_cmd { __le32 tlv_header; __le32 vdev_id; @@ -2782,7 +2786,7 @@ struct wmi_vdev_start_request_cmd { __le32 cac_duration_ms; __le32 regdomain; __le32 min_data_rate; - __le32 mbssid_flags; + __le32 mbssid_flags; /* uses enum wmi_vdev_mbssid_flags */ __le32 mbssid_tx_vdev_id; __le32 eht_ops; __le32 punct_bitmap; -- cgit From 9f06911998cac015e333f519243f1601ca687f47 Mon Sep 17 00:00:00 2001 From: Sowmiya Sree Elavalagan Date: Mon, 29 Jan 2024 12:27:13 +0530 Subject: wifi: ath12k: fetch correct pdev id from WMI_SERVICE_READY_EXT_EVENTID Currently while fetching for pdev id from WMI_SERVICE_READY_EXT_EVENTID we consider 32 bit pdev_id in ath12k_wmi_caps_ext_params structure. But Firmware sends lower 16 bit for pdev id along with higher 16 bit for hw_link_id. Due to this wrong pdev id is fetched. This wrong pdev id when used for WMI commands leads to Firmware crash. Hence fetch the correct pdev id considering only the lower 16 bits. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Sowmiya Sree Elavalagan Co-developed-by: Raj Kumar Bhagat Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-3-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.c | 9 +++---- drivers/net/wireless/ath/ath12k/wmi.h | 44 ++++++++++++++++++++++++++++------- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 5f1cce16589f..487ca82bd17d 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -493,13 +493,13 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, mac_caps = wmi_mac_phy_caps + phy_idx; - pdev->pdev_id = le32_to_cpu(mac_caps->pdev_id); + pdev->pdev_id = ath12k_wmi_mac_phy_get_pdev_id(mac_caps); pdev_cap->supported_bands |= le32_to_cpu(mac_caps->supported_bands); pdev_cap->ampdu_density = le32_to_cpu(mac_caps->ampdu_density); fw_pdev = &ab->fw_pdev[ab->fw_pdev_count]; fw_pdev->supported_bands = le32_to_cpu(mac_caps->supported_bands); - fw_pdev->pdev_id = le32_to_cpu(mac_caps->pdev_id); + fw_pdev->pdev_id = ath12k_wmi_mac_phy_get_pdev_id(mac_caps); fw_pdev->phy_id = le32_to_cpu(mac_caps->phy_id); ab->fw_pdev_count++; @@ -4215,7 +4215,7 @@ ath12k_wmi_tlv_mac_phy_caps_ext_parse(struct ath12k_base *ab, for (i = 0; i < ab->fw_pdev_count; i++) { struct ath12k_fw_pdev *fw_pdev = &ab->fw_pdev[i]; - if (fw_pdev->pdev_id == le32_to_cpu(caps->pdev_id) && + if (fw_pdev->pdev_id == ath12k_wmi_caps_ext_get_pdev_id(caps) && fw_pdev->phy_id == le32_to_cpu(caps->phy_id)) { bands = fw_pdev->supported_bands; break; @@ -4272,7 +4272,8 @@ static int ath12k_wmi_tlv_mac_phy_caps_ext(struct ath12k_base *ab, u16 tag, return 0; } else { for (i = 0; i < ab->num_radios; i++) { - if (ab->pdevs[i].pdev_id == le32_to_cpu(caps->pdev_id)) + if (ab->pdevs[i].pdev_id == + ath12k_wmi_caps_ext_get_pdev_id(caps)) break; } diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index d8481c710021..06b931222321 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2542,9 +2542,17 @@ struct ath12k_wmi_hw_mode_cap_params { #define WMI_MAX_HECAP_PHY_SIZE (3) +/* pdev_id is present in lower 16 bits of pdev_and_hw_link_ids in + * ath12k_wmi_mac_phy_caps_params & ath12k_wmi_caps_ext_params. + * + * hw_link_id is present in higher 16 bits of pdev_and_hw_link_ids. + */ +#define WMI_CAPS_PARAMS_PDEV_ID GENMASK(15, 0) +#define WMI_CAPS_PARAMS_HW_LINK_ID GENMASK(31, 16) + struct ath12k_wmi_mac_phy_caps_params { __le32 hw_mode_id; - __le32 pdev_id; + __le32 pdev_and_hw_link_ids; __le32 phy_id; __le32 supported_flags; __le32 supported_bands; @@ -2636,13 +2644,7 @@ struct wmi_service_ready_ext2_event { struct ath12k_wmi_caps_ext_params { __le32 hw_mode_id; - union { - struct { - __le16 pdev_id; - __le16 hw_link_id; - } __packed ath12k_wmi_pdev_to_link_map; - __le32 pdev_id; - }; + __le32 pdev_and_hw_link_ids; __le32 phy_id; __le32 wireless_modes_ext; __le32 eht_cap_mac_info_2ghz[WMI_MAX_EHTCAP_MAC_SIZE]; @@ -4921,4 +4923,30 @@ int ath12k_wmi_probe_resp_tmpl(struct ath12k *ar, u32 vdev_id, int ath12k_wmi_set_hw_mode(struct ath12k_base *ab, enum wmi_host_hw_mode_config_type mode); +static inline u32 +ath12k_wmi_caps_ext_get_pdev_id(const struct ath12k_wmi_caps_ext_params *param) +{ + return le32_get_bits(param->pdev_and_hw_link_ids, WMI_CAPS_PARAMS_PDEV_ID); +} + +static inline u32 +ath12k_wmi_caps_ext_get_hw_link_id(const struct ath12k_wmi_caps_ext_params *param) +{ + return le32_get_bits(param->pdev_and_hw_link_ids, WMI_CAPS_PARAMS_HW_LINK_ID); +} + +static inline u32 +ath12k_wmi_mac_phy_get_pdev_id(const struct ath12k_wmi_mac_phy_caps_params *param) +{ + return le32_get_bits(param->pdev_and_hw_link_ids, + WMI_CAPS_PARAMS_PDEV_ID); +} + +static inline u32 +ath12k_wmi_mac_phy_get_hw_link_id(const struct ath12k_wmi_mac_phy_caps_params *param) +{ + return le32_get_bits(param->pdev_and_hw_link_ids, + WMI_CAPS_PARAMS_HW_LINK_ID); +} + #endif -- cgit From 28703381099022e18df1de7c2c665d72f92c7819 Mon Sep 17 00:00:00 2001 From: Harshitha Prem Date: Mon, 29 Jan 2024 12:27:14 +0530 Subject: wifi: ath12k: add support for peer meta data version Add support to process WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT service bit. If this service bit is set by firmware, then it expects host to set rx_peer_meta_data_ver in wmi_resource_config's flags2 with value 3 for QCN9274 to indicate as V1B meta version. If this is not set firmware crash is seen during peer addition. Hence, if WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT service bit is set by firmware, set correct peer metadata version to avoid firmware crash. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Harshitha Prem Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-4-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/hw.h | 4 +++- drivers/net/wireless/ath/ath12k/wmi.c | 6 ++++++ drivers/net/wireless/ath/ath12k/wmi.h | 4 ++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 0c3b416ae150..44ba3a50e075 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_HW_H @@ -66,6 +66,8 @@ #define TARGET_NUM_WDS_ENTRIES 32 #define TARGET_DMA_BURST_SIZE 1 #define TARGET_RX_BATCHMODE 1 +#define TARGET_RX_PEER_METADATA_VER_V1A 2 +#define TARGET_RX_PEER_METADATA_VER_V1B 3 #define ATH12K_HW_MAX_QUEUES 4 #define ATH12K_QUEUE_LEN 4096 diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 487ca82bd17d..276351d68efb 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -228,6 +228,9 @@ void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, config->peer_map_unmap_version = 0x32; config->twt_ap_pdev_count = ab->num_radios; config->twt_ap_sta_count = 1000; + + if (test_bit(WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT, ab->wmi_ab.svc_map)) + config->dp_peer_meta_data_ver = TARGET_RX_PEER_METADATA_VER_V1B; } void ath12k_wmi_init_wcn7850(struct ath12k_base *ab, @@ -3266,6 +3269,9 @@ ath12k_wmi_copy_resource_config(struct ath12k_wmi_resource_config_params *wmi_cf wmi_cfg->sched_params = cpu_to_le32(tg_cfg->sched_params); wmi_cfg->twt_ap_pdev_count = cpu_to_le32(tg_cfg->twt_ap_pdev_count); wmi_cfg->twt_ap_sta_count = cpu_to_le32(tg_cfg->twt_ap_sta_count); + wmi_cfg->flags2 = le32_encode_bits(tg_cfg->dp_peer_meta_data_ver, + WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION); + wmi_cfg->host_service_flags = cpu_to_le32(tg_cfg->is_reg_cc_ext_event_supported << WMI_RSRC_CFG_HOST_SVC_FLAG_REG_CC_EXT_SUPPORT_BIT); } diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 06b931222321..7443831d62d8 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2163,6 +2163,8 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_11BE = 289, + WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT = 365, + WMI_MAX_EXT2_SERVICE, }; @@ -2350,6 +2352,7 @@ struct ath12k_wmi_resource_config_arg { u32 twt_ap_pdev_count; u32 twt_ap_sta_count; bool is_reg_cc_ext_event_supported; + u8 dp_peer_meta_data_ver; }; struct ath12k_wmi_init_cmd_arg { @@ -2402,6 +2405,7 @@ struct wmi_init_cmd { } __packed; #define WMI_RSRC_CFG_HOST_SVC_FLAG_REG_CC_EXT_SUPPORT_BIT 4 +#define WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION GENMASK(5, 4) struct ath12k_wmi_resource_config_params { __le32 tlv_header; -- cgit From 902700d55d4a4522bb3eb4ef94f752a19c42230a Mon Sep 17 00:00:00 2001 From: Raj Kumar Bhagat Date: Mon, 29 Jan 2024 12:27:15 +0530 Subject: wifi: ath12k: fix fetching MCBC flag for QCN9274 In QCN9274, RX packet's multicast and broadcast(MCBC) flag is fetched from RX descriptor's msdu_end info5 member but it is not correct for QCN9274. Due to this with encryption, ARP request packet is wrongly marked as MCBC packet and it is sent to mac80211 without setting RX_FLAG_PN_VALIDATED & RX_FLAG_DECRYPTED flag. This results in packet getting dropped in mac80211. Hence ping initiated from station to AP fails. Fix this by fetching correct MCBC flag in case of QCN9274. For QC9274 MCBC flag should be fetched from RX descriptor's mpdu_start info6 member. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Fixes: 8f04852e90cb ("wifi: ath12k: Use msdu_end to check MCBC") Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-5-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/hal.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index a489369d8068..1bdab8604db9 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include "hal_tx.h" @@ -449,8 +449,8 @@ static u8 *ath12k_hw_qcn9274_rx_desc_mpdu_start_addr2(struct hal_rx_desc *desc) static bool ath12k_hw_qcn9274_rx_desc_is_da_mcbc(struct hal_rx_desc *desc) { - return __le16_to_cpu(desc->u.qcn9274.msdu_end.info5) & - RX_MSDU_END_INFO5_DA_IS_MCBC; + return __le32_to_cpu(desc->u.qcn9274.mpdu_start.info6) & + RX_MPDU_START_INFO6_MCAST_BCAST; } static void ath12k_hw_qcn9274_rx_desc_get_dot11_hdr(struct hal_rx_desc *desc, -- cgit From 94e8235c679db3e3b130a91d4c1d8f5023a5bb01 Mon Sep 17 00:00:00 2001 From: P Praneesh Date: Mon, 29 Jan 2024 12:27:16 +0530 Subject: wifi: ath12k: Add logic to write QRTR node id to scratch Currently only one MHI device is registered successfully on platform having two or more identical MHI devices. This is beacuse QMI service runs with identical QRTR node ID. And, qrtr-lookup cannot register more than one QMI service with identical node ID. Hence, generate a unique QRTR instance ID from PCIe domain number and bus number. QMI allows node id to be written on scratch register. Add logic to write QRTR node id to the register. It is available for firmware to uniquely identify an instance. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: P Praneesh Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-6-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/fw.h | 5 +++++ drivers/net/wireless/ath/ath12k/pci.c | 39 ++++++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath12k/pci.h | 3 ++- drivers/net/wireless/ath/ath12k/qmi.h | 1 - 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/fw.h b/drivers/net/wireless/ath/ath12k/fw.h index d91d95fc5740..28dc1423df70 100644 --- a/drivers/net/wireless/ath/ath12k/fw.h +++ b/drivers/net/wireless/ath/ath12k/fw.h @@ -17,6 +17,11 @@ enum ath12k_fw_ie_type { }; enum ath12k_fw_features { + /* The firmware supports setting the QRTR id via register + * PCIE_LOCAL_REG_QRTR_NODE_ID + */ + ATH12K_FW_FEATURE_MULTI_QRTR_ID = 0, + /* keep last */ ATH12K_FW_FEATURE_COUNT, }; diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 76438b3afd55..7a0ed7c9f5a2 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -39,6 +39,10 @@ #define QCN9274_DEVICE_ID 0x1109 #define WCN7850_DEVICE_ID 0x1107 +#define PCIE_LOCAL_REG_QRTR_NODE_ID 0x1E03164 +#define DOMAIN_NUMBER_MASK GENMASK(7, 4) +#define BUS_NUMBER_MASK GENMASK(3, 0) + static const struct pci_device_id ath12k_pci_id_table[] = { { PCI_VDEVICE(QCOM, QCN9274_DEVICE_ID) }, { PCI_VDEVICE(QCOM, WCN7850_DEVICE_ID) }, @@ -682,12 +686,22 @@ static void ath12k_pci_init_qmi_ce_config(struct ath12k_base *ab) { struct ath12k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); + struct pci_bus *bus = ab_pci->pdev->bus; + cfg->tgt_ce = ab->hw_params->target_ce_config; cfg->tgt_ce_len = ab->hw_params->target_ce_count; cfg->svc_to_ce_map = ab->hw_params->svc_to_ce_map; cfg->svc_to_ce_map_len = ab->hw_params->svc_to_ce_map_len; ab->qmi.service_ins_id = ab->hw_params->qmi_service_ins_id; + + if (test_bit(ATH12K_FW_FEATURE_MULTI_QRTR_ID, ab->fw.fw_features)) { + ab_pci->qmi_instance = + u32_encode_bits(pci_domain_nr(bus), DOMAIN_NUMBER_MASK) | + u32_encode_bits(bus->number, BUS_NUMBER_MASK); + ab->qmi.service_ins_id += ab_pci->qmi_instance; + } } static void ath12k_pci_ce_irqs_enable(struct ath12k_base *ab) @@ -901,6 +915,26 @@ static void ath12k_pci_aspm_disable(struct ath12k_pci *ab_pci) set_bit(ATH12K_PCI_ASPM_RESTORE, &ab_pci->flags); } +static void ath12k_pci_update_qrtr_node_id(struct ath12k_base *ab) +{ + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); + u32 reg; + + /* On platforms with two or more identical mhi devices, qmi service run + * with identical qrtr-node-id. Because of this identical ID qrtr-lookup + * cannot register more than one qmi service with identical node ID. + * + * This generates a unique instance ID from PCIe domain number and bus number, + * writes to the given register, it is available for firmware when the QMI service + * is spawned. + */ + reg = PCIE_LOCAL_REG_QRTR_NODE_ID & WINDOW_RANGE_MASK; + ath12k_pci_write32(ab, reg, ab_pci->qmi_instance); + + ath12k_dbg(ab, ATH12K_DBG_PCI, "pci reg 0x%x instance 0x%x read val 0x%x\n", + reg, ab_pci->qmi_instance, ath12k_pci_read32(ab, reg)); +} + static void ath12k_pci_aspm_restore(struct ath12k_pci *ab_pci) { if (test_and_clear_bit(ATH12K_PCI_ASPM_RESTORE, &ab_pci->flags)) @@ -1219,6 +1253,9 @@ int ath12k_pci_power_up(struct ath12k_base *ab) ath12k_pci_msi_enable(ab_pci); + if (test_bit(ATH12K_FW_FEATURE_MULTI_QRTR_ID, ab->fw.fw_features)) + ath12k_pci_update_qrtr_node_id(ab); + ret = ath12k_mhi_start(ab_pci); if (ret) { ath12k_err(ab, "failed to start mhi: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath12k/pci.h b/drivers/net/wireless/ath/ath12k/pci.h index b2edf32ada20..023616928f03 100644 --- a/drivers/net/wireless/ath/ath12k/pci.h +++ b/drivers/net/wireless/ath/ath12k/pci.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_PCI_H #define ATH12K_PCI_H @@ -111,6 +111,7 @@ struct ath12k_pci { u16 link_ctl; unsigned long irq_flags; const struct ath12k_pci_ops *pci_ops; + u32 qmi_instance; }; static inline struct ath12k_pci *ath12k_pci_priv(struct ath12k_base *ab) diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h index 828ab2bf037d..6ee33c9851c6 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.h +++ b/drivers/net/wireless/ath/ath12k/qmi.h @@ -15,7 +15,6 @@ #define ATH12K_QMI_MAX_BDF_FILE_NAME_SIZE 64 #define ATH12K_QMI_CALDB_ADDRESS 0x4BA00000 #define ATH12K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 128 -#define ATH12K_QMI_WLFW_NODE_ID_BASE 0x07 #define ATH12K_QMI_WLFW_SERVICE_ID_V01 0x45 #define ATH12K_QMI_WLFW_SERVICE_VERS_V01 0x01 #define ATH12K_QMI_WLFW_SERVICE_INS_ID_V01 0x02 -- cgit From 664a1c96b297965c443446e61ccb02ebc961ddc3 Mon Sep 17 00:00:00 2001 From: Aaradhana Sahu Date: Mon, 29 Jan 2024 12:27:17 +0530 Subject: wifi: ath12k: fix firmware assert during insmod in memory segment mode In segment memory mode, firmware allocates memory segments of size 2 MB. This 2 MB memory is used by firmware for the number of peers. This number of peer is sent from host to firmware during WMI init command. For single-phy the number of peers sent is TARGET_NUM_PEERS_SINGLE = 529 (512 + 17). While for split-phy number of peers sent to firmware is TARGET_NUM_PEERS_DBS = 2 *(512 + 17) = 1058. With this 1058 number of peers firmware is unable to allocate memory in 2 MB segment and firmware crash is observed. Hence, fix this firmware crash by reducing the number of stations TARGET_NUM_STATIONS for split-phy. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Aaradhana Sahu Co-developed-by: Raj Kumar Bhagat Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-7-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 27 +++++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/core.h | 3 +++ drivers/net/wireless/ath/ath12k/hw.h | 23 +++++++++++++++++------ drivers/net/wireless/ath/ath12k/mac.c | 4 ++-- drivers/net/wireless/ath/ath12k/wmi.c | 15 +++------------ 5 files changed, 52 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 634a9ddc2fe5..7f0b395f1296 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -510,6 +510,33 @@ exit: return ret; } +u32 ath12k_core_get_max_station_per_radio(struct ath12k_base *ab) +{ + if (ab->num_radios == 2) + return TARGET_NUM_STATIONS_DBS; + else if (ab->num_radios == 3) + return TARGET_NUM_PEERS_PDEV_DBS_SBS; + return TARGET_NUM_STATIONS_SINGLE; +} + +u32 ath12k_core_get_max_peers_per_radio(struct ath12k_base *ab) +{ + if (ab->num_radios == 2) + return TARGET_NUM_PEERS_PDEV_DBS; + else if (ab->num_radios == 3) + return TARGET_NUM_PEERS_PDEV_DBS_SBS; + return TARGET_NUM_PEERS_PDEV_SINGLE; +} + +u32 ath12k_core_get_max_num_tids(struct ath12k_base *ab) +{ + if (ab->num_radios == 2) + return TARGET_NUM_TIDS(DBS); + else if (ab->num_radios == 3) + return TARGET_NUM_TIDS(DBS_SBS); + return TARGET_NUM_TIDS(SINGLE); +} + static void ath12k_core_stop(struct ath12k_base *ab) { if (!test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags)) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index fc906d7acd42..68b4031ac484 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -869,6 +869,9 @@ int ath12k_core_suspend(struct ath12k_base *ab); const struct firmware *ath12k_core_firmware_request(struct ath12k_base *ab, const char *filename); +u32 ath12k_core_get_max_station_per_radio(struct ath12k_base *ab); +u32 ath12k_core_get_max_peers_per_radio(struct ath12k_base *ab); +u32 ath12k_core_get_max_num_tids(struct ath12k_base *ab); static inline const char *ath12k_scan_state_str(enum ath12k_scan_state state) { diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 44ba3a50e075..efa3411dc63d 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -17,19 +17,30 @@ /* Num VDEVS per radio */ #define TARGET_NUM_VDEVS (16 + 1) -#define TARGET_NUM_PEERS_PDEV (512 + TARGET_NUM_VDEVS) +#define TARGET_NUM_PEERS_PDEV_SINGLE (TARGET_NUM_STATIONS_SINGLE + \ + TARGET_NUM_VDEVS) +#define TARGET_NUM_PEERS_PDEV_DBS (TARGET_NUM_STATIONS_DBS + \ + TARGET_NUM_VDEVS) +#define TARGET_NUM_PEERS_PDEV_DBS_SBS (TARGET_NUM_STATIONS_DBS_SBS + \ + TARGET_NUM_VDEVS) /* Num of peers for Single Radio mode */ -#define TARGET_NUM_PEERS_SINGLE (TARGET_NUM_PEERS_PDEV) +#define TARGET_NUM_PEERS_SINGLE (TARGET_NUM_PEERS_PDEV_SINGLE) /* Num of peers for DBS */ -#define TARGET_NUM_PEERS_DBS (2 * TARGET_NUM_PEERS_PDEV) +#define TARGET_NUM_PEERS_DBS (2 * TARGET_NUM_PEERS_PDEV_DBS) /* Num of peers for DBS_SBS */ -#define TARGET_NUM_PEERS_DBS_SBS (3 * TARGET_NUM_PEERS_PDEV) +#define TARGET_NUM_PEERS_DBS_SBS (3 * TARGET_NUM_PEERS_PDEV_DBS_SBS) -/* Max num of stations (per radio) */ -#define TARGET_NUM_STATIONS 512 +/* Max num of stations for Single Radio mode */ +#define TARGET_NUM_STATIONS_SINGLE 512 + +/* Max num of stations for DBS */ +#define TARGET_NUM_STATIONS_DBS 128 + +/* Max num of stations for DBS_SBS */ +#define TARGET_NUM_STATIONS_DBS_SBS 128 #define TARGET_NUM_PEERS(x) TARGET_NUM_PEERS_##x #define TARGET_NUM_PEER_KEYS 2 diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 672c9d347097..046bb466a391 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7624,8 +7624,8 @@ static int ath12k_mac_setup_register(struct ath12k *ar, ath12k_mac_setup_ht_vht_cap(ar, cap, ht_cap); ath12k_mac_setup_sband_iftype_data(ar, cap); - ar->max_num_stations = TARGET_NUM_STATIONS; - ar->max_num_peers = TARGET_NUM_PEERS_PDEV; + ar->max_num_stations = ath12k_core_get_max_station_per_radio(ar->ab); + ar->max_num_peers = ath12k_core_get_max_peers_per_radio(ar->ab); return 0; } diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 276351d68efb..7fc269eb4a0c 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -179,18 +179,9 @@ void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, struct ath12k_wmi_resource_config_arg *config) { config->num_vdevs = ab->num_radios * TARGET_NUM_VDEVS; - - if (ab->num_radios == 2) { - config->num_peers = TARGET_NUM_PEERS(DBS); - config->num_tids = TARGET_NUM_TIDS(DBS); - } else if (ab->num_radios == 3) { - config->num_peers = TARGET_NUM_PEERS(DBS_SBS); - config->num_tids = TARGET_NUM_TIDS(DBS_SBS); - } else { - /* Control should not reach here */ - config->num_peers = TARGET_NUM_PEERS(SINGLE); - config->num_tids = TARGET_NUM_TIDS(SINGLE); - } + config->num_peers = ab->num_radios * + ath12k_core_get_max_peers_per_radio(ab); + config->num_tids = ath12k_core_get_max_num_tids(ab); config->num_offload_peers = TARGET_NUM_OFFLD_PEERS; config->num_offload_reorder_buffs = TARGET_NUM_OFFLD_REORDER_BUFFS; config->num_peer_keys = TARGET_NUM_PEER_KEYS; -- cgit From f7019c2fcdf68a0df3a30735c91bb4fb8e2b810d Mon Sep 17 00:00:00 2001 From: Raj Kumar Bhagat Date: Mon, 29 Jan 2024 12:27:18 +0530 Subject: wifi: ath12k: split hal_ops to support RX TLVs word mask compaction With word mask subscription support, the rx_desc structure will change. The fields in this structure rx_desc will be reduced to only the required fields. To make word mask subscription changes compatible with the older firmware version (firmware that does not support word mask subscription), two different structures of rx_desc will be required for the same hardware. Most of the hal_ops are directly related to rx_desc. Hence, split hal_ops into operations that are independent of rx_desc (hal_ops) and the operations that are directly dependent on rx_desc (hal_rx_ops). These hal_rx_ops depend on both hardware and firmware hence move them out of hw_params. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-8-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/core.h | 2 + drivers/net/wireless/ath/ath12k/dp_mon.c | 3 +- drivers/net/wireless/ath/ath12k/dp_rx.c | 72 ++++++++++++++++---------------- drivers/net/wireless/ath/ath12k/hal.c | 18 +++++--- drivers/net/wireless/ath/ath12k/hal.h | 12 ++++-- drivers/net/wireless/ath/ath12k/pci.c | 2 + 6 files changed, 63 insertions(+), 46 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 68b4031ac484..67bf8d840b00 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -838,6 +838,8 @@ struct ath12k_base { DECLARE_BITMAP(fw_features, ATH12K_FW_FEATURE_COUNT); } fw; + const struct hal_rx_ops *hal_rx_ops; + /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index 2432ab605c85..7aa55cf64e8b 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -917,7 +917,8 @@ ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar, u8 qos_pkt = 0; rx_desc = (struct hal_rx_desc *)head_msdu->data; - hdr_desc = ab->hw_params->hal_ops->rx_desc_get_msdu_payload(rx_desc); + hdr_desc = + ab->hal_rx_ops->rx_desc_get_msdu_payload(rx_desc); /* Base size */ wh = (struct ieee80211_hdr_3addr *)hdr_desc; diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index a31c24b54851..d8816b38ccaa 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -23,34 +23,34 @@ static enum hal_encrypt_type ath12k_dp_rx_h_enctype(struct ath12k_base *ab, struct hal_rx_desc *desc) { - if (!ab->hw_params->hal_ops->rx_desc_encrypt_valid(desc)) + if (!ab->hal_rx_ops->rx_desc_encrypt_valid(desc)) return HAL_ENCRYPT_TYPE_OPEN; - return ab->hw_params->hal_ops->rx_desc_get_encrypt_type(desc); + return ab->hal_rx_ops->rx_desc_get_encrypt_type(desc); } u8 ath12k_dp_rx_h_decap_type(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_decap_type(desc); + return ab->hal_rx_ops->rx_desc_get_decap_type(desc); } static u8 ath12k_dp_rx_h_mesh_ctl_present(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_mesh_ctl(desc); + return ab->hal_rx_ops->rx_desc_get_mesh_ctl(desc); } static bool ath12k_dp_rx_h_seq_ctrl_valid(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_mpdu_seq_ctl_vld(desc); + return ab->hal_rx_ops->rx_desc_get_mpdu_seq_ctl_vld(desc); } static bool ath12k_dp_rx_h_fc_valid(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_mpdu_fc_valid(desc); + return ab->hal_rx_ops->rx_desc_get_mpdu_fc_valid(desc); } static bool ath12k_dp_rx_h_more_frags(struct ath12k_base *ab, @@ -74,149 +74,149 @@ static u16 ath12k_dp_rx_h_frag_no(struct ath12k_base *ab, static u16 ath12k_dp_rx_h_seq_no(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_mpdu_start_seq_no(desc); + return ab->hal_rx_ops->rx_desc_get_mpdu_start_seq_no(desc); } static bool ath12k_dp_rx_h_msdu_done(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->dp_rx_h_msdu_done(desc); + return ab->hal_rx_ops->dp_rx_h_msdu_done(desc); } static bool ath12k_dp_rx_h_l4_cksum_fail(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->dp_rx_h_l4_cksum_fail(desc); + return ab->hal_rx_ops->dp_rx_h_l4_cksum_fail(desc); } static bool ath12k_dp_rx_h_ip_cksum_fail(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->dp_rx_h_ip_cksum_fail(desc); + return ab->hal_rx_ops->dp_rx_h_ip_cksum_fail(desc); } static bool ath12k_dp_rx_h_is_decrypted(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->dp_rx_h_is_decrypted(desc); + return ab->hal_rx_ops->dp_rx_h_is_decrypted(desc); } u32 ath12k_dp_rx_h_mpdu_err(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->dp_rx_h_mpdu_err(desc); + return ab->hal_rx_ops->dp_rx_h_mpdu_err(desc); } static u16 ath12k_dp_rx_h_msdu_len(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_msdu_len(desc); + return ab->hal_rx_ops->rx_desc_get_msdu_len(desc); } static u8 ath12k_dp_rx_h_sgi(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_msdu_sgi(desc); + return ab->hal_rx_ops->rx_desc_get_msdu_sgi(desc); } static u8 ath12k_dp_rx_h_rate_mcs(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_msdu_rate_mcs(desc); + return ab->hal_rx_ops->rx_desc_get_msdu_rate_mcs(desc); } static u8 ath12k_dp_rx_h_rx_bw(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_msdu_rx_bw(desc); + return ab->hal_rx_ops->rx_desc_get_msdu_rx_bw(desc); } static u32 ath12k_dp_rx_h_freq(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_msdu_freq(desc); + return ab->hal_rx_ops->rx_desc_get_msdu_freq(desc); } static u8 ath12k_dp_rx_h_pkt_type(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_msdu_pkt_type(desc); + return ab->hal_rx_ops->rx_desc_get_msdu_pkt_type(desc); } static u8 ath12k_dp_rx_h_nss(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return hweight8(ab->hw_params->hal_ops->rx_desc_get_msdu_nss(desc)); + return hweight8(ab->hal_rx_ops->rx_desc_get_msdu_nss(desc)); } static u8 ath12k_dp_rx_h_tid(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_mpdu_tid(desc); + return ab->hal_rx_ops->rx_desc_get_mpdu_tid(desc); } static u16 ath12k_dp_rx_h_peer_id(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_mpdu_peer_id(desc); + return ab->hal_rx_ops->rx_desc_get_mpdu_peer_id(desc); } u8 ath12k_dp_rx_h_l3pad(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_l3_pad_bytes(desc); + return ab->hal_rx_ops->rx_desc_get_l3_pad_bytes(desc); } static bool ath12k_dp_rx_h_first_msdu(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_first_msdu(desc); + return ab->hal_rx_ops->rx_desc_get_first_msdu(desc); } static bool ath12k_dp_rx_h_last_msdu(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_last_msdu(desc); + return ab->hal_rx_ops->rx_desc_get_last_msdu(desc); } static void ath12k_dp_rx_desc_end_tlv_copy(struct ath12k_base *ab, struct hal_rx_desc *fdesc, struct hal_rx_desc *ldesc) { - ab->hw_params->hal_ops->rx_desc_copy_end_tlv(fdesc, ldesc); + ab->hal_rx_ops->rx_desc_copy_end_tlv(fdesc, ldesc); } static void ath12k_dp_rxdesc_set_msdu_len(struct ath12k_base *ab, struct hal_rx_desc *desc, u16 len) { - ab->hw_params->hal_ops->rx_desc_set_msdu_len(desc, len); + ab->hal_rx_ops->rx_desc_set_msdu_len(desc, len); } static bool ath12k_dp_rx_h_is_da_mcbc(struct ath12k_base *ab, struct hal_rx_desc *desc) { return (ath12k_dp_rx_h_first_msdu(ab, desc) && - ab->hw_params->hal_ops->rx_desc_is_da_mcbc(desc)); + ab->hal_rx_ops->rx_desc_is_da_mcbc(desc)); } static bool ath12k_dp_rxdesc_mac_addr2_valid(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_mac_addr2_valid(desc); + return ab->hal_rx_ops->rx_desc_mac_addr2_valid(desc); } static u8 *ath12k_dp_rxdesc_get_mpdu_start_addr2(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_mpdu_start_addr2(desc); + return ab->hal_rx_ops->rx_desc_mpdu_start_addr2(desc); } static void ath12k_dp_rx_desc_get_dot11_hdr(struct ath12k_base *ab, struct hal_rx_desc *desc, struct ieee80211_hdr *hdr) { - ab->hw_params->hal_ops->rx_desc_get_dot11_hdr(desc, hdr); + ab->hal_rx_ops->rx_desc_get_dot11_hdr(desc, hdr); } static void ath12k_dp_rx_desc_get_crypto_header(struct ath12k_base *ab, @@ -224,13 +224,13 @@ static void ath12k_dp_rx_desc_get_crypto_header(struct ath12k_base *ab, u8 *crypto_hdr, enum hal_encrypt_type enctype) { - ab->hw_params->hal_ops->rx_desc_get_crypto_header(desc, crypto_hdr, enctype); + ab->hal_rx_ops->rx_desc_get_crypto_header(desc, crypto_hdr, enctype); } static u16 ath12k_dp_rxdesc_get_mpdu_frame_ctrl(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_mpdu_frame_ctl(desc); + return ab->hal_rx_ops->rx_desc_get_mpdu_frame_ctl(desc); } static int ath12k_dp_purge_mon_ring(struct ath12k_base *ab) @@ -3935,9 +3935,9 @@ int ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab) tlv_filter.rx_packet_offset = hal_rx_desc_sz; tlv_filter.rx_mpdu_start_offset = - ab->hw_params->hal_ops->rx_desc_get_mpdu_start_offset(); + ab->hal_rx_ops->rx_desc_get_mpdu_start_offset(); tlv_filter.rx_msdu_end_offset = - ab->hw_params->hal_ops->rx_desc_get_msdu_end_offset(); + ab->hal_rx_ops->rx_desc_get_msdu_end_offset(); /* TODO: Selectively subscribe to required qwords within msdu_end * and mpdu_start and setup the mask in below msg @@ -3973,9 +3973,9 @@ int ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab) tlv_filter.rx_header_offset = offsetof(struct hal_rx_desc_wcn7850, pkt_hdr_tlv); tlv_filter.rx_mpdu_start_offset = - ab->hw_params->hal_ops->rx_desc_get_mpdu_start_offset(); + ab->hal_rx_ops->rx_desc_get_mpdu_start_offset(); tlv_filter.rx_msdu_end_offset = - ab->hw_params->hal_ops->rx_desc_get_msdu_end_offset(); + ab->hal_rx_ops->rx_desc_get_msdu_end_offset(); /* TODO: Selectively subscribe to required qwords within msdu_end * and mpdu_start and setup the mask in below msg diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index 1bdab8604db9..b6b8298a2bdc 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -680,7 +680,7 @@ static u32 ath12k_hw_qcn9274_dp_rx_h_mpdu_err(struct hal_rx_desc *desc) return errmap; } -const struct hal_ops hal_qcn9274_ops = { +const struct hal_rx_ops hal_rx_qcn9274_ops = { .rx_desc_get_first_msdu = ath12k_hw_qcn9274_rx_desc_get_first_msdu, .rx_desc_get_last_msdu = ath12k_hw_qcn9274_rx_desc_get_last_msdu, .rx_desc_get_l3_pad_bytes = ath12k_hw_qcn9274_rx_desc_get_l3_pad_bytes, @@ -712,8 +712,6 @@ const struct hal_ops hal_qcn9274_ops = { .rx_desc_get_dot11_hdr = ath12k_hw_qcn9274_rx_desc_get_dot11_hdr, .rx_desc_get_crypto_header = ath12k_hw_qcn9274_rx_desc_get_crypto_hdr, .rx_desc_get_mpdu_frame_ctl = ath12k_hw_qcn9274_rx_desc_get_mpdu_frame_ctl, - .create_srng_config = ath12k_hal_srng_create_config_qcn9274, - .tcl_to_wbm_rbm_map = ath12k_hal_qcn9274_tcl_to_wbm_rbm_map, .dp_rx_h_msdu_done = ath12k_hw_qcn9274_dp_rx_h_msdu_done, .dp_rx_h_l4_cksum_fail = ath12k_hw_qcn9274_dp_rx_h_l4_cksum_fail, .dp_rx_h_ip_cksum_fail = ath12k_hw_qcn9274_dp_rx_h_ip_cksum_fail, @@ -721,6 +719,11 @@ const struct hal_ops hal_qcn9274_ops = { .dp_rx_h_mpdu_err = ath12k_hw_qcn9274_dp_rx_h_mpdu_err, }; +const struct hal_ops hal_qcn9274_ops = { + .create_srng_config = ath12k_hal_srng_create_config_qcn9274, + .tcl_to_wbm_rbm_map = ath12k_hal_qcn9274_tcl_to_wbm_rbm_map, +}; + static bool ath12k_hw_wcn7850_rx_desc_get_first_msdu(struct hal_rx_desc *desc) { return !!le16_get_bits(desc->u.wcn7850.msdu_end.info5, @@ -1134,7 +1137,7 @@ static u32 ath12k_hw_wcn7850_dp_rx_h_mpdu_err(struct hal_rx_desc *desc) return errmap; } -const struct hal_ops hal_wcn7850_ops = { +const struct hal_rx_ops hal_rx_wcn7850_ops = { .rx_desc_get_first_msdu = ath12k_hw_wcn7850_rx_desc_get_first_msdu, .rx_desc_get_last_msdu = ath12k_hw_wcn7850_rx_desc_get_last_msdu, .rx_desc_get_l3_pad_bytes = ath12k_hw_wcn7850_rx_desc_get_l3_pad_bytes, @@ -1167,8 +1170,6 @@ const struct hal_ops hal_wcn7850_ops = { .rx_desc_get_dot11_hdr = ath12k_hw_wcn7850_rx_desc_get_dot11_hdr, .rx_desc_get_crypto_header = ath12k_hw_wcn7850_rx_desc_get_crypto_hdr, .rx_desc_get_mpdu_frame_ctl = ath12k_hw_wcn7850_rx_desc_get_mpdu_frame_ctl, - .create_srng_config = ath12k_hal_srng_create_config_wcn7850, - .tcl_to_wbm_rbm_map = ath12k_hal_wcn7850_tcl_to_wbm_rbm_map, .dp_rx_h_msdu_done = ath12k_hw_wcn7850_dp_rx_h_msdu_done, .dp_rx_h_l4_cksum_fail = ath12k_hw_wcn7850_dp_rx_h_l4_cksum_fail, .dp_rx_h_ip_cksum_fail = ath12k_hw_wcn7850_dp_rx_h_ip_cksum_fail, @@ -1176,6 +1177,11 @@ const struct hal_ops hal_wcn7850_ops = { .dp_rx_h_mpdu_err = ath12k_hw_wcn7850_dp_rx_h_mpdu_err, }; +const struct hal_ops hal_wcn7850_ops = { + .create_srng_config = ath12k_hal_srng_create_config_wcn7850, + .tcl_to_wbm_rbm_map = ath12k_hal_wcn7850_tcl_to_wbm_rbm_map, +}; + static int ath12k_hal_alloc_cont_rdp(struct ath12k_base *ab) { struct ath12k_hal *hal = &ab->hal; diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index fc47e7e6b498..33dedfbb3964 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_HAL_H @@ -1031,7 +1031,7 @@ struct ath12k_hal_tcl_to_wbm_rbm_map { u8 rbm_id; }; -struct hal_ops { +struct hal_rx_ops { bool (*rx_desc_get_first_msdu)(struct hal_rx_desc *desc); bool (*rx_desc_get_last_msdu)(struct hal_rx_desc *desc); u8 (*rx_desc_get_l3_pad_bytes)(struct hal_rx_desc *desc); @@ -1070,18 +1070,24 @@ struct hal_ops { void (*rx_desc_get_crypto_header)(struct hal_rx_desc *desc, u8 *crypto_hdr, enum hal_encrypt_type enctype); - int (*create_srng_config)(struct ath12k_base *ab); bool (*dp_rx_h_msdu_done)(struct hal_rx_desc *desc); bool (*dp_rx_h_l4_cksum_fail)(struct hal_rx_desc *desc); bool (*dp_rx_h_ip_cksum_fail)(struct hal_rx_desc *desc); bool (*dp_rx_h_is_decrypted)(struct hal_rx_desc *desc); u32 (*dp_rx_h_mpdu_err)(struct hal_rx_desc *desc); +}; + +struct hal_ops { + int (*create_srng_config)(struct ath12k_base *ab); const struct ath12k_hal_tcl_to_wbm_rbm_map *tcl_to_wbm_rbm_map; }; extern const struct hal_ops hal_qcn9274_ops; extern const struct hal_ops hal_wcn7850_ops; +extern const struct hal_rx_ops hal_rx_qcn9274_ops; +extern const struct hal_rx_ops hal_rx_wcn7850_ops; + u32 ath12k_hal_reo_qdesc_size(u32 ba_window_size, u8 tid); void ath12k_hal_reo_qdesc_setup(struct hal_rx_reo_queue *qdesc, int tid, u32 ba_window_size, diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 7a0ed7c9f5a2..d334f41f9658 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -1361,6 +1361,7 @@ static int ath12k_pci_probe(struct pci_dev *pdev, ab_pci->msi_config = &ath12k_msi_config[0]; ab->static_window_map = true; ab_pci->pci_ops = &ath12k_pci_ops_qcn9274; + ab->hal_rx_ops = &hal_rx_qcn9274_ops; ath12k_pci_read_hw_version(ab, &soc_hw_version_major, &soc_hw_version_minor); switch (soc_hw_version_major) { @@ -1383,6 +1384,7 @@ static int ath12k_pci_probe(struct pci_dev *pdev, ab_pci->msi_config = &ath12k_msi_config[0]; ab->static_window_map = false; ab_pci->pci_ops = &ath12k_pci_ops_wcn7850; + ab->hal_rx_ops = &hal_rx_wcn7850_ops; ath12k_pci_read_hw_version(ab, &soc_hw_version_major, &soc_hw_version_minor); switch (soc_hw_version_major) { -- cgit From 3cf1a9f7a1b2823af5a57e277bbb7c730c8d737b Mon Sep 17 00:00:00 2001 From: Raj Kumar Bhagat Date: Mon, 29 Jan 2024 12:27:19 +0530 Subject: wifi: ath12k: remove hal_desc_sz from hw params With word mask subscription support, the rx_desc structure will change. The fields in this structure rx_desc will be reduced to only the required fields. To make word mask subscription changes compatible with the older firmware version (firmware that does not support word mask subscription), two different structures of rx_desc will be required for the same hardware. The hardware param hal_desc_sz value cannot be constant for the same hardware. It depends on the size of rx_desc structure which may change based on firmware capability to support word mask subscription. Hence, remove hal_desc_sz from hardware param and add hal_rx_ops to get the size of rx_desc in run time. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-9-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 2 ++ drivers/net/wireless/ath/ath12k/dp.c | 8 +++++++- drivers/net/wireless/ath/ath12k/dp.h | 3 ++- drivers/net/wireless/ath/ath12k/dp_mon.c | 2 +- drivers/net/wireless/ath/ath12k/dp_rx.c | 30 +++++++++++++++--------------- drivers/net/wireless/ath/ath12k/hal.c | 12 ++++++++++++ drivers/net/wireless/ath/ath12k/hal.h | 3 +++ drivers/net/wireless/ath/ath12k/hw.c | 5 +---- drivers/net/wireless/ath/ath12k/hw.h | 1 - 9 files changed, 43 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 7f0b395f1296..ca3777c684b3 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -748,6 +748,8 @@ static int ath12k_core_start(struct ath12k_base *ab, goto err_mac_destroy; } + ath12k_dp_hal_rx_desc_init(ab); + ret = ath12k_wmi_cmd_init(ab); if (ret) { ath12k_err(ab, "failed to send wmi init cmd: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index a6f81f2f97ef..af800d60f3a2 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -997,6 +997,12 @@ void ath12k_dp_pdev_pre_alloc(struct ath12k_base *ab) } } +void ath12k_dp_hal_rx_desc_init(struct ath12k_base *ab) +{ + ab->hal.hal_desc_sz = + ab->hal_rx_ops->rx_desc_get_desc_size(); +} + static void ath12k_dp_service_mon_ring(struct timer_list *t) { struct ath12k_base *ab = from_timer(ab, t, mon_reap_timer); diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index 0a10cd362356..226b95bd5ab0 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_DP_H @@ -1821,4 +1821,5 @@ struct ath12k_rx_desc_info *ath12k_dp_get_rx_desc(struct ath12k_base *ab, u32 cookie); struct ath12k_tx_desc_info *ath12k_dp_get_tx_desc(struct ath12k_base *ab, u32 desc_id); +void ath12k_dp_hal_rx_desc_init(struct ath12k_base *ab); #endif diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index 7aa55cf64e8b..2d56913a75d0 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -864,7 +864,7 @@ static void ath12k_dp_mon_rx_msdus_set_payload(struct ath12k *ar, struct sk_buff { u32 rx_pkt_offset, l2_hdr_offset; - rx_pkt_offset = ar->ab->hw_params->hal_desc_sz; + rx_pkt_offset = ar->ab->hal.hal_desc_sz; l2_hdr_offset = ath12k_dp_rx_h_l3pad(ar->ab, (struct hal_rx_desc *)msdu->data); skb_pull(msdu, rx_pkt_offset + l2_hdr_offset); diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index d8816b38ccaa..10ea33fafff4 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -58,7 +58,7 @@ static bool ath12k_dp_rx_h_more_frags(struct ath12k_base *ab, { struct ieee80211_hdr *hdr; - hdr = (struct ieee80211_hdr *)(skb->data + ab->hw_params->hal_desc_sz); + hdr = (struct ieee80211_hdr *)(skb->data + ab->hal.hal_desc_sz); return ieee80211_has_morefrags(hdr->frame_control); } @@ -67,7 +67,7 @@ static u16 ath12k_dp_rx_h_frag_no(struct ath12k_base *ab, { struct ieee80211_hdr *hdr; - hdr = (struct ieee80211_hdr *)(skb->data + ab->hw_params->hal_desc_sz); + hdr = (struct ieee80211_hdr *)(skb->data + ab->hal.hal_desc_sz); return le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; } @@ -1761,7 +1761,7 @@ static int ath12k_dp_rx_msdu_coalesce(struct ath12k *ar, int buf_first_hdr_len, buf_first_len; struct hal_rx_desc *ldesc; int space_extra, rem_len, buf_len; - u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; /* As the msdu is spread across multiple rx buffers, * find the offset to the start of msdu for computing @@ -2473,7 +2473,7 @@ static int ath12k_dp_rx_process_msdu(struct ath12k *ar, u8 l3_pad_bytes; u16 msdu_len; int ret; - u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; last_buf = ath12k_dp_rx_get_msdu_last_buf(msdu_list, msdu); if (!last_buf) { @@ -2804,7 +2804,7 @@ static int ath12k_dp_rx_h_verify_tkip_mic(struct ath12k *ar, struct ath12k_peer u8 mic[IEEE80211_CCMP_MIC_LEN]; int head_len, tail_len, ret; size_t data_len; - u32 hdr_len, hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 hdr_len, hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; u8 *key, *data; u8 key_idx; @@ -2854,7 +2854,7 @@ static void ath12k_dp_rx_h_undecap_frag(struct ath12k *ar, struct sk_buff *msdu, struct ieee80211_hdr *hdr; size_t hdr_len; size_t crypto_len; - u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; if (!flags) return; @@ -2892,7 +2892,7 @@ static int ath12k_dp_rx_h_defrag(struct ath12k *ar, bool is_decrypted = false; int msdu_len = 0; int extra_space; - u32 flags, hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 flags, hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; first_frag = skb_peek(&rx_tid->rx_frags); last_frag = skb_peek_tail(&rx_tid->rx_frags); @@ -2968,7 +2968,7 @@ static int ath12k_dp_rx_h_defrag_reo_reinject(struct ath12k *ar, struct ath12k_rx_desc_info *desc_info; u8 dst_ind; - hal_rx_desc_sz = ab->hw_params->hal_desc_sz; + hal_rx_desc_sz = ab->hal.hal_desc_sz; link_desc_banks = dp->link_desc_banks; reo_dest_ring = rx_tid->dst_ring_desc; @@ -3122,7 +3122,7 @@ static u64 ath12k_dp_rx_h_get_pn(struct ath12k *ar, struct sk_buff *skb) struct ieee80211_hdr *hdr; u64 pn = 0; u8 *ehdr; - u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; hdr = (struct ieee80211_hdr *)(skb->data + hal_rx_desc_sz); ehdr = skb->data + hal_rx_desc_sz + ieee80211_hdrlen(hdr->frame_control); @@ -3305,7 +3305,7 @@ ath12k_dp_process_rx_err_buf(struct ath12k *ar, struct hal_reo_dest_ring *desc, struct ath12k_skb_rxcb *rxcb; struct hal_rx_desc *rx_desc; u16 msdu_len; - u32 hal_rx_desc_sz = ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ab->hal.hal_desc_sz; struct ath12k_rx_desc_info *desc_info; u64 desc_va; @@ -3486,7 +3486,7 @@ static void ath12k_dp_rx_null_q_desc_sg_drop(struct ath12k *ar, int n_buffs; n_buffs = DIV_ROUND_UP(msdu_len, - (DP_RX_BUFFER_SIZE - ar->ab->hw_params->hal_desc_sz)); + (DP_RX_BUFFER_SIZE - ar->ab->hal.hal_desc_sz)); skb_queue_walk_safe(msdu_list, skb, tmp) { rxcb = ATH12K_SKB_RXCB(skb); @@ -3510,7 +3510,7 @@ static int ath12k_dp_rx_h_null_q_desc(struct ath12k *ar, struct sk_buff *msdu, struct hal_rx_desc *desc = (struct hal_rx_desc *)msdu->data; u8 l3pad_bytes; struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); - u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; msdu_len = ath12k_dp_rx_h_msdu_len(ab, desc); @@ -3607,7 +3607,7 @@ static void ath12k_dp_rx_h_tkip_mic_err(struct ath12k *ar, struct sk_buff *msdu, struct hal_rx_desc *desc = (struct hal_rx_desc *)msdu->data; u8 l3pad_bytes; struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); - u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; rxcb->is_first_msdu = ath12k_dp_rx_h_first_msdu(ab, desc); rxcb->is_last_msdu = ath12k_dp_rx_h_last_msdu(ab, desc); @@ -3922,7 +3922,7 @@ int ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab) struct htt_rx_ring_tlv_filter tlv_filter = {0}; u32 ring_id; int ret; - u32 hal_rx_desc_sz = ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ab->hal.hal_desc_sz; ring_id = dp->rx_refill_buf_ring.refill_buf_ring.ring_id; @@ -3957,7 +3957,7 @@ int ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab) struct htt_rx_ring_tlv_filter tlv_filter = {0}; u32 ring_id; int ret; - u32 hal_rx_desc_sz = ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ab->hal.hal_desc_sz; int i; ring_id = dp->rx_refill_buf_ring.refill_buf_ring.ring_id; diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index b6b8298a2bdc..fa1bfb5256d0 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -680,6 +680,11 @@ static u32 ath12k_hw_qcn9274_dp_rx_h_mpdu_err(struct hal_rx_desc *desc) return errmap; } +static u32 ath12k_hw_qcn9274_get_rx_desc_size(void) +{ + return sizeof(struct hal_rx_desc_qcn9274); +} + const struct hal_rx_ops hal_rx_qcn9274_ops = { .rx_desc_get_first_msdu = ath12k_hw_qcn9274_rx_desc_get_first_msdu, .rx_desc_get_last_msdu = ath12k_hw_qcn9274_rx_desc_get_last_msdu, @@ -717,6 +722,7 @@ const struct hal_rx_ops hal_rx_qcn9274_ops = { .dp_rx_h_ip_cksum_fail = ath12k_hw_qcn9274_dp_rx_h_ip_cksum_fail, .dp_rx_h_is_decrypted = ath12k_hw_qcn9274_dp_rx_h_is_decrypted, .dp_rx_h_mpdu_err = ath12k_hw_qcn9274_dp_rx_h_mpdu_err, + .rx_desc_get_desc_size = ath12k_hw_qcn9274_get_rx_desc_size, }; const struct hal_ops hal_qcn9274_ops = { @@ -1137,6 +1143,11 @@ static u32 ath12k_hw_wcn7850_dp_rx_h_mpdu_err(struct hal_rx_desc *desc) return errmap; } +static u32 ath12k_hw_wcn7850_get_rx_desc_size(void) +{ + return sizeof(struct hal_rx_desc_wcn7850); +} + const struct hal_rx_ops hal_rx_wcn7850_ops = { .rx_desc_get_first_msdu = ath12k_hw_wcn7850_rx_desc_get_first_msdu, .rx_desc_get_last_msdu = ath12k_hw_wcn7850_rx_desc_get_last_msdu, @@ -1175,6 +1186,7 @@ const struct hal_rx_ops hal_rx_wcn7850_ops = { .dp_rx_h_ip_cksum_fail = ath12k_hw_wcn7850_dp_rx_h_ip_cksum_fail, .dp_rx_h_is_decrypted = ath12k_hw_wcn7850_dp_rx_h_is_decrypted, .dp_rx_h_mpdu_err = ath12k_hw_wcn7850_dp_rx_h_mpdu_err, + .rx_desc_get_desc_size = ath12k_hw_wcn7850_get_rx_desc_size, }; const struct hal_ops hal_wcn7850_ops = { diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index 33dedfbb3964..82517991510b 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -1023,6 +1023,8 @@ struct ath12k_hal { /* shadow register configuration */ u32 shadow_reg_addr[HAL_SHADOW_NUM_REGS]; int num_shadow_reg_configured; + + u32 hal_desc_sz; }; /* Maps WBM ring number and Return Buffer Manager Id per TCL ring */ @@ -1075,6 +1077,7 @@ struct hal_rx_ops { bool (*dp_rx_h_ip_cksum_fail)(struct hal_rx_desc *desc); bool (*dp_rx_h_is_decrypted)(struct hal_rx_desc *desc); u32 (*dp_rx_h_mpdu_err)(struct hal_rx_desc *desc); + u32 (*rx_desc_get_desc_size)(void); }; struct hal_ops { diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index cbb6e2b6d826..f399511746a8 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -897,7 +897,6 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .reoq_lut_support = false, .supports_shadow_regs = false, - .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9274), .num_tcl_banks = 48, .max_tx_ring = 4, @@ -963,7 +962,6 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .reoq_lut_support = false, .supports_shadow_regs = true, - .hal_desc_sz = sizeof(struct hal_rx_desc_wcn7850), .num_tcl_banks = 7, .max_tx_ring = 3, @@ -1029,7 +1027,6 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .reoq_lut_support = false, .supports_shadow_regs = false, - .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9274), .num_tcl_banks = 48, .max_tx_ring = 4, diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index efa3411dc63d..987188f56b29 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -187,7 +187,6 @@ struct ath12k_hw_params { bool reoq_lut_support:1; bool supports_shadow_regs:1; - u32 hal_desc_sz; u32 num_tcl_banks; u32 max_tx_ring; -- cgit From 419927ec8438e336f9dea183de9153da4e65dafc Mon Sep 17 00:00:00 2001 From: Karthikeyan Kathirvel Date: Mon, 29 Jan 2024 12:27:20 +0530 Subject: wifi: ath12k: subscribe required word mask from rx tlv Most of the RX descriptors fields are currently not used in the ath12k driver. Hence add support to selectively subscribe to the required quad words (64 bits) within msdu_end and mpdu_start of rx_desc. Add compact rx_desc structures and configure the bit mask for Rx TLVs (msdu_end, mpdu_start, mpdu_end) via registers. With these registers SW can configure to DMA the partial TLV struct to Rx buffer. Each TLV type has its own register to configure the mask value. The mask value configured in register will indicate if a particular QWORD has to be written to rx buffer or not i.e., if Nth bit is enabled in the mask Nth QWORD will be written and it will not be written if the bit is disabled in mask. While 0th bit indicates whether TLV tag will be written or not. Advantages of Qword subscription of TLVs - Avoid multiple cache-line misses as the all the required fields of the TLV are within 128 bytes. - Memory optimization as TLVs + DATA + SHINFO can fit in 2k buffer even for 64 bit kernel. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Kathirvel Co-developed-by: Raj Kumar Bhagat Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-10-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/dp.c | 17 ++ drivers/net/wireless/ath/ath12k/dp.h | 14 ++ drivers/net/wireless/ath/ath12k/dp_rx.c | 14 +- drivers/net/wireless/ath/ath12k/dp_tx.c | 20 ++ drivers/net/wireless/ath/ath12k/hal.c | 359 ++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/hal.h | 4 + drivers/net/wireless/ath/ath12k/rx_desc.h | 114 +++++++++- drivers/net/wireless/ath/ath12k/wmi.h | 2 + 8 files changed, 535 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index af800d60f3a2..c8e1b244b69e 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -997,8 +997,25 @@ void ath12k_dp_pdev_pre_alloc(struct ath12k_base *ab) } } +bool ath12k_dp_wmask_compaction_rx_tlv_supported(struct ath12k_base *ab) +{ + if (test_bit(WMI_TLV_SERVICE_WMSK_COMPACTION_RX_TLVS, ab->wmi_ab.svc_map) && + ab->hw_params->hal_ops->rxdma_ring_wmask_rx_mpdu_start && + ab->hw_params->hal_ops->rxdma_ring_wmask_rx_msdu_end && + ab->hw_params->hal_ops->get_hal_rx_compact_ops) { + return true; + } + return false; +} + void ath12k_dp_hal_rx_desc_init(struct ath12k_base *ab) { + if (ath12k_dp_wmask_compaction_rx_tlv_supported(ab)) { + /* RX TLVS compaction is supported, hence change the hal_rx_ops + * to compact hal_rx_ops. + */ + ab->hal_rx_ops = ab->hw_params->hal_ops->get_hal_rx_compact_ops(); + } ab->hal.hal_desc_sz = ab->hal_rx_ops->rx_desc_get_desc_size(); } diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index 226b95bd5ab0..eb2dd408e081 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -766,6 +766,11 @@ enum htt_stats_internal_ppdu_frametype { #define HTT_RX_RING_SELECTION_CFG_RX_MSDU_START_OFFSET GENMASK(31, 16) #define HTT_RX_RING_SELECTION_CFG_RX_ATTENTION_OFFSET GENMASK(15, 0) +#define HTT_RX_RING_SELECTION_CFG_WORD_MASK_COMPACT_SET BIT(23) +#define HTT_RX_RING_SELECTION_CFG_RX_MPDU_START_MASK GENMASK(15, 0) +#define HTT_RX_RING_SELECTION_CFG_RX_MPDU_END_MASK GENMASK(18, 16) +#define HTT_RX_RING_SELECTION_CFG_RX_MSDU_END_MASK GENMASK(16, 0) + enum htt_rx_filter_tlv_flags { HTT_RX_FILTER_TLV_FLAGS_MPDU_START = BIT(0), HTT_RX_FILTER_TLV_FLAGS_MSDU_START = BIT(1), @@ -1089,6 +1094,11 @@ struct htt_rx_ring_selection_cfg_cmd { __le32 rx_mpdu_offset; __le32 rx_msdu_offset; __le32 rx_attn_offset; + __le32 info2; + __le32 reserved[2]; + __le32 rx_mpdu_start_end_mask; + __le32 rx_msdu_end_word_mask; + __le32 info3; } __packed; struct htt_rx_ring_tlv_filter { @@ -1105,6 +1115,9 @@ struct htt_rx_ring_tlv_filter { u16 rx_msdu_end_offset; u16 rx_msdu_start_offset; u16 rx_attn_offset; + u16 rx_mpdu_start_wmask; + u16 rx_mpdu_end_wmask; + u32 rx_msdu_end_wmask; }; #define HTT_STATS_FRAME_CTRL_TYPE_MGMT 0x0 @@ -1821,5 +1834,6 @@ struct ath12k_rx_desc_info *ath12k_dp_get_rx_desc(struct ath12k_base *ab, u32 cookie); struct ath12k_tx_desc_info *ath12k_dp_get_tx_desc(struct ath12k_base *ab, u32 desc_id); +bool ath12k_dp_wmask_compaction_rx_tlv_supported(struct ath12k_base *ab); void ath12k_dp_hal_rx_desc_init(struct ath12k_base *ab); #endif diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 10ea33fafff4..5c2316e40019 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -3939,10 +3939,16 @@ int ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab) tlv_filter.rx_msdu_end_offset = ab->hal_rx_ops->rx_desc_get_msdu_end_offset(); - /* TODO: Selectively subscribe to required qwords within msdu_end - * and mpdu_start and setup the mask in below msg - * and modify the rx_desc struct - */ + if (ath12k_dp_wmask_compaction_rx_tlv_supported(ab)) { + tlv_filter.rx_mpdu_start_wmask = + ab->hw_params->hal_ops->rxdma_ring_wmask_rx_mpdu_start(); + tlv_filter.rx_msdu_end_wmask = + ab->hw_params->hal_ops->rxdma_ring_wmask_rx_msdu_end(); + ath12k_dbg(ab, ATH12K_DBG_DATA, + "Configuring compact tlv masks rx_mpdu_start_wmask 0x%x rx_msdu_end_wmask 0x%x\n", + tlv_filter.rx_mpdu_start_wmask, tlv_filter.rx_msdu_end_wmask); + } + ret = ath12k_dp_tx_htt_rx_filter_setup(ab, ring_id, 0, HAL_RXDMA_BUF, DP_RXDMA_REFILL_RING_SIZE, diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index d4db94112deb..572b87153647 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -964,6 +964,26 @@ int ath12k_dp_tx_htt_rx_filter_setup(struct ath12k_base *ab, u32 ring_id, HTT_RX_RING_SELECTION_CFG_RX_ATTENTION_OFFSET); } + if (tlv_filter->rx_mpdu_start_wmask > 0 && + tlv_filter->rx_msdu_end_wmask > 0) { + cmd->info2 |= + le32_encode_bits(true, + HTT_RX_RING_SELECTION_CFG_WORD_MASK_COMPACT_SET); + cmd->rx_mpdu_start_end_mask = + le32_encode_bits(tlv_filter->rx_mpdu_start_wmask, + HTT_RX_RING_SELECTION_CFG_RX_MPDU_START_MASK); + /* mpdu_end is not used for any hardwares so far + * please assign it in future if any chip is + * using through hal ops + */ + cmd->rx_mpdu_start_end_mask |= + le32_encode_bits(tlv_filter->rx_mpdu_end_wmask, + HTT_RX_RING_SELECTION_CFG_RX_MPDU_END_MASK); + cmd->rx_msdu_end_word_mask = + le32_encode_bits(tlv_filter->rx_msdu_end_wmask, + HTT_RX_RING_SELECTION_CFG_RX_MSDU_END_MASK); + } + ret = ath12k_htc_send(&ab->htc, ab->dp.eid, skb); if (ret) goto err_free; diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index fa1bfb5256d0..cb540251acf8 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -626,6 +626,21 @@ static int ath12k_hal_srng_create_config_qcn9274(struct ath12k_base *ab) return 0; } +static u16 ath12k_hal_qcn9274_rx_mpdu_start_wmask_get(void) +{ + return QCN9274_MPDU_START_WMASK; +} + +static u32 ath12k_hal_qcn9274_rx_msdu_end_wmask_get(void) +{ + return QCN9274_MSDU_END_WMASK; +} + +static const struct hal_rx_ops *ath12k_hal_qcn9274_get_hal_rx_compact_ops(void) +{ + return &hal_rx_qcn9274_compact_ops; +} + static bool ath12k_hw_qcn9274_dp_rx_h_msdu_done(struct hal_rx_desc *desc) { return !!le32_get_bits(desc->u.qcn9274.msdu_end.info14, @@ -725,9 +740,350 @@ const struct hal_rx_ops hal_rx_qcn9274_ops = { .rx_desc_get_desc_size = ath12k_hw_qcn9274_get_rx_desc_size, }; +static bool ath12k_hw_qcn9274_compact_rx_desc_get_first_msdu(struct hal_rx_desc *desc) +{ + return !!le16_get_bits(desc->u.qcn9274_compact.msdu_end.info5, + RX_MSDU_END_INFO5_FIRST_MSDU); +} + +static bool ath12k_hw_qcn9274_compact_rx_desc_get_last_msdu(struct hal_rx_desc *desc) +{ + return !!le16_get_bits(desc->u.qcn9274_compact.msdu_end.info5, + RX_MSDU_END_INFO5_LAST_MSDU); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_l3_pad_bytes(struct hal_rx_desc *desc) +{ + return le16_get_bits(desc->u.qcn9274_compact.msdu_end.info5, + RX_MSDU_END_INFO5_L3_HDR_PADDING); +} + +static bool ath12k_hw_qcn9274_compact_rx_desc_encrypt_valid(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcn9274_compact.mpdu_start.info4, + RX_MPDU_START_INFO4_ENCRYPT_INFO_VALID); +} + +static u32 ath12k_hw_qcn9274_compact_rx_desc_get_encrypt_type(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.mpdu_start.info2, + RX_MPDU_START_INFO2_ENC_TYPE); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_decap_type(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info11, + RX_MSDU_END_INFO11_DECAP_FORMAT); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_mesh_ctl(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274.msdu_end.info11, + RX_MSDU_END_INFO11_MESH_CTRL_PRESENT); +} + +static bool +ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_seq_ctl_vld(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcn9274_compact.mpdu_start.info4, + RX_MPDU_START_INFO4_MPDU_SEQ_CTRL_VALID); +} + +static bool ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_fc_valid(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcn9274_compact.mpdu_start.info4, + RX_MPDU_START_INFO4_MPDU_FCTRL_VALID); +} + +static u16 +ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_start_seq_no(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.mpdu_start.info4, + RX_MPDU_START_INFO4_MPDU_SEQ_NUM); +} + +static u16 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_len(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info10, + RX_MSDU_END_INFO10_MSDU_LENGTH); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_sgi(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info12, + RX_MSDU_END_INFO12_SGI); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_rate_mcs(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info12, + RX_MSDU_END_INFO12_RATE_MCS); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_rx_bw(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info12, + RX_MSDU_END_INFO12_RECV_BW); +} + +static u32 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_freq(struct hal_rx_desc *desc) +{ + return __le32_to_cpu(desc->u.qcn9274_compact.msdu_end.phy_meta_data); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_pkt_type(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info12, + RX_MSDU_END_INFO12_PKT_TYPE); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_nss(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info12, + RX_MSDU_END_QCN9274_INFO12_MIMO_SS_BITMAP); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_tid(struct hal_rx_desc *desc) +{ + return le16_get_bits(desc->u.qcn9274_compact.msdu_end.info5, + RX_MSDU_END_QCN9274_INFO5_TID); +} + +static u16 ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_peer_id(struct hal_rx_desc *desc) +{ + return __le16_to_cpu(desc->u.qcn9274_compact.mpdu_start.sw_peer_id); +} + +static void ath12k_hw_qcn9274_compact_rx_desc_copy_end_tlv(struct hal_rx_desc *fdesc, + struct hal_rx_desc *ldesc) +{ + fdesc->u.qcn9274_compact.msdu_end = ldesc->u.qcn9274_compact.msdu_end; +} + +static u32 ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_ppdu_id(struct hal_rx_desc *desc) +{ + return __le16_to_cpu(desc->u.qcn9274_compact.mpdu_start.phy_ppdu_id); +} + +static void +ath12k_hw_qcn9274_compact_rx_desc_set_msdu_len(struct hal_rx_desc *desc, u16 len) +{ + u32 info = __le32_to_cpu(desc->u.qcn9274_compact.msdu_end.info10); + + info = u32_replace_bits(info, len, RX_MSDU_END_INFO10_MSDU_LENGTH); + desc->u.qcn9274_compact.msdu_end.info10 = __cpu_to_le32(info); +} + +static u8 *ath12k_hw_qcn9274_compact_rx_desc_get_msdu_payload(struct hal_rx_desc *desc) +{ + return &desc->u.qcn9274_compact.msdu_payload[0]; +} + +static u32 ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_start_offset(void) +{ + return offsetof(struct hal_rx_desc_qcn9274_compact, mpdu_start); +} + +static u32 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_end_offset(void) +{ + return offsetof(struct hal_rx_desc_qcn9274_compact, msdu_end); +} + +static bool ath12k_hw_qcn9274_compact_rx_desc_mac_addr2_valid(struct hal_rx_desc *desc) +{ + return __le32_to_cpu(desc->u.qcn9274_compact.mpdu_start.info4) & + RX_MPDU_START_INFO4_MAC_ADDR2_VALID; +} + +static u8 *ath12k_hw_qcn9274_compact_rx_desc_mpdu_start_addr2(struct hal_rx_desc *desc) +{ + return desc->u.qcn9274_compact.mpdu_start.addr2; +} + +static bool ath12k_hw_qcn9274_compact_rx_desc_is_da_mcbc(struct hal_rx_desc *desc) +{ + return __le32_to_cpu(desc->u.qcn9274_compact.mpdu_start.info6) & + RX_MPDU_START_INFO6_MCAST_BCAST; +} + +static void ath12k_hw_qcn9274_compact_rx_desc_get_dot11_hdr(struct hal_rx_desc *desc, + struct ieee80211_hdr *hdr) +{ + hdr->frame_control = desc->u.qcn9274_compact.mpdu_start.frame_ctrl; + hdr->duration_id = desc->u.qcn9274_compact.mpdu_start.duration; + ether_addr_copy(hdr->addr1, desc->u.qcn9274_compact.mpdu_start.addr1); + ether_addr_copy(hdr->addr2, desc->u.qcn9274_compact.mpdu_start.addr2); + ether_addr_copy(hdr->addr3, desc->u.qcn9274_compact.mpdu_start.addr3); + if (__le32_to_cpu(desc->u.qcn9274_compact.mpdu_start.info4) & + RX_MPDU_START_INFO4_MAC_ADDR4_VALID) { + ether_addr_copy(hdr->addr4, desc->u.qcn9274_compact.mpdu_start.addr4); + } + hdr->seq_ctrl = desc->u.qcn9274_compact.mpdu_start.seq_ctrl; +} + +static void +ath12k_hw_qcn9274_compact_rx_desc_get_crypto_hdr(struct hal_rx_desc *desc, + u8 *crypto_hdr, + enum hal_encrypt_type enctype) +{ + unsigned int key_id; + + switch (enctype) { + case HAL_ENCRYPT_TYPE_OPEN: + return; + case HAL_ENCRYPT_TYPE_TKIP_NO_MIC: + case HAL_ENCRYPT_TYPE_TKIP_MIC: + crypto_hdr[0] = + HAL_RX_MPDU_INFO_PN_GET_BYTE2(desc->u.qcn9274_compact.mpdu_start.pn[0]); + crypto_hdr[1] = 0; + crypto_hdr[2] = + HAL_RX_MPDU_INFO_PN_GET_BYTE1(desc->u.qcn9274_compact.mpdu_start.pn[0]); + break; + case HAL_ENCRYPT_TYPE_CCMP_128: + case HAL_ENCRYPT_TYPE_CCMP_256: + case HAL_ENCRYPT_TYPE_GCMP_128: + case HAL_ENCRYPT_TYPE_AES_GCMP_256: + crypto_hdr[0] = + HAL_RX_MPDU_INFO_PN_GET_BYTE1(desc->u.qcn9274_compact.mpdu_start.pn[0]); + crypto_hdr[1] = + HAL_RX_MPDU_INFO_PN_GET_BYTE2(desc->u.qcn9274_compact.mpdu_start.pn[0]); + crypto_hdr[2] = 0; + break; + case HAL_ENCRYPT_TYPE_WEP_40: + case HAL_ENCRYPT_TYPE_WEP_104: + case HAL_ENCRYPT_TYPE_WEP_128: + case HAL_ENCRYPT_TYPE_WAPI_GCM_SM4: + case HAL_ENCRYPT_TYPE_WAPI: + return; + } + key_id = le32_get_bits(desc->u.qcn9274_compact.mpdu_start.info5, + RX_MPDU_START_INFO5_KEY_ID); + crypto_hdr[3] = 0x20 | (key_id << 6); + crypto_hdr[4] = + HAL_RX_MPDU_INFO_PN_GET_BYTE3(desc->u.qcn9274_compact.mpdu_start.pn[0]); + crypto_hdr[5] = + HAL_RX_MPDU_INFO_PN_GET_BYTE4(desc->u.qcn9274_compact.mpdu_start.pn[0]); + crypto_hdr[6] = + HAL_RX_MPDU_INFO_PN_GET_BYTE1(desc->u.qcn9274_compact.mpdu_start.pn[1]); + crypto_hdr[7] = + HAL_RX_MPDU_INFO_PN_GET_BYTE2(desc->u.qcn9274_compact.mpdu_start.pn[1]); +} + +static u16 ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_frame_ctl(struct hal_rx_desc *desc) +{ + return __le16_to_cpu(desc->u.qcn9274_compact.mpdu_start.frame_ctrl); +} + +static bool ath12k_hw_qcn9274_compact_dp_rx_h_msdu_done(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcn9274_compact.msdu_end.info14, + RX_MSDU_END_INFO14_MSDU_DONE); +} + +static bool ath12k_hw_qcn9274_compact_dp_rx_h_l4_cksum_fail(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcn9274_compact.msdu_end.info13, + RX_MSDU_END_INFO13_TCP_UDP_CKSUM_FAIL); +} + +static bool ath12k_hw_qcn9274_compact_dp_rx_h_ip_cksum_fail(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcn9274_compact.msdu_end.info13, + RX_MSDU_END_INFO13_IP_CKSUM_FAIL); +} + +static bool ath12k_hw_qcn9274_compact_dp_rx_h_is_decrypted(struct hal_rx_desc *desc) +{ + return (le32_get_bits(desc->u.qcn9274_compact.msdu_end.info14, + RX_MSDU_END_INFO14_DECRYPT_STATUS_CODE) == + RX_DESC_DECRYPT_STATUS_CODE_OK); +} + +static u32 ath12k_hw_qcn9274_compact_dp_rx_h_mpdu_err(struct hal_rx_desc *desc) +{ + u32 info = __le32_to_cpu(desc->u.qcn9274_compact.msdu_end.info13); + u32 errmap = 0; + + if (info & RX_MSDU_END_INFO13_FCS_ERR) + errmap |= HAL_RX_MPDU_ERR_FCS; + + if (info & RX_MSDU_END_INFO13_DECRYPT_ERR) + errmap |= HAL_RX_MPDU_ERR_DECRYPT; + + if (info & RX_MSDU_END_INFO13_TKIP_MIC_ERR) + errmap |= HAL_RX_MPDU_ERR_TKIP_MIC; + + if (info & RX_MSDU_END_INFO13_A_MSDU_ERROR) + errmap |= HAL_RX_MPDU_ERR_AMSDU_ERR; + + if (info & RX_MSDU_END_INFO13_OVERFLOW_ERR) + errmap |= HAL_RX_MPDU_ERR_OVERFLOW; + + if (info & RX_MSDU_END_INFO13_MSDU_LEN_ERR) + errmap |= HAL_RX_MPDU_ERR_MSDU_LEN; + + if (info & RX_MSDU_END_INFO13_MPDU_LEN_ERR) + errmap |= HAL_RX_MPDU_ERR_MPDU_LEN; + + return errmap; +} + +static u32 ath12k_hw_qcn9274_compact_get_rx_desc_size(void) +{ + return sizeof(struct hal_rx_desc_qcn9274_compact); +} + +const struct hal_rx_ops hal_rx_qcn9274_compact_ops = { + .rx_desc_get_first_msdu = ath12k_hw_qcn9274_compact_rx_desc_get_first_msdu, + .rx_desc_get_last_msdu = ath12k_hw_qcn9274_compact_rx_desc_get_last_msdu, + .rx_desc_get_l3_pad_bytes = ath12k_hw_qcn9274_compact_rx_desc_get_l3_pad_bytes, + .rx_desc_encrypt_valid = ath12k_hw_qcn9274_compact_rx_desc_encrypt_valid, + .rx_desc_get_encrypt_type = ath12k_hw_qcn9274_compact_rx_desc_get_encrypt_type, + .rx_desc_get_decap_type = ath12k_hw_qcn9274_compact_rx_desc_get_decap_type, + .rx_desc_get_mesh_ctl = ath12k_hw_qcn9274_compact_rx_desc_get_mesh_ctl, + .rx_desc_get_mpdu_seq_ctl_vld = + ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_seq_ctl_vld, + .rx_desc_get_mpdu_fc_valid = ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_fc_valid, + .rx_desc_get_mpdu_start_seq_no = + ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_start_seq_no, + .rx_desc_get_msdu_len = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_len, + .rx_desc_get_msdu_sgi = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_sgi, + .rx_desc_get_msdu_rate_mcs = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_rate_mcs, + .rx_desc_get_msdu_rx_bw = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_rx_bw, + .rx_desc_get_msdu_freq = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_freq, + .rx_desc_get_msdu_pkt_type = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_pkt_type, + .rx_desc_get_msdu_nss = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_nss, + .rx_desc_get_mpdu_tid = ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_tid, + .rx_desc_get_mpdu_peer_id = ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_peer_id, + .rx_desc_copy_end_tlv = ath12k_hw_qcn9274_compact_rx_desc_copy_end_tlv, + .rx_desc_get_mpdu_ppdu_id = ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_ppdu_id, + .rx_desc_set_msdu_len = ath12k_hw_qcn9274_compact_rx_desc_set_msdu_len, + .rx_desc_get_msdu_payload = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_payload, + .rx_desc_get_mpdu_start_offset = + ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_start_offset, + .rx_desc_get_msdu_end_offset = + ath12k_hw_qcn9274_compact_rx_desc_get_msdu_end_offset, + .rx_desc_mac_addr2_valid = ath12k_hw_qcn9274_compact_rx_desc_mac_addr2_valid, + .rx_desc_mpdu_start_addr2 = ath12k_hw_qcn9274_compact_rx_desc_mpdu_start_addr2, + .rx_desc_is_da_mcbc = ath12k_hw_qcn9274_compact_rx_desc_is_da_mcbc, + .rx_desc_get_dot11_hdr = ath12k_hw_qcn9274_compact_rx_desc_get_dot11_hdr, + .rx_desc_get_crypto_header = ath12k_hw_qcn9274_compact_rx_desc_get_crypto_hdr, + .rx_desc_get_mpdu_frame_ctl = + ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_frame_ctl, + .dp_rx_h_msdu_done = ath12k_hw_qcn9274_compact_dp_rx_h_msdu_done, + .dp_rx_h_l4_cksum_fail = ath12k_hw_qcn9274_compact_dp_rx_h_l4_cksum_fail, + .dp_rx_h_ip_cksum_fail = ath12k_hw_qcn9274_compact_dp_rx_h_ip_cksum_fail, + .dp_rx_h_is_decrypted = ath12k_hw_qcn9274_compact_dp_rx_h_is_decrypted, + .dp_rx_h_mpdu_err = ath12k_hw_qcn9274_compact_dp_rx_h_mpdu_err, + .rx_desc_get_desc_size = ath12k_hw_qcn9274_compact_get_rx_desc_size, +}; + const struct hal_ops hal_qcn9274_ops = { .create_srng_config = ath12k_hal_srng_create_config_qcn9274, .tcl_to_wbm_rbm_map = ath12k_hal_qcn9274_tcl_to_wbm_rbm_map, + .rxdma_ring_wmask_rx_mpdu_start = ath12k_hal_qcn9274_rx_mpdu_start_wmask_get, + .rxdma_ring_wmask_rx_msdu_end = ath12k_hal_qcn9274_rx_msdu_end_wmask_get, + .get_hal_rx_compact_ops = ath12k_hal_qcn9274_get_hal_rx_compact_ops, }; static bool ath12k_hw_wcn7850_rx_desc_get_first_msdu(struct hal_rx_desc *desc) @@ -1192,6 +1548,9 @@ const struct hal_rx_ops hal_rx_wcn7850_ops = { const struct hal_ops hal_wcn7850_ops = { .create_srng_config = ath12k_hal_srng_create_config_wcn7850, .tcl_to_wbm_rbm_map = ath12k_hal_wcn7850_tcl_to_wbm_rbm_map, + .rxdma_ring_wmask_rx_mpdu_start = NULL, + .rxdma_ring_wmask_rx_msdu_end = NULL, + .get_hal_rx_compact_ops = NULL, }; static int ath12k_hal_alloc_cont_rdp(struct ath12k_base *ab) diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index 82517991510b..b7d78ba2b801 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -1082,6 +1082,9 @@ struct hal_rx_ops { struct hal_ops { int (*create_srng_config)(struct ath12k_base *ab); + u16 (*rxdma_ring_wmask_rx_mpdu_start)(void); + u32 (*rxdma_ring_wmask_rx_msdu_end)(void); + const struct hal_rx_ops *(*get_hal_rx_compact_ops)(void); const struct ath12k_hal_tcl_to_wbm_rbm_map *tcl_to_wbm_rbm_map; }; @@ -1089,6 +1092,7 @@ extern const struct hal_ops hal_qcn9274_ops; extern const struct hal_ops hal_wcn7850_ops; extern const struct hal_rx_ops hal_rx_qcn9274_ops; +extern const struct hal_rx_ops hal_rx_qcn9274_compact_ops; extern const struct hal_rx_ops hal_rx_wcn7850_ops; u32 ath12k_hal_reo_qdesc_size(u32 ba_window_size, u8 tid); diff --git a/drivers/net/wireless/ath/ath12k/rx_desc.h b/drivers/net/wireless/ath/ath12k/rx_desc.h index 55f20c446ca9..d5fd3a3b6b4d 100644 --- a/drivers/net/wireless/ath/ath12k/rx_desc.h +++ b/drivers/net/wireless/ath/ath12k/rx_desc.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_RX_DESC_H #define ATH12K_RX_DESC_H @@ -147,6 +147,61 @@ struct rx_mpdu_start_qcn9274 { __le32 res1; } __packed; +#define QCN9274_MPDU_START_SELECT_MPDU_START_TAG BIT(0) +#define QCN9274_MPDU_START_SELECT_INFO0_REO_QUEUE_DESC_LO BIT(1) +#define QCN9274_MPDU_START_SELECT_INFO1_PN_31_0 BIT(2) +#define QCN9274_MPDU_START_SELECT_PN_95_32 BIT(3) +#define QCN9274_MPDU_START_SELECT_PN_127_96_INFO2 BIT(4) +#define QCN9274_MPDU_START_SELECT_PEER_MDATA_INFO3_PHY_PPDU_ID BIT(5) +#define QCN9274_MPDU_START_SELECT_AST_IDX_SW_PEER_ID_INFO4 BIT(6) +#define QCN9274_MPDU_START_SELECT_INFO5_INFO6 BIT(7) +#define QCN9274_MPDU_START_SELECT_FRAME_CTRL_DURATION_ADDR1_31_0 BIT(8) +#define QCN9274_MPDU_START_SELECT_ADDR2_47_0_ADDR1_47_32 BIT(9) +#define QCN9274_MPDU_START_SELECT_ADDR3_47_0_SEQ_CTRL BIT(10) +#define QCN9274_MPDU_START_SELECT_ADDR4_47_0_QOS_CTRL BIT(11) +#define QCN9274_MPDU_START_SELECT_HT_CTRL_INFO7 BIT(12) +#define QCN9274_MPDU_START_SELECT_ML_ADDR1_47_0_ML_ADDR2_15_0 BIT(13) +#define QCN9274_MPDU_START_SELECT_ML_ADDR2_47_16_INFO8 BIT(14) +#define QCN9274_MPDU_START_SELECT_RES_0_RES_1 BIT(15) + +#define QCN9274_MPDU_START_WMASK (QCN9274_MPDU_START_SELECT_INFO1_PN_31_0 | \ + QCN9274_MPDU_START_SELECT_PN_95_32 | \ + QCN9274_MPDU_START_SELECT_PN_127_96_INFO2 | \ + QCN9274_MPDU_START_SELECT_PEER_MDATA_INFO3_PHY_PPDU_ID | \ + QCN9274_MPDU_START_SELECT_AST_IDX_SW_PEER_ID_INFO4 | \ + QCN9274_MPDU_START_SELECT_INFO5_INFO6 | \ + QCN9274_MPDU_START_SELECT_FRAME_CTRL_DURATION_ADDR1_31_0 | \ + QCN9274_MPDU_START_SELECT_ADDR2_47_0_ADDR1_47_32 | \ + QCN9274_MPDU_START_SELECT_ADDR3_47_0_SEQ_CTRL | \ + QCN9274_MPDU_START_SELECT_ADDR4_47_0_QOS_CTRL) + +/* The below rx_mpdu_start_qcn9274_compact structure is tied with the mask + * value QCN9274_MPDU_START_WMASK. If the mask value changes the structure + * will also change. + */ + +struct rx_mpdu_start_qcn9274_compact { + __le32 info1; + __le32 pn[4]; + __le32 info2; + __le32 peer_meta_data; + __le16 info3; + __le16 phy_ppdu_id; + __le16 ast_index; + __le16 sw_peer_id; + __le32 info4; + __le32 info5; + __le32 info6; + __le16 frame_ctrl; + __le16 duration; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctrl; + u8 addr4[ETH_ALEN]; + __le16 qos_ctrl; +} __packed; + /* rx_mpdu_start * * reo_destination_indication @@ -786,6 +841,52 @@ struct rx_msdu_end_qcn9274 { __le32 info14; } __packed; +#define QCN9274_MSDU_END_SELECT_MSDU_END_TAG BIT(0) +#define QCN9274_MSDU_END_SELECT_INFO0_PHY_PPDUID_IP_HDR_CSUM_INFO1 BIT(1) +#define QCN9274_MSDU_END_SELECT_INFO2_CUMULATIVE_CSUM_RULE_IND_0 BIT(2) +#define QCN9274_MSDU_END_SELECT_IPV6_OP_CRC_INFO3_TYPE13 BIT(3) +#define QCN9274_MSDU_END_SELECT_RULE_IND_1_TCP_SEQ_NUM BIT(4) +#define QCN9274_MSDU_END_SELECT_TCP_ACK_NUM_INFO4_WINDOW_SIZE BIT(5) +#define QCN9274_MSDU_END_SELECT_SA_SW_PER_ID_INFO5_SA_DA_ID BIT(6) +#define QCN9274_MSDU_END_SELECT_INFO6_FSE_METADATA BIT(7) +#define QCN9274_MSDU_END_SELECT_CCE_MDATA_TCP_UDP_CSUM_INFO7_IP_LEN BIT(8) +#define QCN9274_MSDU_END_SELECT_INFO8_INFO9 BIT(9) +#define QCN9274_MSDU_END_SELECT_INFO10_INFO11 BIT(10) +#define QCN9274_MSDU_END_SELECT_VLAN_CTAG_STAG_CI_PEER_MDATA BIT(11) +#define QCN9274_MSDU_END_SELECT_INFO12_AND_FLOW_ID_TOEPLITZ BIT(12) +#define QCN9274_MSDU_END_SELECT_PPDU_START_TS_63_32_PHY_MDATA BIT(13) +#define QCN9274_MSDU_END_SELECT_PPDU_START_TS_31_0_TOEPLITZ_HASH_2_4 BIT(14) +#define QCN9274_MSDU_END_SELECT_RES0_SA_47_0 BIT(15) +#define QCN9274_MSDU_END_SELECT_INFO13_INFO14 BIT(16) + +#define QCN9274_MSDU_END_WMASK (QCN9274_MSDU_END_SELECT_MSDU_END_TAG | \ + QCN9274_MSDU_END_SELECT_SA_SW_PER_ID_INFO5_SA_DA_ID | \ + QCN9274_MSDU_END_SELECT_INFO10_INFO11 | \ + QCN9274_MSDU_END_SELECT_INFO12_AND_FLOW_ID_TOEPLITZ | \ + QCN9274_MSDU_END_SELECT_PPDU_START_TS_63_32_PHY_MDATA | \ + QCN9274_MSDU_END_SELECT_INFO13_INFO14) + +/* The below rx_msdu_end_qcn9274_compact structure is tied with the mask value + * QCN9274_MSDU_END_WMASK. If the mask value changes the structure will also + * change. + */ + +struct rx_msdu_end_qcn9274_compact { + __le64 msdu_end_tag; + __le16 sa_sw_peer_id; + __le16 info5; + __le16 sa_idx; + __le16 da_idx_or_sw_peer_id; + __le32 info10; + __le32 info11; + __le32 info12; + __le32 flow_id_toeplitz; + __le32 ppdu_start_timestamp_63_32; + __le32 phy_meta_data; + __le32 info13; + __le32 info14; +} __packed; + /* These macro definitions are only used for WCN7850 */ #define RX_MSDU_END_WCN7850_INFO2_KEY_ID BIT(7, 0) @@ -1450,16 +1551,18 @@ struct rx_msdu_end_wcn7850 { * */ -/* TODO: Move to compact TLV approach - * By default these tlv's are not aligned to 128b boundary - * Need to remove unused qwords and make them compact/aligned - */ struct hal_rx_desc_qcn9274 { struct rx_msdu_end_qcn9274 msdu_end; struct rx_mpdu_start_qcn9274 mpdu_start; u8 msdu_payload[]; } __packed; +struct hal_rx_desc_qcn9274_compact { + struct rx_msdu_end_qcn9274_compact msdu_end; + struct rx_mpdu_start_qcn9274_compact mpdu_start; + u8 msdu_payload[]; +} __packed; + #define RX_BE_PADDING0_BYTES 8 #define RX_BE_PADDING1_BYTES 8 @@ -1484,6 +1587,7 @@ struct hal_rx_desc_wcn7850 { struct hal_rx_desc { union { struct hal_rx_desc_qcn9274 qcn9274; + struct hal_rx_desc_qcn9274_compact qcn9274_compact; struct hal_rx_desc_wcn7850 wcn7850; } u; } __packed; diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 7443831d62d8..d740701809c2 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2163,6 +2163,8 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_11BE = 289, + WMI_TLV_SERVICE_WMSK_COMPACTION_RX_TLVS = 361, + WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT = 365, WMI_MAX_EXT2_SERVICE, -- cgit From 57c8b5c332e587cceec5d6bde57146edc2f4af87 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Mon, 29 Jan 2024 12:27:21 +0530 Subject: wifi: ath12k: add MAC id support in WBM error path When more than one pdev is supported in the chip/SoC, the packet belonging to second pdev is given to first pdev due to not identifying the MAC id in the WBM error path. So ping fails. In WBM error path, src link id information not available in the descriptor. So get this information from the msdu_end 64bit tag. It is necessary to get the src link id to identify the MAC id in the given chip. Then only we can pass the skb to the corresponding pdev. The msdu_end 64bit tag is available only if compact Rx TLVs descriptors are used. Thus, src link id is fetched correctly in WBM error path when compact descriptors are in use. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-11-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_rx.c | 42 ++++++++++++++++--------------- drivers/net/wireless/ath/ath12k/hal.c | 20 +++++++++++++++ drivers/net/wireless/ath/ath12k/hal.h | 1 + drivers/net/wireless/ath/ath12k/rx_desc.h | 2 ++ 4 files changed, 45 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 5c2316e40019..ca76c018dd0c 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -233,6 +233,12 @@ static u16 ath12k_dp_rxdesc_get_mpdu_frame_ctrl(struct ath12k_base *ab, return ab->hal_rx_ops->rx_desc_get_mpdu_frame_ctl(desc); } +static inline u8 ath12k_dp_rx_get_msdu_src_link(struct ath12k_base *ab, + struct hal_rx_desc *desc) +{ + return ab->hal_rx_ops->rx_desc_get_msdu_src_link_id(desc); +} + static int ath12k_dp_purge_mon_ring(struct ath12k_base *ab) { int i, reaped = 0; @@ -3695,16 +3701,15 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, struct hal_rx_wbm_rel_info err_info; struct hal_srng *srng; struct sk_buff *msdu; - struct sk_buff_head msdu_list[MAX_RADIOS]; + struct sk_buff_head msdu_list; struct ath12k_skb_rxcb *rxcb; void *rx_desc; - int mac_id; + u8 mac_id; int num_buffs_reaped = 0; struct ath12k_rx_desc_info *desc_info; - int ret, i; + int ret, pdev_id; - for (i = 0; i < ab->num_radios; i++) - __skb_queue_head_init(&msdu_list[i]); + __skb_queue_head_init(&msdu_list); srng = &ab->hal.srng_list[dp->rx_rel_ring.ring_id]; rx_ring = &dp->rx_refill_buf_ring; @@ -3737,11 +3742,6 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, } } - /* FIXME: Extract mac id correctly. Since descs are not tied - * to mac, we can extract from vdev id in ring desc. - */ - mac_id = 0; - if (desc_info->magic != ATH12K_DP_RX_DESC_MAGIC) ath12k_warn(ab, "WBM RX err, Check HW CC implementation"); @@ -3771,7 +3771,8 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, rxcb->err_rel_src = err_info.err_rel_src; rxcb->err_code = err_info.err_code; rxcb->rx_desc = (struct hal_rx_desc *)msdu->data; - __skb_queue_tail(&msdu_list[mac_id], msdu); + + __skb_queue_tail(&msdu_list, msdu); rxcb->is_first_msdu = err_info.first_msdu; rxcb->is_last_msdu = err_info.last_msdu; @@ -3788,21 +3789,22 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_buffs_reaped); rcu_read_lock(); - for (i = 0; i < ab->num_radios; i++) { - if (!rcu_dereference(ab->pdevs_active[i])) { - __skb_queue_purge(&msdu_list[i]); + while ((msdu = __skb_dequeue(&msdu_list))) { + mac_id = ath12k_dp_rx_get_msdu_src_link(ab, + (struct hal_rx_desc *)msdu->data); + pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id); + ar = ab->pdevs[pdev_id].ar; + + if (!ar || !rcu_dereference(ar->ab->pdevs_active[mac_id])) { + dev_kfree_skb_any(msdu); continue; } - ar = ab->pdevs[i].ar; - if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) { - __skb_queue_purge(&msdu_list[i]); + dev_kfree_skb_any(msdu); continue; } - - while ((msdu = __skb_dequeue(&msdu_list[i])) != NULL) - ath12k_dp_rx_wbm_err(ar, napi, msdu, &msdu_list[i]); + ath12k_dp_rx_wbm_err(ar, napi, msdu, &msdu_list); } rcu_read_unlock(); done: diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index cb540251acf8..78310da8cfe8 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -700,6 +700,11 @@ static u32 ath12k_hw_qcn9274_get_rx_desc_size(void) return sizeof(struct hal_rx_desc_qcn9274); } +static u8 ath12k_hw_qcn9274_rx_desc_get_msdu_src_link(struct hal_rx_desc *desc) +{ + return 0; +} + const struct hal_rx_ops hal_rx_qcn9274_ops = { .rx_desc_get_first_msdu = ath12k_hw_qcn9274_rx_desc_get_first_msdu, .rx_desc_get_last_msdu = ath12k_hw_qcn9274_rx_desc_get_last_msdu, @@ -738,6 +743,7 @@ const struct hal_rx_ops hal_rx_qcn9274_ops = { .dp_rx_h_is_decrypted = ath12k_hw_qcn9274_dp_rx_h_is_decrypted, .dp_rx_h_mpdu_err = ath12k_hw_qcn9274_dp_rx_h_mpdu_err, .rx_desc_get_desc_size = ath12k_hw_qcn9274_get_rx_desc_size, + .rx_desc_get_msdu_src_link_id = ath12k_hw_qcn9274_rx_desc_get_msdu_src_link, }; static bool ath12k_hw_qcn9274_compact_rx_desc_get_first_msdu(struct hal_rx_desc *desc) @@ -1033,6 +1039,12 @@ static u32 ath12k_hw_qcn9274_compact_get_rx_desc_size(void) return sizeof(struct hal_rx_desc_qcn9274_compact); } +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_src_link(struct hal_rx_desc *desc) +{ + return le64_get_bits(desc->u.qcn9274_compact.msdu_end.msdu_end_tag, + RX_MSDU_END_64_TLV_SRC_LINK_ID); +} + const struct hal_rx_ops hal_rx_qcn9274_compact_ops = { .rx_desc_get_first_msdu = ath12k_hw_qcn9274_compact_rx_desc_get_first_msdu, .rx_desc_get_last_msdu = ath12k_hw_qcn9274_compact_rx_desc_get_last_msdu, @@ -1076,6 +1088,8 @@ const struct hal_rx_ops hal_rx_qcn9274_compact_ops = { .dp_rx_h_is_decrypted = ath12k_hw_qcn9274_compact_dp_rx_h_is_decrypted, .dp_rx_h_mpdu_err = ath12k_hw_qcn9274_compact_dp_rx_h_mpdu_err, .rx_desc_get_desc_size = ath12k_hw_qcn9274_compact_get_rx_desc_size, + .rx_desc_get_msdu_src_link_id = + ath12k_hw_qcn9274_compact_rx_desc_get_msdu_src_link, }; const struct hal_ops hal_qcn9274_ops = { @@ -1504,6 +1518,11 @@ static u32 ath12k_hw_wcn7850_get_rx_desc_size(void) return sizeof(struct hal_rx_desc_wcn7850); } +static u8 ath12k_hw_wcn7850_rx_desc_get_msdu_src_link(struct hal_rx_desc *desc) +{ + return 0; +} + const struct hal_rx_ops hal_rx_wcn7850_ops = { .rx_desc_get_first_msdu = ath12k_hw_wcn7850_rx_desc_get_first_msdu, .rx_desc_get_last_msdu = ath12k_hw_wcn7850_rx_desc_get_last_msdu, @@ -1543,6 +1562,7 @@ const struct hal_rx_ops hal_rx_wcn7850_ops = { .dp_rx_h_is_decrypted = ath12k_hw_wcn7850_dp_rx_h_is_decrypted, .dp_rx_h_mpdu_err = ath12k_hw_wcn7850_dp_rx_h_mpdu_err, .rx_desc_get_desc_size = ath12k_hw_wcn7850_get_rx_desc_size, + .rx_desc_get_msdu_src_link_id = ath12k_hw_wcn7850_rx_desc_get_msdu_src_link, }; const struct hal_ops hal_wcn7850_ops = { diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index b7d78ba2b801..107927d64bbb 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -1078,6 +1078,7 @@ struct hal_rx_ops { bool (*dp_rx_h_is_decrypted)(struct hal_rx_desc *desc); u32 (*dp_rx_h_mpdu_err)(struct hal_rx_desc *desc); u32 (*rx_desc_get_desc_size)(void); + u8 (*rx_desc_get_msdu_src_link_id)(struct hal_rx_desc *desc); }; struct hal_ops { diff --git a/drivers/net/wireless/ath/ath12k/rx_desc.h b/drivers/net/wireless/ath/ath12k/rx_desc.h index d5fd3a3b6b4d..a0db6702a189 100644 --- a/drivers/net/wireless/ath/ath12k/rx_desc.h +++ b/drivers/net/wireless/ath/ath12k/rx_desc.h @@ -663,6 +663,8 @@ enum rx_msdu_start_reception_type { RX_MSDU_START_RECEPTION_TYPE_UL_MU_OFDMA_MIMO, }; +#define RX_MSDU_END_64_TLV_SRC_LINK_ID GENMASK(24, 22) + #define RX_MSDU_END_INFO0_RXPCU_MPDU_FITLER GENMASK(1, 0) #define RX_MSDU_END_INFO0_SW_FRAME_GRP_ID GENMASK(8, 2) -- cgit From afeee629e72eeed719eb3f2918d7c8f3ae33497f Mon Sep 17 00:00:00 2001 From: P Praneesh Date: Mon, 29 Jan 2024 12:27:22 +0530 Subject: wifi: ath12k: fix PCI read and write Currently, PCI read is failing for the registers belonging to SECURITY_CONTROL_WLAN registers. These registers read is required to read the board-id to identify the dual-mac QCN9274 hardware. The failure is because, for these registers (SECURITY_CONTROL_WLAN) offset, ath12k_pci_get_window_start() returns window_start as 0. Due to this PCI read is done without PCI select window and with window_start offset as 0. Hence, fix PCI read and write by doing PCI select window and by using the correct window_start offset - WINDOW_START for SECURITY_CONTROL_WLAN registers. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: P Praneesh Co-developed-by: Karthikeyan Periyasamy Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-12-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/pci.c | 43 +++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index d334f41f9658..14954bc05144 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -205,18 +205,17 @@ static u32 ath12k_pci_get_window_start(struct ath12k_base *ab, /* If offset lies within CE register range, use 2nd window */ else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < WINDOW_RANGE_MASK) window_start = 2 * WINDOW_START; - /* If offset lies within PCI_BAR_WINDOW0_BASE and within PCI_SOC_PCI_REG_BASE - * use 0th window - */ - else if (((offset ^ PCI_BAR_WINDOW0_BASE) < WINDOW_RANGE_MASK) && - !((offset ^ PCI_SOC_PCI_REG_BASE) < PCI_SOC_RANGE_MASK)) - window_start = 0; else window_start = WINDOW_START; return window_start; } +static inline bool ath12k_pci_is_offset_within_mhi_region(u32 offset) +{ + return (offset >= PCI_MHIREGLEN_REG && offset <= PCI_MHI_REGION_END); +} + static void ath12k_pci_soc_global_reset(struct ath12k_base *ab) { u32 val, delay; @@ -1172,15 +1171,17 @@ u32 ath12k_pci_read32(struct ath12k_base *ab, u32 offset) if (window_start == WINDOW_START) { spin_lock_bh(&ab_pci->window_lock); ath12k_pci_select_window(ab_pci, offset); - val = ioread32(ab->mem + window_start + - (offset & WINDOW_RANGE_MASK)); + + if (ath12k_pci_is_offset_within_mhi_region(offset)) { + offset = offset - PCI_MHIREGLEN_REG; + val = ioread32(ab->mem + + (offset & WINDOW_RANGE_MASK)); + } else { + val = ioread32(ab->mem + window_start + + (offset & WINDOW_RANGE_MASK)); + } spin_unlock_bh(&ab_pci->window_lock); } else { - if ((!window_start) && - (offset >= PCI_MHIREGLEN_REG && - offset <= PCI_MHI_REGION_END)) - offset = offset - PCI_MHIREGLEN_REG; - val = ioread32(ab->mem + window_start + (offset & WINDOW_RANGE_MASK)); } @@ -1217,15 +1218,17 @@ void ath12k_pci_write32(struct ath12k_base *ab, u32 offset, u32 value) if (window_start == WINDOW_START) { spin_lock_bh(&ab_pci->window_lock); ath12k_pci_select_window(ab_pci, offset); - iowrite32(value, ab->mem + window_start + - (offset & WINDOW_RANGE_MASK)); + + if (ath12k_pci_is_offset_within_mhi_region(offset)) { + offset = offset - PCI_MHIREGLEN_REG; + iowrite32(value, ab->mem + + (offset & WINDOW_RANGE_MASK)); + } else { + iowrite32(value, ab->mem + window_start + + (offset & WINDOW_RANGE_MASK)); + } spin_unlock_bh(&ab_pci->window_lock); } else { - if ((!window_start) && - (offset >= PCI_MHIREGLEN_REG && - offset <= PCI_MHI_REGION_END)) - offset = offset - PCI_MHIREGLEN_REG; - iowrite32(value, ab->mem + window_start + (offset & WINDOW_RANGE_MASK)); } -- cgit From af9bc78d14fbe77db6e7526efaced162060f27bc Mon Sep 17 00:00:00 2001 From: Ganesh Babu Jothiram Date: Mon, 29 Jan 2024 12:27:23 +0530 Subject: wifi: ath12k: Read board id to support split-PHY QCN9274 QCN9274 can support single-PHY or split-PHY architecture. Currently, only the single-PHY architecture is supported in ath12k. The split-PHY QCN9274 requires different AMSS firmware binary "amss_dualmac.bin". Hence, add support to read board id from OTP. Based on board id decide whether single-mac / dual-mac firmware needs to be downloaded to the target. Also, update HW param max_radios to support split-PHY in QCN9274. Also, add new Firmware IE for firmware_N.bin "ATH11K_FW_IE_AMSS_DUALMAC_IMAGE" to support dualmac QCN9274. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Ganesh Babu Jothiram Co-developed-by: Raj Kumar Bhagat Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-13-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/core.h | 2 ++ drivers/net/wireless/ath/ath12k/fw.c | 7 +++++ drivers/net/wireless/ath/ath12k/fw.h | 1 + drivers/net/wireless/ath/ath12k/hw.c | 8 +++++- drivers/net/wireless/ath/ath12k/hw.h | 2 ++ drivers/net/wireless/ath/ath12k/mac.c | 3 ++- drivers/net/wireless/ath/ath12k/mhi.c | 49 +++++++++++++++++++++++++++------- drivers/net/wireless/ath/ath12k/pci.h | 3 +++ 8 files changed, 64 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 67bf8d840b00..f0a319ea57c1 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -832,6 +832,8 @@ struct ath12k_base { const struct firmware *fw; const u8 *amss_data; size_t amss_len; + const u8 *amss_dualmac_data; + size_t amss_dualmac_len; const u8 *m3_data; size_t m3_len; diff --git a/drivers/net/wireless/ath/ath12k/fw.c b/drivers/net/wireless/ath/ath12k/fw.c index fbcf40c97792..5be4b2d4a19d 100644 --- a/drivers/net/wireless/ath/ath12k/fw.c +++ b/drivers/net/wireless/ath/ath12k/fw.c @@ -119,6 +119,13 @@ static int ath12k_fw_request_firmware_api_n(struct ath12k_base *ab, ab->fw.m3_data = data; ab->fw.m3_len = ie_len; break; + case ATH12K_FW_IE_AMSS_DUALMAC_IMAGE: + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "found dualmac fw image ie (%zd B)\n", + ie_len); + ab->fw.amss_dualmac_data = data; + ab->fw.amss_dualmac_len = ie_len; + break; default: ath12k_warn(ab, "Unknown FW IE: %u\n", ie_id); break; diff --git a/drivers/net/wireless/ath/ath12k/fw.h b/drivers/net/wireless/ath/ath12k/fw.h index 28dc1423df70..3ff041f15fa0 100644 --- a/drivers/net/wireless/ath/ath12k/fw.h +++ b/drivers/net/wireless/ath/ath12k/fw.h @@ -14,6 +14,7 @@ enum ath12k_fw_ie_type { ATH12K_FW_IE_FEATURES = 1, ATH12K_FW_IE_AMSS_IMAGE = 2, ATH12K_FW_IE_M3_IMAGE = 3, + ATH12K_FW_IE_AMSS_DUALMAC_IMAGE = 4, }; enum ath12k_fw_features { diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index f399511746a8..a9adb547c83d 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -916,6 +916,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .def_num_link = 0, .max_mlo_peer = 256, + + .otp_board_id_register = QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB, }, { .name = "wcn7850 hw2.0", @@ -982,6 +984,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .def_num_link = 2, .max_mlo_peer = 32, + + .otp_board_id_register = 0, }, { .name = "qcn9274 hw2.0", @@ -991,7 +995,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .board_size = 256 * 1024, .cal_offset = 128 * 1024, }, - .max_radios = 1, + .max_radios = 2, .single_pdev_only = false, .qmi_service_ins_id = ATH12K_QMI_WLFW_SERVICE_INS_ID_V01_QCN9274, .internal_sleep_clock = false, @@ -1046,6 +1050,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .def_num_link = 0, .max_mlo_peer = 256, + + .otp_board_id_register = QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB, }, }; diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 987188f56b29..2e9c3b05d75a 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -207,6 +207,8 @@ struct ath12k_hw_params { u8 def_num_link; u16 max_mlo_peer; + + u32 otp_board_id_register; }; struct ath12k_hw_ops { diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 046bb466a391..6ef55876e7df 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -563,7 +563,8 @@ struct ath12k_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab, for (i = 0; i < ab->num_radios; i++) { pdev = rcu_dereference(ab->pdevs_active[i]); - if (pdev && pdev->ar) { + if (pdev && pdev->ar && + (pdev->ar->allocated_vdev_map & (1LL << vdev_id))) { arvif = ath12k_mac_get_arvif(pdev->ar, vdev_id); if (arvif) return arvif; diff --git a/drivers/net/wireless/ath/ath12k/mhi.c b/drivers/net/wireless/ath/ath12k/mhi.c index b7b31978a434..50b9e44504f7 100644 --- a/drivers/net/wireless/ath/ath12k/mhi.c +++ b/drivers/net/wireless/ath/ath12k/mhi.c @@ -14,6 +14,8 @@ #include "pci.h" #define MHI_TIMEOUT_DEFAULT_MS 90000 +#define OTP_INVALID_BOARD_ID 0xFFFF +#define OTP_VALID_DUALMAC_BOARD_ID_MASK 0x1000 static const struct mhi_channel_config ath12k_mhi_channels_qcn9274[] = { { @@ -359,7 +361,9 @@ int ath12k_mhi_register(struct ath12k_pci *ab_pci) { struct ath12k_base *ab = ab_pci->ab; struct mhi_controller *mhi_ctrl; + unsigned int board_id; int ret; + bool dualmac = false; mhi_ctrl = mhi_alloc_controller(); if (!mhi_ctrl) @@ -371,16 +375,43 @@ int ath12k_mhi_register(struct ath12k_pci *ab_pci) mhi_ctrl->reg_len = ab->mem_len; mhi_ctrl->rddm_size = ab->hw_params->rddm_size; - if (ab->fw.amss_data && ab->fw.amss_len > 0) { - /* use MHI firmware file from firmware-N.bin */ - mhi_ctrl->fw_data = ab->fw.amss_data; - mhi_ctrl->fw_sz = ab->fw.amss_len; + if (ab->hw_params->otp_board_id_register) { + board_id = + ath12k_pci_read32(ab, ab->hw_params->otp_board_id_register); + board_id = u32_get_bits(board_id, OTP_BOARD_ID_MASK); + + if (!board_id || (board_id == OTP_INVALID_BOARD_ID)) { + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "failed to read board id\n"); + } else if (board_id & OTP_VALID_DUALMAC_BOARD_ID_MASK) { + dualmac = true; + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "dualmac fw selected for board id: %x\n", board_id); + } + } + + if (dualmac) { + if (ab->fw.amss_dualmac_data && ab->fw.amss_dualmac_len > 0) { + /* use MHI firmware file from firmware-N.bin */ + mhi_ctrl->fw_data = ab->fw.amss_dualmac_data; + mhi_ctrl->fw_sz = ab->fw.amss_dualmac_len; + } else { + ath12k_warn(ab, "dualmac firmware IE not present in firmware-N.bin\n"); + ret = -ENOENT; + goto free_controller; + } } else { - /* use the old separate mhi.bin MHI firmware file */ - ath12k_core_create_firmware_path(ab, ATH12K_AMSS_FILE, - ab_pci->amss_path, - sizeof(ab_pci->amss_path)); - mhi_ctrl->fw_image = ab_pci->amss_path; + if (ab->fw.amss_data && ab->fw.amss_len > 0) { + /* use MHI firmware file from firmware-N.bin */ + mhi_ctrl->fw_data = ab->fw.amss_data; + mhi_ctrl->fw_sz = ab->fw.amss_len; + } else { + /* use the old separate mhi.bin MHI firmware file */ + ath12k_core_create_firmware_path(ab, ATH12K_AMSS_FILE, + ab_pci->amss_path, + sizeof(ab_pci->amss_path)); + mhi_ctrl->fw_image = ab_pci->amss_path; + } } ret = ath12k_mhi_get_msi(ab_pci); diff --git a/drivers/net/wireless/ath/ath12k/pci.h b/drivers/net/wireless/ath/ath12k/pci.h index 023616928f03..ca93693ba4e9 100644 --- a/drivers/net/wireless/ath/ath12k/pci.h +++ b/drivers/net/wireless/ath/ath12k/pci.h @@ -53,6 +53,9 @@ #define WLAON_QFPROM_PWR_CTRL_REG 0x01f8031c #define QFPROM_PWR_CTRL_VDD4BLOW_MASK 0x4 +#define QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB 0x1E20338 +#define OTP_BOARD_ID_MASK GENMASK(15, 0) + #define PCI_BAR_WINDOW0_BASE 0x1E00000 #define PCI_BAR_WINDOW0_END 0x1E7FFFC #define PCI_SOC_RANGE_MASK 0x3FFF -- cgit From 2d3a7384b9c8ea0b640747176cc01af64cf722ec Mon Sep 17 00:00:00 2001 From: Raj Kumar Bhagat Date: Mon, 29 Jan 2024 12:27:24 +0530 Subject: wifi: ath12k: disable QMI PHY capability learn in split-phy QCN9274 QMI PHY capability learn is used to get PHY count information to support single/multi link operation (SLO/MLO) configuration. The QCN9274 dualmac firmware currently do not support SLO/MLO, if two PHYs are within the same chip. Due to this firmware crashes in split-phy QCN9274, while bringing up AP with MLO parameter enabled in QMI host capability request message. The QMI PHY capability learn is not required for split-phy QCN9274, if SLO/MLO is not supported within the same chip. Hence, disable QMI PHY capability learn support in split-phy QCN9274. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-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: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-14-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 1 + drivers/net/wireless/ath/ath12k/core.h | 5 +++++ drivers/net/wireless/ath/ath12k/mhi.c | 1 + drivers/net/wireless/ath/ath12k/qmi.c | 3 +++ 4 files changed, 10 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index ca3777c684b3..0d4640ff8d6f 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1218,6 +1218,7 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size, ab->dev = dev; ab->hif.bus = bus; ab->qmi.num_radios = U8_MAX; + ab->slo_capable = true; return ab; diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index f0a319ea57c1..a984171e4a08 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -842,6 +842,11 @@ struct ath12k_base { const struct hal_rx_ops *hal_rx_ops; + /* slo_capable denotes if the single/multi link operation + * is supported within the same chip (SoC). + */ + bool slo_capable; + /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath12k/mhi.c b/drivers/net/wireless/ath/ath12k/mhi.c index 50b9e44504f7..adb8c3ec1950 100644 --- a/drivers/net/wireless/ath/ath12k/mhi.c +++ b/drivers/net/wireless/ath/ath12k/mhi.c @@ -385,6 +385,7 @@ int ath12k_mhi_register(struct ath12k_pci *ab_pci) "failed to read board id\n"); } else if (board_id & OTP_VALID_DUALMAC_BOARD_ID_MASK) { dualmac = true; + ab->slo_capable = false; ath12k_dbg(ab, ATH12K_DBG_BOOT, "dualmac fw selected for board id: %x\n", board_id); } diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 0f0eaadc8418..92845ffff44a 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -2124,6 +2124,9 @@ static void ath12k_qmi_phy_cap_send(struct ath12k_base *ab) struct qmi_txn txn; int ret; + if (!ab->slo_capable) + goto out; + ret = qmi_txn_init(&ab->qmi.handle, &txn, qmi_wlanfw_phy_cap_resp_msg_v01_ei, &resp); if (ret < 0) -- cgit From 2f92b22beef74a4051ee04dba390b59080ad85e2 Mon Sep 17 00:00:00 2001 From: Lingbo Kong Date: Mon, 22 Jan 2024 03:53:35 -0500 Subject: wifi: ath12k: add processing for TWT enable event When ath12k send TWT enable command to firmware, firmware will return a TWT enable event to ath12k. Through the analysis of TWT enable event status, we can easily obtain the status of TWT enable command. It can be more convenient to debug TWT. This patch works with WCN7850 and QCN9274. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Lingbo Kong Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240122085336.3985-2-quic_lingbok@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.c | 35 ++++++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath12k/wmi.h | 5 +++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 7fc269eb4a0c..7d65dff7ab1e 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -162,6 +162,8 @@ static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = { .min_len = sizeof(struct wmi_probe_resp_tx_status_event) }, [WMI_TAG_VDEV_DELETE_RESP_EVENT] = { .min_len = sizeof(struct wmi_vdev_delete_resp_event) }, + [WMI_TAG_TWT_ENABLE_COMPLETE_EVENT] = { + .min_len = sizeof(struct wmi_twt_enable_event) }, }; static __le32 ath12k_wmi_tlv_hdr(u32 cmd, u32 len) @@ -6669,6 +6671,35 @@ ath12k_wmi_diag_event(struct ath12k_base *ab, struct sk_buff *skb) trace_ath12k_wmi_diag(ab, skb->data, skb->len); } +static void ath12k_wmi_twt_enable_event(struct ath12k_base *ab, + struct sk_buff *skb) +{ + const void **tb; + const struct wmi_twt_enable_event *ev; + 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 wmi twt enable status event tlv: %d\n", + ret); + return; + } + + ev = tb[WMI_TAG_TWT_ENABLE_COMPLETE_EVENT]; + if (!ev) { + ath12k_warn(ab, "failed to fetch twt enable wmi event\n"); + goto exit; + } + + ath12k_dbg(ab, ATH12K_DBG_MAC, "wmi twt enable event pdev id %u status %u\n", + le32_to_cpu(ev->pdev_id), + le32_to_cpu(ev->status)); + +exit: + kfree(tb); +} + static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; @@ -6764,10 +6795,12 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) case WMI_RFKILL_STATE_CHANGE_EVENTID: ath12k_rfkill_state_change_event(ab, skb); break; + case WMI_TWT_ENABLE_EVENTID: + ath12k_wmi_twt_enable_event(ab, skb); + break; /* add Unsupported events here */ case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID: case WMI_PEER_OPER_MODE_CHANGE_EVENTID: - case WMI_TWT_ENABLE_EVENTID: case WMI_TWT_DISABLE_EVENTID: case WMI_PDEV_DMA_RING_CFG_RSP_EVENTID: ath12k_dbg(ab, ATH12K_DBG_WMI, diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index d740701809c2..0819f16b09f6 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -4809,6 +4809,11 @@ struct wmi_rfkill_state_change_event { __le32 radio_state; } __packed; +struct wmi_twt_enable_event { + __le32 pdev_id; + __le32 status; +} __packed; + void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, struct ath12k_wmi_resource_config_arg *config); void ath12k_wmi_init_wcn7850(struct ath12k_base *ab, -- cgit From ad2b29ad94c3ed9e39f2eae50915c0f34af4f6fc Mon Sep 17 00:00:00 2001 From: Lingbo Kong Date: Mon, 22 Jan 2024 03:53:36 -0500 Subject: wifi: ath12k: add processing for TWT disable event When ath12k send TWT disable command to firmware, firmware will return a TWT disable event to ath12k. Through the analysis of TWT disable event status, we can easily obtain the status of TWT disable command. It can be more convenient to debug TWT. This patch works with WCN7850 and QCN9274. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Lingbo Kong Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240122085336.3985-3-quic_lingbok@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.c | 35 ++++++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath12k/wmi.h | 5 +++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 7d65dff7ab1e..5acbed4f64f2 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -164,6 +164,8 @@ static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = { .min_len = sizeof(struct wmi_vdev_delete_resp_event) }, [WMI_TAG_TWT_ENABLE_COMPLETE_EVENT] = { .min_len = sizeof(struct wmi_twt_enable_event) }, + [WMI_TAG_TWT_DISABLE_COMPLETE_EVENT] = { + .min_len = sizeof(struct wmi_twt_disable_event) }, }; static __le32 ath12k_wmi_tlv_hdr(u32 cmd, u32 len) @@ -6700,6 +6702,35 @@ exit: kfree(tb); } +static void ath12k_wmi_twt_disable_event(struct ath12k_base *ab, + struct sk_buff *skb) +{ + const void **tb; + const struct wmi_twt_disable_event *ev; + 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 wmi twt disable status event tlv: %d\n", + ret); + return; + } + + ev = tb[WMI_TAG_TWT_DISABLE_COMPLETE_EVENT]; + if (!ev) { + ath12k_warn(ab, "failed to fetch twt disable wmi event\n"); + goto exit; + } + + ath12k_dbg(ab, ATH12K_DBG_MAC, "wmi twt disable event pdev id %d status %u\n", + le32_to_cpu(ev->pdev_id), + le32_to_cpu(ev->status)); + +exit: + kfree(tb); +} + static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; @@ -6798,10 +6829,12 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) case WMI_TWT_ENABLE_EVENTID: ath12k_wmi_twt_enable_event(ab, skb); break; + case WMI_TWT_DISABLE_EVENTID: + ath12k_wmi_twt_disable_event(ab, skb); + break; /* add Unsupported events here */ case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID: case WMI_PEER_OPER_MODE_CHANGE_EVENTID: - case WMI_TWT_DISABLE_EVENTID: case WMI_PDEV_DMA_RING_CFG_RSP_EVENTID: ath12k_dbg(ab, ATH12K_DBG_WMI, "ignoring unsupported event 0x%x\n", id); diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 0819f16b09f6..dceb55ca153a 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -4814,6 +4814,11 @@ struct wmi_twt_enable_event { __le32 status; } __packed; +struct wmi_twt_disable_event { + __le32 pdev_id; + __le32 status; +} __packed; + void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, struct ath12k_wmi_resource_config_arg *config); void ath12k_wmi_init_wcn7850(struct ath12k_base *ab, -- cgit From e7c7fbb582bc7936cf7ee744f62b82bd46a7d4a8 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Thu, 25 Jan 2024 21:15:55 +0530 Subject: wifi: ath12k: refactor the rfkill worker Currently, the rfkill worker handler access mac80211 HW from the radio/link structure. This is will be incorrect for single wiphy model, as they will hold multiple link/radio structures. To fix this, access mac80211 HW based on the number of hardware in the SoC/chip. This approach makes the rfkill worker handler compatible with both multi wiphy and single wiphy models. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240125154555.3169706-1-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 0d4640ff8d6f..b82550b35149 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -909,21 +909,29 @@ static void ath12k_rfkill_work(struct work_struct *work) { struct ath12k_base *ab = container_of(work, struct ath12k_base, rfkill_work); struct ath12k *ar; + struct ath12k_hw *ah; struct ieee80211_hw *hw; bool rfkill_radio_on; - int i; + int i, j; spin_lock_bh(&ab->base_lock); rfkill_radio_on = ab->rfkill_radio_on; spin_unlock_bh(&ab->base_lock); - for (i = 0; i < ab->num_radios; i++) { - ar = ab->pdevs[i].ar; - if (!ar) + for (i = 0; i < ab->num_hw; i++) { + ah = ab->ah[i]; + if (!ah) continue; - hw = ath12k_ar_to_hw(ar); - ath12k_mac_rfkill_enable_radio(ar, rfkill_radio_on); + for (j = 0; j < ah->num_radio; j++) { + ar = &ah->radio[j]; + if (!ar) + continue; + + ath12k_mac_rfkill_enable_radio(ar, rfkill_radio_on); + } + + hw = ah->hw; wiphy_rfkill_set_hw_state(hw->wiphy, !rfkill_radio_on); } } -- cgit From 54ca3308a23c5fc0cd5c53d86918217834626c44 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 1 Feb 2024 11:58:30 +0800 Subject: wifi: ath12k: enable 802.11 power save mode in station mode To reduce power consumption enable 802.11 power save mode in station mode. This allows both radio and CPU to sleep more. Only enable the mode on WCN7850, other chips don't support it for now. To test that power save mode is running, run below command and check there is no NULL Data frame seen by a sniffer: iw dev set power_save off And run below command, then check there is a NULL Data frame in sniffer: iw dev set power_save on Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240201035830.2534-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/core.h | 1 + drivers/net/wireless/ath/ath12k/hw.c | 6 ++++ drivers/net/wireless/ath/ath12k/hw.h | 2 ++ drivers/net/wireless/ath/ath12k/mac.c | 54 ++++++++++++++++++++++++++++++++++ 4 files changed, 63 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index a984171e4a08..97e5a0ccd233 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -266,6 +266,7 @@ struct ath12k_vif { u8 tx_encap_type; u8 vdev_stats_id; u32 punct_bitmap; + bool ps; }; struct ath12k_vif_iter { diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index a9adb547c83d..6e2242a79a2f 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -918,6 +918,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .max_mlo_peer = 256, .otp_board_id_register = QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB, + + .supports_sta_ps = false, }, { .name = "wcn7850 hw2.0", @@ -986,6 +988,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .max_mlo_peer = 32, .otp_board_id_register = 0, + + .supports_sta_ps = true, }, { .name = "qcn9274 hw2.0", @@ -1052,6 +1056,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .max_mlo_peer = 256, .otp_board_id_register = QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB, + + .supports_sta_ps = false, }, }; diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 2e9c3b05d75a..87965980b938 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -209,6 +209,8 @@ struct ath12k_hw_params { u16 max_mlo_peer; u32 otp_board_id_register; + + bool supports_sta_ps; }; struct ath12k_hw_ops { diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 6ef55876e7df..fb5bf500ed87 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -2510,12 +2510,60 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif, return ret; } +static void ath12k_mac_vif_setup_ps(struct ath12k_vif *arvif) +{ + struct ath12k *ar = arvif->ar; + struct ieee80211_vif *vif = arvif->vif; + struct ieee80211_conf *conf = &ath12k_ar_to_hw(ar)->conf; + enum wmi_sta_powersave_param param; + enum wmi_sta_ps_mode psmode; + int ret; + int timeout; + bool enable_ps; + + lockdep_assert_held(&ar->conf_mutex); + + if (vif->type != NL80211_IFTYPE_STATION) + return; + + enable_ps = arvif->ps; + if (enable_ps) { + psmode = WMI_STA_PS_MODE_ENABLED; + param = WMI_STA_PS_PARAM_INACTIVITY_TIME; + + timeout = conf->dynamic_ps_timeout; + if (timeout == 0) { + /* firmware doesn't like 0 */ + timeout = ieee80211_tu_to_usec(vif->bss_conf.beacon_int) / 1000; + } + + ret = ath12k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, + timeout); + if (ret) { + ath12k_warn(ar->ab, "failed to set inactivity time for vdev %d: %i\n", + arvif->vdev_id, ret); + return; + } + } else { + psmode = WMI_STA_PS_MODE_DISABLED; + } + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev %d psmode %s\n", + arvif->vdev_id, psmode ? "enable" : "disable"); + + ret = ath12k_wmi_pdev_set_ps_mode(ar, arvif->vdev_id, psmode); + if (ret) + ath12k_warn(ar->ab, "failed to set sta power save mode %d for vdev %d: %d\n", + psmode, arvif->vdev_id, ret); +} + static void ath12k_mac_bss_info_changed(struct ath12k *ar, struct ath12k_vif *arvif, struct ieee80211_bss_conf *info, u64 changed) { struct ieee80211_vif *vif = arvif->vif; + struct ieee80211_vif_cfg *vif_cfg = &vif->cfg; struct cfg80211_chan_def def; u32 param_id, param_value; enum nl80211_band band; @@ -2788,6 +2836,12 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar, if (changed & BSS_CHANGED_EHT_PUNCTURING) arvif->punct_bitmap = info->eht_puncturing; + + if (changed & BSS_CHANGED_PS && + ar->ab->hw_params->supports_sta_ps) { + arvif->ps = vif_cfg->ps; + ath12k_mac_vif_setup_ps(arvif); + } } static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, -- cgit From b802e7b7e771dee3377d071418281f8b64d2d832 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Fri, 2 Feb 2024 10:35:47 +0800 Subject: wifi: ath11k: initialize rx_mcs_80 and rx_mcs_160 before use Currently in ath11k_peer_assoc_h_he() rx_mcs_80 and rx_mcs_160 are used to calculate max_nss, see if (support_160) max_nss = min(rx_mcs_80, rx_mcs_160); else max_nss = rx_mcs_80; Kernel test robot complains on uninitialized symbols: drivers/net/wireless/ath/ath11k/mac.c:2321 ath11k_peer_assoc_h_he() error: uninitialized symbol 'rx_mcs_80'. drivers/net/wireless/ath/ath11k/mac.c:2321 ath11k_peer_assoc_h_he() error: uninitialized symbol 'rx_mcs_160'. drivers/net/wireless/ath/ath11k/mac.c:2323 ath11k_peer_assoc_h_he() error: uninitialized symbol 'rx_mcs_80'. This is because there are some code paths that never set them, so the assignment of max_nss can come from uninitialized variables. This could result in some unknown issues since a wrong peer_nss might be passed to firmware. Change to initialize them to an invalid value at the beginning. This makes sense because even max_nss gets an invalid value, due to either or both of them being invalid, we can get an valid peer_nss with following guard: arg->peer_nss = min(sta->deflink.rx_nss, max_nss) Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Fixes: 3db26ecf7114 ("ath11k: calculate the correct NSS of peer for HE capabilities") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202401311243.NyXwWZxP-lkp@intel.com/ Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240202023547.11141-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index df1b1ee71881..10cfb60e14a0 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -2294,6 +2294,8 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar, mcs_160_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); mcs_80_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80); + /* Initialize rx_mcs_160 to 9 which is an invalid value */ + rx_mcs_160 = 9; if (support_160) { for (i = 7; i >= 0; i--) { u8 mcs_160 = (mcs_160_map >> (2 * i)) & 3; @@ -2305,6 +2307,8 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar, } } + /* Initialize rx_mcs_80 to 9 which is an invalid value */ + rx_mcs_80 = 9; for (i = 7; i >= 0; i--) { u8 mcs_80 = (mcs_80_map >> (2 * i)) & 3; -- cgit From b82fb7ef690bd929b88d9aab1d191ff502ed9029 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Fri, 2 Feb 2024 10:40:11 +0800 Subject: wifi: ath11k: initialize eirp_power before use Currently, at the end of ath11k_mac_fill_reg_tpc_info(), the reg_tpc_info struct is populated, including the following: reg_tpc_info->is_psd_power = is_psd_power; reg_tpc_info->eirp_power = eirp_power; Kernel test robot complains on uninitialized symbol: drivers/net/wireless/ath/ath11k/mac.c:7949 ath11k_mac_fill_reg_tpc_info() error: uninitialized symbol 'eirp_power'. This is because there are some code paths that never set eirp_power, so the assignment of reg_tpc_info->eirp_power can come from an uninitialized variable. Functionally this is OK since the eirp_power only has meaning when is_psd_power is true, and all code paths which set is_psd_power to true also set eirp_power. However, to keep the robot happy, always initialize eirp_power before use. Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Fixes: 92425f788fee ("wifi: ath11k: fill parameters for vdev set tpc power WMI command") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202401311243.NyXwWZxP-lkp@intel.com/ Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240202024011.11341-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 10cfb60e14a0..dc2bf13f00c1 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -7597,7 +7597,8 @@ void ath11k_mac_fill_reg_tpc_info(struct ath11k *ar, u8 pwr_lvl_idx, num_pwr_levels, pwr_reduction; bool is_psd_power = false, is_tpe_present = false; s8 max_tx_power[IEEE80211_MAX_NUM_PWR_LEVEL], - psd_power, tx_power, eirp_power; + psd_power, tx_power; + s8 eirp_power = 0; u16 start_freq, center_freq; chan = ctx->def.chan; -- cgit From 4f684533afe2317b5338209cbad4551bae7949a2 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:27 +0200 Subject: wifi: ath12k: fix broken structure wmi_vdev_create_cmd Current structure wmi_vdev_create_cmd is not matched to the firmware definition. So update it. And update vdev_stats_id_valid for vdev_stats_id. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-2-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.c | 3 +++ drivers/net/wireless/ath/ath12k/wmi.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 5acbed4f64f2..49ac8d4ccbef 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -824,6 +824,9 @@ int ath12k_wmi_vdev_create(struct ath12k *ar, u8 *macaddr, cmd->vdev_stats_id = cpu_to_le32(args->if_stats_id); ether_addr_copy(cmd->vdev_macaddr.addr, macaddr); + if (args->if_stats_id != ATH12K_INVAL_VDEV_STATS_ID) + cmd->vdev_stats_id_valid = cpu_to_le32(BIT(0)); + ptr = skb->data + sizeof(*cmd); len = WMI_NUM_SUPPORTED_BAND_MAX * sizeof(*txrx_streams); diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index dceb55ca153a..61b2dd1d32cd 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2724,6 +2724,9 @@ struct wmi_vdev_create_cmd { struct ath12k_wmi_mac_addr_params vdev_macaddr; __le32 num_cfg_txrx_streams; __le32 pdev_id; + __le32 mbssid_flags; + __le32 mbssid_tx_vdev_id; + __le32 vdev_stats_id_valid; __le32 vdev_stats_id; } __packed; -- cgit From 019b58dcb6ed267e17b7efd03ec8575c1b67d942 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:27 +0200 Subject: wifi: ath12k: fix incorrect logic of calculating vdev_stats_id During calculate vdev_stats_id, will compare vdev_stats_id with ATH12K_INVAL_VDEV_STATS_ID by '<='. If vdev_stats_id is relatively small, then assign ATH12K_INVAL_VDEV_STATS_ID to vdev_stats_id. This logic is incorrect. Firstly, should use '>=' instead of '<=' to check if this u8 variable exceeds the max valid range. Secondly, should use the maximum value as comparison value. Correct comparison symbols and use the maximum value ATH12K_MAX_VDEV_STATS_ID for comparison. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-3-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index fb5bf500ed87..078dda43dded 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5421,7 +5421,7 @@ ath12k_mac_get_vdev_stats_id(struct ath12k_vif *arvif) do { if (ab->free_vdev_stats_id_map & (1LL << vdev_stats_id)) { vdev_stats_id++; - if (vdev_stats_id <= ATH12K_INVAL_VDEV_STATS_ID) { + if (vdev_stats_id >= ATH12K_MAX_VDEV_STATS_ID) { vdev_stats_id = ATH12K_INVAL_VDEV_STATS_ID; break; } -- cgit From ef860c6a3adfc5f3fc5b5c96fc0e1856c944a1d1 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:27 +0200 Subject: wifi: ath12k: change interface combination for P2P mode Current interface combination doesn't support P2P mode. Change the combination for P2P mode. Also, there is a bug that when mesh is enabled but ap is not enabled. In this situation, the mesh's max_interface of interface combination won't be set. So assign the max_interfaces for mesh directly. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-4-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 078dda43dded..f2920a3401c6 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7539,9 +7539,10 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah) struct ieee80211_iface_combination *combinations; struct ieee80211_iface_limit *limits; int n_limits, max_interfaces; - bool ap, mesh; + 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); mesh = IS_ENABLED(CONFIG_MAC80211_MESH) && ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_MESH_POINT); @@ -7550,9 +7551,15 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah) if (!combinations) return -ENOMEM; - if (ap || mesh) { + if ((ap || mesh) && !p2p) { n_limits = 2; max_interfaces = 16; + } else if (p2p) { + n_limits = 3; + if (ap || mesh) + max_interfaces = 16; + else + max_interfaces = 3; } else { n_limits = 1; max_interfaces = 1; @@ -7567,14 +7574,22 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah) limits[0].max = 1; limits[0].types |= BIT(NL80211_IFTYPE_STATION); - if (ap) { + if (ap || mesh || p2p) limits[1].max = max_interfaces; + + if (ap) limits[1].types |= BIT(NL80211_IFTYPE_AP); - } if (mesh) limits[1].types |= BIT(NL80211_IFTYPE_MESH_POINT); + if (p2p) { + limits[1].types |= BIT(NL80211_IFTYPE_P2P_CLIENT) | + 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; -- cgit From 575ec73cb8803b4e149df5ff5cdb9f1ce3735554 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:28 +0200 Subject: wifi: ath12k: add P2P IE in beacon template P2P Element is a necessary component of P2P protocol communication. It contains the Vendor Specific Information Element which includes the WFA OUI and an OUI Type indicating P2P. Add P2P IE in beacon template, and implement WMI interface for it. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-5-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 84 ++++++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath12k/wmi.c | 42 ++++++++++++++++++ drivers/net/wireless/ath/ath12k/wmi.h | 8 ++++ 3 files changed, 132 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index f2920a3401c6..7bfc6ee6567c 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -1139,6 +1139,63 @@ static int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed) return ret; } +static int ath12k_mac_setup_bcn_p2p_ie(struct ath12k_vif *arvif, + struct sk_buff *bcn) +{ + struct ath12k *ar = arvif->ar; + struct ieee80211_mgmt *mgmt; + const u8 *p2p_ie; + int ret; + + mgmt = (void *)bcn->data; + p2p_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P, + mgmt->u.beacon.variable, + bcn->len - (mgmt->u.beacon.variable - + bcn->data)); + if (!p2p_ie) { + ath12k_warn(ar->ab, "no P2P ie found in beacon\n"); + return -ENOENT; + } + + ret = ath12k_wmi_p2p_go_bcn_ie(ar, arvif->vdev_id, p2p_ie); + if (ret) { + ath12k_warn(ar->ab, "failed to submit P2P GO bcn ie for vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + return 0; +} + +static int ath12k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui, + u8 oui_type, size_t ie_offset) +{ + const u8 *next, *end; + size_t len; + u8 *ie; + + if (WARN_ON(skb->len < ie_offset)) + return -EINVAL; + + ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type, + skb->data + ie_offset, + skb->len - ie_offset); + if (!ie) + return -ENOENT; + + len = ie[1] + 2; + end = skb->data + skb->len; + next = ie + len; + + if (WARN_ON(next > end)) + return -EINVAL; + + memmove(ie, next, end - next); + skb_trim(skb, skb->len - len); + + return 0; +} + static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) { struct ath12k *ar = arvif->ar; @@ -1171,14 +1228,37 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) ies, (skb_tail_pointer(bcn) - ies))) arvif->wpaie_present = true; - ret = ath12k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn); + if (arvif->vif->type == NL80211_IFTYPE_AP && arvif->vif->p2p) { + ret = ath12k_mac_setup_bcn_p2p_ie(arvif, bcn); + if (ret) { + ath12k_warn(ab, "failed to setup P2P GO bcn ie: %d\n", + ret); + goto free_bcn_skb; + } - kfree_skb(bcn); + /* P2P IE is inserted by firmware automatically (as + * configured above) so remove it from the base beacon + * template to avoid duplicate P2P IEs in beacon frames. + */ + ret = ath12k_mac_remove_vendor_ie(bcn, WLAN_OUI_WFA, + WLAN_OUI_TYPE_WFA_P2P, + offsetof(struct ieee80211_mgmt, + u.beacon.variable)); + if (ret) { + ath12k_warn(ab, "failed to remove P2P vendor ie: %d\n", + ret); + goto free_bcn_skb; + } + } + + ret = ath12k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn); if (ret) ath12k_warn(ab, "failed to submit beacon template command: %d\n", ret); +free_bcn_skb: + kfree_skb(bcn); return ret; } diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 49ac8d4ccbef..61fc7ec86985 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -1712,6 +1712,48 @@ int ath12k_wmi_send_bcn_offload_control_cmd(struct ath12k *ar, return ret; } +int ath12k_wmi_p2p_go_bcn_ie(struct ath12k *ar, u32 vdev_id, + const u8 *p2p_ie) +{ + struct ath12k_wmi_pdev *wmi = ar->wmi; + struct wmi_p2p_go_set_beacon_ie_cmd *cmd; + size_t p2p_ie_len, aligned_len; + struct wmi_tlv *tlv; + struct sk_buff *skb; + void *ptr; + int ret, len; + + p2p_ie_len = p2p_ie[1] + 2; + aligned_len = roundup(p2p_ie_len, sizeof(u32)); + + len = sizeof(*cmd) + TLV_HDR_SIZE + aligned_len; + + skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + ptr = skb->data; + cmd = ptr; + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_P2P_GO_SET_BEACON_IE, + sizeof(*cmd)); + cmd->vdev_id = cpu_to_le32(vdev_id); + cmd->ie_buf_len = cpu_to_le32(p2p_ie_len); + + ptr += sizeof(*cmd); + tlv = ptr; + tlv->header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_ARRAY_BYTE, + aligned_len); + memcpy(tlv->value, p2p_ie, p2p_ie_len); + + ret = ath12k_wmi_cmd_send(wmi, skb, WMI_P2P_GO_SET_BEACON_IE); + if (ret) { + ath12k_warn(ar->ab, "failed to send WMI_P2P_GO_SET_BEACON_IE\n"); + dev_kfree_skb(skb); + } + + return ret; +} + int ath12k_wmi_bcn_tmpl(struct ath12k *ar, u32 vdev_id, struct ieee80211_mutable_offsets *offs, struct sk_buff *bcn) diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 61b2dd1d32cd..c5002468b1de 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -3518,6 +3518,12 @@ struct wmi_bcn_tmpl_cmd { __le32 esp_ie_offset; } __packed; +struct wmi_p2p_go_set_beacon_ie_cmd { + __le32 tlv_header; + __le32 vdev_id; + __le32 ie_buf_len; +} __packed; + struct wmi_vdev_install_key_cmd { __le32 tlv_header; __le32 vdev_id; @@ -4831,6 +4837,8 @@ int ath12k_wmi_cmd_send(struct ath12k_wmi_pdev *wmi, struct sk_buff *skb, struct sk_buff *ath12k_wmi_alloc_skb(struct ath12k_wmi_base *wmi_sc, u32 len); int ath12k_wmi_mgmt_send(struct ath12k *ar, u32 vdev_id, u32 buf_id, struct sk_buff *frame); +int ath12k_wmi_p2p_go_bcn_ie(struct ath12k *ar, u32 vdev_id, + const u8 *p2p_ie); int ath12k_wmi_bcn_tmpl(struct ath12k *ar, u32 vdev_id, struct ieee80211_mutable_offsets *offs, struct sk_buff *bcn); -- cgit From 9411eecb60cbc36edcbd47176e2bec85776e62e3 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:28 +0200 Subject: wifi: ath12k: implement handling of P2P NoA event The Notice of Absence (NoA) attribute is used by the P2P Group Owner to signal its absence due to power save timing, concurrent operation, or off-channel scanning. It is also used in the P2P Presence Request-Response mechanism. The NoA attribute shall be present in the P2P IE in the beacon frames transmitted by a P2P Group Owner when a NoA schedule is being advertised, or when the CTWindow is non-zero. So add support to update P2P information after P2P GO is up through event WMI_P2P_NOA_EVENTID, and always put it in probe resp. Create p2p.c and p2p.h for P2P related functions and definitions. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-6-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/Makefile | 3 +- drivers/net/wireless/ath/ath12k/mac.c | 28 +++++- drivers/net/wireless/ath/ath12k/p2p.c | 142 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/p2p.h | 23 +++++ drivers/net/wireless/ath/ath12k/wmi.c | 57 ++++++++++++- drivers/net/wireless/ath/ath12k/wmi.h | 31 +++++++ 6 files changed, 281 insertions(+), 3 deletions(-) create mode 100644 drivers/net/wireless/ath/ath12k/p2p.c create mode 100644 drivers/net/wireless/ath/ath12k/p2p.h diff --git a/drivers/net/wireless/ath/ath12k/Makefile b/drivers/net/wireless/ath/ath12k/Makefile index 0d723e85cf6b..71669f94ff75 100644 --- a/drivers/net/wireless/ath/ath12k/Makefile +++ b/drivers/net/wireless/ath/ath12k/Makefile @@ -20,7 +20,8 @@ ath12k-y += core.o \ mhi.o \ pci.o \ dp_mon.o \ - fw.o + fw.o \ + p2p.o ath12k-$(CONFIG_ATH12K_TRACING) += trace.o diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 7bfc6ee6567c..ceb5be5a6a95 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5173,6 +5173,27 @@ static int ath12k_mac_mgmt_tx(struct ath12k *ar, struct sk_buff *skb, return 0; } +static void ath12k_mac_add_p2p_noa_ie(struct ath12k *ar, + struct ieee80211_vif *vif, + struct sk_buff *skb, + bool is_prb_rsp) +{ + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + + if (likely(!is_prb_rsp)) + return; + + spin_lock_bh(&ar->data_lock); + + if (arvif->u.ap.noa_data && + !pskb_expand_head(skb, 0, arvif->u.ap.noa_len, + GFP_ATOMIC)) + skb_put_data(skb, arvif->u.ap.noa_data, + arvif->u.ap.noa_len); + + spin_unlock_bh(&ar->data_lock); +} + static void ath12k_mac_op_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) @@ -5196,10 +5217,11 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw, skb_cb->flags |= ATH12K_SKB_CIPHER_SET; } + is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control); + if (info_flags & IEEE80211_TX_CTL_HW_80211_ENCAP) { skb_cb->flags |= ATH12K_SKB_HW_80211_ENCAP; } else if (ieee80211_is_mgmt(hdr->frame_control)) { - is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control); ret = ath12k_mac_mgmt_tx(ar, skb, is_prb_rsp); if (ret) { ath12k_warn(ar->ab, "failed to queue management frame %d\n", @@ -5209,6 +5231,10 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw, return; } + /* This is case only for P2P_GO */ + if (vif->type == NL80211_IFTYPE_AP && vif->p2p) + ath12k_mac_add_p2p_noa_ie(ar, vif, skb, is_prb_rsp); + ret = ath12k_dp_tx(ar, arvif, skb); if (ret) { ath12k_warn(ar->ab, "failed to transmit frame %d\n", ret); diff --git a/drivers/net/wireless/ath/ath12k/p2p.c b/drivers/net/wireless/ath/ath12k/p2p.c new file mode 100644 index 000000000000..61e919b23b16 --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/p2p.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: ISC +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include "core.h" +#include "mac.h" +#include "p2p.h" + +static void ath12k_p2p_noa_ie_fill(u8 *data, size_t len, + const struct ath12k_wmi_p2p_noa_info *noa) +{ + struct ieee80211_p2p_noa_attr *noa_attr; + u8 ctwindow = le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_CTWIN_TU); + bool oppps = le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_OPP_PS); + __le16 *noa_attr_len; + u16 attr_len; + u8 noa_descriptors = le32_get_bits(noa->noa_attr, + WMI_P2P_NOA_INFO_DESC_NUM); + int i; + + /* P2P IE */ + data[0] = WLAN_EID_VENDOR_SPECIFIC; + data[1] = len - 2; + data[2] = (WLAN_OUI_WFA >> 16) & 0xff; + data[3] = (WLAN_OUI_WFA >> 8) & 0xff; + data[4] = (WLAN_OUI_WFA >> 0) & 0xff; + data[5] = WLAN_OUI_TYPE_WFA_P2P; + + /* NOA ATTR */ + data[6] = IEEE80211_P2P_ATTR_ABSENCE_NOTICE; + noa_attr_len = (__le16 *)&data[7]; /* 2 bytes */ + noa_attr = (struct ieee80211_p2p_noa_attr *)&data[9]; + + noa_attr->index = le32_get_bits(noa->noa_attr, + WMI_P2P_NOA_INFO_INDEX); + noa_attr->oppps_ctwindow = ctwindow; + if (oppps) + noa_attr->oppps_ctwindow |= IEEE80211_P2P_OPPPS_ENABLE_BIT; + + for (i = 0; i < noa_descriptors; i++) { + noa_attr->desc[i].count = + __le32_to_cpu(noa->descriptors[i].type_count); + noa_attr->desc[i].duration = noa->descriptors[i].duration; + noa_attr->desc[i].interval = noa->descriptors[i].interval; + noa_attr->desc[i].start_time = noa->descriptors[i].start_time; + } + + attr_len = 2; /* index + oppps_ctwindow */ + attr_len += noa_descriptors * sizeof(struct ieee80211_p2p_noa_desc); + *noa_attr_len = __cpu_to_le16(attr_len); +} + +static size_t ath12k_p2p_noa_ie_len_compute(const struct ath12k_wmi_p2p_noa_info *noa) +{ + size_t len = 0; + + if (!(le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_DESC_NUM)) && + !(le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_OPP_PS))) + return 0; + + len += 1 + 1 + 4; /* EID + len + OUI */ + len += 1 + 2; /* noa attr + attr len */ + len += 1 + 1; /* index + oppps_ctwindow */ + len += le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_DESC_NUM) * + sizeof(struct ieee80211_p2p_noa_desc); + + return len; +} + +static void ath12k_p2p_noa_ie_assign(struct ath12k_vif *arvif, void *ie, + size_t len) +{ + struct ath12k *ar = arvif->ar; + + lockdep_assert_held(&ar->data_lock); + + kfree(arvif->u.ap.noa_data); + + arvif->u.ap.noa_data = ie; + arvif->u.ap.noa_len = len; +} + +static void __ath12k_p2p_noa_update(struct ath12k_vif *arvif, + const struct ath12k_wmi_p2p_noa_info *noa) +{ + struct ath12k *ar = arvif->ar; + void *ie; + size_t len; + + lockdep_assert_held(&ar->data_lock); + + ath12k_p2p_noa_ie_assign(arvif, NULL, 0); + + len = ath12k_p2p_noa_ie_len_compute(noa); + if (!len) + return; + + ie = kmalloc(len, GFP_ATOMIC); + if (!ie) + return; + + ath12k_p2p_noa_ie_fill(ie, len, noa); + ath12k_p2p_noa_ie_assign(arvif, ie, len); +} + +void ath12k_p2p_noa_update(struct ath12k_vif *arvif, + const struct ath12k_wmi_p2p_noa_info *noa) +{ + struct ath12k *ar = arvif->ar; + + spin_lock_bh(&ar->data_lock); + __ath12k_p2p_noa_update(arvif, noa); + spin_unlock_bh(&ar->data_lock); +} + +static void ath12k_p2p_noa_update_vdev_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_p2p_noa_arg *arg = data; + + if (arvif->vdev_id != arg->vdev_id) + return; + + ath12k_p2p_noa_update(arvif, arg->noa); +} + +void ath12k_p2p_noa_update_by_vdev_id(struct ath12k *ar, u32 vdev_id, + const struct ath12k_wmi_p2p_noa_info *noa) +{ + struct ath12k_p2p_noa_arg arg = { + .vdev_id = vdev_id, + .noa = noa, + }; + + ieee80211_iterate_active_interfaces_atomic(ath12k_ar_to_hw(ar), + IEEE80211_IFACE_ITER_NORMAL, + ath12k_p2p_noa_update_vdev_iter, + &arg); +} diff --git a/drivers/net/wireless/ath/ath12k/p2p.h b/drivers/net/wireless/ath/ath12k/p2p.h new file mode 100644 index 000000000000..b6f177fe4ff4 --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/p2p.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: ISC */ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.. + */ + +#ifndef ATH12K_P2P_H +#define ATH12K_P2P_H + +#include "wmi.h" + +struct ath12k_wmi_p2p_noa_info; + +struct ath12k_p2p_noa_arg { + u32 vdev_id; + const struct ath12k_wmi_p2p_noa_info *noa; +}; + +void ath12k_p2p_noa_update(struct ath12k_vif *arvif, + const struct ath12k_wmi_p2p_noa_info *noa); +void ath12k_p2p_noa_update_by_vdev_id(struct ath12k *ar, u32 vdev_id, + const struct ath12k_wmi_p2p_noa_info *noa); + +#endif diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 61fc7ec86985..ff086428fb0c 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -19,6 +19,7 @@ #include "mac.h" #include "hw.h" #include "peer.h" +#include "p2p.h" struct ath12k_wmi_svc_ready_parse { bool wmi_svc_bitmap_done; @@ -166,6 +167,10 @@ static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = { .min_len = sizeof(struct wmi_twt_enable_event) }, [WMI_TAG_TWT_DISABLE_COMPLETE_EVENT] = { .min_len = sizeof(struct wmi_twt_disable_event) }, + [WMI_TAG_P2P_NOA_INFO] = { + .min_len = sizeof(struct ath12k_wmi_p2p_noa_info) }, + [WMI_TAG_P2P_NOA_EVENT] = { + .min_len = sizeof(struct wmi_p2p_noa_event) }, }; static __le32 ath12k_wmi_tlv_hdr(u32 cmd, u32 len) @@ -1053,7 +1058,7 @@ int ath12k_wmi_vdev_start(struct ath12k *ar, struct wmi_vdev_start_req_arg *arg, tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, 0); /* Note: This is a nested TLV containing: - * [wmi_tlv][wmi_p2p_noa_descriptor][wmi_tlv].. + * [wmi_tlv][ath12k_wmi_p2p_noa_descriptor][wmi_tlv].. */ ptr += sizeof(*tlv); @@ -6678,6 +6683,53 @@ static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab, kfree(tb); } +static int ath12k_wmi_p2p_noa_event(struct ath12k_base *ab, + struct sk_buff *skb) +{ + const void **tb; + const struct wmi_p2p_noa_event *ev; + const struct ath12k_wmi_p2p_noa_info *noa; + struct ath12k *ar; + int ret, vdev_id; + + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath12k_warn(ab, "failed to parse P2P NoA TLV: %d\n", ret); + return ret; + } + + ev = tb[WMI_TAG_P2P_NOA_EVENT]; + noa = tb[WMI_TAG_P2P_NOA_INFO]; + + if (!ev || !noa) { + ret = -EPROTO; + goto out; + } + + vdev_id = __le32_to_cpu(ev->vdev_id); + + ath12k_dbg(ab, ATH12K_DBG_WMI, + "wmi tlv p2p noa vdev_id %i descriptors %u\n", + vdev_id, le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_DESC_NUM)); + + ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id); + if (!ar) { + ath12k_warn(ab, "invalid vdev id %d in P2P NoA event\n", + vdev_id); + ret = -EINVAL; + goto out; + } + + ath12k_p2p_noa_update_by_vdev_id(ar, vdev_id, noa); + + ret = 0; + +out: + kfree(tb); + return ret; +} + static void ath12k_rfkill_state_change_event(struct ath12k_base *ab, struct sk_buff *skb) { @@ -6877,6 +6929,9 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) case WMI_TWT_DISABLE_EVENTID: ath12k_wmi_twt_disable_event(ab, skb); break; + 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: diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index c5002468b1de..be6bf93f091d 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -3504,6 +3504,37 @@ struct wmi_get_pdev_temperature_cmd { __le32 pdev_id; } __packed; +#define WMI_P2P_MAX_NOA_DESCRIPTORS 4 + +struct wmi_p2p_noa_event { + __le32 vdev_id; +} __packed; + +struct ath12k_wmi_p2p_noa_descriptor { + __le32 type_count; /* 255: continuous schedule, 0: reserved */ + __le32 duration; /* Absent period duration in micro seconds */ + __le32 interval; /* Absent period interval in micro seconds */ + __le32 start_time; /* 32 bit tsf time when in starts */ +} __packed; + +#define WMI_P2P_NOA_INFO_CHANGED_FLAG BIT(0) +#define WMI_P2P_NOA_INFO_INDEX GENMASK(15, 8) +#define WMI_P2P_NOA_INFO_OPP_PS BIT(16) +#define WMI_P2P_NOA_INFO_CTWIN_TU GENMASK(23, 17) +#define WMI_P2P_NOA_INFO_DESC_NUM GENMASK(31, 24) + +struct ath12k_wmi_p2p_noa_info { + /* Bit 0 - Flag to indicate an update in NOA schedule + * Bits 7-1 - Reserved + * Bits 15-8 - Index (identifies the instance of NOA sub element) + * Bit 16 - Opp PS state of the AP + * Bits 23-17 - Ctwindow in TUs + * Bits 31-24 - Number of NOA descriptors + */ + __le32 noa_attr; + struct ath12k_wmi_p2p_noa_descriptor descriptors[WMI_P2P_MAX_NOA_DESCRIPTORS]; +} __packed; + #define WMI_BEACON_TX_BUFFER_SIZE 512 struct wmi_bcn_tmpl_cmd { -- cgit From 2830bc9e784ff18ecb0eafd53d0bdae32c478c16 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:29 +0200 Subject: wifi: ath12k: implement remain on channel for P2P mode Implement remain on channel for p2p mode in ath12k_ops: ath12k_mac_op_remain_on_channel ath12k_mac_op_cancel_remain_on_channel P2P device can trigger ROC scan. Then keep listening or sending management frames on particular channels. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-7-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 1 + drivers/net/wireless/ath/ath12k/mac.c | 122 +++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/wmi.c | 8 +++ 3 files changed, 131 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index b82550b35149..391b6fb2bd42 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -988,6 +988,7 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) ath12k_mac_drain_tx(ar); complete(&ar->scan.started); complete(&ar->scan.completed); + complete(&ar->scan.on_channel); complete(&ar->peer_assoc_done); complete(&ar->peer_delete_done); complete(&ar->install_key_done); diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index ceb5be5a6a95..dbaef009e972 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7451,6 +7451,125 @@ static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); } +static int ath12k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + + ar = ath12k_ah_to_ar(ah); + + mutex_lock(&ar->conf_mutex); + + spin_lock_bh(&ar->data_lock); + ar->scan.roc_notify = false; + spin_unlock_bh(&ar->data_lock); + + ath12k_scan_abort(ar); + + mutex_unlock(&ar->conf_mutex); + + cancel_delayed_work_sync(&ar->scan.timeout); + + return 0; +} + +static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel *chan, + int duration, + enum ieee80211_roc_type type) +{ + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k_wmi_scan_req_arg arg; + struct ath12k *ar; + u32 scan_time_msec; + int ret; + + ar = ath12k_ah_to_ar(ah); + + mutex_lock(&ar->conf_mutex); + spin_lock_bh(&ar->data_lock); + + switch (ar->scan.state) { + case ATH12K_SCAN_IDLE: + reinit_completion(&ar->scan.started); + reinit_completion(&ar->scan.completed); + 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.roc_freq = chan->center_freq; + ar->scan.roc_notify = true; + ret = 0; + break; + case ATH12K_SCAN_STARTING: + case ATH12K_SCAN_RUNNING: + case ATH12K_SCAN_ABORTING: + ret = -EBUSY; + break; + } + + spin_unlock_bh(&ar->data_lock); + + if (ret) + goto exit; + + 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; + } + + 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_flags |= WMI_SCAN_FLAG_PASSIVE; + 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; + } + + ret = wait_for_completion_timeout(&ar->scan.on_channel, 3 * HZ); + if (ret == 0) { + ath12k_warn(ar->ab, "failed to switch to channel for roc scan\n"); + ret = ath12k_scan_stop(ar); + if (ret) + ath12k_warn(ar->ab, "failed to stop scan: %d\n", ret); + ret = -ETIMEDOUT; + goto free_chan_list; + } + + ieee80211_queue_delayed_work(hw, &ar->scan.timeout, + msecs_to_jiffies(duration)); + + ret = 0; + +free_chan_list: + kfree(arg.chan_list); +exit: + mutex_unlock(&ar->conf_mutex); + + return ret; +} + static const struct ieee80211_ops ath12k_ops = { .tx = ath12k_mac_op_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, @@ -7485,6 +7604,8 @@ static const struct ieee80211_ops ath12k_ops = { .get_survey = ath12k_mac_op_get_survey, .flush = ath12k_mac_op_flush, .sta_statistics = ath12k_mac_op_sta_statistics, + .remain_on_channel = ath12k_mac_op_remain_on_channel, + .cancel_remain_on_channel = ath12k_mac_op_cancel_remain_on_channel, }; static void ath12k_mac_update_ch_list(struct ath12k *ar, @@ -8012,6 +8133,7 @@ static void ath12k_mac_setup(struct ath12k *ar) init_completion(&ar->bss_survey_done); init_completion(&ar->scan.started); init_completion(&ar->scan.completed); + init_completion(&ar->scan.on_channel); INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work); INIT_WORK(&ar->regd_update_work, ath12k_regd_update_work); diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index ff086428fb0c..37cfd607c043 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -5059,6 +5059,10 @@ static void ath12k_wmi_event_scan_started(struct ath12k *ar) break; case ATH12K_SCAN_STARTING: ar->scan.state = ATH12K_SCAN_RUNNING; + + if (ar->scan.is_roc) + ieee80211_ready_on_channel(ath12k_ar_to_hw(ar)); + complete(&ar->scan.started); break; } @@ -5143,6 +5147,10 @@ static void ath12k_wmi_event_scan_foreign_chan(struct ath12k *ar, u32 freq) case ATH12K_SCAN_RUNNING: case ATH12K_SCAN_ABORTING: ar->scan_channel = ieee80211_get_channel(hw->wiphy, freq); + + if (ar->scan.is_roc && ar->scan.roc_freq == freq) + complete(&ar->scan.on_channel); + break; } } -- cgit From 28035a88f8b3cc849e4b13b9b5f5dd0aa1e18365 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:29 +0200 Subject: wifi: ath12k: change WLAN_SCAN_PARAMS_MAX_IE_LEN from 256 to 512 Mac80211 needs more space for P2P scan ie in P2P mode, 256 is not enough, resize it to 512. Also delete the duplicate macro definitions in wmi.h. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-8-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index be6bf93f091d..4bd1d0f270a1 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -168,10 +168,6 @@ struct wmi_tlv { #define WLAN_SCAN_MAX_HINT_BSSID 10 #define MAX_RNR_BSS 5 -#define WLAN_SCAN_PARAMS_MAX_SSID 16 -#define WLAN_SCAN_PARAMS_MAX_BSSID 4 -#define WLAN_SCAN_PARAMS_MAX_IE_LEN 256 - #define WMI_APPEND_TO_EXISTING_CHAN_LIST_FLAG 1 #define WMI_BA_MODE_BUFFER_SIZE_256 3 @@ -3161,7 +3157,7 @@ struct ath12k_wmi_element_info_arg { #define WLAN_SCAN_PARAMS_MAX_SSID 16 #define WLAN_SCAN_PARAMS_MAX_BSSID 4 -#define WLAN_SCAN_PARAMS_MAX_IE_LEN 256 +#define WLAN_SCAN_PARAMS_MAX_IE_LEN 512 /* Values lower than this may be refused by some firmware revisions with a scan * completion with a timedout reason. -- cgit From 32e7b12e2611e6b49510a3b36c0ba4deafac10c7 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:29 +0200 Subject: wifi: ath12k: allow specific mgmt frame tx while vdev is not up In current code, the management frames must be sent after vdev is started. But for P2P device, vdev won't start until P2P negotiation is done. So this logic doesn't make sense for P2P device. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-9-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index dbaef009e972..04a4a7c0eedf 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5123,8 +5123,8 @@ static void ath12k_mgmt_over_wmi_tx_work(struct work_struct *work) } arvif = ath12k_vif_to_arvif(skb_cb->vif); - if (ar->allocated_vdev_map & (1LL << arvif->vdev_id) && - arvif->is_started) { + + if (ar->allocated_vdev_map & (1LL << arvif->vdev_id)) { ret = ath12k_mac_mgmt_tx_wmi(ar, arvif, skb); if (ret) { ath12k_warn(ar->ab, "failed to tx mgmt frame, vdev_id %d :%d\n", -- cgit From c9e4e41e71ffaf3f6ff1fafcb96fda92a12dc2f5 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:30 +0200 Subject: wifi: ath12k: move peer delete after vdev stop of station for WCN7850 In current code, when STA/P2P Client connect to AP/P2P GO, the WMI command sequence is: peer_create->vdev_start->vdev_up And sequence of STA/P2P Client disconnect from AP/P2P GO is: peer_delete->vdev_down->vdev_stop This sequence of disconnect is not opposite of connect. For STA or P2P GO, bss peer is not needed by firmware during handling vdev stop command. So with this sequence, STA and P2P GO can work normally. But for P2P Client, firmware needs bss peer in some functions during handling vdev stop command. The opposite sequence of disconnect should be: vdev_down->vdev_stop->peer_delete So change the sequence of disconnect as above opposite sequence for WCN7850. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-10-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 99 +++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 45 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 04a4a7c0eedf..810be179e8b6 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -1084,6 +1084,46 @@ static int ath12k_mac_monitor_stop(struct ath12k *ar) return ret; } +static int ath12k_mac_vdev_stop(struct ath12k_vif *arvif) +{ + struct ath12k *ar = arvif->ar; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + reinit_completion(&ar->vdev_setup_done); + + ret = ath12k_wmi_vdev_stop(ar, arvif->vdev_id); + if (ret) { + ath12k_warn(ar->ab, "failed to stop WMI vdev %i: %d\n", + arvif->vdev_id, ret); + goto err; + } + + ret = ath12k_mac_vdev_setup_sync(ar); + if (ret) { + ath12k_warn(ar->ab, "failed to synchronize setup for vdev %i: %d\n", + arvif->vdev_id, ret); + goto err; + } + + WARN_ON(ar->num_started_vdevs == 0); + + ar->num_started_vdevs--; + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "vdev %pM stopped, vdev_id %d\n", + arvif->vif->addr, arvif->vdev_id); + + if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) { + clear_bit(ATH12K_CAC_RUNNING, &ar->dev_flags); + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "CAC Stopped for vdev %d\n", + arvif->vdev_id); + } + + return 0; +err: + return ret; +} + static int ath12k_mac_config(struct ath12k *ar, u32 changed) { struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); @@ -3959,6 +3999,13 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, sta->addr, arvif->vdev_id); } else if ((old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_NOTEXIST)) { + if (arvif->vdev_type == WMI_VDEV_TYPE_STA) { + ath12k_bss_disassoc(ar, arvif); + ret = ath12k_mac_vdev_stop(arvif); + if (ret) + ath12k_warn(ar->ab, "failed to stop vdev %i: %d\n", + arvif->vdev_id, ret); + } ath12k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr); ret = ath12k_peer_delete(ar, arvif->vdev_id, sta->addr); @@ -6395,46 +6442,6 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, return 0; } -static int ath12k_mac_vdev_stop(struct ath12k_vif *arvif) -{ - struct ath12k *ar = arvif->ar; - int ret; - - lockdep_assert_held(&ar->conf_mutex); - - reinit_completion(&ar->vdev_setup_done); - - ret = ath12k_wmi_vdev_stop(ar, arvif->vdev_id); - if (ret) { - ath12k_warn(ar->ab, "failed to stop WMI vdev %i: %d\n", - arvif->vdev_id, ret); - goto err; - } - - ret = ath12k_mac_vdev_setup_sync(ar); - if (ret) { - ath12k_warn(ar->ab, "failed to synchronize setup for vdev %i: %d\n", - arvif->vdev_id, ret); - goto err; - } - - WARN_ON(ar->num_started_vdevs == 0); - - ar->num_started_vdevs--; - ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "vdev %pM stopped, vdev_id %d\n", - arvif->vif->addr, arvif->vdev_id); - - if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) { - clear_bit(ATH12K_CAC_RUNNING, &ar->dev_flags); - ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "CAC Stopped for vdev %d\n", - arvif->vdev_id); - } - - return 0; -err: - return ret; -} - static int ath12k_mac_vdev_start(struct ath12k_vif *arvif, struct ieee80211_chanctx_conf *ctx) { @@ -6801,11 +6808,13 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, arvif->is_started = false; } - ret = ath12k_mac_vdev_stop(arvif); - if (ret) - ath12k_warn(ab, "failed to stop vdev %i: %d\n", - arvif->vdev_id, ret); - + if (arvif->vdev_type != WMI_VDEV_TYPE_STA) { + ath12k_bss_disassoc(ar, arvif); + ret = ath12k_mac_vdev_stop(arvif); + if (ret) + ath12k_warn(ab, "failed to stop vdev %i: %d\n", + arvif->vdev_id, ret); + } arvif->is_started = false; if (ab->hw_params->vdev_start_delay && -- cgit From cf0425eead75687078369e48691b8a5f624885cd Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:30 +0200 Subject: wifi: ath12k: designating channel frequency for ROC scan For P2P mode, the WLAN interface may be requested to remain on a specific channel and then to send some management frames on that channel. Now chananel frequency of wmi_mgmt_send_cmd is set as 0. As a result, firmware may choose a default but wrong channel. Fix it by assigning chanfreq field with the ROC channel frequency. This change only applies to WCN7850, other chips are not affected. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-11-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 37cfd607c043..84d7d6584fba 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -730,6 +730,20 @@ static int ath12k_service_ready_event(struct ath12k_base *ab, struct sk_buff *sk return 0; } +static u32 ath12k_wmi_mgmt_get_freq(struct ath12k *ar, + struct ieee80211_tx_info *info) +{ + struct ath12k_base *ab = ar->ab; + u32 freq = 0; + + if (ab->hw_params->single_pdev_only && + ar->scan.is_roc && + (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)) + freq = ar->scan.roc_freq; + + return freq; +} + struct sk_buff *ath12k_wmi_alloc_skb(struct ath12k_wmi_base *wmi_ab, u32 len) { struct sk_buff *skb; @@ -755,6 +769,7 @@ int ath12k_wmi_mgmt_send(struct ath12k *ar, u32 vdev_id, u32 buf_id, { struct ath12k_wmi_pdev *wmi = ar->wmi; struct wmi_mgmt_send_cmd *cmd; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(frame); struct wmi_tlv *frame_tlv; struct sk_buff *skb; u32 buf_len; @@ -773,7 +788,7 @@ int ath12k_wmi_mgmt_send(struct ath12k *ar, u32 vdev_id, u32 buf_id, sizeof(*cmd)); cmd->vdev_id = cpu_to_le32(vdev_id); cmd->desc_id = cpu_to_le32(buf_id); - cmd->chanfreq = 0; + cmd->chanfreq = cpu_to_le32(ath12k_wmi_mgmt_get_freq(ar, info)); cmd->paddr_lo = cpu_to_le32(lower_32_bits(ATH12K_SKB_CB(frame)->paddr)); cmd->paddr_hi = cpu_to_le32(upper_32_bits(ATH12K_SKB_CB(frame)->paddr)); cmd->frame_len = cpu_to_le32(frame->len); -- cgit From e65a6398657561831b8a1a5aa3ec43ff24c428f2 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:31 +0200 Subject: wifi: ath12k: advertise P2P dev support for WCN7850 Now that all the necessary pieces are implemented we can enable P2P support for WCN7850. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-12-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/hw.c | 5 ++++- drivers/net/wireless/ath/ath12k/mac.c | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index 6e2242a79a2f..0b17dfd47856 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -956,7 +956,10 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .vdev_start_delay = true, .interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP), + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_DEVICE) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO), .supports_monitor = false, .idle_ps = true, diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 810be179e8b6..a3b002d77a07 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5799,17 +5799,29 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_STATION: arvif->vdev_type = WMI_VDEV_TYPE_STA; + + if (vif->p2p) + arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_CLIENT; + break; case NL80211_IFTYPE_MESH_POINT: arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH_11S; fallthrough; case NL80211_IFTYPE_AP: arvif->vdev_type = WMI_VDEV_TYPE_AP; + + if (vif->p2p) + arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_GO; + break; case NL80211_IFTYPE_MONITOR: arvif->vdev_type = WMI_VDEV_TYPE_MONITOR; ar->monitor_vdev_id = bit; break; + case NL80211_IFTYPE_P2P_DEVICE: + arvif->vdev_type = WMI_VDEV_TYPE_STA; + arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE; + break; default: WARN_ON(1); break; -- cgit From d7a5c7cde2cb6b5d83e1c95892d6bc4650c0a3a2 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Mon, 5 Feb 2024 08:16:18 -0800 Subject: wifi: ath11k: Really consistently use ath11k_vif_to_arvif() Commit 9476cda44c13 ("wifi: ath11k: Consistently use ath11k_vif_to_arvif()") previously replaced all open coding of the ath11k_vif_to_arvif() functionality. Subsequently two more instances of open coding were introduced, one in commit 92425f788fee ("wifi: ath11k: fill parameters for vdev set tpc power WMI command") and one in commit 6f4e235be655 ("wifi: ath11k: add parse of transmit power envelope element"), so fix those as well. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240205-ath11k_vif_to_arvif-v1-1-7c41313c8318@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index dc2bf13f00c1..be04f823566f 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -7590,7 +7590,7 @@ void ath11k_mac_fill_reg_tpc_info(struct ath11k *ar, struct ieee80211_chanctx_conf *ctx) { struct ath11k_base *ab = ar->ab; - struct ath11k_vif *arvif = (void *)vif->drv_priv; + struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ath11k_reg_tpc_power_info *reg_tpc_info = &arvif->reg_tpc_info; struct ieee80211_channel *chan, *temp_chan; @@ -7764,7 +7764,7 @@ static void ath11k_mac_parse_tx_pwr_env(struct ath11k *ar, struct ieee80211_chanctx_conf *ctx) { struct ath11k_base *ab = ar->ab; - struct ath11k_vif *arvif = (void *)vif->drv_priv; + struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ieee80211_tx_pwr_env *single_tpe; enum wmi_reg_6ghz_client_type client_type; -- cgit From 04edb5dc68f4356fd8df44c04547a729dc44f43e Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Mon, 5 Feb 2024 12:49:53 -0700 Subject: wifi: ath12k: Fix uninitialized use of ret in ath12k_mac_allocate() Clang warns (or errors with CONFIG_WERROR=y): drivers/net/wireless/ath/ath12k/mac.c:8060:9: error: variable 'ret' is uninitialized when used here [-Werror,-Wuninitialized] 8060 | return ret; | ^~~ drivers/net/wireless/ath/ath12k/mac.c:8022:9: note: initialize the variable 'ret' to silence this warning 8022 | int ret, i, j; | ^ | = 0 1 error generated. Commit 6db6e70a17f6 ("wifi: ath12k: Introduce the container for mac80211 hw") added a completely uninitialized use of ret. Prior to that change, -ENOMEM was returned to the callers of ath12k_mac_allocate() whenever ath12k_mac_hw_allocate() failed. Assign that value to ret to make sure it is always initialized when used and clear up the warning. Closes: https://github.com/ClangBuiltLinux/linux/issues/1989i Fixes: 6db6e70a17f6 ("wifi: ath12k: Introduce the container for mac80211 hw") Signed-off-by: Nathan Chancellor Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240205-ath12k-mac-wuninitialized-v1-1-3fda7b17357f@kernel.org --- drivers/net/wireless/ath/ath12k/mac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index a3b002d77a07..a737a09a0b9c 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -8302,6 +8302,7 @@ int ath12k_mac_allocate(struct ath12k_base *ab) if (!ah) { ath12k_warn(ab, "failed to allocate mac80211 hw device for hw_idx %d\n", i); + ret = -ENOMEM; goto err; } -- cgit From 64493a7ff74b679640ff493aed11753a1d284ca9 Mon Sep 17 00:00:00 2001 From: Nicolas Escande Date: Fri, 9 Feb 2024 12:35:35 +0100 Subject: wifi: ath11k: Do not directly use scan_flags in struct scan_req_params As discussed in [1] lets not use WMI_SCAN_XXX defines in combination with scan_flags directly when setting scan params in struct scan_req_params but use the underlying bitfield. This bitfield is then converted to WMI_SCAN_XXX when filling the WMI command to send to the firmware. [1] https://lore.kernel.org/all/871qae51wx.fsf@kernel.org/ Tested-on: QCN9074 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Nicolas Escande Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240209113536.266822-2-nico.escande@gmail.com --- drivers/net/wireless/ath/ath11k/mac.c | 6 +++--- drivers/net/wireless/ath/ath11k/wmi.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index be04f823566f..7bf5d1068164 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -4013,7 +4013,7 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw, req->ssids[i].ssid_len); } } else { - arg->scan_flags |= WMI_SCAN_FLAG_PASSIVE; + arg->scan_f_passive = 1; } if (req->n_channels) { @@ -9252,8 +9252,8 @@ static int ath11k_mac_op_remain_on_channel(struct ieee80211_hw *hw, arg->dwell_time_active = scan_time_msec; arg->dwell_time_passive = scan_time_msec; arg->max_scan_time = scan_time_msec; - arg->scan_flags |= WMI_SCAN_FLAG_PASSIVE; - arg->scan_flags |= WMI_SCAN_FILTER_PROBE_REQ; + arg->scan_f_passive = 1; + arg->scan_f_filter_prb_req = 1; arg->burst_duration = duration; ret = ath11k_start_scan(ar, arg); diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 688ee20528a0..78c11025c21c 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -2098,7 +2098,7 @@ void ath11k_wmi_start_scan_init(struct ath11k *ar, WMI_SCAN_EVENT_BSS_CHANNEL | WMI_SCAN_EVENT_FOREIGN_CHAN | WMI_SCAN_EVENT_DEQUEUED; - arg->scan_flags |= WMI_SCAN_CHAN_STAT_EVENT; + arg->scan_f_chan_stat_evnt = 1; if (test_bit(WMI_TLV_SERVICE_PASSIVE_SCAN_START_TIME_ENHANCE, ar->ab->wmi_ab.svc_map)) -- cgit From 79ad70c6df0af8e6515a0cc064423b280f281582 Mon Sep 17 00:00:00 2001 From: Nicolas Escande Date: Fri, 9 Feb 2024 12:35:36 +0100 Subject: wifi: ath11k: Remove scan_flags union from struct scan_req_params Now that we do not use scan_flags directly with WMI_SCAN_XXX macros anymore but only the bitfield scan_f_xxx, lets remove the scan_flags & the underlying union. This will prevent further problems as some entries in the scan_f_xxx bitfield don't match their corresponding WMI_SCAN_XXX flags as seen in [1] [1] https://lore.kernel.org/all/20231127180559.1696041-1-nico.escande@gmail.com/ Signed-off-by: Nicolas Escande Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240209113536.266822-3-nico.escande@gmail.com --- drivers/net/wireless/ath/ath11k/wmi.h | 55 ++++++++++++++++------------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 6dcd14700570..bc7adf7f13fb 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -3394,36 +3394,31 @@ struct scan_req_params { u32 idle_time; u32 max_scan_time; u32 probe_delay; - union { - struct { - u32 scan_f_passive:1, - scan_f_bcast_probe:1, - scan_f_cck_rates:1, - scan_f_ofdm_rates:1, - scan_f_chan_stat_evnt:1, - scan_f_filter_prb_req:1, - scan_f_bypass_dfs_chn:1, - scan_f_continue_on_err:1, - scan_f_offchan_mgmt_tx:1, - scan_f_offchan_data_tx:1, - scan_f_promisc_mode:1, - scan_f_capture_phy_err:1, - scan_f_strict_passive_pch:1, - scan_f_half_rate:1, - scan_f_quarter_rate:1, - scan_f_force_active_dfs_chn:1, - scan_f_add_tpc_ie_in_probe:1, - scan_f_add_ds_ie_in_probe:1, - scan_f_add_spoofed_mac_in_probe:1, - scan_f_add_rand_seq_in_probe:1, - scan_f_en_ie_whitelist_in_probe:1, - scan_f_forced:1, - scan_f_2ghz:1, - scan_f_5ghz:1, - scan_f_80mhz:1; - }; - u32 scan_flags; - }; + u32 scan_f_passive:1, + scan_f_bcast_probe:1, + scan_f_cck_rates:1, + scan_f_ofdm_rates:1, + scan_f_chan_stat_evnt:1, + scan_f_filter_prb_req:1, + scan_f_bypass_dfs_chn:1, + scan_f_continue_on_err:1, + scan_f_offchan_mgmt_tx:1, + scan_f_offchan_data_tx:1, + scan_f_promisc_mode:1, + scan_f_capture_phy_err:1, + scan_f_strict_passive_pch:1, + scan_f_half_rate:1, + scan_f_quarter_rate:1, + scan_f_force_active_dfs_chn:1, + scan_f_add_tpc_ie_in_probe:1, + scan_f_add_ds_ie_in_probe:1, + scan_f_add_spoofed_mac_in_probe:1, + scan_f_add_rand_seq_in_probe:1, + scan_f_en_ie_whitelist_in_probe:1, + scan_f_forced:1, + scan_f_2ghz:1, + scan_f_5ghz:1, + scan_f_80mhz:1; enum scan_dwelltime_adaptive_mode adaptive_dwell_time_mode; u32 burst_duration; u32 num_chan; -- cgit From b53adefc884ce470a5b27885466439cbb087813e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 7 Feb 2024 17:15:24 +0000 Subject: wifi: carl9170: Remove redundant assignment to pointer super The pointer super is being assigned a value that is not being read, it is being re-assigned later. The assignment is redundant and can be removed. Cleans up clang scan warning: drivers/net/wireless/ath/carl9170/tx.c:192:34: warning: Value stored to 'super' during its initialization is never read [deadcode.DeadStores] Signed-off-by: Colin Ian King Acked-by: Christian Lamparter Signed-off-by: Kalle Valo Link: https://msgid.link/20240207171524.2458418-1-colin.i.king@gmail.com --- drivers/net/wireless/ath/carl9170/tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index 6bb9aa2bfe65..e902ca80eba7 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -189,7 +189,7 @@ static void carl9170_tx_accounting_free(struct ar9170 *ar, struct sk_buff *skb) static int carl9170_alloc_dev_space(struct ar9170 *ar, struct sk_buff *skb) { - struct _carl9170_tx_superframe *super = (void *) skb->data; + struct _carl9170_tx_superframe *super; unsigned int chunks; int cookie = -1; -- cgit From bcdb44f30be92b7bc750996dfc45c1fe3d49d715 Mon Sep 17 00:00:00 2001 From: Nicolas Escande Date: Sun, 11 Feb 2024 15:55:47 +0100 Subject: wifi: ath12k: Do not use scan_flags from struct ath12k_wmi_scan_req_arg As discussed in [1] to fix the mismatch between the WMI_SCAN_XXX macros & their corresponding scan_f_xxx bitfield equivalent, lets stop using the scan_flags in the union altogether. [1] https://lore.kernel.org/all/4be7d62e-cb59-462d-aac2-94e27efc22ff@quicinc.com/ Tested-on: QCN9274 hw2.0 PCI CI_WLAN.WBE.1.3-02907.1-QCAHKSWPL_SILICONZ-10 Signed-off-by: Nicolas Escande Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240211145548.1939610-2-nico.escande@gmail.com --- drivers/net/wireless/ath/ath12k/mac.c | 4 ++-- drivers/net/wireless/ath/ath12k/wmi.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index a737a09a0b9c..7d3f5321a36d 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -3201,7 +3201,7 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, for (i = 0; i < arg.num_ssids; i++) arg.ssid[i] = req->ssids[i]; } else { - arg.scan_flags |= WMI_SCAN_FLAG_PASSIVE; + arg.scan_f_passive = 1; } if (req->n_channels) { @@ -7555,7 +7555,7 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, arg.dwell_time_active = scan_time_msec; arg.dwell_time_passive = scan_time_msec; arg.max_scan_time = scan_time_msec; - arg.scan_flags |= WMI_SCAN_FLAG_PASSIVE; + arg.scan_f_passive = 1; arg.burst_duration = duration; ret = ath12k_start_scan(ar, &arg); diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 84d7d6584fba..2c2a010d88df 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -2194,7 +2194,7 @@ void ath12k_wmi_start_scan_init(struct ath12k *ar, WMI_SCAN_EVENT_BSS_CHANNEL | WMI_SCAN_EVENT_FOREIGN_CHAN | WMI_SCAN_EVENT_DEQUEUED; - arg->scan_flags |= WMI_SCAN_CHAN_STAT_EVENT; + arg->scan_f_chan_stat_evnt = 1; arg->num_bssid = 1; /* fill bssid_list[0] with 0xff, otherwise bssid and RA will be -- cgit From 80fd22d7d41acd55ba362e9975290d9056079fea Mon Sep 17 00:00:00 2001 From: Nicolas Escande Date: Sun, 11 Feb 2024 15:55:48 +0100 Subject: wifi: ath12k: Remove unused scan_flags from struct ath12k_wmi_scan_req_arg As we did for ath11k lets remove the unused scan_flags from struct ath12k_wmi_scan_req_arg. This will prevent us from using out of sync values between WMI_SCAN_XXX & scan_f_xxx bitfield. While at it remove the underlying wrapping struct/union construct as it serves no purpose anymore. Signed-off-by: Nicolas Escande Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240211145548.1939610-3-nico.escande@gmail.com --- drivers/net/wireless/ath/ath12k/wmi.h | 55 ++++++++++++++++------------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 4bd1d0f270a1..892f21f95ee5 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -3311,36 +3311,31 @@ struct ath12k_wmi_scan_req_arg { u32 idle_time; u32 max_scan_time; u32 probe_delay; - union { - struct { - u32 scan_f_passive:1, - scan_f_bcast_probe:1, - scan_f_cck_rates:1, - scan_f_ofdm_rates:1, - scan_f_chan_stat_evnt:1, - scan_f_filter_prb_req:1, - scan_f_bypass_dfs_chn:1, - scan_f_continue_on_err:1, - scan_f_offchan_mgmt_tx:1, - scan_f_offchan_data_tx:1, - scan_f_promisc_mode:1, - scan_f_capture_phy_err:1, - scan_f_strict_passive_pch:1, - scan_f_half_rate:1, - scan_f_quarter_rate:1, - scan_f_force_active_dfs_chn:1, - scan_f_add_tpc_ie_in_probe:1, - scan_f_add_ds_ie_in_probe:1, - scan_f_add_spoofed_mac_in_probe:1, - scan_f_add_rand_seq_in_probe:1, - scan_f_en_ie_whitelist_in_probe:1, - scan_f_forced:1, - scan_f_2ghz:1, - scan_f_5ghz:1, - scan_f_80mhz:1; - }; - u32 scan_flags; - }; + u32 scan_f_passive:1, + scan_f_bcast_probe:1, + scan_f_cck_rates:1, + scan_f_ofdm_rates:1, + scan_f_chan_stat_evnt:1, + scan_f_filter_prb_req:1, + scan_f_bypass_dfs_chn:1, + scan_f_continue_on_err:1, + scan_f_offchan_mgmt_tx:1, + scan_f_offchan_data_tx:1, + scan_f_promisc_mode:1, + scan_f_capture_phy_err:1, + scan_f_strict_passive_pch:1, + scan_f_half_rate:1, + scan_f_quarter_rate:1, + scan_f_force_active_dfs_chn:1, + scan_f_add_tpc_ie_in_probe:1, + scan_f_add_ds_ie_in_probe:1, + scan_f_add_spoofed_mac_in_probe:1, + scan_f_add_rand_seq_in_probe:1, + scan_f_en_ie_whitelist_in_probe:1, + scan_f_forced:1, + scan_f_2ghz:1, + scan_f_5ghz:1, + scan_f_80mhz:1; enum scan_dwelltime_adaptive_mode adaptive_dwell_time_mode; u32 burst_duration; u32 num_chan; -- cgit From f0024c980df2547224a5b0843bbe96d26eb5b601 Mon Sep 17 00:00:00 2001 From: Nicolas Escande Date: Sun, 11 Feb 2024 16:11:04 +0100 Subject: wifi: ath12k: remove the unused scan_events from ath12k_wmi_scan_req_arg As done for ath11k, lets keep on cleaning up struct ath12k_wmi_scan_req_arg by removing the unused scan_events. Also remove the underlying union & struct construct as it isn't needed anymore. No functionnal changes. Signed-off-by: Nicolas Escande Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240211151104.1951418-1-nico.escande@gmail.com --- drivers/net/wireless/ath/ath12k/wmi.h | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 892f21f95ee5..103462feb935 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -3281,24 +3281,19 @@ struct ath12k_wmi_scan_req_arg { u32 vdev_id; u32 pdev_id; enum wmi_scan_priority scan_priority; - union { - struct { - u32 scan_ev_started:1, - scan_ev_completed:1, - scan_ev_bss_chan:1, - scan_ev_foreign_chan:1, - scan_ev_dequeued:1, - scan_ev_preempted:1, - scan_ev_start_failed:1, - scan_ev_restarted:1, - scan_ev_foreign_chn_exit:1, - scan_ev_invalid:1, - scan_ev_gpio_timeout:1, - scan_ev_suspended:1, - scan_ev_resumed:1; - }; - u32 scan_events; - }; + u32 scan_ev_started:1, + scan_ev_completed:1, + scan_ev_bss_chan:1, + scan_ev_foreign_chan:1, + scan_ev_dequeued:1, + scan_ev_preempted:1, + scan_ev_start_failed:1, + scan_ev_restarted:1, + scan_ev_foreign_chn_exit:1, + scan_ev_invalid:1, + scan_ev_gpio_timeout:1, + scan_ev_suspended:1, + scan_ev_resumed:1; u32 dwell_time_active; u32 dwell_time_active_2g; u32 dwell_time_passive; -- cgit From f019f4dff2e4cb8704dc608496e3f2829de3e919 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Wed, 14 Feb 2024 10:38:10 +0200 Subject: wifi: ath11k: support 2 station interfaces Add hardware parameter support_dual_stations to indicate whether 2 station interfaces are supported. For chips which support this feature, limit total number of AP interface and mesh point to 1. The max interfaces are 3 for such chips. The chips affected are: QCA6390 hw2.0 WCN6855 hw2.0 WCN6855 hw2.1 Other chips are not affected. For affected chips, remove radar_detect_widths because now num_different_channels is set to 2. radar_detect_widths can be set only when num_different_channels is 1, see mac80211 function wiphy_verify_combinations for details. This means that in affectected chips DFS cannot be enabled in AP mode. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://msgid.link/20230714023801.2621802-2-quic_cjhuang@quicinc.com --- drivers/net/wireless/ath/ath11k/core.c | 14 ++++++-- drivers/net/wireless/ath/ath11k/hw.c | 2 +- drivers/net/wireless/ath/ath11k/hw.h | 1 + drivers/net/wireless/ath/ath11k/mac.c | 62 ++++++++++++++++++++++------------ 4 files changed, 53 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 0c6ecbb9a066..3c1ba8fd28f4 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -122,6 +122,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tcl_ring_retry = true, .tx_ring_size = DP_TCL_DATA_RING_SIZE, .smp2p_wow_exit = false, + .support_dual_stations = false, }, { .hw_rev = ATH11K_HW_IPQ6018_HW10, @@ -205,6 +206,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tx_ring_size = DP_TCL_DATA_RING_SIZE, .smp2p_wow_exit = false, .support_fw_mac_sequence = false, + .support_dual_stations = false, }, { .name = "qca6390 hw2.0", @@ -255,7 +257,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .coldboot_cal_ftm = false, .cbcal_restart_fw = false, .fw_mem_mode = 0, - .num_vdevs = 16 + 1, + .num_vdevs = 2 + 1, .num_peers = 512, .supports_suspend = true, .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), @@ -290,6 +292,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tx_ring_size = DP_TCL_DATA_RING_SIZE, .smp2p_wow_exit = false, .support_fw_mac_sequence = true, + .support_dual_stations = true, }, { .name = "qcn9074 hw1.0", @@ -372,6 +375,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tx_ring_size = DP_TCL_DATA_RING_SIZE, .smp2p_wow_exit = false, .support_fw_mac_sequence = false, + .support_dual_stations = false, }, { .name = "wcn6855 hw2.0", @@ -422,7 +426,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .coldboot_cal_ftm = false, .cbcal_restart_fw = false, .fw_mem_mode = 0, - .num_vdevs = 16 + 1, + .num_vdevs = 2 + 1, .num_peers = 512, .supports_suspend = true, .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), @@ -457,6 +461,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tx_ring_size = DP_TCL_DATA_RING_SIZE, .smp2p_wow_exit = false, .support_fw_mac_sequence = true, + .support_dual_stations = true, }, { .name = "wcn6855 hw2.1", @@ -505,7 +510,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .coldboot_cal_ftm = false, .cbcal_restart_fw = false, .fw_mem_mode = 0, - .num_vdevs = 16 + 1, + .num_vdevs = 2 + 1, .num_peers = 512, .supports_suspend = true, .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), @@ -540,6 +545,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tx_ring_size = DP_TCL_DATA_RING_SIZE, .smp2p_wow_exit = false, .support_fw_mac_sequence = true, + .support_dual_stations = true, }, { .name = "wcn6750 hw1.0", @@ -621,6 +627,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tx_ring_size = DP_TCL_DATA_RING_SIZE_WCN6750, .smp2p_wow_exit = true, .support_fw_mac_sequence = true, + .support_dual_stations = false, }, { .hw_rev = ATH11K_HW_IPQ5018_HW10, @@ -702,6 +709,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tx_ring_size = DP_TCL_DATA_RING_SIZE, .smp2p_wow_exit = false, .support_fw_mac_sequence = false, + .support_dual_stations = false, }, }; diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c index 77d8f9237680..caa6dc12a790 100644 --- a/drivers/net/wireless/ath/ath11k/hw.c +++ b/drivers/net/wireless/ath/ath11k/hw.c @@ -58,7 +58,7 @@ static void ath11k_hw_wcn6855_tx_mesh_enable(struct ath11k_base *ab, static void ath11k_init_wmi_config_qca6390(struct ath11k_base *ab, struct target_resource_config *config) { - config->num_vdevs = 4; + config->num_vdevs = ab->hw_params.num_vdevs; config->num_peers = 16; config->num_tids = 32; diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 1b070747a5db..14ef4eb48f80 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -226,6 +226,7 @@ struct ath11k_hw_params { u32 tx_ring_size; bool smp2p_wow_exit; bool support_fw_mac_sequence; + bool support_dual_stations; }; struct ath11k_hw_ops { diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 7bf5d1068164..7180ce9dbf98 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -9843,28 +9843,46 @@ static int ath11k_mac_setup_iface_combinations(struct ath11k *ar) return -ENOMEM; } - limits[0].max = 1; - limits[0].types |= BIT(NL80211_IFTYPE_STATION); - - limits[1].max = 16; - limits[1].types |= BIT(NL80211_IFTYPE_AP); - - if (IS_ENABLED(CONFIG_MAC80211_MESH) && - ab->hw_params.interface_modes & BIT(NL80211_IFTYPE_MESH_POINT)) - limits[1].types |= BIT(NL80211_IFTYPE_MESH_POINT); - - combinations[0].limits = limits; - combinations[0].n_limits = n_limits; - combinations[0].max_interfaces = 16; - 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) | - BIT(NL80211_CHAN_WIDTH_80P80) | - BIT(NL80211_CHAN_WIDTH_160); + if (ab->hw_params.support_dual_stations) { + limits[0].max = 2; + limits[0].types |= BIT(NL80211_IFTYPE_STATION); + + limits[1].max = 1; + limits[1].types |= BIT(NL80211_IFTYPE_AP); + if (IS_ENABLED(CONFIG_MAC80211_MESH) && + ab->hw_params.interface_modes & BIT(NL80211_IFTYPE_MESH_POINT)) + limits[1].types |= BIT(NL80211_IFTYPE_MESH_POINT); + + combinations[0].limits = limits; + combinations[0].n_limits = 2; + combinations[0].max_interfaces = ab->hw_params.num_vdevs; + combinations[0].num_different_channels = 2; + combinations[0].beacon_int_infra_match = true; + combinations[0].beacon_int_min_gcd = 100; + } else { + limits[0].max = 1; + limits[0].types |= BIT(NL80211_IFTYPE_STATION); + + limits[1].max = 16; + limits[1].types |= BIT(NL80211_IFTYPE_AP); + + if (IS_ENABLED(CONFIG_MAC80211_MESH) && + ab->hw_params.interface_modes & BIT(NL80211_IFTYPE_MESH_POINT)) + limits[1].types |= BIT(NL80211_IFTYPE_MESH_POINT); + + combinations[0].limits = limits; + combinations[0].n_limits = 2; + combinations[0].max_interfaces = 16; + 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) | + BIT(NL80211_CHAN_WIDTH_80P80) | + BIT(NL80211_CHAN_WIDTH_160); + } ar->hw->wiphy->iface_combinations = combinations; ar->hw->wiphy->n_iface_combinations = 1; -- cgit From 24395ec117076216c78d0874d9d44f62ba1f9747 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Wed, 14 Feb 2024 10:38:10 +0200 Subject: wifi: ath11k: provide address list if chip supports 2 stations Provide address list to mac80211 so user doesn't need to specify addresses when a second interface is added because the address can be allocated from the list by mac80211. The derived addresses have LAA (Local Administered Address) bit set, and only the first byte is changed. Take the 00:03:7f:xx:xx:xx as example to derive: addresses[0] is unchanged, it's still 00:03:7f:xx:xx:xx, addresses[1] is 02:03:7f:xx:xx:xx, addresses[2] is 12:03:7f:xx:xx:xx, addresses[3] is 22:03:7f:xx:xx:xx, addresses[4] is 32:03:7f:xx:xx:xx. However as only 3 addresses are reported now, so addresses[3] and addresses[4] aren't actually derived. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://msgid.link/20230714023801.2621802-3-quic_cjhuang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 7180ce9dbf98..7f18a6a68b81 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -9824,6 +9824,33 @@ static int ath11k_mac_setup_channels_rates(struct ath11k *ar, return 0; } +static void ath11k_mac_setup_mac_address_list(struct ath11k *ar) +{ + struct mac_address *addresses; + u16 n_addresses; + int i; + + if (!ar->ab->hw_params.support_dual_stations) + return; + + n_addresses = ar->ab->hw_params.num_vdevs; + addresses = kcalloc(n_addresses, sizeof(*addresses), GFP_KERNEL); + if (!addresses) + return; + + memcpy(addresses[0].addr, ar->mac_addr, ETH_ALEN); + for (i = 1; i < n_addresses; i++) { + memcpy(addresses[i].addr, ar->mac_addr, ETH_ALEN); + /* set Local Administered Address bit */ + addresses[i].addr[0] |= 0x2; + + addresses[i].addr[0] += (i - 1) << 4; + } + + ar->hw->wiphy->addresses = addresses; + ar->hw->wiphy->n_addresses = n_addresses; +} + static int ath11k_mac_setup_iface_combinations(struct ath11k *ar) { struct ath11k_base *ab = ar->ab; @@ -9947,6 +9974,8 @@ static void __ath11k_mac_unregister(struct ath11k *ar) kfree(ar->hw->wiphy->iface_combinations[0].limits); kfree(ar->hw->wiphy->iface_combinations); + kfree(ar->hw->wiphy->addresses); + SET_IEEE80211_DEV(ar->hw, NULL); } @@ -9989,6 +10018,7 @@ static int __ath11k_mac_register(struct ath11k *ar) ath11k_pdev_caps_update(ar); SET_IEEE80211_PERM_ADDR(ar->hw, ar->mac_addr); + ath11k_mac_setup_mac_address_list(ar); SET_IEEE80211_DEV(ar->hw, ab->dev); -- cgit From 515bcdf587f9911f2d5de51524cb7e048d295052 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 9 Jan 2024 10:13:35 +0800 Subject: wifi: ath11k: move pci.ops registration ahead In ath11k_pci_probe() there is a switch statement that, based upon the PCI device ID, assigns pci_ops. After the switch, ath11k_pcic_register_pci_ops() is called to register the pci_ops. Unfortunately, this registration is too late if any of the cases in the switch need to perform operations that require the pci_ops to already be registered. In particular, an upcoming patch for QCA2066 needs to call ath11k_pcic_read32(). To address this issue, call ath11k_pcic_register_pci_ops() from each case instead of doing so after the switch. That way the ops will be registered if any subsequent operations within the case processing require the ops to be present. Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3 Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20240109021336.4143-2-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/pci.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index d667d5e06a66..022d695be00f 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -742,7 +742,6 @@ static int ath11k_pci_probe(struct pci_dev *pdev, struct ath11k_base *ab; struct ath11k_pci *ab_pci; u32 soc_hw_version_major, soc_hw_version_minor, addr; - const struct ath11k_pci_ops *pci_ops; int ret; ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI); @@ -788,6 +787,12 @@ static int ath11k_pci_probe(struct pci_dev *pdev, switch (pci_dev->device) { case QCA6390_DEVICE_ID: + ret = ath11k_pcic_register_pci_ops(ab, &ath11k_pci_ops_qca6390); + if (ret) { + ath11k_err(ab, "failed to register PCI ops: %d\n", ret); + goto err_pci_free_region; + } + ath11k_pci_read_hw_version(ab, &soc_hw_version_major, &soc_hw_version_minor); switch (soc_hw_version_major) { @@ -801,13 +806,21 @@ static int ath11k_pci_probe(struct pci_dev *pdev, goto err_pci_free_region; } - pci_ops = &ath11k_pci_ops_qca6390; break; case QCN9074_DEVICE_ID: - pci_ops = &ath11k_pci_ops_qcn9074; + ret = ath11k_pcic_register_pci_ops(ab, &ath11k_pci_ops_qcn9074); + if (ret) { + ath11k_err(ab, "failed to register PCI ops: %d\n", ret); + goto err_pci_free_region; + } ab->hw_rev = ATH11K_HW_QCN9074_HW10; break; case WCN6855_DEVICE_ID: + ret = ath11k_pcic_register_pci_ops(ab, &ath11k_pci_ops_qca6390); + if (ret) { + ath11k_err(ab, "failed to register PCI ops: %d\n", ret); + goto err_pci_free_region; + } ab->id.bdf_search = ATH11K_BDF_SEARCH_BUS_AND_BOARD; ath11k_pci_read_hw_version(ab, &soc_hw_version_major, &soc_hw_version_minor); @@ -834,7 +847,6 @@ unsupported_wcn6855_soc: goto err_pci_free_region; } - pci_ops = &ath11k_pci_ops_qca6390; break; default: dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n", @@ -843,12 +855,6 @@ unsupported_wcn6855_soc: goto err_pci_free_region; } - ret = ath11k_pcic_register_pci_ops(ab, pci_ops); - if (ret) { - ath11k_err(ab, "failed to register PCI ops: %d\n", ret); - goto err_pci_free_region; - } - ret = ath11k_pcic_init_msi_config(ab); if (ret) { ath11k_err(ab, "failed to init msi config: %d\n", ret); -- cgit From 5dc9d1a55e953d9059ecbdd8fe6ec81e9edd349e Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 9 Jan 2024 10:13:36 +0800 Subject: wifi: ath11k: add support for QCA2066 QCA2066 is a PCI based DBS device. It is very similar to WCN6855 overall: they share the same PCI device ID, the same major and minor version numbers, the same register address, and same HAL descriptors etc. The most significant difference is that QCA2066 supports 3-antenna configuration while WCN6855 does not. To differentiate them, subversion numbers are used. Currently four numbers are used by QCA2066: 0x1019A0E1, 0x1019B0E1, 0x1019C0E1 and 0x1019D0E1. Tested-on: QCA2066 hw2.1 PCI WLAN.HSP.1.1-03737-QCAHSPSWPL_V2_SILICONZ_CE-1 Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3 Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20240109021336.4143-3-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/core.c | 86 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/core.h | 1 + drivers/net/wireless/ath/ath11k/mhi.c | 1 + drivers/net/wireless/ath/ath11k/pci.c | 17 ++++++- drivers/net/wireless/ath/ath11k/pcic.c | 11 +++++ 5 files changed, 115 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 3c1ba8fd28f4..922e67f8e04f 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -711,6 +711,92 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .support_fw_mac_sequence = false, .support_dual_stations = false, }, + { + .name = "qca2066 hw2.1", + .hw_rev = ATH11K_HW_QCA2066_HW21, + .fw = { + .dir = "QCA2066/hw2.1", + .board_size = 256 * 1024, + .cal_offset = 128 * 1024, + }, + .max_radios = 3, + .bdf_addr = 0x4B0C0000, + .hw_ops = &wcn6855_ops, + .ring_mask = &ath11k_hw_ring_mask_qca6390, + .internal_sleep_clock = true, + .regs = &wcn6855_regs, + .qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390, + .host_ce_config = ath11k_host_ce_config_qca6390, + .ce_count = 9, + .target_ce_config = ath11k_target_ce_config_wlan_qca6390, + .target_ce_count = 9, + .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390, + .svc_to_ce_map_len = 14, + .ce_ie_addr = &ath11k_ce_ie_addr_ipq8074, + .single_pdev_only = true, + .rxdma1_enable = false, + .num_rxmda_per_pdev = 2, + .rx_mac_buf_ring = true, + .vdev_start_delay = true, + .htt_peer_map_v2 = false, + + .spectral = { + .fft_sz = 0, + .fft_pad_sz = 0, + .summary_pad_sz = 0, + .fft_hdr_len = 0, + .max_fft_bins = 0, + .fragment_160mhz = false, + }, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP), + .supports_monitor = false, + .full_monitor_mode = false, + .supports_shadow_regs = true, + .idle_ps = true, + .supports_sta_ps = true, + .coldboot_cal_mm = false, + .coldboot_cal_ftm = false, + .cbcal_restart_fw = false, + .fw_mem_mode = 0, + .num_vdevs = 2 + 1, + .num_peers = 512, + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), + .supports_regdb = true, + .fix_l1ss = false, + .credit_flow = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, + .hal_params = &ath11k_hw_hal_params_qca6390, + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = false, + .supports_rssi_stats = true, + .fw_wmi_diag_event = true, + .current_cc_support = true, + .dbr_debug_support = false, + .global_reset = true, + .bios_sar_capa = &ath11k_hw_sar_capa_wcn6855, + .m3_fw_support = true, + .fixed_bdf_addr = false, + .fixed_mem_region = false, + .static_window_map = false, + .hybrid_bus_type = false, + .fixed_fw_mem = false, + .support_off_channel_tx = true, + .supports_multi_bssid = true, + + .sram_dump = { + .start = 0x01400000, + .end = 0x0177ffff, + }, + + .tcl_ring_retry = true, + .tx_ring_size = DP_TCL_DATA_RING_SIZE, + .smp2p_wow_exit = false, + .support_fw_mac_sequence = true, + .support_dual_stations = true, + }, }; static inline struct ath11k_pdev *ath11k_core_get_single_pdev(struct ath11k_base *ab) diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 0b2d4a93d706..b3fb74a226fb 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -147,6 +147,7 @@ enum ath11k_hw_rev { ATH11K_HW_WCN6855_HW21, ATH11K_HW_WCN6750_HW10, ATH11K_HW_IPQ5018_HW10, + ATH11K_HW_QCA2066_HW21, }; enum ath11k_firmware_mode { diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index e6e69bb91103..b53659145fcf 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -443,6 +443,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci) case ATH11K_HW_QCA6390_HW20: case ATH11K_HW_WCN6855_HW20: case ATH11K_HW_WCN6855_HW21: + case ATH11K_HW_QCA2066_HW21: ath11k_mhi_config = &ath11k_mhi_config_qca6390; break; default: diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 022d695be00f..be9d2c69cc41 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -29,6 +29,8 @@ #define QCN9074_DEVICE_ID 0x1104 #define WCN6855_DEVICE_ID 0x1103 +#define TCSR_SOC_HW_SUB_VER 0x1910010 + static const struct pci_device_id ath11k_pci_id_table[] = { { PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) }, { PCI_VDEVICE(QCOM, WCN6855_DEVICE_ID) }, @@ -743,6 +745,7 @@ static int ath11k_pci_probe(struct pci_dev *pdev, struct ath11k_pci *ab_pci; u32 soc_hw_version_major, soc_hw_version_minor, addr; int ret; + u32 sub_version; ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI); @@ -833,7 +836,19 @@ static int ath11k_pci_probe(struct pci_dev *pdev, break; case 0x10: case 0x11: - ab->hw_rev = ATH11K_HW_WCN6855_HW21; + sub_version = ath11k_pcic_read32(ab, TCSR_SOC_HW_SUB_VER); + ath11k_dbg(ab, ATH11K_DBG_PCI, "sub_version 0x%x\n", + sub_version); + switch (sub_version) { + case 0x1019A0E1: + case 0x1019B0E1: + case 0x1019C0E1: + case 0x1019D0E1: + ab->hw_rev = ATH11K_HW_QCA2066_HW21; + break; + default: + ab->hw_rev = ATH11K_HW_WCN6855_HW21; + } break; default: goto unsupported_wcn6855_soc; diff --git a/drivers/net/wireless/ath/ath11k/pcic.c b/drivers/net/wireless/ath/ath11k/pcic.c index 15e2ceb22a44..add4db4c50bc 100644 --- a/drivers/net/wireless/ath/ath11k/pcic.c +++ b/drivers/net/wireless/ath/ath11k/pcic.c @@ -115,6 +115,17 @@ static const struct ath11k_msi_config ath11k_msi_config[] = { }, .hw_rev = ATH11K_HW_WCN6750_HW10, }, + { + .total_vectors = 32, + .total_users = 4, + .users = (struct ath11k_msi_user[]) { + { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, + { .name = "CE", .num_vectors = 10, .base_vector = 3 }, + { .name = "WAKE", .num_vectors = 1, .base_vector = 13 }, + { .name = "DP", .num_vectors = 18, .base_vector = 14 }, + }, + .hw_rev = ATH11K_HW_QCA2066_HW21, + }, }; int ath11k_pcic_init_msi_config(struct ath11k_base *ab) -- cgit From 3ab6aff5793c3c7bdf6535d9b0024544a4abbdd5 Mon Sep 17 00:00:00 2001 From: Nicolas Escande Date: Sun, 11 Feb 2024 16:10:36 +0100 Subject: wifi: ath11k: remove unused scan_events from struct scan_req_params As discussed lets remove the unused scan_events field from struct scan_req_params. Also, as it is not needed anymore, remove the underlying union wrapping too. No functionnal changes. Link: https://lore.kernel.org/all/4be7d62e-cb59-462d-aac2-94e27efc22ff@quicinc.com/ Signed-off-by: Nicolas Escande Signed-off-by: Kalle Valo Link: https://msgid.link/20240211151036.1950292-1-nico.escande@gmail.com --- drivers/net/wireless/ath/ath11k/wmi.h | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index bc7adf7f13fb..bb419e3abb00 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -3363,24 +3363,19 @@ struct scan_req_params { u32 vdev_id; u32 pdev_id; enum wmi_scan_priority scan_priority; - union { - struct { - u32 scan_ev_started:1, - scan_ev_completed:1, - scan_ev_bss_chan:1, - scan_ev_foreign_chan:1, - scan_ev_dequeued:1, - scan_ev_preempted:1, - scan_ev_start_failed:1, - scan_ev_restarted:1, - scan_ev_foreign_chn_exit:1, - scan_ev_invalid:1, - scan_ev_gpio_timeout:1, - scan_ev_suspended:1, - scan_ev_resumed:1; - }; - u32 scan_events; - }; + u32 scan_ev_started:1, + scan_ev_completed:1, + scan_ev_bss_chan:1, + scan_ev_foreign_chan:1, + scan_ev_dequeued:1, + scan_ev_preempted:1, + scan_ev_start_failed:1, + scan_ev_restarted:1, + scan_ev_foreign_chn_exit:1, + scan_ev_invalid:1, + scan_ev_gpio_timeout:1, + scan_ev_suspended:1, + scan_ev_resumed:1; u32 scan_ctrl_flags_ext; u32 dwell_time_active; u32 dwell_time_active_2g; -- cgit From 6030b3a469f8936d7f0f928e788f12a4fe14a4ca Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Fri, 16 Feb 2024 20:16:20 +0530 Subject: wifi: mac80211: check beacon countdown is complete on per link basis Currently, function to check if beacon countdown is complete uses deflink to fetch the beacon and check the counter. However, with MLO, there is a need to check the counter for the beacon in a particular link. Add support to use link_id in order to fetch the beacon from a particular link data. Signed-off-by: Aditya Kumar Singh Link: https://msgid.link/20240216144621.514385-2-quic_adisi@quicinc.com Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- drivers/net/wireless/ath/ath11k/mac.c | 2 +- drivers/net/wireless/ath/ath9k/beacon.c | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 2 +- drivers/net/wireless/mediatek/mt76/mac80211.c | 4 ++-- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 2 +- drivers/net/wireless/virtual/mac80211_hwsim.c | 2 +- include/net/mac80211.h | 4 +++- net/mac80211/tx.c | 14 ++++++++++++-- 12 files changed, 26 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 41053219ee95..e322b528baaf 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2034,7 +2034,7 @@ static void ath10k_mac_vif_ap_csa_count_down(struct ath10k_vif *arvif) if (!arvif->is_up) return; - if (!ieee80211_beacon_cntdwn_is_complete(vif)) { + if (!ieee80211_beacon_cntdwn_is_complete(vif, 0)) { ieee80211_beacon_update_cntdwn(vif, 0); ret = ath10k_mac_setup_bcn_tmpl(arvif); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index ddf15717d504..2e9661f4bea8 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3884,7 +3884,7 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) * actual channel switch is done */ if (arvif->vif->bss_conf.csa_active && - ieee80211_beacon_cntdwn_is_complete(arvif->vif)) { + ieee80211_beacon_cntdwn_is_complete(arvif->vif, 0)) { ieee80211_csa_finish(arvif->vif, 0); continue; } diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index f7cab50bdfd1..a1e2729582e8 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1577,7 +1577,7 @@ void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif) return; if (vif->bss_conf.color_change_active && - ieee80211_beacon_cntdwn_is_complete(vif)) { + ieee80211_beacon_cntdwn_is_complete(vif, 0)) { arvif->bcca_zero_sent = true; ieee80211_color_change_finish(vif); return; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 4e48407138b2..b399a7926ef5 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -365,7 +365,7 @@ bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif) if (!vif || !vif->bss_conf.csa_active) return false; - if (!ieee80211_beacon_cntdwn_is_complete(vif)) + if (!ieee80211_beacon_cntdwn_is_complete(vif, 0)) return false; ieee80211_csa_finish(vif, 0); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 8179d35dc310..547634f82183 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -514,7 +514,7 @@ bool ath9k_htc_csa_is_finished(struct ath9k_htc_priv *priv) if (!vif || !vif->bss_conf.csa_active) return false; - if (!ieee80211_beacon_cntdwn_is_complete(vif)) + if (!ieee80211_beacon_cntdwn_is_complete(vif, 0)) return false; ieee80211_csa_finish(vif, 0); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index cc592e288188..123fe9bba982 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1466,7 +1466,7 @@ static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm, mvmvif->csa_countdown = true; - if (!ieee80211_beacon_cntdwn_is_complete(csa_vif)) { + if (!ieee80211_beacon_cntdwn_is_complete(csa_vif, 0)) { int c = ieee80211_beacon_update_cntdwn(csa_vif, 0); iwl_mvm_mac_ctxt_beacon_changed(mvm, csa_vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 89b1c7a87660..a59d264a11c5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -156,7 +156,7 @@ static void iwl_mvm_csa_noa_start(struct iwl_mvm *mvm) * So we just do nothing here and the switch * will be performed on the last TBTT. */ - if (!ieee80211_beacon_cntdwn_is_complete(csa_vif)) { + if (!ieee80211_beacon_cntdwn_is_complete(csa_vif, 0)) { IWL_WARN(mvm, "CSA NOA started too early\n"); goto out_unlock; } diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 8bf82755ca4c..758e380fdf1d 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1613,7 +1613,7 @@ EXPORT_SYMBOL_GPL(mt76_get_sar_power); static void __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { - if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) + if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif, 0)) ieee80211_csa_finish(vif, 0); } @@ -1638,7 +1638,7 @@ __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif) if (!vif->bss_conf.csa_active) return; - dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif); + dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif, 0); } void mt76_csa_check(struct mt76_dev *dev) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 66bf92c164c3..db5041d23938 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5739,7 +5739,7 @@ static void rtl8xxxu_update_beacon_work_callback(struct work_struct *work) } if (vif->bss_conf.csa_active) { - if (ieee80211_beacon_cntdwn_is_complete(vif)) { + if (ieee80211_beacon_cntdwn_is_complete(vif, 0)) { ieee80211_csa_finish(vif, 0); return; } diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 0554946ed30e..2ea11a86d920 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -2305,7 +2305,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, rcu_dereference(link_conf->chanctx_conf)->def.chan); } - if (link_conf->csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) + if (link_conf->csa_active && ieee80211_beacon_cntdwn_is_complete(vif, link_id)) ieee80211_csa_finish(vif, link_id); } diff --git a/include/net/mac80211.h b/include/net/mac80211.h index fc223761e3af..25c892ea9eb3 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -5566,10 +5566,12 @@ void ieee80211_csa_finish(struct ieee80211_vif *vif, unsigned int link_id); /** * ieee80211_beacon_cntdwn_is_complete - find out if countdown reached 1 * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @link_id: valid link_id during MLO or 0 for non-MLO * * This function returns whether the countdown reached zero. */ -bool ieee80211_beacon_cntdwn_is_complete(struct ieee80211_vif *vif); +bool ieee80211_beacon_cntdwn_is_complete(struct ieee80211_vif *vif, + unsigned int link_id); /** * ieee80211_color_change_finish - notify mac80211 about color change diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index f4be4af568be..6bf223e6cd1a 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -5095,9 +5095,11 @@ unlock: } EXPORT_SYMBOL(ieee80211_beacon_set_cntdwn); -bool ieee80211_beacon_cntdwn_is_complete(struct ieee80211_vif *vif) +bool ieee80211_beacon_cntdwn_is_complete(struct ieee80211_vif *vif, + unsigned int link_id) { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_link_data *link; struct beacon_data *beacon = NULL; u8 *beacon_data; size_t beacon_data_len; @@ -5106,9 +5108,17 @@ bool ieee80211_beacon_cntdwn_is_complete(struct ieee80211_vif *vif) if (!ieee80211_sdata_running(sdata)) return false; + if (WARN_ON(link_id >= IEEE80211_MLD_MAX_NUM_LINKS)) + return 0; + rcu_read_lock(); + + link = rcu_dereference(sdata->link[link_id]); + if (!link) + goto out; + if (vif->type == NL80211_IFTYPE_AP) { - beacon = rcu_dereference(sdata->deflink.u.ap.beacon); + beacon = rcu_dereference(link->u.ap.beacon); if (WARN_ON(!beacon || !beacon->tail)) goto out; beacon_data = beacon->tail; -- cgit From 7f501452364e2c1e38a819bcc96bdfdf59d2bbda Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Fri, 16 Feb 2024 20:16:21 +0530 Subject: wifi: mac80211_hwsim: add support for switch_vif_chanctx callback Currently switch_vif_chanctx mac80211 callback is not supported for MLO. Add it. Signed-off-by: Aditya Kumar Singh Link: https://msgid.link/20240216144621.514385-3-quic_adisi@quicinc.com Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/mac80211_hwsim.c | 44 ++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 2ea11a86d920..b55fe320633c 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -3215,6 +3215,47 @@ static void mac80211_hwsim_unassign_vif_chanctx(struct ieee80211_hw *hw, } } +static int mac80211_hwsim_switch_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif_chanctx_switch *vifs, + int n_vifs, + enum ieee80211_chanctx_switch_mode mode) +{ + int i; + + if (n_vifs <= 0) + return -EINVAL; + + wiphy_dbg(hw->wiphy, + "switch vif channel context mode: %u\n", mode); + + for (i = 0; i < n_vifs; i++) { + hwsim_check_chanctx_magic(vifs[i].old_ctx); + wiphy_dbg(hw->wiphy, + "switch vif channel context: %d MHz/width: %d/cfreqs:%d/%d MHz -> %d MHz/width: %d/cfreqs:%d/%d MHz\n", + vifs[i].old_ctx->def.chan->center_freq, + vifs[i].old_ctx->def.width, + vifs[i].old_ctx->def.center_freq1, + vifs[i].old_ctx->def.center_freq2, + vifs[i].new_ctx->def.chan->center_freq, + vifs[i].new_ctx->def.width, + vifs[i].new_ctx->def.center_freq1, + vifs[i].new_ctx->def.center_freq2); + + switch (mode) { + case CHANCTX_SWMODE_REASSIGN_VIF: + hwsim_check_chanctx_magic(vifs[i].new_ctx); + break; + case CHANCTX_SWMODE_SWAP_CONTEXTS: + hwsim_set_chanctx_magic(vifs[i].new_ctx); + hwsim_clear_chanctx_magic(vifs[i].old_ctx); + break; + default: + WARN_ON("Invalid mode"); + } + } + return 0; +} + static const char mac80211_hwsim_gstrings_stats[][ETH_GSTRING_LEN] = { "tx_pkts_nic", "tx_bytes_nic", @@ -3940,7 +3981,8 @@ static const struct ieee80211_ops mac80211_hwsim_ops = { .remove_chanctx = mac80211_hwsim_remove_chanctx, \ .change_chanctx = mac80211_hwsim_change_chanctx, \ .assign_vif_chanctx = mac80211_hwsim_assign_vif_chanctx,\ - .unassign_vif_chanctx = mac80211_hwsim_unassign_vif_chanctx, + .unassign_vif_chanctx = mac80211_hwsim_unassign_vif_chanctx, \ + .switch_vif_chanctx = mac80211_hwsim_switch_vif_chanctx, static const struct ieee80211_ops mac80211_hwsim_mchan_ops = { HWSIM_COMMON_OPS -- cgit From d73fbaf24c5a1e0698a7a5e17d66a5100efef72a Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Tue, 6 Feb 2024 16:54:06 +0200 Subject: wifi: mac80211: make associated BSS pointer visible to the driver Some drivers need the data in it, so move it to the link conf, which is exposed to the driver. Signed-off-by: Miri Korenblit Link: https://msgid.link/20240206164849.6fe9782b87b4.Ifbffef638f07ca7f5c2b27f40d2cf2942d21de0b@changeid [remove bss pointer from internal struct, update docs] Signed-off-by: Johannes Berg --- include/net/mac80211.h | 5 +++++ net/mac80211/ieee80211_i.h | 2 -- net/mac80211/mlme.c | 18 +++++++++--------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 25c892ea9eb3..56c6ecb2c10a 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -557,6 +557,10 @@ struct ieee80211_fils_discovery { * to that BSS) that can change during the lifetime of the BSS. * * @vif: reference to owning VIF + * @bss: the cfg80211 bss descriptor. Valid only for a station, and only + * when associated. Note: This contains information which is not + * necessarily authenticated. For example, information coming from probe + * responses. * @addr: (link) address used locally * @link_id: link ID, or 0 for non-MLO * @htc_trig_based_pkt_ext: default PE in 4us units, if BSS supports HE @@ -700,6 +704,7 @@ struct ieee80211_fils_discovery { */ struct ieee80211_bss_conf { struct ieee80211_vif *vif; + struct cfg80211_bss *bss; const u8 *bssid; unsigned int link_id; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f3edb1a148a7..4bec625a84d1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1006,8 +1006,6 @@ struct ieee80211_link_data_managed { int mu_edca_last_param_set; u8 bss_param_ch_cnt; - - struct cfg80211_bss *bss; }; struct ieee80211_link_data_ap { diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e1554666d706..87ffc19770b8 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2015,7 +2015,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct cfg80211_bss *cbss = link->u.mgd.bss; + struct cfg80211_bss *cbss = link->conf->bss; struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *chanctx; enum nl80211_band current_band; @@ -2928,7 +2928,7 @@ static u64 ieee80211_link_set_associated(struct ieee80211_link_data *link, ieee80211_check_rate_mask(link); - link->u.mgd.bss = cbss; + link->conf->bss = cbss; memcpy(link->u.mgd.bssid, cbss->bssid, ETH_ALEN); if (sdata->vif.p2p || @@ -3076,7 +3076,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ifmgd->associated = false; /* other links will be destroyed */ - sdata->deflink.u.mgd.bss = NULL; + sdata->deflink.conf->bss = NULL; sdata->deflink.smps_mode = IEEE80211_SMPS_OFF; netif_carrier_off(sdata->dev); @@ -3406,7 +3406,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) ieee80211_mlme_send_probe_req(sdata, sdata->vif.addr, dst, sdata->vif.cfg.ssid, sdata->vif.cfg.ssid_len, - sdata->deflink.u.mgd.bss->channel); + sdata->deflink.conf->bss->channel); } ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); @@ -3489,7 +3489,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, return NULL; if (ifmgd->associated) - cbss = sdata->deflink.u.mgd.bss; + cbss = sdata->deflink.conf->bss; else if (ifmgd->auth_data) cbss = ifmgd->auth_data->bss; else if (ifmgd->assoc_data && ifmgd->assoc_data->link[0].bss) @@ -3568,8 +3568,8 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) link = sdata_dereference(sdata->link[link_id], sdata); if (!link) continue; - cfg80211_unlink_bss(local->hw.wiphy, link->u.mgd.bss); - link->u.mgd.bss = NULL; + cfg80211_unlink_bss(local->hw.wiphy, link->conf->bss); + link->conf->bss = NULL; } } @@ -6208,7 +6208,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, } if (!ifmgd->associated || - !ieee80211_rx_our_beacon(bssid, link->u.mgd.bss)) + !ieee80211_rx_our_beacon(bssid, link->conf->bss)) return; bssid = link->u.mgd.bssid; @@ -6235,7 +6235,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, */ if (!ieee80211_is_s1g_beacon(hdr->frame_control)) ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); - parse_params.bss = link->u.mgd.bss; + parse_params.bss = link->conf->bss; parse_params.filter = care_about_ies; parse_params.crc = ncrc; elems = ieee802_11_parse_elems_full(&parse_params); -- cgit From ba4b1fa3128b2fbf14e167230315cbd9074b629b Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 15 Feb 2024 23:21:51 +0000 Subject: wifi: mac80211: clean up assignments to pointer cache. The assignment to pointer cache in function mesh_fast_tx_gc can be made at the declaration time rather than a later assignment. There are also 3 functions where pointer cache is being initialized at declaration time and later re-assigned again with the same value, these are redundant and can be removed. Cleans up code and three clang scan build warnings: warning: Value stored to 'cache' during its initialization is never read [deadcode.DeadStores] Signed-off-by: Colin Ian King Reviewed-by: Simon Horman Link: https://msgid.link/20240215232151.2075483-1-colin.i.king@gmail.com Signed-off-by: Johannes Berg --- net/mac80211/mesh_pathtbl.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 735edde1bd81..91b55d6a68b9 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -600,11 +600,10 @@ unlock_sta: void mesh_fast_tx_gc(struct ieee80211_sub_if_data *sdata) { unsigned long timeout = msecs_to_jiffies(MESH_FAST_TX_CACHE_TIMEOUT); - struct mesh_tx_cache *cache; + struct mesh_tx_cache *cache = &sdata->u.mesh.tx_cache; struct ieee80211_mesh_fast_tx *entry; struct hlist_node *n; - cache = &sdata->u.mesh.tx_cache; if (atomic_read(&cache->rht.nelems) < MESH_FAST_TX_CACHE_THRESHOLD_SIZE) return; @@ -622,7 +621,6 @@ void mesh_fast_tx_flush_mpath(struct mesh_path *mpath) struct ieee80211_mesh_fast_tx *entry; struct hlist_node *n; - cache = &sdata->u.mesh.tx_cache; spin_lock_bh(&cache->walk_lock); hlist_for_each_entry_safe(entry, n, &cache->walk_head, walk_list) if (entry->mpath == mpath) @@ -637,7 +635,6 @@ void mesh_fast_tx_flush_sta(struct ieee80211_sub_if_data *sdata, struct ieee80211_mesh_fast_tx *entry; struct hlist_node *n; - cache = &sdata->u.mesh.tx_cache; spin_lock_bh(&cache->walk_lock); hlist_for_each_entry_safe(entry, n, &cache->walk_head, walk_list) if (rcu_access_pointer(entry->mpath->next_hop) == sta) @@ -651,7 +648,6 @@ void mesh_fast_tx_flush_addr(struct ieee80211_sub_if_data *sdata, struct mesh_tx_cache *cache = &sdata->u.mesh.tx_cache; struct ieee80211_mesh_fast_tx *entry; - cache = &sdata->u.mesh.tx_cache; spin_lock_bh(&cache->walk_lock); entry = rhashtable_lookup_fast(&cache->rht, addr, fast_tx_rht_params); if (entry) -- cgit From f79ab5d2bced9bd7c0ce86d2aa5b70d053001bb4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 15 Feb 2024 17:41:36 +0200 Subject: wifi: cfg80211: Add KHZ_PER_GHZ to units.h and reuse The KHZ_PER_GHZ might be used by others (with the name aligned with similar constants). Define it in units.h and convert wireless to use it. Signed-off-by: Andy Shevchenko Reviewed-by: Simon Horman Link: https://msgid.link/20240215154136.630029-1-andriy.shevchenko@linux.intel.com Signed-off-by: Johannes Berg --- include/linux/units.h | 5 ++++- net/wireless/reg.c | 7 +++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/linux/units.h b/include/linux/units.h index 45110daaf8d3..00e15de33eca 100644 --- a/include/linux/units.h +++ b/include/linux/units.h @@ -24,10 +24,13 @@ #define NANOHZ_PER_HZ 1000000000UL #define MICROHZ_PER_HZ 1000000UL #define MILLIHZ_PER_HZ 1000UL + #define HZ_PER_KHZ 1000UL -#define KHZ_PER_MHZ 1000UL #define HZ_PER_MHZ 1000000UL +#define KHZ_PER_MHZ 1000UL +#define KHZ_PER_GHZ 1000000UL + #define MILLIWATT_PER_WATT 1000UL #define MICROWATT_PER_MILLIWATT 1000UL #define MICROWATT_PER_WATT 1000000UL diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 50cadbad485f..753f8e9aa4b1 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -57,6 +57,8 @@ #include #include #include +#include + #include #include "core.h" #include "reg.h" @@ -1289,20 +1291,17 @@ static bool is_valid_rd(const struct ieee80211_regdomain *rd) static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, u32 freq_khz) { -#define ONE_GHZ_IN_KHZ 1000000 /* * From 802.11ad: directional multi-gigabit (DMG): * Pertaining to operation in a frequency band containing a channel * with the Channel starting frequency above 45 GHz. */ - u32 limit = freq_khz > 45 * ONE_GHZ_IN_KHZ ? - 20 * ONE_GHZ_IN_KHZ : 2 * ONE_GHZ_IN_KHZ; + u32 limit = freq_khz > 45 * KHZ_PER_GHZ ? 20 * KHZ_PER_GHZ : 2 * KHZ_PER_GHZ; if (abs(freq_khz - freq_range->start_freq_khz) <= limit) return true; if (abs(freq_khz - freq_range->end_freq_khz) <= limit) return true; return false; -#undef ONE_GHZ_IN_KHZ } /* -- cgit From f8599d634094b1257054a8d0815785d658cbdb74 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Fri, 16 Feb 2024 13:54:27 +0200 Subject: wifi: cfg80211: set correct param change count in ML element The ML element generation code to create a BSS entry from a per-STA profile was not overwriting the BSS parameter change count. This meant that the incorrect parameter change count would be reported within the multi-link element. Fix this by returning the BSS parameter change count from the function and placing it into the ML element. The returned tbtt info was never used, so just drop that to simplify the code. Fixes: 5f478adf1f99 ("wifi: cfg80211: generate an ML element for per-STA profiles") Signed-off-by: Benjamin Berg Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240216135047.f2a507634692.I06b122c7a319a38b4e970f5e0bd3d3ef9cac4cbe@changeid Signed-off-by: Johannes Berg --- net/wireless/scan.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 88e8b25c073a..0907a72231ee 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -2567,9 +2567,9 @@ error: } static u8 -cfg80211_tbtt_info_for_mld_ap(const u8 *ie, size_t ielen, u8 mld_id, u8 link_id, - const struct ieee80211_neighbor_ap_info **ap_info, - const u8 **tbtt_info) +cfg80211_rnr_info_for_mld_ap(const u8 *ie, size_t ielen, u8 mld_id, u8 link_id, + const struct ieee80211_neighbor_ap_info **ap_info, + u8 *param_ch_count) { const struct ieee80211_neighbor_ap_info *info; const struct element *rnr; @@ -2626,7 +2626,9 @@ cfg80211_tbtt_info_for_mld_ap(const u8 *ie, size_t ielen, u8 mld_id, u8 link_id, if (mld_id == mld_params->mld_id && link_id == lid) { *ap_info = info; - *tbtt_info = pos; + *param_ch_count = + le16_get_bits(mld_params->params, + IEEE80211_RNR_MLD_PARAMS_BSS_CHANGE_COUNT); return use_for; } @@ -2836,8 +2838,8 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, enum nl80211_band band; u32 freq; const u8 *profile; - const u8 *tbtt_info; ssize_t profile_len; + u8 param_ch_count; u8 link_id, use_for; if (!ieee80211_mle_basic_sta_prof_size_ok((u8 *)mle->sta_prof[i], @@ -2880,10 +2882,11 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, profile_len -= 2; /* Find in RNR to look up channel information */ - use_for = cfg80211_tbtt_info_for_mld_ap(tx_data->ie, - tx_data->ielen, - mld_id, link_id, - &ap_info, &tbtt_info); + use_for = cfg80211_rnr_info_for_mld_ap(tx_data->ie, + tx_data->ielen, + mld_id, link_id, + &ap_info, + ¶m_ch_count); if (!use_for) continue; @@ -2926,7 +2929,8 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, continue; /* Copy the Basic Multi-Link element including the common - * information, and then fix up the link ID. + * information, and then fix up the link ID and BSS param + * change count. * Note that the ML element length has been verified and we * also checked that it contains the link ID. */ @@ -2937,6 +2941,8 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, sizeof(*ml_elem) + ml_common_len); new_ie[data.ielen + sizeof(*ml_elem) + 1 + ETH_ALEN] = link_id; + new_ie[data.ielen + sizeof(*ml_elem) + 1 + ETH_ALEN + 1] = + param_ch_count; data.ielen += sizeof(*ml_elem) + ml_common_len; -- cgit From 317bad4c3b61eaf14a7f5c65521a3aa8b0b6f1bc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Feb 2024 13:54:28 +0200 Subject: wifi: cfg80211: remove cfg80211_inform_single_bss_frame_data() This function pretty much does what cfg80211_inform_single_bss_data() already does, except on a frame data. But we can call the other one, after populating the inform_data more completely, so we don't need to do everything twice. This also uncovered a few bugs: * the 6 GHz power type checks were only done in this function, move (and rename from 'uhb') those; * the chains/chain_signal information wasn't used in the latter, add that Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240216135047.f3f864f94c78.I2192adb32ab10713e71f395a9d203386264f6ed5@changeid Signed-off-by: Johannes Berg --- net/wireless/scan.c | 245 +++++++++++++++++----------------------------------- 1 file changed, 80 insertions(+), 165 deletions(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 0907a72231ee..754138168646 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -2087,6 +2087,35 @@ struct cfg80211_inform_single_bss_data { u64 cannot_use_reasons; }; +static bool cfg80211_6ghz_power_type_valid(const u8 *ie, size_t ielen, + const u32 flags) +{ + const struct element *tmp; + struct ieee80211_he_operation *he_oper; + + tmp = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ie, ielen); + if (tmp && tmp->datalen >= sizeof(*he_oper) + 1) { + const struct ieee80211_he_6ghz_oper *he_6ghz_oper; + + he_oper = (void *)&tmp->data[1]; + he_6ghz_oper = ieee80211_he_6ghz_oper(he_oper); + + if (!he_6ghz_oper) + return false; + + switch (u8_get_bits(he_6ghz_oper->control, + IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO)) { + case IEEE80211_6GHZ_CTRL_REG_LPI_AP: + return true; + case IEEE80211_6GHZ_CTRL_REG_SP_AP: + return !(flags & IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT); + case IEEE80211_6GHZ_CTRL_REG_VLP_AP: + return !(flags & IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT); + } + } + return false; +} + /* Returned bss is reference counted and must be cleaned up appropriately. */ static struct cfg80211_bss * cfg80211_inform_single_bss_data(struct wiphy *wiphy, @@ -2119,6 +2148,14 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, if (!channel) return NULL; + if (channel->band == NL80211_BAND_6GHZ && + !cfg80211_6ghz_power_type_valid(data->ie, data->ielen, + channel->flags)) { + data->use_for = 0; + data->cannot_use_reasons = + NL80211_BSS_CANNOT_USE_6GHZ_PWR_MISMATCH; + } + memcpy(tmp.pub.bssid, data->bssid, ETH_ALEN); tmp.pub.channel = channel; if (data->bss_source != BSS_SOURCE_STA_PROFILE) @@ -2130,6 +2167,9 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, tmp.ts_boottime = drv_data->boottime_ns; tmp.parent_tsf = drv_data->parent_tsf; ether_addr_copy(tmp.parent_bssid, drv_data->parent_bssid); + tmp.pub.chains = drv_data->chains; + memcpy(tmp.pub.chain_signal, drv_data->chain_signal, + IEEE80211_MAX_CHAINS); tmp.pub.use_for = data->use_for; tmp.pub.cannot_use_reasons = data->cannot_use_reasons; @@ -3025,59 +3065,23 @@ cfg80211_inform_bss_data(struct wiphy *wiphy, } EXPORT_SYMBOL(cfg80211_inform_bss_data); -static bool cfg80211_uhb_power_type_valid(const u8 *ie, - size_t ielen, - const u32 flags) -{ - const struct element *tmp; - struct ieee80211_he_operation *he_oper; - - tmp = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ie, ielen); - if (tmp && tmp->datalen >= sizeof(*he_oper) + 1) { - const struct ieee80211_he_6ghz_oper *he_6ghz_oper; - - he_oper = (void *)&tmp->data[1]; - he_6ghz_oper = ieee80211_he_6ghz_oper(he_oper); - - if (!he_6ghz_oper) - return false; - - switch (u8_get_bits(he_6ghz_oper->control, - IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO)) { - case IEEE80211_6GHZ_CTRL_REG_LPI_AP: - return true; - case IEEE80211_6GHZ_CTRL_REG_SP_AP: - return !(flags & IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT); - case IEEE80211_6GHZ_CTRL_REG_VLP_AP: - return !(flags & IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT); - } - } - return false; -} - -/* cfg80211_inform_bss_width_frame helper */ -static struct cfg80211_bss * -cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy, - struct cfg80211_inform_bss *data, - struct ieee80211_mgmt *mgmt, size_t len, - gfp_t gfp) +struct cfg80211_bss * +cfg80211_inform_bss_frame_data(struct wiphy *wiphy, + struct cfg80211_inform_bss *data, + struct ieee80211_mgmt *mgmt, size_t len, + gfp_t gfp) { - struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); - struct cfg80211_internal_bss tmp = {}, *res; - struct cfg80211_bss_ies *ies; - struct ieee80211_channel *channel; - bool signal_valid; + struct cfg80211_inform_single_bss_data inform_data = { + .drv_data = data, + .use_for = data->restrict_use ? + data->use_for : + NL80211_BSS_USE_FOR_ALL, + .cannot_use_reasons = data->cannot_use_reasons, + }; + size_t min_hdr_len = offsetof(struct ieee80211_mgmt, + u.probe_resp.variable); struct ieee80211_ext *ext = NULL; - u8 *bssid, *variable; - u16 capability, beacon_int; - size_t ielen, min_hdr_len = offsetof(struct ieee80211_mgmt, - u.probe_resp.variable); - int bss_type; - - BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) != - offsetof(struct ieee80211_mgmt, u.beacon.variable)); - - trace_cfg80211_inform_bss_frame(wiphy, data, mgmt, len); + struct cfg80211_bss *res; if (WARN_ON(!mgmt)) return NULL; @@ -3085,9 +3089,10 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy, if (WARN_ON(!wiphy)) return NULL; - if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC && - (data->signal < 0 || data->signal > 100))) - return NULL; + BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) != + offsetof(struct ieee80211_mgmt, u.beacon.variable)); + + trace_cfg80211_inform_bss_frame(wiphy, data, mgmt, len); if (ieee80211_is_s1g_beacon(mgmt->frame_control)) { ext = (void *) mgmt; @@ -3100,140 +3105,50 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy, if (WARN_ON(len < min_hdr_len)) return NULL; - ielen = len - min_hdr_len; - variable = mgmt->u.probe_resp.variable; - if (ext) { - if (ieee80211_is_s1g_short_beacon(mgmt->frame_control)) - variable = ext->u.s1g_short_beacon.variable; - else - variable = ext->u.s1g_beacon.variable; - } - - channel = cfg80211_get_bss_channel(wiphy, variable, ielen, data->chan); - if (!channel) - return NULL; - - if (channel->band == NL80211_BAND_6GHZ && - !cfg80211_uhb_power_type_valid(variable, ielen, channel->flags)) { - data->restrict_use = 1; - data->use_for = 0; - data->cannot_use_reasons = - NL80211_BSS_CANNOT_USE_6GHZ_PWR_MISMATCH; - } - + inform_data.ielen = len - min_hdr_len; + inform_data.ie = mgmt->u.probe_resp.variable; if (ext) { const struct ieee80211_s1g_bcn_compat_ie *compat; const struct element *elem; + if (ieee80211_is_s1g_short_beacon(mgmt->frame_control)) + inform_data.ie = ext->u.s1g_short_beacon.variable; + else + inform_data.ie = ext->u.s1g_beacon.variable; + elem = cfg80211_find_elem(WLAN_EID_S1G_BCN_COMPAT, - variable, ielen); + inform_data.ie, inform_data.ielen); if (!elem) return NULL; if (elem->datalen < sizeof(*compat)) return NULL; compat = (void *)elem->data; - bssid = ext->u.s1g_beacon.sa; - capability = le16_to_cpu(compat->compat_info); - beacon_int = le16_to_cpu(compat->beacon_int); + memcpy(inform_data.bssid, ext->u.s1g_beacon.sa, ETH_ALEN); + inform_data.capability = le16_to_cpu(compat->compat_info); + inform_data.beacon_interval = le16_to_cpu(compat->beacon_int); } else { - bssid = mgmt->bssid; - beacon_int = le16_to_cpu(mgmt->u.probe_resp.beacon_int); - capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); + memcpy(inform_data.bssid, mgmt->bssid, ETH_ALEN); + inform_data.beacon_interval = + le16_to_cpu(mgmt->u.probe_resp.beacon_int); + inform_data.capability = + le16_to_cpu(mgmt->u.probe_resp.capab_info); } - if (channel->band == NL80211_BAND_60GHZ) { - bss_type = capability & WLAN_CAPABILITY_DMG_TYPE_MASK; - if (bss_type == WLAN_CAPABILITY_DMG_TYPE_AP || - bss_type == WLAN_CAPABILITY_DMG_TYPE_PBSS) - regulatory_hint_found_beacon(wiphy, channel, gfp); - } else { - if (capability & WLAN_CAPABILITY_ESS) - regulatory_hint_found_beacon(wiphy, channel, gfp); - } - - ies = kzalloc(sizeof(*ies) + ielen, gfp); - if (!ies) - return NULL; - ies->len = ielen; - ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); - ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control) || - ieee80211_is_s1g_beacon(mgmt->frame_control); - memcpy(ies->data, variable, ielen); + inform_data.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); if (ieee80211_is_probe_resp(mgmt->frame_control)) - rcu_assign_pointer(tmp.pub.proberesp_ies, ies); + inform_data.ftype = CFG80211_BSS_FTYPE_PRESP; else - rcu_assign_pointer(tmp.pub.beacon_ies, ies); - rcu_assign_pointer(tmp.pub.ies, ies); + inform_data.ftype = CFG80211_BSS_FTYPE_BEACON; - memcpy(tmp.pub.bssid, bssid, ETH_ALEN); - tmp.pub.beacon_interval = beacon_int; - tmp.pub.capability = capability; - tmp.pub.channel = channel; - tmp.pub.signal = data->signal; - tmp.ts_boottime = data->boottime_ns; - tmp.parent_tsf = data->parent_tsf; - tmp.pub.chains = data->chains; - memcpy(tmp.pub.chain_signal, data->chain_signal, IEEE80211_MAX_CHAINS); - ether_addr_copy(tmp.parent_bssid, data->parent_bssid); - tmp.pub.use_for = data->restrict_use ? - data->use_for : - NL80211_BSS_USE_FOR_ALL; - tmp.pub.cannot_use_reasons = data->cannot_use_reasons; - - signal_valid = data->chan == channel; - spin_lock_bh(&rdev->bss_lock); - res = __cfg80211_bss_update(rdev, &tmp, signal_valid, jiffies); - if (!res) - goto drop; - - rdev_inform_bss(rdev, &res->pub, ies, data->drv_data); - - spin_unlock_bh(&rdev->bss_lock); - - trace_cfg80211_return_bss(&res->pub); - /* __cfg80211_bss_update gives us a referenced result */ - return &res->pub; - -drop: - spin_unlock_bh(&rdev->bss_lock); - return NULL; -} - -struct cfg80211_bss * -cfg80211_inform_bss_frame_data(struct wiphy *wiphy, - struct cfg80211_inform_bss *data, - struct ieee80211_mgmt *mgmt, size_t len, - gfp_t gfp) -{ - struct cfg80211_inform_single_bss_data inform_data = { - .drv_data = data, - .ie = mgmt->u.probe_resp.variable, - .ielen = len - offsetof(struct ieee80211_mgmt, - u.probe_resp.variable), - .use_for = data->restrict_use ? - data->use_for : - NL80211_BSS_USE_FOR_ALL, - .cannot_use_reasons = data->cannot_use_reasons, - }; - struct cfg80211_bss *res; - - res = cfg80211_inform_single_bss_frame_data(wiphy, data, mgmt, - len, gfp); + res = cfg80211_inform_single_bss_data(wiphy, &inform_data, gfp); if (!res) return NULL; /* don't do any further MBSSID/ML handling for S1G */ - if (ieee80211_is_s1g_beacon(mgmt->frame_control)) + if (ext) return res; - inform_data.ftype = ieee80211_is_beacon(mgmt->frame_control) ? - CFG80211_BSS_FTYPE_BEACON : CFG80211_BSS_FTYPE_PRESP; - memcpy(inform_data.bssid, mgmt->bssid, ETH_ALEN); - inform_data.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); - inform_data.beacon_interval = - le16_to_cpu(mgmt->u.probe_resp.beacon_int); - /* process each non-transmitting bss */ cfg80211_parse_mbssid_data(wiphy, &inform_data, res, gfp); -- cgit From 7e899c1d6f0da2a98ebf6629274ef912d4c83359 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Feb 2024 13:54:29 +0200 Subject: wifi: cfg80211: clean up cfg80211_inform_bss_frame_data() Make cfg80211_inform_bss_frame_data() call the existing cfg80211_inform_bss_data() after parsing the frame in the appropriate way, so we have less code duplication. This required introducing a new CFG80211_BSS_FTYPE_S1G_BEACON, but that can be used by other drivers as well. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240216135047.874aed1eff5f.Ib7d88d126eec50c64763251a78cb432bb5df14df@changeid Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 2 ++ net/wireless/scan.c | 71 +++++++++++++++++++++++--------------------------- 2 files changed, 34 insertions(+), 39 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 57c2298af35b..f9eada2a26ec 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -7175,11 +7175,13 @@ size_t cfg80211_merge_profile(const u8 *ie, size_t ielen, * from a beacon or probe response * @CFG80211_BSS_FTYPE_BEACON: data comes from a beacon * @CFG80211_BSS_FTYPE_PRESP: data comes from a probe response + * @CFG80211_BSS_FTYPE_S1G_BEACON: data comes from an S1G beacon */ enum cfg80211_bss_frame_type { CFG80211_BSS_FTYPE_UNKNOWN, CFG80211_BSS_FTYPE_BEACON, CFG80211_BSS_FTYPE_PRESP, + CFG80211_BSS_FTYPE_S1G_BEACON, }; /** diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 754138168646..c2d85fa4b75d 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -2213,6 +2213,7 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, switch (data->ftype) { case CFG80211_BSS_FTYPE_BEACON: + case CFG80211_BSS_FTYPE_S1G_BEACON: ies->from_beacon = true; fallthrough; case CFG80211_BSS_FTYPE_UNKNOWN: @@ -3057,6 +3058,10 @@ cfg80211_inform_bss_data(struct wiphy *wiphy, if (!res) return NULL; + /* don't do any further MBSSID/ML handling for S1G */ + if (ftype == CFG80211_BSS_FTYPE_S1G_BEACON) + return res; + cfg80211_parse_mbssid_data(wiphy, &inform_data, res, gfp); cfg80211_parse_ml_sta_data(wiphy, &inform_data, res, gfp); @@ -3071,17 +3076,16 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy, struct ieee80211_mgmt *mgmt, size_t len, gfp_t gfp) { - struct cfg80211_inform_single_bss_data inform_data = { - .drv_data = data, - .use_for = data->restrict_use ? - data->use_for : - NL80211_BSS_USE_FOR_ALL, - .cannot_use_reasons = data->cannot_use_reasons, - }; size_t min_hdr_len = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); struct ieee80211_ext *ext = NULL; - struct cfg80211_bss *res; + enum cfg80211_bss_frame_type ftype; + u16 beacon_interval; + const u8 *bssid; + u16 capability; + const u8 *ie; + size_t ielen; + u64 tsf; if (WARN_ON(!mgmt)) return NULL; @@ -3105,56 +3109,45 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy, if (WARN_ON(len < min_hdr_len)) return NULL; - inform_data.ielen = len - min_hdr_len; - inform_data.ie = mgmt->u.probe_resp.variable; + ielen = len - min_hdr_len; + ie = mgmt->u.probe_resp.variable; if (ext) { const struct ieee80211_s1g_bcn_compat_ie *compat; const struct element *elem; if (ieee80211_is_s1g_short_beacon(mgmt->frame_control)) - inform_data.ie = ext->u.s1g_short_beacon.variable; + ie = ext->u.s1g_short_beacon.variable; else - inform_data.ie = ext->u.s1g_beacon.variable; + ie = ext->u.s1g_beacon.variable; - elem = cfg80211_find_elem(WLAN_EID_S1G_BCN_COMPAT, - inform_data.ie, inform_data.ielen); + elem = cfg80211_find_elem(WLAN_EID_S1G_BCN_COMPAT, ie, ielen); if (!elem) return NULL; if (elem->datalen < sizeof(*compat)) return NULL; compat = (void *)elem->data; - memcpy(inform_data.bssid, ext->u.s1g_beacon.sa, ETH_ALEN); - inform_data.capability = le16_to_cpu(compat->compat_info); - inform_data.beacon_interval = le16_to_cpu(compat->beacon_int); + bssid = ext->u.s1g_beacon.sa; + capability = le16_to_cpu(compat->compat_info); + beacon_interval = le16_to_cpu(compat->beacon_int); } else { - memcpy(inform_data.bssid, mgmt->bssid, ETH_ALEN); - inform_data.beacon_interval = - le16_to_cpu(mgmt->u.probe_resp.beacon_int); - inform_data.capability = - le16_to_cpu(mgmt->u.probe_resp.capab_info); + bssid = mgmt->bssid; + beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); + capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); } - inform_data.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); + tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); if (ieee80211_is_probe_resp(mgmt->frame_control)) - inform_data.ftype = CFG80211_BSS_FTYPE_PRESP; + ftype = CFG80211_BSS_FTYPE_PRESP; + else if (ext) + ftype = CFG80211_BSS_FTYPE_S1G_BEACON; else - inform_data.ftype = CFG80211_BSS_FTYPE_BEACON; - - res = cfg80211_inform_single_bss_data(wiphy, &inform_data, gfp); - if (!res) - return NULL; - - /* don't do any further MBSSID/ML handling for S1G */ - if (ext) - return res; - - /* process each non-transmitting bss */ - cfg80211_parse_mbssid_data(wiphy, &inform_data, res, gfp); + ftype = CFG80211_BSS_FTYPE_BEACON; - cfg80211_parse_ml_sta_data(wiphy, &inform_data, res, gfp); - - return res; + return cfg80211_inform_bss_data(wiphy, data, ftype, + bssid, tsf, capability, + beacon_interval, ie, ielen, + gfp); } EXPORT_SYMBOL(cfg80211_inform_bss_frame_data); -- cgit From 6b756efcd9f01a7f972c0aa0da1c4f84658ba156 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Feb 2024 13:54:30 +0200 Subject: wifi: cfg80211: refactor RNR parsing We'll need more parsing of the reduced neighbor report element, and we already have two places doing pretty much the same. Combine by refactoring the parsing into a separate function with a callback for each item found. Signed-off-by: Johannes Berg Reviewed-by: Benjamin Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240216135047.cfff14b692fc.Ibe25be88a769eab29ebb17b9d19af666df6a2227@changeid Signed-off-by: Johannes Berg --- net/wireless/scan.c | 306 +++++++++++++++++++++++++++++----------------------- 1 file changed, 169 insertions(+), 137 deletions(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index c2d85fa4b75d..e46dfc71c497 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -611,104 +611,144 @@ static int cfg80211_parse_ap_info(struct cfg80211_colocated_ap *entry, return 0; } -VISIBLE_IF_CFG80211_KUNIT int -cfg80211_parse_colocated_ap(const struct cfg80211_bss_ies *ies, - struct list_head *list) +enum cfg80211_rnr_iter_ret { + RNR_ITER_CONTINUE, + RNR_ITER_BREAK, + RNR_ITER_ERROR, +}; + +static bool +cfg80211_iter_rnr(const u8 *elems, size_t elems_len, + enum cfg80211_rnr_iter_ret + (*iter)(void *data, u8 type, + const struct ieee80211_neighbor_ap_info *info, + const u8 *tbtt_info, u8 tbtt_info_len), + void *iter_data) { - struct ieee80211_neighbor_ap_info *ap_info; - const struct element *elem, *ssid_elem; + const struct element *rnr; const u8 *pos, *end; - u32 s_ssid_tmp; - int n_coloc = 0, ret; - LIST_HEAD(ap_list); - ret = cfg80211_calc_short_ssid(ies, &ssid_elem, &s_ssid_tmp); - if (ret) - return 0; + for_each_element_id(rnr, WLAN_EID_REDUCED_NEIGHBOR_REPORT, + elems, elems_len) { + const struct ieee80211_neighbor_ap_info *info; - for_each_element_id(elem, WLAN_EID_REDUCED_NEIGHBOR_REPORT, - ies->data, ies->len) { - pos = elem->data; - end = elem->data + elem->datalen; + pos = rnr->data; + end = rnr->data + rnr->datalen; /* RNR IE may contain more than one NEIGHBOR_AP_INFO */ - while (pos + sizeof(*ap_info) <= end) { - enum nl80211_band band; - int freq; + while (sizeof(*info) <= end - pos) { u8 length, i, count; + u8 type; - ap_info = (void *)pos; - count = u8_get_bits(ap_info->tbtt_info_hdr, - IEEE80211_AP_INFO_TBTT_HDR_COUNT) + 1; - length = ap_info->tbtt_info_len; + info = (void *)pos; + count = u8_get_bits(info->tbtt_info_hdr, + IEEE80211_AP_INFO_TBTT_HDR_COUNT) + + 1; + length = info->tbtt_info_len; - pos += sizeof(*ap_info); + pos += sizeof(*info); - if (!ieee80211_operating_class_to_band(ap_info->op_class, - &band)) - break; + if (count * length > end - pos) + return false; - freq = ieee80211_channel_to_frequency(ap_info->channel, - band); + type = u8_get_bits(info->tbtt_info_hdr, + IEEE80211_AP_INFO_TBTT_HDR_TYPE); - if (end - pos < count * length) - break; + for (i = 0; i < count; i++) { + switch (iter(iter_data, type, info, + pos, length)) { + case RNR_ITER_CONTINUE: + break; + case RNR_ITER_BREAK: + return true; + case RNR_ITER_ERROR: + return false; + } - if (u8_get_bits(ap_info->tbtt_info_hdr, - IEEE80211_AP_INFO_TBTT_HDR_TYPE) != - IEEE80211_TBTT_INFO_TYPE_TBTT) { - pos += count * length; - continue; + pos += length; } + } - /* TBTT info must include bss param + BSSID + - * (short SSID or same_ssid bit to be set). - * ignore other options, and move to the - * next AP info - */ - if (band != NL80211_BAND_6GHZ || - !(length == offsetofend(struct ieee80211_tbtt_info_7_8_9, - bss_params) || - length == sizeof(struct ieee80211_tbtt_info_7_8_9) || - length >= offsetofend(struct ieee80211_tbtt_info_ge_11, - bss_params))) { - pos += count * length; - continue; - } + if (pos != end) + return false; + } - for (i = 0; i < count; i++) { - struct cfg80211_colocated_ap *entry; + return true; +} + +struct colocated_ap_data { + const struct element *ssid_elem; + struct list_head ap_list; + u32 s_ssid_tmp; + int n_coloc; +}; - entry = kzalloc(sizeof(*entry) + IEEE80211_MAX_SSID_LEN, - GFP_ATOMIC); +static enum cfg80211_rnr_iter_ret +cfg80211_parse_colocated_ap_iter(void *_data, u8 type, + const struct ieee80211_neighbor_ap_info *info, + const u8 *tbtt_info, u8 tbtt_info_len) +{ + struct colocated_ap_data *data = _data; + struct cfg80211_colocated_ap *entry; + enum nl80211_band band; - if (!entry) - goto error; + if (type != IEEE80211_TBTT_INFO_TYPE_TBTT) + return RNR_ITER_CONTINUE; - entry->center_freq = freq; + if (!ieee80211_operating_class_to_band(info->op_class, &band)) + return RNR_ITER_CONTINUE; - if (!cfg80211_parse_ap_info(entry, pos, length, - ssid_elem, - s_ssid_tmp)) { - n_coloc++; - list_add_tail(&entry->list, &ap_list); - } else { - kfree(entry); - } + /* TBTT info must include bss param + BSSID + (short SSID or + * same_ssid bit to be set). Ignore other options, and move to + * the next AP info + */ + if (band != NL80211_BAND_6GHZ || + !(tbtt_info_len == offsetofend(struct ieee80211_tbtt_info_7_8_9, + bss_params) || + tbtt_info_len == sizeof(struct ieee80211_tbtt_info_7_8_9) || + tbtt_info_len >= offsetofend(struct ieee80211_tbtt_info_ge_11, + bss_params))) + return RNR_ITER_CONTINUE; + + entry = kzalloc(sizeof(*entry) + IEEE80211_MAX_SSID_LEN, GFP_ATOMIC); + if (!entry) + return RNR_ITER_ERROR; + + entry->center_freq = + ieee80211_channel_to_frequency(info->channel, band); + + if (!cfg80211_parse_ap_info(entry, tbtt_info, tbtt_info_len, + data->ssid_elem, data->s_ssid_tmp)) { + data->n_coloc++; + list_add_tail(&entry->list, &data->ap_list); + } else { + kfree(entry); + } - pos += length; - } - } + return RNR_ITER_CONTINUE; +} -error: - if (pos != end) { - cfg80211_free_coloc_ap_list(&ap_list); - return 0; - } +VISIBLE_IF_CFG80211_KUNIT int +cfg80211_parse_colocated_ap(const struct cfg80211_bss_ies *ies, + struct list_head *list) +{ + struct colocated_ap_data data = {}; + int ret; + + INIT_LIST_HEAD(&data.ap_list); + + ret = cfg80211_calc_short_ssid(ies, &data.ssid_elem, &data.s_ssid_tmp); + if (ret) + return 0; + + if (!cfg80211_iter_rnr(ies->data, ies->len, + cfg80211_parse_colocated_ap_iter, &data)) { + cfg80211_free_coloc_ap_list(&data.ap_list); + return 0; } - list_splice_tail(&ap_list, list); - return n_coloc; + list_splice_tail(&data.ap_list, list); + return data.n_coloc; } EXPORT_SYMBOL_IF_CFG80211_KUNIT(cfg80211_parse_colocated_ap); @@ -2607,79 +2647,71 @@ error: return NULL; } -static u8 -cfg80211_rnr_info_for_mld_ap(const u8 *ie, size_t ielen, u8 mld_id, u8 link_id, - const struct ieee80211_neighbor_ap_info **ap_info, - u8 *param_ch_count) -{ - const struct ieee80211_neighbor_ap_info *info; - const struct element *rnr; - const u8 *pos, *end; - - for_each_element_id(rnr, WLAN_EID_REDUCED_NEIGHBOR_REPORT, ie, ielen) { - pos = rnr->data; - end = rnr->data + rnr->datalen; - - /* RNR IE may contain more than one NEIGHBOR_AP_INFO */ - while (sizeof(*info) <= end - pos) { - const struct ieee80211_rnr_mld_params *mld_params; - u16 params; - u8 length, i, count, mld_params_offset; - u8 type, lid; - u32 use_for; - - info = (void *)pos; - count = u8_get_bits(info->tbtt_info_hdr, - IEEE80211_AP_INFO_TBTT_HDR_COUNT) + 1; - length = info->tbtt_info_len; +struct tbtt_info_iter_data { + const struct ieee80211_neighbor_ap_info *ap_info; + u8 param_ch_count; + u32 use_for; + u8 mld_id, link_id; +}; - pos += sizeof(*info); +static enum cfg80211_rnr_iter_ret +cfg802121_mld_ap_rnr_iter(void *_data, u8 type, + const struct ieee80211_neighbor_ap_info *info, + const u8 *tbtt_info, u8 tbtt_info_len) +{ + const struct ieee80211_rnr_mld_params *mld_params; + struct tbtt_info_iter_data *data = _data; + u8 link_id; + + if (type == IEEE80211_TBTT_INFO_TYPE_TBTT && + tbtt_info_len >= offsetofend(struct ieee80211_tbtt_info_ge_11, + mld_params)) + mld_params = (void *)(tbtt_info + + offsetof(struct ieee80211_tbtt_info_ge_11, + mld_params)); + else if (type == IEEE80211_TBTT_INFO_TYPE_MLD && + tbtt_info_len >= sizeof(struct ieee80211_rnr_mld_params)) + mld_params = (void *)tbtt_info; + else + return RNR_ITER_CONTINUE; - if (count * length > end - pos) - return 0; + link_id = le16_get_bits(mld_params->params, + IEEE80211_RNR_MLD_PARAMS_LINK_ID); - type = u8_get_bits(info->tbtt_info_hdr, - IEEE80211_AP_INFO_TBTT_HDR_TYPE); + if (data->mld_id != mld_params->mld_id) + return RNR_ITER_CONTINUE; - if (type == IEEE80211_TBTT_INFO_TYPE_TBTT && - length >= - offsetofend(struct ieee80211_tbtt_info_ge_11, - mld_params)) { - mld_params_offset = - offsetof(struct ieee80211_tbtt_info_ge_11, mld_params); - use_for = NL80211_BSS_USE_FOR_ALL; - } else if (type == IEEE80211_TBTT_INFO_TYPE_MLD && - length >= sizeof(struct ieee80211_rnr_mld_params)) { - mld_params_offset = 0; - use_for = NL80211_BSS_USE_FOR_MLD_LINK; - } else { - pos += count * length; - continue; - } + if (data->link_id != link_id) + return RNR_ITER_CONTINUE; - for (i = 0; i < count; i++) { - mld_params = (void *)pos + mld_params_offset; - params = le16_to_cpu(mld_params->params); + data->ap_info = info; + data->param_ch_count = + le16_get_bits(mld_params->params, + IEEE80211_RNR_MLD_PARAMS_BSS_CHANGE_COUNT); - lid = u16_get_bits(params, - IEEE80211_RNR_MLD_PARAMS_LINK_ID); + if (type == IEEE80211_TBTT_INFO_TYPE_TBTT) + data->use_for = NL80211_BSS_USE_FOR_ALL; + else + data->use_for = NL80211_BSS_USE_FOR_MLD_LINK; + return RNR_ITER_BREAK; +} - if (mld_id == mld_params->mld_id && - link_id == lid) { - *ap_info = info; - *param_ch_count = - le16_get_bits(mld_params->params, - IEEE80211_RNR_MLD_PARAMS_BSS_CHANGE_COUNT); +static u8 +cfg80211_rnr_info_for_mld_ap(const u8 *ie, size_t ielen, u8 mld_id, u8 link_id, + const struct ieee80211_neighbor_ap_info **ap_info, + u8 *param_ch_count) +{ + struct tbtt_info_iter_data data = { + .mld_id = mld_id, + .link_id = link_id, + }; - return use_for; - } + cfg80211_iter_rnr(ie, ielen, cfg802121_mld_ap_rnr_iter, &data); - pos += length; - } - } - } + *ap_info = data.ap_info; + *param_ch_count = data.param_ch_count; - return 0; + return data.use_for; } static struct element * -- cgit From 6bd14aee0bd25525ab229acd9bfe536dd8642364 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Feb 2024 13:54:31 +0200 Subject: wifi: mac80211: align ieee80211_mle_get_bss_param_ch_cnt() Align the prototype of ieee80211_mle_get_bss_param_ch_cnt() to also take a u8 * like the other functions, and make it return -1 when the field isn't found, so that mac80211 can check that instead of explicitly open-coding the check. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240216135047.583309181bc3.Ia61cb0b4fc034d5ac8fcfaf6f6fb2e115fadafe7@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 11 ++++++----- net/mac80211/mlme.c | 9 +++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index e4322238f273..303c75459897 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4990,17 +4990,18 @@ static inline int ieee80211_mle_get_link_id(const u8 *data) /** * ieee80211_mle_get_bss_param_ch_cnt - returns the BSS parameter change count - * @mle: the basic multi link element + * @data: pointer to the basic multi link element * * The element is assumed to be of the correct type (BASIC) and big enough, * this must be checked using ieee80211_mle_type_ok(). * * If the BSS parameter change count value can't be found (the presence bit - * for it is clear), 0 will be returned. + * for it is clear), -1 will be returned. */ -static inline u8 -ieee80211_mle_get_bss_param_ch_cnt(const struct ieee80211_multi_link_elem *mle) +static inline int +ieee80211_mle_get_bss_param_ch_cnt(const u8 *data) { + const struct ieee80211_multi_link_elem *mle = (const void *)data; u16 control = le16_to_cpu(mle->control); const u8 *common = mle->variable; @@ -5008,7 +5009,7 @@ ieee80211_mle_get_bss_param_ch_cnt(const struct ieee80211_multi_link_elem *mle) common += sizeof(struct ieee80211_mle_basic_common_info); if (!(control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT)) - return 0; + return -1; if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) common += 1; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 87ffc19770b8..5f2e9f5e1779 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4202,13 +4202,14 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, */ assoc_data->link[link_id].status = WLAN_STATUS_SUCCESS; if (elems->ml_basic) { - if (!(elems->ml_basic->control & - cpu_to_le16(IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT))) { + int bss_param_ch_cnt = + ieee80211_mle_get_bss_param_ch_cnt((const void *)elems->ml_basic); + + if (bss_param_ch_cnt < 0) { ret = false; goto out; } - link->u.mgd.bss_param_ch_cnt = - ieee80211_mle_get_bss_param_ch_cnt(elems->ml_basic); + link->u.mgd.bss_param_ch_cnt = bss_param_ch_cnt; } } else if (elems->parse_error & IEEE80211_PARSE_ERR_DUP_NEST_ML_BASIC || !elems->prof || -- cgit From 894dd84e49ec114a2dde7b312ae4cada40d15bdb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Feb 2024 13:54:32 +0200 Subject: wifi: cfg80211: use ML element parsing helpers Use the existing ML element parsing helpers and add a new one for this (ieee80211_mle_get_mld_id). Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240216135047.4da47b1f035b.I437a5570ac456449facb0b147851ef24a1e473c2@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 38 ++++++++++++++++++++++++++++++++++++++ net/wireless/scan.c | 41 ++++++++--------------------------------- 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 303c75459897..3385a2cc5b09 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -5115,6 +5115,44 @@ static inline u16 ieee80211_mle_get_mld_capa_op(const u8 *data) return get_unaligned_le16(common); } +/** + * ieee80211_mle_get_mld_id - returns the MLD ID + * @data: pointer to the multi link element + * + * The element is assumed to be of the correct type (BASIC) and big enough, + * this must be checked using ieee80211_mle_type_ok(). + * + * If the MLD ID is not present, 0 will be returned. + */ +static inline u8 ieee80211_mle_get_mld_id(const u8 *data) +{ + const struct ieee80211_multi_link_elem *mle = (const void *)data; + u16 control = le16_to_cpu(mle->control); + const u8 *common = mle->variable; + + /* + * common points now at the beginning of + * ieee80211_mle_basic_common_info + */ + common += sizeof(struct ieee80211_mle_basic_common_info); + + if (!(control & IEEE80211_MLC_BASIC_PRES_MLD_ID)) + return 0; + + if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) + common += 1; + if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT) + common += 1; + if (control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY) + common += 2; + if (control & IEEE80211_MLC_BASIC_PRES_EML_CAPA) + common += 2; + if (control & IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP) + common += 2; + + return *common; +} + /** * ieee80211_mle_size_ok - validate multi-link element size * @data: pointer to the element data diff --git a/net/wireless/scan.c b/net/wireless/scan.c index e46dfc71c497..7cf36b8d3ae7 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -2833,17 +2833,16 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, struct cfg80211_bss *bss; u8 mld_id, reporter_link_id, bss_change_count; u16 seen_links = 0; - const u8 *pos; u8 i; - if (!ieee80211_mle_size_ok(elem->data + 1, elem->datalen - 1)) + if (!ieee80211_mle_type_ok(elem->data + 1, + IEEE80211_ML_CONTROL_TYPE_BASIC, + elem->datalen - 1)) return; - ml_elem = (void *)elem->data + 1; + ml_elem = (void *)(elem->data + 1); control = le16_to_cpu(ml_elem->control); - if (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE) != - IEEE80211_ML_CONTROL_TYPE_BASIC) - return; + ml_common_len = ml_elem->variable[0]; /* Must be present when transmitted by an AP (in a probe response) */ if (!(control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT) || @@ -2851,24 +2850,8 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, !(control & IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP)) return; - ml_common_len = ml_elem->variable[0]; - - /* length + MLD MAC address */ - pos = ml_elem->variable + 1 + 6; - - reporter_link_id = pos[0]; - pos += 1; - - bss_change_count = pos[0]; - pos += 1; - - if (u16_get_bits(control, IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY)) - pos += 2; - if (u16_get_bits(control, IEEE80211_MLC_BASIC_PRES_EML_CAPA)) - pos += 2; - - /* MLD capabilities and operations */ - pos += 2; + reporter_link_id = ieee80211_mle_get_link_id(elem->data + 1); + bss_change_count = ieee80211_mle_get_bss_param_ch_cnt(elem->data + 1); /* * The MLD ID of the reporting AP is always zero. It is set if the AP @@ -2876,15 +2859,7 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, * relating to a nontransmitted BSS (matching the Multi-BSSID Index, * Draft P802.11be_D3.2, 35.3.4.2) */ - if (u16_get_bits(control, IEEE80211_MLC_BASIC_PRES_MLD_ID)) { - mld_id = *pos; - pos += 1; - } else { - mld_id = 0; - } - - /* Extended MLD capabilities and operations */ - pos += 2; + mld_id = ieee80211_mle_get_mld_id(elem->data + 1); /* Fully defrag the ML element for sta information/profile iteration */ mle = cfg80211_defrag_mle(elem, tx_data->ie, tx_data->ielen, gfp); -- cgit From 32a5690e9acb461c7c6a4595f9e77a6fb5c4094f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 18 Feb 2024 19:51:42 +0200 Subject: wifi: iwlwifi: mvm: support wider-bandwidth OFDMA To support wider-bandwidth OFDMA we need to configure the PHY context in the firmware, which will in turn configure the DSP accordingly. Pass the relevant information down. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240218194912.ca666ede5dd6.I357972823d20e9045e2c97dbb7ac24fe9f5a6e41@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 5 +++-- drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c | 5 +++-- .../net/wireless/intel/iwlwifi/mvm/ftm-responder.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 9 ++++++--- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c | 19 +++++++++++++++---- 6 files changed, 30 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index b6a9896bce25..9830a3c3600b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -720,7 +720,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_chanctx_conf *ctx; u8 chains_static, chains_dynamic; - struct cfg80211_chan_def chandef; + struct cfg80211_chan_def chandef, ap_def; int ret, i; struct iwl_binding_cmd_v1 binding_cmd = {}; struct iwl_time_quota_cmd quota_cmd = {}; @@ -742,12 +742,13 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return -EINVAL; } chandef = ctx->def; + ap_def = ctx->ap; chains_static = ctx->rx_chains_static; chains_dynamic = ctx->rx_chains_dynamic; rcu_read_unlock(); ret = iwl_mvm_phy_ctxt_add(mvm, mvmvif->deflink.phy_ctxt, &chandef, - chains_static, chains_dynamic); + &ap_def, chains_static, chains_dynamic); if (ret) return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index aa3c9c2cbd7f..51b01f7528be 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -592,7 +592,7 @@ static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf, for_each_vif_active_link(vif, link_conf, link_id) { struct ieee80211_chanctx_conf *chanctx_conf; - struct cfg80211_chan_def min_def; + struct cfg80211_chan_def min_def, ap_def; struct iwl_mvm_phy_ctxt *phy_ctxt; u8 chains_static, chains_dynamic; @@ -606,6 +606,7 @@ static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf, * everything here and use it after unlocking */ min_def = chanctx_conf->min_def; + ap_def = chanctx_conf->ap; chains_static = chanctx_conf->rx_chains_static; chains_dynamic = chanctx_conf->rx_chains_dynamic; rcu_read_unlock(); @@ -614,7 +615,7 @@ static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf, if (!phy_ctxt) continue; - ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &min_def, + ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &min_def, &ap_def, chains_static, chains_dynamic); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c index dca36b0662c7..8e760300a1ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c @@ -438,7 +438,7 @@ int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif, rcu_read_unlock(); phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; - ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx.def, + ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx.def, &ctx.ap, ctx.rx_chains_static, ctx.rx_chains_dynamic); if (ret) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 229d87a786df..69f6a96b0cfb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1644,6 +1644,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, IEEE80211_VIF_SUPPORTS_CQM_RSSI; } + if (vif->p2p || iwl_fw_lookup_cmd_ver(mvm->fw, PHY_CONTEXT_CMD, 1) < 5) + vif->driver_flags |= IEEE80211_VIF_IGNORE_OFDMA_WIDER_BW; + if (vif->type == NL80211_IFTYPE_P2P_DEVICE) mvm->p2p_device_vif = vif; @@ -4651,7 +4654,7 @@ static int iwl_mvm_p2p_find_phy_ctxt(struct iwl_mvm *mvm, cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT); return iwl_mvm_phy_ctxt_add(mvm, mvmvif->deflink.phy_ctxt, - &chandef, 1, 1); + &chandef, NULL, 1, 1); } /* Execute the common part for MLD and non-MLD modes */ @@ -4772,7 +4775,7 @@ static int __iwl_mvm_add_chanctx(struct iwl_mvm *mvm, goto out; } - ret = iwl_mvm_phy_ctxt_add(mvm, phy_ctxt, def, + ret = iwl_mvm_phy_ctxt_add(mvm, phy_ctxt, def, &ctx->ap, ctx->rx_chains_static, ctx->rx_chains_dynamic); if (ret) { @@ -4850,7 +4853,7 @@ void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, } iwl_mvm_bt_coex_vif_change(mvm); - iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, def, + iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, def, &ctx->ap, ctx->rx_chains_static, ctx->rx_chains_dynamic); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index ce78c21883e9..fcae5199ac90 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1810,9 +1810,11 @@ void iwl_mvm_rx_shared_mem_cfg_notif(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm); int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, const struct cfg80211_chan_def *chandef, + const struct cfg80211_chan_def *ap, u8 chains_static, u8 chains_dynamic); int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, const struct cfg80211_chan_def *chandef, + const struct cfg80211_chan_def *ap, u8 chains_static, u8 chains_dynamic); void iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index bac655834f32..e208e3c34c25 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -198,12 +198,16 @@ int iwl_mvm_phy_send_rlc(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, const struct cfg80211_chan_def *chandef, + const struct cfg80211_chan_def *ap, u8 chains_static, u8 chains_dynamic, u32 action) { int ret; int ver = iwl_fw_lookup_cmd_ver(mvm->fw, PHY_CONTEXT_CMD, 1); + if (ver < 5 || !ap || !ap->chan) + ap = NULL; + if (ver >= 3 && ver <= 5) { struct iwl_phy_context_cmd cmd = {}; @@ -215,6 +219,11 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, chains_static, chains_dynamic); + if (ap) { + cmd.v5.sbb_bandwidth = iwl_mvm_get_channel_width(ap); + cmd.v5.sbb_ctrl_channel_loc = iwl_mvm_get_ctrl_pos(ap); + } + ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, 0, sizeof(cmd), &cmd); } else if (ver < 3) { @@ -255,6 +264,7 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, */ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, const struct cfg80211_chan_def *chandef, + const struct cfg80211_chan_def *ap, u8 chains_static, u8 chains_dynamic) { int ret; @@ -267,7 +277,7 @@ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, ctxt->width = chandef->width; ctxt->center_freq1 = chandef->center_freq1; - ret = iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, + ret = iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, ap, chains_static, chains_dynamic, FW_CTXT_ACTION_ADD); @@ -301,6 +311,7 @@ void iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) */ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, const struct cfg80211_chan_def *chandef, + const struct cfg80211_chan_def *ap, u8 chains_static, u8 chains_dynamic) { enum iwl_ctxt_action action = FW_CTXT_ACTION_MODIFY; @@ -324,7 +335,7 @@ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, int ret; /* ... remove it here ...*/ - ret = iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, + ret = iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, NULL, chains_static, chains_dynamic, FW_CTXT_ACTION_REMOVE); if (ret) @@ -338,7 +349,7 @@ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, ctxt->width = chandef->width; ctxt->center_freq1 = chandef->center_freq1; - return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, + return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, ap, chains_static, chains_dynamic, action); } @@ -358,7 +369,7 @@ void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) cfg80211_chandef_create(&chandef, ctxt->channel, NL80211_CHAN_NO_HT); - iwl_mvm_phy_ctxt_apply(mvm, ctxt, &chandef, 1, 1, + iwl_mvm_phy_ctxt_apply(mvm, ctxt, &chandef, NULL, 1, 1, FW_CTXT_ACTION_REMOVE); } -- cgit From 3eab2034364dc446d3ccd0bee15af681638fcb9d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 18 Feb 2024 19:51:43 +0200 Subject: wifi: iwlwifi: mvm: partially support PHY context version 6 The version 6 command adds the puncture mask to the PHY context and is otherwise the same. Support that in the API definitions, but don't fill it yet. While at it, also mark the field as removed from the link context command since it moved from there to PHY context. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240218194912.2156fca5b1a5.I57f47f26ec0d96ecfb1192039f72b1c6d4e8a357@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h | 10 ++++------ drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h | 9 +++++---- drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c | 6 +++--- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h index 200362e5ceca..c6d1f5644638 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -373,7 +373,7 @@ struct iwl_mac_config_cmd { * iwl_link_ctx_cfg_cmd::bss_color_disable * @LINK_CONTEXT_MODIFY_EHT_PARAMS: covers iwl_link_ctx_cfg_cmd::puncture_mask. * This flag can be set only if the MAC that this link relates to has - * eht_support set to true. + * eht_support set to true. No longer used since _VER_3 of this command. * @LINK_CONTEXT_MODIFY_ALL: set all above flags */ enum iwl_link_ctx_modify_flags { @@ -462,7 +462,7 @@ enum iwl_link_ctx_flags { * @bi: beacon interval in TU, applicable only when associated * @dtim_interval: DTIM interval in TU. * Relevant only for GO, otherwise this is offloaded. - * @puncture_mask: puncture mask for EHT + * @puncture_mask: puncture mask for EHT (removed in VER_3) * @frame_time_rts_th: HE duration RTS threshold, in units of 32us * @flags: a combination from &enum iwl_link_ctx_flags * @flags_mask: what of %flags have changed. Also &enum iwl_link_ctx_flags @@ -505,7 +505,7 @@ struct iwl_link_config_cmd { struct iwl_he_backoff_conf trig_based_txf[AC_NUM]; __le32 bi; __le32 dtim_interval; - __le16 puncture_mask; + __le16 puncture_mask; /* removed in _VER_3 */ __le16 frame_time_rts_th; __le32 flags; __le32 flags_mask; @@ -519,9 +519,7 @@ struct iwl_link_config_cmd { u8 ibss_bssid_addr[6]; __le16 reserved_for_ibss_bssid_addr; __le32 reserved3[8]; -} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1 and - * LINK_CONTEXT_CONFIG_CMD_API_S_VER_2 - */ +} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1, _VER_2, _VER_3 */ /* Currently FW supports link ids in the range 0-3 and can have * at most two active links for each vif. diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h index 205d0413e626..08a2c416ce60 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h @@ -156,17 +156,18 @@ struct iwl_phy_context_cmd { __le32 lmac_id; union { __le32 rxchain_info; /* reserved in _VER_4 */ - struct { /* used for _VER_5 */ + struct { /* used for _VER_5/_VER_6 */ u8 sbb_bandwidth; u8 sbb_ctrl_channel_loc; - __le16 reserved; - } v5; + __le16 puncture_mask; /* added in VER_6 */ + }; }; __le32 dsp_cfg_flags; __le32 reserved; } __packed; /* PHY_CONTEXT_CMD_API_VER_3, * PHY_CONTEXT_CMD_API_VER_4, - * PHY_CONTEXT_CMD_API_VER_5 + * PHY_CONTEXT_CMD_API_VER_5, + * PHY_CONTEXT_CMD_API_VER_6 */ #endif /* __iwl_fw_api_phy_ctxt_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index e208e3c34c25..5db44514d025 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -208,7 +208,7 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, if (ver < 5 || !ap || !ap->chan) ap = NULL; - if (ver >= 3 && ver <= 5) { + if (ver >= 3 && ver <= 6) { struct iwl_phy_context_cmd cmd = {}; /* Set the command header fields */ @@ -220,8 +220,8 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, chains_dynamic); if (ap) { - cmd.v5.sbb_bandwidth = iwl_mvm_get_channel_width(ap); - cmd.v5.sbb_ctrl_channel_loc = iwl_mvm_get_ctrl_pos(ap); + cmd.sbb_bandwidth = iwl_mvm_get_channel_width(ap); + cmd.sbb_ctrl_channel_loc = iwl_mvm_get_ctrl_pos(ap); } ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, -- cgit From 9a43c1902e56231fcf11780d7e2015638ff43cca Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 18 Feb 2024 19:51:44 +0200 Subject: wifi: iwlwifi: mvm: support PHY context version 6 Fill the new puncture mask in the PHY context command if supported. In this case, also don't send it in the link context command. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240218194912.16d9f5fc41df.I9eeb55787d8483f820f5790e8874761f598da314@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/link.c | 3 ++- drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index 129eefcc45d6..f13f13e6b71a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -204,7 +204,8 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, def = iwl_mvm_chanctx_def(mvm, ctx); if (iwlwifi_mod_params.disable_11be || - !link_conf->eht_support || !def) + !link_conf->eht_support || !def || + iwl_fw_lookup_cmd_ver(mvm->fw, PHY_CONTEXT_CMD, 1) >= 6) changes &= ~LINK_CONTEXT_MODIFY_EHT_PARAMS; else cmd.puncture_mask = cpu_to_le16(def->punctured); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index 5db44514d025..ce264b386029 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH */ @@ -224,6 +224,9 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, cmd.sbb_ctrl_channel_loc = iwl_mvm_get_ctrl_pos(ap); } + if (ver == 6) + cmd.puncture_mask = cpu_to_le16(chandef->punctured); + ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, 0, sizeof(cmd), &cmd); } else if (ver < 3) { -- cgit From 653a90f6b226d8f95d06cb6c0bf5473f99582cc9 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Sun, 18 Feb 2024 19:51:45 +0200 Subject: wifi: iwlwifi: bump FW API to 90 for BZ/SC devices Start supporting API version 90 for new devices. Signed-off-by: Miri Korenblit Link: https://msgid.link/20240218194912.21cf0b641f12.I2f9196191f1ea78e96e92f9db8ecb3cc9bbfd9b3@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 2 +- drivers/net/wireless/intel/iwlwifi/cfg/sc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index 14c5cc265fe3..18b1f2cf08cc 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_BZ_UCODE_API_MAX 89 +#define IWL_BZ_UCODE_API_MAX 90 /* Lowest firmware API version supported */ #define IWL_BZ_UCODE_API_MIN 80 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index dbbcb2d0968c..9b79279fd76c 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_SC_UCODE_API_MAX 89 +#define IWL_SC_UCODE_API_MAX 90 /* Lowest firmware API version supported */ #define IWL_SC_UCODE_API_MIN 82 -- cgit From e2967e83921a3748116b8e330cbbb794817ceee8 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Sun, 18 Feb 2024 19:51:46 +0200 Subject: wifi: iwlwifi: mvm: unlock mvm if there is no primary link At that point in the code mvm->mutex has already been taken, so jump to out_noreset in order to unlock before returning the error. Fixes: 8c9bef26e98b ("wifi: iwlwifi: mvm: d3: implement suspend with MLO") Signed-off-by: Benjamin Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240218194912.21de6e68d9e5.I3c0ebe577dec6b26ab6b4eac48035d6f35a8b0f8@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 9830a3c3600b..6d5ed79b9fff 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1290,8 +1290,10 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, mvmvif = iwl_mvm_vif_from_mac80211(vif); mvm_link = mvmvif->link[primary_link]; - if (WARN_ON_ONCE(!mvm_link)) - return -EINVAL; + if (WARN_ON_ONCE(!mvm_link)) { + ret = -EINVAL; + goto out_noreset; + } if (mvm_link->ap_sta_id == IWL_MVM_INVALID_STA) { /* if we're not associated, this must be netdetect */ -- cgit From f63280ab7aa2a5ccd39a9e931ad2dc311ddc7e8d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 18 Feb 2024 19:51:48 +0200 Subject: wifi: iwlwifi: api: fix kernel-doc reference This is for iwl_tas_config_cmd_v4, not iwl_tas_config_cmd_v3. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240218194912.5475d49bce86.I640a12bc799612e82c3e7a4d628bbb7760511297@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index 8c886569f01e..58034dfa7e70 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -462,7 +462,7 @@ struct iwl_tas_config_cmd_v3 { } __packed; /* TAS_CONFIG_CMD_API_S_VER_3 */ /** - * struct iwl_tas_config_cmd_v3 - configures the TAS + * struct iwl_tas_config_cmd_v4 - configures the TAS * @override_tas_iec: indicates whether to override default value of IEC regulatory * @enable_tas_iec: in case override_tas_iec is set - * indicates whether IEC regulatory is enabled or disabled -- cgit From ccb2f72cee5fb3421cc71e5d07bc46a57accd7ba Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 18 Feb 2024 19:51:49 +0200 Subject: wifi: iwlwifi: iwl-fh.h: fix kernel-doc issues Clean up kernel-doc in iwl-fh.h. In one case, rename the (otherwise unused) struct member to have the correct name. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240218194912.4a342ac06f0b.I604ea964a094b43df0ab29b06231c2f42d6bd79b@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-fh.h | 36 ++++++++++++++++------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h index e0400ba2ab74..6ba374efaacb 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2021, 2023 Intel Corporation + * Copyright (C) 2005-2014, 2018-2021, 2023-2024 Intel Corporation * Copyright (C) 2015-2017 Intel Deutschland GmbH */ #ifndef __iwl_fh_h__ @@ -570,18 +570,19 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans, /** * struct iwl_rb_status - reserve buffer status * host memory mapped FH registers - * @closed_rb_num [0:11] - Indicates the index of the RB which was closed - * @closed_fr_num [0:11] - Indicates the index of the RX Frame which was closed - * @finished_rb_num [0:11] - Indicates the index of the current RB + * @closed_rb_num: [0:11] Indicates the index of the RB which was closed + * @closed_fr_num: [0:11] Indicates the index of the RX Frame which was closed + * @finished_rb_num: [0:11] Indicates the index of the current RB * in which the last frame was written to - * @finished_fr_num [0:11] - Indicates the index of the RX Frame + * @finished_fr_num: [0:11] Indicates the index of the RX Frame * which was transferred + * @__spare: reserved */ struct iwl_rb_status { __le16 closed_rb_num; __le16 closed_fr_num; __le16 finished_rb_num; - __le16 finished_fr_nam; + __le16 finished_fr_num; __le32 __spare; } __packed; @@ -651,15 +652,15 @@ struct iwl_tfd_tb { * * This structure contains dma address and length of transmission address * - * @tb_len length of the tx buffer - * @addr 64 bits dma address + * @tb_len: length of the tx buffer + * @addr: 64 bits dma address */ struct iwl_tfh_tb { __le16 tb_len; __le64 addr; } __packed; -/** +/* * Each Tx queue uses a circular buffer of 256 TFDs stored in host DRAM. * Both driver and device share these circular buffers, each of which must be * contiguous 256 TFDs. @@ -698,10 +699,11 @@ struct iwl_tfd { /** * struct iwl_tfh_tfd - Transmit Frame Descriptor (TFD) - * @ num_tbs 0-4 number of active tbs - * 5 -15 reserved - * @ tbs[25] transmit frame buffer descriptors - * @ __pad padding + * @num_tbs: + * 0-4 number of active tbs + * 5-15 reserved + * @tbs: transmit frame buffer descriptors + * @__pad: padding */ struct iwl_tfh_tfd { __le16 num_tbs; @@ -718,10 +720,12 @@ struct iwl_tfh_tfd { * struct iwlagn_schedq_bc_tbl scheduler byte count table * base physical address provided by SCD_DRAM_BASE_ADDR * For devices up to 22000: - * @tfd_offset 0-12 - tx command byte count + * @tfd_offset: + * For devices up to 22000: + * 0-12 - tx command byte count * 12-16 - station index - * For 22000: - * @tfd_offset 0-12 - tx command byte count + * For 22000: + * 0-12 - tx command byte count * 12-13 - number of 64 byte chunks * 14-16 - reserved */ -- cgit From 740dfecc336bc79789b992f260e1a5bdfbdf2bfa Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Sun, 18 Feb 2024 19:51:51 +0200 Subject: wifi: iwlwifi: handle per-phy statistics from fw In the operational statistics notifications (both old and new API) the driver receives the statistics per phy. currently this statistics wasn't handled because they wasn't needed. Now the channel_load_by_us parameter in these statistics will be used for the link grading calculation (implemented in another patch), so store its value in phy_ctxt. Signed-off-by: Miri Korenblit Reviewed-by: Johannes Berg Link: https://msgid.link/20240218194912.e84f975b69ee.Ibbc7817135827e45adaaa47b796be165f9f1ca48@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index fcae5199ac90..c85d9e460ad2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -106,6 +106,7 @@ struct iwl_mvm_phy_ctxt { /* track for RLC config command */ u32 center_freq1; bool rlc_disabled; + u32 channel_load_by_us; }; struct iwl_mvm_time_event_data { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 72df41996464..b1add7942c5b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -752,6 +752,19 @@ iwl_mvm_update_tcm_from_stats(struct iwl_mvm *mvm, __le32 *air_time_le, spin_unlock(&mvm->tcm.lock); } +static void iwl_mvm_handle_per_phy_stats(struct iwl_mvm *mvm, + struct iwl_stats_ntfy_per_phy *per_phy) +{ + int i; + + for (i = 0; i < NUM_PHY_CTX; i++) { + if (!mvm->phy_ctxts[i].ref) + continue; + mvm->phy_ctxts[i].channel_load_by_us = + le32_to_cpu(per_phy[i].channel_load_by_us); + } +} + static void iwl_mvm_stats_ver_15(struct iwl_mvm *mvm, struct iwl_statistics_operational_ntfy *stats) @@ -766,6 +779,7 @@ iwl_mvm_stats_ver_15(struct iwl_mvm *mvm, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_stat_iterator_all_macs, &data); + iwl_mvm_handle_per_phy_stats(mvm, stats->per_phy); } static void @@ -942,6 +956,7 @@ void iwl_mvm_handle_rx_system_oper_stats(struct iwl_mvm *mvm, ieee80211_iterate_stations_atomic(mvm->hw, iwl_mvm_stats_energy_iter, average_energy); + iwl_mvm_handle_per_phy_stats(mvm, stats->per_phy); } void iwl_mvm_handle_rx_system_oper_part1_stats(struct iwl_mvm *mvm, -- cgit From 32a1bbd3fe3ff21deca67e3508ab3cc05931ccd2 Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Sun, 18 Feb 2024 19:51:52 +0200 Subject: wifi: iwlwifi: load b0 version of ucode for HR1/HR2 load b0 version of ucode for both a0 and b0 step of HR RF. Signed-off-by: Mukesh Sisodiya Signed-off-by: Miri Korenblit Link: https://msgid.link/20240218194912.0166f5d2d5d2.I34c1d46aefd70b34c1c75cea67792bc5ec8bc285@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 91e974de0ade..4696d73c8971 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2005-2014, 2018-2023 Intel Corporation + * Copyright (C) 2005-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -187,6 +187,7 @@ const char *iwl_drv_get_fwname_pre(struct iwl_trans *trans, char *buf) case IWL_CFG_RF_TYPE_HR1: case IWL_CFG_RF_TYPE_HR2: rf = "hr"; + rf_step = 'b'; break; case IWL_CFG_RF_TYPE_GF: rf = "gf"; -- cgit From 4f4d8be6dc37a28b8655d03918680d8ea8c82f75 Mon Sep 17 00:00:00 2001 From: Alexis Lothoré Date: Thu, 15 Feb 2024 15:13:52 +0100 Subject: wifi: nl80211: force WLAN_AKM_SUITE_SAE in big endian in NL80211_CMD_EXTERNAL_AUTH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User-space supplicant (observed at least on wpa_supplicant) historically parses the NL80211_ATTR_AKM_SUITES from the NL80211_CMD_EXTERNAL_AUTH message as big endian _only_ when its value is WLAN_AKM_SUITE_SAE, while processing anything else in host endian. This behavior makes any driver relying on SAE external auth to switch AKM suite to big endian if it is WLAN_AKM_SUITE_SAE. A fix bringing compatibility with both endianness has been brought into wpa_supplicant, however we must keep compatibility with older versions, while trying to reduce the occurences of this manual conversion in wireless drivers. Add the be32 conversion specifically on WLAN_AKM_SUITE_SAE in nl80211 layer to keep compatibility with older wpa_supplicant versions. Suggested-by: Johannes Berg Signed-off-by: Alexis Lothoré Link: https://msgid.link/20240215-nl80211_fix_akm_suites_endianness-v1-1-57e902632f9d@bootlin.com Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index dd9a092b6bab..ab6d98cdac13 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -20132,9 +20132,26 @@ int cfg80211_external_auth_request(struct net_device *dev, if (!hdr) goto nla_put_failure; + /* Some historical mistakes in drivers <-> userspace interface (notably + * between drivers and wpa_supplicant) led to a big-endian conversion + * being needed on NL80211_ATTR_AKM_SUITES _only_ when its value is + * WLAN_AKM_SUITE_SAE. This is now fixed on userspace side, but for the + * benefit of older wpa_supplicant versions, send this particular value + * in big-endian. Note that newer wpa_supplicant will also detect this + * particular value in big endian still, so it all continues to work. + */ + if (params->key_mgmt_suite == WLAN_AKM_SUITE_SAE) { + if (nla_put_be32(msg, NL80211_ATTR_AKM_SUITES, + cpu_to_be32(WLAN_AKM_SUITE_SAE))) + goto nla_put_failure; + } else { + if (nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, + params->key_mgmt_suite)) + goto nla_put_failure; + } + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || - nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, params->key_mgmt_suite) || nla_put_u32(msg, NL80211_ATTR_EXTERNAL_AUTH_ACTION, params->action) || nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid) || -- cgit From 81830c8f809c01f3780dc33f7d951be8e146ced1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 21 Feb 2024 12:48:18 +0100 Subject: wifi: nl80211: refactor parsing CSA offsets The CSA offset parsing happens the same way for all of beacon template offsets, probe response template offsets and TX offsets (for using during probe response TX from userspace directly). Refactor the parsing here. There's an additional check this introduces, which is that the number of counters in TX offsets doesn't exceed the driver capability, but as only two counters are used at most for anything, this is hopefully OK. Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 137 ++++++++++++++++++++----------------------------- 1 file changed, 56 insertions(+), 81 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ab6d98cdac13..bb65b684e26a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -10048,6 +10048,42 @@ static int nl80211_notify_radar_detection(struct sk_buff *skb, return 0; } +static int nl80211_parse_counter_offsets(struct cfg80211_registered_device *rdev, + const u8 *data, size_t datalen, + int first_count, struct nlattr *attr, + const u16 **offsets, unsigned int *n_offsets) +{ + int i; + + *n_offsets = 0; + + if (!attr) + return 0; + + if (!nla_len(attr) || (nla_len(attr) % sizeof(u16))) + return -EINVAL; + + *n_offsets = nla_len(attr) / sizeof(u16); + if (rdev->wiphy.max_num_csa_counters && + (*n_offsets > rdev->wiphy.max_num_csa_counters)) + return -EINVAL; + + *offsets = nla_data(attr); + + /* sanity checks - counters should fit and be the same */ + for (i = 0; i < *n_offsets; i++) { + u16 offset = (*offsets)[i]; + + if (offset >= datalen) + return -EINVAL; + + if (first_count != -1 && data[offset] != first_count) + return -EINVAL; + } + + return 0; +} + static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; @@ -10059,7 +10095,6 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) int err; bool need_new_beacon = false; bool need_handle_dfs_flag = true; - int len, i; u32 cs_count; if (!rdev->ops->channel_switch || @@ -10144,72 +10179,23 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) goto free; } - len = nla_len(csa_attrs[NL80211_ATTR_CNTDWN_OFFS_BEACON]); - if (!len || (len % sizeof(u16))) { - err = -EINVAL; + err = nl80211_parse_counter_offsets(rdev, params.beacon_csa.tail, + params.beacon_csa.tail_len, + params.count, + csa_attrs[NL80211_ATTR_CNTDWN_OFFS_BEACON], + ¶ms.counter_offsets_beacon, + ¶ms.n_counter_offsets_beacon); + if (err) goto free; - } - params.n_counter_offsets_beacon = len / sizeof(u16); - if (rdev->wiphy.max_num_csa_counters && - (params.n_counter_offsets_beacon > - rdev->wiphy.max_num_csa_counters)) { - err = -EINVAL; + err = nl80211_parse_counter_offsets(rdev, params.beacon_csa.probe_resp, + params.beacon_csa.probe_resp_len, + params.count, + csa_attrs[NL80211_ATTR_CNTDWN_OFFS_PRESP], + ¶ms.counter_offsets_presp, + ¶ms.n_counter_offsets_presp); + if (err) goto free; - } - - params.counter_offsets_beacon = - nla_data(csa_attrs[NL80211_ATTR_CNTDWN_OFFS_BEACON]); - - /* sanity checks - counters should fit and be the same */ - for (i = 0; i < params.n_counter_offsets_beacon; i++) { - u16 offset = params.counter_offsets_beacon[i]; - - if (offset >= params.beacon_csa.tail_len) { - err = -EINVAL; - goto free; - } - - if (params.beacon_csa.tail[offset] != params.count) { - err = -EINVAL; - goto free; - } - } - - if (csa_attrs[NL80211_ATTR_CNTDWN_OFFS_PRESP]) { - len = nla_len(csa_attrs[NL80211_ATTR_CNTDWN_OFFS_PRESP]); - if (!len || (len % sizeof(u16))) { - err = -EINVAL; - goto free; - } - - params.n_counter_offsets_presp = len / sizeof(u16); - if (rdev->wiphy.max_num_csa_counters && - (params.n_counter_offsets_presp > - rdev->wiphy.max_num_csa_counters)) { - err = -EINVAL; - goto free; - } - - params.counter_offsets_presp = - nla_data(csa_attrs[NL80211_ATTR_CNTDWN_OFFS_PRESP]); - - /* sanity checks - counters should fit and be the same */ - for (i = 0; i < params.n_counter_offsets_presp; i++) { - u16 offset = params.counter_offsets_presp[i]; - - if (offset >= params.beacon_csa.probe_resp_len) { - err = -EINVAL; - goto free; - } - - if (params.beacon_csa.probe_resp[offset] != - params.count) { - err = -EINVAL; - goto free; - } - } - } skip_beacons: err = nl80211_parse_chandef(rdev, info, ¶ms.chandef); @@ -12638,23 +12624,12 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]); params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]); - if (info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]) { - int len = nla_len(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]); - int i; - - if (len % sizeof(u16)) - return -EINVAL; - - params.n_csa_offsets = len / sizeof(u16); - params.csa_offsets = - nla_data(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]); - - /* check that all the offsets fit the frame */ - for (i = 0; i < params.n_csa_offsets; i++) { - if (params.csa_offsets[i] >= params.len) - return -EINVAL; - } - } + err = nl80211_parse_counter_offsets(rdev, NULL, params.len, -1, + info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX], + ¶ms.csa_offsets, + ¶ms.n_csa_offsets); + if (err) + return err; if (!params.dont_wait_for_ack) { msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); -- cgit From 00413dd3641408f5728694d794478613fbe06c23 Mon Sep 17 00:00:00 2001 From: Alexis Lothoré Date: Thu, 15 Feb 2024 15:13:53 +0100 Subject: wifi: wilc1000: remove AKM suite be32 conversion for external auth request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver currently raises the following sparse warning: [...] cfg80211.c:360:42: warning: incorrect type in assignment (different base types) [...] cfg80211.c:360:42: expected unsigned int key_mgmt_suite [...] cfg80211.c:360:42: got restricted __be32 [usertype] CHECK drivers/net/wireless/microchip/wilc1000/netdev.c This conversion was needed because historically the external supplicant (observed with wpa_supplicant) expects AKM suite as big endian in NL80211_CMD_EXTERNAL_AUTH message when the AKM suite is WLAN_AKM_SUITE_SAE. This is not needed anymore: - new (to be released) versions of wpa_supplicant now reads it in host endian _while_ keeping compatibility for older drivers - for new drivers used with current/old wpa_supplicant, this conversion has been added to nl80211 to force big endian when the AKM suite is WLAN_AKM_SUITE_SAE Remove this not-needed-anymore conversion to fix the sparse warning. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202308290615.lUTIgqUl-lkp@intel.com/ Tested-on: WILC1000 hwB SPI WILC_WIFI_FW_REL_16_1-13452 Signed-off-by: Alexis Lothoré Signed-off-by: Kalle Valo Link: https://msgid.link/20240215-nl80211_fix_akm_suites_endianness-v1-2-57e902632f9d@bootlin.com --- drivers/net/wireless/microchip/wilc1000/cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index 33f8e3a41937..089102ed9ae5 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -356,7 +356,7 @@ static int connect(struct wiphy *wiphy, struct net_device *dev, memcpy(vif->auth.ssid.ssid, sme->ssid, sme->ssid_len); vif->auth.ssid.ssid_len = sme->ssid_len; } - vif->auth.key_mgmt_suite = cpu_to_be32(sme->crypto.akm_suites[0]); + vif->auth.key_mgmt_suite = sme->crypto.akm_suites[0]; ether_addr_copy(vif->auth.bssid, sme->bssid); break; -- cgit From 8ca4cdef93297c9b9bf08da39bc940bd20acbb94 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Thu, 15 Feb 2024 20:57:59 +0200 Subject: wifi: rtlwifi: rtl8192cu: Fix TX aggregation rtl8192cu is checking rtl_mac.tids when deciding if it should enable aggregation. This is wrong because rtl_mac.tids is not initialised anywhere. Check rtl_sta_info.tids instead, which is initialised. Also, when enabling aggregation also enable RTS. The vendor driver does this, my router does this. It seems like the thing to do. Also also, it seems right to set the AMPDU density only when enabling aggregation. Also also also, delete the unused member rtl_mac.tids and the unused macros RTL_AGG_ON and RTL_AGG_OFF. Naturally, with working AMPDU the download/upload speeds are better. Before: 59/32 Mbps. After: 68/46 Mbps. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/4e936334-5f81-403f-a495-0628ebfb6903@gmail.com --- .../net/wireless/realtek/rtlwifi/rtl8192cu/trx.c | 29 +++++++++++++--------- .../net/wireless/realtek/rtlwifi/rtl8192cu/trx.h | 2 -- drivers/net/wireless/realtek/rtlwifi/wifi.h | 3 --- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c index 4856ed40005b..aa702ba7c9f5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c @@ -482,8 +482,9 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - u8 *qc = ieee80211_get_qos_ctl(hdr); - u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + struct rtl_sta_info *sta_entry; + u8 agg_state = RTL_AGG_STOP; + u8 ampdu_density = 0; u16 seq_number; __le16 fc = hdr->frame_control; u8 rate_flag = info->control.rates[0].flags; @@ -492,6 +493,7 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, skb_get_queue_mapping(skb)); u8 *txdesc8; __le32 *txdesc; + u8 tid; seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; rtl_get_tcb_desc(hw, info, sta, skb, tcb_desc); @@ -505,10 +507,21 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, set_tx_desc_tx_rate(txdesc, tcb_desc->hw_rate); if (tcb_desc->use_shortgi || tcb_desc->use_shortpreamble) set_tx_desc_data_shortgi(txdesc, 1); - if (mac->tids[tid].agg.agg_state == RTL_AGG_ON && - info->flags & IEEE80211_TX_CTL_AMPDU) { + + if (sta) { + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + tid = ieee80211_get_tid(hdr); + agg_state = sta_entry->tids[tid].agg.agg_state; + ampdu_density = sta->deflink.ht_cap.ampdu_density; + } + + if (agg_state == RTL_AGG_OPERATIONAL && + info->flags & IEEE80211_TX_CTL_AMPDU) { set_tx_desc_agg_enable(txdesc, 1); set_tx_desc_max_agg_num(txdesc, 0x14); + set_tx_desc_ampdu_density(txdesc, ampdu_density); + tcb_desc->rts_enable = 1; + tcb_desc->rts_rate = DESC_RATE24M; } else { set_tx_desc_agg_break(txdesc, 1); } @@ -543,14 +556,6 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, set_tx_desc_data_bw(txdesc, 0); set_tx_desc_data_sc(txdesc, 0); } - rcu_read_lock(); - sta = ieee80211_find_sta(mac->vif, mac->bssid); - if (sta) { - u8 ampdu_density = sta->deflink.ht_cap.ampdu_density; - - set_tx_desc_ampdu_density(txdesc, ampdu_density); - } - rcu_read_unlock(); if (info->control.hw_key) { struct ieee80211_key_conf *keyconf = info->control.hw_key; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.h index 8678fa0043f4..09e61dc0f317 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.h @@ -10,8 +10,6 @@ #define RTL92C_SIZE_MAX_RX_BUFFER 15360 /* 8192 */ #define RX_DRV_INFO_SIZE_UNIT 8 -#define RTL_AGG_ON 1 - enum usb_rx_agg_mode { USB_RX_AGG_DISABLE, USB_RX_AGG_DMA, diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 01df00a43cdb..f388d13e2ba8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -1397,8 +1397,6 @@ struct rtl_phy { #define RTL_AGG_PROGRESS 1 #define RTL_AGG_START 2 #define RTL_AGG_OPERATIONAL 3 -#define RTL_AGG_OFF 0 -#define RTL_AGG_ON 1 #define RTL_RX_AGG_START 1 #define RTL_RX_AGG_STOP 0 #define RTL_AGG_EMPTYING_HW_QUEUE_ADDBA 2 @@ -1473,7 +1471,6 @@ struct rtl_mac { enum nl80211_iftype opmode; /*Probe Beacon management */ - struct rtl_tid_data tids[MAX_TID_COUNT]; enum rtl_link_state link_state; int n_channels; -- cgit From 513c559ca9f05394da79fbf20a8f89eec5f53dce Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 16 Feb 2024 11:39:23 +0800 Subject: wifi: rtl8xxxu: check vif before using in rtl8xxxu_tx() The 'vif' is from tx_info of SKB, and other codes check 'vif' before using, which raises smatch warnings: drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c:5656 rtl8xxxu_tx() warn: variable dereferenced before check 'vif' (see line 5553) Compile tested only. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240216033923.34683-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index db5041d23938..efddbe402f0d 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5550,7 +5550,7 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, struct rtl8xxxu_tx_urb *tx_urb; struct ieee80211_sta *sta = NULL; struct ieee80211_vif *vif = tx_info->control.vif; - struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv; + struct rtl8xxxu_vif *rtlvif = vif ? (struct rtl8xxxu_vif *)vif->drv_priv : NULL; struct device *dev = &priv->udev->dev; u32 queue, rts_rate; u16 pktlen = skb->len; @@ -5621,7 +5621,7 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, default: break; } - if (bmc && rtlvif->hw_key_idx != 0xff) { + if (bmc && rtlvif && rtlvif->hw_key_idx != 0xff) { tx_desc->txdw1 |= cpu_to_le32(TXDESC_EN_DESC_ID); macid = rtlvif->hw_key_idx; } -- cgit From 9208e85c62720608aa6ec6e4265b584a48fb43b0 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 16 Feb 2024 11:39:49 +0800 Subject: wifi: rtlwifi: set initial values for unexpected cases of USB endpoint priority Map USB endpoints to hardware and AC queues according to number of USB endpoints. However, original only give a warning for unexpected cases but initial values are not given. Then, smatch warns: drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c:642 _rtl92cu_init_chipn_two_out_ep_priority() error: uninitialized symbol 'valuelow'. drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c:644 _rtl92cu_init_chipn_two_out_ep_priority() error: uninitialized symbol 'valuehi'. drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c:649 _rtl92cu_init_chipn_two_out_ep_priority() error: uninitialized symbol 'valuehi'. drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c:650 _rtl92cu_init_chipn_two_out_ep_priority() error: uninitialized symbol 'valuelow'. The regular selection is high and low queues, so move default (unexpected) case along with that. Compile tested only. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240216033949.34765-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c index 5ec0eb8773a5..4217c9a08d01 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c @@ -622,6 +622,9 @@ static void _rtl92cu_init_chipn_two_out_ep_priority(struct ieee80211_hw *hw, u16 valuelow; switch (queue_sel) { + default: + WARN_ON(1); + fallthrough; case (TX_SELE_HQ | TX_SELE_LQ): valuehi = QUEUE_HIGH; valuelow = QUEUE_LOW; @@ -634,9 +637,6 @@ static void _rtl92cu_init_chipn_two_out_ep_priority(struct ieee80211_hw *hw, valuehi = QUEUE_HIGH; valuelow = QUEUE_NORMAL; break; - default: - WARN_ON(1); - break; } if (!wmm_enable) { beq = valuelow; -- cgit From 32167707aa5e7ae4b160c18be79d85a7b4fdfcfb Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 16 Feb 2024 22:36:49 +0100 Subject: wifi: brcmfmac: Add DMI nvram filename quirk for ACEPC W5 Pro The ACEPC W5 Pro HDMI stick contains quite generic names in the sys_vendor and product_name DMI strings, without this patch brcmfmac will try to load: "brcmfmac43455-sdio.$(DEFAULT_STRING)-$(DEFAULT_STRING).txt" as nvram file which is both too generic and messy with the $ symbols in the name. The ACEPC W5 Pro uses the same Ampak AP6255 module as the ACEPC T8 and the nvram for the T8 is already in linux-firmware, so point the new DMI nvram filename quirk to the T8 nvram file. Signed-off-by: Hans de Goede Acked-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240216213649.251718-1-hdegoede@redhat.com --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c index 86ff174936a9..c3a602197662 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c @@ -82,6 +82,15 @@ static const struct dmi_system_id dmi_platform_data[] = { }, .driver_data = (void *)&acepc_t8_data, }, + { + /* ACEPC W5 Pro Cherry Trail Z8350 HDMI stick, same wifi as the T8 */ + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "T3 MRD"), + DMI_MATCH(DMI_CHASSIS_TYPE, "3"), + DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), + }, + .driver_data = (void *)&acepc_t8_data, + }, { /* Chuwi Hi8 Pro with D2D3_Hi8Pro.233 BIOS */ .matches = { -- cgit From f3ec643947634bed41b97bd56b248f7c78498eab Mon Sep 17 00:00:00 2001 From: Alexis Lothoré Date: Sat, 17 Feb 2024 14:22:41 +0100 Subject: wifi: wilc1000: revert reset line logic flip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit fcf690b0b47494df51d214db5c5a714a400b0257. When using a wilc1000 chip over a spi bus, users can optionally define a reset gpio and a chip enable gpio. The reset line of wilc1000 is active low, so to hold the chip in reset, a low (physical) value must be applied. The corresponding device tree binding documentation was introduced by commit f31ee3c0a555 ("wilc1000: Document enable-gpios and reset-gpios properties") and correctly indicates that the reset line is an active-low signal. The corresponding driver part, brought by commit ec031ac4792c ("wilc1000: Add reset/enable GPIO support to SPI driver") was applying the correct logic. But commit fcf690b0b474 ("wifi: wilc1000: use correct sequence of RESET for chip Power-UP/Down") eventually flipped this logic and started misusing the gpiod APIs, applying an inverted logic when powering up/down the chip (for example, setting the reset line to a logic "1" during power up, which in fact asserts the reset line when device tree describes the reset line as GPIO_ACTIVE_LOW). As a consequence, any platform currently using the driver in SPI mode must use a faulty reset line description in device tree, or else chip will be maintained in reset and will not even allow to bring up the chip. Fix reset line usage by inverting back the gpiod APIs usage, setting the reset line to the logic value "0" when powering the chip, and the logic value "1" when powering off the chip. Fixes: fcf690b0b474 ("wifi: wilc1000: use correct sequence of RESET for chip Power-UP/Down") Signed-off-by: Alexis Lothoré Acked-by: Conor Dooley Acked-by: Ajay Singh Signed-off-by: Kalle Valo Link: https://msgid.link/20240217-wilc_1000_reset_line-v2-1-b216f433d7d5@bootlin.com --- drivers/net/wireless/microchip/wilc1000/spi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c index 3c4451535c8a..61c3572ce321 100644 --- a/drivers/net/wireless/microchip/wilc1000/spi.c +++ b/drivers/net/wireless/microchip/wilc1000/spi.c @@ -194,11 +194,11 @@ static void wilc_wlan_power(struct wilc *wilc, bool on) /* assert ENABLE: */ gpiod_set_value(gpios->enable, 1); mdelay(5); - /* assert RESET: */ - gpiod_set_value(gpios->reset, 1); - } else { /* deassert RESET: */ gpiod_set_value(gpios->reset, 0); + } else { + /* assert RESET: */ + gpiod_set_value(gpios->reset, 1); /* deassert ENABLE: */ gpiod_set_value(gpios->enable, 0); } -- cgit