From 5cbfef9039f61691c87f522f8761d628033bc392 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sun, 8 Jun 2025 20:08:47 -0700 Subject: [PATCH 001/199] wifi: ath9k: ahb: reorder declarations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Easier to look at. Follows netdev style. Also remove ret assignment. Because of all of these devm conversions, ret = 0 is a path that never gets hit. The first time it does it when request_irq fails, but that ends up reassigning it. Signed-off-by: Rosen Penev Reviewed-by: Krzysztof Kozlowski Acked-by: Toke Høiland-Jørgensen Link: https://patch.msgid.link/20250609030851.17739-2-rosenp@gmail.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath9k/ahb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 49b7ab26c477..d2a97e74f451 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -71,14 +71,14 @@ static const struct ath_bus_ops ath_ahb_bus_ops = { static int ath_ahb_probe(struct platform_device *pdev) { - void __iomem *mem; - struct ath_softc *sc; - struct ieee80211_hw *hw; const struct platform_device_id *id = platform_get_device_id(pdev); - int irq; - int ret = 0; + struct ieee80211_hw *hw; + struct ath_softc *sc; struct ath_hw *ah; + void __iomem *mem; char hw_name[64]; + int irq; + int ret; if (!dev_get_platdata(&pdev->dev)) { dev_err(&pdev->dev, "no platform data specified\n"); From c8123302c01936d297e22adbd75cad38c5049f92 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sun, 8 Jun 2025 20:08:48 -0700 Subject: [PATCH 002/199] wifi: ath9k: ahb: reorder includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Alphabetic includes are easier to look at and to make further changes to them. Signed-off-by: Rosen Penev Reviewed-by: Krzysztof Kozlowski Acked-by: Toke Høiland-Jørgensen Link: https://patch.msgid.link/20250609030851.17739-3-rosenp@gmail.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath9k/ahb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index d2a97e74f451..1ffec827ed87 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -16,10 +16,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include +#include #include #include -#include -#include + #include "ath9k.h" static const struct platform_device_id ath9k_platform_id_table[] = { From f902f2c39a807382353b4c6b8d8d4ac1f03aade9 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sun, 8 Jun 2025 20:08:49 -0700 Subject: [PATCH 003/199] dt-bindings: net: wireless: ath9k: add WIFI bindings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These are for the wireless chips that come built in with various Atheros/QCA SoCs. dts wise, the difference between pcie and the wmac is AHB > PCIE > WIFI AHB > WIFI Signed-off-by: Rosen Penev Reviewed-by: Krzysztof Kozlowski Acked-by: Toke Høiland-Jørgensen Link: https://patch.msgid.link/20250609030851.17739-4-rosenp@gmail.com Signed-off-by: Jeff Johnson --- .../bindings/net/wireless/qca,ath9k.yaml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/net/wireless/qca,ath9k.yaml b/Documentation/devicetree/bindings/net/wireless/qca,ath9k.yaml index 0e5412cff2bc..d16ca8e0a25d 100644 --- a/Documentation/devicetree/bindings/net/wireless/qca,ath9k.yaml +++ b/Documentation/devicetree/bindings/net/wireless/qca,ath9k.yaml @@ -12,7 +12,7 @@ maintainers: description: | This node provides properties for configuring the ath9k wireless device. The node is expected to be specified as a child node of the PCI controller - to which the wireless chip is connected. + or AHB bus to which the wireless chip is connected. allOf: - $ref: ieee80211.yaml# @@ -35,6 +35,12 @@ properties: - pci168c,0034 # AR9462 - pci168c,0036 # AR9565 - pci168c,0037 # AR1111 and AR9485 + - qca,ar9130-wifi + - qca,ar9330-wifi + - qca,ar9340-wifi + - qca,qca9530-wifi + - qca,qca9550-wifi + - qca,qca9560-wifi reg: maxItems: 1 @@ -88,3 +94,13 @@ examples: nvmem-cell-names = "mac-address", "calibration"; }; }; + - | + ahb { + #address-cells = <1>; + #size-cells = <1>; + wifi@180c0000 { + compatible = "qca,ar9130-wifi"; + reg = <0x180c0000 0x230000>; + interrupts = <2>; + }; + }; From 2fa490c0d7591918bed267059700f1c9e505e881 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sun, 8 Jun 2025 20:08:50 -0700 Subject: [PATCH 004/199] wifi: ath9k: ahb: replace id_table with of MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 2b0996c7646 , all of this platform code became no-op with no OF replacement. Not only that, there are no users of AHB here. Add an OF match table that mostly mirrors the original platform device id table. Use a qca prefix as is done for the only other property: qca,no-eeprom. Also used qca prefix for ar9530 as the latter seems to be a mistake. This will be used to add ath9k support for the various ath79 devices here. Signed-off-by: Rosen Penev Reviewed-by: Krzysztof Kozlowski Acked-by: Toke Høiland-Jørgensen Link: https://patch.msgid.link/20250609030851.17739-5-rosenp@gmail.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath9k/ahb.c | 47 ++++++++-------------------- 1 file changed, 13 insertions(+), 34 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 1ffec827ed87..802e6596a6a8 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -19,35 +19,18 @@ #include #include #include +#include #include #include "ath9k.h" -static const struct platform_device_id ath9k_platform_id_table[] = { - { - .name = "ath9k", - .driver_data = AR5416_AR9100_DEVID, - }, - { - .name = "ar933x_wmac", - .driver_data = AR9300_DEVID_AR9330, - }, - { - .name = "ar934x_wmac", - .driver_data = AR9300_DEVID_AR9340, - }, - { - .name = "qca955x_wmac", - .driver_data = AR9300_DEVID_QCA955X, - }, - { - .name = "qca953x_wmac", - .driver_data = AR9300_DEVID_AR953X, - }, - { - .name = "qca956x_wmac", - .driver_data = AR9300_DEVID_QCA956X, - }, +static const struct of_device_id ath9k_of_match_table[] = { + { .compatible = "qca,ar9130-wifi", .data = (void *)AR5416_AR9100_DEVID }, + { .compatible = "qca,ar9330-wifi", .data = (void *)AR9300_DEVID_AR9330 }, + { .compatible = "qca,ar9340-wifi", .data = (void *)AR9300_DEVID_AR9340 }, + { .compatible = "qca,qca9530-wifi", .data = (void *)AR9300_DEVID_AR953X }, + { .compatible = "qca,qca9550-wifi", .data = (void *)AR9300_DEVID_QCA955X }, + { .compatible = "qca,qca9560-wifi", .data = (void *)AR9300_DEVID_QCA956X }, {}, }; @@ -72,20 +55,15 @@ static const struct ath_bus_ops ath_ahb_bus_ops = { static int ath_ahb_probe(struct platform_device *pdev) { - const struct platform_device_id *id = platform_get_device_id(pdev); struct ieee80211_hw *hw; struct ath_softc *sc; struct ath_hw *ah; void __iomem *mem; char hw_name[64]; + u16 dev_id; int irq; int ret; - if (!dev_get_platdata(&pdev->dev)) { - dev_err(&pdev->dev, "no platform data specified\n"); - return -EINVAL; - } - mem = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mem)) { dev_err(&pdev->dev, "ioremap failed\n"); @@ -118,7 +96,8 @@ static int ath_ahb_probe(struct platform_device *pdev) goto err_free_hw; } - ret = ath9k_init_device(id->driver_data, sc, &ath_ahb_bus_ops); + dev_id = (u16)(kernel_ulong_t)of_device_get_match_data(&pdev->dev); + ret = ath9k_init_device(dev_id, sc, &ath_ahb_bus_ops); if (ret) { dev_err(&pdev->dev, "failed to initialize device\n"); goto err_irq; @@ -156,11 +135,11 @@ static struct platform_driver ath_ahb_driver = { .remove = ath_ahb_remove, .driver = { .name = "ath9k", + .of_match_table = ath9k_of_match_table, }, - .id_table = ath9k_platform_id_table, }; -MODULE_DEVICE_TABLE(platform, ath9k_platform_id_table); +MODULE_DEVICE_TABLE(of, ath9k_of_match_table); int ath_ahb_init(void) { From 02dcb6921b8827782e51e26593d4a2866576ab63 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Thu, 22 May 2025 09:34:43 +0800 Subject: [PATCH 005/199] dt-bindings: net: wireless: ath11k-pci: describe firmware-name property Introduce 'firmware-name' property to allow end-users and/or integrators to decide which usecase-specific firmware to run on the WCN6855. This is necessary due to resource limitations such as memory capacity and CPU capability, or performance and power optimization for different application scenarios. Two firmwares are supported: 'WCN6855/hw2.0' and 'WCN6855/hw2.0/nfa765'. The former is the default firmware, suitable for most WiFi 6 STA functions. The latter adds support for commercial-quality SAP and optimizes power consumption for IoT applications. Signed-off-by: Miaoqing Pan Acked-by: Conor Dooley Link: https://patch.msgid.link/20250522013444.1301330-2-miaoqing.pan@oss.qualcomm.com Signed-off-by: Jeff Johnson --- .../devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml index 653b319fee88..e34d42a30192 100644 --- a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml @@ -35,6 +35,12 @@ properties: string to uniquely identify variant of the calibration data for designs with colliding bus and device ids + firmware-name: + maxItems: 1 + description: + If present, a board or platform specific string used to lookup + usecase-specific firmware files for the device. + vddrfacmn-supply: description: VDD_RFA_CMN supply regulator handle From edbbc647c4f36e8a6375d07ecb5aad8e8b90de5e Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Thu, 22 May 2025 09:34:44 +0800 Subject: [PATCH 006/199] wifi: ath11k: support usercase-specific firmware overrides Introduce 'firmware-name' property to allow end-users and/or integrators to decide which usecase-specific firmware to run on the WCN6855. This is necessary due to resource limitations such as memory capacity and CPU capability, or performance and power optimization for different application scenarios. Currently, there are two firmwares, both files can be executed interchangeably. For example: - ath11k/WCN6855/hw2.0/amss.bin, ath11k/WCN6855/hw2.0/m3.bin ath11k/WCN6855/hw2.0/board-2.bin - ath11k/WCN6855/hw2.0/nfa765/amss.bin, ath11k/WCN6855/hw2.0/nfa765/m3.bin ath11k/WCN6855/hw2.0/board-2.bin The former is the default firmware, suitable for most WiFi 6 STA functions. The latter adds support for commercial-quality SAP and optimizes power consumption for IoT applications. And both use the same BDF/regdb data within the main board-2.bin. Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-04479-QCAHSPSWPL_V1_V2_SILICONZ_IOE-1 Signed-off-by: Miaoqing Pan Reviewed-by: Baochen Qiang Link: https://patch.msgid.link/20250522013444.1301330-3-miaoqing.pan@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath11k/core.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 6b2f207975e3..220d69a7a429 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -17,6 +17,7 @@ #include #include #include +#include #include "qmi.h" #include "htc.h" @@ -1322,8 +1323,16 @@ static inline void ath11k_core_create_firmware_path(struct ath11k_base *ab, const char *filename, void *buf, size_t buf_len) { - snprintf(buf, buf_len, "%s/%s/%s", ATH11K_FW_DIR, - ab->hw_params.fw.dir, filename); + const char *fw_name = NULL; + + of_property_read_string(ab->dev->of_node, "firmware-name", &fw_name); + + if (fw_name && strncmp(filename, "board", 5)) + snprintf(buf, buf_len, "%s/%s/%s/%s", ATH11K_FW_DIR, + ab->hw_params.fw.dir, fw_name, filename); + else + snprintf(buf, buf_len, "%s/%s/%s", ATH11K_FW_DIR, + ab->hw_params.fw.dir, filename); } static inline const char *ath11k_bus_str(enum ath11k_bus bus) From a5b46aa7cf5f05c213316a018e49a8e086efd98e Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Thu, 12 Jun 2025 17:45:06 +0900 Subject: [PATCH 007/199] wifi: ath11k: clear initialized flag for deinit-ed srng lists In a number of cases we see kernel panics on resume due to ath11k kernel page fault, which happens under the following circumstances: 1) First ath11k_hal_dump_srng_stats() call Last interrupt received for each group: ath11k_pci 0000:01:00.0: group_id 0 22511ms before ath11k_pci 0000:01:00.0: group_id 1 14440788ms before [..] ath11k_pci 0000:01:00.0: failed to receive control response completion, polling.. ath11k_pci 0000:01:00.0: Service connect timeout ath11k_pci 0000:01:00.0: failed to connect to HTT: -110 ath11k_pci 0000:01:00.0: failed to start core: -110 ath11k_pci 0000:01:00.0: firmware crashed: MHI_CB_EE_RDDM ath11k_pci 0000:01:00.0: already resetting count 2 ath11k_pci 0000:01:00.0: failed to wait wlan mode request (mode 4): -110 ath11k_pci 0000:01:00.0: qmi failed to send wlan mode off: -110 ath11k_pci 0000:01:00.0: failed to reconfigure driver on crash recovery [..] 2) At this point reconfiguration fails (we have 2 resets) and ath11k_core_reconfigure_on_crash() calls ath11k_hal_srng_deinit() which destroys srng lists. However, it does not reset per-list ->initialized flag. 3) Second ath11k_hal_dump_srng_stats() call sees stale ->initialized flag and attempts to dump srng stats: Last interrupt received for each group: ath11k_pci 0000:01:00.0: group_id 0 66785ms before ath11k_pci 0000:01:00.0: group_id 1 14485062ms before ath11k_pci 0000:01:00.0: group_id 2 14485062ms before ath11k_pci 0000:01:00.0: group_id 3 14485062ms before ath11k_pci 0000:01:00.0: group_id 4 14780845ms before ath11k_pci 0000:01:00.0: group_id 5 14780845ms before ath11k_pci 0000:01:00.0: group_id 6 14485062ms before ath11k_pci 0000:01:00.0: group_id 7 66814ms before ath11k_pci 0000:01:00.0: group_id 8 68997ms before ath11k_pci 0000:01:00.0: group_id 9 67588ms before ath11k_pci 0000:01:00.0: group_id 10 69511ms before BUG: unable to handle page fault for address: ffffa007404eb010 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page PGD 100000067 P4D 100000067 PUD 10022d067 PMD 100b01067 PTE 0 Oops: 0000 [#1] PREEMPT SMP NOPTI RIP: 0010:ath11k_hal_dump_srng_stats+0x2b4/0x3b0 [ath11k] Call Trace: ? __die_body+0xae/0xb0 ? page_fault_oops+0x381/0x3e0 ? exc_page_fault+0x69/0xa0 ? asm_exc_page_fault+0x22/0x30 ? ath11k_hal_dump_srng_stats+0x2b4/0x3b0 [ath11k (HASH:6cea 4)] ath11k_qmi_driver_event_work+0xbd/0x1050 [ath11k (HASH:6cea 4)] worker_thread+0x389/0x930 kthread+0x149/0x170 Clear per-list ->initialized flag in ath11k_hal_srng_deinit(). Signed-off-by: Sergey Senozhatsky Reviewed-by: Baochen Qiang Fixes: 5118935b1bc2 ("ath11k: dump SRNG stats during FW assert") Link: https://patch.msgid.link/20250612084551.702803-1-senozhatsky@chromium.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath11k/hal.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index f1d76839a87b..a6513aa6fbfa 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -1348,6 +1348,10 @@ EXPORT_SYMBOL(ath11k_hal_srng_init); void ath11k_hal_srng_deinit(struct ath11k_base *ab) { struct ath11k_hal *hal = &ab->hal; + int i; + + for (i = 0; i < HAL_SRNG_RING_ID_MAX; i++) + ab->hal.srng_list[i].initialized = 0; ath11k_hal_unregister_srng_key(ab); ath11k_hal_free_cont_rdp(ab); From 8f9480451514c065dc8296c0db6e26d6c467fafe Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 24 Jun 2025 10:20:22 +0200 Subject: [PATCH 008/199] wifi: ath11k: fix suspend use-after-free after probe failure Make sure to deregister the PM notifier to avoid a use-after-free on suspend in case core initialisation fails (e.g. due to missing firmware). Tested-on: WCN6855 hw2.0 WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.41 Fixes: 32d93b51bc7e ("wifi: ath11k: choose default PM policy for hibernation") Reported-by: Konrad Dybcio Closes: https://lore.kernel.org/all/d0cd065c-1cd1-4e56-8c57-60777b1f3664@oss.qualcomm.com/ Cc: Baochen Qiang Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20250624082022.15469-1-johan+linaro@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath11k/core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 48d81b82f895..ad942fad01e9 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -2583,10 +2583,15 @@ int ath11k_core_init(struct ath11k_base *ab) ret = ath11k_core_soc_create(ab); if (ret) { ath11k_err(ab, "failed to create soc core: %d\n", ret); - return ret; + goto err_unregister_pm_notifier; } return 0; + +err_unregister_pm_notifier: + ath11k_core_pm_notifier_unregister(ab); + + return ret; } EXPORT_SYMBOL(ath11k_core_init); From d8f07889e920493845fd628407ff0debbe96fa09 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 19 Jun 2025 09:20:10 +0100 Subject: [PATCH 009/199] wifi: ath11k: Make read-only const array svc_id static const Don't populate the read-only array svc_id on the stack at run time, instead make it static const. Signed-off-by: Colin Ian King Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250619082010.1834109-1-colin.i.king@gmail.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath11k/htc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/htc.c b/drivers/net/wireless/ath/ath11k/htc.c index 23054ab29a5e..4571d01cc33d 100644 --- a/drivers/net/wireless/ath/ath11k/htc.c +++ b/drivers/net/wireless/ath/ath11k/htc.c @@ -497,7 +497,7 @@ static u8 ath11k_htc_get_credit_allocation(struct ath11k_htc *htc, static int ath11k_htc_setup_target_buffer_assignments(struct ath11k_htc *htc) { struct ath11k_htc_svc_tx_credits *serv_entry; - u32 svc_id[] = { + static const u32 svc_id[] = { ATH11K_HTC_SVC_ID_WMI_CONTROL, ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC1, ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC2, From 0314ee81a91d22366e8ec6f5a993d75b246cbea8 Mon Sep 17 00:00:00 2001 From: Raj Kumar Bhagat Date: Mon, 23 Jun 2025 21:19:09 +0530 Subject: [PATCH 010/199] wifi: ath12k: handle WMI event for real noise floor calculation At present, the ATH12K_DEFAULT_NOISE_FLOOR (-95) is used to calculate RSSI value, providing an estimated noise floor value. Consequently, the RSSI value is also approximate. This works but however, using actual noise floor value will enable the reporting of the true RSSI value. The firmware possesses the necessary data to determine the actual noise floor. This data is provided to the host via the WMI event WMI_PDEV_RSSI_DBM_CONVERSION_PARAMS_INFO_EVENTID, which includes the runtime parameters needed for calculating the real noise floor in dBm. This event is triggered by the firmware during channel changes, temperature offset adjustments, and hardware chainmask modifications. The individual TLVs may not always be present in each event. For instance, temperature information might only appear if there is a change in offset due to temperature variation. Add support to handle and parse this WMI event. Use the received values to calculate and store the noise floor value. A subsequent change will use this noise floor value in the actual RSSI calculation. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Signed-off-by: Raj Kumar Bhagat Co-developed-by: Aditya Kumar Singh Signed-off-by: Aditya Kumar Singh Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250623-support_real_noise_floor-v2-1-974bbafa317e@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.h | 17 ++ drivers/net/wireless/ath/ath12k/mac.c | 4 + drivers/net/wireless/ath/ath12k/wmi.c | 226 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/wmi.h | 42 +++++ 4 files changed, 289 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 0c1a6df7a02e..3c10d7eb9669 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -674,6 +674,15 @@ struct ath12k_per_peer_tx_stats { bool is_ampdu; }; +struct ath12k_pdev_rssi_offsets { + s32 temp_offset; + s8 min_nf_dbm; + /* Cache the sum here to avoid calculating it every time in hot path + * noise_floor = min_nf_dbm + temp_offset + */ + s32 noise_floor; +}; + #define ATH12K_FLUSH_TIMEOUT (5 * HZ) #define ATH12K_VDEV_DELETE_TIMEOUT_HZ (5 * HZ) @@ -827,6 +836,7 @@ struct ath12k { unsigned long last_tx_power_update; s8 max_allowed_tx_power; + struct ath12k_pdev_rssi_offsets rssi_info; }; struct ath12k_hw { @@ -1467,4 +1477,11 @@ static inline struct ath12k_base *ath12k_ag_to_ab(struct ath12k_hw_group *ag, return ag->ab[device_id]; } +static inline s32 ath12k_pdev_get_noise_floor(struct ath12k *ar) +{ + lockdep_assert_held(&ar->data_lock); + + return ar->rssi_info.noise_floor; +} + #endif /* _CORE_H_ */ diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 32519666632d..4a35577f79f1 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -12529,6 +12529,10 @@ static int ath12k_mac_setup_register(struct ath12k *ar, 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); + ar->rssi_info.min_nf_dbm = ATH12K_DEFAULT_NOISE_FLOOR; + ar->rssi_info.temp_offset = 0; + ar->rssi_info.noise_floor = ar->rssi_info.min_nf_dbm + ar->rssi_info.temp_offset; + return 0; } diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index b38f22118d73..3ec58feab755 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -9319,6 +9319,229 @@ static void ath12k_wmi_process_tpc_stats(struct ath12k_base *ab, } #endif +static int +ath12k_wmi_rssi_dbm_conv_info_evt_subtlv_parser(struct ath12k_base *ab, + u16 tag, u16 len, + const void *ptr, void *data) +{ + const struct ath12k_wmi_rssi_dbm_conv_temp_info_params *temp_info; + const struct ath12k_wmi_rssi_dbm_conv_info_params *param_info; + struct ath12k_wmi_rssi_dbm_conv_info_arg *rssi_info = data; + struct ath12k_wmi_rssi_dbm_conv_param_arg param_arg; + s32 nf_hw_dbm[ATH12K_MAX_NUM_NF_HW_DBM]; + u8 num_20mhz_segments; + s8 min_nf, *nf_ptr; + int i, j; + + switch (tag) { + case WMI_TAG_RSSI_DBM_CONVERSION_PARAMS_INFO: + if (len < sizeof(*param_info)) { + ath12k_warn(ab, + "RSSI dbm conv subtlv 0x%x invalid len %d rcvd", + tag, len); + return -EINVAL; + } + + param_info = ptr; + + param_arg.curr_bw = le32_to_cpu(param_info->curr_bw); + param_arg.curr_rx_chainmask = le32_to_cpu(param_info->curr_rx_chainmask); + + /* The received array is actually a 2D byte-array for per chain, + * per 20MHz subband. Convert to 2D byte-array + */ + nf_ptr = ¶m_arg.nf_hw_dbm[0][0]; + + for (i = 0; i < ATH12K_MAX_NUM_NF_HW_DBM; i++) { + nf_hw_dbm[i] = a_sle32_to_cpu(param_info->nf_hw_dbm[i]); + + for (j = 0; j < 4; j++) { + *nf_ptr = (nf_hw_dbm[i] >> (j * 8)) & 0xFF; + nf_ptr++; + } + } + + switch (param_arg.curr_bw) { + case WMI_CHAN_WIDTH_20: + num_20mhz_segments = 1; + break; + case WMI_CHAN_WIDTH_40: + num_20mhz_segments = 2; + break; + case WMI_CHAN_WIDTH_80: + num_20mhz_segments = 4; + break; + case WMI_CHAN_WIDTH_160: + num_20mhz_segments = 8; + break; + case WMI_CHAN_WIDTH_320: + num_20mhz_segments = 16; + break; + default: + ath12k_warn(ab, "Invalid current bandwidth %d in RSSI dbm event", + param_arg.curr_bw); + /* In error case, still consider the primary 20 MHz segment since + * that would be much better than instead of dropping the whole + * event + */ + num_20mhz_segments = 1; + } + + min_nf = ATH12K_DEFAULT_NOISE_FLOOR; + + for (i = 0; i < ATH12K_MAX_NUM_ANTENNA; i++) { + if (!(param_arg.curr_rx_chainmask & BIT(i))) + continue; + + for (j = 0; j < num_20mhz_segments; j++) { + if (param_arg.nf_hw_dbm[i][j] < min_nf) + min_nf = param_arg.nf_hw_dbm[i][j]; + } + } + + rssi_info->min_nf_dbm = min_nf; + rssi_info->nf_dbm_present = true; + break; + case WMI_TAG_RSSI_DBM_CONVERSION_TEMP_OFFSET_INFO: + if (len < sizeof(*temp_info)) { + ath12k_warn(ab, + "RSSI dbm conv subtlv 0x%x invalid len %d rcvd", + tag, len); + return -EINVAL; + } + + temp_info = ptr; + rssi_info->temp_offset = a_sle32_to_cpu(temp_info->offset); + rssi_info->temp_offset_present = true; + break; + default: + ath12k_dbg(ab, ATH12K_DBG_WMI, + "Unknown subtlv 0x%x in RSSI dbm conversion event\n", tag); + } + + return 0; +} + +static int +ath12k_wmi_rssi_dbm_conv_info_event_parser(struct ath12k_base *ab, + u16 tag, u16 len, + const void *ptr, void *data) +{ + int ret = 0; + + switch (tag) { + case WMI_TAG_RSSI_DBM_CONVERSION_PARAMS_INFO_FIXED_PARAM: + /* Fixed param is already processed*/ + break; + case WMI_TAG_ARRAY_STRUCT: + /* len 0 is expected for array of struct when there + * is no content of that type inside that tlv + */ + if (len == 0) + return 0; + + ret = ath12k_wmi_tlv_iter(ab, ptr, len, + ath12k_wmi_rssi_dbm_conv_info_evt_subtlv_parser, + data); + break; + default: + ath12k_dbg(ab, ATH12K_DBG_WMI, + "Received invalid tag 0x%x for RSSI dbm conv info event\n", + tag); + break; + } + + return ret; +} + +static int +ath12k_wmi_rssi_dbm_conv_info_process_fixed_param(struct ath12k_base *ab, u8 *ptr, + size_t len, int *pdev_id) +{ + struct ath12k_wmi_rssi_dbm_conv_info_fixed_params *fixed_param; + const struct wmi_tlv *tlv; + u16 tlv_tag; + + if (len < (sizeof(*fixed_param) + TLV_HDR_SIZE)) { + ath12k_warn(ab, "invalid RSSI dbm conv event size %zu\n", len); + return -EINVAL; + } + + tlv = (struct wmi_tlv *)ptr; + tlv_tag = le32_get_bits(tlv->header, WMI_TLV_TAG); + ptr += sizeof(*tlv); + + if (tlv_tag != WMI_TAG_RSSI_DBM_CONVERSION_PARAMS_INFO_FIXED_PARAM) { + ath12k_warn(ab, "RSSI dbm conv event received without fixed param tlv\n"); + return -EINVAL; + } + + fixed_param = (struct ath12k_wmi_rssi_dbm_conv_info_fixed_params *)ptr; + *pdev_id = le32_to_cpu(fixed_param->pdev_id); + + return 0; +} + +static void +ath12k_wmi_update_rssi_offsets(struct ath12k *ar, + struct ath12k_wmi_rssi_dbm_conv_info_arg *rssi_info) +{ + struct ath12k_pdev_rssi_offsets *info = &ar->rssi_info; + + lockdep_assert_held(&ar->data_lock); + + if (rssi_info->temp_offset_present) + info->temp_offset = rssi_info->temp_offset; + + if (rssi_info->nf_dbm_present) + info->min_nf_dbm = rssi_info->min_nf_dbm; + + info->noise_floor = info->min_nf_dbm + info->temp_offset; +} + +static void +ath12k_wmi_rssi_dbm_conversion_params_info_event(struct ath12k_base *ab, + struct sk_buff *skb) +{ + struct ath12k_wmi_rssi_dbm_conv_info_arg rssi_info; + struct ath12k *ar; + s32 noise_floor; + u32 pdev_id; + int ret; + + ret = ath12k_wmi_rssi_dbm_conv_info_process_fixed_param(ab, skb->data, skb->len, + &pdev_id); + if (ret) { + ath12k_warn(ab, "failed to parse fixed param in RSSI dbm conv event: %d\n", + ret); + return; + } + + rcu_read_lock(); + ar = ath12k_mac_get_ar_by_pdev_id(ab, pdev_id); + /* If pdev is not active, ignore the event */ + if (!ar) + goto out_unlock; + + ret = ath12k_wmi_tlv_iter(ab, skb->data, skb->len, + ath12k_wmi_rssi_dbm_conv_info_event_parser, + &rssi_info); + if (ret) { + ath12k_warn(ab, "unable to parse RSSI dbm conversion event\n"); + goto out_unlock; + } + + spin_lock_bh(&ar->data_lock); + ath12k_wmi_update_rssi_offsets(ar, &rssi_info); + noise_floor = ath12k_pdev_get_noise_floor(ar); + spin_unlock_bh(&ar->data_lock); + + ath12k_dbg(ab, ATH12K_DBG_WMI, + "RSSI noise floor updated, new value is %d dbm\n", noise_floor); +out_unlock: + rcu_read_unlock(); +} + static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; @@ -9450,6 +9673,9 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) case WMI_11D_NEW_COUNTRY_EVENTID: ath12k_reg_11d_new_cc_event(ab, skb); break; + case WMI_PDEV_RSSI_DBM_CONVERSION_PARAMS_INFO_EVENTID: + ath12k_wmi_rssi_dbm_conversion_params_info_event(ab, skb); + break; /* add Unsupported events (rare) 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 8627154f1680..ccf430164717 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -734,6 +734,8 @@ enum wmi_tlv_event_id { WMI_SERVICE_READY_EXT2_EVENTID, WMI_PDEV_GET_HALPHY_CAL_STATUS_EVENTID = WMI_SERVICE_READY_EXT2_EVENTID + 4, + WMI_PDEV_RSSI_DBM_CONVERSION_PARAMS_INFO_EVENTID = + WMI_PDEV_GET_HALPHY_CAL_STATUS_EVENTID + 5, WMI_VDEV_START_RESP_EVENTID = WMI_TLV_CMD(WMI_GRP_VDEV), WMI_VDEV_STOPPED_EVENTID, WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID, @@ -1992,6 +1994,9 @@ enum wmi_tlv_tag { WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD = 0x3D8, WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD = 0x3D9, WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD = 0x3FB, + WMI_TAG_RSSI_DBM_CONVERSION_PARAMS_INFO_FIXED_PARAM = 0x427, + WMI_TAG_RSSI_DBM_CONVERSION_PARAMS_INFO, + WMI_TAG_RSSI_DBM_CONVERSION_TEMP_OFFSET_INFO, WMI_TAG_HALPHY_CTRL_PATH_CMD_FIXED_PARAM = 0x442, WMI_TAG_HALPHY_CTRL_PATH_EVENT_FIXED_PARAM, WMI_TAG_MAX @@ -6176,6 +6181,43 @@ struct wmi_mlo_link_set_active_arg { struct wmi_ml_disallow_mode_bmap_arg disallow_bmap[WMI_ML_MAX_DISALLOW_BMAP_COMB]; }; +#define ATH12K_MAX_20MHZ_SEGMENTS 16 +#define ATH12K_MAX_NUM_ANTENNA 8 +#define ATH12K_MAX_NUM_NF_HW_DBM 32 + +struct ath12k_wmi_rssi_dbm_conv_info_fixed_params { + __le32 pdev_id; +} __packed; + +struct ath12k_wmi_rssi_dbm_conv_info_params { + __le32 curr_bw; + __le32 curr_rx_chainmask; + __le32 xbar_config; + a_sle32 xlna_bypass_offset; + a_sle32 xlna_bypass_threshold; + a_sle32 nf_hw_dbm[ATH12K_MAX_NUM_NF_HW_DBM]; +} __packed; + +struct ath12k_wmi_rssi_dbm_conv_temp_info_params { + a_sle32 offset; +} __packed; + +struct ath12k_wmi_rssi_dbm_conv_param_arg { + u32 curr_bw; + u32 curr_rx_chainmask; + u32 xbar_config; + s32 xlna_bypass_offset; + s32 xlna_bypass_threshold; + s8 nf_hw_dbm[ATH12K_MAX_NUM_ANTENNA][ATH12K_MAX_20MHZ_SEGMENTS]; +}; + +struct ath12k_wmi_rssi_dbm_conv_info_arg { + bool temp_offset_present; + s32 temp_offset; + bool nf_dbm_present; + s8 min_nf_dbm; +}; + 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, From 662e9032140fd92662142d4bf394916cf48e426f Mon Sep 17 00:00:00 2001 From: Raj Kumar Bhagat Date: Mon, 23 Jun 2025 21:19:10 +0530 Subject: [PATCH 011/199] wifi: ath12k: use real noise floor instead of default value ATH12K_DEFAULT_NOISE_FLOOR represents the approximate noise floor value which is used for RSSI calculation. Commit "wifi: ath12k: handle WMI event for real noise floor calculation" added support to get the real noise floor value from the firmware. Add changes to use the real value now instead of the default one. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Signed-off-by: Raj Kumar Bhagat Co-developed-by: Aditya Kumar Singh Signed-off-by: Aditya Kumar Singh Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250623-support_real_noise_floor-v2-2-974bbafa317e@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/dp_mon.c | 7 ++++++- drivers/net/wireless/ath/ath12k/dp_tx.c | 20 ++++++++++++++++---- drivers/net/wireless/ath/ath12k/mac.c | 10 +++++++--- drivers/net/wireless/ath/ath12k/wmi.c | 7 ++++++- 4 files changed, 35 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index 91f4e3aff74c..b408103fe9d4 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -2146,10 +2146,15 @@ static void ath12k_dp_mon_update_radiotap(struct ath12k *ar, struct ieee80211_rx_status *rxs) { struct ieee80211_supported_band *sband; + s32 noise_floor; u8 *ptr = NULL; + spin_lock_bh(&ar->data_lock); + noise_floor = ath12k_pdev_get_noise_floor(ar); + spin_unlock_bh(&ar->data_lock); + rxs->flag |= RX_FLAG_MACTIME_START; - rxs->signal = ppduinfo->rssi_comb + ATH12K_DEFAULT_NOISE_FLOOR; + rxs->signal = ppduinfo->rssi_comb + noise_floor; rxs->nss = ppduinfo->nss + 1; if (ppduinfo->userstats[ppduinfo->userid].ampdu_present) { diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index 075912eacfaa..ca3d97043da0 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -553,6 +553,7 @@ ath12k_dp_tx_htt_tx_complete_buf(struct ath12k_base *ab, struct ath12k_vif *ahvif; struct ath12k *ar; struct sk_buff *msdu = desc_params->skb; + s32 noise_floor; skb_cb = ATH12K_SKB_CB(msdu); info = IEEE80211_SKB_CB(msdu); @@ -591,8 +592,13 @@ ath12k_dp_tx_htt_tx_complete_buf(struct ath12k_base *ab, info->status.ack_signal = ts->ack_rssi; if (!test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT, - ab->wmi_ab.svc_map)) - info->status.ack_signal += ATH12K_DEFAULT_NOISE_FLOOR; + ab->wmi_ab.svc_map)) { + spin_lock_bh(&ar->data_lock); + noise_floor = ath12k_pdev_get_noise_floor(ar); + spin_unlock_bh(&ar->data_lock); + + info->status.ack_signal += noise_floor; + } info->status.flags = IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; } else { @@ -774,6 +780,7 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar, struct ieee80211_vif *vif; struct ath12k_vif *ahvif; struct sk_buff *msdu = desc_params->skb; + s32 noise_floor; if (WARN_ON_ONCE(ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM)) { /* Must not happen */ @@ -826,8 +833,13 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar, info->status.ack_signal = ts->ack_rssi; if (!test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT, - ab->wmi_ab.svc_map)) - info->status.ack_signal += ATH12K_DEFAULT_NOISE_FLOOR; + ab->wmi_ab.svc_map)) { + spin_lock_bh(&ar->data_lock); + noise_floor = ath12k_pdev_get_noise_floor(ar); + spin_unlock_bh(&ar->data_lock); + + info->status.ack_signal += noise_floor; + } info->status.flags = IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; } diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 4a35577f79f1..ab184c5c7da1 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -11590,8 +11590,8 @@ static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta); struct ath12k_fw_stats_req_params params = {}; struct ath12k_link_sta *arsta; + s8 signal, noise_floor; struct ath12k *ar; - s8 signal; bool db2dbm; lockdep_assert_wiphy(hw->wiphy); @@ -11639,15 +11639,19 @@ static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, !(ath12k_mac_get_fw_stats(ar, ¶ms))) signal = arsta->rssi_beacon; + spin_lock_bh(&ar->data_lock); + noise_floor = ath12k_pdev_get_noise_floor(ar); + spin_unlock_bh(&ar->data_lock); + if (signal) { - sinfo->signal = db2dbm ? signal : signal + ATH12K_DEFAULT_NOISE_FLOOR; + sinfo->signal = db2dbm ? signal : signal + noise_floor; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); } sinfo->signal_avg = ewma_avg_rssi_read(&arsta->avg_rssi); if (!db2dbm) - sinfo->signal_avg += ATH12K_DEFAULT_NOISE_FLOOR; + sinfo->signal_avg += noise_floor; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG); } diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 3ec58feab755..37ac921fb7da 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -6981,6 +6981,7 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb) struct ieee80211_hdr *hdr; u16 fc; struct ieee80211_supported_band *sband; + s32 noise_floor; if (ath12k_pull_mgmt_rx_params_tlv(ab, skb, &rx_ev) != 0) { ath12k_warn(ab, "failed to extract mgmt rx event"); @@ -7042,7 +7043,11 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb) status->freq = ieee80211_channel_to_frequency(rx_ev.channel, status->band); - status->signal = rx_ev.snr + ATH12K_DEFAULT_NOISE_FLOOR; + spin_lock_bh(&ar->data_lock); + noise_floor = ath12k_pdev_get_noise_floor(ar); + spin_unlock_bh(&ar->data_lock); + + status->signal = rx_ev.snr + noise_floor; status->rate_idx = ath12k_mac_bitrate_to_idx(sband, rx_ev.rate / 100); hdr = (struct ieee80211_hdr *)skb->data; From 70eeacc1a92a444f4b5777ab19e1c378a5edc8dd Mon Sep 17 00:00:00 2001 From: Hari Chandrakanthan Date: Fri, 30 May 2025 09:26:14 +0530 Subject: [PATCH 012/199] wifi: ath12k: Fix station association with MBSSID Non-TX BSS ath12k station is unable to associate with non-transmitting BSSes in a Multiple BSS set because the user-space does not receive information about the non-transmitting BSSes from mac80211's scan results. The ath12k driver does not advertise its MBSSID capability to mac80211, resulting in wiphy->support_mbssid not being set. Consequently, the information about non-transmitting BSS is not parsed from received Beacon/Probe response frames and is therefore not included in the scan results. Fix this by advertising the MBSSID capability of ath12k driver to mac80211. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00284-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1 Signed-off-by: Hari Chandrakanthan Signed-off-by: Rameshkumar Sundaram Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250530035615.3178480-2-rameshkumar.sundaram@oss.qualcomm.com Signed-off-by: Jeff Johnson --- 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 ab184c5c7da1..42036658cf71 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -12719,6 +12719,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) wiphy->mbssid_max_interfaces = mbssid_max_interfaces; wiphy->ema_max_profile_periodicity = TARGET_EMA_MAX_PROFILE_PERIOD; + ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); if (is_6ghz) { wiphy_ext_feature_set(wiphy, From ce7c93d196bfd2190dc4a0b86deee04e82042ed1 Mon Sep 17 00:00:00 2001 From: Rameshkumar Sundaram Date: Fri, 30 May 2025 09:26:15 +0530 Subject: [PATCH 013/199] wifi: ath12k: Fix beacon reception for sta associated to Non-TX AP Currently, when a station is associated with a Non-Transmitting BSS of an MBSSID set, beacons are not frequently received from the firmware. This results in missing events via beacons, such as channel switches, leading to the station not switching to new channel as the AP does, eventually causing a kick out event from the firmware. This issue arises due to missing configuration of Non-Transmitting BSS information in station's vdev up command. Fix this by filling information such as the Transmitting BSSID, profile index and profile count in vdev up command of station. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00284-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1 Signed-off-by: Rameshkumar Sundaram Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250530035615.3178480-3-rameshkumar.sundaram@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 56 ++++++++++++++++++--------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 42036658cf71..4496002a17a0 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -602,6 +602,33 @@ ath12k_mac_get_tx_arvif(struct ath12k_link_vif *arvif, return NULL; } +static const u8 *ath12k_mac_get_tx_bssid(struct ath12k_link_vif *arvif) +{ + struct ieee80211_bss_conf *link_conf; + struct ath12k_link_vif *tx_arvif; + struct ath12k *ar = arvif->ar; + + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + link_conf = ath12k_mac_get_link_bss_conf(arvif); + if (!link_conf) { + ath12k_warn(ar->ab, + "unable to access bss link conf for link %u required to retrieve transmitting link conf\n", + arvif->link_id); + return NULL; + } + if (link_conf->vif->type == NL80211_IFTYPE_STATION) { + if (link_conf->nontransmitted) + return link_conf->transmitter_bssid; + } else { + tx_arvif = ath12k_mac_get_tx_arvif(arvif, link_conf); + if (tx_arvif) + return tx_arvif->bssid; + } + + return NULL; +} + struct ieee80211_bss_conf * ath12k_mac_get_link_bss_conf(struct ath12k_link_vif *arvif) { @@ -1691,8 +1718,6 @@ static void ath12k_control_beaconing(struct ath12k_link_vif *arvif, { struct ath12k_wmi_vdev_up_params params = {}; struct ath12k_vif *ahvif = arvif->ahvif; - struct ieee80211_bss_conf *link_conf; - struct ath12k_link_vif *tx_arvif; struct ath12k *ar = arvif->ar; int ret; @@ -1723,18 +1748,8 @@ static void ath12k_control_beaconing(struct ath12k_link_vif *arvif, params.vdev_id = arvif->vdev_id; params.aid = ahvif->aid; params.bssid = arvif->bssid; - - link_conf = ath12k_mac_get_link_bss_conf(arvif); - if (!link_conf) { - ath12k_warn(ar->ab, - "unable to access bss link conf for link %u required to retrieve transmitting link conf\n", - arvif->link_id); - return; - } - - tx_arvif = ath12k_mac_get_tx_arvif(arvif, link_conf); - if (tx_arvif) { - params.tx_bssid = tx_arvif->bssid; + params.tx_bssid = ath12k_mac_get_tx_bssid(arvif); + if (params.tx_bssid) { params.nontx_profile_idx = info->bssid_index; params.nontx_profile_cnt = 1 << info->bssid_indicator; } @@ -3264,6 +3279,11 @@ static void ath12k_bss_assoc(struct ath12k *ar, params.vdev_id = arvif->vdev_id; params.aid = ahvif->aid; params.bssid = arvif->bssid; + params.tx_bssid = ath12k_mac_get_tx_bssid(arvif); + if (params.tx_bssid) { + params.nontx_profile_idx = bss_conf->bssid_index; + params.nontx_profile_cnt = 1 << bss_conf->bssid_indicator; + } ret = ath12k_wmi_vdev_up(ar, ¶ms); if (ret) { ath12k_warn(ar->ab, "failed to set vdev %d up: %d\n", @@ -10132,7 +10152,7 @@ ath12k_mac_update_vif_chan(struct ath12k *ar, int n_vifs) { struct ath12k_wmi_vdev_up_params params = {}; - struct ath12k_link_vif *arvif, *tx_arvif; + struct ath12k_link_vif *arvif; struct ieee80211_bss_conf *link_conf; struct ath12k_base *ab = ar->ab; struct ieee80211_vif *vif; @@ -10204,10 +10224,8 @@ ath12k_mac_update_vif_chan(struct ath12k *ar, params.vdev_id = arvif->vdev_id; params.aid = ahvif->aid; params.bssid = arvif->bssid; - - tx_arvif = ath12k_mac_get_tx_arvif(arvif, link_conf); - if (tx_arvif) { - params.tx_bssid = tx_arvif->bssid; + params.tx_bssid = ath12k_mac_get_tx_bssid(arvif); + if (params.tx_bssid) { params.nontx_profile_idx = link_conf->bssid_index; params.nontx_profile_cnt = 1 << link_conf->bssid_indicator; } From 9903c0986f782dfc511d7638b6f15fb6e8600cd3 Mon Sep 17 00:00:00 2001 From: Sarika Sharma Date: Tue, 3 Jun 2025 12:05:12 +0530 Subject: [PATCH 014/199] wifi: ath12k: Add memset and update default rate value in wmi tx completion When both AP/STA and monitor interfaces are enabled, ieee80211_tx_status() is invoked from two paths: the TX completion handler for data frames and the WMI TX completion handler for management frames. In the data path, the skb->cb is properly zeroed using memset, but in the WMI path, this step is missing. As a result, mac80211 encountered uninitialized (junk) values in skb->cb when generating the radiotap header for monitor mode, leading to invalid radiotap lengths. Hence, explicitly zero the status field in the skb->cb using memset in WMI TX completion path to ensure consistent and correct behavior during WMI tx completion path. Additionally, set info->status.rates[0].idx = -1 to indicate that no valid rate information is available, avoiding misinterpretation of garbage values. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Signed-off-by: Sarika Sharma Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250603063512.1887652-1-quic_sarishar@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/wmi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 37ac921fb7da..12bea62dc3d0 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -6140,6 +6140,11 @@ static int wmi_process_mgmt_tx_comp(struct ath12k *ar, u32 desc_id, dma_unmap_single(ar->ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); info = IEEE80211_SKB_CB(msdu); + memset(&info->status, 0, sizeof(info->status)); + + /* skip tx rate update from ieee80211_status*/ + info->status.rates[0].idx = -1; + if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) && !status) info->flags |= IEEE80211_TX_STAT_ACK; From a44958c83e52238996a48e7d604167c9b9d0a529 Mon Sep 17 00:00:00 2001 From: Hariharan Basuthkar Date: Fri, 6 Jun 2025 16:53:16 +0530 Subject: [PATCH 015/199] wifi: ath12k: Send WMI_VDEV_SET_TPC_POWER_CMD for AP vdev The power value is 6 dBm on an AP operating on the 6 GHz channel. This is a very low value. On 6 GHz, the target computes the EIRP based on the power values sent in the WMI_VDEV_SET_TPC_POWER_CMD. Currently, this is being sent only for station interfaces and not for AP interfaces. Therefore, add AP vdev to the condition in ath12k_mac_station_supports_tpc() and rename ath12k_mac_station_supports_tpc() to ath12k_mac_supports_tpc(). For a AP vdev, hardcode ap_power_type as IEEE80211_REG_LPI_AP, which is filled in the WMI_VDEV_SET_TPC_POWER_CMDID sent to the target. Currently, LPI is the only supported AP power mode. Since there is no method currently to set the AP power mode from user-space, the power mode is hard-coded to LPI. Retain the existing logic for populating the power mode for a station vdev. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Signed-off-by: Hariharan Basuthkar Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250606112316.39316-1-quic_hbasuthk@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 4496002a17a0..1b9dd3ac280f 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -3775,13 +3775,13 @@ static void ath12k_mac_vif_setup_ps(struct ath12k_link_vif *arvif) psmode, arvif->vdev_id, ret); } -static bool ath12k_mac_supports_station_tpc(struct ath12k *ar, - struct ath12k_vif *ahvif, - const struct cfg80211_chan_def *chandef) +static bool ath12k_mac_supports_tpc(struct ath12k *ar, struct ath12k_vif *ahvif, + const struct cfg80211_chan_def *chandef) { return ath12k_wmi_supports_6ghz_cc_ext(ar) && test_bit(WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT, ar->ab->wmi_ab.svc_map) && - ahvif->vdev_type == WMI_VDEV_TYPE_STA && + (ahvif->vdev_type == WMI_VDEV_TYPE_STA || + ahvif->vdev_type == WMI_VDEV_TYPE_AP) && ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE && chandef->chan && chandef->chan->band == NL80211_BAND_6GHZ; @@ -9964,7 +9964,7 @@ ath12k_mac_vdev_start_restart(struct ath12k_link_vif *arvif, /* TODO: For now we only set TPC power here. However when * channel changes, say CSA, it should be updated again. */ - if (ath12k_mac_supports_station_tpc(ar, ahvif, chandef)) { + if (ath12k_mac_supports_tpc(ar, ahvif, chandef)) { ath12k_mac_fill_reg_tpc_info(ar, arvif, ctx); ath12k_wmi_send_vdev_set_tpc_power(ar, arvif->vdev_id, &arvif->reg_tpc_info); @@ -10519,7 +10519,9 @@ void ath12k_mac_fill_reg_tpc_info(struct ath12k *ar, bool is_psd_power = false, is_tpe_present = false; s8 max_tx_power[ATH12K_NUM_PWR_LEVELS], psd_power, tx_power, eirp_power; + struct ath12k_vif *ahvif = arvif->ahvif; u16 start_freq, center_freq; + u8 reg_6ghz_power_mode; chan = ctx->def.chan; start_freq = ath12k_mac_get_6ghz_start_frequency(&ctx->def); @@ -10675,8 +10677,14 @@ void ath12k_mac_fill_reg_tpc_info(struct ath12k *ar, reg_tpc_info->num_pwr_levels = num_pwr_levels; reg_tpc_info->is_psd_power = is_psd_power; reg_tpc_info->eirp_power = eirp_power; + if (ahvif->vdev_type == WMI_VDEV_TYPE_STA) + reg_6ghz_power_mode = bss_conf->power_type; + else + /* For now, LPI is the only supported AP power mode */ + reg_6ghz_power_mode = IEEE80211_REG_LPI_AP; + reg_tpc_info->ap_power_type = - ath12k_reg_ap_pwr_convert(bss_conf->power_type); + ath12k_reg_ap_pwr_convert(reg_6ghz_power_mode); } static void ath12k_mac_parse_tx_pwr_env(struct ath12k *ar, From 8c1ba5091fa9a2d1478da63173b16a701bdf86bb Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 4 Jun 2025 16:34:53 +0200 Subject: [PATCH 016/199] wifi: ath11k: fix dest ring-buffer corruption Add the missing memory barrier to make sure that destination ring descriptors are read after the head pointers to avoid using stale data on weakly ordered architectures like aarch64. The barrier is added to the ath11k_hal_srng_access_begin() helper for symmetry with follow-on fixes for source ring buffer corruption which will add barriers to ath11k_hal_srng_access_end(). Tested-on: WCN6855 hw2.1 WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.41 Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices") Cc: stable@vger.kernel.org # 5.6 Signed-off-by: Johan Hovold Reviewed-by: Baochen Qiang Link: https://patch.msgid.link/20250604143457.26032-2-johan+linaro@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath11k/ce.c | 3 --- drivers/net/wireless/ath/ath11k/dp_rx.c | 3 --- drivers/net/wireless/ath/ath11k/hal.c | 12 +++++++++++- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c index be9395f2ed8b..878ce30b307c 100644 --- a/drivers/net/wireless/ath/ath11k/ce.c +++ b/drivers/net/wireless/ath/ath11k/ce.c @@ -395,9 +395,6 @@ static int ath11k_ce_completed_recv_next(struct ath11k_ce_pipe *pipe, goto err; } - /* Make sure descriptor is read after the head pointer. */ - dma_rmb(); - *nbytes = ath11k_hal_ce_dst_status_get_length(desc); *skb = pipe->dest_ring->skb[sw_index]; diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 9230a965f6f0..065fc40e2541 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -2650,9 +2650,6 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id, try_again: ath11k_hal_srng_access_begin(ab, srng); - /* Make sure descriptor is read after the head pointer. */ - dma_rmb(); - while (likely(desc = (struct hal_reo_dest_ring *)ath11k_hal_srng_dst_get_next_entry(ab, srng))) { diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index a6513aa6fbfa..0aa73774150c 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -825,13 +825,23 @@ u32 *ath11k_hal_srng_src_peek(struct ath11k_base *ab, struct hal_srng *srng) void ath11k_hal_srng_access_begin(struct ath11k_base *ab, struct hal_srng *srng) { + u32 hp; + lockdep_assert_held(&srng->lock); if (srng->ring_dir == HAL_SRNG_DIR_SRC) { srng->u.src_ring.cached_tp = *(volatile u32 *)srng->u.src_ring.tp_addr; } else { - srng->u.dst_ring.cached_hp = READ_ONCE(*srng->u.dst_ring.hp_addr); + hp = READ_ONCE(*srng->u.dst_ring.hp_addr); + + if (hp != srng->u.dst_ring.cached_hp) { + srng->u.dst_ring.cached_hp = hp; + /* Make sure descriptor is read after the head + * pointer. + */ + dma_rmb(); + } /* Try to prefetch the next descriptor in the ring */ if (srng->flags & HAL_SRNG_FLAGS_CACHED) From 3a690e9091ec07f70cedd9a7dcc074c8554f1bed Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 4 Jun 2025 16:34:54 +0200 Subject: [PATCH 017/199] wifi: ath11k: use plain access for descriptor length The read memory barrier added by commit 6d037a372f81 ("wifi: ath11k: fix ring-buffer corruption") is enough to guarantee ordering also for plain descriptor accesses if the length helper is ever inlined so drop the unnecessary READ_ONCE(). Tested-on: WCN6855 hw2.1 WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.41 Signed-off-by: Johan Hovold Reviewed-by: Baochen Qiang Link: https://patch.msgid.link/20250604143457.26032-3-johan+linaro@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath11k/hal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index 0aa73774150c..4a3bdacc5769 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -601,7 +601,7 @@ u32 ath11k_hal_ce_dst_status_get_length(void *buf) struct hal_ce_srng_dst_status_desc *desc = buf; u32 len; - len = FIELD_GET(HAL_CE_DST_STATUS_DESC_FLAGS_LEN, READ_ONCE(desc->flags)); + len = FIELD_GET(HAL_CE_DST_STATUS_DESC_FLAGS_LEN, desc->flags); desc->flags &= ~HAL_CE_DST_STATUS_DESC_FLAGS_LEN; return len; From 4aba95fb1faed7fe7f6e1edfb60c333e0275dfc1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 4 Jun 2025 16:34:55 +0200 Subject: [PATCH 018/199] wifi: ath11k: use plain accesses for monitor descriptor The read memory barrier added by commit ab52e3e44fe9 ("wifi: ath11k: fix rx completion meta data corruption") is enough to guarantee ordering also for plain descriptor accesses so drop the unnecessary READ_ONCE(). Tested-on: WCN6855 hw2.1 WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.41 Signed-off-by: Johan Hovold Reviewed-by: Baochen Qiang Link: https://patch.msgid.link/20250604143457.26032-4-johan+linaro@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath11k/dp_rx.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 065fc40e2541..1eec1cc114fe 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -2637,7 +2637,7 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id, struct ath11k *ar; struct hal_reo_dest_ring *desc; enum hal_reo_dest_ring_push_reason push_reason; - u32 cookie, info0, rx_msdu_info0, rx_mpdu_info0; + u32 cookie; int i; for (i = 0; i < MAX_RADIOS; i++) @@ -2654,7 +2654,7 @@ try_again: (struct hal_reo_dest_ring *)ath11k_hal_srng_dst_get_next_entry(ab, srng))) { cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, - READ_ONCE(desc->buf_addr_info.info1)); + desc->buf_addr_info.info1); buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, cookie); mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID, cookie); @@ -2683,9 +2683,8 @@ try_again: num_buffs_reaped[mac_id]++; - info0 = READ_ONCE(desc->info0); push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON, - info0); + desc->info0); if (unlikely(push_reason != HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION)) { dev_kfree_skb_any(msdu); @@ -2693,21 +2692,18 @@ try_again: continue; } - rx_msdu_info0 = READ_ONCE(desc->rx_msdu_info.info0); - rx_mpdu_info0 = READ_ONCE(desc->rx_mpdu_info.info0); - - rxcb->is_first_msdu = !!(rx_msdu_info0 & + rxcb->is_first_msdu = !!(desc->rx_msdu_info.info0 & RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU); - rxcb->is_last_msdu = !!(rx_msdu_info0 & + rxcb->is_last_msdu = !!(desc->rx_msdu_info.info0 & RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU); - rxcb->is_continuation = !!(rx_msdu_info0 & + rxcb->is_continuation = !!(desc->rx_msdu_info.info0 & RX_MSDU_DESC_INFO0_MSDU_CONTINUATION); rxcb->peer_id = FIELD_GET(RX_MPDU_DESC_META_DATA_PEER_ID, - READ_ONCE(desc->rx_mpdu_info.meta_data)); + desc->rx_mpdu_info.meta_data); rxcb->seq_no = FIELD_GET(RX_MPDU_DESC_INFO0_SEQ_NUM, - rx_mpdu_info0); + desc->rx_mpdu_info.info0); rxcb->tid = FIELD_GET(HAL_REO_DEST_RING_INFO0_RX_QUEUE_NUM, - info0); + desc->info0); rxcb->mac_id = mac_id; __skb_queue_tail(&msdu_list[mac_id], msdu); From 6efa0df54022c6c9fd4d294b87622c7fcdc418c8 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 4 Jun 2025 16:34:56 +0200 Subject: [PATCH 019/199] wifi: ath11k: fix source ring-buffer corruption Add the missing memory barrier to make sure that LMAC source ring descriptors are written before updating the head pointer to avoid passing stale data to the firmware on weakly ordered architectures like aarch64. Note that non-LMAC rings use MMIO write accessors which have the required write memory barrier. Tested-on: WCN6855 hw2.1 WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.41 Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices") Cc: stable@vger.kernel.org # 5.6 Signed-off-by: Johan Hovold Reviewed-by: Baochen Qiang Link: https://patch.msgid.link/20250604143457.26032-5-johan+linaro@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath11k/hal.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index 4a3bdacc5769..28f94c36d304 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -864,7 +864,11 @@ void ath11k_hal_srng_access_end(struct ath11k_base *ab, struct hal_srng *srng) if (srng->ring_dir == HAL_SRNG_DIR_SRC) { srng->u.src_ring.last_tp = *(volatile u32 *)srng->u.src_ring.tp_addr; - *srng->u.src_ring.hp_addr = srng->u.src_ring.hp; + /* Make sure descriptor is written before updating the + * head pointer. + */ + dma_wmb(); + WRITE_ONCE(*srng->u.src_ring.hp_addr, srng->u.src_ring.hp); } else { srng->u.dst_ring.last_hp = *srng->u.dst_ring.hp_addr; *srng->u.dst_ring.tp_addr = srng->u.dst_ring.tp; @@ -873,6 +877,10 @@ void ath11k_hal_srng_access_end(struct ath11k_base *ab, struct hal_srng *srng) if (srng->ring_dir == HAL_SRNG_DIR_SRC) { srng->u.src_ring.last_tp = *(volatile u32 *)srng->u.src_ring.tp_addr; + /* Assume implementation use an MMIO write accessor + * which has the required wmb() so that the descriptor + * is written before the updating the head pointer. + */ ath11k_hif_write32(ab, (unsigned long)srng->u.src_ring.hp_addr - (unsigned long)ab->mem, From aa6956150f820e6a6deba44be325ddfcb5b10f88 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 4 Jun 2025 16:34:57 +0200 Subject: [PATCH 020/199] wifi: ath11k: fix dest ring-buffer corruption when ring is full Add the missing memory barriers to make sure that destination ring descriptors are read before updating the tail pointer (and passing ownership to the device) to avoid memory corruption on weakly ordered architectures like aarch64 when the ring is full. Tested-on: WCN6855 hw2.1 WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.41 Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices") Cc: stable@vger.kernel.org # 5.6 Signed-off-by: Johan Hovold Reviewed-by: Baochen Qiang Link: https://patch.msgid.link/20250604143457.26032-6-johan+linaro@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath11k/hal.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index 28f94c36d304..0c3ce7509ab8 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -856,7 +856,6 @@ void ath11k_hal_srng_access_end(struct ath11k_base *ab, struct hal_srng *srng) { lockdep_assert_held(&srng->lock); - /* TODO: See if we need a write memory barrier here */ if (srng->flags & HAL_SRNG_FLAGS_LMAC_RING) { /* For LMAC rings, ring pointer updates are done through FW and * hence written to a shared memory location that is read by FW @@ -871,7 +870,11 @@ void ath11k_hal_srng_access_end(struct ath11k_base *ab, struct hal_srng *srng) WRITE_ONCE(*srng->u.src_ring.hp_addr, srng->u.src_ring.hp); } else { srng->u.dst_ring.last_hp = *srng->u.dst_ring.hp_addr; - *srng->u.dst_ring.tp_addr = srng->u.dst_ring.tp; + /* Make sure descriptor is read before updating the + * tail pointer. + */ + dma_mb(); + WRITE_ONCE(*srng->u.dst_ring.tp_addr, srng->u.dst_ring.tp); } } else { if (srng->ring_dir == HAL_SRNG_DIR_SRC) { @@ -887,6 +890,10 @@ void ath11k_hal_srng_access_end(struct ath11k_base *ab, struct hal_srng *srng) srng->u.src_ring.hp); } else { srng->u.dst_ring.last_hp = *srng->u.dst_ring.hp_addr; + /* Make sure descriptor is read before updating the + * tail pointer. + */ + mb(); ath11k_hif_write32(ab, (unsigned long)srng->u.dst_ring.tp_addr - (unsigned long)ab->mem, From 8157ce533a60521f21d466eb4de45d9735b19484 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 17 Jun 2025 10:43:59 +0200 Subject: [PATCH 021/199] wifi: ath12k: fix dest ring-buffer corruption Add the missing memory barrier to make sure that destination ring descriptors are read after the head pointers to avoid using stale data on weakly ordered architectures like aarch64. The barrier is added to the ath12k_hal_srng_access_begin() helper for symmetry with follow-on fixes for source ring buffer corruption which will add barriers to ath12k_hal_srng_access_end(). Tested-on: WCN7850 hw2.0 WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Cc: stable@vger.kernel.org # 6.3 Signed-off-by: Johan Hovold Reviewed-by: Baochen Qiang Link: https://patch.msgid.link/20250617084402.14475-2-johan+linaro@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/ce.c | 3 --- drivers/net/wireless/ath/ath12k/hal.c | 17 ++++++++++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/ce.c b/drivers/net/wireless/ath/ath12k/ce.c index 3f3439262cf4..f7c15b547504 100644 --- a/drivers/net/wireless/ath/ath12k/ce.c +++ b/drivers/net/wireless/ath/ath12k/ce.c @@ -433,9 +433,6 @@ static int ath12k_ce_completed_recv_next(struct ath12k_ce_pipe *pipe, goto err; } - /* Make sure descriptor is read after the head pointer. */ - dma_rmb(); - *nbytes = ath12k_hal_ce_dst_status_get_length(desc); *skb = pipe->dest_ring->skb[sw_index]; diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index a301898e5849..f8bd3837b9dc 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -2143,13 +2143,24 @@ void *ath12k_hal_srng_src_get_next_reaped(struct ath12k_base *ab, void ath12k_hal_srng_access_begin(struct ath12k_base *ab, struct hal_srng *srng) { + u32 hp; + lockdep_assert_held(&srng->lock); - if (srng->ring_dir == HAL_SRNG_DIR_SRC) + if (srng->ring_dir == HAL_SRNG_DIR_SRC) { srng->u.src_ring.cached_tp = *(volatile u32 *)srng->u.src_ring.tp_addr; - else - srng->u.dst_ring.cached_hp = READ_ONCE(*srng->u.dst_ring.hp_addr); + } else { + hp = READ_ONCE(*srng->u.dst_ring.hp_addr); + + if (hp != srng->u.dst_ring.cached_hp) { + srng->u.dst_ring.cached_hp = hp; + /* Make sure descriptor is read after the head + * pointer. + */ + dma_rmb(); + } + } } /* Update cached ring head/tail pointers to HW. ath12k_hal_srng_access_begin() From 79390f613d639f7ef913377719cc5094357e53bc Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 17 Jun 2025 10:44:00 +0200 Subject: [PATCH 022/199] wifi: ath12k: use plain access for descriptor length The read memory barrier added by commit 6b67d2cf14ea ("wifi: ath12k: fix ring-buffer corruption") is enough to guarantee ordering also for plain descriptor accesses if the length helper is ever inlined so drop the unnecessary READ_ONCE(). Tested-on: WCN7850 hw2.0 WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Johan Hovold Reviewed-by: Baochen Qiang Link: https://patch.msgid.link/20250617084402.14475-3-johan+linaro@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/hal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index f8bd3837b9dc..726969cfcaec 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -1950,7 +1950,7 @@ u32 ath12k_hal_ce_dst_status_get_length(struct hal_ce_srng_dst_status_desc *desc { u32 len; - len = le32_get_bits(READ_ONCE(desc->flags), HAL_CE_DST_STATUS_DESC_FLAGS_LEN); + len = le32_get_bits(desc->flags, HAL_CE_DST_STATUS_DESC_FLAGS_LEN); desc->flags &= ~cpu_to_le32(HAL_CE_DST_STATUS_DESC_FLAGS_LEN); return len; From e834da4cbd6fe1d24f89368bf0c80adcad212726 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 17 Jun 2025 10:44:01 +0200 Subject: [PATCH 023/199] wifi: ath12k: fix source ring-buffer corruption Add the missing memory barrier to make sure that LMAC source ring descriptors are written before updating the head pointer to avoid passing stale data to the firmware on weakly ordered architectures like aarch64. Note that non-LMAC rings use MMIO write accessors which have the required write memory barrier. Tested-on: WCN7850 hw2.0 WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Cc: stable@vger.kernel.org # 6.3 Signed-off-by: Johan Hovold Reviewed-by: Baochen Qiang Link: https://patch.msgid.link/20250617084402.14475-4-johan+linaro@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/hal.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index 726969cfcaec..d8193d9577bb 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -2178,7 +2178,11 @@ void ath12k_hal_srng_access_end(struct ath12k_base *ab, struct hal_srng *srng) if (srng->ring_dir == HAL_SRNG_DIR_SRC) { srng->u.src_ring.last_tp = *(volatile u32 *)srng->u.src_ring.tp_addr; - *srng->u.src_ring.hp_addr = srng->u.src_ring.hp; + /* Make sure descriptor is written before updating the + * head pointer. + */ + dma_wmb(); + WRITE_ONCE(*srng->u.src_ring.hp_addr, srng->u.src_ring.hp); } else { srng->u.dst_ring.last_hp = *srng->u.dst_ring.hp_addr; *srng->u.dst_ring.tp_addr = srng->u.dst_ring.tp; @@ -2187,6 +2191,10 @@ void ath12k_hal_srng_access_end(struct ath12k_base *ab, struct hal_srng *srng) if (srng->ring_dir == HAL_SRNG_DIR_SRC) { srng->u.src_ring.last_tp = *(volatile u32 *)srng->u.src_ring.tp_addr; + /* Assume implementation use an MMIO write accessor + * which has the required wmb() so that the descriptor + * is written before the updating the head pointer. + */ ath12k_hif_write32(ab, (unsigned long)srng->u.src_ring.hp_addr - (unsigned long)ab->mem, From ed32169be1ccb9b1a295275ba7746dc6bf103e80 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 17 Jun 2025 10:44:02 +0200 Subject: [PATCH 024/199] wifi: ath12k: fix dest ring-buffer corruption when ring is full Add the missing memory barriers to make sure that destination ring descriptors are read before updating the tail pointer (and passing ownership to the device) to avoid memory corruption on weakly ordered architectures like aarch64 when the ring is full. Tested-on: WCN7850 hw2.0 WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Cc: stable@vger.kernel.org # 6.3 Signed-off-by: Johan Hovold Reviewed-by: Baochen Qiang Link: https://patch.msgid.link/20250617084402.14475-5-johan+linaro@kernel.org Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/hal.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index d8193d9577bb..6406fcf5d69f 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -2170,7 +2170,6 @@ void ath12k_hal_srng_access_end(struct ath12k_base *ab, struct hal_srng *srng) { lockdep_assert_held(&srng->lock); - /* TODO: See if we need a write memory barrier here */ if (srng->flags & HAL_SRNG_FLAGS_LMAC_RING) { /* For LMAC rings, ring pointer updates are done through FW and * hence written to a shared memory location that is read by FW @@ -2185,7 +2184,11 @@ void ath12k_hal_srng_access_end(struct ath12k_base *ab, struct hal_srng *srng) WRITE_ONCE(*srng->u.src_ring.hp_addr, srng->u.src_ring.hp); } else { srng->u.dst_ring.last_hp = *srng->u.dst_ring.hp_addr; - *srng->u.dst_ring.tp_addr = srng->u.dst_ring.tp; + /* Make sure descriptor is read before updating the + * tail pointer. + */ + dma_mb(); + WRITE_ONCE(*srng->u.dst_ring.tp_addr, srng->u.dst_ring.tp); } } else { if (srng->ring_dir == HAL_SRNG_DIR_SRC) { @@ -2201,6 +2204,10 @@ void ath12k_hal_srng_access_end(struct ath12k_base *ab, struct hal_srng *srng) srng->u.src_ring.hp); } else { srng->u.dst_ring.last_hp = *srng->u.dst_ring.hp_addr; + /* Make sure descriptor is read before updating the + * tail pointer. + */ + mb(); ath12k_hif_write32(ab, (unsigned long)srng->u.dst_ring.tp_addr - (unsigned long)ab->mem, From c27bb624b3d789a337df3bbcc020a575680555cc Mon Sep 17 00:00:00 2001 From: Thiraviyam Mariyappan Date: Sun, 8 Jun 2025 20:26:51 +0530 Subject: [PATCH 025/199] wifi: ath12k: Clear auth flag only for actual association in security mode When setting a new bitrate, WMI peer association command is sent from the host without the peer authentication bit set in peer_flags for security mode, which causes ping failure. The firmware handles peer_flags when the client is associating, as the peer authentication bit in peer_flags is set after the key exchange. When the WMI peer association command is sent from the host to update the new bitrate for an associated STA, the firmware expects the WMI peer authentication bit to be set in peer_flags. Fix this issue by ensuring that the WMI peer auth bit is set in peer_flags in WMI peer association command when updating the new bitrate. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Signed-off-by: Thiraviyam Mariyappan Signed-off-by: Ramasamy Kaliappan Link: https://patch.msgid.link/20250608145651.1735236-1-ramasamy.kaliappan@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 4 ++++ drivers/net/wireless/ath/ath12k/wmi.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 1b9dd3ac280f..f565db7b7b44 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -3250,6 +3250,7 @@ static void ath12k_bss_assoc(struct ath12k *ar, rcu_read_unlock(); + peer_arg->is_assoc = true; ret = ath12k_wmi_send_peer_assoc_cmd(ar, peer_arg); if (ret) { ath12k_warn(ar->ab, "failed to run peer assoc for %pM vdev %i: %d\n", @@ -5354,6 +5355,8 @@ static int ath12k_mac_station_assoc(struct ath12k *ar, "invalid peer NSS %d\n", peer_arg->peer_nss); return -EINVAL; } + + peer_arg->is_assoc = true; ret = ath12k_wmi_send_peer_assoc_cmd(ar, peer_arg); if (ret) { ath12k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n", @@ -5600,6 +5603,7 @@ static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk) ath12k_peer_assoc_prepare(ar, arvif, arsta, peer_arg, true); + peer_arg->is_assoc = false; err = ath12k_wmi_send_peer_assoc_cmd(ar, peer_arg); if (err) ath12k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n", diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 12bea62dc3d0..d6efbea2e724 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -2152,7 +2152,7 @@ static void ath12k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd, cmd->peer_flags |= cpu_to_le32(WMI_PEER_AUTH); if (arg->need_ptk_4_way) { cmd->peer_flags |= cpu_to_le32(WMI_PEER_NEED_PTK_4_WAY); - if (!hw_crypto_disabled) + if (!hw_crypto_disabled && arg->is_assoc) cmd->peer_flags &= cpu_to_le32(~WMI_PEER_AUTH); } if (arg->need_gtk_2_way) From ffc7adb0a121cd72a02095106bd006f44593ee35 Mon Sep 17 00:00:00 2001 From: Saleemuddin Shaik Date: Tue, 17 Jun 2025 16:51:39 +0530 Subject: [PATCH 026/199] wifi: ath12k: Add support for transmit histogram stats Add support for transmit histogram stats under HTT stats type 9. These stats give information about drop count, MCS drop rate, histogram count, etc. Note: WCN7850 firmware version - WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 does not support tag HTT_STATS_TX_PDEV_HISTOGRAM_STATS_TAG(144), currently. Sample output: echo 9 > /sys/kernel/debug/ath12k/pci-0000\:58\:00.0/mac0/htt_stats_type cat /sys/kernel/debug/ath12k/pci-0000\:58\:00.0/mac0/htt_stats ... low_latency_rate_cnt = 0 su_burst_rate_drop_cnt = 0 su_burst_rate_drop_fail_cnt = 0 rate_retry_mcs_drop_cnt = 0 PER_HISTOGRAM_STATS mcs_drop_rate = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:0, 12:0, 13:0, 14:0, 15:0 per_histogram_count = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:0, 12:0, 13:0, 14:0, 15:0, 16:0, 17:0, 18:0, 19:0, 20:0, 21:0, 22:0, 23:0, 24:0, 25:0, 26:0, 27:0, 28:0, 29:0, 30:0, 31:0, 32:0, 33:0, 34:0, 35:0, 36:0, 37:0, 38:0, 39:0, 40:0, 41:0, 42:0, 43:0, 44:0, 45:0, 46:0, 47:0, 48:0, 49:0, 50:0, 51:0, 52:0, 53:0, 54:0, 55:0, 56:0, 57:0, 58:0, 59:0, 60:0, 61:0, 62:0, 63:0, 64:0, 65:0, 66:0, 67:0, 68:0, 69:0, 70:0, 71:0, 72:0, 73:0, 74:0, 75:0, 76:0, 77:0, 78:0, 79:0, 80:0, 81:0, 82:0, 83:0, 84:0, 85:0, 86:0, 87:0, 88:0, 89:0, 90:0, 91:0, 92:0, 93:0, 94:0, 95:0, 96:0, 97:0, 98:0, 99:0, 100:0 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Signed-off-by: Saleemuddin Shaik Signed-off-by: Roopni Devanathan Link: https://patch.msgid.link/20250617112139.865788-1-quic_rdevanat@quicinc.com [add __packed to struct ath12k_htt_tx_histogram_stats_tlv] Signed-off-by: Jeff Johnson --- .../wireless/ath/ath12k/debugfs_htt_stats.c | 36 ++++++++++++++++++- .../wireless/ath/ath12k/debugfs_htt_stats.h | 16 +++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c index aeaf970339d4..0da6c91dd314 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c @@ -4720,7 +4720,38 @@ ath12k_htt_print_tx_pdev_rate_stats_tlv(const void *tag_buf, u16 tag_len, len += print_array_to_buf(buf, len, "tx_pream", htt_stats_buf->tx_pream, ATH12K_HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES, "\n"); len += print_array_to_buf(buf, len, "tx_dcm", htt_stats_buf->tx_dcm, - ATH12K_HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS, "\n"); + ATH12K_HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS, "\n\n"); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_histogram_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_histogram_stats_tlv *stats_buf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf; + + if (tag_len < sizeof(*stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "low_latency_rate_cnt = %u\n", + le32_to_cpu(stats_buf->low_latency_rate_cnt)); + len += scnprintf(buf + len, buf_len - len, "su_burst_rate_drop_cnt = %u\n", + le32_to_cpu(stats_buf->su_burst_rate_drop_cnt)); + len += scnprintf(buf + len, buf_len - len, "su_burst_rate_drop_fail_cnt = %u\n", + le32_to_cpu(stats_buf->su_burst_rate_drop_fail_cnt)); + len += scnprintf(buf + len, buf_len - len, "rate_retry_mcs_drop_cnt = %u\n", + le32_to_cpu(stats_buf->rate_retry_mcs_drop_cnt)); + + len += scnprintf(buf + len, buf_len - len, "\nPER_HISTOGRAM_STATS\n"); + len += print_array_to_buf(buf, len, "mcs_drop_rate", stats_buf->mcs_drop_rate, + ATH12K_HTT_TX_PDEV_STATS_NUM_MCS_DROP_COUNTERS, "\n"); + len += print_array_to_buf(buf, len, "per_histogram_count", + stats_buf->per_histogram_cnt, + ATH12K_HTT_TX_PDEV_STATS_NUM_PER_COUNTERS, "\n\n"); stats_req->buf_len = len; } @@ -5277,6 +5308,9 @@ static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab, case HTT_STATS_TX_PDEV_RATE_STATS_TAG: ath12k_htt_print_tx_pdev_rate_stats_tlv(tag_buf, len, stats_req); break; + case HTT_STATS_TX_PDEV_HISTOGRAM_STATS_TAG: + ath12k_htt_print_histogram_stats_tlv(tag_buf, len, stats_req); + break; case HTT_STATS_RX_PDEV_RATE_STATS_TAG: ath12k_htt_print_rx_pdev_rate_stats_tlv(tag_buf, len, stats_req); break; diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h index c2a02cf8a38b..ec1b4613be51 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h @@ -237,6 +237,7 @@ enum ath12k_dbg_htt_tlv_tag { HTT_STATS_TX_SELFGEN_BE_ERR_STATS_TAG = 137, HTT_STATS_TX_SELFGEN_BE_STATS_TAG = 138, HTT_STATS_TX_SELFGEN_BE_SCHED_STATUS_STATS_TAG = 139, + HTT_STATS_TX_PDEV_HISTOGRAM_STATS_TAG = 144, HTT_STATS_TXBF_OFDMA_AX_NDPA_STATS_TAG = 147, HTT_STATS_TXBF_OFDMA_AX_NDP_STATS_TAG = 148, HTT_STATS_TXBF_OFDMA_AX_BRP_STATS_TAG = 149, @@ -418,6 +419,12 @@ struct ath12k_htt_tx_pdev_mu_ppdu_dist_stats_tlv { #define ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA_MCS_COUNTERS 2 #define ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA2_MCS_COUNTERS 2 #define ATH12K_HTT_TX_PDEV_STATS_NUM_11AX_TRIGGER_TYPES 6 +#define ATH12K_HTT_TX_PDEV_STATS_NUM_PER_COUNTERS 101 + +#define ATH12K_HTT_TX_PDEV_STATS_NUM_MCS_DROP_COUNTERS \ + (ATH12K_HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS + \ + ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA_MCS_COUNTERS + \ + ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA2_MCS_COUNTERS) struct ath12k_htt_tx_pdev_rate_stats_tlv { __le32 mac_id_word; @@ -472,6 +479,15 @@ struct ath12k_htt_tx_pdev_rate_stats_tlv { __le32 tx_bw_320mhz; }; +struct ath12k_htt_tx_histogram_stats_tlv { + __le32 rate_retry_mcs_drop_cnt; + __le32 mcs_drop_rate[ATH12K_HTT_TX_PDEV_STATS_NUM_MCS_DROP_COUNTERS]; + __le32 per_histogram_cnt[ATH12K_HTT_TX_PDEV_STATS_NUM_PER_COUNTERS]; + __le32 low_latency_rate_cnt; + __le32 su_burst_rate_drop_cnt; + __le32 su_burst_rate_drop_fail_cnt; +} __packed; + #define ATH12K_HTT_RX_PDEV_STATS_NUM_LEGACY_CCK_STATS 4 #define ATH12K_HTT_RX_PDEV_STATS_NUM_LEGACY_OFDM_STATS 8 #define ATH12K_HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS 12 From a7f74e782e274e8255808c165cb2cf63ee0876cc Mon Sep 17 00:00:00 2001 From: Maharaja Kennadyrajan Date: Tue, 17 Jun 2025 10:41:35 +0530 Subject: [PATCH 027/199] wifi: ath12k: Add support to TDMA and MLO stats Add support to request TDMA stats, MLO scheduled stats and MLO IPC stats from firmware through HTT stats type 57, 63 and 64, respectively. These stats give information about TDMA schedules, TDMA slot switches, MLO preferred timeout, delay, MLO IPC ring count, etc. Note: WCN firmware version - WLAN.HMT.1.1.c5-00284.1-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 does not support tags HTT_STATS_PDEV_TDMA_TAG(187), HTT_STATS_MLO_SCHED_STATS_TAG(190) and HTT_STATS_PDEV_MLO_IPC_STATS_TAG(191), currently. Sample output: echo 57 > /sys/kernel/debug/ath12k/pci-0000\:58\:00.0/mac0/htt_stats_type cat /sys/kernel/debug/ath12k/pci-0000\:58\:00.0/mac0/htt_stats HTT_PDEV_TDMA_STATS_TLV: mac_id = 0 num_tdma_active_schedules = 0 num_tdma_reserved_schedules = 0 num_tdma_restricted_schedules = 0 num_tdma_unconfigured_schedules = 0 num_tdma_slot_switches = 0 num_tdma_edca_switches = 0 echo 63 > /sys/kernel/debug/ath12k/pci-0000\:58\:00.0/mac0/htt_stats_type cat /sys/kernel/debug/ath12k/pci-0000\:58\:00.0/mac0/htt_stats HTT_STATS_MLO_SCHED_STATS: num_sec_link_sched = 0 num_pref_link_timeout = 0 num_pref_link_sch_delay_ipc = 0 num_pref_link_timeout_ipc = 0 echo 64 > /sys/kernel/debug/ath12k/pci-0000\:58\:00.0/mac0/htt_stats_type cat /sys/kernel/debug/ath12k/pci-0000\:58\:00.0/mac0/htt_stats HTT_STATS_MLO_IPC_STATS: src_link: 0 mlo_ipc_ring_full_cnt[0]: 0 mlo_ipc_ring_full_cnt[1]: 0 mlo_ipc_ring_full_cnt[2]: 0 mlo_ipc_ring_full_cnt[3]: 0 mlo_ipc_ring_full_cnt[4]: 0 mlo_ipc_ring_full_cnt[5]: 0 mlo_ipc_ring_full_cnt[6]: 0 src_link: 1 mlo_ipc_ring_full_cnt[0]: 0 mlo_ipc_ring_full_cnt[1]: 0 mlo_ipc_ring_full_cnt[2]: 0 mlo_ipc_ring_full_cnt[3]: 0 mlo_ipc_ring_full_cnt[4]: 0 mlo_ipc_ring_full_cnt[5]: 0 mlo_ipc_ring_full_cnt[6]: 0 ..... Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Signed-off-by: Maharaja Kennadyrajan Signed-off-by: Roopni Devanathan Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250617051136.264193-2-quic_rdevanat@quicinc.com Signed-off-by: Jeff Johnson --- .../wireless/ath/ath12k/debugfs_htt_stats.c | 96 +++++++++++++++++++ .../wireless/ath/ath12k/debugfs_htt_stats.h | 30 ++++++ 2 files changed, 126 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c index 0da6c91dd314..004ee0688cd7 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c @@ -5046,6 +5046,93 @@ ath12k_htt_print_rx_pdev_rate_ext_stats_tlv(const void *tag_buf, u16 tag_len, stats_req->buf_len = len; } +static void +ath12k_htt_print_pdev_tdma_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_pdev_tdma_stats_tlv *htt_stats_buf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf; + u32 mac_id_word; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + mac_id_word = le32_to_cpu(htt_stats_buf->mac_id__word); + + len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_TDMA_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", + u32_get_bits(mac_id_word, ATH12K_HTT_STATS_MAC_ID)); + len += scnprintf(buf + len, buf_len - len, "num_tdma_active_schedules = %u\n", + le32_to_cpu(htt_stats_buf->num_tdma_active_schedules)); + len += scnprintf(buf + len, buf_len - len, "num_tdma_reserved_schedules = %u\n", + le32_to_cpu(htt_stats_buf->num_tdma_reserved_schedules)); + len += scnprintf(buf + len, buf_len - len, + "num_tdma_restricted_schedules = %u\n", + le32_to_cpu(htt_stats_buf->num_tdma_restricted_schedules)); + len += scnprintf(buf + len, buf_len - len, + "num_tdma_unconfigured_schedules = %u\n", + le32_to_cpu(htt_stats_buf->num_tdma_unconfigured_schedules)); + len += scnprintf(buf + len, buf_len - len, "num_tdma_slot_switches = %u\n", + le32_to_cpu(htt_stats_buf->num_tdma_slot_switches)); + len += scnprintf(buf + len, buf_len - len, "num_tdma_edca_switches = %u\n\n", + le32_to_cpu(htt_stats_buf->num_tdma_edca_switches)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_mlo_sched_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_mlo_sched_stats_tlv *stats_buf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf; + + if (tag_len < sizeof(*stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_STATS_MLO_SCHED_STATS:\n"); + len += scnprintf(buf + len, buf_len - len, "num_sec_link_sched = %u\n", + le32_to_cpu(stats_buf->pref_link_num_sec_link_sched)); + len += scnprintf(buf + len, buf_len - len, "num_pref_link_timeout = %u\n", + le32_to_cpu(stats_buf->pref_link_num_pref_link_timeout)); + len += scnprintf(buf + len, buf_len - len, "num_pref_link_sch_delay_ipc = %u\n", + le32_to_cpu(stats_buf->pref_link_num_pref_link_sch_delay_ipc)); + len += scnprintf(buf + len, buf_len - len, "num_pref_link_timeout_ipc = %u\n\n", + le32_to_cpu(stats_buf->pref_link_num_pref_link_timeout_ipc)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_mlo_ipc_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_pdev_mlo_ipc_stats_tlv *stats_buf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf; + u8 i, j; + + if (tag_len < sizeof(*stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_STATS_MLO_IPC_STATS:\n"); + for (i = 0; i < ATH12K_HTT_HWMLO_MAX_LINKS; i++) { + len += scnprintf(buf + len, buf_len - len, "src_link: %u\n", i); + for (j = 0; j < ATH12K_HTT_MLO_MAX_IPC_RINGS; j++) + len += scnprintf(buf + len, buf_len - len, + "mlo_ipc_ring_full_cnt[%u]: %u\n", j, + le32_to_cpu(stats_buf->mlo_ipc_ring_cnt[i][j])); + len += scnprintf(buf + len, buf_len - len, "\n"); + } + + stats_req->buf_len = len; +} + static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab, u16 tag, u16 len, const void *tag_buf, void *user_data) @@ -5317,6 +5404,15 @@ static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab, case HTT_STATS_RX_PDEV_RATE_EXT_STATS_TAG: ath12k_htt_print_rx_pdev_rate_ext_stats_tlv(tag_buf, len, stats_req); break; + case HTT_STATS_PDEV_TDMA_TAG: + ath12k_htt_print_pdev_tdma_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_MLO_SCHED_STATS_TAG: + ath12k_htt_print_mlo_sched_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_PDEV_MLO_IPC_STATS_TAG: + ath12k_htt_print_mlo_ipc_stats_tlv(tag_buf, len, stats_req); + break; default: break; } diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h index ec1b4613be51..e301958bfddd 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h @@ -155,6 +155,9 @@ enum ath12k_dbg_htt_ext_stats_type { ATH12K_DBG_HTT_EXT_STATS_PDEV_SCHED_ALGO = 49, ATH12K_DBG_HTT_EXT_STATS_MANDATORY_MUOFDMA = 51, ATH12K_DGB_HTT_EXT_STATS_PDEV_MBSSID_CTRL_FRAME = 54, + ATH12K_DBG_HTT_PDEV_TDMA_STATS = 57, + ATH12K_DBG_HTT_MLO_SCHED_STATS = 63, + ATH12K_DBG_HTT_PDEV_MLO_IPC_STATS = 64, /* keep this last */ ATH12K_DBG_HTT_NUM_EXT_STATS, @@ -248,6 +251,9 @@ enum ath12k_dbg_htt_tlv_tag { HTT_STATS_PDEV_SCHED_ALGO_OFDMA_STATS_TAG = 165, HTT_STATS_TXBF_OFDMA_AX_STEER_MPDU_STATS_TAG = 172, HTT_STATS_PDEV_MBSSID_CTRL_FRAME_STATS_TAG = 176, + HTT_STATS_PDEV_TDMA_TAG = 187, + HTT_STATS_MLO_SCHED_STATS_TAG = 190, + HTT_STATS_PDEV_MLO_IPC_STATS_TAG = 191, HTT_STATS_MAX_TAG, }; @@ -1888,4 +1894,28 @@ struct ath12k_htt_pdev_mbssid_ctrl_frame_tlv { __le32 ul_mumimo_trigger_within_bss; } __packed; +struct ath12k_htt_pdev_tdma_stats_tlv { + __le32 mac_id__word; + __le32 num_tdma_active_schedules; + __le32 num_tdma_reserved_schedules; + __le32 num_tdma_restricted_schedules; + __le32 num_tdma_unconfigured_schedules; + __le32 num_tdma_slot_switches; + __le32 num_tdma_edca_switches; +} __packed; + +struct ath12k_htt_mlo_sched_stats_tlv { + __le32 pref_link_num_sec_link_sched; + __le32 pref_link_num_pref_link_timeout; + __le32 pref_link_num_pref_link_sch_delay_ipc; + __le32 pref_link_num_pref_link_timeout_ipc; +} __packed; + +#define ATH12K_HTT_HWMLO_MAX_LINKS 6 +#define ATH12K_HTT_MLO_MAX_IPC_RINGS 7 + +struct ath12k_htt_pdev_mlo_ipc_stats_tlv { + __le32 mlo_ipc_ring_cnt[ATH12K_HTT_HWMLO_MAX_LINKS][ATH12K_HTT_MLO_MAX_IPC_RINGS]; +} __packed; + #endif From 81a0286cefe6f81744160d3524d70e67479b314b Mon Sep 17 00:00:00 2001 From: Maharaja Kennadyrajan Date: Tue, 17 Jun 2025 10:41:36 +0530 Subject: [PATCH 028/199] wifi: ath12k: Add support to RTT stats Add support to request RTT stats from firmware through HTT stats type 65 and 66. HTT stats type 65 support RTT response stats, RTT hardware stats, RTT to-be-read self-generated stats and RTT command-result stats and HTT stats type 66 support RTT initiator stats and RTT hardware stats. These stats give information about number of scheduled commands, responder allocation and termination count, initiator termination count, PASN authentication drop and receive counts, etc. Note: WCN firmware version - WLAN.HMT.1.1.c5-00284.1-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 does not support tags HTT_STATS_PDEV_RTT_RESP_STATS_TAG(194), HTT_STATS_PDEV_RTT_INIT_STATS_TAG(195), HTT_STATS_PDEV_RTT_HW_STATS_TAG(196), HTT_STATS_PDEV_RTT_TBR_SELFGEN_QUEUED_STATS_TAG(197) and HTT_STATS_PDEV_RTT_TBR_CMD_RESULT_STATS_TAG(198), currently. Sample output: echo 65 > /sys/kernel/debug/ath12k/pci-0000\:58\:00.0/mac0/htt_stats_type cat /sys/kernel/debug/ath12k/pci-0000\:58\:00.0/mac0/htt_stats HTT_PDEV_RTT_RESP_STATS_TLV: pdev_id = 0 tx_11mc_ftm_suc = 0 tx_11mc_ftm_suc_retry = 0 tx_11mc_ftm_fail = 0 ..... HTT_STATS_PDEV_RTT_HW_STATS_TAG: ista_ranging_ndpa_cnt = 0 ista_ranging_ndp_cnt = 0 ista_ranging_i2r_lmr_cnt = 0 rtsa_ranging_resp_cnt = 0 ..... HTT_STATS_PDEV_RTT_TBR_SELFGEN_QUEUED_STATS_TAG: SU poll = 0 SU sound = 0 ..... MU poll = 0 MU sound = 0 ..... HTT_STATS_PDEV_RTT_TBR_CMD_RESULT_STATS_TAG: num_sch_cmd_status_0: SU frame_SGEN_TF_POLL = 0 SU frame_SGEN_TF_SOUND = 0 SU frame_SGEN_TBR_NDPA = 0 SU frame_SGEN_TBR_NDP = 0 SU frame_SGEN_TBR_LMR = 0 SU frame_SGEN_TF_REPORT = 0 MU frame_SGEN_TF_POLL = 0 ..... echo 66 > /sys/kernel/debug/ath12k/pci-0000\:58\:00.0/mac0/htt_stats_type cat /sys/kernel/debug/ath12k/pci-0000\:58\:00.0/mac0/htt_stats HTT_PDEV_RTT_INIT_STATS_TLV: pdev_id = 0 tx_11mc_ftmr_cnt = 0 tx_11mc_ftmr_fail = 0 tx_11mc_ftmr_suc_retry = 0 rx_11mc_ftm_cnt = 0 rx_11az_ftm_cnt = 0 ..... HTT_STATS_PDEV_RTT_HW_STATS_TAG: ista_ranging_ndpa_cnt = 0 ista_ranging_ndp_cnt = 0 ista_ranging_i2r_lmr_cnt = 0 rtsa_ranging_resp_cnt = 0 rtsa_ranging_ndp_cnt = 0 rsta_ranging_lmr_cnt = 0 ..... Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Signed-off-by: Maharaja Kennadyrajan Signed-off-by: Roopni Devanathan Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250617051136.264193-3-quic_rdevanat@quicinc.com [rename enum ath12k_htt_stats_txsend_ftype_t] Signed-off-by: Jeff Johnson --- .../wireless/ath/ath12k/debugfs_htt_stats.c | 420 ++++++++++++++++++ .../wireless/ath/ath12k/debugfs_htt_stats.h | 155 +++++++ 2 files changed, 575 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c index 004ee0688cd7..96c834b987db 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c @@ -5133,6 +5133,410 @@ ath12k_htt_print_mlo_ipc_stats_tlv(const void *tag_buf, u16 tag_len, stats_req->buf_len = len; } +static void +ath12k_htt_print_pdev_rtt_resp_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_stats_pdev_rtt_resp_stats_tlv *sbuf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf; + + if (tag_len < sizeof(*sbuf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_RTT_RESP_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "pdev_id = %u\n", + le32_to_cpu(sbuf->pdev_id)); + len += scnprintf(buf + len, buf_len - len, "tx_11mc_ftm_suc = %u\n", + le32_to_cpu(sbuf->tx_11mc_ftm_suc)); + len += scnprintf(buf + len, buf_len - len, "tx_11mc_ftm_suc_retry = %u\n", + le32_to_cpu(sbuf->tx_11mc_ftm_suc_retry)); + len += scnprintf(buf + len, buf_len - len, "tx_11mc_ftm_fail = %u\n", + le32_to_cpu(sbuf->tx_11mc_ftm_fail)); + len += scnprintf(buf + len, buf_len - len, "rx_11mc_ftmr_cnt = %u\n", + le32_to_cpu(sbuf->rx_11mc_ftmr_cnt)); + len += scnprintf(buf + len, buf_len - len, "rx_11mc_ftmr_dup_cnt = %u\n", + le32_to_cpu(sbuf->rx_11mc_ftmr_dup_cnt)); + len += scnprintf(buf + len, buf_len - len, "rx_11mc_iftmr_cnt = %u\n", + le32_to_cpu(sbuf->rx_11mc_iftmr_cnt)); + len += scnprintf(buf + len, buf_len - len, "rx_11mc_iftmr_dup_cnt = %u\n", + le32_to_cpu(sbuf->rx_11mc_iftmr_dup_cnt)); + len += scnprintf(buf + len, buf_len - len, + "ftmr_drop_11mc_resp_role_not_enabled_cnt = %u\n", + le32_to_cpu(sbuf->ftmr_drop_11mc_resp_role_not_enabled_cnt)); + len += scnprintf(buf + len, buf_len - len, "tx_11az_ftm_successful = %u\n", + le32_to_cpu(sbuf->tx_11az_ftm_successful)); + len += scnprintf(buf + len, buf_len - len, "tx_11az_ftm_failed = %u\n", + le32_to_cpu(sbuf->tx_11az_ftm_failed)); + len += scnprintf(buf + len, buf_len - len, "rx_11az_ftmr_cnt = %u\n", + le32_to_cpu(sbuf->rx_11az_ftmr_cnt)); + len += scnprintf(buf + len, buf_len - len, "rx_11az_ftmr_dup_cnt = %u\n", + le32_to_cpu(sbuf->rx_11az_ftmr_dup_cnt)); + len += scnprintf(buf + len, buf_len - len, "rx_11az_iftmr_dup_cnt = %u\n", + le32_to_cpu(sbuf->rx_11az_iftmr_dup_cnt)); + len += scnprintf(buf + len, buf_len - len, + "initiator_active_responder_rejected_cnt = %u\n", + le32_to_cpu(sbuf->initiator_active_responder_rejected_cnt)); + len += scnprintf(buf + len, buf_len - len, "malformed_ftmr = %u\n", + le32_to_cpu(sbuf->malformed_ftmr)); + len += scnprintf(buf + len, buf_len - len, + "ftmr_drop_ntb_resp_role_not_enabled_cnt = %u\n", + le32_to_cpu(sbuf->ftmr_drop_ntb_resp_role_not_enabled_cnt)); + len += scnprintf(buf + len, buf_len - len, + "ftmr_drop_tb_resp_role_not_enabled_cnt = %u\n", + le32_to_cpu(sbuf->ftmr_drop_tb_resp_role_not_enabled_cnt)); + len += scnprintf(buf + len, buf_len - len, "responder_alloc_cnt = %u\n", + le32_to_cpu(sbuf->responder_alloc_cnt)); + len += scnprintf(buf + len, buf_len - len, "responder_alloc_failure = %u\n", + le32_to_cpu(sbuf->responder_alloc_failure)); + len += scnprintf(buf + len, buf_len - len, "responder_terminate_cnt = %u\n", + le32_to_cpu(sbuf->responder_terminate_cnt)); + len += scnprintf(buf + len, buf_len - len, "active_rsta_open = %u\n", + le32_to_cpu(sbuf->active_rsta_open)); + len += scnprintf(buf + len, buf_len - len, "active_rsta_mac = %u\n", + le32_to_cpu(sbuf->active_rsta_mac)); + len += scnprintf(buf + len, buf_len - len, "active_rsta_mac_phy = %u\n", + le32_to_cpu(sbuf->active_rsta_mac_phy)); + len += scnprintf(buf + len, buf_len - len, "pn_check_failure_cnt = %u\n", + le32_to_cpu(sbuf->pn_check_failure_cnt)); + len += scnprintf(buf + len, buf_len - len, "num_assoc_ranging_peers = %u\n", + le32_to_cpu(sbuf->num_assoc_ranging_peers)); + len += scnprintf(buf + len, buf_len - len, "num_unassoc_ranging_peers = %u\n", + le32_to_cpu(sbuf->num_unassoc_ranging_peers)); + len += scnprintf(buf + len, buf_len - len, "pasn_m1_auth_recv_cnt = %u\n", + le32_to_cpu(sbuf->pasn_m1_auth_recv_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_m1_auth_drop_cnt = %u\n", + le32_to_cpu(sbuf->pasn_m1_auth_drop_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_m2_auth_recv_cnt = %u\n", + le32_to_cpu(sbuf->pasn_m2_auth_recv_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_m2_auth_tx_fail_cnt = %u\n", + le32_to_cpu(sbuf->pasn_m2_auth_tx_fail_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_m3_auth_recv_cnt = %u\n", + le32_to_cpu(sbuf->pasn_m3_auth_recv_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_m3_auth_drop_cnt = %u\n", + le32_to_cpu(sbuf->pasn_m3_auth_drop_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_peer_create_request_cnt = %u\n", + le32_to_cpu(sbuf->pasn_peer_create_request_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_peer_created_cnt = %u\n", + le32_to_cpu(sbuf->pasn_peer_created_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_peer_create_timeout_cnt = %u\n", + le32_to_cpu(sbuf->pasn_peer_create_timeout_cnt)); + len += scnprintf(buf + len, buf_len - len, + "sec_ranging_not_supported_mfp_not_setup = %u\n", + le32_to_cpu(sbuf->sec_ranging_not_supported_mfp_not_setup)); + len += scnprintf(buf + len, buf_len - len, + "non_sec_ranging_discarded_for_assoc_peer_with_mfpr_set = %u\n", + le32_to_cpu(sbuf->non_sec_ranging_discarded_for_assoc_peer)); + len += scnprintf(buf + len, buf_len - len, + "open_ranging_discarded_with_URNM_MFPR_set_for_pasn_peer = %u\n", + le32_to_cpu(sbuf->open_ranging_discarded_set_for_pasn_peer)); + len += scnprintf(buf + len, buf_len - len, + "unassoc_non_pasn_ranging_not_supported_with_URNM_MFPR = %u\n", + le32_to_cpu(sbuf->unassoc_non_pasn_ranging_not_supported)); + len += scnprintf(buf + len, buf_len - len, "invalid_ftm_request_params = %u\n", + le32_to_cpu(sbuf->invalid_ftm_request_params)); + len += scnprintf(buf + len, buf_len - len, + "requested_bw_format_not_supported = %u\n", + le32_to_cpu(sbuf->requested_bw_format_not_supported)); + len += scnprintf(buf + len, buf_len - len, + "ntb_unsec_unassoc_mode_ranging_peer_alloc_failed = %u\n", + le32_to_cpu(sbuf->ntb_unsec_unassoc_ranging_peer_alloc_failed)); + len += scnprintf(buf + len, buf_len - len, + "tb_unassoc_unsec_mode_pasn_peer_creation_failed = %u\n", + le32_to_cpu(sbuf->tb_unassoc_unsec_pasn_peer_creation_failed)); + len += scnprintf(buf + len, buf_len - len, + "num_ranging_sequences_processed = %u\n", + le32_to_cpu(sbuf->num_ranging_sequences_processed)); + len += scnprintf(buf + len, buf_len - len, "ndp_rx_cnt = %u\n", + le32_to_cpu(sbuf->ndp_rx_cnt)); + len += scnprintf(buf + len, buf_len - len, "num_req_bw_20_MHz = %u\n", + le32_to_cpu(sbuf->num_req_bw_20_mhz)); + len += scnprintf(buf + len, buf_len - len, "num_req_bw_40_MHz = %u\n", + le32_to_cpu(sbuf->num_req_bw_40_mhz)); + len += scnprintf(buf + len, buf_len - len, "num_req_bw_80_MHz = %u\n", + le32_to_cpu(sbuf->num_req_bw_80_mhz)); + len += scnprintf(buf + len, buf_len - len, "num_req_bw_160_MHz = %u\n", + le32_to_cpu(sbuf->num_req_bw_160_mhz)); + len += scnprintf(buf + len, buf_len - len, "ntb_tx_ndp = %u\n", + le32_to_cpu(sbuf->ntb_tx_ndp)); + len += scnprintf(buf + len, buf_len - len, "num_ntb_ranging_NDPAs_recv = %u\n", + le32_to_cpu(sbuf->num_ntb_ranging_ndpas_recv)); + len += scnprintf(buf + len, buf_len - len, "recv_lmr = %u\n", + le32_to_cpu(sbuf->recv_lmr)); + len += scnprintf(buf + len, buf_len - len, "invalid_ftmr_cnt = %u\n", + le32_to_cpu(sbuf->invalid_ftmr_cnt)); + len += scnprintf(buf + len, buf_len - len, "max_time_bw_meas_exp_cnt = %u\n\n", + le32_to_cpu(sbuf->max_time_bw_meas_exp_cnt)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_pdev_rtt_init_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_stats_pdev_rtt_init_stats_tlv *htt_stats_buf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf, i; + __le32 sch_fail; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_RTT_INIT_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "pdev_id = %u\n", + le32_to_cpu(htt_stats_buf->pdev_id)); + len += scnprintf(buf + len, buf_len - len, "tx_11mc_ftmr_cnt = %u\n", + le32_to_cpu(htt_stats_buf->tx_11mc_ftmr_cnt)); + len += scnprintf(buf + len, buf_len - len, "tx_11mc_ftmr_fail = %u\n", + le32_to_cpu(htt_stats_buf->tx_11mc_ftmr_fail)); + len += scnprintf(buf + len, buf_len - len, "tx_11mc_ftmr_suc_retry = %u\n", + le32_to_cpu(htt_stats_buf->tx_11mc_ftmr_suc_retry)); + len += scnprintf(buf + len, buf_len - len, "rx_11mc_ftm_cnt = %u\n", + le32_to_cpu(htt_stats_buf->rx_11mc_ftm_cnt)); + len += scnprintf(buf + len, buf_len - len, "rx_11az_ftm_cnt = %u\n", + le32_to_cpu(htt_stats_buf->rx_11az_ftm_cnt)); + len += scnprintf(buf + len, buf_len - len, "initiator_terminate_cnt = %u\n", + le32_to_cpu(htt_stats_buf->initiator_terminate_cnt)); + len += scnprintf(buf + len, buf_len - len, "tx_meas_req_count = %u\n", + le32_to_cpu(htt_stats_buf->tx_meas_req_count)); + len += scnprintf(buf + len, buf_len - len, "tx_11az_ftmr_start = %u\n", + le32_to_cpu(htt_stats_buf->tx_11az_ftmr_start)); + len += scnprintf(buf + len, buf_len - len, "tx_11az_ftmr_stop = %u\n", + le32_to_cpu(htt_stats_buf->tx_11az_ftmr_stop)); + len += scnprintf(buf + len, buf_len - len, "tx_11az_ftmr_fail = %u\n", + le32_to_cpu(htt_stats_buf->tx_11az_ftmr_fail)); + len += scnprintf(buf + len, buf_len - len, + "ftmr_tx_failed_null_11az_peer = %u\n", + le32_to_cpu(htt_stats_buf->ftmr_tx_failed_null_11az_peer)); + len += scnprintf(buf + len, buf_len - len, "ftmr_retry_timeout = %u\n", + le32_to_cpu(htt_stats_buf->ftmr_retry_timeout)); + len += scnprintf(buf + len, buf_len - len, "ftm_parse_failure = %u\n", + le32_to_cpu(htt_stats_buf->ftm_parse_failure)); + len += scnprintf(buf + len, buf_len - len, "incompatible_ftm_params = %u\n", + le32_to_cpu(htt_stats_buf->incompatible_ftm_params)); + len += scnprintf(buf + len, buf_len - len, + "ranging_negotiation_successful_cnt = %u\n", + le32_to_cpu(htt_stats_buf->ranging_negotiation_successful_cnt)); + len += scnprintf(buf + len, buf_len - len, "active_ista = %u\n", + le32_to_cpu(htt_stats_buf->active_ista)); + len += scnprintf(buf + len, buf_len - len, "init_role_not_enabled = %u\n", + le32_to_cpu(htt_stats_buf->init_role_not_enabled)); + len += scnprintf(buf + len, buf_len - len, "invalid_preamble = %u\n", + le32_to_cpu(htt_stats_buf->invalid_preamble)); + len += scnprintf(buf + len, buf_len - len, "invalid_chan_bw_format = %u\n", + le32_to_cpu(htt_stats_buf->invalid_chan_bw_format)); + len += scnprintf(buf + len, buf_len - len, "mgmt_buff_alloc_fail_cnt = %u\n", + le32_to_cpu(htt_stats_buf->mgmt_buff_alloc_fail_cnt)); + len += scnprintf(buf + len, buf_len - len, "sec_ranging_req_in_open_mode = %u\n", + le32_to_cpu(htt_stats_buf->sec_ranging_req_in_open_mode)); + len += scnprintf(buf + len, buf_len - len, "max_time_bw_meas_exp_cnt = %u\n", + le32_to_cpu(htt_stats_buf->max_time_bw_meas_exp_cnt)); + len += scnprintf(buf + len, buf_len - len, "num_tb_ranging_requests = %u\n", + le32_to_cpu(htt_stats_buf->num_tb_ranging_requests)); + len += scnprintf(buf + len, buf_len - len, "tb_meas_duration_expiry_cnt = %u\n", + le32_to_cpu(htt_stats_buf->tb_meas_duration_expiry_cnt)); + len += scnprintf(buf + len, buf_len - len, "ntbr_triggered_successfully = %u\n", + le32_to_cpu(htt_stats_buf->ntbr_triggered_successfully)); + len += scnprintf(buf + len, buf_len - len, "ntbr_trigger_failed = %u\n", + le32_to_cpu(htt_stats_buf->ntbr_trigger_failed)); + len += scnprintf(buf + len, buf_len - len, "invalid_or_no_vreg_idx = %u\n", + le32_to_cpu(htt_stats_buf->invalid_or_no_vreg_idx)); + len += scnprintf(buf + len, buf_len - len, "set_vreg_params_failed = %u\n", + le32_to_cpu(htt_stats_buf->set_vreg_params_failed)); + len += scnprintf(buf + len, buf_len - len, "sac_mismatch = %u\n", + le32_to_cpu(htt_stats_buf->sac_mismatch)); + len += scnprintf(buf + len, buf_len - len, "pasn_m1_auth_recv_cnt = %u\n", + le32_to_cpu(htt_stats_buf->pasn_m1_auth_recv_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_m1_auth_tx_fail_cnt = %u\n", + le32_to_cpu(htt_stats_buf->pasn_m1_auth_tx_fail_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_m2_auth_recv_cnt = %u\n", + le32_to_cpu(htt_stats_buf->pasn_m2_auth_recv_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_m2_auth_drop_cnt = %u\n", + le32_to_cpu(htt_stats_buf->pasn_m2_auth_drop_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_m3_auth_recv_cnt = %u\n", + le32_to_cpu(htt_stats_buf->pasn_m3_auth_recv_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_m3_auth_tx_fail_cnt = %u\n", + le32_to_cpu(htt_stats_buf->pasn_m3_auth_tx_fail_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_peer_create_request_cnt = %u\n", + le32_to_cpu(htt_stats_buf->pasn_peer_create_request_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_peer_created_cnt = %u\n", + le32_to_cpu(htt_stats_buf->pasn_peer_created_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_peer_create_timeout_cnt = %u\n", + le32_to_cpu(htt_stats_buf->pasn_peer_create_timeout_cnt)); + len += scnprintf(buf + len, buf_len - len, "ntbr_ndpa_failed = %u\n", + le32_to_cpu(htt_stats_buf->ntbr_ndpa_failed)); + len += scnprintf(buf + len, buf_len - len, "ntbr_sequence_successful = %u\n", + le32_to_cpu(htt_stats_buf->ntbr_sequence_successful)); + len += scnprintf(buf + len, buf_len - len, "ntbr_ndp_failed = %u\n", + le32_to_cpu(htt_stats_buf->ntbr_ndp_failed)); + len += scnprintf(buf + len, buf_len - len, "num_tb_ranging_NDPAs_recv = %u\n", + le32_to_cpu(htt_stats_buf->num_tb_ranging_ndpas_recv)); + len += scnprintf(buf + len, buf_len - len, "ndp_rx_cnt = %u\n", + le32_to_cpu(htt_stats_buf->ndp_rx_cnt)); + len += scnprintf(buf + len, buf_len - len, "num_trigger_frames_received = %u\n", + le32_to_cpu(htt_stats_buf->num_trigger_frames_received)); + for (i = 0; i < (ATH12K_HTT_SCH_CMD_STATUS_CNT - 1); i++) + len += scnprintf(buf + len, buf_len - len, + "num_sch_cmd_status_%d = %u\n", i, + le32_to_cpu(htt_stats_buf->sch_cmd_status_cnts[i])); + sch_fail = htt_stats_buf->sch_cmd_status_cnts[ATH12K_HTT_SCH_CMD_STATUS_CNT - 1]; + len += scnprintf(buf + len, buf_len - len, + "num_sch_cmd_status_other_failure = %u\n", + le32_to_cpu(sch_fail)); + len += scnprintf(buf + len, buf_len - len, "lmr_timeout = %u\n", + le32_to_cpu(htt_stats_buf->lmr_timeout)); + len += scnprintf(buf + len, buf_len - len, "lmr_recv = %u\n\n", + le32_to_cpu(htt_stats_buf->lmr_recv)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_pdev_rtt_hw_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_stats_pdev_rtt_hw_stats_tlv *htt_stats_buf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_STATS_PDEV_RTT_HW_STATS_TAG:\n"); + len += scnprintf(buf + len, buf_len - len, "ista_ranging_ndpa_cnt = %u\n", + le32_to_cpu(htt_stats_buf->ista_ranging_ndpa_cnt)); + len += scnprintf(buf + len, buf_len - len, "ista_ranging_ndp_cnt = %u\n", + le32_to_cpu(htt_stats_buf->ista_ranging_ndp_cnt)); + len += scnprintf(buf + len, buf_len - len, "ista_ranging_i2r_lmr_cnt = %u\n", + le32_to_cpu(htt_stats_buf->ista_ranging_i2r_lmr_cnt)); + len += scnprintf(buf + len, buf_len - len, "rtsa_ranging_resp_cnt = %u\n", + le32_to_cpu(htt_stats_buf->rtsa_ranging_resp_cnt)); + len += scnprintf(buf + len, buf_len - len, "rtsa_ranging_ndp_cnt = %u\n", + le32_to_cpu(htt_stats_buf->rtsa_ranging_ndp_cnt)); + len += scnprintf(buf + len, buf_len - len, "rsta_ranging_lmr_cnt = %u\n", + le32_to_cpu(htt_stats_buf->rsta_ranging_lmr_cnt)); + len += scnprintf(buf + len, buf_len - len, "tb_ranging_cts2s_rcvd_cnt = %u\n", + le32_to_cpu(htt_stats_buf->tb_ranging_cts2s_rcvd_cnt)); + len += scnprintf(buf + len, buf_len - len, "tb_ranging_ndp_rcvd_cnt = %u\n", + le32_to_cpu(htt_stats_buf->tb_ranging_ndp_rcvd_cnt)); + len += scnprintf(buf + len, buf_len - len, "tb_ranging_lmr_rcvd_cnt = %u\n", + le32_to_cpu(htt_stats_buf->tb_ranging_lmr_rcvd_cnt)); + len += scnprintf(buf + len, buf_len - len, + "tb_ranging_tf_poll_resp_sent_cnt = %u\n", + le32_to_cpu(htt_stats_buf->tb_ranging_tf_poll_resp_sent_cnt)); + len += scnprintf(buf + len, buf_len - len, + "tb_ranging_tf_sound_resp_sent_cnt = %u\n", + le32_to_cpu(htt_stats_buf->tb_ranging_tf_sound_resp_sent_cnt)); + len += scnprintf(buf + len, buf_len - len, + "tb_ranging_tf_report_resp_sent_cnt = %u\n\n", + le32_to_cpu(htt_stats_buf->tb_ranging_tf_report_resp_sent_cnt)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_pdev_rtt_tbr_selfgen_queued_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *req) +{ + const struct ath12k_htt_stats_pdev_rtt_tbr_tlv *sbuf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = req->buf_len; + u8 *buf = req->buf; + + if (tag_len < sizeof(*sbuf)) + return; + + len += scnprintf(buf + len, buf_len - len, + "HTT_STATS_PDEV_RTT_TBR_SELFGEN_QUEUED_STATS_TAG:\n"); + len += scnprintf(buf + len, buf_len - len, "SU poll = %u\n", + le32_to_cpu(sbuf->su_ftype[ATH12K_HTT_FTYPE_TF_POLL])); + len += scnprintf(buf + len, buf_len - len, "SU sound = %u\n", + le32_to_cpu(sbuf->su_ftype[ATH12K_HTT_FTYPE_TF_SOUND])); + len += scnprintf(buf + len, buf_len - len, "SU NDPA = %u\n", + le32_to_cpu(sbuf->su_ftype[ATH12K_HTT_FTYPE_TBR_NDPA])); + len += scnprintf(buf + len, buf_len - len, "SU NDP = %u\n", + le32_to_cpu(sbuf->su_ftype[ATH12K_HTT_FTYPE_TBR_NDP])); + len += scnprintf(buf + len, buf_len - len, "SU LMR = %u\n", + le32_to_cpu(sbuf->su_ftype[ATH12K_HTT_FTYPE_TBR_LMR])); + len += scnprintf(buf + len, buf_len - len, "SU TF_REPORT = %u\n", + le32_to_cpu(sbuf->su_ftype[ATH12K_HTT_FTYPE_TF_RPRT])); + len += scnprintf(buf + len, buf_len - len, "MU poll = %u\n", + le32_to_cpu(sbuf->mu_ftype[ATH12K_HTT_FTYPE_TF_POLL])); + len += scnprintf(buf + len, buf_len - len, "MU sound = %u\n", + le32_to_cpu(sbuf->mu_ftype[ATH12K_HTT_FTYPE_TF_SOUND])); + len += scnprintf(buf + len, buf_len - len, "MU NDPA = %u\n", + le32_to_cpu(sbuf->mu_ftype[ATH12K_HTT_FTYPE_TBR_NDPA])); + len += scnprintf(buf + len, buf_len - len, "MU NDP = %u\n", + le32_to_cpu(sbuf->mu_ftype[ATH12K_HTT_FTYPE_TBR_NDP])); + len += scnprintf(buf + len, buf_len - len, "MU LMR = %u\n", + le32_to_cpu(sbuf->mu_ftype[ATH12K_HTT_FTYPE_TBR_LMR])); + len += scnprintf(buf + len, buf_len - len, "MU TF_REPORT = %u\n\n", + le32_to_cpu(sbuf->mu_ftype[ATH12K_HTT_FTYPE_TF_RPRT])); + + req->buf_len = len; +} + +static void +ath12k_htt_print_pdev_rtt_tbr_cmd_res_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_stats_pdev_rtt_tbr_cmd_result_stats_tlv *sbuf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf, i; + + if (tag_len < sizeof(*sbuf)) + return; + + len += scnprintf(buf + len, buf_len - len, + "HTT_STATS_PDEV_RTT_TBR_CMD_RESULT_STATS_TAG:\n"); + for (i = 0; i < le32_to_cpu(sbuf->tbr_num_sch_cmd_result_buckets); i++) { + len += scnprintf(buf + len, buf_len - len, "num_sch_cmd_status_%u:\n", i); + len += scnprintf(buf + len, buf_len - len, + "SU frame_SGEN_TF_POLL = %u\n", + le32_to_cpu(sbuf->su_res[ATH12K_HTT_FTYPE_TF_POLL][i])); + len += scnprintf(buf + len, buf_len - len, + "SU frame_SGEN_TF_SOUND = %u\n", + le32_to_cpu(sbuf->su_res[ATH12K_HTT_FTYPE_TF_SOUND][i])); + len += scnprintf(buf + len, buf_len - len, + "SU frame_SGEN_TBR_NDPA = %u\n", + le32_to_cpu(sbuf->su_res[ATH12K_HTT_FTYPE_TBR_NDPA][i])); + len += scnprintf(buf + len, buf_len - len, + "SU frame_SGEN_TBR_NDP = %u\n", + le32_to_cpu(sbuf->su_res[ATH12K_HTT_FTYPE_TBR_NDP][i])); + len += scnprintf(buf + len, buf_len - len, + "SU frame_SGEN_TBR_LMR = %u\n", + le32_to_cpu(sbuf->su_res[ATH12K_HTT_FTYPE_TBR_LMR][i])); + len += scnprintf(buf + len, buf_len - len, + "SU frame_SGEN_TF_REPORT = %u\n", + le32_to_cpu(sbuf->su_res[ATH12K_HTT_FTYPE_TF_RPRT][i])); + len += scnprintf(buf + len, buf_len - len, + "MU frame_SGEN_TF_POLL = %u\n", + le32_to_cpu(sbuf->mu_res[ATH12K_HTT_FTYPE_TF_POLL][i])); + len += scnprintf(buf + len, buf_len - len, + "MU frame_SGEN_TF_SOUND = %u\n", + le32_to_cpu(sbuf->mu_res[ATH12K_HTT_FTYPE_TF_SOUND][i])); + len += scnprintf(buf + len, buf_len - len, + "MU frame_SGEN_TBR_NDPA = %u\n", + le32_to_cpu(sbuf->mu_res[ATH12K_HTT_FTYPE_TBR_NDPA][i])); + len += scnprintf(buf + len, buf_len - len, + "MU frame_SGEN_TBR_NDP = %u\n", + le32_to_cpu(sbuf->mu_res[ATH12K_HTT_FTYPE_TBR_NDP][i])); + len += scnprintf(buf + len, buf_len - len, + "MU frame_SGEN_TBR_LMR = %u\n", + le32_to_cpu(sbuf->mu_res[ATH12K_HTT_FTYPE_TBR_LMR][i])); + len += scnprintf(buf + len, buf_len - len, + "MU frame_SGEN_TF_REPORT = %u\n\n", + le32_to_cpu(sbuf->mu_res[ATH12K_HTT_FTYPE_TF_RPRT][i])); + } + + stats_req->buf_len = len; +} + static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab, u16 tag, u16 len, const void *tag_buf, void *user_data) @@ -5413,6 +5817,22 @@ static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab, case HTT_STATS_PDEV_MLO_IPC_STATS_TAG: ath12k_htt_print_mlo_ipc_stats_tlv(tag_buf, len, stats_req); break; + case HTT_STATS_PDEV_RTT_RESP_STATS_TAG: + ath12k_htt_print_pdev_rtt_resp_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_PDEV_RTT_INIT_STATS_TAG: + ath12k_htt_print_pdev_rtt_init_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_PDEV_RTT_HW_STATS_TAG: + ath12k_htt_print_pdev_rtt_hw_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_PDEV_RTT_TBR_SELFGEN_QUEUED_STATS_TAG: + ath12k_htt_print_pdev_rtt_tbr_selfgen_queued_stats_tlv(tag_buf, len, + stats_req); + break; + case HTT_STATS_PDEV_RTT_TBR_CMD_RESULT_STATS_TAG: + ath12k_htt_print_pdev_rtt_tbr_cmd_res_stats_tlv(tag_buf, len, stats_req); + break; default: break; } diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h index e301958bfddd..13fbfb069ead 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h @@ -158,6 +158,8 @@ enum ath12k_dbg_htt_ext_stats_type { ATH12K_DBG_HTT_PDEV_TDMA_STATS = 57, ATH12K_DBG_HTT_MLO_SCHED_STATS = 63, ATH12K_DBG_HTT_PDEV_MLO_IPC_STATS = 64, + ATH12K_DBG_HTT_EXT_PDEV_RTT_RESP_STATS = 65, + ATH12K_DBG_HTT_EXT_PDEV_RTT_INITIATOR_STATS = 66, /* keep this last */ ATH12K_DBG_HTT_NUM_EXT_STATS, @@ -254,6 +256,11 @@ enum ath12k_dbg_htt_tlv_tag { HTT_STATS_PDEV_TDMA_TAG = 187, HTT_STATS_MLO_SCHED_STATS_TAG = 190, HTT_STATS_PDEV_MLO_IPC_STATS_TAG = 191, + HTT_STATS_PDEV_RTT_RESP_STATS_TAG = 194, + HTT_STATS_PDEV_RTT_INIT_STATS_TAG = 195, + HTT_STATS_PDEV_RTT_HW_STATS_TAG = 196, + HTT_STATS_PDEV_RTT_TBR_SELFGEN_QUEUED_STATS_TAG = 197, + HTT_STATS_PDEV_RTT_TBR_CMD_RESULT_STATS_TAG = 198, HTT_STATS_MAX_TAG, }; @@ -1918,4 +1925,152 @@ struct ath12k_htt_pdev_mlo_ipc_stats_tlv { __le32 mlo_ipc_ring_cnt[ATH12K_HTT_HWMLO_MAX_LINKS][ATH12K_HTT_MLO_MAX_IPC_RINGS]; } __packed; +struct ath12k_htt_stats_pdev_rtt_resp_stats_tlv { + __le32 pdev_id; + __le32 tx_11mc_ftm_suc; + __le32 tx_11mc_ftm_suc_retry; + __le32 tx_11mc_ftm_fail; + __le32 rx_11mc_ftmr_cnt; + __le32 rx_11mc_ftmr_dup_cnt; + __le32 rx_11mc_iftmr_cnt; + __le32 rx_11mc_iftmr_dup_cnt; + __le32 ftmr_drop_11mc_resp_role_not_enabled_cnt; + __le32 initiator_active_responder_rejected_cnt; + __le32 responder_terminate_cnt; + __le32 active_rsta_open; + __le32 active_rsta_mac; + __le32 active_rsta_mac_phy; + __le32 num_assoc_ranging_peers; + __le32 num_unassoc_ranging_peers; + __le32 responder_alloc_cnt; + __le32 responder_alloc_failure; + __le32 pn_check_failure_cnt; + __le32 pasn_m1_auth_recv_cnt; + __le32 pasn_m1_auth_drop_cnt; + __le32 pasn_m2_auth_recv_cnt; + __le32 pasn_m2_auth_tx_fail_cnt; + __le32 pasn_m3_auth_recv_cnt; + __le32 pasn_m3_auth_drop_cnt; + __le32 pasn_peer_create_request_cnt; + __le32 pasn_peer_create_timeout_cnt; + __le32 pasn_peer_created_cnt; + __le32 sec_ranging_not_supported_mfp_not_setup; + __le32 non_sec_ranging_discarded_for_assoc_peer; + __le32 open_ranging_discarded_set_for_pasn_peer; + __le32 unassoc_non_pasn_ranging_not_supported; + __le32 num_req_bw_20_mhz; + __le32 num_req_bw_40_mhz; + __le32 num_req_bw_80_mhz; + __le32 num_req_bw_160_mhz; + __le32 tx_11az_ftm_successful; + __le32 tx_11az_ftm_failed; + __le32 rx_11az_ftmr_cnt; + __le32 rx_11az_ftmr_dup_cnt; + __le32 rx_11az_iftmr_dup_cnt; + __le32 malformed_ftmr; + __le32 ftmr_drop_ntb_resp_role_not_enabled_cnt; + __le32 ftmr_drop_tb_resp_role_not_enabled_cnt; + __le32 invalid_ftm_request_params; + __le32 requested_bw_format_not_supported; + __le32 ntb_unsec_unassoc_ranging_peer_alloc_failed; + __le32 tb_unassoc_unsec_pasn_peer_creation_failed; + __le32 num_ranging_sequences_processed; + __le32 ntb_tx_ndp; + __le32 ndp_rx_cnt; + __le32 num_ntb_ranging_ndpas_recv; + __le32 recv_lmr; + __le32 invalid_ftmr_cnt; + __le32 max_time_bw_meas_exp_cnt; +} __packed; + +#define ATH12K_HTT_MAX_SCH_CMD_RESULT 25 +#define ATH12K_HTT_SCH_CMD_STATUS_CNT 9 + +struct ath12k_htt_stats_pdev_rtt_init_stats_tlv { + __le32 pdev_id; + __le32 tx_11mc_ftmr_cnt; + __le32 tx_11mc_ftmr_fail; + __le32 tx_11mc_ftmr_suc_retry; + __le32 rx_11mc_ftm_cnt; + __le32 tx_meas_req_count; + __le32 init_role_not_enabled; + __le32 initiator_terminate_cnt; + __le32 tx_11az_ftmr_fail; + __le32 tx_11az_ftmr_start; + __le32 tx_11az_ftmr_stop; + __le32 rx_11az_ftm_cnt; + __le32 active_ista; + __le32 invalid_preamble; + __le32 invalid_chan_bw_format; + __le32 mgmt_buff_alloc_fail_cnt; + __le32 ftm_parse_failure; + __le32 ranging_negotiation_successful_cnt; + __le32 incompatible_ftm_params; + __le32 sec_ranging_req_in_open_mode; + __le32 ftmr_tx_failed_null_11az_peer; + __le32 ftmr_retry_timeout; + __le32 max_time_bw_meas_exp_cnt; + __le32 tb_meas_duration_expiry_cnt; + __le32 num_tb_ranging_requests; + __le32 ntbr_triggered_successfully; + __le32 ntbr_trigger_failed; + __le32 invalid_or_no_vreg_idx; + __le32 set_vreg_params_failed; + __le32 sac_mismatch; + __le32 pasn_m1_auth_recv_cnt; + __le32 pasn_m1_auth_tx_fail_cnt; + __le32 pasn_m2_auth_recv_cnt; + __le32 pasn_m2_auth_drop_cnt; + __le32 pasn_m3_auth_recv_cnt; + __le32 pasn_m3_auth_tx_fail_cnt; + __le32 pasn_peer_create_request_cnt; + __le32 pasn_peer_create_timeout_cnt; + __le32 pasn_peer_created_cnt; + __le32 ntbr_ndpa_failed; + __le32 ntbr_sequence_successful; + __le32 ntbr_ndp_failed; + __le32 sch_cmd_status_cnts[ATH12K_HTT_SCH_CMD_STATUS_CNT]; + __le32 lmr_timeout; + __le32 lmr_recv; + __le32 num_trigger_frames_received; + __le32 num_tb_ranging_ndpas_recv; + __le32 ndp_rx_cnt; +} __packed; + +struct ath12k_htt_stats_pdev_rtt_hw_stats_tlv { + __le32 ista_ranging_ndpa_cnt; + __le32 ista_ranging_ndp_cnt; + __le32 ista_ranging_i2r_lmr_cnt; + __le32 rtsa_ranging_resp_cnt; + __le32 rtsa_ranging_ndp_cnt; + __le32 rsta_ranging_lmr_cnt; + __le32 tb_ranging_cts2s_rcvd_cnt; + __le32 tb_ranging_ndp_rcvd_cnt; + __le32 tb_ranging_lmr_rcvd_cnt; + __le32 tb_ranging_tf_poll_resp_sent_cnt; + __le32 tb_ranging_tf_sound_resp_sent_cnt; + __le32 tb_ranging_tf_report_resp_sent_cnt; +} __packed; + +enum ath12k_htt_stats_txsend_ftype { + ATH12K_HTT_FTYPE_TF_POLL, + ATH12K_HTT_FTYPE_TF_SOUND, + ATH12K_HTT_FTYPE_TBR_NDPA, + ATH12K_HTT_FTYPE_TBR_NDP, + ATH12K_HTT_FTYPE_TBR_LMR, + ATH12K_HTT_FTYPE_TF_RPRT, + ATH12K_HTT_FTYPE_MAX +}; + +struct ath12k_htt_stats_pdev_rtt_tbr_tlv { + __le32 su_ftype[ATH12K_HTT_FTYPE_MAX]; + __le32 mu_ftype[ATH12K_HTT_FTYPE_MAX]; +} __packed; + +struct ath12k_htt_stats_pdev_rtt_tbr_cmd_result_stats_tlv { + __le32 tbr_num_sch_cmd_result_buckets; + __le32 su_res[ATH12K_HTT_FTYPE_MAX][ATH12K_HTT_MAX_SCH_CMD_RESULT]; + __le32 mu_res[ATH12K_HTT_FTYPE_MAX][ATH12K_HTT_MAX_SCH_CMD_RESULT]; +} __packed; + #endif From ed259ae54de6d7daa778dcb3471c00367d32c11c Mon Sep 17 00:00:00 2001 From: Sumanth Gavini Date: Tue, 20 May 2025 22:33:21 -0700 Subject: [PATCH 029/199] wifi: wil6210: wmi: Fix spellings reported by codespell Fix "busses" to "buses" Fix "Measurments" to "Measurements" Signed-off-by: Sumanth Gavini Link: https://patch.msgid.link/20250521053323.284845-1-sumanth.gavini@yahoo.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/wil6210/wmi.c | 2 +- drivers/net/wireless/ath/wil6210/wmi.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 74edd007cd8d..6d376f85fbde 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -53,7 +53,7 @@ MODULE_PARM_DESC(led_id, * * There are several buses present on the WIL6210 card. * Same memory areas are visible at different address on - * the different busses. There are 3 main bus masters: + * the different buses. There are 3 main bus masters: * - MAC CPU (ucode) * - User CPU (firmware) * - AHB (host) diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 38f64524019e..a6761a1e9d7d 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -3495,7 +3495,7 @@ struct wmi_aoa_meas_event { u8 channel; /* enum wmi_aoa_meas_type */ u8 aoa_meas_type; - /* Measurments are from RFs, defined by the mask */ + /* Measurements are from RFs, defined by the mask */ __le32 meas_rf_mask; /* enum wmi_aoa_meas_status */ u8 meas_status; @@ -3634,7 +3634,7 @@ struct wmi_tof_ftm_per_dest_res_event { __le32 tsf_sync; /* actual received ftm per burst */ u8 actual_ftm_per_burst; - /* Measurments are from RFs, defined by the mask */ + /* Measurements are from RFs, defined by the mask */ __le32 meas_rf_mask; u8 reserved0[3]; struct wmi_responder_ftm_res responder_ftm_res[]; From 20870fb0a3001fa99f2684dafb200c2ae6b8aae7 Mon Sep 17 00:00:00 2001 From: Sumanth Gavini Date: Tue, 20 May 2025 22:54:09 -0700 Subject: [PATCH 030/199] wifi: ath10k: Fix Spelling Fix "trasmitting" to "transmitting" Signed-off-by: Sumanth Gavini Link: https://patch.msgid.link/20250521055411.288724-1-sumanth.gavini@yahoo.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath10k/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 446dca74f06a..5fab10f55c5d 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -779,7 +779,7 @@ enum ath10k_fw_features { /* Firmware supports bypassing PLL setting on init. */ ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT = 9, - /* Raw mode support. If supported, FW supports receiving and trasmitting + /* Raw mode support. If supported, FW supports receiving and transmitting * frames in raw mode. */ ATH10K_FW_FEATURE_RAW_MODE_SUPPORT = 10, From cb6dcabdfd0e3b608969d1cab71d8658495f9c4f Mon Sep 17 00:00:00 2001 From: Sumanth Gavini Date: Thu, 22 May 2025 13:56:53 -0700 Subject: [PATCH 031/199] wifi: ath6kl: Fix spellings Fix misspelling reported by codespell. Signed-off-by: Sumanth Gavini Link: https://patch.msgid.link/20250522205701.393612-1-sumanth.gavini@yahoo.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath6kl/core.c | 2 +- drivers/net/wireless/ath/ath6kl/hif.c | 2 +- drivers/net/wireless/ath/ath6kl/htc.h | 6 +++--- drivers/net/wireless/ath/ath6kl/htc_mbox.c | 2 +- drivers/net/wireless/ath/ath6kl/htc_pipe.c | 2 +- drivers/net/wireless/ath/ath6kl/init.c | 4 ++-- drivers/net/wireless/ath/ath6kl/main.c | 2 +- drivers/net/wireless/ath/ath6kl/sdio.c | 2 +- drivers/net/wireless/ath/ath6kl/usb.c | 6 +++--- drivers/net/wireless/ath/ath6kl/wmi.c | 2 +- drivers/net/wireless/ath/ath6kl/wmi.h | 10 +++++----- 11 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index 4f0a7a185fc9..830350bda531 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -91,7 +91,7 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) /* * Turn on power to get hardware (target) version and leave power - * on delibrately as we will boot the hardware anyway within few + * on deliberately as we will boot the hardware anyway within few * seconds. */ ret = ath6kl_hif_power_on(ar); diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c index d1942537ea10..c693783bb9de 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.c +++ b/drivers/net/wireless/ath/ath6kl/hif.c @@ -513,7 +513,7 @@ static int proc_pending_irqs(struct ath6kl_device *dev, bool *done) out: /* * An optimization to bypass reading the IRQ status registers - * unecessarily which can re-wake the target, if upper layers + * unnecessarily which can re-wake the target, if upper layers * determine that we are in a low-throughput mode, we can rely on * taking another interrupt rather than re-checking the status * registers which can re-wake the target. diff --git a/drivers/net/wireless/ath/ath6kl/htc.h b/drivers/net/wireless/ath/ath6kl/htc.h index d3534a29c4f0..d61be202677c 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.h +++ b/drivers/net/wireless/ath/ath6kl/htc.h @@ -485,7 +485,7 @@ struct htc_endpoint_stats { /* count of credits received via another endpoint */ u32 cred_from_ep0; - /* count of consummed credits */ + /* count of consumed credits */ u32 cred_cosumd; /* count of credits returned */ @@ -596,7 +596,7 @@ struct htc_target { /* protects free_ctrl_txbuf and free_ctrl_rxbuf */ spinlock_t htc_lock; - /* FIXME: does this protext rx_bufq and endpoint structures or what? */ + /* FIXME: does this protect rx_bufq and endpoint structures or what? */ spinlock_t rx_lock; /* protects endpoint->txq */ @@ -624,7 +624,7 @@ struct htc_target { int chk_irq_status_cnt; - /* counts the number of Tx without bundling continously per AC */ + /* counts the number of Tx without bundling continuously per AC */ u32 ac_tx_count[WMM_NUM_AC]; struct { diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c index f8a94d764be6..122e07ef3965 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c +++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c @@ -938,7 +938,7 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, /* * if an AC has bundling disabled and no tx bundling - * has occured continously for a certain number of TX, + * has occurred continuously for a certain number of TX, * enable tx bundling for this AC */ if (!bundle_sent) { diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index 2f2edfe43761..7b823be9d846 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c @@ -718,7 +718,7 @@ static struct htc_packet *htc_lookup_tx_packet(struct htc_target *target, spin_lock_bh(&target->tx_lock); /* - * interate from the front of tx lookup queue + * iterate from the front of tx lookup queue * this lookup should be fast since lower layers completes in-order and * so the completed packet should be at the head of the list generally */ diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 9b100ee2ebc3..782209dcb782 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -207,7 +207,7 @@ static const struct ath6kl_hw hw_list[] = { /* * This configuration item sets the value of disconnect timeout - * Firmware delays sending the disconnec event to the host for this + * Firmware delays sending the disconnect event to the host for this * timeout after is gets disconnected from the current AP. * If the firmware successly roams within the disconnect timeout * it sends a new connect event @@ -221,7 +221,7 @@ struct sk_buff *ath6kl_buf_alloc(int size) struct sk_buff *skb; u16 reserved; - /* Add chacheline space at front and back of buffer */ + /* Add cacheline space at front and back of buffer */ reserved = roundup((2 * L1_CACHE_BYTES) + ATH6KL_DATA_OFFSET + sizeof(struct htc_packet) + ATH6KL_HTC_ALIGN_BYTES, 4); skb = dev_alloc_skb(size + reserved); diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index d62b96459751..59068ea3879b 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -583,7 +583,7 @@ static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel) switch (vif->nw_type) { case AP_NETWORK: /* - * reconfigure any saved RSN IE capabilites in the beacon / + * reconfigure any saved RSN IE capabilities in the beacon / * probe response to stay in sync with the supplicant. */ if (vif->rsn_capab && diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 9ab091044706..83de40bc4445 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -486,7 +486,7 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func) ar_sdio = sdio_get_drvdata(func); atomic_set(&ar_sdio->irq_handling, 1); /* - * Release the host during interrups so we can pick it back up when + * Release the host during interrupts so we can pick it back up when * we process commands. */ sdio_release_host(ar_sdio->func); diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index 5220809841a6..38bb501fc553 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -93,7 +93,7 @@ struct ath6kl_urb_context { #define ATH6KL_USB_EP_ADDR_APP_DATA_MP_OUT 0x03 #define ATH6KL_USB_EP_ADDR_APP_DATA_HP_OUT 0x04 -/* diagnostic command defnitions */ +/* diagnostic command definitions */ #define ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD 1 #define ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP 2 #define ATH6KL_USB_CONTROL_REQ_DIAG_CMD 3 @@ -882,7 +882,7 @@ static int ath6kl_usb_submit_ctrl_out(struct ath6kl_usb *ar_usb, return -ENOMEM; } - /* note: if successful returns number of bytes transfered */ + /* note: if successful returns number of bytes transferred */ ret = usb_control_msg(ar_usb->udev, usb_sndctrlpipe(ar_usb->udev, 0), req, @@ -914,7 +914,7 @@ static int ath6kl_usb_submit_ctrl_in(struct ath6kl_usb *ar_usb, return -ENOMEM; } - /* note: if successful returns number of bytes transfered */ + /* note: if successful returns number of bytes transferred */ ret = usb_control_msg(ar_usb->udev, usb_rcvctrlpipe(ar_usb->udev, 0), req, diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 84317afe4651..08a154bce139 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -2601,7 +2601,7 @@ int ath6kl_wmi_create_pstream_cmd(struct wmi *wmi, u8 if_idx, } /* - * Indicate activty change to driver layer only if this is the + * Indicate activity change to driver layer only if this is the * first TSID to get created in this AC explicitly or an implicit * fat pipe is getting created. */ diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 68384159870b..3080d82e25cc 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -655,7 +655,7 @@ enum wmi_mgmt_frame_type { enum wmi_ie_field_type { WMI_RSN_IE_CAPB = 0x1, - WMI_IE_FULL = 0xFF, /* indicats full IE */ + WMI_IE_FULL = 0xFF, /* indicates full IE */ }; /* WMI_CONNECT_CMDID */ @@ -1178,10 +1178,10 @@ struct wmi_create_pstream_cmd { __le32 sba; __le32 medium_time; - /* in octects */ + /* in octets */ __le16 nominal_msdu; - /* in octects */ + /* in octets */ __le16 max_msdu; u8 traffic_class; @@ -1742,7 +1742,7 @@ struct wmi_scan_complete_event { /* * Special frame receive Event. - * Mechanism used to inform host of the receiption of the special frames. + * Mechanism used to inform host of the reception of the special frames. * Consists of special frame info header followed by special frame body. * The 802.11 header is not included. */ @@ -1860,7 +1860,7 @@ struct wmi_target_stats { /* * WMI_RSSI_THRESHOLD_EVENTID. * Indicate the RSSI events to host. Events are indicated when we breach a - * thresold value. + * threshold value. */ enum wmi_rssi_threshold_val { WMI_RSSI_THRESHOLD1_ABOVE = 0, From 6e17bbb5a86e6c68d65e38dfc850699e7a0706cb Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Thu, 26 Jun 2025 10:49:56 +0530 Subject: [PATCH 032/199] wifi: ath12k: fix timeout while waiting for regulatory update during interface creation During interface creation, following print is observed on the console - Timeout while waiting for regulatory update This occurs due to commit 906619a00967 ("wifi: ath12k: handle regulatory hints during mac registration"), which introduced a completion mechanism to synchronize the regulatory update process. The intent behind this change is to coordinate the timing between when the firmware sends regulatory data to the driver and when the driver processes that data. However, during interface addition, if the 6 GHz band is active, the driver invokes ath12k_regd_update() to apply the appropriate 6 GHz power mode regulatory settings. At this point, there is no interaction with the firmware, so the completion object is not reinitialized. As a result, wait_for_completion() eventually times out, leading to the observed error log message. Hence to fix this, move all complete() on regd_update_completed to complete_all(). The complete() function signals only once, causing any subsequent waits without reinitialization to timeout. In this scenario, since waiting is unnecessary, complete_all() can be used instead, ensuring that subsequent calls to wait without reinitialization will simply bail out and not actually wait. This approach is ideal because if the firmware is not involved, there is no need to wait for the completion event. However, if the firmware is involved, it is guaranteed that the completion will be reinitialized, and thus, it would wait. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.5-01651-QCAHKSWPL_SILICONZ-1 Tested-by: Kang Yang Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Fixes: 906619a00967 ("wifi: ath12k: handle regulatory hints during mac registration") Signed-off-by: Aditya Kumar Singh Link: https://patch.msgid.link/20250626-fix_timeout_during_interface_creation-v1-1-90a7fdc222d4@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.c | 2 +- drivers/net/wireless/ath/ath12k/mac.c | 2 +- drivers/net/wireless/ath/ath12k/wmi.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 83caba3104d6..ffc19a6b9485 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1475,7 +1475,7 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) complete(&ar->vdev_setup_done); complete(&ar->vdev_delete_done); complete(&ar->bss_survey_done); - complete(&ar->regd_update_completed); + complete_all(&ar->regd_update_completed); wake_up(&ar->dp.tx_empty_waitq); idr_for_each(&ar->txmgmt_idr, diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index f565db7b7b44..71e07c546a2d 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -12794,7 +12794,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) * proceeding with registration. */ for_each_ar(ah, ar, i) - complete(&ar->regd_update_completed); + complete_all(&ar->regd_update_completed); ret = ieee80211_register_hw(hw); if (ret) { diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index d6efbea2e724..6c6354b3e18e 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -6769,7 +6769,7 @@ out: * before registering the hardware. */ if (ar) - complete(&ar->regd_update_completed); + complete_all(&ar->regd_update_completed); return ret; } From c256a94d1b1b15109740306f7f2a7c2173e12072 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 23 Jun 2025 10:27:31 +0800 Subject: [PATCH 033/199] wifi: ath10k: shutdown driver when hardware is unreliable In rare cases, ath10k may lose connection with the PCIe bus due to some unknown reasons, which could further lead to system crashes during resuming due to watchdog timeout: ath10k_pci 0000:01:00.0: wmi command 20486 timeout, restarting hardware ath10k_pci 0000:01:00.0: already restarting ath10k_pci 0000:01:00.0: failed to stop WMI vdev 0: -11 ath10k_pci 0000:01:00.0: failed to stop vdev 0: -11 ieee80211 phy0: PM: **** DPM device timeout **** Call Trace: panic+0x125/0x315 dpm_watchdog_set+0x54/0x54 dpm_watchdog_handler+0x57/0x57 call_timer_fn+0x31/0x13c At this point, all WMI commands will timeout and attempt to restart device. So set a threshold for consecutive restart failures. If the threshold is exceeded, consider the hardware is unreliable and all ath10k operations should be skipped to avoid system crash. fail_cont_count and pending_recovery are atomic variables, and do not involve complex conditional logic. Therefore, even if recovery check and reconfig complete are executed concurrently, the recovery mechanism will not be broken. Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00288-QCARMSWPZ-1 Signed-off-by: Kang Yang Reviewed-by: Loic Poulain Link: https://patch.msgid.link/20250623022731.509-1-kang.yang@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath10k/core.c | 48 +++++++++++++++++++++++--- drivers/net/wireless/ath/ath10k/core.h | 11 ++++-- drivers/net/wireless/ath/ath10k/mac.c | 7 +++- drivers/net/wireless/ath/ath10k/wmi.c | 6 ++++ 4 files changed, 63 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index d31708eca3c8..9c6c07598b3a 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2493,12 +2493,50 @@ static int ath10k_init_hw_params(struct ath10k *ar) return 0; } +static bool ath10k_core_needs_recovery(struct ath10k *ar) +{ + long time_left; + + /* Sometimes the recovery will fail and then the next all recovery fail, + * so avoid infinite recovery. + */ + if (atomic_read(&ar->fail_cont_count) >= ATH10K_RECOVERY_MAX_FAIL_COUNT) { + ath10k_err(ar, "consecutive fail %d times, will shutdown driver!", + atomic_read(&ar->fail_cont_count)); + ar->state = ATH10K_STATE_WEDGED; + return false; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "total recovery count: %d", ++ar->recovery_count); + + if (atomic_read(&ar->pending_recovery)) { + /* Sometimes it happened another recovery work before the previous one + * completed, then the second recovery work will destroy the previous + * one, thus below is to avoid that. + */ + time_left = wait_for_completion_timeout(&ar->driver_recovery, + ATH10K_RECOVERY_TIMEOUT_HZ); + if (time_left) { + ath10k_warn(ar, "previous recovery succeeded, skip this!\n"); + return false; + } + + /* Record the continuous recovery fail count when recovery failed. */ + atomic_inc(&ar->fail_cont_count); + + /* Avoid having multiple recoveries at the same time. */ + return false; + } + + atomic_inc(&ar->pending_recovery); + + return true; +} + void ath10k_core_start_recovery(struct ath10k *ar) { - if (test_and_set_bit(ATH10K_FLAG_RESTARTING, &ar->dev_flags)) { - ath10k_warn(ar, "already restarting\n"); + if (!ath10k_core_needs_recovery(ar)) return; - } queue_work(ar->workqueue, &ar->restart_work); } @@ -2534,6 +2572,8 @@ static void ath10k_core_restart(struct work_struct *work) struct ath10k *ar = container_of(work, struct ath10k, restart_work); int ret; + reinit_completion(&ar->driver_recovery); + set_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags); /* Place a barrier to make sure the compiler doesn't reorder @@ -2598,8 +2638,6 @@ static void ath10k_core_restart(struct work_struct *work) if (ret) ath10k_warn(ar, "failed to send firmware crash dump via devcoredump: %d", ret); - - complete(&ar->driver_recovery); } static void ath10k_core_set_coverage_class_work(struct work_struct *work) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 5fab10f55c5d..8c72ed386edb 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -4,6 +4,7 @@ * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef _CORE_H_ @@ -87,6 +88,8 @@ IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER) #define ATH10K_ITER_RESUME_FLAGS (IEEE80211_IFACE_ITER_RESUME_ALL |\ IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER) +#define ATH10K_RECOVERY_TIMEOUT_HZ (5 * HZ) +#define ATH10K_RECOVERY_MAX_FAIL_COUNT 4 struct ath10k; @@ -865,9 +868,6 @@ enum ath10k_dev_flags { /* Per Station statistics service */ ATH10K_FLAG_PEER_STATS, - /* Indicates that ath10k device is during recovery process and not complete */ - ATH10K_FLAG_RESTARTING, - /* protected by conf_mutex */ ATH10K_FLAG_NAPI_ENABLED, }; @@ -1211,6 +1211,11 @@ struct ath10k { struct work_struct bundle_tx_work; struct work_struct tx_complete_work; + atomic_t pending_recovery; + unsigned int recovery_count; + /* continuous recovery fail count */ + atomic_t fail_cont_count; + /* cycle count is reported twice for each visited channel during scan. * access protected by data_lock */ diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 40843974d6f8..11569c18204c 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -8162,7 +8162,12 @@ static void ath10k_reconfig_complete(struct ieee80211_hw *hw, ath10k_info(ar, "device successfully recovered\n"); ar->state = ATH10K_STATE_ON; ieee80211_wake_queues(ar->hw); - clear_bit(ATH10K_FLAG_RESTARTING, &ar->dev_flags); + + /* Clear recovery state. */ + complete(&ar->driver_recovery); + atomic_set(&ar->fail_cont_count, 0); + atomic_set(&ar->pending_recovery, 0); + if (ar->hw_params.hw_restart_disconnect) { list_for_each_entry(arvif, &ar->arvifs, list) { if (arvif->is_up && arvif->vdev_type == WMI_VDEV_TYPE_STA) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index df6a24f8f8d5..cb8ae751eb31 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4,6 +4,7 @@ * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -1941,6 +1942,11 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id) } wait_event_timeout(ar->wmi.tx_credits_wq, ({ + if (ar->state == ATH10K_STATE_WEDGED) { + ret = -ESHUTDOWN; + ath10k_dbg(ar, ATH10K_DBG_WMI, + "drop wmi command %d, hardware is wedged\n", cmd_id); + } /* try to send pending beacons first. they take priority */ ath10k_wmi_tx_beacons_nowait(ar); From 5d6707e88e7fe2d603ad45c5fe7eba096be9533a Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Mon, 30 Jun 2025 18:04:00 -0700 Subject: [PATCH 034/199] wifi: ath12k: push HE MU-MIMO params to hardware Currently, only the HE IE in management frames is updated with respect to MU-MIMO configurations, but this change is not reflected in the hardware. Add support to propagate MU-MIMO configurations to the hardware as well. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Co-developed-by: Muna Sinada Signed-off-by: Muna Sinada Signed-off-by: Pradeep Kumar Chitrapu Acked-by: Jeff Johnson Link: https://patch.msgid.link/20250701010408.1257201-2-quic_pradeepc@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 228 +++++++++++++++++--------- drivers/net/wireless/ath/ath12k/mac.h | 15 ++ drivers/net/wireless/ath/ath12k/wmi.h | 28 +--- 3 files changed, 169 insertions(+), 102 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 71e07c546a2d..c81cecb01c06 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -3160,6 +3160,125 @@ static int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_link_vif *arv ath12k_smps_map[smps]); } +static int ath12k_mac_set_he_txbf_conf(struct ath12k_link_vif *arvif) +{ + struct ath12k_vif *ahvif = arvif->ahvif; + struct ath12k *ar = arvif->ar; + u32 param = WMI_VDEV_PARAM_SET_HEMU_MODE; + u32 value = 0; + int ret; + struct ieee80211_bss_conf *link_conf; + + link_conf = ath12k_mac_get_link_bss_conf(arvif); + if (!link_conf) { + ath12k_warn(ar->ab, "unable to access bss link conf in txbf conf\n"); + return -EINVAL; + } + + if (!link_conf->he_support) + return 0; + + if (link_conf->he_su_beamformer) { + value |= u32_encode_bits(HE_SU_BFER_ENABLE, HE_MODE_SU_TX_BFER); + if (link_conf->he_mu_beamformer && + ahvif->vdev_type == WMI_VDEV_TYPE_AP) + value |= u32_encode_bits(HE_MU_BFER_ENABLE, HE_MODE_MU_TX_BFER); + } + + if (ahvif->vif->type != NL80211_IFTYPE_MESH_POINT) { + value |= u32_encode_bits(HE_DL_MUOFDMA_ENABLE, HE_MODE_DL_OFDMA) | + u32_encode_bits(HE_UL_MUOFDMA_ENABLE, HE_MODE_UL_OFDMA); + + if (link_conf->he_full_ul_mumimo) + value |= u32_encode_bits(HE_UL_MUMIMO_ENABLE, HE_MODE_UL_MUMIMO); + + if (link_conf->he_su_beamformee) + value |= u32_encode_bits(HE_SU_BFEE_ENABLE, HE_MODE_SU_TX_BFEE); + } + + ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param, value); + if (ret) { + ath12k_warn(ar->ab, "failed to set vdev %d HE MU mode: %d\n", + arvif->vdev_id, ret); + return ret; + } + + param = WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE; + value = u32_encode_bits(HE_VHT_SOUNDING_MODE_ENABLE, HE_VHT_SOUNDING_MODE) | + u32_encode_bits(HE_TRIG_NONTRIG_SOUNDING_MODE_ENABLE, + HE_TRIG_NONTRIG_SOUNDING_MODE); + ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + param, value); + if (ret) { + ath12k_warn(ar->ab, "failed to set vdev %d sounding mode: %d\n", + arvif->vdev_id, ret); + return ret; + } + + return 0; +} + +static int ath12k_mac_vif_recalc_sta_he_txbf(struct ath12k *ar, + struct ath12k_link_vif *arvif, + struct ieee80211_sta_he_cap *he_cap, + int *hemode) +{ + struct ieee80211_vif *vif = arvif->ahvif->vif; + struct ieee80211_he_cap_elem he_cap_elem = {}; + struct ieee80211_sta_he_cap *cap_band; + struct cfg80211_chan_def def; + u8 link_id = arvif->link_id; + struct ieee80211_bss_conf *link_conf; + + link_conf = ath12k_mac_get_link_bss_conf(arvif); + if (!link_conf) { + ath12k_warn(ar->ab, "unable to access bss link conf in recalc txbf conf\n"); + return -EINVAL; + } + + if (!link_conf->he_support) + return 0; + + if (vif->type != NL80211_IFTYPE_STATION) + return -EINVAL; + + if (WARN_ON(ath12k_mac_vif_link_chan(vif, link_id, &def))) + return -EINVAL; + + if (def.chan->band == NL80211_BAND_2GHZ) + cap_band = &ar->mac.iftype[NL80211_BAND_2GHZ][vif->type].he_cap; + else + cap_band = &ar->mac.iftype[NL80211_BAND_5GHZ][vif->type].he_cap; + + memcpy(&he_cap_elem, &cap_band->he_cap_elem, sizeof(he_cap_elem)); + + *hemode = 0; + if (HECAP_PHY_SUBFME_GET(he_cap_elem.phy_cap_info)) { + if (HECAP_PHY_SUBFMR_GET(he_cap->he_cap_elem.phy_cap_info)) + *hemode |= u32_encode_bits(HE_SU_BFEE_ENABLE, HE_MODE_SU_TX_BFEE); + if (HECAP_PHY_MUBFMR_GET(he_cap->he_cap_elem.phy_cap_info)) + *hemode |= u32_encode_bits(HE_MU_BFEE_ENABLE, HE_MODE_MU_TX_BFEE); + } + + if (vif->type != NL80211_IFTYPE_MESH_POINT) { + *hemode |= u32_encode_bits(HE_DL_MUOFDMA_ENABLE, HE_MODE_DL_OFDMA) | + u32_encode_bits(HE_UL_MUOFDMA_ENABLE, HE_MODE_UL_OFDMA); + + if (HECAP_PHY_ULMUMIMO_GET(he_cap_elem.phy_cap_info)) + if (HECAP_PHY_ULMUMIMO_GET(he_cap->he_cap_elem.phy_cap_info)) + *hemode |= u32_encode_bits(HE_UL_MUMIMO_ENABLE, + HE_MODE_UL_MUMIMO); + + if (u32_get_bits(*hemode, HE_MODE_MU_TX_BFEE)) + *hemode |= u32_encode_bits(HE_SU_BFEE_ENABLE, HE_MODE_SU_TX_BFEE); + + if (u32_get_bits(*hemode, HE_MODE_MU_TX_BFER)) + *hemode |= u32_encode_bits(HE_SU_BFER_ENABLE, HE_MODE_SU_TX_BFER); + } + + return 0; +} + static u32 ath12k_mac_ieee80211_sta_bw_to_wmi(struct ath12k *ar, struct ieee80211_link_sta *link_sta) { @@ -3205,6 +3324,7 @@ static void ath12k_bss_assoc(struct ath12k *ar, struct ath12k_sta *ahsta; struct ath12k_peer *peer; bool is_auth = false; + u32 hemode = 0; int ret; lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); @@ -3248,8 +3368,26 @@ static void ath12k_bss_assoc(struct ath12k *ar, ath12k_peer_assoc_prepare(ar, arvif, arsta, peer_arg, false); + /* link_sta->he_cap must be protected by rcu_read_lock */ + ret = ath12k_mac_vif_recalc_sta_he_txbf(ar, arvif, &link_sta->he_cap, &hemode); + if (ret) { + ath12k_warn(ar->ab, "failed to recalc he txbf for vdev %i on bss %pM: %d\n", + arvif->vdev_id, bss_conf->bssid, ret); + rcu_read_unlock(); + return; + } + rcu_read_unlock(); + /* keep this before ath12k_wmi_send_peer_assoc_cmd() */ + ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + WMI_VDEV_PARAM_SET_HEMU_MODE, hemode); + if (ret) { + ath12k_warn(ar->ab, "failed to submit vdev param txbf 0x%x: %d\n", + hemode, ret); + return; + } + peer_arg->is_assoc = true; ret = ath12k_wmi_send_peer_assoc_cmd(ar, peer_arg); if (ret) { @@ -3874,6 +4012,13 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar, ether_addr_copy(arvif->bssid, info->bssid); if (changed & BSS_CHANGED_BEACON_ENABLED) { + if (info->enable_beacon) { + ret = ath12k_mac_set_he_txbf_conf(arvif); + if (ret) + ath12k_warn(ar->ab, + "failed to set HE TXBF config for vdev: %d\n", + arvif->vdev_id); + } ath12k_control_beaconing(arvif, info); if (arvif->is_up && info->he_support && @@ -7349,11 +7494,14 @@ static void ath12k_mac_copy_he_cap(struct ath12k_band_cap *band_cap, he_cap_elem->mac_cap_info[1] &= IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK; - + he_cap_elem->phy_cap_info[0] &= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; + he_cap_elem->phy_cap_info[0] &= + ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G; he_cap_elem->phy_cap_info[5] &= ~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK; - he_cap_elem->phy_cap_info[5] &= - ~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK; he_cap_elem->phy_cap_info[5] |= num_tx_chains - 1; switch (iftype) { @@ -8672,72 +8820,6 @@ static int ath12k_mac_setup_vdev_create_arg(struct ath12k_link_vif *arvif, return 0; } -static u32 -ath12k_mac_prepare_he_mode(struct ath12k_pdev *pdev, u32 viftype) -{ - struct ath12k_pdev_cap *pdev_cap = &pdev->cap; - struct ath12k_band_cap *cap_band = NULL; - u32 *hecap_phy_ptr = NULL; - u32 hemode; - - if (pdev->cap.supported_bands & WMI_HOST_WLAN_2GHZ_CAP) - cap_band = &pdev_cap->band[NL80211_BAND_2GHZ]; - else - cap_band = &pdev_cap->band[NL80211_BAND_5GHZ]; - - hecap_phy_ptr = &cap_band->he_cap_phy_info[0]; - - hemode = u32_encode_bits(HE_SU_BFEE_ENABLE, HE_MODE_SU_TX_BFEE) | - u32_encode_bits(HECAP_PHY_SUBFMR_GET(hecap_phy_ptr), - HE_MODE_SU_TX_BFER) | - u32_encode_bits(HECAP_PHY_ULMUMIMO_GET(hecap_phy_ptr), - HE_MODE_UL_MUMIMO); - - /* TODO: WDS and other modes */ - if (viftype == NL80211_IFTYPE_AP) { - hemode |= u32_encode_bits(HECAP_PHY_MUBFMR_GET(hecap_phy_ptr), - HE_MODE_MU_TX_BFER) | - u32_encode_bits(HE_DL_MUOFDMA_ENABLE, HE_MODE_DL_OFDMA) | - u32_encode_bits(HE_UL_MUOFDMA_ENABLE, HE_MODE_UL_OFDMA); - } else { - hemode |= u32_encode_bits(HE_MU_BFEE_ENABLE, HE_MODE_MU_TX_BFEE); - } - - return hemode; -} - -static int ath12k_set_he_mu_sounding_mode(struct ath12k *ar, - struct ath12k_link_vif *arvif) -{ - u32 param_id, param_value; - struct ath12k_base *ab = ar->ab; - struct ath12k_vif *ahvif = arvif->ahvif; - int ret; - - param_id = WMI_VDEV_PARAM_SET_HEMU_MODE; - param_value = ath12k_mac_prepare_he_mode(ar->pdev, ahvif->vif->type); - ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, - param_id, param_value); - if (ret) { - ath12k_warn(ab, "failed to set vdev %d HE MU mode: %d param_value %x\n", - arvif->vdev_id, ret, param_value); - return ret; - } - param_id = WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE; - param_value = - u32_encode_bits(HE_VHT_SOUNDING_MODE_ENABLE, HE_VHT_SOUNDING_MODE) | - u32_encode_bits(HE_TRIG_NONTRIG_SOUNDING_MODE_ENABLE, - HE_TRIG_NONTRIG_SOUNDING_MODE); - ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, - param_id, param_value); - if (ret) { - ath12k_warn(ab, "failed to set vdev %d HE MU mode: %d\n", - arvif->vdev_id, ret); - return ret; - } - return ret; -} - static void ath12k_mac_update_vif_offload(struct ath12k_link_vif *arvif) { struct ath12k_vif *ahvif = arvif->ahvif; @@ -9931,14 +10013,6 @@ ath12k_mac_vdev_start_restart(struct ath12k_link_vif *arvif, spin_unlock_bh(&ab->base_lock); /* TODO: Notify if secondary 80Mhz also needs radar detection */ - if (link_conf->he_support) { - ret = ath12k_set_he_mu_sounding_mode(ar, arvif); - if (ret) { - ath12k_warn(ar->ab, "failed to set he mode vdev %i\n", - arg.vdev_id); - return ret; - } - } } arg.passive |= !!(chandef->chan->flags & IEEE80211_CHAN_NO_IR); diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h index 473611bfccdc..9241afe7dc02 100644 --- a/drivers/net/wireless/ath/ath12k/mac.h +++ b/drivers/net/wireless/ath/ath12k/mac.h @@ -59,6 +59,21 @@ struct ath12k_generic_iter { #define ATH12K_NUM_MAX_ACTIVE_LINKS_PER_DEVICE 2 +#define HECAP_PHY_SUBFMR_GET(hecap_phy) \ + u8_get_bits(hecap_phy[3], IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER) + +#define HECAP_PHY_SUBFME_GET(hecap_phy) \ + u8_get_bits(hecap_phy[4], IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE) + +#define HECAP_PHY_MUBFMR_GET(hecap_phy) \ + u8_get_bits(hecap_phy[4], IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER) + +#define HECAP_PHY_ULMUMIMO_GET(hecap_phy) \ + u8_get_bits(hecap_phy[2], IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO) + +#define HECAP_PHY_ULOFDMA_GET(hecap_phy) \ + u8_get_bits(hecap_phy[2], IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO) + enum ath12k_supported_bw { ATH12K_BW_20 = 0, ATH12K_BW_40 = 1, diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index ccf430164717..07cba3997e75 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -3136,31 +3136,6 @@ struct ath12k_wmi_rx_reorder_queue_remove_arg { #define WMI_VDEV_PARAM_TXBF_SU_TX_BFER BIT(2) #define WMI_VDEV_PARAM_TXBF_MU_TX_BFER BIT(3) -#define HECAP_PHYDWORD_0 0 -#define HECAP_PHYDWORD_1 1 -#define HECAP_PHYDWORD_2 2 - -#define HECAP_PHY_SU_BFER BIT(31) -#define HECAP_PHY_SU_BFEE BIT(0) -#define HECAP_PHY_MU_BFER BIT(1) -#define HECAP_PHY_UL_MUMIMO BIT(22) -#define HECAP_PHY_UL_MUOFDMA BIT(23) - -#define HECAP_PHY_SUBFMR_GET(hecap_phy) \ - u32_get_bits(hecap_phy[HECAP_PHYDWORD_0], HECAP_PHY_SU_BFER) - -#define HECAP_PHY_SUBFME_GET(hecap_phy) \ - u32_get_bits(hecap_phy[HECAP_PHYDWORD_1], HECAP_PHY_SU_BFEE) - -#define HECAP_PHY_MUBFMR_GET(hecap_phy) \ - u32_get_bits(hecap_phy[HECAP_PHYDWORD_1], HECAP_PHY_MU_BFER) - -#define HECAP_PHY_ULMUMIMO_GET(hecap_phy) \ - u32_get_bits(hecap_phy[HECAP_PHYDWORD_0], HECAP_PHY_UL_MUMIMO) - -#define HECAP_PHY_ULOFDMA_GET(hecap_phy) \ - u32_get_bits(hecap_phy[HECAP_PHYDWORD_0], HECAP_PHY_UL_MUOFDMA) - #define HE_MODE_SU_TX_BFEE BIT(0) #define HE_MODE_SU_TX_BFER BIT(1) #define HE_MODE_MU_TX_BFEE BIT(2) @@ -3172,8 +3147,11 @@ struct ath12k_wmi_rx_reorder_queue_remove_arg { #define HE_DL_MUOFDMA_ENABLE 1 #define HE_UL_MUOFDMA_ENABLE 1 #define HE_DL_MUMIMO_ENABLE 1 +#define HE_UL_MUMIMO_ENABLE 1 #define HE_MU_BFEE_ENABLE 1 #define HE_SU_BFEE_ENABLE 1 +#define HE_MU_BFER_ENABLE 1 +#define HE_SU_BFER_ENABLE 1 #define HE_VHT_SOUNDING_MODE_ENABLE 1 #define HE_SU_MU_SOUNDING_MODE_ENABLE 1 From df8207bc0b4895c18e98a4b084806222b592d9f1 Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Mon, 30 Jun 2025 18:04:01 -0700 Subject: [PATCH 035/199] wifi: ath12k: push EHT MU-MIMO params to hardware Currently, only the EHT IE in management frames is updated with respect to MU-MIMO configurations, but this change is not reflected in the hardware. Add support to propagate MU-MIMO configurations to the hardware as well for AP mode. Similar support for STA mode will be added in future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Co-developed-by: Muna Sinada Signed-off-by: Muna Sinada Signed-off-by: Pradeep Kumar Chitrapu Acked-by: Jeff Johnson Link: https://patch.msgid.link/20250701010408.1257201-3-quic_pradeepc@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 58 +++++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/wmi.h | 21 ++++++++++ 2 files changed, 79 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index c81cecb01c06..811b44c703b4 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -3279,6 +3279,58 @@ static int ath12k_mac_vif_recalc_sta_he_txbf(struct ath12k *ar, return 0; } +static int ath12k_mac_set_eht_txbf_conf(struct ath12k_link_vif *arvif) +{ + struct ath12k_vif *ahvif = arvif->ahvif; + struct ath12k *ar = arvif->ar; + u32 param = WMI_VDEV_PARAM_SET_EHT_MU_MODE; + u32 value = 0; + int ret; + struct ieee80211_bss_conf *link_conf; + + link_conf = ath12k_mac_get_link_bss_conf(arvif); + if (!link_conf) { + ath12k_warn(ar->ab, "unable to access bss link conf in eht txbf conf\n"); + return -ENOENT; + } + + if (!link_conf->eht_support) + return 0; + + if (link_conf->eht_su_beamformer) { + value |= u32_encode_bits(EHT_SU_BFER_ENABLE, EHT_MODE_SU_TX_BFER); + if (link_conf->eht_mu_beamformer && + ahvif->vdev_type == WMI_VDEV_TYPE_AP) + value |= u32_encode_bits(EHT_MU_BFER_ENABLE, + EHT_MODE_MU_TX_BFER) | + u32_encode_bits(EHT_DL_MUOFDMA_ENABLE, + EHT_MODE_DL_OFDMA_MUMIMO) | + u32_encode_bits(EHT_UL_MUOFDMA_ENABLE, + EHT_MODE_UL_OFDMA_MUMIMO); + } + + if (ahvif->vif->type != NL80211_IFTYPE_MESH_POINT) { + value |= u32_encode_bits(EHT_DL_MUOFDMA_ENABLE, EHT_MODE_DL_OFDMA) | + u32_encode_bits(EHT_UL_MUOFDMA_ENABLE, EHT_MODE_UL_OFDMA); + + if (link_conf->eht_80mhz_full_bw_ul_mumimo) + value |= u32_encode_bits(EHT_UL_MUMIMO_ENABLE, EHT_MODE_MUMIMO); + + if (link_conf->eht_su_beamformee) + value |= u32_encode_bits(EHT_SU_BFEE_ENABLE, + EHT_MODE_SU_TX_BFEE); + } + + ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param, value); + if (ret) { + ath12k_warn(ar->ab, "failed to set vdev %d EHT MU mode: %d\n", + arvif->vdev_id, ret); + return ret; + } + + return 0; +} + static u32 ath12k_mac_ieee80211_sta_bw_to_wmi(struct ath12k *ar, struct ieee80211_link_sta *link_sta) { @@ -4018,6 +4070,12 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar, ath12k_warn(ar->ab, "failed to set HE TXBF config for vdev: %d\n", arvif->vdev_id); + + ret = ath12k_mac_set_eht_txbf_conf(arvif); + if (ret) + ath12k_warn(ar->ab, + "failed to set EHT TXBF config for vdev: %d\n", + arvif->vdev_id); } ath12k_control_beaconing(arvif, info); diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 07cba3997e75..0964ca03069a 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -1178,6 +1178,7 @@ enum wmi_tlv_vdev_param { WMI_VDEV_PARAM_BSS_COLOR, WMI_VDEV_PARAM_SET_HEMU_MODE, WMI_VDEV_PARAM_HEOPS_0_31 = 0x8003, + WMI_VDEV_PARAM_SET_EHT_MU_MODE = 0x8005, }; enum wmi_tlv_peer_flags { @@ -3153,6 +3154,26 @@ struct ath12k_wmi_rx_reorder_queue_remove_arg { #define HE_MU_BFER_ENABLE 1 #define HE_SU_BFER_ENABLE 1 +#define EHT_MODE_SU_TX_BFEE BIT(0) +#define EHT_MODE_SU_TX_BFER BIT(1) +#define EHT_MODE_MU_TX_BFEE BIT(2) +#define EHT_MODE_MU_TX_BFER BIT(3) +#define EHT_MODE_DL_OFDMA BIT(4) +#define EHT_MODE_UL_OFDMA BIT(5) +#define EHT_MODE_MUMIMO BIT(6) +#define EHT_MODE_DL_OFDMA_TXBF BIT(7) +#define EHT_MODE_DL_OFDMA_MUMIMO BIT(8) +#define EHT_MODE_UL_OFDMA_MUMIMO BIT(9) + +#define EHT_DL_MUOFDMA_ENABLE 1 +#define EHT_UL_MUOFDMA_ENABLE 1 +#define EHT_DL_MUMIMO_ENABLE 1 +#define EHT_UL_MUMIMO_ENABLE 1 +#define EHT_MU_BFEE_ENABLE 1 +#define EHT_SU_BFEE_ENABLE 1 +#define EHT_MU_BFER_ENABLE 1 +#define EHT_SU_BFER_ENABLE 1 + #define HE_VHT_SOUNDING_MODE_ENABLE 1 #define HE_SU_MU_SOUNDING_MODE_ENABLE 1 #define HE_TRIG_NONTRIG_SOUNDING_MODE_ENABLE 1 From 1eafb8d15d8af39ac7b4d78d69b17f85aa8e00fa Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Mon, 30 Jun 2025 18:04:02 -0700 Subject: [PATCH 036/199] wifi: ath12k: move HE MCS mapper to a separate function Refactor the HE MCS mapper functionality in ath12k_mac_copy_he_cap() into a new function. This helps improve readability, extensibility and will be used when adding support for 160 MHz bandwidth in subsequent patches. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Co-developed-by: Muna Sinada Signed-off-by: Muna Sinada Signed-off-by: Pradeep Kumar Chitrapu Acked-by: Jeff Johnson Link: https://patch.msgid.link/20250701010408.1257201-4-quic_pradeepc@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 811b44c703b4..f3833fa08070 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7537,12 +7537,24 @@ static __le16 ath12k_mac_setup_he_6ghz_cap(struct ath12k_pdev_cap *pcap, return cpu_to_le16(bcap->he_6ghz_capa); } +static void ath12k_mac_set_hemcsmap(struct ath12k_band_cap *band_cap, + struct ieee80211_sta_he_cap *he_cap) +{ + struct ieee80211_he_mcs_nss_supp *mcs_nss = &he_cap->he_mcs_nss_supp; + + mcs_nss->rx_mcs_80 = cpu_to_le16(band_cap->he_mcs & 0xffff); + mcs_nss->tx_mcs_80 = cpu_to_le16(band_cap->he_mcs & 0xffff); + mcs_nss->rx_mcs_160 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); + mcs_nss->tx_mcs_160 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); + mcs_nss->rx_mcs_80p80 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); + mcs_nss->tx_mcs_80p80 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); +} + static void ath12k_mac_copy_he_cap(struct ath12k_band_cap *band_cap, int iftype, u8 num_tx_chains, struct ieee80211_sta_he_cap *he_cap) { struct ieee80211_he_cap_elem *he_cap_elem = &he_cap->he_cap_elem; - struct ieee80211_he_mcs_nss_supp *mcs_nss = &he_cap->he_mcs_nss_supp; he_cap->has_he = true; memcpy(he_cap_elem->mac_cap_info, band_cap->he_cap_info, @@ -7582,13 +7594,7 @@ static void ath12k_mac_copy_he_cap(struct ath12k_band_cap *band_cap, break; } - mcs_nss->rx_mcs_80 = cpu_to_le16(band_cap->he_mcs & 0xffff); - mcs_nss->tx_mcs_80 = cpu_to_le16(band_cap->he_mcs & 0xffff); - mcs_nss->rx_mcs_160 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); - mcs_nss->tx_mcs_160 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); - mcs_nss->rx_mcs_80p80 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); - mcs_nss->tx_mcs_80p80 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); - + ath12k_mac_set_hemcsmap(band_cap, he_cap); memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres)); if (he_cap_elem->phy_cap_info[6] & IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) From 5ab7479a063d1b557fa59999de701ad8a4624b84 Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Mon, 30 Jun 2025 18:04:03 -0700 Subject: [PATCH 037/199] wifi: ath12k: generate rx and tx mcs maps for supported HE mcs Generate rx and tx mcs maps in ath12k_mac_set_hemcsmap() based on number of supported tx/rx chains and set them in supported mcs/nss for HE capabilities. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Co-developed-by: Muna Sinada Signed-off-by: Muna Sinada Signed-off-by: Pradeep Kumar Chitrapu Acked-by: Jeff Johnson Link: https://patch.msgid.link/20250701010408.1257201-5-quic_pradeepc@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 40 ++++++++++++++++++++------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index f3833fa08070..37f50851a236 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7537,20 +7537,40 @@ static __le16 ath12k_mac_setup_he_6ghz_cap(struct ath12k_pdev_cap *pcap, return cpu_to_le16(bcap->he_6ghz_capa); } -static void ath12k_mac_set_hemcsmap(struct ath12k_band_cap *band_cap, +static void ath12k_mac_set_hemcsmap(struct ath12k *ar, + struct ath12k_pdev_cap *cap, struct ieee80211_sta_he_cap *he_cap) { struct ieee80211_he_mcs_nss_supp *mcs_nss = &he_cap->he_mcs_nss_supp; + u16 txmcs_map, rxmcs_map; + u32 i; - mcs_nss->rx_mcs_80 = cpu_to_le16(band_cap->he_mcs & 0xffff); - mcs_nss->tx_mcs_80 = cpu_to_le16(band_cap->he_mcs & 0xffff); - mcs_nss->rx_mcs_160 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); - mcs_nss->tx_mcs_160 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); - mcs_nss->rx_mcs_80p80 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); - mcs_nss->tx_mcs_80p80 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); + rxmcs_map = 0; + txmcs_map = 0; + for (i = 0; i < 8; i++) { + if (i < ar->num_tx_chains && + (ar->cfg_tx_chainmask >> cap->tx_chain_mask_shift) & BIT(i)) + txmcs_map |= IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2); + else + txmcs_map |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2); + + if (i < ar->num_rx_chains && + (ar->cfg_rx_chainmask >> cap->tx_chain_mask_shift) & BIT(i)) + rxmcs_map |= IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2); + else + rxmcs_map |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2); + } + + mcs_nss->rx_mcs_80 = cpu_to_le16(rxmcs_map & 0xffff); + mcs_nss->tx_mcs_80 = cpu_to_le16(txmcs_map & 0xffff); + mcs_nss->rx_mcs_160 = cpu_to_le16(rxmcs_map & 0xffff); + mcs_nss->tx_mcs_160 = cpu_to_le16(txmcs_map & 0xffff); + mcs_nss->rx_mcs_80p80 = cpu_to_le16(rxmcs_map & 0xffff); + mcs_nss->tx_mcs_80p80 = cpu_to_le16(txmcs_map & 0xffff); } -static void ath12k_mac_copy_he_cap(struct ath12k_band_cap *band_cap, +static void ath12k_mac_copy_he_cap(struct ath12k *ar, + struct ath12k_band_cap *band_cap, int iftype, u8 num_tx_chains, struct ieee80211_sta_he_cap *he_cap) { @@ -7594,7 +7614,7 @@ static void ath12k_mac_copy_he_cap(struct ath12k_band_cap *band_cap, break; } - ath12k_mac_set_hemcsmap(band_cap, he_cap); + ath12k_mac_set_hemcsmap(ar, &ar->pdev->cap, he_cap); memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres)); if (he_cap_elem->phy_cap_info[6] & IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) @@ -7784,7 +7804,7 @@ static int ath12k_mac_copy_sband_iftype_data(struct ath12k *ar, data[idx].types_mask = BIT(i); - ath12k_mac_copy_he_cap(band_cap, i, ar->num_tx_chains, he_cap); + ath12k_mac_copy_he_cap(ar, band_cap, i, ar->num_tx_chains, he_cap); if (band == NL80211_BAND_6GHZ) { data[idx].he_6ghz_capa.capa = ath12k_mac_setup_he_6ghz_cap(cap, band_cap); From 9ad6b169ddef679a64727e3870a6177c78f24b05 Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Mon, 30 Jun 2025 18:04:05 -0700 Subject: [PATCH 038/199] wifi: ath12k: add support for setting fixed HE rate/GI/LTF Add support to set fixed HE rate/GI/LTF values using nl80211. Reuse parts of the existing code path already used for HT/VHT to implement the new helpers symmetrically, similar to how HT/VHT is handled. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Co-developed-by: Muna Sinada Signed-off-by: Muna Sinada Signed-off-by: Pradeep Kumar Chitrapu Link: https://patch.msgid.link/20250701010408.1257201-7-quic_pradeepc@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 652 +++++++++++++++++++++++--- drivers/net/wireless/ath/ath12k/wmi.h | 27 ++ 2 files changed, 626 insertions(+), 53 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 37f50851a236..aefb620b28e2 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -521,6 +521,18 @@ ath12k_mac_max_vht_nss(const u16 *vht_mcs_mask) return 1; } +static u32 +ath12k_mac_max_he_nss(const u16 he_mcs_mask[NL80211_HE_NSS_MAX]) +{ + int nss; + + for (nss = NL80211_HE_NSS_MAX - 1; nss >= 0; nss--) + if (he_mcs_mask[nss]) + return nss + 1; + + return 1; +} + static u8 ath12k_parse_mpdudensity(u8 mpdudensity) { /* From IEEE Std 802.11-2020 defined values for "Minimum MPDU Start Spacing": @@ -2071,9 +2083,15 @@ static void ath12k_peer_assoc_h_ht(struct ath12k *ar, arg->peer_rate_caps |= WMI_HOST_RC_CW40_FLAG; } - if (arvif->bitrate_mask.control[band].gi != NL80211_TXRATE_FORCE_LGI) { - if (ht_cap->cap & (IEEE80211_HT_CAP_SGI_20 | - IEEE80211_HT_CAP_SGI_40)) + /* As firmware handles these two flags (IEEE80211_HT_CAP_SGI_20 + * and IEEE80211_HT_CAP_SGI_40) for enabling SGI, reset both + * flags if guard interval is to force Long GI + */ + if (arvif->bitrate_mask.control[band].gi == NL80211_TXRATE_FORCE_LGI) { + arg->peer_ht_caps &= ~(IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40); + } else { + /* Enable SGI flag if either SGI_20 or SGI_40 is supported */ + if (ht_cap->cap & (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40)) arg->peer_rate_caps |= WMI_HOST_RC_SGI_FLAG; } @@ -2196,11 +2214,12 @@ static void ath12k_peer_assoc_h_vht(struct ath12k *ar, struct ieee80211_link_sta *link_sta; struct cfg80211_chan_def def; enum nl80211_band band; - const u16 *vht_mcs_mask; + u16 *vht_mcs_mask; u16 tx_mcs_map; u8 ampdu_factor; u8 max_nss, vht_mcs; - int i; + int i, vht_nss, nss_idx; + bool user_rate_valid = true; lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); @@ -2253,6 +2272,25 @@ static void ath12k_peer_assoc_h_vht(struct ath12k *ar, if (link_sta->bandwidth == IEEE80211_STA_RX_BW_160) arg->bw_160 = true; + vht_nss = ath12k_mac_max_vht_nss(vht_mcs_mask); + + if (vht_nss > link_sta->rx_nss) { + user_rate_valid = false; + for (nss_idx = link_sta->rx_nss - 1; nss_idx >= 0; nss_idx--) { + if (vht_mcs_mask[nss_idx]) { + user_rate_valid = true; + break; + } + } + } + + if (!user_rate_valid) { + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "Setting vht range MCS value to peer supported nss:%d for peer %pM\n", + link_sta->rx_nss, arsta->addr); + vht_mcs_mask[link_sta->rx_nss - 1] = vht_mcs_mask[vht_nss - 1]; + } + /* Calculate peer NSS capability from VHT capabilities if STA * supports VHT. */ @@ -2292,6 +2330,72 @@ static void ath12k_peer_assoc_h_vht(struct ath12k *ar, /* TODO: rxnss_override */ } +static int ath12k_mac_get_max_he_mcs_map(u16 mcs_map, int nss) +{ + switch ((mcs_map >> (2 * nss)) & 0x3) { + case IEEE80211_HE_MCS_SUPPORT_0_7: return BIT(8) - 1; + case IEEE80211_HE_MCS_SUPPORT_0_9: return BIT(10) - 1; + case IEEE80211_HE_MCS_SUPPORT_0_11: return BIT(12) - 1; + } + return 0; +} + +static u16 ath12k_peer_assoc_h_he_limit(u16 tx_mcs_set, + const u16 *he_mcs_limit) +{ + int idx_limit; + int nss; + u16 mcs_map; + u16 mcs; + + for (nss = 0; nss < NL80211_HE_NSS_MAX; nss++) { + mcs_map = ath12k_mac_get_max_he_mcs_map(tx_mcs_set, nss) & + he_mcs_limit[nss]; + + if (mcs_map) + idx_limit = fls(mcs_map) - 1; + else + idx_limit = -1; + + switch (idx_limit) { + case 0 ... 7: + mcs = IEEE80211_HE_MCS_SUPPORT_0_7; + break; + case 8: + case 9: + mcs = IEEE80211_HE_MCS_SUPPORT_0_9; + break; + case 10: + case 11: + mcs = IEEE80211_HE_MCS_SUPPORT_0_11; + break; + default: + WARN_ON(1); + fallthrough; + case -1: + mcs = IEEE80211_HE_MCS_NOT_SUPPORTED; + break; + } + + tx_mcs_set &= ~(0x3 << (nss * 2)); + tx_mcs_set |= mcs << (nss * 2); + } + + return tx_mcs_set; +} + +static bool +ath12k_peer_assoc_h_he_masked(const u16 he_mcs_mask[NL80211_HE_NSS_MAX]) +{ + int nss; + + for (nss = 0; nss < NL80211_HE_NSS_MAX; nss++) + if (he_mcs_mask[nss]) + return false; + + return true; +} + static void ath12k_peer_assoc_h_he(struct ath12k *ar, struct ath12k_link_vif *arvif, struct ath12k_link_sta *arsta, @@ -2302,18 +2406,28 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar, const struct ieee80211_sta_he_cap *he_cap; struct ieee80211_bss_conf *link_conf; struct ieee80211_link_sta *link_sta; + struct cfg80211_chan_def def; int i; u8 ampdu_factor, max_nss; u8 rx_mcs_80 = IEEE80211_HE_MCS_NOT_SUPPORTED; u8 rx_mcs_160 = IEEE80211_HE_MCS_NOT_SUPPORTED; u16 mcs_160_map, mcs_80_map; + u8 link_id = arvif->link_id; bool support_160; - u16 v; + enum nl80211_band band; + u16 *he_mcs_mask; + u8 he_mcs; + u16 he_tx_mcs = 0, v = 0; + int he_nss, nss_idx; + bool user_rate_valid = true; + + if (WARN_ON(ath12k_mac_vif_link_chan(vif, link_id, &def))) + return; link_conf = ath12k_mac_get_link_bss_conf(arvif); if (!link_conf) { ath12k_warn(ar->ab, "unable to access bss link conf in peer assoc he for vif %pM link %u", - vif->addr, arvif->link_id); + vif->addr, link_id); return; } @@ -2328,6 +2442,12 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar, if (!he_cap->has_he) return; + band = def.chan->band; + he_mcs_mask = arvif->bitrate_mask.control[band].he_mcs; + + if (ath12k_peer_assoc_h_he_masked(he_mcs_mask)) + return; + arg->he_flag = true; support_160 = !!(he_cap->he_cap_elem.phy_cap_info[0] & @@ -2433,25 +2553,47 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar, if (he_cap->he_cap_elem.mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_TWT_REQ) arg->twt_requester = true; + he_nss = ath12k_mac_max_he_nss(he_mcs_mask); + + if (he_nss > link_sta->rx_nss) { + user_rate_valid = false; + for (nss_idx = link_sta->rx_nss - 1; nss_idx >= 0; nss_idx--) { + if (he_mcs_mask[nss_idx]) { + user_rate_valid = true; + break; + } + } + } + + if (!user_rate_valid) { + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "Setting he range MCS value to peer supported nss:%d for peer %pM\n", + link_sta->rx_nss, arsta->addr); + he_mcs_mask[link_sta->rx_nss - 1] = he_mcs_mask[he_nss - 1]; + } + switch (link_sta->bandwidth) { case IEEE80211_STA_RX_BW_160: if (he_cap->he_cap_elem.phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) { - v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80p80); + v = ath12k_peer_assoc_h_he_limit(v, he_mcs_mask); arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] = v; v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80p80); arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] = v; arg->peer_he_mcs_count++; + he_tx_mcs = v; } v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v; - v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_160); + v = ath12k_peer_assoc_h_he_limit(v, he_mcs_mask); arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v; arg->peer_he_mcs_count++; + if (!he_tx_mcs) + he_tx_mcs = v; fallthrough; default: @@ -2459,11 +2601,36 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar, arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v; v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80); + v = ath12k_peer_assoc_h_he_limit(v, he_mcs_mask); arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v; arg->peer_he_mcs_count++; + if (!he_tx_mcs) + he_tx_mcs = v; break; } + + /* Calculate peer NSS capability from HE capabilities if STA + * supports HE. + */ + for (i = 0, max_nss = 0, he_mcs = 0; i < NL80211_HE_NSS_MAX; i++) { + he_mcs = he_tx_mcs >> (2 * i) & 3; + + /* In case of fixed rates, MCS Range in he_tx_mcs might have + * unsupported range, with he_mcs_mask set, so check either of them + * to find nss. + */ + if (he_mcs != IEEE80211_HE_MCS_NOT_SUPPORTED || + he_mcs_mask[i]) + max_nss = i + 1; + } + + max_nss = min(max_nss, ar->num_tx_chains); + arg->peer_nss = min(link_sta->rx_nss, max_nss); + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "mac he peer %pM nss %d mcs cnt %d\n", + arsta->addr, arg->peer_nss, arg->peer_he_mcs_count); } static void ath12k_peer_assoc_h_he_6ghz(struct ath12k *ar, @@ -2799,6 +2966,7 @@ static void ath12k_peer_assoc_h_phymode(struct ath12k *ar, enum nl80211_band band; const u8 *ht_mcs_mask; const u16 *vht_mcs_mask; + const u16 *he_mcs_mask; enum wmi_phy_mode phymode = MODE_UNKNOWN; lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); @@ -2812,6 +2980,7 @@ static void ath12k_peer_assoc_h_phymode(struct ath12k *ar, band = def.chan->band; ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs; vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs; + he_mcs_mask = arvif->bitrate_mask.control[band].he_mcs; link_sta = ath12k_mac_get_link_sta(arsta); if (!link_sta) { @@ -2827,7 +2996,8 @@ static void ath12k_peer_assoc_h_phymode(struct ath12k *ar, phymode = MODE_11BE_EHT40_2G; else phymode = MODE_11BE_EHT20_2G; - } else if (link_sta->he_cap.has_he) { + } else if (link_sta->he_cap.has_he && + !ath12k_peer_assoc_h_he_masked(he_mcs_mask)) { if (link_sta->bandwidth == IEEE80211_STA_RX_BW_80) phymode = MODE_11AX_HE80_2G; else if (link_sta->bandwidth == IEEE80211_STA_RX_BW_40) @@ -2857,7 +3027,8 @@ static void ath12k_peer_assoc_h_phymode(struct ath12k *ar, /* Check EHT first */ if (link_sta->eht_cap.has_eht) { phymode = ath12k_mac_get_phymode_eht(ar, link_sta); - } else if (link_sta->he_cap.has_he) { + } else if (link_sta->he_cap.has_he && + !ath12k_peer_assoc_h_he_masked(he_mcs_mask)) { phymode = ath12k_mac_get_phymode_he(ar, link_sta); } else if (link_sta->vht_cap.vht_supported && !ath12k_peer_assoc_h_vht_masked(vht_mcs_mask)) { @@ -3647,10 +3818,13 @@ static void ath12k_mac_init_arvif(struct ath12k_vif *ahvif, for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) { arvif->bitrate_mask.control[i].legacy = 0xffffffff; + arvif->bitrate_mask.control[i].gi = NL80211_TXRATE_DEFAULT_GI; memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff, sizeof(arvif->bitrate_mask.control[i].ht_mcs)); memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff, sizeof(arvif->bitrate_mask.control[i].vht_mcs)); + memset(arvif->bitrate_mask.control[i].he_mcs, 0xff, + sizeof(arvif->bitrate_mask.control[i].he_mcs)); } /* Handle MLO related assignments */ @@ -5474,6 +5648,20 @@ ath12k_mac_bitrate_mask_num_vht_rates(struct ath12k *ar, return num_rates; } +static int +ath12k_mac_bitrate_mask_num_he_rates(struct ath12k *ar, + enum nl80211_band band, + const struct cfg80211_bitrate_mask *mask) +{ + int num_rates = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(mask->control[band].he_mcs); i++) + num_rates += hweight16(mask->control[band].he_mcs[i]); + + return num_rates; +} + static int ath12k_mac_set_peer_vht_fixed_rate(struct ath12k_link_vif *arvif, struct ath12k_link_sta *arsta, @@ -5520,6 +5708,60 @@ ath12k_mac_set_peer_vht_fixed_rate(struct ath12k_link_vif *arvif, return ret; } +static int +ath12k_mac_set_peer_he_fixed_rate(struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, + const struct cfg80211_bitrate_mask *mask, + enum nl80211_band band) +{ + struct ath12k *ar = arvif->ar; + u8 he_rate, nss; + u32 rate_code; + int ret, i; + struct ath12k_sta *ahsta = arsta->ahsta; + struct ieee80211_sta *sta; + + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + sta = ath12k_ahsta_to_sta(ahsta); + nss = 0; + + for (i = 0; i < ARRAY_SIZE(mask->control[band].he_mcs); i++) { + if (hweight16(mask->control[band].he_mcs[i]) == 1) { + nss = i + 1; + he_rate = ffs(mask->control[band].he_mcs[i]) - 1; + } + } + + if (!nss) { + ath12k_warn(ar->ab, "No single HE Fixed rate found to set for %pM", + arsta->addr); + return -EINVAL; + } + + /* Avoid updating invalid nss as fixed rate*/ + if (nss > sta->deflink.rx_nss) + return -EINVAL; + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "Setting Fixed HE Rate for peer %pM. Device will not switch to any other selected rates", + arsta->addr); + + rate_code = ATH12K_HW_RATE_CODE(he_rate, nss - 1, + WMI_RATE_PREAMBLE_HE); + + ret = ath12k_wmi_set_peer_param(ar, arsta->addr, + arvif->vdev_id, + WMI_PEER_PARAM_FIXED_RATE, + rate_code); + if (ret) + ath12k_warn(ar->ab, + "failed to update STA %pM Fixed Rate %d: %d\n", + arsta->addr, rate_code, ret); + + return ret; +} + static int ath12k_mac_station_assoc(struct ath12k *ar, struct ath12k_link_vif *arvif, struct ath12k_link_sta *arsta, @@ -5532,7 +5774,7 @@ static int ath12k_mac_station_assoc(struct ath12k *ar, struct cfg80211_chan_def def; enum nl80211_band band; struct cfg80211_bitrate_mask *mask; - u8 num_vht_rates; + u8 num_vht_rates, num_he_rates; u8 link_id = arvif->link_id; lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); @@ -5574,9 +5816,10 @@ static int ath12k_mac_station_assoc(struct ath12k *ar, } num_vht_rates = ath12k_mac_bitrate_mask_num_vht_rates(ar, band, mask); + num_he_rates = ath12k_mac_bitrate_mask_num_he_rates(ar, band, mask); - /* If single VHT rate is configured (by set_bitrate_mask()), - * peer_assoc will disable VHT. This is now enabled by a peer specific + /* If single VHT/HE rate is configured (by set_bitrate_mask()), + * peer_assoc will disable VHT/HE. This is now enabled by a peer specific * fixed param. * Note that all other rates and NSS will be disabled for this peer. */ @@ -5592,8 +5835,9 @@ static int ath12k_mac_station_assoc(struct ath12k *ar, spin_unlock_bh(&ar->data_lock); if (link_sta->vht_cap.vht_supported && num_vht_rates == 1) { - ret = ath12k_mac_set_peer_vht_fixed_rate(arvif, arsta, mask, - band); + ret = ath12k_mac_set_peer_vht_fixed_rate(arvif, arsta, mask, band); + } else if (link_sta->he_cap.has_he && num_he_rates == 1) { + ret = ath12k_mac_set_peer_he_fixed_rate(arvif, arsta, mask, band); if (ret) return ret; } @@ -5657,8 +5901,9 @@ static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk) enum nl80211_band band; const u8 *ht_mcs_mask; const u16 *vht_mcs_mask; - u32 changed, bw, nss, smps, bw_prev; - int err, num_vht_rates; + const u16 *he_mcs_mask; + u32 changed, bw, nss, mac_nss, smps, bw_prev; + int err, num_vht_rates, num_he_rates; const struct cfg80211_bitrate_mask *mask; enum wmi_phy_mode peer_phymode; struct ath12k_link_sta *arsta; @@ -5678,6 +5923,7 @@ static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk) band = def.chan->band; ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs; vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs; + he_mcs_mask = arvif->bitrate_mask.control[band].he_mcs; spin_lock_bh(&ar->data_lock); @@ -5692,8 +5938,10 @@ static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk) spin_unlock_bh(&ar->data_lock); nss = max_t(u32, 1, nss); - nss = min(nss, max(ath12k_mac_max_ht_nss(ht_mcs_mask), - ath12k_mac_max_vht_nss(vht_mcs_mask))); + mac_nss = max3(ath12k_mac_max_ht_nss(ht_mcs_mask), + ath12k_mac_max_vht_nss(vht_mcs_mask), + ath12k_mac_max_he_nss(he_mcs_mask)); + nss = min(nss, mac_nss); struct ath12k_wmi_peer_assoc_arg *peer_arg __free(kfree) = kzalloc(sizeof(*peer_arg), GFP_KERNEL); @@ -5776,6 +6024,8 @@ static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk) mask = &arvif->bitrate_mask; num_vht_rates = ath12k_mac_bitrate_mask_num_vht_rates(ar, band, mask); + num_he_rates = ath12k_mac_bitrate_mask_num_he_rates(ar, band, + mask); /* Peer_assoc_prepare will reject vht rates in * bitrate_mask if its not available in range format and @@ -5798,11 +6048,24 @@ static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk) if (link_sta->vht_cap.vht_supported && num_vht_rates == 1) { ath12k_mac_set_peer_vht_fixed_rate(arvif, arsta, mask, band); + } else if (link_sta->he_cap.has_he && num_he_rates == 1) { + ath12k_mac_set_peer_he_fixed_rate(arvif, arsta, mask, band); } else { - /* If the peer is non-VHT or no fixed VHT rate + /* If the peer is non-VHT/HE or no fixed VHT/HE rate * is provided in the new bitrate mask we set the - * other rates using peer_assoc command. + * other rates using peer_assoc command. Also clear + * the peer fixed rate settings as it has higher proprity + * than peer assoc */ + err = ath12k_wmi_set_peer_param(ar, arsta->addr, + arvif->vdev_id, + WMI_PEER_PARAM_FIXED_RATE, + WMI_FIXED_RATE_NONE); + if (err) + ath12k_warn(ar->ab, + "failed to disable peer fixed rate for STA %pM ret %d\n", + arsta->addr, err); + ath12k_peer_assoc_prepare(ar, arvif, arsta, peer_arg, true); @@ -11269,19 +11532,40 @@ ath12k_mac_has_single_legacy_rate(struct ath12k *ar, if (ath12k_mac_bitrate_mask_num_vht_rates(ar, band, mask)) return false; + if (ath12k_mac_bitrate_mask_num_he_rates(ar, band, mask)) + return false; + return num_rates == 1; } +static __le16 +ath12k_mac_get_tx_mcs_map(const struct ieee80211_sta_he_cap *he_cap) +{ + if (he_cap->he_cap_elem.phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) + return he_cap->he_mcs_nss_supp.tx_mcs_80p80; + + if (he_cap->he_cap_elem.phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) + return he_cap->he_mcs_nss_supp.tx_mcs_160; + + return he_cap->he_mcs_nss_supp.tx_mcs_80; +} + static bool ath12k_mac_bitrate_mask_get_single_nss(struct ath12k *ar, + struct ieee80211_vif *vif, enum nl80211_band band, const struct cfg80211_bitrate_mask *mask, int *nss) { struct ieee80211_supported_band *sband = &ar->mac.sbands[band]; u16 vht_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map); + const struct ieee80211_sta_he_cap *he_cap; + u16 he_mcs_map = 0; u8 ht_nss_mask = 0; u8 vht_nss_mask = 0; + u8 he_nss_mask = 0; int i; /* No need to consider legacy here. Basic rates are always present @@ -11308,7 +11592,24 @@ ath12k_mac_bitrate_mask_get_single_nss(struct ath12k *ar, return false; } - if (ht_nss_mask != vht_nss_mask) + he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif); + if (!he_cap) + return false; + + he_mcs_map = le16_to_cpu(ath12k_mac_get_tx_mcs_map(he_cap)); + + for (i = 0; i < ARRAY_SIZE(mask->control[band].he_mcs); i++) { + if (mask->control[band].he_mcs[i] == 0) + continue; + + if (mask->control[band].he_mcs[i] == + ath12k_mac_get_max_he_mcs_map(he_mcs_map, i)) + he_nss_mask |= BIT(i); + else + return false; + } + + if (ht_nss_mask != vht_nss_mask || ht_nss_mask != he_nss_mask) return false; if (ht_nss_mask == 0) @@ -11355,28 +11656,147 @@ ath12k_mac_get_single_legacy_rate(struct ath12k *ar, return 0; } -static int ath12k_mac_set_fixed_rate_params(struct ath12k_link_vif *arvif, - u32 rate, u8 nss, u8 sgi, u8 ldpc) +static int +ath12k_mac_set_fixed_rate_gi_ltf(struct ath12k_link_vif *arvif, u8 he_gi, u8 he_ltf) { struct ath12k *ar = arvif->ar; - u32 vdev_param; int ret; lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); - ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac set fixed rate params vdev %i rate 0x%02x nss %u sgi %u\n", - arvif->vdev_id, rate, nss, sgi); + /* 0.8 = 0, 1.6 = 2 and 3.2 = 3. */ + if (he_gi && he_gi != 0xFF) + he_gi += 1; - vdev_param = WMI_VDEV_PARAM_FIXED_RATE; ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, - vdev_param, rate); + WMI_VDEV_PARAM_SGI, he_gi); if (ret) { - ath12k_warn(ar->ab, "failed to set fixed rate param 0x%02x: %d\n", - rate, ret); + ath12k_warn(ar->ab, "failed to set HE GI:%d, error:%d\n", + he_gi, ret); + return ret; + } + /* start from 1 */ + if (he_ltf != 0xFF) + he_ltf += 1; + + ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + WMI_VDEV_PARAM_HE_LTF, he_ltf); + if (ret) { + ath12k_warn(ar->ab, "failed to set HE LTF:%d, error:%d\n", + he_ltf, ret); + return ret; + } + return 0; +} + +static int +ath12k_mac_set_auto_rate_gi_ltf(struct ath12k_link_vif *arvif, u16 he_gi, u8 he_ltf) +{ + struct ath12k *ar = arvif->ar; + int ret; + u32 he_ar_gi_ltf; + + if (he_gi != 0xFF) { + switch (he_gi) { + case NL80211_RATE_INFO_HE_GI_0_8: + he_gi = WMI_AUTORATE_800NS_GI; + break; + case NL80211_RATE_INFO_HE_GI_1_6: + he_gi = WMI_AUTORATE_1600NS_GI; + break; + case NL80211_RATE_INFO_HE_GI_3_2: + he_gi = WMI_AUTORATE_3200NS_GI; + break; + default: + ath12k_warn(ar->ab, "Invalid GI\n"); + return -EINVAL; + } + } + + if (he_ltf != 0xFF) { + switch (he_ltf) { + case NL80211_RATE_INFO_HE_1XLTF: + he_ltf = WMI_HE_AUTORATE_LTF_1X; + break; + case NL80211_RATE_INFO_HE_2XLTF: + he_ltf = WMI_HE_AUTORATE_LTF_2X; + break; + case NL80211_RATE_INFO_HE_4XLTF: + he_ltf = WMI_HE_AUTORATE_LTF_4X; + break; + default: + ath12k_warn(ar->ab, "Invalid LTF\n"); + return -EINVAL; + } + } + + he_ar_gi_ltf = he_gi | he_ltf; + + ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + WMI_VDEV_PARAM_AUTORATE_MISC_CFG, + he_ar_gi_ltf); + if (ret) { + ath12k_warn(ar->ab, + "failed to set HE autorate GI:%u, LTF:%u params, error:%d\n", + he_gi, he_ltf, ret); return ret; } + return 0; +} + +static u32 ath12k_mac_nlgi_to_wmigi(enum nl80211_txrate_gi gi) +{ + switch (gi) { + case NL80211_TXRATE_DEFAULT_GI: + return WMI_GI_400_NS; + case NL80211_TXRATE_FORCE_LGI: + return WMI_GI_800_NS; + default: + return WMI_GI_400_NS; + } +} + +static int ath12k_mac_set_rate_params(struct ath12k_link_vif *arvif, + u32 rate, u8 nss, u8 sgi, u8 ldpc, + u8 he_gi, u8 he_ltf, bool he_fixed_rate) +{ + struct ieee80211_bss_conf *link_conf; + struct ath12k *ar = arvif->ar; + u32 vdev_param; + u32 param_value; + int ret; + bool he_support; + + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + link_conf = ath12k_mac_get_link_bss_conf(arvif); + if (!link_conf) + return -EINVAL; + + he_support = link_conf->he_support; + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "mac set rate params vdev %i rate 0x%02x nss 0x%02x sgi 0x%02x ldpc 0x%02x\n", + arvif->vdev_id, rate, nss, sgi, ldpc); + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "he_gi 0x%02x he_ltf 0x%02x he_fixed_rate %d\n", he_gi, + he_ltf, he_fixed_rate); + + if (!he_support) { + vdev_param = WMI_VDEV_PARAM_FIXED_RATE; + ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + vdev_param, rate); + if (ret) { + ath12k_warn(ar->ab, "failed to set fixed rate param 0x%02x: %d\n", + rate, ret); + return ret; + } + } + vdev_param = WMI_VDEV_PARAM_NSS; + ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, vdev_param, nss); if (ret) { @@ -11385,24 +11805,33 @@ static int ath12k_mac_set_fixed_rate_params(struct ath12k_link_vif *arvif, return ret; } - vdev_param = WMI_VDEV_PARAM_SGI; ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, - vdev_param, sgi); - if (ret) { - ath12k_warn(ar->ab, "failed to set sgi param %d: %d\n", - sgi, ret); - return ret; - } - - vdev_param = WMI_VDEV_PARAM_LDPC; - ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, - vdev_param, ldpc); + WMI_VDEV_PARAM_LDPC, ldpc); if (ret) { ath12k_warn(ar->ab, "failed to set ldpc param %d: %d\n", ldpc, ret); return ret; } + if (he_support) { + if (he_fixed_rate) + ret = ath12k_mac_set_fixed_rate_gi_ltf(arvif, he_gi, he_ltf); + else + ret = ath12k_mac_set_auto_rate_gi_ltf(arvif, he_gi, he_ltf); + if (ret) + return ret; + } else { + vdev_param = WMI_VDEV_PARAM_SGI; + param_value = ath12k_mac_nlgi_to_wmigi(sgi); + ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + vdev_param, param_value); + if (ret) { + ath12k_warn(ar->ab, "failed to set sgi param %d: %d\n", + sgi, ret); + return ret; + } + } + return 0; } @@ -11431,6 +11860,31 @@ ath12k_mac_vht_mcs_range_present(struct ath12k *ar, return true; } +static bool +ath12k_mac_he_mcs_range_present(struct ath12k *ar, + enum nl80211_band band, + const struct cfg80211_bitrate_mask *mask) +{ + int i; + u16 he_mcs; + + for (i = 0; i < NL80211_HE_NSS_MAX; i++) { + he_mcs = mask->control[band].he_mcs[i]; + + switch (he_mcs) { + case 0: + case BIT(8) - 1: + case BIT(10) - 1: + case BIT(12) - 1: + break; + default: + return false; + } + } + + return true; +} + static void ath12k_mac_set_bitrate_mask_iter(void *data, struct ieee80211_sta *sta) { @@ -11439,7 +11893,10 @@ static void ath12k_mac_set_bitrate_mask_iter(void *data, struct ath12k_link_sta *arsta; struct ath12k *ar = arvif->ar; - arsta = rcu_dereference(ahsta->link[arvif->link_id]); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + arsta = wiphy_dereference(ath12k_ar_to_hw(ar)->wiphy, + ahsta->link[arvif->link_id]); if (!arsta || arsta->arvif != arvif) return; @@ -11477,6 +11934,61 @@ static void ath12k_mac_disable_peer_fixed_rate(void *data, arsta->addr, ret); } +static bool +ath12k_mac_validate_fixed_rate_settings(struct ath12k *ar, enum nl80211_band band, + const struct cfg80211_bitrate_mask *mask, + unsigned int link_id) +{ + bool he_fixed_rate = false, vht_fixed_rate = false; + const u16 *vht_mcs_mask, *he_mcs_mask; + struct ieee80211_link_sta *link_sta; + struct ath12k_peer *peer, *tmp; + u8 vht_nss, he_nss; + int ret = true; + + vht_mcs_mask = mask->control[band].vht_mcs; + he_mcs_mask = mask->control[band].he_mcs; + + if (ath12k_mac_bitrate_mask_num_vht_rates(ar, band, mask) == 1) + vht_fixed_rate = true; + + if (ath12k_mac_bitrate_mask_num_he_rates(ar, band, mask) == 1) + he_fixed_rate = true; + + if (!vht_fixed_rate && !he_fixed_rate) + return true; + + vht_nss = ath12k_mac_max_vht_nss(vht_mcs_mask); + he_nss = ath12k_mac_max_he_nss(he_mcs_mask); + + rcu_read_lock(); + spin_lock_bh(&ar->ab->base_lock); + list_for_each_entry_safe(peer, tmp, &ar->ab->peers, list) { + if (peer->sta) { + link_sta = rcu_dereference(peer->sta->link[link_id]); + if (!link_sta) { + ret = false; + goto exit; + } + + if (vht_fixed_rate && (!link_sta->vht_cap.vht_supported || + link_sta->rx_nss < vht_nss)) { + ret = false; + goto exit; + } + if (he_fixed_rate && (!link_sta->he_cap.has_he || + link_sta->rx_nss < he_nss)) { + ret = false; + goto exit; + } + } + } +exit: + spin_unlock_bh(&ar->ab->base_lock); + rcu_read_unlock(); + return ret; +} + static int ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -11489,13 +12001,17 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, enum nl80211_band band; const u8 *ht_mcs_mask; const u16 *vht_mcs_mask; + const u16 *he_mcs_mask; + u8 he_ltf = 0; + u8 he_gi = 0; u32 rate; - u8 nss; + u8 nss, mac_nss; u8 sgi; u8 ldpc; int single_nss; int ret; int num_rates; + bool he_fixed_rate = false; lockdep_assert_wiphy(hw->wiphy); @@ -11510,14 +12026,18 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, band = def.chan->band; ht_mcs_mask = mask->control[band].ht_mcs; vht_mcs_mask = mask->control[band].vht_mcs; + he_mcs_mask = mask->control[band].he_mcs; ldpc = !!(ar->ht_cap_info & WMI_HT_CAP_LDPC); sgi = mask->control[band].gi; - if (sgi == NL80211_TXRATE_FORCE_LGI) { + if (sgi == NL80211_TXRATE_FORCE_SGI) { ret = -EINVAL; goto out; } + he_gi = mask->control[band].he_gi; + he_ltf = mask->control[band].he_ltf; + /* mac80211 doesn't support sending a fixed HT/VHT MCS alone, rather it * requires passing at least one of used basic rates along with them. * Fixed rate setting across different preambles(legacy, HT, VHT) is @@ -11534,18 +12054,31 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, arvif->vdev_id, ret); goto out; } + ieee80211_iterate_stations_mtx(hw, ath12k_mac_disable_peer_fixed_rate, arvif); - } else if (ath12k_mac_bitrate_mask_get_single_nss(ar, band, mask, + } else if (ath12k_mac_bitrate_mask_get_single_nss(ar, vif, band, mask, &single_nss)) { rate = WMI_FIXED_RATE_NONE; nss = single_nss; + arvif->bitrate_mask = *mask; + + ieee80211_iterate_stations_atomic(hw, + ath12k_mac_set_bitrate_mask_iter, + arvif); } else { rate = WMI_FIXED_RATE_NONE; - nss = min_t(u32, ar->num_tx_chains, - max(ath12k_mac_max_ht_nss(ht_mcs_mask), - ath12k_mac_max_vht_nss(vht_mcs_mask))); + + if (!ath12k_mac_validate_fixed_rate_settings(ar, band, + mask, arvif->link_id)) + ath12k_warn(ar->ab, + "failed to update fixed rate settings due to mcs/nss incompatibility\n"); + + mac_nss = max3(ath12k_mac_max_ht_nss(ht_mcs_mask), + ath12k_mac_max_vht_nss(vht_mcs_mask), + ath12k_mac_max_he_nss(he_mcs_mask)); + nss = min_t(u32, ar->num_tx_chains, mac_nss); /* If multiple rates across different preambles are given * we can reconfigure this info with all peers using PEER_ASSOC @@ -11577,9 +12110,21 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, */ ath12k_warn(ar->ab, "Setting more than one MCS Value in bitrate mask not supported\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } + num_rates = ath12k_mac_bitrate_mask_num_he_rates(ar, band, mask); + if (num_rates == 1) + he_fixed_rate = true; + + if (!ath12k_mac_he_mcs_range_present(ar, band, mask) && + num_rates > 1) { + ath12k_warn(ar->ab, + "Setting more than one HE MCS Value in bitrate mask not supported\n"); + ret = -EINVAL; + goto out; + } ieee80211_iterate_stations_mtx(hw, ath12k_mac_disable_peer_fixed_rate, arvif); @@ -11590,9 +12135,10 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, arvif); } - ret = ath12k_mac_set_fixed_rate_params(arvif, rate, nss, sgi, ldpc); + ret = ath12k_mac_set_rate_params(arvif, rate, nss, sgi, ldpc, he_gi, + he_ltf, he_fixed_rate); if (ret) { - ath12k_warn(ar->ab, "failed to set fixed rate params on vdev %i: %d\n", + ath12k_warn(ar->ab, "failed to set rate params on vdev %i: %d\n", arvif->vdev_id, ret); } diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 0964ca03069a..59b9e9abf7a8 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -222,6 +222,22 @@ enum WMI_HOST_WLAN_BAND { WMI_HOST_WLAN_2GHZ_5GHZ_CAP = 3, }; +/* Parameters used for WMI_VDEV_PARAM_AUTORATE_MISC_CFG command. + * Used only for HE auto rate mode. + */ +enum { + /* HE LTF related configuration */ + WMI_HE_AUTORATE_LTF_1X = BIT(0), + WMI_HE_AUTORATE_LTF_2X = BIT(1), + WMI_HE_AUTORATE_LTF_4X = BIT(2), + + /* HE GI related configuration */ + WMI_AUTORATE_400NS_GI = BIT(8), + WMI_AUTORATE_800NS_GI = BIT(9), + WMI_AUTORATE_1600NS_GI = BIT(10), + WMI_AUTORATE_3200NS_GI = BIT(11), +}; + enum wmi_cmd_group { /* 0 to 2 are reserved */ WMI_GRP_START = 0x3, @@ -1171,7 +1187,9 @@ enum wmi_tlv_vdev_param { WMI_VDEV_PARAM_HE_RANGE_EXT, WMI_VDEV_PARAM_ENABLE_BCAST_PROBE_RESPONSE, WMI_VDEV_PARAM_FILS_MAX_CHANNEL_GUARD_TIME, + WMI_VDEV_PARAM_HE_LTF = 0x74, WMI_VDEV_PARAM_BA_MODE = 0x7e, + WMI_VDEV_PARAM_AUTORATE_MISC_CFG = 0x80, WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE = 0x87, WMI_VDEV_PARAM_6GHZ_PARAMS = 0x99, WMI_VDEV_PARAM_PROTOTYPE = 0x8000, @@ -3636,6 +3654,15 @@ struct wmi_force_fw_hang_cmd { __le32 delay_time_ms; } __packed; +/* Param values to be sent for WMI_VDEV_PARAM_SGI param_id + * which are used in 11n, 11ac systems + * @WMI_GI_800_NS - Always uses 0.8us (Long GI) + * @WMI_GI_400_NS - Firmware switches between 0.4us (Short GI) + * and 0.8us (Long GI) based on packet error rate. + */ +#define WMI_GI_800_NS 0 +#define WMI_GI_400_NS 1 + struct wmi_vdev_set_param_cmd { __le32 tlv_header; __le32 vdev_id; From dd25a004fb66c60934fa9572298671c1eb1c06c2 Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Mon, 30 Jun 2025 18:04:06 -0700 Subject: [PATCH 039/199] wifi: ath12k: clean up 80P80 support Clean up unused 80P80 references as hardware does not support it. This is applicable to both QCN9274 and WCN7850. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Pradeep Kumar Chitrapu Acked-by: Jeff Johnson Link: https://patch.msgid.link/20250701010408.1257201-8-quic_pradeepc@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 48 ++++++--------------------- drivers/net/wireless/ath/ath12k/wmi.c | 2 -- drivers/net/wireless/ath/ath12k/wmi.h | 1 - 3 files changed, 10 insertions(+), 41 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index aefb620b28e2..8fba1bd2e372 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -209,7 +209,7 @@ ath12k_phymodes[NUM_NL80211_BANDS][ATH12K_CHAN_WIDTH_NUM] = { [NL80211_CHAN_WIDTH_40] = MODE_11BE_EHT40, [NL80211_CHAN_WIDTH_80] = MODE_11BE_EHT80, [NL80211_CHAN_WIDTH_160] = MODE_11BE_EHT160, - [NL80211_CHAN_WIDTH_80P80] = MODE_11BE_EHT80_80, + [NL80211_CHAN_WIDTH_80P80] = MODE_UNKNOWN, [NL80211_CHAN_WIDTH_320] = MODE_11BE_EHT320, }, [NL80211_BAND_6GHZ] = { @@ -220,7 +220,7 @@ ath12k_phymodes[NUM_NL80211_BANDS][ATH12K_CHAN_WIDTH_NUM] = { [NL80211_CHAN_WIDTH_40] = MODE_11BE_EHT40, [NL80211_CHAN_WIDTH_80] = MODE_11BE_EHT80, [NL80211_CHAN_WIDTH_160] = MODE_11BE_EHT160, - [NL80211_CHAN_WIDTH_80P80] = MODE_11BE_EHT80_80, + [NL80211_CHAN_WIDTH_80P80] = MODE_UNKNOWN, [NL80211_CHAN_WIDTH_320] = MODE_11BE_EHT320, }, @@ -2574,17 +2574,6 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar, switch (link_sta->bandwidth) { case IEEE80211_STA_RX_BW_160: - if (he_cap->he_cap_elem.phy_cap_info[0] & - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) { - v = ath12k_peer_assoc_h_he_limit(v, he_mcs_mask); - arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] = v; - - v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80p80); - arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] = v; - - arg->peer_he_mcs_count++; - he_tx_mcs = v; - } v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v; @@ -2871,16 +2860,11 @@ static enum wmi_phy_mode ath12k_mac_get_phymode_vht(struct ath12k *ar, struct ieee80211_link_sta *link_sta) { if (link_sta->bandwidth == IEEE80211_STA_RX_BW_160) { - switch (link_sta->vht_cap.cap & - IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) { - case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: + if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ) return MODE_11AC_VHT160; - case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: - return MODE_11AC_VHT80_80; - default: - /* not sure if this is a valid case? */ - return MODE_11AC_VHT160; - } + + /* not sure if this is a valid case? */ + return MODE_11AC_VHT160; } if (link_sta->bandwidth == IEEE80211_STA_RX_BW_80) @@ -2902,11 +2886,8 @@ static enum wmi_phy_mode ath12k_mac_get_phymode_he(struct ath12k *ar, if (link_sta->he_cap.he_cap_elem.phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) return MODE_11AX_HE160; - else if (link_sta->he_cap.he_cap_elem.phy_cap_info[0] & - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) - return MODE_11AX_HE80_80; - /* not sure if this is a valid case? */ - return MODE_11AX_HE160; + + return MODE_UNKNOWN; } if (link_sta->bandwidth == IEEE80211_STA_RX_BW_80) @@ -2934,14 +2915,10 @@ static enum wmi_phy_mode ath12k_mac_get_phymode_eht(struct ath12k *ar, IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) return MODE_11BE_EHT160; - if (link_sta->he_cap.he_cap_elem.phy_cap_info[0] & - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) - return MODE_11BE_EHT80_80; - ath12k_warn(ar->ab, "invalid EHT PHY capability info for 160 Mhz: %d\n", link_sta->he_cap.he_cap_elem.phy_cap_info[0]); - return MODE_11BE_EHT160; + return MODE_UNKNOWN; } if (link_sta->bandwidth == IEEE80211_STA_RX_BW_80) @@ -7828,8 +7805,6 @@ static void ath12k_mac_set_hemcsmap(struct ath12k *ar, mcs_nss->tx_mcs_80 = cpu_to_le16(txmcs_map & 0xffff); mcs_nss->rx_mcs_160 = cpu_to_le16(rxmcs_map & 0xffff); mcs_nss->tx_mcs_160 = cpu_to_le16(txmcs_map & 0xffff); - mcs_nss->rx_mcs_80p80 = cpu_to_le16(rxmcs_map & 0xffff); - mcs_nss->tx_mcs_80p80 = cpu_to_le16(txmcs_map & 0xffff); } static void ath12k_mac_copy_he_cap(struct ath12k *ar, @@ -7851,6 +7826,7 @@ static void ath12k_mac_copy_he_cap(struct ath12k *ar, IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; + /* 80PLUS80 is not supported */ he_cap_elem->phy_cap_info[0] &= ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G; he_cap_elem->phy_cap_info[5] &= @@ -11541,10 +11517,6 @@ ath12k_mac_has_single_legacy_rate(struct ath12k *ar, static __le16 ath12k_mac_get_tx_mcs_map(const struct ieee80211_sta_he_cap *he_cap) { - if (he_cap->he_cap_elem.phy_cap_info[0] & - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) - return he_cap->he_mcs_nss_supp.tx_mcs_80p80; - if (he_cap->he_cap_elem.phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) return he_cap->he_mcs_nss_supp.tx_mcs_160; diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 6c6354b3e18e..05e406273ebf 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -1066,8 +1066,6 @@ static void ath12k_wmi_put_wmi_channel(struct ath12k_wmi_channel_params *chan, chan->band_center_freq1 = cpu_to_le32(center_freq1 - 40); chan->band_center_freq2 = cpu_to_le32(center_freq1); - } else if (arg->mode == MODE_11BE_EHT80_80) { - chan->band_center_freq2 = cpu_to_le32(arg->band_center_freq2); } else { chan->band_center_freq2 = 0; } diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 59b9e9abf7a8..79cc3db3f27c 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -3804,7 +3804,6 @@ struct wmi_vdev_install_key_arg { #define WMI_HOST_MAX_HE_RATE_SET 3 #define WMI_HECAP_TXRX_MCS_NSS_IDX_80 0 #define WMI_HECAP_TXRX_MCS_NSS_IDX_160 1 -#define WMI_HECAP_TXRX_MCS_NSS_IDX_80_80 2 #define ATH12K_WMI_MLO_MAX_PARTNER_LINKS \ (ATH12K_WMI_MLO_MAX_LINKS + ATH12K_MAX_NUM_BRIDGE_LINKS - 1) From 18ab9d038fadd35d8a4ac5db87ad16dde78f5fdc Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Mon, 30 Jun 2025 18:04:07 -0700 Subject: [PATCH 040/199] wifi: ath12k: add support for 160 MHz bandwidth Add support to configure maximum NSS in 160 MHz bandwidth. Firmware advertises support for handling NSS ratio information as a part of service ready ext event using nss_ratio_enabled flag. Save this information in ath12k_pdev_cap to calculate NSS ratio. Additionally, reorder the code by moving ath12k_peer_assoc_h_phymode() before ath12k_peer_assoc_h_vht() to ensure that arg->peer_phymode correctly reflects the bandwidth in the max NSS calculation. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Co-developed-by: P Praneesh Signed-off-by: P Praneesh Signed-off-by: Pradeep Kumar Chitrapu Acked-by: Jeff Johnson Link: https://patch.msgid.link/20250701010408.1257201-9-quic_pradeepc@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.h | 2 + drivers/net/wireless/ath/ath12k/mac.c | 89 ++++++++++++++++++++++---- drivers/net/wireless/ath/ath12k/mac.h | 2 + drivers/net/wireless/ath/ath12k/wmi.c | 7 +- drivers/net/wireless/ath/ath12k/wmi.h | 21 ++++++ 5 files changed, 108 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 3c10d7eb9669..96ff9b08a848 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -894,6 +894,8 @@ struct ath12k_pdev_cap { struct ath12k_band_cap band[NUM_NL80211_BANDS]; u32 eml_cap; u32 mld_cap; + bool nss_ratio_enabled; + u8 nss_ratio_info; }; struct mlo_timestamp { diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 8fba1bd2e372..c0d58a587d6a 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -2203,6 +2203,34 @@ ath12k_peer_assoc_h_vht_limit(u16 tx_mcs_set, return tx_mcs_set; } +static u8 ath12k_get_nss_160mhz(struct ath12k *ar, + u8 max_nss) +{ + u8 nss_ratio_info = ar->pdev->cap.nss_ratio_info; + u8 max_sup_nss = 0; + + switch (nss_ratio_info) { + case WMI_NSS_RATIO_1BY2_NSS: + max_sup_nss = max_nss >> 1; + break; + case WMI_NSS_RATIO_3BY4_NSS: + ath12k_warn(ar->ab, "WMI_NSS_RATIO_3BY4_NSS not supported\n"); + break; + case WMI_NSS_RATIO_1_NSS: + max_sup_nss = max_nss; + break; + case WMI_NSS_RATIO_2_NSS: + ath12k_warn(ar->ab, "WMI_NSS_RATIO_2_NSS not supported\n"); + break; + default: + ath12k_warn(ar->ab, "invalid nss ratio received from fw: %d\n", + nss_ratio_info); + break; + } + + return max_sup_nss; +} + static void ath12k_peer_assoc_h_vht(struct ath12k *ar, struct ath12k_link_vif *arvif, struct ath12k_link_sta *arsta, @@ -2220,6 +2248,7 @@ static void ath12k_peer_assoc_h_vht(struct ath12k *ar, u8 max_nss, vht_mcs; int i, vht_nss, nss_idx; bool user_rate_valid = true; + u32 rx_nss, tx_nss, nss_160; lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); @@ -2324,10 +2353,24 @@ static void ath12k_peer_assoc_h_vht(struct ath12k *ar, /* TODO: Check */ arg->tx_max_mcs_nss = 0xFF; - ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n", - arsta->addr, arg->peer_max_mpdu, arg->peer_flags); + if (arg->peer_phymode == MODE_11AC_VHT160) { + tx_nss = ath12k_get_nss_160mhz(ar, max_nss); + rx_nss = min(arg->peer_nss, tx_nss); + arg->peer_bw_rxnss_override = ATH12K_BW_NSS_MAP_ENABLE; - /* TODO: rxnss_override */ + if (!rx_nss) { + ath12k_warn(ar->ab, "invalid max_nss\n"); + return; + } + + nss_160 = u32_encode_bits(rx_nss - 1, ATH12K_PEER_RX_NSS_160MHZ); + arg->peer_bw_rxnss_override |= nss_160; + } + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "mac vht peer %pM max_mpdu %d flags 0x%x nss_override 0x%x\n", + arsta->addr, arg->peer_max_mpdu, arg->peer_flags, + arg->peer_bw_rxnss_override); } static int ath12k_mac_get_max_he_mcs_map(u16 mcs_map, int nss) @@ -2420,6 +2463,7 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar, u16 he_tx_mcs = 0, v = 0; int he_nss, nss_idx; bool user_rate_valid = true; + u32 rx_nss, tx_nss, nss_160; if (WARN_ON(ath12k_mac_vif_link_chan(vif, link_id, &def))) return; @@ -2617,9 +2661,25 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar, max_nss = min(max_nss, ar->num_tx_chains); arg->peer_nss = min(link_sta->rx_nss, max_nss); + if (arg->peer_phymode == MODE_11AX_HE160) { + tx_nss = ath12k_get_nss_160mhz(ar, max_nss); + rx_nss = min(arg->peer_nss, tx_nss); + arg->peer_bw_rxnss_override = ATH12K_BW_NSS_MAP_ENABLE; + + if (!rx_nss) { + ath12k_warn(ar->ab, "invalid max_nss\n"); + return; + } + + nss_160 = u32_encode_bits(rx_nss - 1, ATH12K_PEER_RX_NSS_160MHZ); + arg->peer_bw_rxnss_override |= nss_160; + } + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, - "mac he peer %pM nss %d mcs cnt %d\n", - arsta->addr, arg->peer_nss, arg->peer_he_mcs_count); + "mac he peer %pM nss %d mcs cnt %d nss_override 0x%x\n", + arsta->addr, arg->peer_nss, + arg->peer_he_mcs_count, + arg->peer_bw_rxnss_override); } static void ath12k_peer_assoc_h_he_6ghz(struct ath12k *ar, @@ -2860,10 +2920,13 @@ static enum wmi_phy_mode ath12k_mac_get_phymode_vht(struct ath12k *ar, struct ieee80211_link_sta *link_sta) { if (link_sta->bandwidth == IEEE80211_STA_RX_BW_160) { - if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ) + if (link_sta->vht_cap.cap & (IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | + IEEE80211_VHT_CAP_EXT_NSS_BW_MASK)) return MODE_11AC_VHT160; - /* not sure if this is a valid case? */ + /* Allow STA to connect even if it does not explicitly advertise 160 MHz + * support + */ return MODE_11AC_VHT160; } @@ -7575,10 +7638,8 @@ ath12k_create_vht_cap(struct ath12k *ar, u32 rate_cap_tx_chainmask, ath12k_set_vht_txbf_cap(ar, &vht_cap.cap); - /* TODO: Enable back VHT160 mode once association issues are fixed */ - /* Disabling VHT160 and VHT80+80 modes */ - vht_cap.cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK; - vht_cap.cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160; + /* 80P80 is not supported */ + vht_cap.cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; rxmcs_map = 0; txmcs_map = 0; @@ -12974,7 +13035,8 @@ ath12k_mac_setup_radio_iface_comb(struct ath12k *ar, comb[0].radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | BIT(NL80211_CHAN_WIDTH_20) | BIT(NL80211_CHAN_WIDTH_40) | - BIT(NL80211_CHAN_WIDTH_80); + BIT(NL80211_CHAN_WIDTH_80) | + BIT(NL80211_CHAN_WIDTH_160); } return 0; @@ -13356,6 +13418,9 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) ieee80211_hw_set(hw, REPORTS_LOW_ACK); ieee80211_hw_set(hw, NO_VIRTUAL_MONITOR); + if (cap->nss_ratio_enabled) + ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); + if ((ht_cap & WMI_HT_CAP_ENABLED) || is_6ghz) { ieee80211_hw_set(hw, AMPDU_AGGREGATION); ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW); diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h index 9241afe7dc02..18c79d4002cb 100644 --- a/drivers/net/wireless/ath/ath12k/mac.h +++ b/drivers/net/wireless/ath/ath12k/mac.h @@ -41,6 +41,8 @@ struct ath12k_generic_iter { #define IEEE80211_DISABLE_VHT_MCS_SUPPORT_0_11 BIT(24) #define ATH12K_CHAN_WIDTH_NUM 14 +#define ATH12K_BW_NSS_MAP_ENABLE BIT(31) +#define ATH12K_PEER_RX_NSS_160MHZ GENMASK(2, 0) #define ATH12K_TX_POWER_MAX_VAL 70 #define ATH12K_TX_POWER_MIN_VAL 0 diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 05e406273ebf..b34f2c183312 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -537,6 +537,10 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, pdev_cap->he_mcs = le32_to_cpu(mac_caps->he_supp_mcs_5g); pdev_cap->tx_chain_mask = le32_to_cpu(mac_caps->tx_chain_mask_5g); pdev_cap->rx_chain_mask = le32_to_cpu(mac_caps->rx_chain_mask_5g); + pdev_cap->nss_ratio_enabled = + WMI_NSS_RATIO_EN_DIS_GET(mac_caps->nss_ratio); + pdev_cap->nss_ratio_info = + WMI_NSS_RATIO_INFO_GET(mac_caps->nss_ratio); } else { return -EINVAL; } @@ -1059,7 +1063,8 @@ static void ath12k_wmi_put_wmi_channel(struct ath12k_wmi_channel_params *chan, chan->band_center_freq2 = cpu_to_le32(center_freq1); - } else if (arg->mode == MODE_11BE_EHT160) { + } else if (arg->mode == MODE_11BE_EHT160 || + arg->mode == MODE_11AX_HE160) { if (arg->freq > center_freq1) chan->band_center_freq1 = cpu_to_le32(center_freq1 + 40); else diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 79cc3db3f27c..ed9b4324a7b8 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2333,6 +2333,21 @@ enum wmi_direct_buffer_module { WMI_DIRECT_BUF_MAX }; +/** + * enum wmi_nss_ratio - NSS ratio received from FW during service ready ext event + * @WMI_NSS_RATIO_1BY2_NSS: Max nss of 160MHz is equals to half of the max nss of 80MHz + * @WMI_NSS_RATIO_3BY4_NSS: Max nss of 160MHz is equals to 3/4 of the max nss of 80MHz + * @WMI_NSS_RATIO_1_NSS: Max nss of 160MHz is equals to the max nss of 80MHz + * @WMI_NSS_RATIO_2_NSS: Max nss of 160MHz is equals to two times the max nss of 80MHz + */ + +enum wmi_nss_ratio { + WMI_NSS_RATIO_1BY2_NSS, + WMI_NSS_RATIO_3BY4_NSS, + WMI_NSS_RATIO_1_NSS, + WMI_NSS_RATIO_2_NSS +}; + struct ath12k_wmi_pdev_band_arg { u32 pdev_id; u32 start_freq; @@ -2652,6 +2667,12 @@ struct ath12k_wmi_hw_mode_cap_params { } __packed; #define WMI_MAX_HECAP_PHY_SIZE (3) +#define WMI_NSS_RATIO_EN_DIS_BITPOS BIT(0) +#define WMI_NSS_RATIO_EN_DIS_GET(_val) \ + le32_get_bits(_val, WMI_NSS_RATIO_EN_DIS_BITPOS) +#define WMI_NSS_RATIO_INFO_BITPOS GENMASK(4, 1) +#define WMI_NSS_RATIO_INFO_GET(_val) \ + le32_get_bits(_val, WMI_NSS_RATIO_INFO_BITPOS) /* 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. From a82ce08775bc5b50613d48ab7e41b25fc46825af Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Mon, 30 Jun 2025 18:04:08 -0700 Subject: [PATCH 041/199] wifi: ath12k: add extended NSS bandwidth support for 160 MHz Currently rx and tx MCS map for 160 MHz under HE capabilities are not updating properly, when 160 MHz is configured with NSS lesser than max NSS support. Fix this by utilizing nss_ratio_enabled and nss_ratio_info fields sent by firmware in service ready event. However, if firmware advertises EXT NSS BW support in VHT caps as 1(1x2) and when nss_ratio_info indicates 1:1, reset the EXT NSS BW Support in VHT caps to 0 which indicates 1x1. This is to avoid incorrectly choosing 1:2 NSS ratio when using the default VHT caps advertised by firmware. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Pradeep Kumar Chitrapu Acked-by: Jeff Johnson Link: https://patch.msgid.link/20250701010408.1257201-10-quic_pradeepc@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 33 ++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index c0d58a587d6a..6dd4441ce9a0 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -2662,8 +2662,10 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar, arg->peer_nss = min(link_sta->rx_nss, max_nss); if (arg->peer_phymode == MODE_11AX_HE160) { - tx_nss = ath12k_get_nss_160mhz(ar, max_nss); + tx_nss = ath12k_get_nss_160mhz(ar, ar->num_tx_chains); rx_nss = min(arg->peer_nss, tx_nss); + + arg->peer_nss = min(link_sta->rx_nss, ar->num_rx_chains); arg->peer_bw_rxnss_override = ATH12K_BW_NSS_MAP_ENABLE; if (!rx_nss) { @@ -7661,6 +7663,12 @@ ath12k_create_vht_cap(struct ath12k *ar, u32 rate_cap_tx_chainmask, vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(rxmcs_map); vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(txmcs_map); + /* Check if the HW supports 1:1 NSS ratio and reset + * EXT NSS BW Support field to 0 to indicate 1:1 ratio + */ + if (ar->pdev->cap.nss_ratio_info == WMI_NSS_RATIO_1_NSS) + vht_cap.cap &= ~IEEE80211_VHT_CAP_EXT_NSS_BW_MASK; + return vht_cap; } @@ -7843,11 +7851,12 @@ static void ath12k_mac_set_hemcsmap(struct ath12k *ar, struct ieee80211_sta_he_cap *he_cap) { struct ieee80211_he_mcs_nss_supp *mcs_nss = &he_cap->he_mcs_nss_supp; - u16 txmcs_map, rxmcs_map; + u8 maxtxnss_160 = ath12k_get_nss_160mhz(ar, ar->num_tx_chains); + u8 maxrxnss_160 = ath12k_get_nss_160mhz(ar, ar->num_rx_chains); + u16 txmcs_map_160 = 0, rxmcs_map_160 = 0; + u16 txmcs_map = 0, rxmcs_map = 0; u32 i; - rxmcs_map = 0; - txmcs_map = 0; for (i = 0; i < 8; i++) { if (i < ar->num_tx_chains && (ar->cfg_tx_chainmask >> cap->tx_chain_mask_shift) & BIT(i)) @@ -7860,12 +7869,24 @@ static void ath12k_mac_set_hemcsmap(struct ath12k *ar, rxmcs_map |= IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2); else rxmcs_map |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2); + + if (i < maxtxnss_160 && + (ar->cfg_tx_chainmask >> cap->tx_chain_mask_shift) & BIT(i)) + txmcs_map_160 |= IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2); + else + txmcs_map_160 |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2); + + if (i < maxrxnss_160 && + (ar->cfg_tx_chainmask >> cap->tx_chain_mask_shift) & BIT(i)) + rxmcs_map_160 |= IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2); + else + rxmcs_map_160 |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2); } mcs_nss->rx_mcs_80 = cpu_to_le16(rxmcs_map & 0xffff); mcs_nss->tx_mcs_80 = cpu_to_le16(txmcs_map & 0xffff); - mcs_nss->rx_mcs_160 = cpu_to_le16(rxmcs_map & 0xffff); - mcs_nss->tx_mcs_160 = cpu_to_le16(txmcs_map & 0xffff); + mcs_nss->rx_mcs_160 = cpu_to_le16(rxmcs_map_160 & 0xffff); + mcs_nss->tx_mcs_160 = cpu_to_le16(txmcs_map_160 & 0xffff); } static void ath12k_mac_copy_he_cap(struct ath12k *ar, From 34d9a2aa7f5015f69899a8f665b052b8dcf87317 Mon Sep 17 00:00:00 2001 From: Pei Xiao Date: Tue, 24 Jun 2025 10:52:40 +0800 Subject: [PATCH 042/199] wifi: rtw88: coex: Use bitwise instead of arithmetic operator for flags This silences the following coccinelle warning: WARNING: sum of probable bitmasks, consider | Compile tested only. Signed-off-by: Pei Xiao Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/c68a8642c325f626ac34ccee71d9d9aa69f0c92c.1750733428.git.xiaopei01@kylinos.cn --- drivers/net/wireless/realtek/rtw88/coex.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c index 64904278ddad..b4dc6ff2c175 100644 --- a/drivers/net/wireless/realtek/rtw88/coex.c +++ b/drivers/net/wireless/realtek/rtw88/coex.c @@ -1501,28 +1501,28 @@ static u8 rtw_coex_algorithm(struct rtw_dev *rtwdev) algorithm = COEX_ALGO_HFP; break; case BPM_HID: - case BPM_HFP + BPM_HID: + case BPM_HFP | BPM_HID: algorithm = COEX_ALGO_HID; break; - case BPM_HFP + BPM_A2DP: - case BPM_HID + BPM_A2DP: - case BPM_HFP + BPM_HID + BPM_A2DP: + case BPM_HFP | BPM_A2DP: + case BPM_HID | BPM_A2DP: + case BPM_HFP | BPM_HID | BPM_A2DP: algorithm = COEX_ALGO_A2DP_HID; break; - case BPM_HFP + BPM_PAN: - case BPM_HID + BPM_PAN: - case BPM_HFP + BPM_HID + BPM_PAN: + case BPM_HFP | BPM_PAN: + case BPM_HID | BPM_PAN: + case BPM_HFP | BPM_HID | BPM_PAN: algorithm = COEX_ALGO_PAN_HID; break; - case BPM_HFP + BPM_A2DP + BPM_PAN: - case BPM_HID + BPM_A2DP + BPM_PAN: - case BPM_HFP + BPM_HID + BPM_A2DP + BPM_PAN: + case BPM_HFP | BPM_A2DP | BPM_PAN: + case BPM_HID | BPM_A2DP | BPM_PAN: + case BPM_HFP | BPM_HID | BPM_A2DP | BPM_PAN: algorithm = COEX_ALGO_A2DP_PAN_HID; break; case BPM_PAN: algorithm = COEX_ALGO_PAN; break; - case BPM_A2DP + BPM_PAN: + case BPM_A2DP | BPM_PAN: algorithm = COEX_ALGO_A2DP_PAN; break; case BPM_A2DP: From 626afc6cd5369bbf3c4b487ab1bb87a7e5ff0b3b Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 27 Jun 2025 11:51:56 +0800 Subject: [PATCH 043/199] wifi: rtw89: 8851b: rfk: extend DPK path_ok type to u8 Originally the type of path_ok is bool to denote that DPK is ready on certain path and can be enabled. For RTL8851B, hardware design can support more than one calibration set, so use type u8 instead to record the hardware set in current use. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250627035201.16416-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index cdacf100a59a..06ceb77a1cc6 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -5146,7 +5146,7 @@ struct rtw89_dpk_bkup_para { enum rtw89_band band; enum rtw89_bandwidth bw; u8 ch; - bool path_ok; + u8 path_ok; u8 mdpd_en; u8 txagc_dpk; u8 ther_dpk; From 64d0633f1c476ed234355f7dca3c9cf83bb9f38b Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 27 Jun 2025 11:51:57 +0800 Subject: [PATCH 044/199] wifi: rtw89: 8851b: set ADC bandwidth select according to calibration value To handle hardware characteristic of ADC, calibrate the function and add a efuse field to record result, which driver uses it to set proper value accordingly. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250627035201.16416-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/rtw8851b.c | 28 ++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 06ceb77a1cc6..a72cd6e13de2 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3480,6 +3480,7 @@ struct rtw89_efuse { u8 addr[ETH_ALEN]; u8 rfe_type; char country_code[2]; + u8 adc_td; }; struct rtw89_phy_rate_pattern { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index c55833f259de..287d53203b38 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -712,12 +712,22 @@ static void rtw8851b_phycap_parsing_gain_comp(struct rtw89_dev *rtwdev, u8 *phyc gain->comp_valid = valid; } +static void rtw8851b_phycap_parsing_adc_td(struct rtw89_dev *rtwdev, u8 *phycap_map) +{ + u32 phycap_addr = rtwdev->chip->phycap_addr; + struct rtw89_efuse *efuse = &rtwdev->efuse; + const u32 addr_adc_td = 0x5AF; + + efuse->adc_td = phycap_map[addr_adc_td - phycap_addr] & GENMASK(4, 0); +} + static int rtw8851b_read_phycap(struct rtw89_dev *rtwdev, u8 *phycap_map) { rtw8851b_phycap_parsing_tssi(rtwdev, phycap_map); rtw8851b_phycap_parsing_thermal_trim(rtwdev, phycap_map); rtw8851b_phycap_parsing_pa_bias_trim(rtwdev, phycap_map); rtw8851b_phycap_parsing_gain_comp(rtwdev, phycap_map); + rtw8851b_phycap_parsing_adc_td(rtwdev, phycap_map); return 0; } @@ -1083,10 +1093,26 @@ static void rtw8851b_ctrl_ch(struct rtw89_dev *rtwdev, static void rtw8851b_bw_setting(struct rtw89_dev *rtwdev, u8 bw) { + struct rtw89_efuse *efuse = &rtwdev->efuse; + u8 adc_bw_sel; + + switch (efuse->adc_td) { + default: + case 0x19: + adc_bw_sel = 0x4; + break; + case 0x11: + adc_bw_sel = 0x5; + break; + case 0x9: + adc_bw_sel = 0x3; + break; + } + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_CTL, 0x8); rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_EN, 0x2); rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_BW0, 0x2); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1, B_P0_CFCH_BW1, 0x4); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1, B_P0_CFCH_BW1, adc_bw_sel); rtw89_phy_write32_mask(rtwdev, R_DRCK, B_DRCK_MUL, 0xf); rtw89_phy_write32_mask(rtwdev, R_ADCMOD, B_ADCMOD_LP, 0xa); rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ADJ, 0x92); From 408d55331f961b4dbbcaa2edf63999ab2b2e3907 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 27 Jun 2025 11:51:58 +0800 Subject: [PATCH 045/199] wifi: rtw89: 8851b: adjust ADC setting for RF calibration To get expected result of RF calibration at runtime, adjust ADC setting ahead for coming changes of RF calibration. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250627035201.16416-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 287d53203b38..7801732d5b8b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -1109,39 +1109,56 @@ static void rtw8851b_bw_setting(struct rtw89_dev *rtwdev, u8 bw) break; } - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_CTL, 0x8); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_EN, 0x2); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_BW0, 0x2); rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1, B_P0_CFCH_BW1, adc_bw_sel); rtw89_phy_write32_mask(rtwdev, R_DRCK, B_DRCK_MUL, 0xf); rtw89_phy_write32_mask(rtwdev, R_ADCMOD, B_ADCMOD_LP, 0xa); - rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ADJ, 0x92); + rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_RC, 0x3); switch (bw) { case RTW89_CHANNEL_WIDTH_5: + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_CTL, 0x8); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_EN, 0x2); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_BW0, 0x2); rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x1); rtw89_phy_write32_mask(rtwdev, R_WDADC, B_WDADC_SEL, 0x0); rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK_DS, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ADJ, 0x92); break; case RTW89_CHANNEL_WIDTH_10: + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_CTL, 0x8); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_EN, 0x2); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_BW0, 0x2); rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x1); rtw89_phy_write32_mask(rtwdev, R_WDADC, B_WDADC_SEL, 0x1); rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK_DS, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ADJ, 0x92); break; case RTW89_CHANNEL_WIDTH_20: + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_CTL, 0x8); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_EN, 0x2); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_BW0, 0x2); rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x2); rtw89_phy_write32_mask(rtwdev, R_WDADC, B_WDADC_SEL, 0x2); rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK_DS, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ADJ, 0x92); break; case RTW89_CHANNEL_WIDTH_40: + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_CTL, 0x8); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_EN, 0x2); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_BW0, 0x2); rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x2); rtw89_phy_write32_mask(rtwdev, R_WDADC, B_WDADC_SEL, 0x2); rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK_DS, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ADJ, 0x92); break; case RTW89_CHANNEL_WIDTH_80: + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_CTL, 0x8); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_EN, 0x2); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_BW0, 0x2); rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x0); rtw89_phy_write32_mask(rtwdev, R_WDADC, B_WDADC_SEL, 0x2); rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK_DS, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ADJ, 0x92); break; default: rtw89_warn(rtwdev, "Fail to set ADC\n"); From de2a9b2837608945d725d94d8dea44377e2fc291 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 27 Jun 2025 11:51:59 +0800 Subject: [PATCH 046/199] wifi: rtw89: 8851b: update NCTL 0xB To support new commands in DPK 0x11, update NCTL to version 0xB. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250627035201.16416-5-pkshih@realtek.com --- .../wireless/realtek/rtw89/rtw8851b_table.c | 501 +++++++++--------- 1 file changed, 250 insertions(+), 251 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c index 522883c8dfb9..a9c309c245c3 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c @@ -2320,9 +2320,9 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x813c, 0x40000000}, {0x8140, 0x00000000}, {0x8144, 0x0b040b03}, - {0x8148, 0x07020b04}, - {0x814c, 0x07020b04}, - {0x8150, 0xa0a00000}, + {0x8148, 0x07020a04}, + {0x814c, 0x07020a04}, + {0x8150, 0xe4e40000}, {0x8158, 0xffffffff}, {0x815c, 0xffffffff}, {0x8160, 0xffffffff}, @@ -2577,14 +2577,14 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8534, 0x400042fe}, {0x8538, 0x50554200}, {0x853c, 0xb4183000}, - {0x8540, 0xe537a50f}, + {0x8540, 0xe535a50f}, {0x8544, 0xf12bf02b}, {0x8548, 0xf32bf22b}, {0x854c, 0xf62bf42b}, {0x8550, 0xf82bf72b}, {0x8554, 0xfa2bf92b}, {0x8558, 0xfd2bfc2b}, - {0x855c, 0xe537fe2b}, + {0x855c, 0xe535fe2b}, {0x8560, 0xf12af02a}, {0x8564, 0xf32af22a}, {0x8568, 0xf52af42a}, @@ -2653,7 +2653,7 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8664, 0x9700140f}, {0x8668, 0x00017430}, {0x866c, 0xe39ce35e}, - {0x8670, 0xe52a0bbd}, + {0x8670, 0xe5280bbd}, {0x8674, 0xe36a0001}, {0x8678, 0x0001e3c4}, {0x867c, 0x55005b30}, @@ -2664,93 +2664,93 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8690, 0x46100005}, {0x8694, 0x00010004}, {0x8698, 0x30f8e35e}, - {0x869c, 0xe52a0023}, + {0x869c, 0xe5280023}, {0x86a0, 0x54ed0002}, {0x86a4, 0x00230baa}, - {0x86a8, 0x0002e52a}, + {0x86a8, 0x0002e528}, {0x86ac, 0xe356e3e4}, {0x86b0, 0xe35e0001}, {0x86b4, 0x002230f3}, - {0x86b8, 0x0002e52a}, + {0x86b8, 0x0002e528}, {0x86bc, 0x0baa54ec}, - {0x86c0, 0xe52a0022}, + {0x86c0, 0xe5280022}, {0x86c4, 0xe3e40002}, {0x86c8, 0x0001e356}, {0x86cc, 0x0baae35e}, {0x86d0, 0xe3e430ec}, {0x86d4, 0x0001e356}, {0x86d8, 0x6d0f6c67}, - {0x86dc, 0xe52ae39c}, + {0x86dc, 0xe528e39c}, {0x86e0, 0xe39c6c8b}, - {0x86e4, 0x0bace52a}, + {0x86e4, 0x0bace528}, {0x86e8, 0x6d0f6cb3}, - {0x86ec, 0xe52ae39c}, + {0x86ec, 0xe528e39c}, {0x86f0, 0x6cdb0bad}, {0x86f4, 0xe39c6d0f}, - {0x86f8, 0x6cf5e52a}, + {0x86f8, 0x6cf5e528}, {0x86fc, 0xe39c6d0f}, - {0x8700, 0x6c0be52a}, + {0x8700, 0x6c0be528}, {0x8704, 0xe39c6d00}, - {0x8708, 0x6c25e52a}, - {0x870c, 0xe52ae39c}, + {0x8708, 0x6c25e528}, + {0x870c, 0xe528e39c}, {0x8710, 0x6c4df8c6}, - {0x8714, 0xe52ae39c}, + {0x8714, 0xe528e39c}, {0x8718, 0x6c75f9cf}, - {0x871c, 0xe52ae39c}, + {0x871c, 0xe528e39c}, {0x8720, 0xe39c6c99}, - {0x8724, 0xfad6e52a}, + {0x8724, 0xfad6e528}, {0x8728, 0x21e87410}, {0x872c, 0x6e670009}, {0x8730, 0xe3c46f0f}, - {0x8734, 0x7410e52f}, + {0x8734, 0x7410e52d}, {0x8738, 0x000b21e8}, {0x873c, 0xe3c46e8b}, - {0x8740, 0x7410e52f}, + {0x8740, 0x7410e52d}, {0x8744, 0x000d21e8}, {0x8748, 0x6f0f6eb3}, - {0x874c, 0xe52fe3c4}, + {0x874c, 0xe52de3c4}, {0x8750, 0xfe07ff08}, {0x8754, 0x21e87410}, {0x8758, 0x6ec7000e}, - {0x875c, 0xe52fe3c4}, + {0x875c, 0xe52de3c4}, {0x8760, 0x21e87410}, {0x8764, 0x6edb000f}, {0x8768, 0xe3c46f0f}, - {0x876c, 0x7410e52f}, + {0x876c, 0x7410e52d}, {0x8770, 0x001021e8}, {0x8774, 0xe3c46eef}, - {0x8778, 0xff03e52f}, - {0x877c, 0xe52ffe02}, + {0x8778, 0xff03e52d}, + {0x877c, 0xe52dfe02}, {0x8780, 0x21e87410}, {0x8784, 0x6e110013}, {0x8788, 0xe3c46f00}, - {0x878c, 0xff03e52f}, - {0x8790, 0xe52ffe02}, + {0x878c, 0xff03e52d}, + {0x8790, 0xe52dfe02}, {0x8794, 0x21e87410}, {0x8798, 0x6e250014}, - {0x879c, 0xe52fe3c4}, + {0x879c, 0xe52de3c4}, {0x87a0, 0xff08fc24}, {0x87a4, 0x7410fe07}, {0x87a8, 0x001521e8}, {0x87ac, 0xe3c46e39}, - {0x87b0, 0x7410e52f}, + {0x87b0, 0x7410e52d}, {0x87b4, 0x001621e8}, {0x87b8, 0xe3c46e4d}, - {0x87bc, 0xfd27e52f}, + {0x87bc, 0xfd27e52d}, {0x87c0, 0x21e87410}, {0x87c4, 0x6e750018}, - {0x87c8, 0xe52fe3c4}, + {0x87c8, 0xe52de3c4}, {0x87cc, 0x21e87410}, {0x87d0, 0x6e99001a}, - {0x87d4, 0xe52fe3c4}, + {0x87d4, 0xe52de3c4}, {0x87d8, 0xe36afe24}, {0x87dc, 0x63404380}, {0x87e0, 0x43006880}, {0x87e4, 0x31300bac}, - {0x87e8, 0xe52f0022}, + {0x87e8, 0xe52d0022}, {0x87ec, 0x54ec0002}, {0x87f0, 0x00220baa}, - {0x87f4, 0x0002e52f}, + {0x87f4, 0x0002e52d}, {0x87f8, 0xe362e3e4}, {0x87fc, 0xe36a0001}, {0x8800, 0x63404380}, @@ -2770,7 +2770,7 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8838, 0x55010004}, {0x883c, 0x66055b40}, {0x8840, 0x62000007}, - {0x8844, 0xe40e6300}, + {0x8844, 0xe40c6300}, {0x8848, 0x09000004}, {0x884c, 0x0b400a01}, {0x8850, 0x0e010d00}, @@ -2782,13 +2782,13 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8868, 0x00044d01}, {0x886c, 0x00074300}, {0x8870, 0x05a30562}, - {0x8874, 0xe40e961f}, + {0x8874, 0xe40c961f}, {0x8878, 0xe37e0004}, {0x887c, 0x06a20007}, - {0x8880, 0xe40e07a3}, + {0x8880, 0xe40c07a3}, {0x8884, 0xe37e0004}, - {0x8888, 0x0002e3fe}, - {0x888c, 0x4380e406}, + {0x8888, 0x0002e3fc}, + {0x888c, 0x4380e404}, {0x8890, 0x4d000007}, {0x8894, 0x43000004}, {0x8898, 0x000742fe}, @@ -2815,13 +2815,13 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x88ec, 0x42000004}, {0x88f0, 0x00070001}, {0x88f4, 0x62006220}, - {0x88f8, 0x0001e406}, + {0x88f8, 0x0001e404}, {0x88fc, 0x63000007}, {0x8900, 0x09000004}, {0x8904, 0x0e010a00}, {0x8908, 0x00070032}, - {0x890c, 0xe40e06a2}, - {0x8910, 0x0002e41a}, + {0x890c, 0xe40c06a2}, + {0x8910, 0x0002e418}, {0x8914, 0x000742fe}, {0x8918, 0x00044d00}, {0x891c, 0x00014200}, @@ -2839,50 +2839,50 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x894c, 0x00014300}, {0x8950, 0x6c060005}, {0x8954, 0xe2aae298}, - {0x8958, 0xe42ae285}, - {0x895c, 0xe432e2f3}, + {0x8958, 0xe428e285}, + {0x895c, 0xe430e2f3}, {0x8960, 0x0001e30c}, {0x8964, 0x0005e285}, {0x8968, 0xe2986c06}, - {0x896c, 0xe42ae4a9}, - {0x8970, 0xe432e2f3}, + {0x896c, 0xe428e4a7}, + {0x8970, 0xe430e2f3}, {0x8974, 0x0001e30c}, {0x8978, 0x6c000005}, {0x897c, 0xe2aae298}, - {0x8980, 0xe445e285}, - {0x8984, 0xe44de2f3}, + {0x8980, 0xe443e285}, + {0x8984, 0xe44be2f3}, {0x8988, 0x0001e30c}, {0x898c, 0x0005e285}, {0x8990, 0xe2986c00}, - {0x8994, 0xe445e4a9}, - {0x8998, 0xe44de2f3}, + {0x8994, 0xe443e4a7}, + {0x8998, 0xe44be2f3}, {0x899c, 0x0001e30c}, {0x89a0, 0x6c040005}, {0x89a4, 0xe2aae298}, - {0x89a8, 0xe460e285}, - {0x89ac, 0xe468e2f3}, + {0x89a8, 0xe45ee285}, + {0x89ac, 0xe466e2f3}, {0x89b0, 0x0001e30c}, {0x89b4, 0x0005e285}, {0x89b8, 0xe2986c04}, - {0x89bc, 0xe460e4a9}, - {0x89c0, 0xe468e2f3}, + {0x89bc, 0xe45ee4a7}, + {0x89c0, 0xe466e2f3}, {0x89c4, 0x0001e30c}, {0x89c8, 0x6c020005}, {0x89cc, 0xe2aae298}, - {0x89d0, 0xe47be285}, - {0x89d4, 0xe483e2f3}, + {0x89d0, 0xe479e285}, + {0x89d4, 0xe481e2f3}, {0x89d8, 0x0001e30c}, {0x89dc, 0x0005e285}, {0x89e0, 0xe2986c02}, - {0x89e4, 0xe47be4a9}, - {0x89e8, 0xe483e2f3}, + {0x89e4, 0xe479e4a7}, + {0x89e8, 0xe481e2f3}, {0x89ec, 0x0001e30c}, {0x89f0, 0x43800004}, {0x89f4, 0x610a6008}, {0x89f8, 0x63ce6200}, {0x89fc, 0x60800006}, {0x8a00, 0x00047f00}, - {0x8a04, 0xe4e04300}, + {0x8a04, 0xe4de4300}, {0x8a08, 0x00070001}, {0x8a0c, 0x4d015500}, {0x8a10, 0x74200004}, @@ -2895,22 +2895,22 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8a2c, 0x00014300}, {0x8a30, 0x74200004}, {0x8a34, 0x77000005}, - {0x8a38, 0x73887e07}, + {0x8a38, 0x73887e06}, {0x8a3c, 0x8f007380}, {0x8a40, 0x0004140f}, {0x8a44, 0x00057430}, {0x8a48, 0x00017300}, - {0x8a4c, 0x0005e496}, + {0x8a4c, 0x0005e494}, {0x8a50, 0x00017300}, {0x8a54, 0x43800004}, {0x8a58, 0x0006b103}, {0x8a5c, 0x91037cdb}, {0x8a60, 0x40db0007}, {0x8a64, 0x43000004}, - {0x8a68, 0x0005e496}, + {0x8a68, 0x0005e494}, {0x8a6c, 0x00067380}, {0x8a70, 0x60025d01}, - {0x8a74, 0xe4ba6200}, + {0x8a74, 0xe4b86200}, {0x8a78, 0x73000005}, {0x8a7c, 0x76080007}, {0x8a80, 0x00047578}, @@ -2943,8 +2943,8 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8aec, 0x7cdb0006}, {0x8af0, 0x00079103}, {0x8af4, 0x000440db}, - {0x8af8, 0xe4964300}, - {0x8afc, 0xe4ba7e03}, + {0x8af8, 0xe4944300}, + {0x8afc, 0xe4b87e03}, {0x8b00, 0x43800004}, {0x8b04, 0x0006b103}, {0x8b08, 0x91037c5b}, @@ -2976,14 +2976,14 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8b70, 0x43000004}, {0x8b74, 0x73000005}, {0x8b78, 0x76000007}, - {0x8b7c, 0xe4c30001}, + {0x8b7c, 0xe4c10001}, {0x8b80, 0x00040001}, {0x8b84, 0x60004380}, {0x8b88, 0x62016100}, {0x8b8c, 0x00066310}, {0x8b90, 0x00046000}, {0x8b94, 0x00014300}, - {0x8b98, 0x0001e4e0}, + {0x8b98, 0x0001e4de}, {0x8b9c, 0x4e004f02}, {0x8ba0, 0x52015302}, {0x8ba4, 0x140f0001}, @@ -3030,7 +3030,7 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8c48, 0xbf1ae3ac}, {0x8c4c, 0xe36e300b}, {0x8c50, 0xe390e377}, - {0x8c54, 0x0001e523}, + {0x8c54, 0x0001e521}, {0x8c58, 0x54c054bf}, {0x8c5c, 0x54c154a3}, {0x8c60, 0x4c1854a4}, @@ -3039,7 +3039,7 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8c6c, 0xbf051402}, {0x8c70, 0x54a354c1}, {0x8c74, 0xbf011402}, - {0x8c78, 0x54dfe534}, + {0x8c78, 0x54dfe532}, {0x8c7c, 0x54bf0001}, {0x8c80, 0x050a54e5}, {0x8c84, 0x000154df}, @@ -3060,186 +3060,185 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8cc0, 0x56005610}, {0x8cc4, 0x00018c00}, {0x8cc8, 0x57005704}, - {0x8ccc, 0xa7038e00}, - {0x8cd0, 0x33f0aff7}, - {0x8cd4, 0xaf034019}, - {0x8cd8, 0x33f0402b}, - {0x8cdc, 0x33df402b}, - {0x8ce0, 0x57005708}, - {0x8ce4, 0x57818e00}, - {0x8ce8, 0x8e005780}, - {0x8cec, 0x00074380}, - {0x8cf0, 0x5c005c01}, - {0x8cf4, 0x00041403}, - {0x8cf8, 0x00014300}, - {0x8cfc, 0x0007427f}, - {0x8d00, 0x62006280}, - {0x8d04, 0x00049200}, - {0x8d08, 0x00014200}, - {0x8d0c, 0x0007427f}, - {0x8d10, 0x63146394}, - {0x8d14, 0x00049200}, - {0x8d18, 0x00014200}, - {0x8d1c, 0x42fe0004}, - {0x8d20, 0x4d010007}, - {0x8d24, 0x42000004}, - {0x8d28, 0x140f7420}, - {0x8d2c, 0x57005710}, - {0x8d30, 0x0001141f}, - {0x8d34, 0x42fe0004}, - {0x8d38, 0x4d010007}, - {0x8d3c, 0x42000004}, - {0x8d40, 0x140f7420}, - {0x8d44, 0x000742bf}, - {0x8d48, 0x62006240}, - {0x8d4c, 0x0004141f}, - {0x8d50, 0x00014200}, - {0x8d54, 0x5d060006}, - {0x8d58, 0x61046003}, - {0x8d5c, 0x00056201}, - {0x8d60, 0x00017310}, - {0x8d64, 0x43800004}, - {0x8d68, 0x5e010007}, - {0x8d6c, 0x140a5e00}, - {0x8d70, 0x0006b103}, - {0x8d74, 0x91037f07}, - {0x8d78, 0x43070007}, - {0x8d7c, 0x5c000006}, - {0x8d80, 0x5e035d02}, - {0x8d84, 0x43000004}, - {0x8d88, 0x00060001}, - {0x8d8c, 0x60005d04}, - {0x8d90, 0x62016104}, - {0x8d94, 0x73100005}, - {0x8d98, 0x00040001}, - {0x8d9c, 0x00074380}, - {0x8da0, 0x5e005e01}, - {0x8da4, 0xb103140a}, - {0x8da8, 0x7fc60006}, - {0x8dac, 0x00079103}, - {0x8db0, 0x000643c6}, - {0x8db4, 0x5d025c00}, - {0x8db8, 0x00045e03}, - {0x8dbc, 0x00014300}, - {0x8dc0, 0x5d040006}, - {0x8dc4, 0x61046000}, - {0x8dc8, 0x00056201}, - {0x8dcc, 0x00017310}, - {0x8dd0, 0x43800004}, - {0x8dd4, 0x5e010007}, - {0x8dd8, 0x140a5e00}, - {0x8ddc, 0x0006b103}, - {0x8de0, 0x91037fc6}, - {0x8de4, 0x43c60007}, - {0x8de8, 0x5c000006}, - {0x8dec, 0x5e035d02}, - {0x8df0, 0x43000004}, - {0x8df4, 0x00060001}, - {0x8df8, 0x60025d00}, - {0x8dfc, 0x62016100}, - {0x8e00, 0x73000005}, - {0x8e04, 0x00040001}, - {0x8e08, 0x00074380}, - {0x8e0c, 0x5e005e01}, - {0x8e10, 0xb103140a}, - {0x8e14, 0x7fc00006}, - {0x8e18, 0x00079103}, - {0x8e1c, 0x000643c0}, - {0x8e20, 0x5d025c00}, - {0x8e24, 0x00045e03}, - {0x8e28, 0x00014300}, - {0x8e2c, 0x7e020005}, - {0x8e30, 0x42f70004}, - {0x8e34, 0x6c080005}, - {0x8e38, 0x42700004}, - {0x8e3c, 0x73810005}, - {0x8e40, 0x93007380}, - {0x8e44, 0x42f70004}, - {0x8e48, 0x6c000005}, - {0x8e4c, 0x42000004}, - {0x8e50, 0x00040001}, - {0x8e54, 0x00074380}, - {0x8e58, 0x73007304}, - {0x8e5c, 0x72401405}, - {0x8e60, 0x43000004}, - {0x8e64, 0x74040006}, - {0x8e68, 0x40010007}, - {0x8e6c, 0xab004000}, - {0x8e70, 0x0001140f}, - {0x8e74, 0x140ae517}, - {0x8e78, 0x140ae4c3}, - {0x8e7c, 0x0001e51e}, - {0x8e80, 0xe4c3e517}, - {0x8e84, 0x00040001}, - {0x8e88, 0x00047410}, - {0x8e8c, 0x42f04380}, - {0x8e90, 0x62080007}, - {0x8e94, 0x24206301}, - {0x8e98, 0x14c80000}, - {0x8e9c, 0x00002428}, - {0x8ea0, 0x1a4215f4}, - {0x8ea4, 0x6300000b}, - {0x8ea8, 0x42000004}, - {0x8eac, 0x74304300}, - {0x8eb0, 0x4380140f}, - {0x8eb4, 0x73080007}, - {0x8eb8, 0x00047300}, - {0x8ebc, 0x00014300}, - {0x8ec0, 0x4bf00007}, - {0x8ec4, 0x490b4a8f}, - {0x8ec8, 0x4a8e48f1}, - {0x8ecc, 0x48a5490a}, - {0x8ed0, 0x49094a8d}, - {0x8ed4, 0x4a8c487d}, - {0x8ed8, 0x48754908}, - {0x8edc, 0x49074a8b}, - {0x8ee0, 0x4a8a4889}, - {0x8ee4, 0x48b74906}, - {0x8ee8, 0x49054a89}, - {0x8eec, 0x4a8848fc}, - {0x8ef0, 0x48564905}, - {0x8ef4, 0x49044a87}, - {0x8ef8, 0x4a8648c1}, - {0x8efc, 0x483d4904}, - {0x8f00, 0x49034a85}, - {0x8f04, 0x4a8448c7}, - {0x8f08, 0x485e4903}, - {0x8f0c, 0x49024a83}, - {0x8f10, 0x4a8248ac}, - {0x8f14, 0x48624902}, - {0x8f18, 0x49024a81}, - {0x8f1c, 0x4a804820}, - {0x8f20, 0x48004900}, - {0x8f24, 0x49014a90}, - {0x8f28, 0x4a10481f}, - {0x8f2c, 0x00060001}, - {0x8f30, 0x5f005f80}, - {0x8f34, 0x00059900}, - {0x8f38, 0x00017300}, - {0x8f3c, 0x63800006}, - {0x8f40, 0x98006300}, - {0x8f44, 0x549f0001}, - {0x8f48, 0x5c015400}, - {0x8f4c, 0x540054df}, - {0x8f50, 0x00015c02}, - {0x8f54, 0x07145c01}, - {0x8f58, 0x5c025400}, - {0x8f5c, 0x5c020001}, - {0x8f60, 0x54000714}, - {0x8f64, 0x00015c01}, - {0x8f68, 0x4c184c98}, - {0x8f6c, 0x00080001}, - {0x8f70, 0x5c020004}, - {0x8f74, 0x09017430}, - {0x8f78, 0x0ba60c01}, - {0x8f7c, 0x77800005}, - {0x8f80, 0x52200007}, - {0x8f84, 0x43800004}, - {0x8f88, 0x610a6008}, - {0x8f8c, 0x63c26200}, - {0x8f90, 0x5c000007}, - {0x8f94, 0x43000004}, - {0x8f98, 0x00000001}, + {0x8ccc, 0x33ee8e00}, + {0x8cd0, 0xaf034019}, + {0x8cd4, 0x33ee402b}, + {0x8cd8, 0x33df402b}, + {0x8cdc, 0x57005708}, + {0x8ce0, 0x57818e00}, + {0x8ce4, 0x8e005780}, + {0x8ce8, 0x00074380}, + {0x8cec, 0x5c005c01}, + {0x8cf0, 0x00041403}, + {0x8cf4, 0x00014300}, + {0x8cf8, 0x0007427f}, + {0x8cfc, 0x62006280}, + {0x8d00, 0x00049200}, + {0x8d04, 0x00014200}, + {0x8d08, 0x0007427f}, + {0x8d0c, 0x63146394}, + {0x8d10, 0x00049200}, + {0x8d14, 0x00014200}, + {0x8d18, 0x42fe0004}, + {0x8d1c, 0x4d010007}, + {0x8d20, 0x42000004}, + {0x8d24, 0x140f7420}, + {0x8d28, 0x57005710}, + {0x8d2c, 0x0001141f}, + {0x8d30, 0x42fe0004}, + {0x8d34, 0x4d010007}, + {0x8d38, 0x42000004}, + {0x8d3c, 0x140f7420}, + {0x8d40, 0x000742bf}, + {0x8d44, 0x62006240}, + {0x8d48, 0x0004141f}, + {0x8d4c, 0x00014200}, + {0x8d50, 0x5d060006}, + {0x8d54, 0x61046003}, + {0x8d58, 0x00056200}, + {0x8d5c, 0x00017310}, + {0x8d60, 0x43800004}, + {0x8d64, 0x5e010007}, + {0x8d68, 0x140a5e00}, + {0x8d6c, 0x0006b103}, + {0x8d70, 0x91037f07}, + {0x8d74, 0x43070007}, + {0x8d78, 0x5c000006}, + {0x8d7c, 0x5e035d02}, + {0x8d80, 0x43000004}, + {0x8d84, 0x00060001}, + {0x8d88, 0x60005d04}, + {0x8d8c, 0x62006104}, + {0x8d90, 0x73100005}, + {0x8d94, 0x00040001}, + {0x8d98, 0x00074380}, + {0x8d9c, 0x5e005e01}, + {0x8da0, 0xb103140a}, + {0x8da4, 0x7fc60006}, + {0x8da8, 0x00079103}, + {0x8dac, 0x000643c6}, + {0x8db0, 0x5d025c00}, + {0x8db4, 0x00045e03}, + {0x8db8, 0x00014300}, + {0x8dbc, 0x5d040006}, + {0x8dc0, 0x61046000}, + {0x8dc4, 0x00056200}, + {0x8dc8, 0x00017310}, + {0x8dcc, 0x43800004}, + {0x8dd0, 0x5e010007}, + {0x8dd4, 0x140a5e00}, + {0x8dd8, 0x0006b103}, + {0x8ddc, 0x91037fc6}, + {0x8de0, 0x43c60007}, + {0x8de4, 0x5c000006}, + {0x8de8, 0x5e035d02}, + {0x8dec, 0x43000004}, + {0x8df0, 0x00060001}, + {0x8df4, 0x60025d00}, + {0x8df8, 0x62006100}, + {0x8dfc, 0x73000005}, + {0x8e00, 0x00040001}, + {0x8e04, 0x00074380}, + {0x8e08, 0x5e005e01}, + {0x8e0c, 0xb103140a}, + {0x8e10, 0x7fc00006}, + {0x8e14, 0x00079103}, + {0x8e18, 0x000643c0}, + {0x8e1c, 0x5d025c00}, + {0x8e20, 0x00045e03}, + {0x8e24, 0x00014300}, + {0x8e28, 0x7e020005}, + {0x8e2c, 0x42f70004}, + {0x8e30, 0x6c080005}, + {0x8e34, 0x42700004}, + {0x8e38, 0x73810005}, + {0x8e3c, 0x93007380}, + {0x8e40, 0x42f70004}, + {0x8e44, 0x6c000005}, + {0x8e48, 0x42000004}, + {0x8e4c, 0x00040001}, + {0x8e50, 0x00074380}, + {0x8e54, 0x73007304}, + {0x8e58, 0x72401405}, + {0x8e5c, 0x43000004}, + {0x8e60, 0x74040006}, + {0x8e64, 0x40010007}, + {0x8e68, 0xab004000}, + {0x8e6c, 0x0001140f}, + {0x8e70, 0x140ae515}, + {0x8e74, 0x140ae4c1}, + {0x8e78, 0x0001e51c}, + {0x8e7c, 0xe4c1e515}, + {0x8e80, 0x00040001}, + {0x8e84, 0x00047410}, + {0x8e88, 0x42f04380}, + {0x8e8c, 0x62080007}, + {0x8e90, 0x24206301}, + {0x8e94, 0x14c80000}, + {0x8e98, 0x00002428}, + {0x8e9c, 0x1a4215f4}, + {0x8ea0, 0x6300000b}, + {0x8ea4, 0x42000004}, + {0x8ea8, 0x74304300}, + {0x8eac, 0x4380140f}, + {0x8eb0, 0x73080007}, + {0x8eb4, 0x00047300}, + {0x8eb8, 0x00014300}, + {0x8ebc, 0x4bf00007}, + {0x8ec0, 0x490b4a8f}, + {0x8ec4, 0x4a8e48f1}, + {0x8ec8, 0x48a5490a}, + {0x8ecc, 0x49094a8d}, + {0x8ed0, 0x4a8c487d}, + {0x8ed4, 0x48754908}, + {0x8ed8, 0x49074a8b}, + {0x8edc, 0x4a8a4889}, + {0x8ee0, 0x48b74906}, + {0x8ee4, 0x49054a89}, + {0x8ee8, 0x4a8848fc}, + {0x8eec, 0x48564905}, + {0x8ef0, 0x49044a87}, + {0x8ef4, 0x4a8648c1}, + {0x8ef8, 0x483d4904}, + {0x8efc, 0x49034a85}, + {0x8f00, 0x4a8448c7}, + {0x8f04, 0x485e4903}, + {0x8f08, 0x49024a83}, + {0x8f0c, 0x4a8248ac}, + {0x8f10, 0x48624902}, + {0x8f14, 0x49024a81}, + {0x8f18, 0x4a804820}, + {0x8f1c, 0x48004900}, + {0x8f20, 0x49014a90}, + {0x8f24, 0x4a10481f}, + {0x8f28, 0x00060001}, + {0x8f2c, 0x5f005f80}, + {0x8f30, 0x00059900}, + {0x8f34, 0x00017300}, + {0x8f38, 0x63800006}, + {0x8f3c, 0x98006300}, + {0x8f40, 0x549f0001}, + {0x8f44, 0x5c015400}, + {0x8f48, 0x540054df}, + {0x8f4c, 0x00015c02}, + {0x8f50, 0x07145c01}, + {0x8f54, 0x5c025400}, + {0x8f58, 0x5c020001}, + {0x8f5c, 0x54000714}, + {0x8f60, 0x00015c01}, + {0x8f64, 0x4c184c98}, + {0x8f68, 0x00080001}, + {0x8f6c, 0x5c020004}, + {0x8f70, 0x09017430}, + {0x8f74, 0x0ba60c01}, + {0x8f78, 0x77800005}, + {0x8f7c, 0x52200007}, + {0x8f80, 0x43800004}, + {0x8f84, 0x610a6008}, + {0x8f88, 0x63c26200}, + {0x8f8c, 0x5c000007}, + {0x8f90, 0x43000004}, + {0x8f94, 0x00000001}, {0x8080, 0x00000004}, {0x8080, 0x00000000}, {0x8088, 0x00000000}, From 56624544c8a63f85f6811b0c2c090d38ca6ab8dc Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 27 Jun 2025 11:53:28 +0800 Subject: [PATCH 047/199] wifi: rtw89: 8851b: rfk: update DPK to 0x11 Update DPK with TX/RX clock to 960MHz and 1920MHz, which improve performance on certain chips. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250627035328.16577-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 3 + .../net/wireless/realtek/rtw89/rtw8851b_rfk.c | 109 +++++++++++++++--- .../realtek/rtw89/rtw8851b_rfk_table.c | 25 ---- .../realtek/rtw89/rtw8851b_rfk_table.h | 1 - 4 files changed, 98 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 4a65b0c9c2d1..90625d692b4d 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -8775,6 +8775,8 @@ #define B_P0_TSSI_RFC GENMASK(28, 27) #define B_P0_TSSI_OFT_EN BIT(28) #define B_P0_TSSI_OFT GENMASK(7, 0) +#define R_P0_TSSI_SLOPE_CAL 0x581c +#define B_P0_TSSI_SLOPE_CAL_EN BIT(20) #define R_P0_TSSI_AVG 0x5820 #define B_P0_TSSI_EN BIT(31) #define B_P0_TSSI_AVG GENMASK(15, 12) @@ -9268,6 +9270,7 @@ #define B_WDADC_SEL GENMASK(5, 4) #define R_ADCMOD 0xC0E8 #define B_ADCMOD_LP GENMASK(31, 16) +#define B_ADCMOD_AUTO_RST BIT(6) #define R_DCIM 0xC0EC #define B_DCIM_RC GENMASK(23, 16) #define B_DCIM_FR GENMASK(14, 13) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c index f72b3ac6f149..907ce6d3c1b1 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -12,8 +12,8 @@ #include "rtw8851b_rfk_table.h" #include "rtw8851b_table.h" -#define DPK_VER_8851B 0x5 -#define DPK_KIP_REG_NUM_8851B 7 +#define DPK_VER_8851B 0x11 +#define DPK_KIP_REG_NUM_8851B 8 #define DPK_RF_REG_NUM_8851B 4 #define DPK_KSET_NUM 4 #define RTW8851B_RXK_GROUP_NR 4 @@ -85,6 +85,24 @@ enum rf_mode { RF_RXK2 = 0x7, }; +enum adc_ck { + ADC_NA = 0, + ADC_480M = 1, + ADC_960M = 2, + ADC_1920M = 3, +}; + +enum dac_ck { + DAC_40M = 0, + DAC_80M = 1, + DAC_120M = 2, + DAC_160M = 3, + DAC_240M = 4, + DAC_320M = 5, + DAC_480M = 6, + DAC_960M = 7, +}; + static const u32 _tssi_de_cck_long[RF_PATH_NUM_8851B] = {0x5858}; static const u32 _tssi_de_cck_short[RF_PATH_NUM_8851B] = {0x5860}; static const u32 _tssi_de_mcs_20m[RF_PATH_NUM_8851B] = {0x5838}; @@ -116,7 +134,7 @@ static const u32 rtw8851b_backup_rf_regs[] = { #define BACKUP_RF_REGS_NR ARRAY_SIZE(rtw8851b_backup_rf_regs) static const u32 dpk_kip_reg[DPK_KIP_REG_NUM_8851B] = { - 0x813c, 0x8124, 0xc0ec, 0xc0e8, 0xc0c4, 0xc0d4, 0xc0d8}; + 0x813c, 0x8124, 0xc0ec, 0xc0e8, 0xc0c4, 0xc0d4, 0xc0d8, 0x12a0}; static const u32 dpk_rf_reg[DPK_RF_REG_NUM_8851B] = {0xde, 0x8f, 0x5, 0x10005}; static void _set_ch(struct rtw89_dev *rtwdev, u32 val); @@ -163,6 +181,51 @@ static void _rfk_drf_direct_cntrl(struct rtw89_dev *rtwdev, rtw89_write_rf(rtwdev, path, RR_BBDC, RR_BBDC_SEL, 0x0); } +static void _txck_force(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, + bool force, enum dac_ck ck) +{ + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_TXCK_ON, 0x0); + + if (!force) + return; + + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_TXCK_VAL, ck); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_TXCK_ON, 0x1); +} + +static void _rxck_force(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, + bool force, enum adc_ck ck) +{ + static const u32 ck960_8851b[] = {0x8, 0x2, 0x2, 0x4, 0xf, 0xa, 0x93}; + static const u32 ck1920_8851b[] = {0x9, 0x0, 0x0, 0x3, 0xf, 0xa, 0x49}; + const u32 *data; + + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_RXCK_ON, 0x0); + if (!force) + return; + + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_RXCK_VAL, ck); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_RXCK_ON, 0x1); + + switch (ck) { + case ADC_960M: + data = ck960_8851b; + break; + case ADC_1920M: + default: + data = ck1920_8851b; + break; + } + + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 | (path << 8), B_P0_CFCH_CTL, data[0]); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 | (path << 8), B_P0_CFCH_EN, data[1]); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 | (path << 8), B_P0_CFCH_BW0, data[2]); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1 | (path << 8), B_P0_CFCH_BW1, data[3]); + rtw89_phy_write32_mask(rtwdev, R_DRCK | (path << 8), B_DRCK_MUL, data[4]); + rtw89_phy_write32_mask(rtwdev, R_ADCMOD | (path << 8), B_ADCMOD_LP, data[5]); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 8), B_P0_RXCK_ADJ, data[6]); +} + static void _wait_rx_mode(struct rtw89_dev *rtwdev, u8 kpath) { u32 rf_mode; @@ -1794,7 +1857,21 @@ static void _dpk_bb_afe_setting(struct rtw89_dev *rtwdev, enum rtw89_rf_path pat rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, BIT(28 + path), 0x0); rtw89_phy_write32_mask(rtwdev, R_UPD_CLK + (path << 13), MASKDWORD, 0xd801dffd); - rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_bb_afe_defs_tbl); + _txck_force(rtwdev, path, true, DAC_960M); + _rxck_force(rtwdev, path, true, ADC_1920M); + + rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x0); + rtw89_phy_write32_mask(rtwdev, R_ADCMOD, B_ADCMOD_AUTO_RST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x1); + udelay(1); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15, 0x1f); + udelay(10); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15, 0x13); + udelay(2); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_15, 0x0001); + udelay(2); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_15, 0x0041); + udelay(10); rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, BIT(20 + path), 0x1); rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, BIT(28 + path), 0x1); @@ -1827,6 +1904,17 @@ static void _dpk_tssi_pause(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, is_pause ? "pause" : "resume"); } +static +void _dpk_tssi_slope_k_onoff(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, + bool is_on) +{ + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_SLOPE_CAL + (path << 13), + B_P0_TSSI_SLOPE_CAL_EN, is_on); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d TSSI slpoe_k %s\n", path, + str_on_off(is_on)); +} + static void _dpk_tpg_sel(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, u8 kidx) { struct rtw89_dpk_info *dpk = &rtwdev->dpk; @@ -1874,9 +1962,6 @@ static void _dpk_kip_control_rfc(struct rtw89_dev *rtwdev, { rtw89_phy_write32_mask(rtwdev, R_UPD_CLK + (path << 13), B_IQK_RFC_ON, ctrl_by_kip); - - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] RFC is controlled by %s\n", - ctrl_by_kip ? "KIP" : "BB"); } static void _dpk_kip_preset(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, @@ -2279,7 +2364,7 @@ static void _dpk_set_mdpd_para(struct rtw89_dev *rtwdev, u8 order) case 0: /* (5,3,1) */ rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_OP, 0x0); rtw89_phy_write32_mask(rtwdev, R_DPK_IDL, B_DPK_IDL_SEL, 0x2); - rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_PN, 0x4); + rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_PN, 0x3); rtw89_phy_write32_mask(rtwdev, R_MDPK_SYNC, B_MDPK_SYNC_DMAN, 0x1); break; case 1: /* (5,3,0) */ @@ -2315,8 +2400,6 @@ static void _dpk_set_mdpd_para(struct rtw89_dev *rtwdev, u8 order) static void _dpk_idl_mpa(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, enum rtw89_rf_path path, u8 kidx) { - rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_MA, 0x1); - if (rtw89_phy_read32_mask(rtwdev, R_IDL_MPA, B_IDL_MD500) == 0x1) _dpk_set_mdpd_para(rtwdev, 0x2); else if (rtw89_phy_read32_mask(rtwdev, R_IDL_MPA, B_IDL_MD530) == 0x1) @@ -2419,9 +2502,6 @@ static bool _dpk_main(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, u8 init_xdbm = 17; bool is_fail; - if (dpk->bp[path][kidx].band != RTW89_BAND_2G) - init_xdbm = 15; - _dpk_kip_control_rfc(rtwdev, path, false); _rfk_rf_direct_cntrl(rtwdev, path, false); rtw89_write_rf(rtwdev, path, RR_BBDC, RFREG_MASK, 0x03ffd); @@ -2485,6 +2565,7 @@ static void _dpk_cal_select(struct rtw89_dev *rtwdev, bool force, "[DPK] ========= S%d[%d] DPK Start =========\n", path, dpk->cur_idx[path]); + _dpk_tssi_slope_k_onoff(rtwdev, path, false); _dpk_rxagc_onoff(rtwdev, path, false); _rfk_drf_direct_cntrl(rtwdev, path, false); _dpk_bb_afe_setting(rtwdev, path); @@ -2502,7 +2583,7 @@ static void _dpk_cal_select(struct rtw89_dev *rtwdev, bool force, _dpk_reload_rf(rtwdev, dpk_rf_reg, rf_bkup, path); _dpk_bb_afe_restore(rtwdev, path); _dpk_rxagc_onoff(rtwdev, path, true); - + _dpk_tssi_slope_k_onoff(rtwdev, path, true); if (rtwdev->is_tssi_mode[path]) _dpk_tssi_pause(rtwdev, path, false); } diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.c index 0abf7978ccab..38ce03331069 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.c @@ -182,31 +182,6 @@ static const struct rtw89_reg5_def rtw8851b_iqk_macbb_defs[] = { RTW89_DECLARE_RFK_TBL(rtw8851b_iqk_macbb_defs); -static const struct rtw89_reg5_def rtw8851b_iqk_bb_afe_defs[] = { - RTW89_DECL_RFK_WM(0x5670, 0x00004000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00008000, 0x1), - RTW89_DECL_RFK_WM(0x5670, 0x80000000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00007000, 0x7), - RTW89_DECL_RFK_WM(0x5670, 0x00002000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00080000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00070000, 0x3), - RTW89_DECL_RFK_WM(0x5670, 0x60000000, 0x2), - RTW89_DECL_RFK_WM(0xc0d4, 0x00000780, 0x9), - RTW89_DECL_RFK_WM(0xc0d4, 0x00007800, 0x1), - RTW89_DECL_RFK_WM(0xc0d4, 0x0c000000, 0x0), - RTW89_DECL_RFK_WM(0xc0d8, 0x000001e0, 0x3), - RTW89_DECL_RFK_WM(0xc0c4, 0x003e0000, 0xa), - RTW89_DECL_RFK_WM(0xc0ec, 0x00006000, 0x0), - RTW89_DECL_RFK_WM(0xc0e8, 0x00000040, 0x1), - RTW89_DECL_RFK_WM(0x12b8, 0x40000000, 0x1), - RTW89_DECL_RFK_WM(0x030c, MASKBYTE3, 0x1f), - RTW89_DECL_RFK_WM(0x030c, MASKBYTE3, 0x13), - RTW89_DECL_RFK_WM(0x032c, MASKHWORD, 0x0001), - RTW89_DECL_RFK_WM(0x032c, MASKHWORD, 0x0041), -}; - -RTW89_DECLARE_RFK_TBL(rtw8851b_iqk_bb_afe_defs); - static const struct rtw89_reg5_def rtw8851b_tssi_sys_defs[] = { RTW89_DECL_RFK_WM(0x12bc, 0x000ffff0, 0xb5b5), RTW89_DECL_RFK_WM(0x32bc, 0x000ffff0, 0xb5b5), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.h b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.h index febfbecb691c..4fd81456109b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.h @@ -17,7 +17,6 @@ extern const struct rtw89_rfk_tbl rtw8851b_iqk_rxclk_others_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_iqk_txk_2ghz_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_iqk_txk_5ghz_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_iqk_afebb_restore_defs_tbl; -extern const struct rtw89_rfk_tbl rtw8851b_iqk_bb_afe_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_iqk_macbb_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_tssi_sys_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_tssi_sys_a_defs_2g_tbl; From 58f1510a8b6deb9872a23bc636b4859c08518f66 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 27 Jun 2025 11:53:38 +0800 Subject: [PATCH 048/199] wifi: rtw89: 8851b: rfk: update IQK to 0x14 Update IQK along with TX/RX clock to 960MHz and 1920MHz to improve performance. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250627035338.16637-1-pkshih@realtek.com --- .../net/wireless/realtek/rtw89/rtw8851b_rfk.c | 47 +++++++++++++++-- .../realtek/rtw89/rtw8851b_rfk_table.c | 52 ++++++++----------- .../realtek/rtw89/rtw8851b_rfk_table.h | 1 + 3 files changed, 66 insertions(+), 34 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c index 907ce6d3c1b1..7a319a6c838a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -19,7 +19,7 @@ #define RTW8851B_RXK_GROUP_NR 4 #define RTW8851B_RXK_GROUP_IDX_NR 2 #define RTW8851B_TXK_GROUP_NR 1 -#define RTW8851B_IQK_VER 0x2a +#define RTW8851B_IQK_VER 0x14 #define RTW8851B_IQK_SS 1 #define RTW8851B_LOK_GRAM 10 #define RTW8851B_TSSI_PATH_NR 1 @@ -1107,10 +1107,43 @@ static void _iqk_rxclk_setting(struct rtw89_dev *rtwdev, u8 path) rtw89_write_rf(rtwdev, path, RR_RXBB2, RR_RXBB2_CKT, 0x1); - if (iqk_info->iqk_bw[path] == RTW89_CHANNEL_WIDTH_80) + if (iqk_info->iqk_bw[path] == RTW89_CHANNEL_WIDTH_80) { + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, B_ADC_FIFO_RXK, 0x0101); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_DPD_GDIS, 0x1); + + _rxck_force(rtwdev, path, true, ADC_960M); + rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_rxclk_80_defs_tbl); - else + } else { + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, B_ADC_FIFO_RXK, 0x0101); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_DPD_GDIS, 0x1); + + _rxck_force(rtwdev, path, true, ADC_960M); + rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_rxclk_others_defs_tbl); + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, (2)before RXK IQK\n", path); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[07:10] = 0x%x\n", path, + 0xc0d4, rtw89_phy_read32_mask(rtwdev, 0xc0d4, GENMASK(10, 7))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[11:14] = 0x%x\n", path, + 0xc0d4, rtw89_phy_read32_mask(rtwdev, 0xc0d4, GENMASK(14, 11))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[26:27] = 0x%x\n", path, + 0xc0d4, rtw89_phy_read32_mask(rtwdev, 0xc0d4, GENMASK(27, 26))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[05:08] = 0x%x\n", path, + 0xc0d8, rtw89_phy_read32_mask(rtwdev, 0xc0d8, GENMASK(8, 5))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[17:21] = 0x%x\n", path, + 0xc0c4, rtw89_phy_read32_mask(rtwdev, 0xc0c4, GENMASK(21, 17))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[16:31] = 0x%x\n", path, + 0xc0e8, rtw89_phy_read32_mask(rtwdev, 0xc0e8, GENMASK(31, 16))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[04:05] = 0x%x\n", path, + 0xc0e4, rtw89_phy_read32_mask(rtwdev, 0xc0e4, GENMASK(5, 4))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[23:31] = 0x%x\n", path, + 0x12a0, rtw89_phy_read32_mask(rtwdev, 0x12a0, GENMASK(31, 23))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[13:14] = 0x%x\n", path, + 0xc0ec, rtw89_phy_read32_mask(rtwdev, 0xc0ec, GENMASK(14, 13))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[16:23] = 0x%x\n", path, + 0xc0ec, rtw89_phy_read32_mask(rtwdev, 0xc0ec, GENMASK(23, 16))); } static bool _txk_5g_group_sel(struct rtw89_dev *rtwdev, @@ -1616,6 +1649,14 @@ static void _iqk_macbb_setting(struct rtw89_dev *rtwdev, rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_macbb_defs_tbl); + + _txck_force(rtwdev, path, true, DAC_960M); + + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_DPD_GDIS, 0x1); + + _rxck_force(rtwdev, path, true, ADC_1920M); + + rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_macbb_bh_defs_tbl); } static void _iqk_init(struct rtw89_dev *rtwdev) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.c index 38ce03331069..c5f70c045692 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.c @@ -63,16 +63,7 @@ static const struct rtw89_reg5_def rtw8851b_dack_manual_off_defs[] = { RTW89_DECLARE_RFK_TBL(rtw8851b_dack_manual_off_defs); static const struct rtw89_reg5_def rtw8851b_iqk_rxclk_80_defs[] = { - RTW89_DECL_RFK_WM(0x20fc, 0xffff0000, 0x0101), - RTW89_DECL_RFK_WM(0x5670, 0x00002000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00080000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00070000, 0x2), RTW89_DECL_RFK_WM(0x5670, 0x60000000, 0x1), - RTW89_DECL_RFK_WM(0xc0d4, 0x00000780, 0x8), - RTW89_DECL_RFK_WM(0xc0d4, 0x00007800, 0x2), - RTW89_DECL_RFK_WM(0xc0d4, 0x0c000000, 0x2), - RTW89_DECL_RFK_WM(0xc0d8, 0x000001e0, 0x5), - RTW89_DECL_RFK_WM(0xc0c4, 0x003e0000, 0xf), RTW89_DECL_RFK_WM(0xc0ec, 0x00006000, 0x0), RTW89_DECL_RFK_WM(0x12b8, 0x40000000, 0x1), RTW89_DECL_RFK_WM(0x030c, 0xff000000, 0x0f), @@ -85,16 +76,7 @@ static const struct rtw89_reg5_def rtw8851b_iqk_rxclk_80_defs[] = { RTW89_DECLARE_RFK_TBL(rtw8851b_iqk_rxclk_80_defs); static const struct rtw89_reg5_def rtw8851b_iqk_rxclk_others_defs[] = { - RTW89_DECL_RFK_WM(0x20fc, 0xffff0000, 0x0101), - RTW89_DECL_RFK_WM(0x5670, 0x00002000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00080000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00070000, 0x2), RTW89_DECL_RFK_WM(0x5670, 0x60000000, 0x0), - RTW89_DECL_RFK_WM(0xc0d4, 0x00000780, 0x8), - RTW89_DECL_RFK_WM(0xc0d4, 0x00007800, 0x2), - RTW89_DECL_RFK_WM(0xc0d4, 0x0c000000, 0x2), - RTW89_DECL_RFK_WM(0xc0d8, 0x000001e0, 0x5), - RTW89_DECL_RFK_WM(0xc0c4, 0x003e0000, 0xf), RTW89_DECL_RFK_WM(0xc0ec, 0x00006000, 0x2), RTW89_DECL_RFK_WM(0x12b8, 0x40000000, 0x1), RTW89_DECL_RFK_WM(0x030c, 0xff000000, 0x0f), @@ -157,30 +139,38 @@ static const struct rtw89_reg5_def rtw8851b_iqk_macbb_defs[] = { RTW89_DECL_RFK_WM(0x20fc, 0x10000000, 0x0), RTW89_DECL_RFK_WM(0x5670, MASKDWORD, 0xf801fffd), RTW89_DECL_RFK_WM(0x5670, 0x00004000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00008000, 0x1), RTW89_DECL_RFK_WM(0x5670, 0x80000000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00007000, 0x7), - RTW89_DECL_RFK_WM(0x5670, 0x00002000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00080000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00070000, 0x3), +}; + +RTW89_DECLARE_RFK_TBL(rtw8851b_iqk_macbb_defs); + +static const struct rtw89_reg5_def rtw8851b_iqk_macbb_bh_defs[] = { RTW89_DECL_RFK_WM(0x5670, 0x60000000, 0x2), - RTW89_DECL_RFK_WM(0xc0d4, 0x00000780, 0x9), - RTW89_DECL_RFK_WM(0xc0d4, 0x00007800, 0x1), - RTW89_DECL_RFK_WM(0xc0d4, 0x0c000000, 0x0), - RTW89_DECL_RFK_WM(0xc0d8, 0x000001e0, 0x3), - RTW89_DECL_RFK_WM(0xc0c4, 0x003e0000, 0xa), - RTW89_DECL_RFK_WM(0xc0ec, 0x00006000, 0x0), - RTW89_DECL_RFK_WM(0xc0e8, 0x00000040, 0x1), RTW89_DECL_RFK_WM(0x12b8, 0x40000000, 0x1), + RTW89_DECL_RFK_DELAY(2), RTW89_DECL_RFK_WM(0x030c, 0xff000000, 0x1f), + RTW89_DECL_RFK_DELAY(10), RTW89_DECL_RFK_WM(0x030c, 0xff000000, 0x13), + RTW89_DECL_RFK_DELAY(2), RTW89_DECL_RFK_WM(0x032c, 0xffff0000, 0x0001), + RTW89_DECL_RFK_DELAY(2), RTW89_DECL_RFK_WM(0x032c, 0xffff0000, 0x0041), + RTW89_DECL_RFK_DELAY(10), + RTW89_DECL_RFK_WM(0x12b8, 0x40000000, 0x1), + RTW89_DECL_RFK_DELAY(2), + RTW89_DECL_RFK_WM(0x030c, 0xff000000, 0x1f), + RTW89_DECL_RFK_DELAY(10), + RTW89_DECL_RFK_WM(0x030c, 0xff000000, 0x13), + RTW89_DECL_RFK_DELAY(2), + RTW89_DECL_RFK_WM(0x032c, 0xffff0000, 0x0001), + RTW89_DECL_RFK_DELAY(2), + RTW89_DECL_RFK_WM(0x032c, 0xffff0000, 0x0041), + RTW89_DECL_RFK_DELAY(10), RTW89_DECL_RFK_WM(0x20fc, 0x00100000, 0x1), RTW89_DECL_RFK_WM(0x20fc, 0x10000000, 0x1), }; -RTW89_DECLARE_RFK_TBL(rtw8851b_iqk_macbb_defs); +RTW89_DECLARE_RFK_TBL(rtw8851b_iqk_macbb_bh_defs); static const struct rtw89_reg5_def rtw8851b_tssi_sys_defs[] = { RTW89_DECL_RFK_WM(0x12bc, 0x000ffff0, 0xb5b5), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.h b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.h index 4fd81456109b..3f1547f57505 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.h @@ -18,6 +18,7 @@ extern const struct rtw89_rfk_tbl rtw8851b_iqk_txk_2ghz_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_iqk_txk_5ghz_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_iqk_afebb_restore_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_iqk_macbb_defs_tbl; +extern const struct rtw89_rfk_tbl rtw8851b_iqk_macbb_bh_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_tssi_sys_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_tssi_sys_a_defs_2g_tbl; extern const struct rtw89_rfk_tbl rtw8851b_tssi_sys_a_defs_5g_tbl; From 4b6ea5a381979239758a1979cdf29f8d34201110 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:40:58 +0300 Subject: [PATCH 049/199] wifi: rtw89: 8851b: Accept USB devices and load their MAC address Make rtw8851b_read_efuse() accept USB devices and load the MAC address from the correct offset. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/6b2a1382-3be4-4038-8005-cf96922e4332@gmail.com --- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 7801732d5b8b..11584ef6ef48 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -461,14 +461,6 @@ static int rtw8851b_pwr_off_func(struct rtw89_dev *rtwdev) return 0; } -static void rtw8851b_efuse_parsing(struct rtw89_efuse *efuse, - struct rtw8851b_efuse *map) -{ - ether_addr_copy(efuse->addr, map->e.mac_addr); - efuse->rfe_type = map->rfe_type; - efuse->xtal_cap = map->xtal_k; -} - static void rtw8851b_efuse_parsing_tssi(struct rtw89_dev *rtwdev, struct rtw8851b_efuse *map) { @@ -549,12 +541,18 @@ static int rtw8851b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, switch (rtwdev->hci.type) { case RTW89_HCI_TYPE_PCIE: - rtw8851b_efuse_parsing(efuse, map); + ether_addr_copy(efuse->addr, map->e.mac_addr); + break; + case RTW89_HCI_TYPE_USB: + ether_addr_copy(efuse->addr, map->u.mac_addr); break; default: return -EOPNOTSUPP; } + efuse->rfe_type = map->rfe_type; + efuse->xtal_cap = map->xtal_k; + rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); return 0; From ee47816f24a1c07ea31f251546c75b42362d6cef Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:41:34 +0300 Subject: [PATCH 050/199] wifi: rtw89: Make dle_mem in rtw89_chip_info an array USB 2, USB 3, and SDIO will need different sets of values compared to PCIe. Add a new dle_type member in struct rtw89_hci_info and make dle_mem in struct rtw89_chip_info an array to hold the four different sets of values. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/c9152735-dbc4-4473-ae29-a79625cfbf78@gmail.com --- drivers/net/wireless/realtek/rtw89/core.h | 12 +++++++++++- drivers/net/wireless/realtek/rtw89/mac.c | 7 ++++--- drivers/net/wireless/realtek/rtw89/pci.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8851b.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8852a.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8852bt.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8852c.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 2 +- 9 files changed, 22 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index a72cd6e13de2..bf32b4eb41dd 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -132,6 +132,15 @@ enum rtw89_hci_type { RTW89_HCI_TYPE_SDIO, }; +enum rtw89_hci_dle_type { + RTW89_HCI_DLE_TYPE_PCIE, + RTW89_HCI_DLE_TYPE_USB2, + RTW89_HCI_DLE_TYPE_USB3, + RTW89_HCI_DLE_TYPE_SDIO, + + RTW89_HCI_DLE_TYPE_NUM, +}; + enum rtw89_core_chip_id { RTL8852A, RTL8852B, @@ -3660,6 +3669,7 @@ struct rtw89_hci_ops { struct rtw89_hci_info { const struct rtw89_hci_ops *ops; enum rtw89_hci_type type; + enum rtw89_hci_dle_type dle_type; u32 rpwm_addr; u32 cpwm_addr; bool paused; @@ -4359,7 +4369,7 @@ struct rtw89_chip_info { bool dis_2g_40m_ul_ofdma; u32 rsvd_ple_ofst; const struct rtw89_hfc_param_ini *hfc_param_ini; - const struct rtw89_dle_mem *dle_mem; + const struct rtw89_dle_mem *dle_mem[RTW89_HCI_DLE_TYPE_NUM]; u8 wde_qempty_acq_grpnum; u8 wde_qempty_mgq_grpsel; u32 rf_base_addr[2]; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 53628838a7c5..8e7ce45207da 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1717,12 +1717,13 @@ static const struct rtw89_dle_mem *get_dle_mem_cfg(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode) { struct rtw89_mac_info *mac = &rtwdev->mac; - const struct rtw89_dle_mem *cfg; + const struct rtw89_dle_mem *cfg, *cfgs; - cfg = &rtwdev->chip->dle_mem[mode]; - if (!cfg) + cfgs = rtwdev->chip->dle_mem[rtwdev->hci.dle_type]; + if (!cfgs) return NULL; + cfg = &cfgs[mode]; if (cfg->mode != mode) { rtw89_warn(rtwdev, "qta mode unmatch!\n"); return NULL; diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 204a3748d913..597de632e364 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -4486,6 +4486,7 @@ int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) rtwdev->pci_info = info->bus.pci; rtwdev->hci.ops = &rtw89_pci_ops; rtwdev->hci.type = RTW89_HCI_TYPE_PCIE; + rtwdev->hci.dle_type = RTW89_HCI_DLE_TYPE_PCIE; rtwdev->hci.rpwm_addr = pci_info->rpwm_addr; rtwdev->hci.cpwm_addr = pci_info->cpwm_addr; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 11584ef6ef48..daec656341af 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2509,7 +2509,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, .hfc_param_ini = rtw8851b_hfc_param_ini_pcie, - .dle_mem = rtw8851b_dle_mem_pcie, + .dle_mem = {rtw8851b_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000}, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 080636e8d0c3..8bf222bdb927 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2185,7 +2185,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x6f800, .hfc_param_ini = rtw8852a_hfc_param_ini_pcie, - .dle_mem = rtw8852a_dle_mem_pcie, + .dle_mem = {rtw8852a_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 16, .wde_qempty_mgq_grpsel = 16, .rf_base_addr = {0xc000, 0xd000}, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index c0bf80450acf..a6faae0d031a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -821,7 +821,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, .hfc_param_ini = rtw8852b_hfc_param_ini_pcie, - .dle_mem = rtw8852b_dle_mem_pcie, + .dle_mem = {rtw8852b_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000, 0xf000}, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c index 95e088734423..f536181bfb66 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c @@ -755,7 +755,7 @@ const struct rtw89_chip_info rtw8852bt_chip_info = { .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x6f800, .hfc_param_ini = rtw8852bt_hfc_param_ini_pcie, - .dle_mem = rtw8852bt_dle_mem_pcie, + .dle_mem = {rtw8852bt_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000, 0xf000}, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 8f3d0c91a3f8..67db480940b3 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -3005,7 +3005,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .dis_2g_40m_ul_ofdma = false, .rsvd_ple_ofst = 0x6f800, .hfc_param_ini = rtw8852c_hfc_param_ini_pcie, - .dle_mem = rtw8852c_dle_mem_pcie, + .dle_mem = {rtw8852c_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 16, .wde_qempty_mgq_grpsel = 16, .rf_base_addr = {0xe000, 0xf000}, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 603212ed4558..09dbe4008b89 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -2860,7 +2860,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .dis_2g_40m_ul_ofdma = false, .rsvd_ple_ofst = 0x8f800, .hfc_param_ini = rtw8922a_hfc_param_ini_pcie, - .dle_mem = rtw8922a_dle_mem_pcie, + .dle_mem = {rtw8922a_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000, 0xf000}, From 82870ba25f32b8f38fb882ce1336789f11bae969 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:42:01 +0300 Subject: [PATCH 051/199] wifi: rtw89: Make hfc_param_ini in rtw89_chip_info an array USB and SDIO will need different sets of values, so make hfc_param_ini in struct rtw89_chip_info an array. Also make param_ini a pointer instead of copying the struct. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/1356f901-9ebf-451e-827f-50dd3efda534@gmail.com --- drivers/net/wireless/realtek/rtw89/core.h | 4 ++- drivers/net/wireless/realtek/rtw89/mac.c | 29 +++++++++---------- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8852a.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 2 +- .../net/wireless/realtek/rtw89/rtw8852bt.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8852c.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 2 +- 8 files changed, 23 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index bf32b4eb41dd..3057ab3d2e7d 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -130,6 +130,8 @@ enum rtw89_hci_type { RTW89_HCI_TYPE_PCIE, RTW89_HCI_TYPE_USB, RTW89_HCI_TYPE_SDIO, + + RTW89_HCI_TYPE_NUM, }; enum rtw89_hci_dle_type { @@ -4368,7 +4370,7 @@ struct rtw89_chip_info { u16 max_amsdu_limit; bool dis_2g_40m_ul_ofdma; u32 rsvd_ple_ofst; - const struct rtw89_hfc_param_ini *hfc_param_ini; + const struct rtw89_hfc_param_ini *hfc_param_ini[RTW89_HCI_TYPE_NUM]; const struct rtw89_dle_mem *dle_mem[RTW89_HCI_DLE_TYPE_NUM]; u8 wde_qempty_acq_grpnum; u8 wde_qempty_mgq_grpsel; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 8e7ce45207da..4432b03e8f7a 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -875,31 +875,30 @@ EXPORT_SYMBOL(rtw89_mac_set_err_status); static int hfc_reset_param(struct rtw89_dev *rtwdev) { + const struct rtw89_hfc_param_ini *param_ini, *param_inis; struct rtw89_hfc_param *param = &rtwdev->mac.hfc_param; - struct rtw89_hfc_param_ini param_ini = {NULL}; u8 qta_mode = rtwdev->mac.dle_info.qta_mode; - switch (rtwdev->hci.type) { - case RTW89_HCI_TYPE_PCIE: - param_ini = rtwdev->chip->hfc_param_ini[qta_mode]; - param->en = 0; - break; - default: + param_inis = rtwdev->chip->hfc_param_ini[rtwdev->hci.type]; + if (!param_inis) return -EINVAL; - } - if (param_ini.pub_cfg) - param->pub_cfg = *param_ini.pub_cfg; + param_ini = ¶m_inis[qta_mode]; - if (param_ini.prec_cfg) - param->prec_cfg = *param_ini.prec_cfg; + param->en = 0; - if (param_ini.ch_cfg) - param->ch_cfg = param_ini.ch_cfg; + if (param_ini->pub_cfg) + param->pub_cfg = *param_ini->pub_cfg; + + if (param_ini->prec_cfg) + param->prec_cfg = *param_ini->prec_cfg; + + if (param_ini->ch_cfg) + param->ch_cfg = param_ini->ch_cfg; memset(¶m->ch_info, 0, sizeof(param->ch_info)); memset(¶m->pub_info, 0, sizeof(param->pub_info)); - param->mode = param_ini.mode; + param->mode = param_ini->mode; return 0; } diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index daec656341af..b678edb00c03 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2508,7 +2508,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .max_amsdu_limit = 3500, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, - .hfc_param_ini = rtw8851b_hfc_param_ini_pcie, + .hfc_param_ini = {rtw8851b_hfc_param_ini_pcie, NULL, NULL}, .dle_mem = {rtw8851b_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 8bf222bdb927..0496deb7278f 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2184,7 +2184,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .max_amsdu_limit = 3500, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x6f800, - .hfc_param_ini = rtw8852a_hfc_param_ini_pcie, + .hfc_param_ini = {rtw8852a_hfc_param_ini_pcie, NULL, NULL}, .dle_mem = {rtw8852a_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 16, .wde_qempty_mgq_grpsel = 16, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index a6faae0d031a..b0b73a4a70a0 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -820,7 +820,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .max_amsdu_limit = 5000, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, - .hfc_param_ini = rtw8852b_hfc_param_ini_pcie, + .hfc_param_ini = {rtw8852b_hfc_param_ini_pcie, NULL, NULL}, .dle_mem = {rtw8852b_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c index f536181bfb66..10d09c12f318 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c @@ -754,7 +754,7 @@ const struct rtw89_chip_info rtw8852bt_chip_info = { .max_amsdu_limit = 5000, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x6f800, - .hfc_param_ini = rtw8852bt_hfc_param_ini_pcie, + .hfc_param_ini = {rtw8852bt_hfc_param_ini_pcie, NULL, NULL}, .dle_mem = {rtw8852bt_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 67db480940b3..6e27f1ff94dc 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -3004,7 +3004,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .max_amsdu_limit = 8000, .dis_2g_40m_ul_ofdma = false, .rsvd_ple_ofst = 0x6f800, - .hfc_param_ini = rtw8852c_hfc_param_ini_pcie, + .hfc_param_ini = {rtw8852c_hfc_param_ini_pcie, NULL, NULL}, .dle_mem = {rtw8852c_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 16, .wde_qempty_mgq_grpsel = 16, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 09dbe4008b89..e23655f3e4c1 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -2859,7 +2859,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .max_amsdu_limit = 8000, .dis_2g_40m_ul_ofdma = false, .rsvd_ple_ofst = 0x8f800, - .hfc_param_ini = rtw8922a_hfc_param_ini_pcie, + .hfc_param_ini = {rtw8922a_hfc_param_ini_pcie, NULL, NULL}, .dle_mem = {rtw8922a_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, From 3c63450c872300546f2454e5972719dc725f8416 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:42:24 +0300 Subject: [PATCH 052/199] wifi: rtw89: Add rtw8851b_dle_mem_usb{2,3} Add rtw8851b_dle_mem_usb2 and rtw8851b_dle_mem_usb3 and their various quotas and sizes in struct rtw89_mac_size_set. "dle" could be "Data Link Engine" or "Double Link Engine". These are some parameters needed for RTL8851BU. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/91622304-614e-4e91-bf2f-7688cf44070b@gmail.com --- drivers/net/wireless/realtek/rtw89/mac.c | 15 +++++++++ drivers/net/wireless/realtek/rtw89/mac.h | 8 +++++ drivers/net/wireless/realtek/rtw89/rtw8851b.c | 31 ++++++++++++++++++- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 4432b03e8f7a..4c469379be6e 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1645,6 +1645,8 @@ const struct rtw89_mac_size_set rtw89_mac_size = { /* 8852C PCIE SCC */ .wde_size19 = {RTW89_WDE_PG_64, 3328, 0,}, .wde_size23 = {RTW89_WDE_PG_64, 1022, 2,}, + /* 8852B USB2.0/USB3.0 SCC */ + .wde_size25 = {RTW89_WDE_PG_64, 162, 94,}, /* PCIE */ .ple_size0 = {RTW89_PLE_PG_128, 1520, 16,}, .ple_size0_v1 = {RTW89_PLE_PG_128, 2688, 240, 212992,}, @@ -1660,6 +1662,10 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .ple_size18 = {RTW89_PLE_PG_128, 2544, 16,}, /* 8852C PCIE SCC */ .ple_size19 = {RTW89_PLE_PG_128, 1904, 16,}, + /* 8852B USB2.0 SCC */ + .ple_size32 = {RTW89_PLE_PG_128, 620, 20,}, + /* 8852B USB3.0 SCC */ + .ple_size33 = {RTW89_PLE_PG_128, 632, 8,}, /* PCIE 64 */ .wde_qt0 = {3792, 196, 0, 107,}, .wde_qt0_v1 = {3302, 6, 0, 20,}, @@ -1674,6 +1680,8 @@ const struct rtw89_mac_size_set rtw89_mac_size = { /* 8852C PCIE SCC */ .wde_qt18 = {3228, 60, 0, 40,}, .wde_qt23 = {958, 48, 0, 16,}, + /* 8852B USB2.0/USB3.0 SCC */ + .wde_qt25 = {152, 2, 0, 8,}, .ple_qt0 = {320, 320, 32, 16, 13, 13, 292, 292, 64, 18, 1, 4, 0,}, .ple_qt1 = {320, 320, 32, 16, 1316, 1316, 1595, 1595, 1367, 1321, 1, 1307, 0,}, /* PCIE SCC */ @@ -1697,6 +1705,13 @@ const struct rtw89_mac_size_set rtw89_mac_size = { /* PCIE 64 */ .ple_qt58 = {147, 0, 16, 20, 157, 13, 229, 0, 172, 14, 24, 0,}, .ple_qt59 = {147, 0, 32, 20, 1860, 13, 2025, 0, 1879, 14, 24, 0,}, + /* USB2.0 52B SCC */ + .ple_qt72 = {130, 0, 16, 48, 4, 13, 322, 0, 32, 14, 8, 0, 0,}, + /* USB2.0 52B 92K */ + .ple_qt73 = {130, 0, 32, 48, 37, 13, 355, 0, 65, 14, 24, 0, 0,}, + /* USB3.0 52B 92K */ + .ple_qt74 = {286, 0, 16, 48, 4, 13, 178, 0, 32, 14, 8, 0, 0,}, + .ple_qt75 = {286, 0, 32, 48, 37, 13, 211, 0, 65, 14, 24, 0, 0,}, /* 8852A PCIE WOW */ .ple_qt_52a_wow = {264, 0, 32, 20, 64, 13, 1005, 0, 64, 128, 120,}, /* 8852B PCIE WOW */ diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index b7fd4a0fdb84..9f596a06b3d0 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -924,6 +924,7 @@ struct rtw89_mac_size_set { const struct rtw89_dle_size wde_size18; const struct rtw89_dle_size wde_size19; const struct rtw89_dle_size wde_size23; + const struct rtw89_dle_size wde_size25; const struct rtw89_dle_size ple_size0; const struct rtw89_dle_size ple_size0_v1; const struct rtw89_dle_size ple_size3_v1; @@ -933,6 +934,8 @@ struct rtw89_mac_size_set { const struct rtw89_dle_size ple_size9; const struct rtw89_dle_size ple_size18; const struct rtw89_dle_size ple_size19; + const struct rtw89_dle_size ple_size32; + const struct rtw89_dle_size ple_size33; const struct rtw89_wde_quota wde_qt0; const struct rtw89_wde_quota wde_qt0_v1; const struct rtw89_wde_quota wde_qt4; @@ -941,6 +944,7 @@ struct rtw89_mac_size_set { const struct rtw89_wde_quota wde_qt17; const struct rtw89_wde_quota wde_qt18; const struct rtw89_wde_quota wde_qt23; + const struct rtw89_wde_quota wde_qt25; const struct rtw89_ple_quota ple_qt0; const struct rtw89_ple_quota ple_qt1; const struct rtw89_ple_quota ple_qt4; @@ -955,6 +959,10 @@ struct rtw89_mac_size_set { const struct rtw89_ple_quota ple_qt57; const struct rtw89_ple_quota ple_qt58; const struct rtw89_ple_quota ple_qt59; + const struct rtw89_ple_quota ple_qt72; + const struct rtw89_ple_quota ple_qt73; + const struct rtw89_ple_quota ple_qt74; + const struct rtw89_ple_quota ple_qt75; const struct rtw89_ple_quota ple_qt_52a_wow; const struct rtw89_ple_quota ple_qt_52b_wow; const struct rtw89_ple_quota ple_qt_52bt_wow; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index b678edb00c03..5cdc42ee59a3 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -68,6 +68,32 @@ static const struct rtw89_dle_mem rtw8851b_dle_mem_pcie[] = { NULL}, }; +static const struct rtw89_dle_mem rtw8851b_dle_mem_usb2[] = { + [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size25, + &rtw89_mac_size.ple_size32, &rtw89_mac_size.wde_qt25, + &rtw89_mac_size.wde_qt25, &rtw89_mac_size.ple_qt72, + &rtw89_mac_size.ple_qt73}, + [RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size9, + &rtw89_mac_size.ple_size8, &rtw89_mac_size.wde_qt4, + &rtw89_mac_size.wde_qt4, &rtw89_mac_size.ple_qt13, + &rtw89_mac_size.ple_qt13}, + [RTW89_QTA_INVALID] = {RTW89_QTA_INVALID, NULL, NULL, NULL, NULL, NULL, + NULL}, +}; + +static const struct rtw89_dle_mem rtw8851b_dle_mem_usb3[] = { + [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size25, + &rtw89_mac_size.ple_size33, &rtw89_mac_size.wde_qt25, + &rtw89_mac_size.wde_qt25, &rtw89_mac_size.ple_qt74, + &rtw89_mac_size.ple_qt75}, + [RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size9, + &rtw89_mac_size.ple_size8, &rtw89_mac_size.wde_qt4, + &rtw89_mac_size.wde_qt4, &rtw89_mac_size.ple_qt13, + &rtw89_mac_size.ple_qt13}, + [RTW89_QTA_INVALID] = {RTW89_QTA_INVALID, NULL, NULL, NULL, NULL, NULL, + NULL}, +}; + static const struct rtw89_reg3_def rtw8851b_btc_preagc_en_defs[] = { {0x46D0, GENMASK(1, 0), 0x3}, {0x4AD4, GENMASK(31, 0), 0xf}, @@ -2509,7 +2535,10 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, .hfc_param_ini = {rtw8851b_hfc_param_ini_pcie, NULL, NULL}, - .dle_mem = {rtw8851b_dle_mem_pcie, NULL, NULL, NULL}, + .dle_mem = {rtw8851b_dle_mem_pcie, + rtw8851b_dle_mem_usb2, + rtw8851b_dle_mem_usb3, + NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000}, From 02a44c2630318b880d49000f151a6d1e450e76e2 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:42:55 +0300 Subject: [PATCH 053/199] wifi: rtw89: Add rtw8851b_hfc_param_ini_usb "hfc" means "hci fc" which is "Host Control Interface Flow Control". These are some parameters needed for RTL8851BU. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/a0dec631-de05-4302-9ef1-e730eb233f08@gmail.com --- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 5cdc42ee59a3..ad41c8bf39fc 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -51,6 +51,48 @@ static const struct rtw89_hfc_param_ini rtw8851b_hfc_param_ini_pcie[] = { [RTW89_QTA_INVALID] = {NULL}, }; +static const struct rtw89_hfc_ch_cfg rtw8851b_hfc_chcfg_usb[] = { + {18, 152, grp_0}, /* ACH 0 */ + {18, 152, grp_0}, /* ACH 1 */ + {18, 152, grp_0}, /* ACH 2 */ + {18, 152, grp_0}, /* ACH 3 */ + {0, 0, grp_0}, /* ACH 4 */ + {0, 0, grp_0}, /* ACH 5 */ + {0, 0, grp_0}, /* ACH 6 */ + {0, 0, grp_0}, /* ACH 7 */ + {18, 152, grp_0}, /* B0MGQ */ + {18, 152, grp_0}, /* B0HIQ */ + {0, 0, grp_0}, /* B1MGQ */ + {0, 0, grp_0}, /* B1HIQ */ + {0, 0, 0} /* FWCMDQ */ +}; + +static const struct rtw89_hfc_pub_cfg rtw8851b_hfc_pubcfg_usb = { + 152, /* Group 0 */ + 0, /* Group 1 */ + 152, /* Public Max */ + 0 /* WP threshold */ +}; + +static const struct rtw89_hfc_prec_cfg rtw8851b_hfc_preccfg_usb = { + 9, /* CH 0-11 pre-cost */ + 32, /* H2C pre-cost */ + 64, /* WP CH 0-7 pre-cost */ + 24, /* WP CH 8-11 pre-cost */ + 1, /* CH 0-11 full condition */ + 1, /* H2C full condition */ + 1, /* WP CH 0-7 full condition */ + 1, /* WP CH 8-11 full condition */ +}; + +static const struct rtw89_hfc_param_ini rtw8851b_hfc_param_ini_usb[] = { + [RTW89_QTA_SCC] = {rtw8851b_hfc_chcfg_usb, &rtw8851b_hfc_pubcfg_usb, + &rtw8851b_hfc_preccfg_usb, RTW89_HCIFC_STF}, + [RTW89_QTA_DLFW] = {NULL, NULL, + &rtw8851b_hfc_preccfg_usb, RTW89_HCIFC_STF}, + [RTW89_QTA_INVALID] = {NULL}, +}; + static const struct rtw89_dle_mem rtw8851b_dle_mem_pcie[] = { [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size6, &rtw89_mac_size.ple_size6, &rtw89_mac_size.wde_qt6, @@ -2534,7 +2576,9 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .max_amsdu_limit = 3500, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, - .hfc_param_ini = {rtw8851b_hfc_param_ini_pcie, NULL, NULL}, + .hfc_param_ini = {rtw8851b_hfc_param_ini_pcie, + rtw8851b_hfc_param_ini_usb, + NULL}, .dle_mem = {rtw8851b_dle_mem_pcie, rtw8851b_dle_mem_usb2, rtw8851b_dle_mem_usb3, From a3b871a0f7c083c2a632a31da8bc3de554ae8550 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:43:25 +0300 Subject: [PATCH 054/199] wifi: rtw89: Disable deep power saving for USB/SDIO Disable deep power saving for USB and SDIO because rtw89_mac_send_rpwm() is called in atomic context and accessing hardware registers results in "scheduling while atomic" errors. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/0f49eceb-0de0-47e2-ba36-3c6a0dddd17d@gmail.com --- drivers/net/wireless/realtek/rtw89/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 1f5639a5d166..fe6b19a078c5 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -2884,6 +2884,9 @@ static enum rtw89_ps_mode rtw89_update_ps_mode(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; + if (rtwdev->hci.type != RTW89_HCI_TYPE_PCIE) + return RTW89_PS_MODE_NONE; + if (rtw89_disable_ps_mode || !chip->ps_mode_supported || RTW89_CHK_FW_FEATURE(NO_DEEP_PS, &rtwdev->fw)) return RTW89_PS_MODE_NONE; From ec542d5e4bf660463d8d578ecebb511cbfe66558 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:44:28 +0300 Subject: [PATCH 055/199] wifi: rtw89: Add extra TX headroom for USB In the case of USB the TX descriptor is transmitted in the same buffer as the 802.11 frame, so add the required headroom. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/91fb7579-60e5-4a06-8007-3312639beea6@gmail.com --- drivers/net/wireless/realtek/rtw89/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index fe6b19a078c5..776d2e5ce8a0 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -5591,6 +5591,9 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) int ret; int tx_headroom = IEEE80211_HT_CTL_LEN; + if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) + tx_headroom += chip->txwd_body_size + chip->txwd_info_size; + hw->vif_data_size = struct_size_t(struct rtw89_vif, links_inst, n); hw->sta_data_size = struct_size_t(struct rtw89_sta, links_inst, n); hw->txq_data_size = sizeof(struct rtw89_txq); From 0740c6beefae03066a562e3047959528d8893709 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:45:02 +0300 Subject: [PATCH 056/199] wifi: rtw89: Hide some errors when the device is unplugged A few unnecessary error messages are printed when the device is unplugged. "read swsi busy" in particular can appear ~1000 times when RTL8851BU is unplugged. Add a new flag RTW89_FLAG_UNPLUGGED and print some error messages only when this flag is not set. The new USB driver will set the flag when the device is unplugged. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/cc18b739-6f38-4c1a-a681-1e2a0d4ed60d@gmail.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/mac.c | 13 ++++++++----- drivers/net/wireless/realtek/rtw89/phy.c | 3 ++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 3057ab3d2e7d..a08d07e44498 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4995,6 +4995,7 @@ enum rtw89_flags { RTW89_FLAG_FORBIDDEN_TRACK_WORK, RTW89_FLAG_CHANGING_INTERFACE, RTW89_FLAG_HW_RFKILL_STATE, + RTW89_FLAG_UNPLUGGED, NUM_OF_RTW89_FLAGS, }; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 4c469379be6e..877944cbb8da 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -88,7 +88,7 @@ int rtw89_mac_write_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 val) ret = read_poll_timeout(rtw89_read8, lte_ctrl, (lte_ctrl & BIT(5)) != 0, 50, 50000, false, rtwdev, R_AX_LTE_CTRL + 3); - if (ret) + if (ret && !test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) rtw89_err(rtwdev, "[ERR]lte not ready(W)\n"); rtw89_write32(rtwdev, R_AX_LTE_WDATA, val); @@ -104,7 +104,7 @@ int rtw89_mac_read_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 *val) ret = read_poll_timeout(rtw89_read8, lte_ctrl, (lte_ctrl & BIT(5)) != 0, 50, 50000, false, rtwdev, R_AX_LTE_CTRL + 3); - if (ret) + if (ret && !test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) rtw89_err(rtwdev, "[ERR]lte not ready(W)\n"); rtw89_write32(rtwdev, R_AX_LTE_CTRL, 0x800F0000 | offset); @@ -5922,13 +5922,15 @@ int rtw89_mac_coex_init(struct rtw89_dev *rtwdev, const struct rtw89_mac_ax_coex ret = rtw89_mac_read_lte(rtwdev, R_AX_LTE_SW_CFG_2, &val32); if (ret) { - rtw89_err(rtwdev, "Read R_AX_LTE_SW_CFG_2 fail!\n"); + if (!test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) + rtw89_err(rtwdev, "Read R_AX_LTE_SW_CFG_2 fail!\n"); return ret; } val32 = val32 & B_AX_WL_RX_CTRL; ret = rtw89_mac_write_lte(rtwdev, R_AX_LTE_SW_CFG_2, val32); if (ret) { - rtw89_err(rtwdev, "Write R_AX_LTE_SW_CFG_2 fail!\n"); + if (!test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) + rtw89_err(rtwdev, "Write R_AX_LTE_SW_CFG_2 fail!\n"); return ret; } @@ -6052,7 +6054,8 @@ int rtw89_mac_cfg_gnt(struct rtw89_dev *rtwdev, ret = rtw89_mac_write_lte(rtwdev, R_AX_LTE_SW_CFG_1, val); if (ret) { - rtw89_err(rtwdev, "Write LTE fail!\n"); + if (!test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) + rtw89_err(rtwdev, "Write LTE fail!\n"); return ret; } diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index f81bee4149bf..7d005db211e5 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -897,7 +897,8 @@ static u32 rtw89_phy_read_rf_a(struct rtw89_dev *rtwdev, 30, false, rtwdev, R_SWSI_V1, B_SWSI_R_DATA_DONE_V1); if (ret) { - rtw89_err(rtwdev, "read swsi busy\n"); + if (!test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) + rtw89_err(rtwdev, "read swsi busy\n"); return INV_RF_DATA; } From e906a11753c96d553c4ace3201f57e08e21bfdba Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:45:32 +0300 Subject: [PATCH 057/199] wifi: rtw89: 8851b: Modify rtw8851b_pwr_{on,off}_func() for USB There are a few differences in the power on/off functions between PCIE and USB. While the RTL8851BU appears to work without these changes, it's probably best to implement them, in case they are needed in some situations. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/469f6882-1859-464d-8a84-9ef1b6c8ce3e@gmail.com --- drivers/net/wireless/realtek/rtw89/reg.h | 1 + drivers/net/wireless/realtek/rtw89/rtw8851b.c | 22 ++++++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 90625d692b4d..196700f0e3b2 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -21,6 +21,7 @@ #define R_AX_SYS_PW_CTRL 0x0004 #define B_AX_SOP_ASWRM BIT(31) #define B_AX_SOP_PWMM_DSWR BIT(29) +#define B_AX_SOP_EDSWR BIT(28) #define B_AX_XTAL_OFF_A_DIE BIT(22) #define B_AX_DIS_WLBT_PDNSUSEN_SOPC BIT(18) #define B_AX_RDY_SYSPWR BIT(17) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index ad41c8bf39fc..96edaf8e9ec4 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -385,7 +385,8 @@ static int rtw8851b_pwr_on_func(struct rtw89_dev *rtwdev) rtw89_write8_clr(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); rtw89_write8_set(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); - rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL, B_AX_PCIE_CALIB_EN_V1); + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) + rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL, B_AX_PCIE_CALIB_EN_V1); ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_OFF_WEI, XTAL_SI_OFF_WEI); @@ -430,8 +431,9 @@ static int rtw8851b_pwr_on_func(struct rtw89_dev *rtwdev) rtw89_write32_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B14); rtw89_write32_clr(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK); - rtw89_write32_set(rtwdev, R_AX_GPIO0_16_EECS_EESK_LED1_PULL_LOW_EN, - B_AX_GPIO10_PULL_LOW_EN | B_AX_GPIO16_PULL_LOW_EN_V1); + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) + rtw89_write32_set(rtwdev, R_AX_GPIO0_16_EECS_EESK_LED1_PULL_LOW_EN, + B_AX_GPIO10_PULL_LOW_EN | B_AX_GPIO16_PULL_LOW_EN_V1); if (rtwdev->hal.cv == CHIP_CAV) { ret = rtw89_read_efuse_ver(rtwdev, &val8); @@ -515,7 +517,10 @@ static int rtw8851b_pwr_off_func(struct rtw89_dev *rtwdev) if (ret) return ret; - rtw89_write32(rtwdev, R_AX_WLLPS_CTRL, SW_LPS_OPTION); + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) + rtw89_write32(rtwdev, R_AX_WLLPS_CTRL, SW_LPS_OPTION); + else if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) + rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_SOP_EDSWR); if (rtwdev->hal.cv == CHIP_CAV) { rtw8851b_patch_swr_pfm2pwm(rtwdev); @@ -524,7 +529,14 @@ static int rtw8851b_pwr_off_func(struct rtw89_dev *rtwdev) rtw89_write32_set(rtwdev, R_AX_SPSANA_ON_CTRL1, B_AX_FPWMDELAY); } - rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFM_SWLPS); + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) { + rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFM_SWLPS); + } else if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) { + val32 = rtw89_read32(rtwdev, R_AX_SYS_PW_CTRL); + val32 &= ~B_AX_AFSM_PCIE_SUS_EN; + val32 |= B_AX_AFSM_WLSUS_EN; + rtw89_write32(rtwdev, R_AX_SYS_PW_CTRL, val32); + } return 0; } From e2b71603333a9dd73ee88347d8894fffc3456ac1 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:45:55 +0300 Subject: [PATCH 058/199] wifi: rtw89: Fix rtw89_mac_power_switch() for USB Clear some bits in some registers in order to allow RTL8851BU to power on. This is done both when powering on and when powering off because that's what the vendor driver does. Also tested with RTL8832BU and RTL8832CU. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/a39da939-d640-4486-ad38-f658f220afc8@gmail.com --- drivers/net/wireless/realtek/rtw89/mac.c | 19 +++++++++++++++++++ drivers/net/wireless/realtek/rtw89/reg.h | 1 + 2 files changed, 20 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 877944cbb8da..ff4335ef4033 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1440,6 +1440,23 @@ void rtw89_mac_notify_wake(struct rtw89_dev *rtwdev) rtw89_mac_send_rpwm(rtwdev, state, true); } +static void rtw89_mac_power_switch_boot_mode(struct rtw89_dev *rtwdev) +{ + u32 boot_mode; + + if (rtwdev->hci.type != RTW89_HCI_TYPE_USB) + return; + + boot_mode = rtw89_read32_mask(rtwdev, R_AX_GPIO_MUXCFG, B_AX_BOOT_MODE); + if (!boot_mode) + return; + + rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFN_ONMAC); + rtw89_write32_clr(rtwdev, R_AX_SYS_STATUS1, B_AX_AUTO_WLPON); + rtw89_write32_clr(rtwdev, R_AX_GPIO_MUXCFG, B_AX_BOOT_MODE); + rtw89_write32_clr(rtwdev, R_AX_RSV_CTRL, B_AX_R_DIS_PRST); +} + static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) { #define PWR_ACT 1 @@ -1450,6 +1467,8 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) int ret; u8 val; + rtw89_mac_power_switch_boot_mode(rtwdev); + if (on) { cfg_seq = chip->pwr_on_seq; cfg_func = chip->ops->pwr_on_func; diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 196700f0e3b2..74b964e02159 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -183,6 +183,7 @@ #define R_AX_SYS_STATUS1 0x00F4 #define B_AX_SEL_0XC0_MASK GENMASK(17, 16) +#define B_AX_AUTO_WLPON BIT(10) #define B_AX_PAD_HCI_SEL_V2_MASK GENMASK(5, 3) #define MAC_AX_HCI_SEL_SDIO_UART 0 #define MAC_AX_HCI_SEL_MULTI_USB 1 From ed88640ea1ac441d5cda98f7c478fcdf34263fa7 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:46:32 +0300 Subject: [PATCH 059/199] wifi: rtw89: Add some definitions for USB Add various register and bit definitions which will be used by the new USB driver. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/5812bb0c-20d0-48df-916d-25225eee8132@gmail.com --- drivers/net/wireless/realtek/rtw89/reg.h | 29 +++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/txrx.h | 1 + 2 files changed, 30 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 74b964e02159..de81103a072f 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -382,6 +382,18 @@ #define B_AX_ACH1_BUSY BIT(9) #define B_AX_ACH0_BUSY BIT(8) +#define R_AX_USB_ENDPOINT_0 0x1060 +#define B_AX_EP_IDX GENMASK(3, 0) +#define R_AX_USB_ENDPOINT_2 0x1068 +#define NUMP 0x1 +#define R_AX_USB_HOST_REQUEST_2 0x1078 +#define B_AX_R_USBIO_MODE BIT(4) +#define R_AX_USB3_MAC_NPI_CONFIG_INTF_0 0x1114 +#define B_AX_SSPHY_LFPS_FILTER BIT(31) +#define R_AX_USB_WLAN0_1 0x1174 +#define B_AX_USBRX_RST BIT(9) +#define B_AX_USBTX_RST BIT(8) + #define R_AX_PCIE_DBG_CTRL 0x11C0 #define B_AX_DBG_DUMMY_MASK GENMASK(23, 16) #define B_AX_PCIE_DBG_SEL_MASK GENMASK(15, 13) @@ -461,6 +473,17 @@ #define R_AX_WP_PAGE_CTRL2_V1 0x17A4 #define R_AX_WP_PAGE_INFO1_V1 0x17A8 +#define R_AX_USB_ENDPOINT_0_V1 0x5060 +#define B_AX_EP_IDX_V1 GENMASK(3, 0) +#define R_AX_USB_ENDPOINT_2_V1 0x5068 +#define R_AX_USB_HOST_REQUEST_2_V1 0x5078 +#define B_AX_R_USBIO_MODE_V1 BIT(4) +#define R_AX_USB3_MAC_NPI_CONFIG_INTF_0_V1 0x5114 +#define B_AX_SSPHY_LFPS_FILTER_V1 BIT(31) +#define R_AX_USB_WLAN0_1_V1 0x5174 +#define B_AX_USBRX_RST_V1 BIT(9) +#define B_AX_USBTX_RST_V1 BIT(8) + #define R_AX_H2CREG_DATA0_V1 0x7140 #define R_AX_H2CREG_DATA1_V1 0x7144 #define R_AX_H2CREG_DATA2_V1 0x7148 @@ -1027,6 +1050,12 @@ #define B_AX_DISPATCHER_INTN_SEL_MASK GENMASK(7, 4) #define B_AX_DISPATCHER_CH_SEL_MASK GENMASK(3, 0) +#define R_AX_RXDMA_SETTING 0x8908 +#define B_AX_BULK_SIZE GENMASK(1, 0) +#define USB11_BULKSIZE 0x2 +#define USB2_BULKSIZE 0x1 +#define USB3_BULKSIZE 0x0 + #define R_AX_RX_FUNCTION_STOP 0x8920 #define B_AX_HDR_RX_STOP BIT(0) diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h index 94f27a9ee9f7..ec01bfc363da 100644 --- a/drivers/net/wireless/realtek/rtw89/txrx.h +++ b/drivers/net/wireless/realtek/rtw89/txrx.h @@ -73,6 +73,7 @@ static inline u8 rtw89_get_data_nss(struct rtw89_dev *rtwdev, u16 hw_rate) #define RTW89_TXWD_BODY0_FW_DL BIT(20) #define RTW89_TXWD_BODY0_CHANNEL_DMA GENMASK(19, 16) #define RTW89_TXWD_BODY0_HDR_LLC_LEN GENMASK(15, 11) +#define RTW89_TXWD_BODY0_STF_MODE BIT(10) #define RTW89_TXWD_BODY0_WD_PAGE BIT(7) #define RTW89_TXWD_BODY0_HW_AMSDU BIT(5) #define RTW89_TXWD_BODY0_HW_SSN_SEL GENMASK(3, 2) From 2135c28be6a84313580a974f7d6890830b83107e Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:46:55 +0300 Subject: [PATCH 060/199] wifi: rtw89: Add usb.{c,h} Add basic USB support. No TX/RX aggregation, no switching to USB 3 mode. RTL8851BU and RTL8832BU work. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/f9ad1664-2d63-4a8f-88bf-c7b7bececbfe@gmail.com --- drivers/net/wireless/realtek/rtw89/usb.c | 1042 ++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/usb.h | 65 ++ 2 files changed, 1107 insertions(+) create mode 100644 drivers/net/wireless/realtek/rtw89/usb.c create mode 100644 drivers/net/wireless/realtek/rtw89/usb.h diff --git a/drivers/net/wireless/realtek/rtw89/usb.c b/drivers/net/wireless/realtek/rtw89/usb.c new file mode 100644 index 000000000000..6cf89aee252e --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/usb.c @@ -0,0 +1,1042 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2025 Realtek Corporation + */ + +#include +#include "debug.h" +#include "mac.h" +#include "reg.h" +#include "txrx.h" +#include "usb.h" + +static void rtw89_usb_read_port_complete(struct urb *urb); + +static void rtw89_usb_vendorreq(struct rtw89_dev *rtwdev, u32 addr, + void *data, u16 len, u8 reqtype) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct usb_device *udev = rtwusb->udev; + unsigned int pipe; + u16 value, index; + int attempt, ret; + + if (test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) + return; + + value = u32_get_bits(addr, GENMASK(15, 0)); + index = u32_get_bits(addr, GENMASK(23, 16)); + + for (attempt = 0; attempt < 10; attempt++) { + *rtwusb->vendor_req_buf = 0; + + if (reqtype == RTW89_USB_VENQT_READ) { + pipe = usb_rcvctrlpipe(udev, 0); + } else { /* RTW89_USB_VENQT_WRITE */ + pipe = usb_sndctrlpipe(udev, 0); + + memcpy(rtwusb->vendor_req_buf, data, len); + } + + ret = usb_control_msg(udev, pipe, RTW89_USB_VENQT, reqtype, + value, index, rtwusb->vendor_req_buf, + len, 500); + + if (ret == len) { /* Success */ + atomic_set(&rtwusb->continual_io_error, 0); + + if (reqtype == RTW89_USB_VENQT_READ) + memcpy(data, rtwusb->vendor_req_buf, len); + + break; + } + + if (ret == -ESHUTDOWN || ret == -ENODEV) + set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags); + else if (ret < 0) + rtw89_warn(rtwdev, + "usb %s%u 0x%x fail ret=%d value=0x%x attempt=%d\n", + reqtype == RTW89_USB_VENQT_READ ? "read" : "write", + len * 8, addr, ret, + le32_to_cpup(rtwusb->vendor_req_buf), + attempt); + else if (ret > 0 && reqtype == RTW89_USB_VENQT_READ) + memcpy(data, rtwusb->vendor_req_buf, len); + + if (atomic_inc_return(&rtwusb->continual_io_error) > 4) { + set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags); + break; + } + } +} + +static u32 rtw89_usb_read_cmac(struct rtw89_dev *rtwdev, u32 addr) +{ + u32 addr32, val32, shift; + __le32 data = 0; + int count; + + addr32 = addr & ~0x3; + shift = (addr & 0x3) * 8; + + for (count = 0; ; count++) { + rtw89_usb_vendorreq(rtwdev, addr32, &data, 4, + RTW89_USB_VENQT_READ); + + val32 = le32_to_cpu(data); + if (val32 != RTW89_R32_DEAD) + break; + + if (count >= MAC_REG_POOL_COUNT) { + rtw89_warn(rtwdev, "%s: addr %#x = %#x\n", + __func__, addr32, val32); + val32 = RTW89_R32_DEAD; + break; + } + + rtw89_write32(rtwdev, R_AX_CK_EN, B_AX_CMAC_ALLCKEN); + } + + return val32 >> shift; +} + +static u8 rtw89_usb_ops_read8(struct rtw89_dev *rtwdev, u32 addr) +{ + u8 data = 0; + + if (ACCESS_CMAC(addr)) + return rtw89_usb_read_cmac(rtwdev, addr); + + rtw89_usb_vendorreq(rtwdev, addr, &data, 1, RTW89_USB_VENQT_READ); + + return data; +} + +static u16 rtw89_usb_ops_read16(struct rtw89_dev *rtwdev, u32 addr) +{ + __le16 data = 0; + + if (ACCESS_CMAC(addr)) + return rtw89_usb_read_cmac(rtwdev, addr); + + rtw89_usb_vendorreq(rtwdev, addr, &data, 2, RTW89_USB_VENQT_READ); + + return le16_to_cpu(data); +} + +static u32 rtw89_usb_ops_read32(struct rtw89_dev *rtwdev, u32 addr) +{ + __le32 data = 0; + + if (ACCESS_CMAC(addr)) + return rtw89_usb_read_cmac(rtwdev, addr); + + rtw89_usb_vendorreq(rtwdev, addr, &data, 4, + RTW89_USB_VENQT_READ); + + return le32_to_cpu(data); +} + +static void rtw89_usb_ops_write8(struct rtw89_dev *rtwdev, u32 addr, u8 val) +{ + u8 data = val; + + rtw89_usb_vendorreq(rtwdev, addr, &data, 1, RTW89_USB_VENQT_WRITE); +} + +static void rtw89_usb_ops_write16(struct rtw89_dev *rtwdev, u32 addr, u16 val) +{ + __le16 data = cpu_to_le16(val); + + rtw89_usb_vendorreq(rtwdev, addr, &data, 2, RTW89_USB_VENQT_WRITE); +} + +static void rtw89_usb_ops_write32(struct rtw89_dev *rtwdev, u32 addr, u32 val) +{ + __le32 data = cpu_to_le32(val); + + rtw89_usb_vendorreq(rtwdev, addr, &data, 4, RTW89_USB_VENQT_WRITE); +} + +static u32 +rtw89_usb_ops_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev, + u8 txch) +{ + if (txch == RTW89_TXCH_CH12) + return 1; + + return 42; /* TODO some kind of calculation? */ +} + +static u8 rtw89_usb_get_bulkout_id(u8 ch_dma) +{ + switch (ch_dma) { + case RTW89_DMA_ACH0: + return 3; + case RTW89_DMA_ACH1: + return 4; + case RTW89_DMA_ACH2: + return 5; + case RTW89_DMA_ACH3: + return 6; + default: + case RTW89_DMA_B0MG: + return 0; + case RTW89_DMA_B0HI: + return 1; + case RTW89_DMA_H2C: + return 2; + } +} + +static void rtw89_usb_write_port_complete(struct urb *urb) +{ + struct rtw89_usb_tx_ctrl_block *txcb = urb->context; + struct rtw89_dev *rtwdev = txcb->rtwdev; + struct ieee80211_tx_info *info; + struct rtw89_txwd_body *txdesc; + struct sk_buff *skb; + u32 txdesc_size; + + while (true) { + skb = skb_dequeue(&txcb->tx_ack_queue); + if (!skb) + break; + + if (txcb->txch == RTW89_TXCH_CH12) { + dev_kfree_skb_any(skb); + continue; + } + + txdesc = (struct rtw89_txwd_body *)skb->data; + + txdesc_size = rtwdev->chip->txwd_body_size; + if (le32_get_bits(txdesc->dword0, RTW89_TXWD_BODY0_WD_INFO_EN)) + txdesc_size += rtwdev->chip->txwd_info_size; + + skb_pull(skb, txdesc_size); + + info = IEEE80211_SKB_CB(skb); + ieee80211_tx_info_clear_status(info); + + if (urb->status == 0) { + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; + else + info->flags |= IEEE80211_TX_STAT_ACK; + } + + ieee80211_tx_status_irqsafe(rtwdev->hw, skb); + } + + switch (urb->status) { + case 0: + case -EPIPE: + case -EPROTO: + case -EINPROGRESS: + case -ENOENT: + case -ECONNRESET: + break; + default: + set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags); + break; + } + + kfree(txcb); + usb_free_urb(urb); +} + +static int rtw89_usb_write_port(struct rtw89_dev *rtwdev, u8 ch_dma, + void *data, int len, void *context) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct usb_device *usbd = rtwusb->udev; + struct urb *urb; + u8 bulkout_id = rtw89_usb_get_bulkout_id(ch_dma); + unsigned int pipe; + int ret; + + if (test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) + return 0; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) + return -ENOMEM; + + pipe = usb_sndbulkpipe(usbd, rtwusb->out_pipe[bulkout_id]); + + usb_fill_bulk_urb(urb, usbd, pipe, data, len, + rtw89_usb_write_port_complete, context); + urb->transfer_flags |= URB_ZERO_PACKET; + ret = usb_submit_urb(urb, GFP_ATOMIC); + + if (ret) + usb_free_urb(urb); + + if (ret == -ENODEV) + set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags); + + return ret; +} + +static void rtw89_usb_ops_tx_kick_off(struct rtw89_dev *rtwdev, u8 txch) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct rtw89_usb_tx_ctrl_block *txcb; + struct sk_buff *skb; + int ret; + + while (true) { + skb = skb_dequeue(&rtwusb->tx_queue[txch]); + if (!skb) + break; + + txcb = kmalloc(sizeof(*txcb), GFP_ATOMIC); + if (!txcb) { + dev_kfree_skb_any(skb); + continue; + } + + txcb->rtwdev = rtwdev; + txcb->txch = txch; + skb_queue_head_init(&txcb->tx_ack_queue); + + skb_queue_tail(&txcb->tx_ack_queue, skb); + + ret = rtw89_usb_write_port(rtwdev, txch, skb->data, skb->len, + txcb); + if (ret) { + rtw89_err(rtwdev, "write port txch %d failed: %d\n", + txch, ret); + + skb_dequeue(&txcb->tx_ack_queue); + kfree(txcb); + dev_kfree_skb_any(skb); + } + } +} + +static int rtw89_usb_tx_write_fwcmd(struct rtw89_dev *rtwdev, + struct rtw89_core_tx_request *tx_req) +{ + struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info; + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct sk_buff *skb = tx_req->skb; + struct sk_buff *skb512; + u32 txdesc_size = rtwdev->chip->h2c_desc_size; + void *txdesc; + + if (((desc_info->pkt_size + txdesc_size) % 512) == 0) { + rtw89_debug(rtwdev, RTW89_DBG_HCI, "avoiding multiple of 512\n"); + + skb512 = dev_alloc_skb(txdesc_size + desc_info->pkt_size + + RTW89_USB_MOD512_PADDING); + if (!skb512) { + rtw89_err(rtwdev, "%s: failed to allocate skb\n", + __func__); + + return -ENOMEM; + } + + skb_pull(skb512, txdesc_size); + skb_put_data(skb512, skb->data, skb->len); + skb_put_zero(skb512, RTW89_USB_MOD512_PADDING); + + dev_kfree_skb_any(skb); + skb = skb512; + tx_req->skb = skb512; + + desc_info->pkt_size += RTW89_USB_MOD512_PADDING; + } + + txdesc = skb_push(skb, txdesc_size); + memset(txdesc, 0, txdesc_size); + rtw89_chip_fill_txdesc_fwcmd(rtwdev, desc_info, txdesc); + + skb_queue_tail(&rtwusb->tx_queue[desc_info->ch_dma], skb); + + return 0; +} + +static int rtw89_usb_ops_tx_write(struct rtw89_dev *rtwdev, + struct rtw89_core_tx_request *tx_req) +{ + struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info; + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct sk_buff *skb = tx_req->skb; + struct rtw89_txwd_body *txdesc; + u32 txdesc_size; + + if ((desc_info->ch_dma == RTW89_TXCH_CH12 || + tx_req->tx_type == RTW89_CORE_TX_TYPE_FWCMD) && + (desc_info->ch_dma != RTW89_TXCH_CH12 || + tx_req->tx_type != RTW89_CORE_TX_TYPE_FWCMD)) { + rtw89_err(rtwdev, "dma channel %d/TX type %d mismatch\n", + desc_info->ch_dma, tx_req->tx_type); + return -EINVAL; + } + + if (desc_info->ch_dma == RTW89_TXCH_CH12) + return rtw89_usb_tx_write_fwcmd(rtwdev, tx_req); + + txdesc_size = rtwdev->chip->txwd_body_size; + if (desc_info->en_wd_info) + txdesc_size += rtwdev->chip->txwd_info_size; + + txdesc = skb_push(skb, txdesc_size); + memset(txdesc, 0, txdesc_size); + rtw89_chip_fill_txdesc(rtwdev, desc_info, txdesc); + + le32p_replace_bits(&txdesc->dword0, 1, RTW89_TXWD_BODY0_STF_MODE); + + skb_queue_tail(&rtwusb->tx_queue[desc_info->ch_dma], skb); + + return 0; +} + +static void rtw89_usb_rx_handler(struct work_struct *work) +{ + struct rtw89_usb *rtwusb = container_of(work, struct rtw89_usb, rx_work); + struct rtw89_dev *rtwdev = rtwusb->rtwdev; + struct rtw89_rx_desc_info desc_info; + struct sk_buff *rx_skb; + struct sk_buff *skb; + u32 pkt_offset; + int limit; + + for (limit = 0; limit < 200; limit++) { + rx_skb = skb_dequeue(&rtwusb->rx_queue); + if (!rx_skb) + break; + + if (skb_queue_len(&rtwusb->rx_queue) >= RTW89_USB_MAX_RXQ_LEN) { + rtw89_warn(rtwdev, "rx_queue overflow\n"); + dev_kfree_skb_any(rx_skb); + continue; + } + + memset(&desc_info, 0, sizeof(desc_info)); + rtw89_chip_query_rxdesc(rtwdev, &desc_info, rx_skb->data, 0); + + skb = rtw89_alloc_skb_for_rx(rtwdev, desc_info.pkt_size); + if (!skb) { + rtw89_debug(rtwdev, RTW89_DBG_HCI, + "failed to allocate RX skb of size %u\n", + desc_info.pkt_size); + continue; + } + + pkt_offset = desc_info.offset + desc_info.rxd_len; + + skb_put_data(skb, rx_skb->data + pkt_offset, + desc_info.pkt_size); + + rtw89_core_rx(rtwdev, &desc_info, skb); + + if (skb_queue_len(&rtwusb->rx_free_queue) >= RTW89_USB_RX_SKB_NUM) + dev_kfree_skb_any(rx_skb); + else + skb_queue_tail(&rtwusb->rx_free_queue, rx_skb); + } + + if (limit == 200) { + rtw89_debug(rtwdev, RTW89_DBG_HCI, + "left %d rx skbs in the queue for later\n", + skb_queue_len(&rtwusb->rx_queue)); + queue_work(rtwusb->rxwq, &rtwusb->rx_work); + } +} + +static void rtw89_usb_rx_resubmit(struct rtw89_usb *rtwusb, + struct rtw89_usb_rx_ctrl_block *rxcb, + gfp_t gfp) +{ + struct rtw89_dev *rtwdev = rtwusb->rtwdev; + struct sk_buff *rx_skb; + int ret; + + rx_skb = skb_dequeue(&rtwusb->rx_free_queue); + if (!rx_skb) + rx_skb = alloc_skb(RTW89_USB_RECVBUF_SZ, gfp); + + if (!rx_skb) + goto try_later; + + skb_reset_tail_pointer(rx_skb); + rx_skb->len = 0; + + rxcb->rx_skb = rx_skb; + + usb_fill_bulk_urb(rxcb->rx_urb, rtwusb->udev, + usb_rcvbulkpipe(rtwusb->udev, rtwusb->in_pipe), + rxcb->rx_skb->data, RTW89_USB_RECVBUF_SZ, + rtw89_usb_read_port_complete, rxcb); + + ret = usb_submit_urb(rxcb->rx_urb, gfp); + if (ret) { + skb_queue_tail(&rtwusb->rx_free_queue, rxcb->rx_skb); + + if (ret == -ENODEV) + set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags); + else + rtw89_err(rtwdev, "Err sending rx data urb %d\n", ret); + + if (ret == -ENOMEM) + goto try_later; + } + + return; + +try_later: + rxcb->rx_skb = NULL; + queue_work(rtwusb->rxwq, &rtwusb->rx_urb_work); +} + +static void rtw89_usb_rx_resubmit_work(struct work_struct *work) +{ + struct rtw89_usb *rtwusb = container_of(work, struct rtw89_usb, rx_urb_work); + struct rtw89_usb_rx_ctrl_block *rxcb; + int i; + + for (i = 0; i < RTW89_USB_RXCB_NUM; i++) { + rxcb = &rtwusb->rx_cb[i]; + + if (!rxcb->rx_skb) + rtw89_usb_rx_resubmit(rtwusb, rxcb, GFP_ATOMIC); + } +} + +static void rtw89_usb_read_port_complete(struct urb *urb) +{ + struct rtw89_usb_rx_ctrl_block *rxcb = urb->context; + struct rtw89_dev *rtwdev = rxcb->rtwdev; + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct sk_buff *skb = rxcb->rx_skb; + + if (urb->status == 0) { + if (urb->actual_length > urb->transfer_buffer_length || + urb->actual_length < sizeof(struct rtw89_rxdesc_short)) { + rtw89_err(rtwdev, "failed to get urb length: %d\n", + urb->actual_length); + skb_queue_tail(&rtwusb->rx_free_queue, skb); + } else { + skb_put(skb, urb->actual_length); + skb_queue_tail(&rtwusb->rx_queue, skb); + queue_work(rtwusb->rxwq, &rtwusb->rx_work); + } + + rtw89_usb_rx_resubmit(rtwusb, rxcb, GFP_ATOMIC); + } else { + skb_queue_tail(&rtwusb->rx_free_queue, skb); + + if (atomic_inc_return(&rtwusb->continual_io_error) > 4) + set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags); + + switch (urb->status) { + case -EINVAL: + case -EPIPE: + case -ENODEV: + case -ESHUTDOWN: + set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags); + break; + case -EPROTO: + case -EILSEQ: + case -ETIME: + case -ECOMM: + case -EOVERFLOW: + case -ENOENT: + break; + case -EINPROGRESS: + rtw89_info(rtwdev, "URB is in progress\n"); + break; + default: + rtw89_err(rtwdev, "%s status %d\n", + __func__, urb->status); + break; + } + } +} + +static void rtw89_usb_cancel_rx_bufs(struct rtw89_usb *rtwusb) +{ + struct rtw89_usb_rx_ctrl_block *rxcb; + int i; + + for (i = 0; i < RTW89_USB_RXCB_NUM; i++) { + rxcb = &rtwusb->rx_cb[i]; + usb_kill_urb(rxcb->rx_urb); + } +} + +static void rtw89_usb_free_rx_bufs(struct rtw89_usb *rtwusb) +{ + struct rtw89_usb_rx_ctrl_block *rxcb; + int i; + + for (i = 0; i < RTW89_USB_RXCB_NUM; i++) { + rxcb = &rtwusb->rx_cb[i]; + usb_free_urb(rxcb->rx_urb); + } +} + +static int rtw89_usb_alloc_rx_bufs(struct rtw89_usb *rtwusb) +{ + struct rtw89_usb_rx_ctrl_block *rxcb; + int i; + + for (i = 0; i < RTW89_USB_RXCB_NUM; i++) { + rxcb = &rtwusb->rx_cb[i]; + + rxcb->rtwdev = rtwusb->rtwdev; + rxcb->rx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!rxcb->rx_urb) { + rtw89_usb_free_rx_bufs(rtwusb); + return -ENOMEM; + } + } + + return 0; +} + +static int rtw89_usb_init_rx(struct rtw89_dev *rtwdev) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct sk_buff *rx_skb; + int i; + + rtwusb->rxwq = alloc_workqueue("rtw89_usb: rx wq", WQ_BH, 0); + if (!rtwusb->rxwq) { + rtw89_err(rtwdev, "failed to create RX work queue\n"); + return -ENOMEM; + } + + skb_queue_head_init(&rtwusb->rx_queue); + skb_queue_head_init(&rtwusb->rx_free_queue); + + INIT_WORK(&rtwusb->rx_work, rtw89_usb_rx_handler); + INIT_WORK(&rtwusb->rx_urb_work, rtw89_usb_rx_resubmit_work); + + for (i = 0; i < RTW89_USB_RX_SKB_NUM; i++) { + rx_skb = alloc_skb(RTW89_USB_RECVBUF_SZ, GFP_KERNEL); + if (rx_skb) + skb_queue_tail(&rtwusb->rx_free_queue, rx_skb); + } + + return 0; +} + +static void rtw89_usb_deinit_rx(struct rtw89_dev *rtwdev) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + + skb_queue_purge(&rtwusb->rx_queue); + + destroy_workqueue(rtwusb->rxwq); + + skb_queue_purge(&rtwusb->rx_free_queue); +} + +static void rtw89_usb_start_rx(struct rtw89_dev *rtwdev) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + int i; + + for (i = 0; i < RTW89_USB_RXCB_NUM; i++) + rtw89_usb_rx_resubmit(rtwusb, &rtwusb->rx_cb[i], GFP_KERNEL); +} + +static void rtw89_usb_init_tx(struct rtw89_dev *rtwdev) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + int i; + + for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++) + skb_queue_head_init(&rtwusb->tx_queue[i]); +} + +static void rtw89_usb_deinit_tx(struct rtw89_dev *rtwdev) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + int i; + + for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++) { + if (i == RTW89_TXCH_CH12) + skb_queue_purge(&rtwusb->tx_queue[i]); + else + ieee80211_purge_tx_queue(rtwdev->hw, &rtwusb->tx_queue[i]); + } +} + +static void rtw89_usb_ops_reset(struct rtw89_dev *rtwdev) +{ + /* TODO: anything to do here? */ +} + +static int rtw89_usb_ops_start(struct rtw89_dev *rtwdev) +{ + return 0; /* Nothing to do. */ +} + +static void rtw89_usb_ops_stop(struct rtw89_dev *rtwdev) +{ + /* Nothing to do. */ +} + +static void rtw89_usb_ops_pause(struct rtw89_dev *rtwdev, bool pause) +{ + /* Nothing to do? */ +} + +static void rtw89_usb_ops_switch_mode(struct rtw89_dev *rtwdev, bool low_power) +{ + /* Nothing to do. */ +} + +static int rtw89_usb_ops_deinit(struct rtw89_dev *rtwdev) +{ + return 0; /* Nothing to do. */ +} + +static int rtw89_usb_ops_mac_pre_init(struct rtw89_dev *rtwdev) +{ + u32 val32; + + rtw89_write32_set(rtwdev, R_AX_USB_HOST_REQUEST_2, B_AX_R_USBIO_MODE); + + /* fix USB IO hang suggest by chihhanli@realtek.com */ + rtw89_write32_clr(rtwdev, R_AX_USB_WLAN0_1, + B_AX_USBRX_RST | B_AX_USBTX_RST); + + val32 = rtw89_read32(rtwdev, R_AX_HCI_FUNC_EN); + val32 &= ~(B_AX_HCI_RXDMA_EN | B_AX_HCI_TXDMA_EN); + rtw89_write32(rtwdev, R_AX_HCI_FUNC_EN, val32); + + val32 |= B_AX_HCI_RXDMA_EN | B_AX_HCI_TXDMA_EN; + rtw89_write32(rtwdev, R_AX_HCI_FUNC_EN, val32); + /* fix USB TRX hang suggest by chihhanli@realtek.com */ + + return 0; +} + +static int rtw89_usb_ops_mac_pre_deinit(struct rtw89_dev *rtwdev) +{ + return 0; /* Nothing to do. */ +} + +static int rtw89_usb_ops_mac_post_init(struct rtw89_dev *rtwdev) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + enum usb_device_speed speed; + u32 ep; + + rtw89_write32_clr(rtwdev, R_AX_USB3_MAC_NPI_CONFIG_INTF_0, + B_AX_SSPHY_LFPS_FILTER); + + speed = rtwusb->udev->speed; + + if (speed == USB_SPEED_SUPER) + rtw89_write8(rtwdev, R_AX_RXDMA_SETTING, USB3_BULKSIZE); + else if (speed == USB_SPEED_HIGH) + rtw89_write8(rtwdev, R_AX_RXDMA_SETTING, USB2_BULKSIZE); + else + rtw89_write8(rtwdev, R_AX_RXDMA_SETTING, USB11_BULKSIZE); + + for (ep = 5; ep <= 12; ep++) { + if (ep == 8) + continue; + + rtw89_write8_mask(rtwdev, R_AX_USB_ENDPOINT_0, + B_AX_EP_IDX, ep); + rtw89_write8(rtwdev, R_AX_USB_ENDPOINT_2 + 1, NUMP); + } + + return 0; +} + +static void rtw89_usb_ops_recalc_int_mit(struct rtw89_dev *rtwdev) +{ + /* Nothing to do. */ +} + +static int rtw89_usb_ops_mac_lv1_rcvy(struct rtw89_dev *rtwdev, + enum rtw89_lv1_rcvy_step step) +{ + u32 reg, mask; + + switch (rtwdev->chip->chip_id) { + case RTL8851B: + case RTL8852A: + case RTL8852B: + reg = R_AX_USB_WLAN0_1; + mask = B_AX_USBRX_RST | B_AX_USBTX_RST; + break; + case RTL8852C: + reg = R_AX_USB_WLAN0_1_V1; + mask = B_AX_USBRX_RST_V1 | B_AX_USBTX_RST_V1; + break; + default: + rtw89_err(rtwdev, "%s: fix me\n", __func__); + return -EOPNOTSUPP; + } + + switch (step) { + case RTW89_LV1_RCVY_STEP_1: + rtw89_write32_set(rtwdev, reg, mask); + + msleep(30); + break; + case RTW89_LV1_RCVY_STEP_2: + rtw89_write32_clr(rtwdev, reg, mask); + break; + default: + return -EINVAL; + } + + return 0; +} + +static void rtw89_usb_ops_dump_err_status(struct rtw89_dev *rtwdev) +{ + rtw89_warn(rtwdev, "%s TODO\n", __func__); +} + +static const struct rtw89_hci_ops rtw89_usb_ops = { + .tx_write = rtw89_usb_ops_tx_write, + .tx_kick_off = rtw89_usb_ops_tx_kick_off, + .flush_queues = NULL, /* Not needed? */ + .reset = rtw89_usb_ops_reset, + .start = rtw89_usb_ops_start, + .stop = rtw89_usb_ops_stop, + .pause = rtw89_usb_ops_pause, + .switch_mode = rtw89_usb_ops_switch_mode, + .recalc_int_mit = rtw89_usb_ops_recalc_int_mit, + + .read8 = rtw89_usb_ops_read8, + .read16 = rtw89_usb_ops_read16, + .read32 = rtw89_usb_ops_read32, + .write8 = rtw89_usb_ops_write8, + .write16 = rtw89_usb_ops_write16, + .write32 = rtw89_usb_ops_write32, + + .mac_pre_init = rtw89_usb_ops_mac_pre_init, + .mac_pre_deinit = rtw89_usb_ops_mac_pre_deinit, + .mac_post_init = rtw89_usb_ops_mac_post_init, + .deinit = rtw89_usb_ops_deinit, + + .check_and_reclaim_tx_resource = rtw89_usb_ops_check_and_reclaim_tx_resource, + .mac_lv1_rcvy = rtw89_usb_ops_mac_lv1_rcvy, + .dump_err_status = rtw89_usb_ops_dump_err_status, + .napi_poll = NULL, + + .recovery_start = NULL, + .recovery_complete = NULL, + + .ctrl_txdma_ch = NULL, + .ctrl_txdma_fw_ch = NULL, + .ctrl_trxhci = NULL, + .poll_txdma_ch_idle = NULL, + + .clr_idx_all = NULL, + .clear = NULL, + .disable_intr = NULL, + .enable_intr = NULL, + .rst_bdram = NULL, +}; + +static int rtw89_usb_parse(struct rtw89_dev *rtwdev, + struct usb_interface *intf) +{ + struct usb_host_interface *host_interface = &intf->altsetting[0]; + struct usb_interface_descriptor *intf_desc = &host_interface->desc; + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct usb_endpoint_descriptor *endpoint; + int num_out_pipes = 0; + u8 num; + int i; + + if (intf_desc->bNumEndpoints > RTW89_MAX_ENDPOINT_NUM) { + rtw89_err(rtwdev, "found %d endpoints, expected %d max\n", + intf_desc->bNumEndpoints, RTW89_MAX_ENDPOINT_NUM); + return -EINVAL; + } + + for (i = 0; i < intf_desc->bNumEndpoints; i++) { + endpoint = &host_interface->endpoint[i].desc; + num = usb_endpoint_num(endpoint); + + if (usb_endpoint_dir_in(endpoint) && + usb_endpoint_xfer_bulk(endpoint)) { + if (rtwusb->in_pipe) { + rtw89_err(rtwdev, + "found more than 1 bulk in endpoint\n"); + return -EINVAL; + } + + rtwusb->in_pipe = num; + } + + if (usb_endpoint_dir_out(endpoint) && + usb_endpoint_xfer_bulk(endpoint)) { + if (num_out_pipes >= RTW89_MAX_BULKOUT_NUM) { + rtw89_err(rtwdev, + "found more than %d bulk out endpoints\n", + RTW89_MAX_BULKOUT_NUM); + return -EINVAL; + } + + rtwusb->out_pipe[num_out_pipes++] = num; + } + } + + if (num_out_pipes < 1) { + rtw89_err(rtwdev, "no bulk out endpoints found\n"); + return -EINVAL; + } + + return 0; +} + +static int rtw89_usb_intf_init(struct rtw89_dev *rtwdev, + struct usb_interface *intf) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + int ret; + + ret = rtw89_usb_parse(rtwdev, intf); + if (ret) + return ret; + + rtwusb->vendor_req_buf = kmalloc(sizeof(*rtwusb->vendor_req_buf), + GFP_KERNEL); + if (!rtwusb->vendor_req_buf) + return -ENOMEM; + + rtwusb->udev = usb_get_dev(interface_to_usbdev(intf)); + + usb_set_intfdata(intf, rtwdev->hw); + + SET_IEEE80211_DEV(rtwdev->hw, &intf->dev); + + return 0; +} + +static void rtw89_usb_intf_deinit(struct rtw89_dev *rtwdev, + struct usb_interface *intf) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + + usb_put_dev(rtwusb->udev); + kfree(rtwusb->vendor_req_buf); + usb_set_intfdata(intf, NULL); +} + +int rtw89_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + const struct rtw89_driver_info *info; + struct rtw89_dev *rtwdev; + struct rtw89_usb *rtwusb; + int ret; + + info = (const struct rtw89_driver_info *)id->driver_info; + + rtwdev = rtw89_alloc_ieee80211_hw(&intf->dev, + sizeof(struct rtw89_usb), + info->chip, info->variant); + if (!rtwdev) { + dev_err(&intf->dev, "failed to allocate hw\n"); + return -ENOMEM; + } + + rtwusb = rtw89_usb_priv(rtwdev); + rtwusb->rtwdev = rtwdev; + + rtwdev->hci.ops = &rtw89_usb_ops; + rtwdev->hci.type = RTW89_HCI_TYPE_USB; + + ret = rtw89_usb_intf_init(rtwdev, intf); + if (ret) { + rtw89_err(rtwdev, "failed to initialise intf: %d\n", ret); + goto err_free_hw; + } + + if (rtwusb->udev->speed == USB_SPEED_SUPER) + rtwdev->hci.dle_type = RTW89_HCI_DLE_TYPE_USB3; + else + rtwdev->hci.dle_type = RTW89_HCI_DLE_TYPE_USB2; + + rtw89_usb_init_tx(rtwdev); + + ret = rtw89_usb_alloc_rx_bufs(rtwusb); + if (ret) + goto err_intf_deinit; + + ret = rtw89_usb_init_rx(rtwdev); + if (ret) + goto err_free_rx_bufs; + + ret = rtw89_core_init(rtwdev); + if (ret) { + rtw89_err(rtwdev, "failed to initialise core: %d\n", ret); + goto err_deinit_rx; + } + + ret = rtw89_chip_info_setup(rtwdev); + if (ret) { + rtw89_err(rtwdev, "failed to setup chip information\n"); + goto err_core_deinit; + } + + ret = rtw89_core_register(rtwdev); + if (ret) { + rtw89_err(rtwdev, "failed to register core\n"); + goto err_core_deinit; + } + + rtw89_usb_start_rx(rtwdev); + + set_bit(RTW89_FLAG_PROBE_DONE, rtwdev->flags); + + return 0; + +err_core_deinit: + rtw89_core_deinit(rtwdev); +err_deinit_rx: + rtw89_usb_deinit_rx(rtwdev); +err_free_rx_bufs: + rtw89_usb_free_rx_bufs(rtwusb); +err_intf_deinit: + rtw89_usb_intf_deinit(rtwdev, intf); +err_free_hw: + rtw89_free_ieee80211_hw(rtwdev); + + return ret; +} +EXPORT_SYMBOL(rtw89_usb_probe); + +void rtw89_usb_disconnect(struct usb_interface *intf) +{ + struct ieee80211_hw *hw = usb_get_intfdata(intf); + struct rtw89_dev *rtwdev; + struct rtw89_usb *rtwusb; + + if (!hw) + return; + + rtwdev = hw->priv; + rtwusb = rtw89_usb_priv(rtwdev); + + rtw89_usb_cancel_rx_bufs(rtwusb); + + rtw89_core_unregister(rtwdev); + rtw89_core_deinit(rtwdev); + rtw89_usb_deinit_rx(rtwdev); + rtw89_usb_free_rx_bufs(rtwusb); + rtw89_usb_deinit_tx(rtwdev); + rtw89_usb_intf_deinit(rtwdev, intf); + rtw89_free_ieee80211_hw(rtwdev); +} +EXPORT_SYMBOL(rtw89_usb_disconnect); + +MODULE_AUTHOR("Bitterblue Smith "); +MODULE_DESCRIPTION("Realtek USB 802.11ax wireless driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw89/usb.h b/drivers/net/wireless/realtek/rtw89/usb.h new file mode 100644 index 000000000000..c1b4bfa20979 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/usb.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2025 Realtek Corporation + */ + +#ifndef __RTW89_USB_H__ +#define __RTW89_USB_H__ + +#include "txrx.h" + +#define RTW89_USB_VENQT 0x05 +#define RTW89_USB_VENQT_READ 0xc0 +#define RTW89_USB_VENQT_WRITE 0x40 + +#define RTW89_USB_RECVBUF_SZ 20480 +#define RTW89_USB_RXCB_NUM 8 +#define RTW89_USB_RX_SKB_NUM 16 +#define RTW89_USB_MAX_RXQ_LEN 512 +#define RTW89_USB_MOD512_PADDING 4 + +#define RTW89_MAX_ENDPOINT_NUM 9 +#define RTW89_MAX_BULKOUT_NUM 7 + +struct rtw89_usb_rx_ctrl_block { + struct rtw89_dev *rtwdev; + struct urb *rx_urb; + struct sk_buff *rx_skb; +}; + +struct rtw89_usb_tx_ctrl_block { + struct rtw89_dev *rtwdev; + u8 txch; + struct sk_buff_head tx_ack_queue; +}; + +struct rtw89_usb { + struct rtw89_dev *rtwdev; + struct usb_device *udev; + + __le32 *vendor_req_buf; + + atomic_t continual_io_error; + + u8 in_pipe; + u8 out_pipe[RTW89_MAX_BULKOUT_NUM]; + + struct workqueue_struct *rxwq; + struct rtw89_usb_rx_ctrl_block rx_cb[RTW89_USB_RXCB_NUM]; + struct sk_buff_head rx_queue; + struct sk_buff_head rx_free_queue; + struct work_struct rx_work; + struct work_struct rx_urb_work; + + struct sk_buff_head tx_queue[RTW89_TXCH_NUM]; +}; + +static inline struct rtw89_usb *rtw89_usb_priv(struct rtw89_dev *rtwdev) +{ + return (struct rtw89_usb *)rtwdev->priv; +} + +int rtw89_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id); +void rtw89_usb_disconnect(struct usb_interface *intf); + +#endif From 52cf4432378568ba1ed275b5aecc61c66dad7368 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:47:19 +0300 Subject: [PATCH 061/199] wifi: rtw89: Add rtw8851bu.c This is the entry point for the new rtw89_8851bu module. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/9d40c265-2982-4073-84a3-d3781defdbca@gmail.com --- .../net/wireless/realtek/rtw89/rtw8851bu.c | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8851bu.c diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851bu.c b/drivers/net/wireless/realtek/rtw89/rtw8851bu.c new file mode 100644 index 000000000000..c3722547c6b0 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8851bu.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2025 Realtek Corporation + */ + +#include +#include +#include "rtw8851b.h" +#include "usb.h" + +static const struct rtw89_driver_info rtw89_8851bu_info = { + .chip = &rtw8851b_chip_info, + .variant = NULL, + .quirks = NULL, +}; + +static const struct usb_device_id rtw_8851bu_id_table[] = { + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xb851, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8851bu_info }, + /* TP-Link Archer TX10UB Nano */ + { USB_DEVICE_AND_INTERFACE_INFO(0x3625, 0x010b, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8851bu_info }, + /* Edimax EW-7611UXB */ + { USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xe611, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8851bu_info }, + {}, +}; +MODULE_DEVICE_TABLE(usb, rtw_8851bu_id_table); + +static struct usb_driver rtw_8851bu_driver = { + .name = KBUILD_MODNAME, + .id_table = rtw_8851bu_id_table, + .probe = rtw89_usb_probe, + .disconnect = rtw89_usb_disconnect, +}; +module_usb_driver(rtw_8851bu_driver); + +MODULE_AUTHOR("Bitterblue Smith "); +MODULE_DESCRIPTION("Realtek 802.11ax wireless 8851BU driver"); +MODULE_LICENSE("Dual BSD/GPL"); From 0030088148d5a070f445c1522989e490b311286b Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:47:52 +0300 Subject: [PATCH 062/199] wifi: rtw89: Enable the new USB modules Enable compilation of the new rtw89_usb and rtw89_8851bu modules. Tested mostly in station mode, and a little bit in AP mode. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/4968a9d5-02c8-4d35-a5ad-b75ece8f5d36@gmail.com --- drivers/net/wireless/realtek/rtw89/Kconfig | 14 ++++++++++++++ drivers/net/wireless/realtek/rtw89/Makefile | 6 ++++++ 2 files changed, 20 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/Kconfig b/drivers/net/wireless/realtek/rtw89/Kconfig index 205d7ecca7d7..bd180f3369c3 100644 --- a/drivers/net/wireless/realtek/rtw89/Kconfig +++ b/drivers/net/wireless/realtek/rtw89/Kconfig @@ -17,6 +17,9 @@ config RTW89_CORE config RTW89_PCI tristate +config RTW89_USB + tristate + config RTW89_8851B tristate @@ -49,6 +52,17 @@ config RTW89_8851BE 802.11ax PCIe wireless network (Wi-Fi 6) adapter +config RTW89_8851BU + tristate "Realtek 8851BU USB wireless network (Wi-Fi 6) adapter" + depends on USB + select RTW89_CORE + select RTW89_USB + select RTW89_8851B + help + Select this option will enable support for 8851BU chipset + + 802.11ax USB wireless network (Wi-Fi 6) adapter + config RTW89_8852AE tristate "Realtek 8852AE PCI wireless network (Wi-Fi 6) adapter" depends on PCI diff --git a/drivers/net/wireless/realtek/rtw89/Makefile b/drivers/net/wireless/realtek/rtw89/Makefile index c751013e811e..891e2d55c335 100644 --- a/drivers/net/wireless/realtek/rtw89/Makefile +++ b/drivers/net/wireless/realtek/rtw89/Makefile @@ -31,6 +31,9 @@ rtw89_8851b-objs := rtw8851b.o \ obj-$(CONFIG_RTW89_8851BE) += rtw89_8851be.o rtw89_8851be-objs := rtw8851be.o +obj-$(CONFIG_RTW89_8851BU) += rtw89_8851bu.o +rtw89_8851bu-objs := rtw8851bu.o + obj-$(CONFIG_RTW89_8852A) += rtw89_8852a.o rtw89_8852a-objs := rtw8852a.o \ rtw8852a_table.o \ @@ -81,3 +84,6 @@ rtw89_core-$(CONFIG_RTW89_DEBUG) += debug.o obj-$(CONFIG_RTW89_PCI) += rtw89_pci.o rtw89_pci-y := pci.o pci_be.o +obj-$(CONFIG_RTW89_USB) += rtw89_usb.o +rtw89_usb-y := usb.o + From 480dd4dddfc510c70e45f3d35a7df8a8a1511a7b Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Tue, 1 Jul 2025 15:38:39 +0800 Subject: [PATCH 063/199] wifi: rtw89: enter power save mode aggressively Currently the driver allows the WiFi chip enter power save mode by checking the transmitting and receiving traffic is very low per two seconds. But it's hard for some applications to enter power save mode, like video streaming, which sends burst traffic regularly for other side to buffer and only send little traffic at most time. So adjust the criteria to enter power save while lower than 10Mbps and check it per 100ms. Thus WiFi chip could reduce power consumption under these applications. Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250701073839.31905-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 110 +++++++++++++----- drivers/net/wireless/realtek/rtw89/core.h | 20 +++- drivers/net/wireless/realtek/rtw89/mac80211.c | 3 + drivers/net/wireless/realtek/rtw89/ser.c | 3 + drivers/net/wireless/realtek/rtw89/wow.c | 2 +- drivers/net/wireless/realtek/rtw89/wow.h | 14 ++- 6 files changed, 123 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 776d2e5ce8a0..23d050041583 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -319,15 +319,25 @@ static const struct ieee80211_supported_band rtw89_sband_6ghz = { .n_bitrates = ARRAY_SIZE(rtw89_bitrates) - 4, }; +static void __rtw89_traffic_stats_accu(struct rtw89_traffic_stats *stats, + struct sk_buff *skb, bool tx) +{ + if (tx) { + stats->tx_cnt++; + stats->tx_unicast += skb->len; + } else { + stats->rx_cnt++; + stats->rx_unicast += skb->len; + } +} + static void rtw89_traffic_stats_accu(struct rtw89_dev *rtwdev, - struct rtw89_traffic_stats *stats, - struct sk_buff *skb, bool tx) + struct rtw89_vif *rtwvif, + struct sk_buff *skb, + bool accu_dev, bool tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - if (tx && ieee80211_is_assoc_req(hdr->frame_control)) - rtw89_wow_parse_akm(rtwdev, skb); - if (!ieee80211_is_data(hdr->frame_control)) return; @@ -335,12 +345,12 @@ static void rtw89_traffic_stats_accu(struct rtw89_dev *rtwdev, is_multicast_ether_addr(hdr->addr1)) return; - if (tx) { - stats->tx_cnt++; - stats->tx_unicast += skb->len; - } else { - stats->rx_cnt++; - stats->rx_unicast += skb->len; + if (accu_dev) + __rtw89_traffic_stats_accu(&rtwdev->stats, skb, tx); + + if (rtwvif) { + __rtw89_traffic_stats_accu(&rtwvif->stats, skb, tx); + __rtw89_traffic_stats_accu(&rtwvif->stats_ps, skb, tx); } } @@ -1150,8 +1160,8 @@ static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev, tx_req.rtwsta_link = rtwsta_link; tx_req.desc_info.sw_mld = sw_mld; - rtw89_traffic_stats_accu(rtwdev, &rtwdev->stats, skb, true); - rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, true); + rtw89_traffic_stats_accu(rtwdev, rtwvif, skb, true, true); + rtw89_wow_parse_akm(rtwdev, skb); rtw89_core_tx_update_desc_info(rtwdev, &tx_req); rtw89_core_tx_wake(rtwdev, &tx_req); @@ -2267,7 +2277,7 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, if (desc_info->data_rate < RTW89_HW_RATE_NR) pkt_stat->rx_rate_cnt[desc_info->data_rate]++; - rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, false); + rtw89_traffic_stats_accu(rtwdev, rtwvif, skb, false, false); out: rcu_read_unlock(); @@ -2280,7 +2290,7 @@ static void rtw89_core_rx_stats(struct rtw89_dev *rtwdev, { struct rtw89_vif_rx_stats_iter_data iter_data; - rtw89_traffic_stats_accu(rtwdev, &rtwdev->stats, skb, false); + rtw89_traffic_stats_accu(rtwdev, NULL, skb, true, false); iter_data.rtwdev = rtwdev; iter_data.phy_ppdu = phy_ppdu; @@ -3570,9 +3580,22 @@ void rtw89_roc_work(struct wiphy *wiphy, struct wiphy_work *work) } static enum rtw89_tfc_lv rtw89_get_traffic_level(struct rtw89_dev *rtwdev, - u32 throughput, u64 cnt) + u32 throughput, u64 cnt, + enum rtw89_tfc_interval interval) { - if (cnt < 100) + u64 cnt_level; + + switch (interval) { + default: + case RTW89_TFC_INTERVAL_100MS: + cnt_level = 5; + break; + case RTW89_TFC_INTERVAL_2SEC: + cnt_level = 100; + break; + } + + if (cnt < cnt_level) return RTW89_TFC_IDLE; if (throughput > 50) return RTW89_TFC_HIGH; @@ -3584,13 +3607,14 @@ static enum rtw89_tfc_lv rtw89_get_traffic_level(struct rtw89_dev *rtwdev, } static bool rtw89_traffic_stats_calc(struct rtw89_dev *rtwdev, - struct rtw89_traffic_stats *stats) + struct rtw89_traffic_stats *stats, + enum rtw89_tfc_interval interval) { enum rtw89_tfc_lv tx_tfc_lv = stats->tx_tfc_lv; enum rtw89_tfc_lv rx_tfc_lv = stats->rx_tfc_lv; - stats->tx_throughput_raw = (u32)(stats->tx_unicast >> RTW89_TP_SHIFT); - stats->rx_throughput_raw = (u32)(stats->rx_unicast >> RTW89_TP_SHIFT); + stats->tx_throughput_raw = rtw89_bytes_to_mbps(stats->tx_unicast, interval); + stats->rx_throughput_raw = rtw89_bytes_to_mbps(stats->rx_unicast, interval); ewma_tp_add(&stats->tx_ewma_tp, stats->tx_throughput_raw); ewma_tp_add(&stats->rx_ewma_tp, stats->rx_throughput_raw); @@ -3598,9 +3622,9 @@ static bool rtw89_traffic_stats_calc(struct rtw89_dev *rtwdev, stats->tx_throughput = ewma_tp_read(&stats->tx_ewma_tp); stats->rx_throughput = ewma_tp_read(&stats->rx_ewma_tp); stats->tx_tfc_lv = rtw89_get_traffic_level(rtwdev, stats->tx_throughput, - stats->tx_cnt); + stats->tx_cnt, interval); stats->rx_tfc_lv = rtw89_get_traffic_level(rtwdev, stats->rx_throughput, - stats->rx_cnt); + stats->rx_cnt, interval); stats->tx_avg_len = stats->tx_cnt ? DIV_ROUND_DOWN_ULL(stats->tx_unicast, stats->tx_cnt) : 0; stats->rx_avg_len = stats->rx_cnt ? @@ -3626,10 +3650,12 @@ static bool rtw89_traffic_stats_track(struct rtw89_dev *rtwdev) unsigned int link_id; bool tfc_changed; - tfc_changed = rtw89_traffic_stats_calc(rtwdev, &rtwdev->stats); + tfc_changed = rtw89_traffic_stats_calc(rtwdev, &rtwdev->stats, + RTW89_TFC_INTERVAL_2SEC); rtw89_for_each_rtwvif(rtwdev, rtwvif) { - rtw89_traffic_stats_calc(rtwdev, &rtwvif->stats); + rtw89_traffic_stats_calc(rtwdev, &rtwvif->stats, + RTW89_TFC_INTERVAL_2SEC); rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) rtw89_fw_h2c_tp_offload(rtwdev, rtwvif_link); @@ -3649,8 +3675,8 @@ static void rtw89_enter_lps_track(struct rtw89_dev *rtwdev) if (rtwvif->offchan) continue; - if (rtwvif->stats.tx_tfc_lv != RTW89_TFC_IDLE || - rtwvif->stats.rx_tfc_lv != RTW89_TFC_IDLE) + if (rtwvif->stats_ps.tx_tfc_lv >= RTW89_TFC_MID || + rtwvif->stats_ps.rx_tfc_lv >= RTW89_TFC_MID) continue; vif = rtwvif_to_vif(rtwvif); @@ -3789,6 +3815,34 @@ static void rtw89_core_mlo_track(struct rtw89_dev *rtwdev) } } +static void rtw89_track_ps_work(struct wiphy *wiphy, struct wiphy_work *work) +{ + struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev, + track_ps_work.work); + struct rtw89_vif *rtwvif; + + lockdep_assert_wiphy(wiphy); + + if (test_bit(RTW89_FLAG_FORBIDDEN_TRACK_WORK, rtwdev->flags)) + return; + + if (!test_bit(RTW89_FLAG_RUNNING, rtwdev->flags)) + return; + + wiphy_delayed_work_queue(wiphy, &rtwdev->track_ps_work, + RTW89_TRACK_PS_WORK_PERIOD); + + rtw89_for_each_rtwvif(rtwdev, rtwvif) + rtw89_traffic_stats_calc(rtwdev, &rtwvif->stats_ps, + RTW89_TFC_INTERVAL_100MS); + + if (rtwdev->scanning) + return; + + if (rtwdev->lps_enabled && !rtwdev->btc.lps) + rtw89_enter_lps_track(rtwdev); +} + static void rtw89_track_work(struct wiphy *wiphy, struct wiphy_work *work) { struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev, @@ -4875,6 +4929,8 @@ int rtw89_core_start(struct rtw89_dev *rtwdev) wiphy_delayed_work_queue(rtwdev->hw->wiphy, &rtwdev->track_work, RTW89_TRACK_WORK_PERIOD); + wiphy_delayed_work_queue(rtwdev->hw->wiphy, &rtwdev->track_ps_work, + RTW89_TRACK_PS_WORK_PERIOD); set_bit(RTW89_FLAG_RUNNING, rtwdev->flags); @@ -4909,6 +4965,7 @@ void rtw89_core_stop(struct rtw89_dev *rtwdev) wiphy_work_cancel(wiphy, &btc->icmp_notify_work); cancel_delayed_work_sync(&rtwdev->txq_reinvoke_work); wiphy_delayed_work_cancel(wiphy, &rtwdev->track_work); + wiphy_delayed_work_cancel(wiphy, &rtwdev->track_ps_work); wiphy_delayed_work_cancel(wiphy, &rtwdev->chanctx_work); wiphy_delayed_work_cancel(wiphy, &rtwdev->coex_act1_work); wiphy_delayed_work_cancel(wiphy, &rtwdev->coex_bt_devinfo_work); @@ -5136,6 +5193,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) INIT_WORK(&rtwdev->txq_work, rtw89_core_txq_work); INIT_DELAYED_WORK(&rtwdev->txq_reinvoke_work, rtw89_core_txq_reinvoke_work); wiphy_delayed_work_init(&rtwdev->track_work, rtw89_track_work); + wiphy_delayed_work_init(&rtwdev->track_ps_work, rtw89_track_ps_work); wiphy_delayed_work_init(&rtwdev->chanctx_work, rtw89_chanctx_work); wiphy_delayed_work_init(&rtwdev->coex_act1_work, rtw89_coex_act1_work); wiphy_delayed_work_init(&rtwdev->coex_bt_devinfo_work, rtw89_coex_bt_devinfo_work); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index a08d07e44498..1d8f89e83c9a 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -40,6 +40,7 @@ extern const struct ieee80211_ops rtw89_ops; #define BYPASS_CR_DATA 0xbabecafe #define RTW89_TRACK_WORK_PERIOD round_jiffies_relative(HZ * 2) +#define RTW89_TRACK_PS_WORK_PERIOD msecs_to_jiffies(100) #define RTW89_FORBID_BA_TIMER round_jiffies_relative(HZ * 4) #define CFO_TRACK_MAX_USER 64 #define MAX_RSSI 110 @@ -1392,6 +1393,11 @@ struct rtw89_btc_wl_smap { u32 emlsr: 1; }; +enum rtw89_tfc_interval { + RTW89_TFC_INTERVAL_100MS, + RTW89_TFC_INTERVAL_2SEC, +}; + enum rtw89_tfc_lv { RTW89_TFC_IDLE, RTW89_TFC_ULTRA_LOW, @@ -1400,7 +1406,6 @@ enum rtw89_tfc_lv { RTW89_TFC_HIGH, }; -#define RTW89_TP_SHIFT 18 /* bytes/2s --> Mbps */ DECLARE_EWMA(tp, 10, 2); struct rtw89_traffic_stats { @@ -5943,6 +5948,7 @@ struct rtw89_dev { } bbs[RTW89_PHY_NUM]; struct wiphy_delayed_work track_work; + struct wiphy_delayed_work track_ps_work; struct wiphy_delayed_work chanctx_work; struct wiphy_delayed_work coex_act1_work; struct wiphy_delayed_work coex_bt_devinfo_work; @@ -5993,6 +5999,7 @@ struct rtw89_vif { __be32 ip_addr; struct rtw89_traffic_stats stats; + struct rtw89_traffic_stats stats_ps; u32 tdls_peer; struct ieee80211_scan_ies *scan_ies; @@ -7305,6 +7312,17 @@ static inline bool rtw89_is_rtl885xb(struct rtw89_dev *rtwdev) return false; } +static inline u32 rtw89_bytes_to_mbps(u64 bytes, enum rtw89_tfc_interval interval) +{ + switch (interval) { + default: + case RTW89_TFC_INTERVAL_2SEC: + return bytes >> 18; /* bytes/2s --> Mbps */; + case RTW89_TFC_INTERVAL_100MS: + return (bytes * 10) >> 17; /* bytes/100ms --> Mbps */ + } +} + int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel); int rtw89_h2c_tx(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index a3ae1e654a98..c982ad633b4a 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -1772,6 +1772,7 @@ static int rtw89_ops_suspend(struct ieee80211_hw *hw, set_bit(RTW89_FLAG_FORBIDDEN_TRACK_WORK, rtwdev->flags); wiphy_delayed_work_cancel(hw->wiphy, &rtwdev->track_work); + wiphy_delayed_work_cancel(hw->wiphy, &rtwdev->track_ps_work); ret = rtw89_wow_suspend(rtwdev, wowlan); if (ret) { @@ -1797,6 +1798,8 @@ static int rtw89_ops_resume(struct ieee80211_hw *hw) clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WORK, rtwdev->flags); wiphy_delayed_work_queue(hw->wiphy, &rtwdev->track_work, RTW89_TRACK_WORK_PERIOD); + wiphy_delayed_work_queue(hw->wiphy, &rtwdev->track_ps_work, + RTW89_TRACK_PS_WORK_PERIOD); return ret ? 1 : 0; } diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c index d504518b8a57..bb39fdbcba0d 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -492,6 +492,7 @@ static void ser_reset_trx_st_hdl(struct rtw89_ser *ser, u8 evt) case SER_EV_STATE_IN: wiphy_lock(wiphy); wiphy_delayed_work_cancel(wiphy, &rtwdev->track_work); + wiphy_delayed_work_cancel(wiphy, &rtwdev->track_ps_work); wiphy_unlock(wiphy); drv_stop_tx(ser); @@ -525,6 +526,8 @@ static void ser_reset_trx_st_hdl(struct rtw89_ser *ser, u8 evt) drv_resume_tx(ser); wiphy_delayed_work_queue(wiphy, &rtwdev->track_work, RTW89_TRACK_WORK_PERIOD); + wiphy_delayed_work_queue(wiphy, &rtwdev->track_ps_work, + RTW89_TRACK_PS_WORK_PERIOD); break; default: diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 34a0ab49bd7a..c935d6683d83 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -12,7 +12,7 @@ #include "util.h" #include "wow.h" -void rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb) +void __rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb) { struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; struct rtw89_wow_param *rtw_wow = &rtwdev->wow; diff --git a/drivers/net/wireless/realtek/rtw89/wow.h b/drivers/net/wireless/realtek/rtw89/wow.h index f91991e8f2e3..6606528d31c7 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.h +++ b/drivers/net/wireless/realtek/rtw89/wow.h @@ -116,9 +116,21 @@ static inline bool rtw_wow_has_mgd_features(struct rtw89_dev *rtwdev) return !bitmap_empty(rtw_wow->flags, RTW89_WOW_FLAG_NUM); } +void __rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb); + +static inline +void rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (likely(!ieee80211_is_assoc_req(hdr->frame_control))) + return; + + __rtw89_wow_parse_akm(rtwdev, skb); +} + int rtw89_wow_suspend(struct rtw89_dev *rtwdev, struct cfg80211_wowlan *wowlan); int rtw89_wow_resume(struct rtw89_dev *rtwdev); -void rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb); #else static inline void rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb) From 5e9184ae7207c828d3721e9fdaeeb61da0994995 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sat, 5 Jul 2025 22:36:59 +0300 Subject: [PATCH 064/199] wifi: rtw89: 8852bx: Accept USB devices and load their MAC address Make __rtw8852bx_read_efuse() accept USB devices and load the MAC address from the correct offset. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/1f58d168-67a9-4d86-9e6a-73789c7a59f4@gmail.com --- .../net/wireless/realtek/rtw89/rtw8852b_common.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c index 0cf03f18cbb1..3fb2972ae6f6 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c @@ -172,14 +172,6 @@ static const struct rtw89_reg3_def rtw8852bx_btc_preagc_dis_defs[] = { static DECLARE_PHY_REG3_TBL(rtw8852bx_btc_preagc_dis_defs); -static void rtw8852be_efuse_parsing(struct rtw89_efuse *efuse, - struct rtw8852bx_efuse *map) -{ - ether_addr_copy(efuse->addr, map->e.mac_addr); - efuse->rfe_type = map->rfe_type; - efuse->xtal_cap = map->xtal_k; -} - static void rtw8852bx_efuse_parsing_tssi(struct rtw89_dev *rtwdev, struct rtw8852bx_efuse *map) { @@ -261,12 +253,18 @@ static int __rtw8852bx_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, switch (rtwdev->hci.type) { case RTW89_HCI_TYPE_PCIE: - rtw8852be_efuse_parsing(efuse, map); + ether_addr_copy(efuse->addr, map->e.mac_addr); + break; + case RTW89_HCI_TYPE_USB: + ether_addr_copy(efuse->addr, map->u.mac_addr); break; default: return -EOPNOTSUPP; } + efuse->rfe_type = map->rfe_type; + efuse->xtal_cap = map->xtal_k; + rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); return 0; From 0980de01da08338d4a7ceaf5e7ab25a56142c75a Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sat, 5 Jul 2025 22:37:32 +0300 Subject: [PATCH 065/199] wifi: rtw89: 8852b: Fix rtw8852b_pwr_{on,off}_func() for USB There are a few differences in the power on/off functions between PCIE and USB. The changes in the power off function in particular are needed for the RTL8832BU to be able to power on again after it's powered off. While the RTL8832BU appears to work without the changes in the power on function, it's probably best to implement them, in case they are needed in some situations. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/c12da54f-88e6-4b11-8587-36f9cac13bf3@gmail.com --- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index b0b73a4a70a0..85b6849db798 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -299,7 +299,8 @@ static int rtw8852b_pwr_on_func(struct rtw89_dev *rtwdev) rtw89_write8_clr(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); rtw89_write8_set(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); - rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL, B_AX_PCIE_CALIB_EN_V1); + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) + rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL, B_AX_PCIE_CALIB_EN_V1); rtw89_write32_set(rtwdev, R_AX_SYS_ADIE_PAD_PWR_CTRL, B_AX_SYM_PADPDN_WL_PTA_1P3); @@ -361,7 +362,7 @@ static int rtw8852b_pwr_on_func(struct rtw89_dev *rtwdev) rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_ON_CTRL0, B_AX_VOL_L1_MASK, 0x9); rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_ON_CTRL0, B_AX_VREFPFM_L_MASK, 0xA); - if (rtwdev->hal.cv == CHIP_CBV) { + if (rtwdev->hal.cv == CHIP_CBV && rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) { rtw89_write32_set(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK); rtw89_write16_mask(rtwdev, R_AX_HCI_LDO_CTRL, B_AX_R_AX_VADJ_MASK, 0xA); rtw89_write32_clr(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK); @@ -443,10 +444,22 @@ static int rtw8852b_pwr_off_func(struct rtw89_dev *rtwdev) if (ret) return ret; - rtw89_write32(rtwdev, R_AX_WLLPS_CTRL, SW_LPS_OPTION); + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) + rtw89_write32(rtwdev, R_AX_WLLPS_CTRL, SW_LPS_OPTION); + else if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) + rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_SOP_EDSWR); + rtw89_write32_set(rtwdev, R_AX_SYS_SWR_CTRL1, B_AX_SYM_CTRL_SPS_PWMFREQ); rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_ON_CTRL0, B_AX_REG_ZCDC_H_MASK, 0x3); - rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFM_SWLPS); + + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) { + rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFM_SWLPS); + } else if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) { + val32 = rtw89_read32(rtwdev, R_AX_SYS_PW_CTRL); + val32 &= ~B_AX_AFSM_PCIE_SUS_EN; + val32 |= B_AX_AFSM_WLSUS_EN; + rtw89_write32(rtwdev, R_AX_SYS_PW_CTRL, val32); + } return 0; } From b57b556a02e6ac1192ab57d5c3a045ad34182b7a Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sat, 5 Jul 2025 22:38:14 +0300 Subject: [PATCH 066/199] wifi: rtw89: 8852b: Add rtw8852b_dle_mem_usb3 "dle" could be "Data Link Engine" or "Double Link Engine". These are some parameters needed for RTL8852BU. In this case the same parameters are used for USB 2 and USB 3. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/7224021b-4fb5-44bc-aeb1-3a6fd3625f2a@gmail.com --- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 85b6849db798..50eed21371a5 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -66,6 +66,19 @@ static const struct rtw89_dle_mem rtw8852b_dle_mem_pcie[] = { NULL}, }; +static const struct rtw89_dle_mem rtw8852b_dle_mem_usb3[] = { + [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size25, + &rtw89_mac_size.ple_size33, &rtw89_mac_size.wde_qt25, + &rtw89_mac_size.wde_qt25, &rtw89_mac_size.ple_qt74, + &rtw89_mac_size.ple_qt75}, + [RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size9, + &rtw89_mac_size.ple_size8, &rtw89_mac_size.wde_qt4, + &rtw89_mac_size.wde_qt4, &rtw89_mac_size.ple_qt13, + &rtw89_mac_size.ple_qt13}, + [RTW89_QTA_INVALID] = {RTW89_QTA_INVALID, NULL, NULL, NULL, NULL, NULL, + NULL}, +}; + static const u32 rtw8852b_h2c_regs[RTW89_H2CREG_MAX] = { R_AX_H2CREG_DATA0, R_AX_H2CREG_DATA1, R_AX_H2CREG_DATA2, R_AX_H2CREG_DATA3 @@ -834,7 +847,10 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, .hfc_param_ini = {rtw8852b_hfc_param_ini_pcie, NULL, NULL}, - .dle_mem = {rtw8852b_dle_mem_pcie, NULL, NULL, NULL}, + .dle_mem = {rtw8852b_dle_mem_pcie, + rtw8852b_dle_mem_usb3, + rtw8852b_dle_mem_usb3, + NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000, 0xf000}, From f56b4446d07ac42ef7e71789a9256fa2f8260876 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sat, 5 Jul 2025 22:38:35 +0300 Subject: [PATCH 067/199] wifi: rtw89: 8852b: Add rtw8852b_hfc_param_ini_usb "hfc" means "hci fc" which is "Host Control Interface Flow Control". These are some parameters needed for RTL8852BU. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/40dd1597-27d8-4316-ac3b-4bf7ff9f3e2f@gmail.com --- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 50eed21371a5..33ab71d84ffc 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -49,6 +49,48 @@ static const struct rtw89_hfc_param_ini rtw8852b_hfc_param_ini_pcie[] = { [RTW89_QTA_INVALID] = {NULL}, }; +static const struct rtw89_hfc_ch_cfg rtw8852b_hfc_chcfg_usb[] = { + {18, 152, grp_0}, /* ACH 0 */ + {18, 152, grp_0}, /* ACH 1 */ + {18, 152, grp_0}, /* ACH 2 */ + {18, 152, grp_0}, /* ACH 3 */ + {0, 0, grp_0}, /* ACH 4 */ + {0, 0, grp_0}, /* ACH 5 */ + {0, 0, grp_0}, /* ACH 6 */ + {0, 0, grp_0}, /* ACH 7 */ + {18, 152, grp_0}, /* B0MGQ */ + {18, 152, grp_0}, /* B0HIQ */ + {0, 0, grp_0}, /* B1MGQ */ + {0, 0, grp_0}, /* B1HIQ */ + {0, 0, 0} /* FWCMDQ */ +}; + +static const struct rtw89_hfc_pub_cfg rtw8852b_hfc_pubcfg_usb = { + 152, /* Group 0 */ + 0, /* Group 1 */ + 152, /* Public Max */ + 0 /* WP threshold */ +}; + +static const struct rtw89_hfc_prec_cfg rtw8852b_hfc_preccfg_usb = { + 9, /* CH 0-11 pre-cost */ + 32, /* H2C pre-cost */ + 64, /* WP CH 0-7 pre-cost */ + 24, /* WP CH 8-11 pre-cost */ + 1, /* CH 0-11 full condition */ + 1, /* H2C full condition */ + 1, /* WP CH 0-7 full condition */ + 1, /* WP CH 8-11 full condition */ +}; + +static const struct rtw89_hfc_param_ini rtw8852b_hfc_param_ini_usb[] = { + [RTW89_QTA_SCC] = {rtw8852b_hfc_chcfg_usb, &rtw8852b_hfc_pubcfg_usb, + &rtw8852b_hfc_preccfg_usb, RTW89_HCIFC_STF}, + [RTW89_QTA_DLFW] = {NULL, NULL, + &rtw8852b_hfc_preccfg_usb, RTW89_HCIFC_STF}, + [RTW89_QTA_INVALID] = {NULL}, +}; + static const struct rtw89_dle_mem rtw8852b_dle_mem_pcie[] = { [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size7, &rtw89_mac_size.ple_size6, &rtw89_mac_size.wde_qt7, @@ -846,7 +888,9 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .max_amsdu_limit = 5000, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, - .hfc_param_ini = {rtw8852b_hfc_param_ini_pcie, NULL, NULL}, + .hfc_param_ini = {rtw8852b_hfc_param_ini_pcie, + rtw8852b_hfc_param_ini_usb, + NULL}, .dle_mem = {rtw8852b_dle_mem_pcie, rtw8852b_dle_mem_usb3, rtw8852b_dle_mem_usb3, From 0ed2a8b1a14e9ebaa72a98b8ee9938cb16c2d606 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sat, 5 Jul 2025 22:38:55 +0300 Subject: [PATCH 068/199] wifi: rtw89: Add rtw8852bu.c This is the entry point for the new rtw89_8852bu module. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/bac25b31-8146-4738-b8f2-eba66c51f3d8@gmail.com --- .../net/wireless/realtek/rtw89/rtw8852bu.c | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852bu.c diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bu.c b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c new file mode 100644 index 000000000000..b315cb997758 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2025 Realtek Corporation + */ + +#include +#include +#include "rtw8852b.h" +#include "usb.h" + +static const struct rtw89_driver_info rtw89_8852bu_info = { + .chip = &rtw8852b_chip_info, + .variant = NULL, + .quirks = NULL, +}; + +static const struct usb_device_id rtw_8852bu_id_table[] = { + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xb832, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xb83a, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xb852, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xb85a, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xa85b, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0586, 0x3428, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x1a62, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0db0, 0x6931, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x3574, 0x6121, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x35bc, 0x0100, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x35bc, 0x0108, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0x6822, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + {}, +}; +MODULE_DEVICE_TABLE(usb, rtw_8852bu_id_table); + +static struct usb_driver rtw_8852bu_driver = { + .name = KBUILD_MODNAME, + .id_table = rtw_8852bu_id_table, + .probe = rtw89_usb_probe, + .disconnect = rtw89_usb_disconnect, +}; +module_usb_driver(rtw_8852bu_driver); + +MODULE_AUTHOR("Bitterblue Smith "); +MODULE_DESCRIPTION("Realtek 802.11ax wireless 8852BU driver"); +MODULE_LICENSE("Dual BSD/GPL"); From 4b295f4fdc80e9b13bd2ca05f4c9434fa0857cab Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sat, 5 Jul 2025 22:39:21 +0300 Subject: [PATCH 069/199] wifi: rtw89: Enable the new rtw89_8852bu module Enable compilation of the new rtw89_8852bu module. Tested mostly in station mode, and a little bit in AP mode. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/627e9e92-6f10-45de-a340-19b10d7bad82@gmail.com --- drivers/net/wireless/realtek/rtw89/Kconfig | 12 ++++++++++++ drivers/net/wireless/realtek/rtw89/Makefile | 3 +++ 2 files changed, 15 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/Kconfig b/drivers/net/wireless/realtek/rtw89/Kconfig index bd180f3369c3..4288c30b400a 100644 --- a/drivers/net/wireless/realtek/rtw89/Kconfig +++ b/drivers/net/wireless/realtek/rtw89/Kconfig @@ -86,6 +86,18 @@ config RTW89_8852BE 802.11ax PCIe wireless network (Wi-Fi 6) adapter +config RTW89_8852BU + tristate "Realtek 8852BU USB wireless network (Wi-Fi 6) adapter" + depends on USB + select RTW89_CORE + select RTW89_USB + select RTW89_8852B + select RTW89_8852B_COMMON + help + Select this option will enable support for 8852BU chipset + + 802.11ax USB wireless network (Wi-Fi 6) adapter + config RTW89_8852BTE tristate "Realtek 8852BE-VT PCI wireless network (Wi-Fi 6) adapter" depends on PCI diff --git a/drivers/net/wireless/realtek/rtw89/Makefile b/drivers/net/wireless/realtek/rtw89/Makefile index 891e2d55c335..23e43c444f69 100644 --- a/drivers/net/wireless/realtek/rtw89/Makefile +++ b/drivers/net/wireless/realtek/rtw89/Makefile @@ -55,6 +55,9 @@ rtw89_8852b-objs := rtw8852b.o \ obj-$(CONFIG_RTW89_8852BE) += rtw89_8852be.o rtw89_8852be-objs := rtw8852be.o +obj-$(CONFIG_RTW89_8852BU) += rtw89_8852bu.o +rtw89_8852bu-objs := rtw8852bu.o + obj-$(CONFIG_RTW89_8852BT) += rtw89_8852bt.o rtw89_8852bt-objs := rtw8852bt.o \ rtw8852bt_rfk.o \ From ebebe66ec208d37e3368b91e2033907cb5140821 Mon Sep 17 00:00:00 2001 From: Sarika Sharma Date: Tue, 1 Jul 2025 16:29:23 +0530 Subject: [PATCH 070/199] wifi: ath12k: fill link station statistics for MLO Introduce ath12k_mac_op_link_sta_statistics(), to report link level station statistics for MLO. The link_station_info structure is filled from arsta and arsta is fetch from corresponding ahsta->link[link_id]. Therefore, this will be helpful to check the link related statistics. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Signed-off-by: Sarika Sharma Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250701105927.803342-2-quic_sarishar@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 78 +++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 6dd4441ce9a0..8fcfb374fc86 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -12444,6 +12444,83 @@ static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG); } +static void ath12k_mac_op_link_sta_statistics(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta, + struct link_station_info *link_sinfo) +{ + struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(link_sta->sta); + struct ath12k_fw_stats_req_params params = {}; + struct ath12k_link_sta *arsta; + struct ath12k *ar; + s8 signal; + bool db2dbm; + + lockdep_assert_wiphy(hw->wiphy); + + arsta = wiphy_dereference(hw->wiphy, ahsta->link[link_sta->link_id]); + + if (!arsta) + return; + + ar = ath12k_get_ar_by_vif(hw, vif, arsta->link_id); + if (!ar) + return; + + db2dbm = test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT, + ar->ab->wmi_ab.svc_map); + + link_sinfo->rx_duration = arsta->rx_duration; + link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION); + + link_sinfo->tx_duration = arsta->tx_duration; + link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_DURATION); + + if (arsta->txrate.legacy || arsta->txrate.nss) { + if (arsta->txrate.legacy) { + link_sinfo->txrate.legacy = arsta->txrate.legacy; + } else { + link_sinfo->txrate.mcs = arsta->txrate.mcs; + link_sinfo->txrate.nss = arsta->txrate.nss; + link_sinfo->txrate.bw = arsta->txrate.bw; + link_sinfo->txrate.he_gi = arsta->txrate.he_gi; + link_sinfo->txrate.he_dcm = arsta->txrate.he_dcm; + link_sinfo->txrate.he_ru_alloc = + arsta->txrate.he_ru_alloc; + link_sinfo->txrate.eht_gi = arsta->txrate.eht_gi; + link_sinfo->txrate.eht_ru_alloc = + arsta->txrate.eht_ru_alloc; + } + link_sinfo->txrate.flags = arsta->txrate.flags; + link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); + } + + /* TODO: Use real NF instead of default one. */ + signal = arsta->rssi_comb; + + params.pdev_id = ar->pdev->pdev_id; + params.vdev_id = 0; + params.stats_id = WMI_REQUEST_VDEV_STAT; + + if (!signal && + ahsta->ahvif->vdev_type == WMI_VDEV_TYPE_STA && + !(ath12k_mac_get_fw_stats(ar, ¶ms))) + signal = arsta->rssi_beacon; + + if (signal) { + link_sinfo->signal = + db2dbm ? signal : signal + ATH12K_DEFAULT_NOISE_FLOOR; + link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); + } + + link_sinfo->signal_avg = ewma_avg_rssi_read(&arsta->avg_rssi); + + if (!db2dbm) + link_sinfo->signal_avg += ATH12K_DEFAULT_NOISE_FLOOR; + + link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG); +} + static int ath12k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -12679,6 +12756,7 @@ 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, + .link_sta_statistics = ath12k_mac_op_link_sta_statistics, .remain_on_channel = ath12k_mac_op_remain_on_channel, .cancel_remain_on_channel = ath12k_mac_op_cancel_remain_on_channel, .change_sta_links = ath12k_mac_op_change_sta_links, From 3b8aa249d0fce93590888a6ed3d22b458091ecb9 Mon Sep 17 00:00:00 2001 From: Sarika Sharma Date: Tue, 1 Jul 2025 16:29:24 +0530 Subject: [PATCH 071/199] wifi: ath12k: add link support for multi-link in arsta Currently, statistics in arsta are updated at deflink for both non-ML and multi-link(ML) station. Link statistics are not updated for multi-link operation(MLO). Hence, add support to correctly obtain the link ID if the peer is ML, fetch the arsta from the appropriate link ID, and update the statistics in the corresponding arsta. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Signed-off-by: Sarika Sharma Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250701105927.803342-3-quic_sarishar@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/dp_mon.c | 22 ++++++++++++++------ drivers/net/wireless/ath/ath12k/dp_rx.c | 11 +++++----- drivers/net/wireless/ath/ath12k/peer.h | 26 ++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index b408103fe9d4..8189e52ed007 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -3615,7 +3615,6 @@ ath12k_dp_mon_rx_update_user_stats(struct ath12k *ar, struct hal_rx_mon_ppdu_info *ppdu_info, u32 uid) { - struct ath12k_sta *ahsta; struct ath12k_link_sta *arsta; struct ath12k_rx_peer_stats *rx_stats = NULL; struct hal_rx_user_status *user_stats = &ppdu_info->userstats[uid]; @@ -3633,8 +3632,13 @@ ath12k_dp_mon_rx_update_user_stats(struct ath12k *ar, return; } - ahsta = ath12k_sta_to_ahsta(peer->sta); - arsta = &ahsta->deflink; + arsta = ath12k_peer_get_link_sta(ar->ab, peer); + if (!arsta) { + ath12k_warn(ar->ab, "link sta not found on peer %pM id %d\n", + peer->addr, peer->peer_id); + return; + } + arsta->rssi_comb = ppdu_info->rssi_comb; ewma_avg_rssi_add(&arsta->avg_rssi, ppdu_info->rssi_comb); rx_stats = arsta->rx_stats; @@ -3747,7 +3751,6 @@ int ath12k_dp_mon_srng_process(struct ath12k *ar, int *budget, struct dp_srng *mon_dst_ring; struct hal_srng *srng; struct dp_rxdma_mon_ring *buf_ring; - struct ath12k_sta *ahsta = NULL; struct ath12k_link_sta *arsta; struct ath12k_peer *peer; struct sk_buff_head skb_list; @@ -3873,8 +3876,15 @@ move_next: } if (ppdu_info->reception_type == HAL_RX_RECEPTION_TYPE_SU) { - ahsta = ath12k_sta_to_ahsta(peer->sta); - arsta = &ahsta->deflink; + arsta = ath12k_peer_get_link_sta(ar->ab, peer); + if (!arsta) { + ath12k_warn(ar->ab, "link sta not found on peer %pM id %d\n", + peer->addr, peer->peer_id); + spin_unlock_bh(&ab->base_lock); + rcu_read_unlock(); + dev_kfree_skb_any(skb); + continue; + } ath12k_dp_mon_rx_update_peer_su_stats(ar, arsta, ppdu_info); } else if ((ppdu_info->fc_valid) && diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 420a9b161f4a..f0cfe03d74b6 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -1417,8 +1417,6 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, { struct ath12k_base *ab = ar->ab; struct ath12k_peer *peer; - struct ieee80211_sta *sta; - struct ath12k_sta *ahsta; struct ath12k_link_sta *arsta; struct htt_ppdu_stats_user_rate *user_rate; struct ath12k_per_peer_tx_stats *peer_stats = &ar->peer_tx_stats; @@ -1499,9 +1497,12 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, return; } - sta = peer->sta; - ahsta = ath12k_sta_to_ahsta(sta); - arsta = &ahsta->deflink; + arsta = ath12k_peer_get_link_sta(ab, peer); + if (!arsta) { + spin_unlock_bh(&ab->base_lock); + rcu_read_unlock(); + return; + } memset(&arsta->txrate, 0, sizeof(arsta->txrate)); diff --git a/drivers/net/wireless/ath/ath12k/peer.h b/drivers/net/wireless/ath/ath12k/peer.h index f3a5e054d2b5..92c4988df2f1 100644 --- a/drivers/net/wireless/ath/ath12k/peer.h +++ b/drivers/net/wireless/ath/ath12k/peer.h @@ -91,5 +91,31 @@ struct ath12k_peer *ath12k_peer_find_by_ast(struct ath12k_base *ab, int ast_hash int ath12k_peer_ml_create(struct ath12k_hw *ah, struct ieee80211_sta *sta); int ath12k_peer_ml_delete(struct ath12k_hw *ah, struct ieee80211_sta *sta); int ath12k_peer_mlo_link_peers_delete(struct ath12k_vif *ahvif, struct ath12k_sta *ahsta); +static inline +struct ath12k_link_sta *ath12k_peer_get_link_sta(struct ath12k_base *ab, + struct ath12k_peer *peer) +{ + struct ath12k_sta *ahsta; + struct ath12k_link_sta *arsta; + + if (!peer->sta) + return NULL; + + ahsta = ath12k_sta_to_ahsta(peer->sta); + if (peer->ml_id & ATH12K_PEER_ML_ID_VALID) { + if (!(ahsta->links_map & BIT(peer->link_id))) { + ath12k_warn(ab, "peer %pM id %d link_id %d can't found in STA link_map 0x%x\n", + peer->addr, peer->peer_id, peer->link_id, + ahsta->links_map); + return NULL; + } + arsta = rcu_dereference(ahsta->link[peer->link_id]); + if (!arsta) + return NULL; + } else { + arsta = &ahsta->deflink; + } + return arsta; +} #endif /* _PEER_H_ */ From ebde0514b4f4e78b5f9629179ca947d98b77da15 Mon Sep 17 00:00:00 2001 From: Sarika Sharma Date: Tue, 1 Jul 2025 16:29:25 +0530 Subject: [PATCH 072/199] wifi: ath12k: add EHT support for TX rate Currently, TX rates are not supported for EHT. Hence, add EHT handling for TX rates and update the EHT-specific fields in arsta accordingly. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Signed-off-by: Sarika Sharma Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250701105927.803342-4-quic_sarishar@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/dp_rx.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index f0cfe03d74b6..0f5edc81fc5d 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -1535,6 +1535,16 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, v = ath12k_he_ru_tones_to_nl80211_he_ru_alloc(tones); arsta->txrate.he_ru_alloc = v; break; + case WMI_RATE_PREAMBLE_EHT: + arsta->txrate.mcs = mcs; + arsta->txrate.flags = RATE_INFO_FLAGS_EHT_MCS; + arsta->txrate.he_dcm = dcm; + arsta->txrate.eht_gi = ath12k_mac_eht_gi_to_nl80211_eht_gi(sgi); + tones = le16_to_cpu(user_rate->ru_end) - + le16_to_cpu(user_rate->ru_start) + 1; + v = ath12k_mac_eht_ru_tones_to_nl80211_eht_ru_alloc(tones); + arsta->txrate.eht_ru_alloc = v; + break; } arsta->txrate.nss = nss; From e0618fca1af294f2e52ec3545d76ee5d937c177e Mon Sep 17 00:00:00 2001 From: Sarika Sharma Date: Tue, 1 Jul 2025 16:29:26 +0530 Subject: [PATCH 073/199] wifi: ath12k: correctly update bw for ofdma packets Currently, arsta->txrate.bw is filled from ath12k_mac_bw_to_mac80211_bw(bw) during ath12k_update_per_peer_tx_stats(). But in tx_completion path bw is filled differently if ppdu_type is ofdma for HE/EHT rates. Hence, update arsta->txrate.bw correctly if packet is ofdma for HE and EHT rate. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Signed-off-by: Sarika Sharma Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250701105927.803342-5-quic_sarishar@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/dp.h | 2 ++ drivers/net/wireless/ath/ath12k/dp_rx.c | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index a353333f83b6..0c1fece27264 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -1559,6 +1559,8 @@ enum HTT_PPDU_STATS_PPDU_TYPE { #define HTT_PPDU_STATS_USER_RATE_FLAGS_DCM_M BIT(28) #define HTT_PPDU_STATS_USER_RATE_FLAGS_LDPC_M BIT(29) +#define HTT_USR_RATE_PPDU_TYPE(_val) \ + le32_get_bits(_val, HTT_PPDU_STATS_USER_RATE_INFO1_PPDU_TYPE_M) #define HTT_USR_RATE_PREAMBLE(_val) \ le32_get_bits(_val, HTT_PPDU_STATS_USER_RATE_FLAGS_PREAMBLE_M) #define HTT_USR_RATE_BW(_val) \ diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 0f5edc81fc5d..7be9f8c02c67 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -1423,12 +1423,12 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, struct htt_ppdu_user_stats *usr_stats = &ppdu_stats->user_stats[user]; struct htt_ppdu_stats_common *common = &ppdu_stats->common; int ret; - u8 flags, mcs, nss, bw, sgi, dcm, rate_idx = 0; + u8 flags, mcs, nss, bw, sgi, dcm, ppdu_type, rate_idx = 0; u32 v, succ_bytes = 0; u16 tones, rate = 0, succ_pkts = 0; u32 tx_duration = 0; u8 tid = HTT_PPDU_STATS_NON_QOS_TID; - bool is_ampdu = false; + bool is_ampdu = false, is_ofdma; if (!(usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_RATE))) return; @@ -1457,6 +1457,10 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, sgi = HTT_USR_RATE_GI(user_rate->rate_flags); dcm = HTT_USR_RATE_DCM(user_rate->rate_flags); + ppdu_type = HTT_USR_RATE_PPDU_TYPE(user_rate->info1); + is_ofdma = (ppdu_type == HTT_PPDU_STATS_PPDU_TYPE_MU_OFDMA) || + (ppdu_type == HTT_PPDU_STATS_PPDU_TYPE_MU_MIMO_OFDMA); + /* Note: If host configured fixed rates and in some other special * cases, the broadcast/management frames are sent in different rates. * Firmware rate's control to be skipped for this? @@ -1506,6 +1510,8 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, memset(&arsta->txrate, 0, sizeof(arsta->txrate)); + arsta->txrate.bw = ath12k_mac_bw_to_mac80211_bw(bw); + switch (flags) { case WMI_RATE_PREAMBLE_OFDM: arsta->txrate.legacy = rate; @@ -1534,6 +1540,8 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, le16_to_cpu(user_rate->ru_start) + 1; v = ath12k_he_ru_tones_to_nl80211_he_ru_alloc(tones); arsta->txrate.he_ru_alloc = v; + if (is_ofdma) + arsta->txrate.bw = RATE_INFO_BW_HE_RU; break; case WMI_RATE_PREAMBLE_EHT: arsta->txrate.mcs = mcs; @@ -1544,11 +1552,12 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, le16_to_cpu(user_rate->ru_start) + 1; v = ath12k_mac_eht_ru_tones_to_nl80211_eht_ru_alloc(tones); arsta->txrate.eht_ru_alloc = v; + if (is_ofdma) + arsta->txrate.bw = RATE_INFO_BW_EHT_RU; break; } arsta->txrate.nss = nss; - arsta->txrate.bw = ath12k_mac_bw_to_mac80211_bw(bw); arsta->tx_duration += tx_duration; memcpy(&arsta->last_txrate, &arsta->txrate, sizeof(struct rate_info)); From a0b963e1da5bff03a43c87b96ae3c0ed78a11960 Mon Sep 17 00:00:00 2001 From: Sarika Sharma Date: Tue, 1 Jul 2025 16:29:27 +0530 Subject: [PATCH 074/199] wifi: ath12k: fetch tx_retry and tx_failed from htt_ppdu_stats_user_cmpltn_common_tlv Currently, tx_retries and tx_failed are updated only in mac80211 during tx_completion path for sta->deflink. This works fine for non-ML station but for multi-link (ML) station, these values should be updated for sta->link[link_id] as per tx link_id. However, in tx_completion path there is no way to determine the link_id for which packet is retried or failed. Therefore, update the tx_retries and tx_failed in arsta structure from htt_ppdu_stats_user_cmpltn_common_tlv during ath12k_update_per_peer_tx_stats() call to utilize the values from arsta. Also, during 'iw dev xxxx station dump' populate the tx_retries and tx_failed in station_info structure to ensure values are correctly reflected. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Signed-off-by: Sarika Sharma Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250701105927.803342-6-quic_sarishar@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.h | 2 ++ drivers/net/wireless/ath/ath12k/dp_rx.c | 12 +++++++++++- drivers/net/wireless/ath/ath12k/mac.c | 10 ++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 96ff9b08a848..295609d849b8 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -563,6 +563,8 @@ struct ath12k_link_sta { /* for firmware use only */ u8 link_idx; + u32 tx_retry_failed; + u32 tx_retry_count; }; struct ath12k_reoq_buf { diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 7be9f8c02c67..ed325aa6322d 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -1428,14 +1428,22 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, u16 tones, rate = 0, succ_pkts = 0; u32 tx_duration = 0; u8 tid = HTT_PPDU_STATS_NON_QOS_TID; + u16 tx_retry_failed = 0, tx_retry_count = 0; bool is_ampdu = false, is_ofdma; if (!(usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_RATE))) return; - if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON)) + if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON)) { is_ampdu = HTT_USR_CMPLTN_IS_AMPDU(usr_stats->cmpltn_cmn.flags); + tx_retry_failed = + __le16_to_cpu(usr_stats->cmpltn_cmn.mpdu_tried) - + __le16_to_cpu(usr_stats->cmpltn_cmn.mpdu_success); + tx_retry_count = + HTT_USR_CMPLTN_LONG_RETRY(usr_stats->cmpltn_cmn.flags) + + HTT_USR_CMPLTN_SHORT_RETRY(usr_stats->cmpltn_cmn.flags); + } if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_ACK_BA_STATUS)) { @@ -1557,6 +1565,8 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, break; } + arsta->tx_retry_failed += tx_retry_failed; + arsta->tx_retry_count += tx_retry_count; arsta->txrate.nss = nss; arsta->tx_duration += tx_duration; memcpy(&arsta->last_txrate, &arsta->txrate, sizeof(struct rate_info)); diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 8fcfb374fc86..a4d7daee94ec 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -12442,6 +12442,11 @@ static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, sinfo->signal_avg += noise_floor; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG); + + sinfo->tx_retries = arsta->tx_retry_count; + sinfo->tx_failed = arsta->tx_retry_failed; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); } static void ath12k_mac_op_link_sta_statistics(struct ieee80211_hw *hw, @@ -12519,6 +12524,11 @@ static void ath12k_mac_op_link_sta_statistics(struct ieee80211_hw *hw, link_sinfo->signal_avg += ATH12K_DEFAULT_NOISE_FLOOR; link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG); + + link_sinfo->tx_retries = arsta->tx_retry_count; + link_sinfo->tx_failed = arsta->tx_retry_failed; + link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); + link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); } static int ath12k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw, From d45d015448fcfbb5dde7c09f2b0dffe5d689e6ca Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Mon, 30 Jun 2025 09:45:15 +0530 Subject: [PATCH 075/199] wifi: ath12k: add support for Tx Power insertion in RRM action frame For certain action frames like the TPC Report IE in the spectrum management TPC Report action frame, and in the Radio Measurement Link Measurement Report action frame there is a requirement to fill in the current and max Tx power of the device in the packet. Add support to populate these fields in the relevant packets. In software-encrypted cases such as PMF, skip insertion since the packets are already encrypted and cannot be modified. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aditya Kumar Singh Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250630-support-for-tx-power-insertion-v1-1-77f45484d5bb@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 182 ++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index a4d7daee94ec..67e51cbb75e6 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -8360,6 +8360,174 @@ static void ath12k_mgmt_over_wmi_tx_purge(struct ath12k *ar) ath12k_mgmt_over_wmi_tx_drop(ar, skb); } +static int ath12k_mac_mgmt_action_frame_fill_elem_data(struct ath12k_link_vif *arvif, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + u8 category, *buf, iv_len, action_code, dialog_token; + struct ieee80211_bss_conf *link_conf; + struct ieee80211_chanctx_conf *conf; + int cur_tx_power, max_tx_power; + struct ath12k *ar = arvif->ar; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); + struct wiphy *wiphy = hw->wiphy; + struct ath12k_skb_cb *skb_cb; + struct ieee80211_mgmt *mgmt; + unsigned int remaining_len; + bool has_protected; + + lockdep_assert_wiphy(wiphy); + + /* make sure category field is present */ + if (skb->len < IEEE80211_MIN_ACTION_SIZE) + return -EINVAL; + + remaining_len = skb->len - IEEE80211_MIN_ACTION_SIZE; + has_protected = ieee80211_has_protected(hdr->frame_control); + + /* In case of SW crypto and hdr protected (PMF), packet will already be encrypted, + * we can't put in data in this case + */ + if (test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags) && + has_protected) + return 0; + + mgmt = (struct ieee80211_mgmt *)hdr; + buf = (u8 *)&mgmt->u.action; + + /* FCTL_PROTECTED frame might have extra space added for HDR_LEN. Offset that + * many bytes if it is there + */ + if (has_protected) { + skb_cb = ATH12K_SKB_CB(skb); + + switch (skb_cb->cipher) { + /* Cipher suite having flag %IEEE80211_KEY_FLAG_GENERATE_IV_MGMT set in + * key needs to be processed. See ath12k_install_key() + */ + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_CCMP_256: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: + iv_len = IEEE80211_CCMP_HDR_LEN; + break; + case WLAN_CIPHER_SUITE_TKIP: + iv_len = 0; + break; + default: + return -EINVAL; + } + + if (remaining_len < iv_len) + return -EINVAL; + + buf += iv_len; + remaining_len -= iv_len; + } + + category = *buf++; + /* category code is already taken care in %IEEE80211_MIN_ACTION_SIZE hence + * no need to adjust remaining_len + */ + + switch (category) { + case WLAN_CATEGORY_RADIO_MEASUREMENT: + /* need action code and dialog token */ + if (remaining_len < 2) + return -EINVAL; + + /* Packet Format: + * Action Code | Dialog Token | Variable Len (based on Action Code) + */ + action_code = *buf++; + dialog_token = *buf++; + remaining_len -= 2; + + link_conf = ath12k_mac_get_link_bss_conf(arvif); + if (!link_conf) { + ath12k_warn(ar->ab, + "failed to get bss link conf for vdev %d in RM handling\n", + arvif->vdev_id); + return -EINVAL; + } + + conf = wiphy_dereference(wiphy, link_conf->chanctx_conf); + if (!conf) + return -ENOENT; + + cur_tx_power = link_conf->txpower; + max_tx_power = min(conf->def.chan->max_reg_power, + (int)ar->max_tx_power / 2); + + ath12k_mac_op_get_txpower(hw, arvif->ahvif->vif, arvif->link_id, + &cur_tx_power); + + switch (action_code) { + case WLAN_RM_ACTION_LINK_MEASUREMENT_REQUEST: + /* need variable fields to be present in len */ + if (remaining_len < 2) + return -EINVAL; + + /* Variable length format as defined in IEEE 802.11-2024, + * Figure 9-1187-Link Measurement Request frame Action field + * format. + * Transmit Power | Max Tx Power + * We fill both of these. + */ + *buf++ = cur_tx_power; + *buf = max_tx_power; + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "RRM: Link Measurement Req dialog_token %u cur_tx_power %d max_tx_power %d\n", + dialog_token, cur_tx_power, max_tx_power); + break; + case WLAN_RM_ACTION_LINK_MEASUREMENT_REPORT: + /* need variable fields to be present in len */ + if (remaining_len < 3) + return -EINVAL; + + /* Variable length format as defined in IEEE 802.11-2024, + * Figure 9-1188-Link Measurement Report frame Action field format + * TPC Report | Variable Fields + * + * TPC Report Format: + * Element ID | Len | Tx Power | Link Margin + * + * We fill Tx power in the TPC Report (2nd index) + */ + buf[2] = cur_tx_power; + + /* TODO: At present, Link margin data is not present so can't + * really fill it now. Once it is available, it can be added + * here + */ + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "RRM: Link Measurement Report dialog_token %u cur_tx_power %d\n", + dialog_token, cur_tx_power); + break; + default: + return -EINVAL; + } + break; + default: + /* nothing to fill */ + return 0; + } + + return 0; +} + +static int ath12k_mac_mgmt_frame_fill_elem_data(struct ath12k_link_vif *arvif, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (!ieee80211_is_action(hdr->frame_control)) + return 0; + + return ath12k_mac_mgmt_action_frame_fill_elem_data(arvif, skb); +} + static void ath12k_mgmt_over_wmi_tx_work(struct wiphy *wiphy, struct wiphy_work *work) { struct ath12k *ar = container_of(work, struct ath12k, wmi_mgmt_tx_work); @@ -8391,6 +8559,20 @@ static void ath12k_mgmt_over_wmi_tx_work(struct wiphy *wiphy, struct wiphy_work arvif = wiphy_dereference(ah->hw->wiphy, ahvif->link[skb_cb->link_id]); if (ar->allocated_vdev_map & (1LL << arvif->vdev_id)) { + /* Fill in the data which is required to be filled by the driver + * For example: Max Tx power in Link Measurement Request/Report + */ + ret = ath12k_mac_mgmt_frame_fill_elem_data(arvif, skb); + if (ret) { + /* If we couldn't fill the data due to any reason, + * let's not discard transmitting the packet. + * For example: Software crypto and PMF case + */ + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "Failed to fill the required data for the mgmt packet err %d\n", + ret); + } + 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", From 93a1cdb9cd94c7b8a2aac33e4b13ca61d712f5eb Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Mon, 30 Jun 2025 09:45:16 +0530 Subject: [PATCH 076/199] wifi: ath12k: advertise NL80211_FEATURE_TX_POWER_INSERTION support Now that driver is capable of inserting Tx power, advertise the support for the same to upper layers. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aditya Kumar Singh Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250630-support-for-tx-power-insertion-v1-2-77f45484d5bb@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 67e51cbb75e6..b2cf3abfe390 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -13744,6 +13744,8 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | NL80211_FEATURE_AP_SCAN; + wiphy->features |= NL80211_FEATURE_TX_POWER_INSERTION; + /* MLO is not yet supported so disable Wireless Extensions for now * to make sure ath12k users don't use it. This flag can be removed * once WIPHY_FLAG_SUPPORTS_MLO is enabled. From 80570587e418f361e7ce3f9200477f728b38c94b Mon Sep 17 00:00:00 2001 From: Aaradhana Sahu Date: Mon, 30 Jun 2025 08:45:02 +0530 Subject: [PATCH 077/199] wifi: ath12k: Block radio bring-up in FTM mode Ensure that all radios remain down when the driver operates in Factory Test Mode (FTM). Reject any userspace attempts to bring up an interface in this mode. Currently, the driver allows userspace to bring up the interface even though it operates in FTM mode, which violates FTM constraints and leads to FTM command failures. Hence, block the radio start when the driver is in FTM mode. Also, remove ath12k_ftm_mode check from ath12k_drain_tx() because FTM mode check is already handled in the caller function (ath12k_mac_op_start()). Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Fixes: 3bc374cbc49e ("wifi: ath12k: add factory test mode support") Signed-off-by: Aaradhana Sahu Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250630031502.8902-1-aaradhana.sahu@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index b2cf3abfe390..50a474f8bc22 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -9101,14 +9101,9 @@ err: static void ath12k_drain_tx(struct ath12k_hw *ah) { - struct ath12k *ar = ah->radio; + struct ath12k *ar; int i; - if (ath12k_ftm_mode) { - ath12k_err(ar->ab, "fail to start mac operations in ftm mode\n"); - return; - } - lockdep_assert_wiphy(ah->hw->wiphy); for_each_ar(ah, ar, i) @@ -9121,6 +9116,9 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw) struct ath12k *ar; int ret, i; + if (ath12k_ftm_mode) + return -EPERM; + lockdep_assert_wiphy(hw->wiphy); ath12k_drain_tx(ah); From acab697c32f7a38ec0e9721ac02febd295e8df74 Mon Sep 17 00:00:00 2001 From: Sarika Sharma Date: Mon, 30 Jun 2025 12:14:31 +0530 Subject: [PATCH 078/199] wifi: ath12k: properly set bit for pdev mask for firmware PPDU_STATS request Currently, the HTT_H2T_MSG_TYPE_PPDU_STATS_CFG request uses bits 8 to 15 as the bitmask for HTT_PPDU_STATS_CFG_PDEV_ID for firmware PPDU_STATS. However, bit 8 is reserved for SOC stats, and the actual PDEV ID should be encoded using bits 9 to 15. This leads to incorrect PDEV ID encoding in the request, causing it to either ignore the request or apply it to the wrong PDEV. Additionally, pdev_mask calculation is done as pdev_mask = 1 << (i + 1); (i.e. i= num_rxmda_per_pdev) but this is not valid for multiple pdevs(multi-MAC configurations) with 1 rxdma per pdev, as this will mask the same value for all pdevs. To correctly identify each and exact MAC in multi-MAC configurations, the calculation should include ar->pdev_idx: pdev_mask = 1 << i + ar->pdev_idx; Due to these issues, the firmware does not send PPDU_STATS for the intended PDEV, leading to inaccurate and incomplete statistics on the host. This might trigger certain WARN_ON() conditions in host that rely on these statistics. Hence, change the bitmask for HTT_PPDU_STATS_CFG_PDEV_ID as bit 9 to 15 to properly fill the pdev id in request message and change the pdev_mask calculation to consider ar->pdev_idx to mask pdev correctly. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Signed-off-by: Sarika Sharma Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250630064431.3446333-1-quic_sarishar@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/dp.h | 3 ++- drivers/net/wireless/ath/ath12k/dp_tx.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index 0c1fece27264..6df07b23b705 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -703,7 +703,8 @@ struct htt_ppdu_stats_cfg_cmd { } __packed; #define HTT_PPDU_STATS_CFG_MSG_TYPE GENMASK(7, 0) -#define HTT_PPDU_STATS_CFG_PDEV_ID GENMASK(15, 8) +#define HTT_PPDU_STATS_CFG_SOC_STATS BIT(8) +#define HTT_PPDU_STATS_CFG_PDEV_ID GENMASK(15, 9) #define HTT_PPDU_STATS_CFG_TLV_TYPE_BITMASK GENMASK(31, 16) enum htt_ppdu_stats_tag_type { diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index ca3d97043da0..1fa37cda1046 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -1257,7 +1257,7 @@ int ath12k_dp_tx_htt_h2t_ppdu_stats_req(struct ath12k *ar, u32 mask) cmd->msg = le32_encode_bits(HTT_H2T_MSG_TYPE_PPDU_STATS_CFG, HTT_PPDU_STATS_CFG_MSG_TYPE); - pdev_mask = 1 << (i + 1); + pdev_mask = 1 << (i + ar->pdev_idx); cmd->msg |= le32_encode_bits(pdev_mask, HTT_PPDU_STATS_CFG_PDEV_ID); cmd->msg |= le32_encode_bits(mask, HTT_PPDU_STATS_CFG_TLV_TYPE_BITMASK); From a1bff3d6cc454d65a3a654cd3fcd0c90f1fb45fb Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Mon, 30 Jun 2025 10:15:31 +0530 Subject: [PATCH 079/199] wifi: ath12k: Add num_stations counter for each interface Currently, ath12k driver maintains a counter to store the number of stations connected to each radio. However, at certain times like debugging, it is useful to know number of stations connected to any one of the interface in that radio. Add support to maintain a counter for number of stations connected to each interface. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Aditya Kumar Singh Signed-off-by: Roopni Devanathan Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250630044531.3490058-1-quic_rdevanat@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.h | 1 + drivers/net/wireless/ath/ath12k/mac.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 295609d849b8..afc8329980c8 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -349,6 +349,7 @@ struct ath12k_link_vif { bool group_key_valid; struct wmi_vdev_install_key_arg group_key; bool pairwise_key_done; + u16 num_stations; }; struct ath12k_vif { diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 50a474f8bc22..42eb9e8e14d1 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -3858,6 +3858,8 @@ static void ath12k_mac_init_arvif(struct ath12k_vif *ahvif, INIT_DELAYED_WORK(&arvif->connection_loss_work, ath12k_mac_vif_sta_connection_loss_work); + arvif->num_stations = 0; + for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) { arvif->bitrate_mask.control[i].legacy = 0xffffffff; arvif->bitrate_mask.control[i].gi = NL80211_TXRATE_DEFAULT_GI; @@ -6168,6 +6170,11 @@ static int ath12k_mac_inc_num_stations(struct ath12k_link_vif *arvif, return -ENOBUFS; ar->num_stations++; + arvif->num_stations++; + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "mac station %pM connected to vdev %u num_stations %u\n", + arsta->addr, arvif->vdev_id, arvif->num_stations); return 0; } @@ -6184,6 +6191,17 @@ static void ath12k_mac_dec_num_stations(struct ath12k_link_vif *arvif, return; ar->num_stations--; + + if (arvif->num_stations) { + arvif->num_stations--; + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "mac station %pM disconnected from vdev %u num_stations %u\n", + arsta->addr, arvif->vdev_id, arvif->num_stations); + } else { + ath12k_warn(ar->ab, + "mac station %pM disconnect for vdev %u without any connected station\n", + arsta->addr, arvif->vdev_id); + } } static void ath12k_mac_station_post_remove(struct ath12k *ar, From 2109e98503bc1c01c399feac68cc8b7faf6d0a4a Mon Sep 17 00:00:00 2001 From: Harshitha Prem Date: Tue, 1 Jul 2025 19:29:02 +0530 Subject: [PATCH 080/199] wifi: ath12k: update unsupported bandwidth flags in reg rules The maximum bandwidth an interface can operate in is defined by the configured country. However, currently, it is able to operate in bandwidths greater than the allowed bandwidth. For example, the Central African Republic (CF) supports a maximum bandwidth of 40 MHz in both the 2 GHz and 5 GHz bands, but an interface is still able to operate in bandwidths higher than 40 MHz. This issue arises because the regulatory rules in the regd are not updated with these restrictions received from firmware on the maximum bandwidth. Hence, update the regulatory rules with unsupported bandwidth flags based on the maximum bandwidth to ensure compliance with country-specific regulations. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00284-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Signed-off-by: Harshitha Prem Signed-off-by: Amith A Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250701135902.722851-1-quic_amitajit@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/reg.c | 31 ++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c index 96254d6fc675..7898f6981e5a 100644 --- a/drivers/net/wireless/ath/ath12k/reg.c +++ b/drivers/net/wireless/ath/ath12k/reg.c @@ -426,6 +426,29 @@ ath12k_map_fw_dfs_region(enum ath12k_dfs_region dfs_region) } } +static u32 ath12k_get_bw_reg_flags(u16 max_bw) +{ + switch (max_bw) { + case 20: + return NL80211_RRF_NO_HT40 | + NL80211_RRF_NO_80MHZ | + NL80211_RRF_NO_160MHZ | + NL80211_RRF_NO_320MHZ; + case 40: + return NL80211_RRF_NO_80MHZ | + NL80211_RRF_NO_160MHZ | + NL80211_RRF_NO_320MHZ; + case 80: + return NL80211_RRF_NO_160MHZ | + NL80211_RRF_NO_320MHZ; + case 160: + return NL80211_RRF_NO_320MHZ; + case 320: + default: + return 0; + } +} + static u32 ath12k_map_fw_reg_flags(u16 reg_flags) { u32 flags = 0; @@ -704,7 +727,7 @@ ath12k_reg_build_regd(struct ath12k_base *ab, reg_rule = reg_info->reg_rules_2g_ptr + i; max_bw = min_t(u16, reg_rule->max_bw, reg_info->max_bw_2g); - flags = 0; + flags = ath12k_get_bw_reg_flags(reg_info->max_bw_2g); ath12k_reg_update_freq_range(&ab->reg_freq_2ghz, reg_rule); } else if (reg_info->num_5g_reg_rules && (j < reg_info->num_5g_reg_rules)) { @@ -718,13 +741,15 @@ ath12k_reg_build_regd(struct ath12k_base *ab, * BW correction if required and applies flags as * per other BW rule flags we pass from here */ - flags = NL80211_RRF_AUTO_BW; + flags = NL80211_RRF_AUTO_BW | + ath12k_get_bw_reg_flags(reg_info->max_bw_5g); ath12k_reg_update_freq_range(&ab->reg_freq_5ghz, reg_rule); } else if (reg_info->is_ext_reg_event && reg_6ghz_number && (k < reg_6ghz_number)) { reg_rule = reg_rule_6ghz + k++; max_bw = min_t(u16, reg_rule->max_bw, max_bw_6ghz); - flags = NL80211_RRF_AUTO_BW; + flags = NL80211_RRF_AUTO_BW | + ath12k_get_bw_reg_flags(max_bw_6ghz); if (reg_rule->psd_flag) flags |= NL80211_RRF_PSD; ath12k_reg_update_freq_range(&ab->reg_freq_6ghz, reg_rule); From fee9b1f6691120182136edacf590f52d62d9de7f Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Wed, 2 Jul 2025 14:29:12 -0700 Subject: [PATCH 081/199] wifi: ath12k: pack HTT pdev rate stats structs In order to ensure the HTT DebugFS structs shared with firmware have matching alignment, the structs should be packed. Most of the structs are correctly packed, however the following are not: ath12k_htt_tx_pdev_rate_stats_tlv ath12k_htt_rx_pdev_rate_stats_tlv ath12k_htt_rx_pdev_rate_ext_stats_tlv So pack those structs. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00284-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Fixes: ba42b22aa336 ("wifi: ath12k: Dump PDEV transmit rate HTT stats") Fixes: a24cd7583003 ("wifi: ath12k: Dump PDEV receive rate HTT stats") Fixes: 7a3e8eec8d18 ("wifi: ath12k: Dump additional PDEV receive rate HTT stats") Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250702-debugfs_htt_packed-v1-1-07bd18b31e79@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h index 13fbfb069ead..9bd3a632b002 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h @@ -490,7 +490,7 @@ struct ath12k_htt_tx_pdev_rate_stats_tlv { [ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA_MCS_COUNTERS]; __le32 tx_mcs_ext_2[ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA2_MCS_COUNTERS]; __le32 tx_bw_320mhz; -}; +} __packed; struct ath12k_htt_tx_histogram_stats_tlv { __le32 rate_retry_mcs_drop_cnt; @@ -579,7 +579,7 @@ struct ath12k_htt_rx_pdev_rate_stats_tlv { __le32 rx_ulofdma_non_data_nusers[ATH12K_HTT_RX_PDEV_MAX_OFDMA_NUM_USER]; __le32 rx_ulofdma_data_nusers[ATH12K_HTT_RX_PDEV_MAX_OFDMA_NUM_USER]; __le32 rx_mcs_ext[ATH12K_HTT_RX_PDEV_STATS_NUM_EXTRA_MCS_COUNTERS]; -}; +} __packed; #define ATH12K_HTT_RX_PDEV_STATS_NUM_BW_EXT_COUNTERS 4 #define ATH12K_HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS_EXT 14 @@ -609,7 +609,7 @@ struct ath12k_htt_rx_pdev_rate_ext_stats_tlv { __le32 rx_gi_ext_2[ATH12K_HTT_RX_PDEV_STATS_NUM_GI_COUNTERS] [ATH12K_HTT_RX_PDEV_STATS_NUM_EXTRA2_MCS_COUNTERS]; __le32 rx_su_punctured_mode[ATH12K_HTT_RX_PDEV_STATS_NUM_PUNCTURED_MODE_COUNTERS]; -}; +} __packed; #define ATH12K_HTT_TX_PDEV_STATS_SCHED_PER_TXQ_MAC_ID GENMASK(7, 0) #define ATH12K_HTT_TX_PDEV_STATS_SCHED_PER_TXQ_ID GENMASK(15, 8) From 0424cc3d70f6bd72e6501c730b1f95ba966e2ee9 Mon Sep 17 00:00:00 2001 From: P Praneesh Date: Thu, 5 Jun 2025 10:31:35 +0530 Subject: [PATCH 082/199] wifi: ath12k: set RX_FLAG_SKIP_MONITOR in WBM error path Packets delivered to mac80211 from the WBM error path currently do not have the RX_FLAG_SKIP_MONITOR flag set in status->flag. As a result, mac80211 performs unnecessary monitor mode checks on each packet, even though these packets are not intended for monitor mode processing. In regular rx path, this flag is explicitly set to avoid such overhead. Align the WBM error path behavior by setting RX_FLAG_SKIP_MONITOR to prevent redundant per-packet checks in mac80211. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: P Praneesh Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250605050135.1802902-1-praneesh.p@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/dp_rx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index ed325aa6322d..c95568f0e5d8 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -4022,6 +4022,8 @@ static void ath12k_dp_rx_wbm_err(struct ath12k *ar, return; } + rx_info.rx_status->flag |= RX_FLAG_SKIP_MONITOR; + ath12k_dp_rx_deliver_msdu(ar, napi, msdu, &rx_info); } From 27ba973caaf85ff3a2a23eca33d6dc9b4fe405e8 Mon Sep 17 00:00:00 2001 From: Karthikeyan Kathirvel Date: Wed, 4 Jun 2025 15:46:20 +0530 Subject: [PATCH 083/199] wifi: ath12k: allow beacon protection keys to be installed in hardware Install beacon protection keys in hardware for AP modes only if hardware supports it, as indicated by the WMI service bit WMI_TLV_SERVICE_BEACON_PROTECTION_SUPPORT. Allow keyidx up to 7, since beacon protection uses keyidx 6 and 7. Control this feature by setting bit 0 of feature_enable_bitmap when sending the WMI_BCN_TMPL_CMDID command to firmware. Check for the beacon protection enabled bit in both tx and non-tx profiles for MBSSID cases. If set in either profile, enable the beacon protection feature in firmware for transmitted vif. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Kathirvel Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250604101620.2948103-1-karthikeyan.kathirvel@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.h | 1 + drivers/net/wireless/ath/ath12k/mac.c | 52 ++++++++++++++++++++------ drivers/net/wireless/ath/ath12k/wmi.c | 3 ++ drivers/net/wireless/ath/ath12k/wmi.h | 5 ++- 4 files changed, 48 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index afc8329980c8..042d6bcd1c6e 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -316,6 +316,7 @@ struct ath12k_link_vif { int bank_id; u8 vdev_id_check_en; + bool beacon_prot; struct wmi_wmm_params_all_arg wmm_params; struct list_head list; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 42eb9e8e14d1..5333da9cac1b 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -1496,11 +1496,13 @@ static int ath12k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui, return 0; } -static void ath12k_mac_set_arvif_ies(struct ath12k_link_vif *arvif, struct sk_buff *bcn, +static void ath12k_mac_set_arvif_ies(struct ath12k_link_vif *arvif, + struct ath12k_link_vif *tx_arvif, + struct sk_buff *bcn, u8 bssid_index, bool *nontx_profile_found) { struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)bcn->data; - const struct element *elem, *nontx, *index, *nie; + const struct element *elem, *nontx, *index, *nie, *ext_cap_ie; const u8 *start, *tail; u16 rem_len; u8 i; @@ -1518,6 +1520,11 @@ static void ath12k_mac_set_arvif_ies(struct ath12k_link_vif *arvif, struct sk_bu start, rem_len)) arvif->wpaie_present = true; + ext_cap_ie = cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY, start, rem_len); + if (ext_cap_ie && ext_cap_ie->datalen >= 11 && + (ext_cap_ie->data[10] & WLAN_EXT_CAPA11_BCN_PROTECT)) + tx_arvif->beacon_prot = true; + /* Return from here for the transmitted profile */ if (!bssid_index) return; @@ -1560,6 +1567,19 @@ static void ath12k_mac_set_arvif_ies(struct ath12k_link_vif *arvif, struct sk_bu if (index->data[0] == bssid_index) { *nontx_profile_found = true; + + /* Check if nontx BSS has beacon protection enabled */ + if (!tx_arvif->beacon_prot) { + ext_cap_ie = + cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY, + nontx->data, + nontx->datalen); + if (ext_cap_ie && ext_cap_ie->datalen >= 11 && + (ext_cap_ie->data[10] & + WLAN_EXT_CAPA11_BCN_PROTECT)) + tx_arvif->beacon_prot = true; + } + if (cfg80211_find_ie(WLAN_EID_RSN, nontx->data, nontx->datalen)) { @@ -1608,11 +1628,11 @@ static int ath12k_mac_setup_bcn_tmpl_ema(struct ath12k_link_vif *arvif, } if (tx_arvif == arvif) - ath12k_mac_set_arvif_ies(arvif, beacons->bcn[0].skb, 0, NULL); + ath12k_mac_set_arvif_ies(arvif, tx_arvif, beacons->bcn[0].skb, 0, NULL); for (i = 0; i < beacons->cnt; i++) { if (tx_arvif != arvif && !nontx_profile_found) - ath12k_mac_set_arvif_ies(arvif, beacons->bcn[i].skb, + ath12k_mac_set_arvif_ies(arvif, tx_arvif, beacons->bcn[i].skb, bssid_index, &nontx_profile_found); @@ -1681,9 +1701,9 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_link_vif *arvif) } if (tx_arvif == arvif) { - ath12k_mac_set_arvif_ies(arvif, bcn, 0, NULL); + ath12k_mac_set_arvif_ies(arvif, tx_arvif, bcn, 0, NULL); } else { - ath12k_mac_set_arvif_ies(arvif, bcn, + ath12k_mac_set_arvif_ies(arvif, tx_arvif, bcn, link_conf->bssid_index, &nontx_profile_found); if (!nontx_profile_found) @@ -5305,6 +5325,16 @@ static int ath12k_install_key(struct ath12k_link_vif *arvif, arg.key_cipher = WMI_CIPHER_AES_GCM; key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT; break; + case WLAN_CIPHER_SUITE_AES_CMAC: + arg.key_cipher = WMI_CIPHER_AES_CMAC; + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + arg.key_cipher = WMI_CIPHER_AES_GMAC; + break; + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + arg.key_cipher = WMI_CIPHER_AES_CMAC; + break; default: ath12k_warn(ar->ab, "cipher %d is not supported\n", key->cipher); return -EOPNOTSUPP; @@ -5599,13 +5629,9 @@ static int ath12k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, lockdep_assert_wiphy(hw->wiphy); - /* BIP needs to be done in software */ - if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC || - key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || - key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 || - key->cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256) { + /* IGTK needs to be done in host software */ + if (key->keyidx == 4 || key->keyidx == 5) return 1; - } if (key->keyidx > WMI_MAX_KEY_INDEX) return -ENOSPC; @@ -13809,6 +13835,8 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) } wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_PUNCT); + if (test_bit(WMI_TLV_SERVICE_BEACON_PROTECTION_SUPPORT, ab->wmi_ab.svc_map)) + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION); ath12k_reg_init(hw); diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index b34f2c183312..a6379f19be2c 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -2016,6 +2016,9 @@ int ath12k_wmi_bcn_tmpl(struct ath12k_link_vif *arvif, u32p_replace_bits(&ema_params, 1, WMI_EMA_BEACON_LAST); cmd->ema_params = cpu_to_le32(ema_params); } + cmd->feature_enable_bitmap = + cpu_to_le32(u32_encode_bits(arvif->beacon_prot, + WMI_BEACON_PROTECTION_EN_BIT)); ptr = skb->data + sizeof(*cmd); diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index ed9b4324a7b8..eeea9a22d93b 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2241,6 +2241,7 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_PER_PEER_HTT_STATS_RESET = 213, WMI_TLV_SERVICE_FREQINFO_IN_METADATA = 219, WMI_TLV_SERVICE_EXT2_MSG = 220, + WMI_TLV_SERVICE_BEACON_PROTECTION_SUPPORT = 244, WMI_TLV_SERVICE_MBSS_PARAM_IN_VDEV_START_SUPPORT = 253, WMI_MAX_EXT_SERVICE = 256, @@ -3755,6 +3756,8 @@ struct ath12k_wmi_ftm_event { #define WMI_EMA_BEACON_FIRST GENMASK(23, 16) #define WMI_EMA_BEACON_LAST GENMASK(31, 24) +#define WMI_BEACON_PROTECTION_EN_BIT BIT(0) + struct ath12k_wmi_bcn_tmpl_ema_arg { u8 bcn_cnt; u8 bcn_index; @@ -4723,7 +4726,7 @@ enum wmi_ap_ps_peer_param { #define DISABLE_SIFS_RESPONSE_TRIGGER 0 -#define WMI_MAX_KEY_INDEX 3 +#define WMI_MAX_KEY_INDEX 7 #define WMI_MAX_KEY_LEN 32 enum wmi_key_type { From 979c5ce4a37680063d87fe13d662ed68e06e77c3 Mon Sep 17 00:00:00 2001 From: Sivashankari Madhavan Date: Wed, 9 Jul 2025 19:05:54 +0530 Subject: [PATCH 084/199] wifi: ath12k: support average ack rssi in station dump Currently, the ACK RSSI value is not shown in station dump. Enable WMI resource flag for ACK RSSI in WMI INIT command to add ACK RSSI value in management TX completion event from WMI. Update ACK RSSI value obtained in management and data frame completion path to ieee80211_tx_info. Also advertise NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT flag during hardware register to mac80211 layer so that ACK RSSI is added to station dump message. Example output : Station aa:bb:cc:dd:ee:ff (on wlp88s0) inactive time: 46584 ms rx bytes: 955 rx packets: 10 tx bytes: 769 tx packets: 6 tx retries: 81 tx failed: 0 rx drop misc: 0 signal: -39 dBm signal avg: -40 dBm tx bitrate: 6.0 MBit/s tx duration: 1185 us rx bitrate: 309.7 MBit/s 40MHz HE-MCS 6 HE-NSS 2 HE-GI 0 HE-DCM 0 rx duration: 0 us last ack signal:-41 dBm avg ack signal: -40 dBm authorized: yes authenticated: yes ....... Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-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: Sivashankari Madhavan Signed-off-by: Sowmiya Sree Elavalagan Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250709133554.622463-1-quic_ssreeela@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/dp_tx.c | 3 +++ drivers/net/wireless/ath/ath12k/mac.c | 1 + drivers/net/wireless/ath/ath12k/wmi.c | 15 +++++++++++---- drivers/net/wireless/ath/ath12k/wmi.h | 3 +++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index 1fa37cda1046..56c08199c79f 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -901,6 +901,9 @@ static void ath12k_dp_tx_status_parse(struct ath12k_base *ab, ts->peer_id = le32_get_bits(desc->info3, HAL_WBM_COMPL_TX_INFO3_PEER_ID); + ts->ack_rssi = le32_get_bits(desc->info2, + HAL_WBM_COMPL_TX_INFO2_ACK_FRAME_RSSI); + if (info0 & HAL_TX_RATE_STATS_INFO0_VALID) { ts->pkt_type = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_PKT_TYPE); ts->mcs = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_MCS); diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 5333da9cac1b..1f4deedcd189 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -13816,6 +13816,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_STA_TX_PWR); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT); wiphy->cipher_suites = cipher_suites; wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index a6379f19be2c..b5b1f93ea22d 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -3886,7 +3886,8 @@ ath12k_wmi_copy_resource_config(struct ath12k_base *ab, wmi_cfg->max_bssid_rx_filters = cpu_to_le32(tg_cfg->max_bssid_rx_filters); wmi_cfg->use_pdev_id = cpu_to_le32(tg_cfg->use_pdev_id); wmi_cfg->flag1 = cpu_to_le32(tg_cfg->atf_config | - WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64); + WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 | + WMI_RSRC_CFG_FLAG1_ACK_RSSI); wmi_cfg->peer_map_unmap_version = cpu_to_le32(tg_cfg->peer_map_unmap_version); 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); @@ -6122,7 +6123,7 @@ static int ath12k_pull_mgmt_rx_params_tlv(struct ath12k_base *ab, } static int wmi_process_mgmt_tx_comp(struct ath12k *ar, u32 desc_id, - u32 status) + u32 status, u32 ack_rssi) { struct sk_buff *msdu; struct ieee80211_tx_info *info; @@ -6151,8 +6152,11 @@ static int wmi_process_mgmt_tx_comp(struct ath12k *ar, u32 desc_id, /* skip tx rate update from ieee80211_status*/ info->status.rates[0].idx = -1; - if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) && !status) + if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) && !status) { info->flags |= IEEE80211_TX_STAT_ACK; + info->status.ack_signal = ack_rssi; + info->status.flags |= IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; + } if ((info->flags & IEEE80211_TX_CTL_NO_ACK) && !status) info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; @@ -6196,6 +6200,8 @@ static int ath12k_pull_mgmt_tx_compl_param_tlv(struct ath12k_base *ab, param->pdev_id = ev->pdev_id; param->desc_id = ev->desc_id; param->status = ev->status; + param->ppdu_id = ev->ppdu_id; + param->ack_rssi = ev->ack_rssi; kfree(tb); return 0; @@ -7122,7 +7128,8 @@ static void ath12k_mgmt_tx_compl_event(struct ath12k_base *ab, struct sk_buff *s } wmi_process_mgmt_tx_comp(ar, le32_to_cpu(tx_compl_param.desc_id), - le32_to_cpu(tx_compl_param.status)); + le32_to_cpu(tx_compl_param.status), + le32_to_cpu(tx_compl_param.ack_rssi)); ath12k_dbg(ab, ATH12K_DBG_MGMT, "mgmt tx compl ev pdev_id %d, desc_id %d, status %d", diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index eeea9a22d93b..967a7cc1e3d5 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2527,6 +2527,7 @@ struct wmi_init_cmd { #define WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION GENMASK(5, 4) #define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 BIT(5) #define WMI_RSRC_CFG_FLAGS2_CALC_NEXT_DTIM_COUNT_SET BIT(9) +#define WMI_RSRC_CFG_FLAG1_ACK_RSSI BIT(18) struct ath12k_wmi_resource_config_params { __le32 tlv_header; @@ -4515,6 +4516,8 @@ struct wmi_mgmt_tx_compl_event { __le32 desc_id; __le32 status; __le32 pdev_id; + __le32 ppdu_id; + __le32 ack_rssi; } __packed; struct wmi_scan_event { From defae535dd63b1eb78ba87d5b8c0b4fb5418fe0c Mon Sep 17 00:00:00 2001 From: Aaradhana Sahu Date: Tue, 8 Jul 2025 23:40:59 +0530 Subject: [PATCH 085/199] wifi: ath12k: Add a table of parameters entries impacting memory consumption Introduce ath12k_mem_profile_based_param structure to define configuration parameters for both default and low-memory profiles. Add support for enabling the low-memory profile in the follow-up patch by making the following changes: - Reduce sizes for transmit, receive, and monitor descriptor rings. - Reduce transmit and receive descriptor count. - Limit the maximum number of virtual devices (vdevs) to 9. - Reduce the maximum number of client support per radio. Centralize these parameters in the ath12k_mem_profile_based_param structure to simplify switching between memory profiles. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.5-01651-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 WLAN.HMT.1.1.c5-00284.1-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Aaradhana Sahu Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250708181102.4111054-2-aaradhana.sahu@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.c | 33 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/core.h | 17 +++++++++++++ drivers/net/wireless/ath/ath12k/qmi.c | 2 +- drivers/net/wireless/ath/ath12k/qmi.h | 6 ++++- 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index ffc19a6b9485..8b0c67735171 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -37,6 +37,36 @@ static struct list_head ath12k_hw_group_list = LIST_HEAD_INIT(ath12k_hw_group_li static DEFINE_MUTEX(ath12k_hw_group_mutex); +static const struct +ath12k_mem_profile_based_param ath12k_mem_profile_based_param[] = { +[ATH12K_QMI_MEMORY_MODE_DEFAULT] = { + .num_vdevs = 17, + .max_client_single = 512, + .max_client_dbs = 128, + .max_client_dbs_sbs = 128, + .dp_params = { + .tx_comp_ring_size = 32768, + .rxdma_monitor_buf_ring_size = 4096, + .rxdma_monitor_dst_ring_size = 8092, + .num_pool_tx_desc = 32768, + .rx_desc_count = 12288, + }, + }, +[ATH12K_QMI_MEMORY_MODE_LOW_512_M] = { + .num_vdevs = 9, + .max_client_single = 128, + .max_client_dbs = 64, + .max_client_dbs_sbs = 64, + .dp_params = { + .tx_comp_ring_size = 16384, + .rxdma_monitor_buf_ring_size = 256, + .rxdma_monitor_dst_ring_size = 512, + .num_pool_tx_desc = 16384, + .rx_desc_count = 6144, + }, + }, +}; + static int ath12k_core_rfkill_config(struct ath12k_base *ab) { struct ath12k *ar; @@ -1713,6 +1743,7 @@ static void ath12k_core_reset(struct work_struct *work) int ath12k_core_pre_init(struct ath12k_base *ab) { + const struct ath12k_mem_profile_based_param *param; int ret; ret = ath12k_hw_init(ab); @@ -1721,6 +1752,8 @@ int ath12k_core_pre_init(struct ath12k_base *ab) return ret; } + param = &ath12k_mem_profile_based_param[ATH12K_QMI_MEMORY_MODE_DEFAULT]; + ab->profile_param = param; ath12k_fw_map(ab); return 0; diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 042d6bcd1c6e..b062bbb1737d 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -1011,6 +1011,22 @@ struct ath12k_wsi_info { u32 hw_link_id_base; }; +struct ath12k_dp_profile_params { + u32 tx_comp_ring_size; + u32 rxdma_monitor_buf_ring_size; + u32 rxdma_monitor_dst_ring_size; + u32 num_pool_tx_desc; + u32 rx_desc_count; +}; + +struct ath12k_mem_profile_based_param { + u32 num_vdevs; + u32 max_client_single; + u32 max_client_dbs; + u32 max_client_dbs_sbs; + struct ath12k_dp_profile_params dp_params; +}; + /* Master structure to hold the hw data which may be used in core module */ struct ath12k_base { enum ath12k_hw_rev hw_rev; @@ -1214,6 +1230,7 @@ struct ath12k_base { struct ath12k_reg_freq reg_freq_2ghz; struct ath12k_reg_freq reg_freq_5ghz; struct ath12k_reg_freq reg_freq_6ghz; + const struct ath12k_mem_profile_based_param *profile_param; /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 99e1fb2910d0..5e8943060443 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -3856,7 +3856,7 @@ int ath12k_qmi_init_service(struct ath12k_base *ab) memset(&ab->qmi.target_mem, 0, sizeof(struct target_mem_chunk)); ab->qmi.ab = ab; - ab->qmi.target_mem_mode = ATH12K_QMI_TARGET_MEM_MODE_DEFAULT; + ab->qmi.target_mem_mode = ATH12K_QMI_MEMORY_MODE_DEFAULT; ret = qmi_handle_init(&ab->qmi.handle, ATH12K_QMI_RESP_LEN_MAX, &ath12k_qmi_ops, ath12k_qmi_msg_handlers); if (ret < 0) { diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h index 96e6c3daecfe..abdaade3b542 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.h +++ b/drivers/net/wireless/ath/ath12k/qmi.h @@ -37,7 +37,6 @@ #define QMI_WLANFW_MAX_DATA_SIZE_V01 6144 #define ATH12K_FIRMWARE_MODE_OFF 4 -#define ATH12K_QMI_TARGET_MEM_MODE_DEFAULT 0 #define ATH12K_BOARD_ID_DEFAULT 0xFF @@ -602,6 +601,11 @@ struct qmi_wlanfw_wlan_ini_resp_msg_v01 { struct qmi_response_type_v01 resp; }; +enum ath12k_qmi_mem_mode { + ATH12K_QMI_MEMORY_MODE_DEFAULT = 0, + ATH12K_QMI_MEMORY_MODE_LOW_512_M, +}; + static inline void ath12k_qmi_set_event_block(struct ath12k_qmi *qmi, bool block) { lockdep_assert_held(&qmi->event_lock); From d11d81c46987720e022dd4008d4d1f1f63312e3e Mon Sep 17 00:00:00 2001 From: Aaradhana Sahu Date: Tue, 8 Jul 2025 23:41:00 +0530 Subject: [PATCH 086/199] wifi: ath12k: Remove redundant TID calculation for QCN9274 Currently, host sends num_tids (number of TID (Traffic Identifier)) value to firmware via WMI_INIT_CMD during WMI initialization. However, the firmware does not use this value, as it determines the number of TIDs using its own internal logic. Hence, remove the redundant num_tids calculation logic for QCN9274. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 WLAN.HMT.1.1.c5-00284.1-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Aaradhana Sahu Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250708181102.4111054-3-aaradhana.sahu@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.c | 9 --------- drivers/net/wireless/ath/ath12k/core.h | 1 - drivers/net/wireless/ath/ath12k/hw.h | 2 -- drivers/net/wireless/ath/ath12k/wmi.c | 1 - 4 files changed, 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 8b0c67735171..037486553ba0 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -638,15 +638,6 @@ u32 ath12k_core_get_max_peers_per_radio(struct ath12k_base *ab) 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); -} - struct reserved_mem *ath12k_core_get_reserved_mem(struct ath12k_base *ab, int index) { diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index b062bbb1737d..8638ba49dca4 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -1357,7 +1357,6 @@ 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); void ath12k_core_hw_group_set_mlo_capable(struct ath12k_hw_group *ag); void ath12k_fw_stats_init(struct ath12k *ar); diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 0a75bc5abfa2..4e10d5df2919 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -45,8 +45,6 @@ #define TARGET_NUM_PEERS(x) TARGET_NUM_PEERS_##x #define TARGET_NUM_PEER_KEYS 2 -#define TARGET_NUM_TIDS(x) (2 * TARGET_NUM_PEERS(x) + \ - 4 * TARGET_NUM_VDEVS + 8) #define TARGET_AST_SKID_LIMIT 16 #define TARGET_NUM_OFFLD_PEERS 4 diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index b5b1f93ea22d..78934925ca11 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -204,7 +204,6 @@ void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, config->num_vdevs = ab->num_radios * TARGET_NUM_VDEVS; 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; From 6397b92bbb00f7cda024056c8c8a10594a27ccaa Mon Sep 17 00:00:00 2001 From: Aaradhana Sahu Date: Tue, 8 Jul 2025 23:41:01 +0530 Subject: [PATCH 087/199] wifi: ath12k: Refactor macros to use memory profile-based values Refactor macros to compute values dynamically at runtime based on the ath12k_mem_profile_based_param structure. Remove hardcoded logic to allow driver to operate more efficiently in memory-constrained platforms without significant functional impact. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.5-01651-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 WLAN.HMT.1.1.c5-00284.1-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Aaradhana Sahu Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250708181102.4111054-4-aaradhana.sahu@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.c | 20 ++-- drivers/net/wireless/ath/ath12k/dp.c | 129 +++++++++++++++--------- drivers/net/wireless/ath/ath12k/dp.h | 39 +++---- drivers/net/wireless/ath/ath12k/dp_rx.c | 4 +- drivers/net/wireless/ath/ath12k/dp_tx.c | 13 ++- drivers/net/wireless/ath/ath12k/hw.h | 28 ++--- drivers/net/wireless/ath/ath12k/mac.c | 11 +- drivers/net/wireless/ath/ath12k/wmi.c | 2 +- 8 files changed, 137 insertions(+), 109 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 037486553ba0..53e60dba3bf8 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -623,19 +623,15 @@ exit: 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; + return TARGET_NUM_STATIONS(ab, DBS); + if (ab->num_radios == 3) + return TARGET_NUM_STATIONS(ab, DBS_SBS); + return TARGET_NUM_STATIONS(ab, 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; + return ath12k_core_get_max_station_per_radio(ab) + TARGET_NUM_VDEVS(ab); } struct reserved_mem *ath12k_core_get_reserved_mem(struct ath12k_base *ab, @@ -1353,7 +1349,7 @@ exit: static int ath12k_core_reconfigure_on_crash(struct ath12k_base *ab) { - int ret; + int ret, total_vdev; mutex_lock(&ab->core_lock); ath12k_dp_pdev_free(ab); @@ -1364,8 +1360,8 @@ static int ath12k_core_reconfigure_on_crash(struct ath12k_base *ab) ath12k_dp_free(ab); ath12k_hal_srng_deinit(ab); - - ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1; + total_vdev = ab->num_radios * TARGET_NUM_VDEVS(ab); + ab->free_vdev_map = (1LL << total_vdev) - 1; ret = ath12k_hal_srng_init(ab); if (ret) diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index c6b10acb643e..d80af435959a 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -521,7 +521,7 @@ static int ath12k_dp_srng_common_setup(struct ath12k_base *ab) ret = ath12k_dp_srng_setup(ab, &dp->tx_ring[i].tcl_comp_ring, HAL_WBM2SW_RELEASE, tx_comp_ring_num, 0, - DP_TX_COMP_RING_SIZE); + DP_TX_COMP_RING_SIZE(ab)); if (ret) { ath12k_warn(ab, "failed to set up tcl_comp ring (%d) :%d\n", tx_comp_ring_num, ret); @@ -1164,31 +1164,36 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) /* RX Descriptor cleanup */ spin_lock_bh(&dp->rx_desc_lock); - for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) { - desc_info = dp->rxbaddr[i]; - - for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) { - if (!desc_info[j].in_use) { - list_del(&desc_info[j].list); + if (dp->rxbaddr) { + for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES(ab); i++) { + if (!dp->rxbaddr[i]) continue; + + desc_info = dp->rxbaddr[i]; + + for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) { + if (!desc_info[j].in_use) { + list_del(&desc_info[j].list); + continue; + } + + skb = desc_info[j].skb; + if (!skb) + continue; + + dma_unmap_single(ab->dev, + ATH12K_SKB_RXCB(skb)->paddr, + skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); } - skb = desc_info[j].skb; - if (!skb) - continue; - - dma_unmap_single(ab->dev, ATH12K_SKB_RXCB(skb)->paddr, - skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); - dev_kfree_skb_any(skb); + kfree(dp->rxbaddr[i]); + dp->rxbaddr[i] = NULL; } - } - for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) { - if (!dp->rxbaddr[i]) - continue; - - kfree(dp->rxbaddr[i]); - dp->rxbaddr[i] = NULL; + kfree(dp->rxbaddr); + dp->rxbaddr = NULL; } spin_unlock_bh(&dp->rx_desc_lock); @@ -1197,8 +1202,8 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) for (i = 0; i < ATH12K_HW_MAX_QUEUES; i++) { spin_lock_bh(&dp->tx_desc_lock[i]); - list_for_each_entry_safe(tx_desc_info, tmp1, &dp->tx_desc_used_list[i], - list) { + list_for_each_entry_safe(tx_desc_info, tmp1, + &dp->tx_desc_used_list[i], list) { list_del(&tx_desc_info->list); skb = tx_desc_info->skb; @@ -1232,19 +1237,25 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) spin_unlock_bh(&dp->tx_desc_lock[i]); } - for (pool_id = 0; pool_id < ATH12K_HW_MAX_QUEUES; pool_id++) { - spin_lock_bh(&dp->tx_desc_lock[pool_id]); + if (dp->txbaddr) { + for (pool_id = 0; pool_id < ATH12K_HW_MAX_QUEUES; pool_id++) { + spin_lock_bh(&dp->tx_desc_lock[pool_id]); - for (i = 0; i < ATH12K_TX_SPT_PAGES_PER_POOL; i++) { - tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL; - if (!dp->txbaddr[tx_spt_page]) - continue; + for (i = 0; i < ATH12K_TX_SPT_PAGES_PER_POOL(ab); i++) { + tx_spt_page = i + pool_id * + ATH12K_TX_SPT_PAGES_PER_POOL(ab); + if (!dp->txbaddr[tx_spt_page]) + continue; - kfree(dp->txbaddr[tx_spt_page]); - dp->txbaddr[tx_spt_page] = NULL; + kfree(dp->txbaddr[tx_spt_page]); + dp->txbaddr[tx_spt_page] = NULL; + } + + spin_unlock_bh(&dp->tx_desc_lock[pool_id]); } - spin_unlock_bh(&dp->tx_desc_lock[pool_id]); + kfree(dp->txbaddr); + dp->txbaddr = NULL; } /* unmap SPT pages */ @@ -1393,8 +1404,8 @@ struct ath12k_rx_desc_info *ath12k_dp_get_rx_desc(struct ath12k_base *ab, ppt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_PPT); spt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_SPT); - start_ppt_idx = dp->rx_ppt_base + ATH12K_RX_SPT_PAGE_OFFSET; - end_ppt_idx = start_ppt_idx + ATH12K_NUM_RX_SPT_PAGES; + start_ppt_idx = dp->rx_ppt_base + ATH12K_RX_SPT_PAGE_OFFSET(ab); + end_ppt_idx = start_ppt_idx + ATH12K_NUM_RX_SPT_PAGES(ab); if (ppt_idx < start_ppt_idx || ppt_idx >= end_ppt_idx || @@ -1418,7 +1429,7 @@ struct ath12k_tx_desc_info *ath12k_dp_get_tx_desc(struct ath12k_base *ab, start_ppt_idx = ATH12K_TX_SPT_PAGE_OFFSET; end_ppt_idx = start_ppt_idx + - (ATH12K_TX_SPT_PAGES_PER_POOL * ATH12K_HW_MAX_QUEUES); + (ATH12K_TX_SPT_PAGES_PER_POOL(ab) * ATH12K_HW_MAX_QUEUES); if (ppt_idx < start_ppt_idx || ppt_idx >= end_ppt_idx || @@ -1435,13 +1446,24 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) struct ath12k_dp *dp = &ab->dp; struct ath12k_rx_desc_info *rx_descs, **rx_desc_addr; struct ath12k_tx_desc_info *tx_descs, **tx_desc_addr; + u32 num_rx_spt_pages = ATH12K_NUM_RX_SPT_PAGES(ab); u32 i, j, pool_id, tx_spt_page; u32 ppt_idx, cookie_ppt_idx; spin_lock_bh(&dp->rx_desc_lock); - /* First ATH12K_NUM_RX_SPT_PAGES of allocated SPT pages are used for RX */ - for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) { + dp->rxbaddr = kcalloc(num_rx_spt_pages, + sizeof(struct ath12k_rx_desc_info *), GFP_ATOMIC); + + if (!dp->rxbaddr) { + spin_unlock_bh(&dp->rx_desc_lock); + return -ENOMEM; + } + + /* First ATH12K_NUM_RX_SPT_PAGES(ab) of allocated SPT pages are used for + * RX + */ + for (i = 0; i < num_rx_spt_pages; i++) { rx_descs = kcalloc(ATH12K_MAX_SPT_ENTRIES, sizeof(*rx_descs), GFP_ATOMIC); @@ -1450,7 +1472,7 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) return -ENOMEM; } - ppt_idx = ATH12K_RX_SPT_PAGE_OFFSET + i; + ppt_idx = ATH12K_RX_SPT_PAGE_OFFSET(ab) + i; cookie_ppt_idx = dp->rx_ppt_base + ppt_idx; dp->rxbaddr[i] = &rx_descs[0]; @@ -1468,9 +1490,15 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) spin_unlock_bh(&dp->rx_desc_lock); + dp->txbaddr = kcalloc(ATH12K_NUM_TX_SPT_PAGES(ab), + sizeof(struct ath12k_tx_desc_info *), GFP_ATOMIC); + + if (!dp->txbaddr) + return -ENOMEM; + for (pool_id = 0; pool_id < ATH12K_HW_MAX_QUEUES; pool_id++) { spin_lock_bh(&dp->tx_desc_lock[pool_id]); - for (i = 0; i < ATH12K_TX_SPT_PAGES_PER_POOL; i++) { + for (i = 0; i < ATH12K_TX_SPT_PAGES_PER_POOL(ab); i++) { tx_descs = kcalloc(ATH12K_MAX_SPT_ENTRIES, sizeof(*tx_descs), GFP_ATOMIC); @@ -1480,7 +1508,8 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) return -ENOMEM; } - tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL; + tx_spt_page = i + pool_id * + ATH12K_TX_SPT_PAGES_PER_POOL(ab); ppt_idx = ATH12K_TX_SPT_PAGE_OFFSET + tx_spt_page; dp->txbaddr[tx_spt_page] = &tx_descs[0]; @@ -1514,12 +1543,12 @@ static int ath12k_dp_cmem_init(struct ath12k_base *ab, switch (type) { case ATH12K_DP_TX_DESC: start = ATH12K_TX_SPT_PAGE_OFFSET; - end = start + ATH12K_NUM_TX_SPT_PAGES; + end = start + ATH12K_NUM_TX_SPT_PAGES(ab); break; case ATH12K_DP_RX_DESC: cmem_base += ATH12K_PPT_ADDR_OFFSET(dp->rx_ppt_base); - start = ATH12K_RX_SPT_PAGE_OFFSET; - end = start + ATH12K_NUM_RX_SPT_PAGES; + start = ATH12K_RX_SPT_PAGE_OFFSET(ab); + end = start + ATH12K_NUM_RX_SPT_PAGES(ab); break; default: ath12k_err(ab, "invalid descriptor type %d in cmem init\n", type); @@ -1547,6 +1576,11 @@ void ath12k_dp_partner_cc_init(struct ath12k_base *ab) } } +static u32 ath12k_dp_get_num_spt_pages(struct ath12k_base *ab) +{ + return ATH12K_NUM_RX_SPT_PAGES(ab) + ATH12K_NUM_TX_SPT_PAGES(ab); +} + static int ath12k_dp_cc_init(struct ath12k_base *ab) { struct ath12k_dp *dp = &ab->dp; @@ -1561,7 +1595,7 @@ static int ath12k_dp_cc_init(struct ath12k_base *ab) spin_lock_init(&dp->tx_desc_lock[i]); } - dp->num_spt_pages = ATH12K_NUM_SPT_PAGES; + dp->num_spt_pages = ath12k_dp_get_num_spt_pages(ab); if (dp->num_spt_pages > ATH12K_MAX_PPT_ENTRIES) dp->num_spt_pages = ATH12K_MAX_PPT_ENTRIES; @@ -1573,7 +1607,7 @@ static int ath12k_dp_cc_init(struct ath12k_base *ab) return -ENOMEM; } - dp->rx_ppt_base = ab->device_id * ATH12K_NUM_RX_SPT_PAGES; + dp->rx_ppt_base = ab->device_id * ATH12K_NUM_RX_SPT_PAGES(ab); for (i = 0; i < dp->num_spt_pages; i++) { dp->spt_info[i].vaddr = dma_alloc_coherent(ab->dev, @@ -1748,7 +1782,8 @@ int ath12k_dp_alloc(struct ath12k_base *ab) if (ret) goto fail_dp_bank_profiles_cleanup; - size = sizeof(struct hal_wbm_release_ring_tx) * DP_TX_COMP_RING_SIZE; + size = sizeof(struct hal_wbm_release_ring_tx) * + DP_TX_COMP_RING_SIZE(ab); ret = ath12k_dp_reoq_lut_setup(ab); if (ret) { @@ -1760,7 +1795,7 @@ int ath12k_dp_alloc(struct ath12k_base *ab) dp->tx_ring[i].tcl_data_ring_id = i; dp->tx_ring[i].tx_status_head = 0; - dp->tx_ring[i].tx_status_tail = DP_TX_COMP_RING_SIZE - 1; + dp->tx_ring[i].tx_status_tail = DP_TX_COMP_RING_SIZE(ab) - 1; dp->tx_ring[i].tx_status = kmalloc(size, GFP_KERNEL); if (!dp->tx_ring[i].tx_status) { ret = -ENOMEM; diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index 6df07b23b705..623facc2cce7 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -46,7 +46,7 @@ struct dp_rxdma_ring { int bufs_max; }; -#define ATH12K_TX_COMPL_NEXT(x) (((x) + 1) % DP_TX_COMP_RING_SIZE) +#define ATH12K_TX_COMPL_NEXT(ab, x) (((x) + 1) % DP_TX_COMP_RING_SIZE(ab)) struct dp_tx_ring { u8 tcl_data_ring_id; @@ -174,8 +174,9 @@ struct ath12k_pdev_dp { #define DP_WBM_RELEASE_RING_SIZE 64 #define DP_TCL_DATA_RING_SIZE 512 -#define DP_TX_COMP_RING_SIZE 32768 -#define DP_TX_IDR_SIZE DP_TX_COMP_RING_SIZE +#define DP_TX_COMP_RING_SIZE(ab) \ + ((ab)->profile_param->dp_params.tx_comp_ring_size) +#define DP_TX_IDR_SIZE(ab) DP_TX_COMP_RING_SIZE(ab) #define DP_TCL_CMD_RING_SIZE 32 #define DP_TCL_STATUS_RING_SIZE 32 #define DP_REO_DST_RING_MAX 8 @@ -190,8 +191,10 @@ struct ath12k_pdev_dp { #define DP_RXDMA_REFILL_RING_SIZE 2048 #define DP_RXDMA_ERR_DST_RING_SIZE 1024 #define DP_RXDMA_MON_STATUS_RING_SIZE 1024 -#define DP_RXDMA_MONITOR_BUF_RING_SIZE 4096 -#define DP_RXDMA_MONITOR_DST_RING_SIZE 8092 +#define DP_RXDMA_MONITOR_BUF_RING_SIZE(ab) \ + ((ab)->profile_param->dp_params.rxdma_monitor_buf_ring_size) +#define DP_RXDMA_MONITOR_DST_RING_SIZE(ab) \ + ((ab)->profile_param->dp_params.rxdma_monitor_dst_ring_size) #define DP_RXDMA_MONITOR_DESC_RING_SIZE 4096 #define DP_TX_MONITOR_BUF_RING_SIZE 4096 #define DP_TX_MONITOR_DEST_RING_SIZE 2048 @@ -225,10 +228,11 @@ struct ath12k_pdev_dp { #define ATH12K_SHADOW_DP_TIMER_INTERVAL 20 #define ATH12K_SHADOW_CTRL_TIMER_INTERVAL 10 -#define ATH12K_NUM_POOL_TX_DESC 32768 - +#define ATH12K_NUM_POOL_TX_DESC(ab) \ + ((ab)->profile_param->dp_params.num_pool_tx_desc) /* TODO: revisit this count during testing */ -#define ATH12K_RX_DESC_COUNT (12288) +#define ATH12K_RX_DESC_COUNT(ab) \ + ((ab)->profile_param->dp_params.rx_desc_count) #define ATH12K_PAGE_SIZE PAGE_SIZE @@ -240,20 +244,21 @@ struct ath12k_pdev_dp { /* Total 512 entries in a SPT, i.e 4K Page/8 */ #define ATH12K_MAX_SPT_ENTRIES 512 -#define ATH12K_NUM_RX_SPT_PAGES ((ATH12K_RX_DESC_COUNT) / ATH12K_MAX_SPT_ENTRIES) - -#define ATH12K_TX_SPT_PAGES_PER_POOL (ATH12K_NUM_POOL_TX_DESC / \ +#define ATH12K_NUM_RX_SPT_PAGES(ab) ((ATH12K_RX_DESC_COUNT(ab)) / \ ATH12K_MAX_SPT_ENTRIES) -#define ATH12K_NUM_TX_SPT_PAGES (ATH12K_TX_SPT_PAGES_PER_POOL * ATH12K_HW_MAX_QUEUES) -#define ATH12K_NUM_SPT_PAGES (ATH12K_NUM_RX_SPT_PAGES + ATH12K_NUM_TX_SPT_PAGES) + +#define ATH12K_TX_SPT_PAGES_PER_POOL(ab) (ATH12K_NUM_POOL_TX_DESC(ab) / \ + ATH12K_MAX_SPT_ENTRIES) +#define ATH12K_NUM_TX_SPT_PAGES(ab) (ATH12K_TX_SPT_PAGES_PER_POOL(ab) * \ + ATH12K_HW_MAX_QUEUES) #define ATH12K_TX_SPT_PAGE_OFFSET 0 -#define ATH12K_RX_SPT_PAGE_OFFSET ATH12K_NUM_TX_SPT_PAGES +#define ATH12K_RX_SPT_PAGE_OFFSET(ab) ATH12K_NUM_TX_SPT_PAGES(ab) /* The SPT pages are divided for RX and TX, first block for RX * and remaining for TX */ -#define ATH12K_NUM_TX_SPT_PAGE_START ATH12K_NUM_RX_SPT_PAGES +#define ATH12K_NUM_TX_SPT_PAGE_START(ab) ATH12K_NUM_RX_SPT_PAGES(ab) #define ATH12K_DP_RX_DESC_MAGIC 0xBABABABA @@ -399,8 +404,8 @@ struct ath12k_dp { struct ath12k_spt_info *spt_info; u32 num_spt_pages; u32 rx_ppt_base; - struct ath12k_rx_desc_info *rxbaddr[ATH12K_NUM_RX_SPT_PAGES]; - struct ath12k_tx_desc_info *txbaddr[ATH12K_NUM_TX_SPT_PAGES]; + struct ath12k_rx_desc_info **rxbaddr; + struct ath12k_tx_desc_info **txbaddr; struct list_head rx_desc_free_list; /* protects the free desc list */ spinlock_t rx_desc_lock; diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index c95568f0e5d8..e44bb2e8490d 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -570,7 +570,7 @@ static int ath12k_dp_rx_pdev_srng_alloc(struct ath12k *ar) &dp->rxdma_mon_dst_ring[i], HAL_RXDMA_MONITOR_DST, 0, mac_id + i, - DP_RXDMA_MONITOR_DST_RING_SIZE); + DP_RXDMA_MONITOR_DST_RING_SIZE(ab)); if (ret) { ath12k_warn(ar->ab, "failed to setup HAL_RXDMA_MONITOR_DST\n"); @@ -4543,7 +4543,7 @@ int ath12k_dp_rx_alloc(struct ath12k_base *ab) ret = ath12k_dp_srng_setup(ab, &dp->rxdma_mon_buf_ring.refill_buf_ring, HAL_RXDMA_MONITOR_BUF, 0, 0, - DP_RXDMA_MONITOR_BUF_RING_SIZE); + DP_RXDMA_MONITOR_BUF_RING_SIZE(ab)); if (ret) { ath12k_warn(ab, "failed to setup HAL_RXDMA_MONITOR_BUF\n"); return ret; diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index 56c08199c79f..0e93afbc4866 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -934,7 +934,8 @@ void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id) ath12k_hal_srng_access_begin(ab, status_ring); - while (ATH12K_TX_COMPL_NEXT(tx_ring->tx_status_head) != tx_ring->tx_status_tail) { + while (ATH12K_TX_COMPL_NEXT(ab, tx_ring->tx_status_head) != + tx_ring->tx_status_tail) { desc = ath12k_hal_srng_dst_get_next_entry(ab, status_ring); if (!desc) break; @@ -942,11 +943,12 @@ void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id) memcpy(&tx_ring->tx_status[tx_ring->tx_status_head], desc, sizeof(*desc)); tx_ring->tx_status_head = - ATH12K_TX_COMPL_NEXT(tx_ring->tx_status_head); + ATH12K_TX_COMPL_NEXT(ab, tx_ring->tx_status_head); } if (ath12k_hal_srng_dst_peek(ab, status_ring) && - (ATH12K_TX_COMPL_NEXT(tx_ring->tx_status_head) == tx_ring->tx_status_tail)) { + (ATH12K_TX_COMPL_NEXT(ab, tx_ring->tx_status_head) == + tx_ring->tx_status_tail)) { /* TODO: Process pending tx_status messages when kfifo_is_full() */ ath12k_warn(ab, "Unable to process some of the tx_status ring desc because status_fifo is full\n"); } @@ -955,12 +957,13 @@ void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id) spin_unlock_bh(&status_ring->lock); - while (ATH12K_TX_COMPL_NEXT(tx_ring->tx_status_tail) != tx_ring->tx_status_head) { + while (ATH12K_TX_COMPL_NEXT(ab, tx_ring->tx_status_tail) != + tx_ring->tx_status_head) { struct hal_wbm_completion_ring_tx *tx_status; u32 desc_id; tx_ring->tx_status_tail = - ATH12K_TX_COMPL_NEXT(tx_ring->tx_status_tail); + ATH12K_TX_COMPL_NEXT(ab, tx_ring->tx_status_tail); tx_status = &tx_ring->tx_status[tx_ring->tx_status_tail]; ath12k_dp_tx_status_parse(ab, tx_status, &ts); diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 4e10d5df2919..9f4ea5e96150 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -16,34 +16,20 @@ /* Target configuration defines */ /* Num VDEVS per radio */ -#define TARGET_NUM_VDEVS (16 + 1) - -#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_SINGLE) - -/* Num of peers for DBS */ -#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_DBS_SBS) +#define TARGET_NUM_VDEVS(ab) ((ab)->profile_param->num_vdevs) /* Max num of stations for Single Radio mode */ -#define TARGET_NUM_STATIONS_SINGLE 512 +#define TARGET_NUM_STATIONS_SINGLE(ab) ((ab)->profile_param->max_client_single) /* Max num of stations for DBS */ -#define TARGET_NUM_STATIONS_DBS 128 +#define TARGET_NUM_STATIONS_DBS(ab) ((ab)->profile_param->max_client_dbs) /* Max num of stations for DBS_SBS */ -#define TARGET_NUM_STATIONS_DBS_SBS 128 +#define TARGET_NUM_STATIONS_DBS_SBS(ab) \ + ((ab)->profile_param->max_client_dbs_sbs) + +#define TARGET_NUM_STATIONS(ab, x) TARGET_NUM_STATIONS_##x(ab) -#define TARGET_NUM_PEERS(x) TARGET_NUM_PEERS_##x #define TARGET_NUM_PEER_KEYS 2 #define TARGET_AST_SKID_LIMIT 16 diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 1f4deedcd189..0118c9492e40 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -10053,9 +10053,9 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw, if (arvif->is_created) goto flush; - if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) { + if (ar->num_created_vdevs > (TARGET_NUM_VDEVS(ab) - 1)) { ath12k_warn(ab, "failed to create vdev, reached max vdev limit %d\n", - TARGET_NUM_VDEVS); + TARGET_NUM_VDEVS(ab)); goto unlock; } @@ -13712,7 +13712,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) else mac_addr = ab->mac_addr; - mbssid_max_interfaces += TARGET_NUM_VDEVS; + mbssid_max_interfaces += TARGET_NUM_VDEVS(ar->ab); } wiphy->available_antennas_rx = antennas_rx; @@ -14269,9 +14269,12 @@ void ath12k_mac_destroy(struct ath12k_hw_group *ag) static void ath12k_mac_set_device_defaults(struct ath12k_base *ab) { + int total_vdev; + /* Initialize channel counters frequency value in hertz */ ab->cc_freq_hz = 320000; - ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1; + total_vdev = ab->num_radios * TARGET_NUM_VDEVS(ab); + ab->free_vdev_map = (1LL << total_vdev) - 1; } int ath12k_mac_allocate(struct ath12k_hw_group *ag) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 78934925ca11..2f0a310ec57d 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -201,7 +201,7 @@ static __le32 ath12k_wmi_tlv_cmd_hdr(u32 cmd, u32 len) 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; + config->num_vdevs = ab->num_radios * TARGET_NUM_VDEVS(ab); config->num_peers = ab->num_radios * ath12k_core_get_max_peers_per_radio(ab); config->num_offload_peers = TARGET_NUM_OFFLD_PEERS; From 545b669403d72cc4a1cf5d93b3fce0b6a85833f7 Mon Sep 17 00:00:00 2001 From: Aaradhana Sahu Date: Tue, 8 Jul 2025 23:41:02 +0530 Subject: [PATCH 088/199] wifi: ath12k: Enable memory profile selection for QCN9274 The QCN9274 supports two memory profiles: a default profile and a low-memory profile. The driver signals the firmware to enable low-memory optimizations using the QMI initialization service. Add support to select the low-memory profile on system with less than 512 MB RAM. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.5-01651-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 WLAN.HMT.1.1.c5-00284.1-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Aaradhana Sahu Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250708181102.4111054-5-aaradhana.sahu@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/ahb.c | 1 + drivers/net/wireless/ath/ath12k/core.c | 16 +++++++++++++++- drivers/net/wireless/ath/ath12k/core.h | 2 ++ drivers/net/wireless/ath/ath12k/pci.c | 2 ++ drivers/net/wireless/ath/ath12k/qmi.c | 2 +- 5 files changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/ahb.c b/drivers/net/wireless/ath/ath12k/ahb.c index 8d1a86e420a4..3b983f4e3268 100644 --- a/drivers/net/wireless/ath/ath12k/ahb.c +++ b/drivers/net/wireless/ath/ath12k/ahb.c @@ -1022,6 +1022,7 @@ static int ath12k_ahb_probe(struct platform_device *pdev) ab->hif.ops = hif_ops; ab->pdev = pdev; ab->hw_rev = hw_rev; + ab->target_mem_mode = ATH12K_QMI_MEMORY_MODE_DEFAULT; platform_set_drvdata(pdev, ab); ab_ahb = ath12k_ab_to_ahb(ab); ab_ahb->ab = ab; diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 53e60dba3bf8..bf46acb54268 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1728,6 +1728,20 @@ static void ath12k_core_reset(struct work_struct *work) mutex_unlock(&ag->mutex); } +enum ath12k_qmi_mem_mode ath12k_core_get_memory_mode(struct ath12k_base *ab) +{ + unsigned long total_ram; + struct sysinfo si; + + si_meminfo(&si); + total_ram = si.totalram * si.mem_unit; + + if (total_ram < SZ_512M) + return ATH12K_QMI_MEMORY_MODE_LOW_512_M; + + return ATH12K_QMI_MEMORY_MODE_DEFAULT; +} + int ath12k_core_pre_init(struct ath12k_base *ab) { const struct ath12k_mem_profile_based_param *param; @@ -1739,7 +1753,7 @@ int ath12k_core_pre_init(struct ath12k_base *ab) return ret; } - param = &ath12k_mem_profile_based_param[ATH12K_QMI_MEMORY_MODE_DEFAULT]; + param = &ath12k_mem_profile_based_param[ab->target_mem_mode]; ab->profile_param = param; ath12k_fw_map(ab); diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 8638ba49dca4..3e55b7b89eae 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -1231,6 +1231,7 @@ struct ath12k_base { struct ath12k_reg_freq reg_freq_5ghz; struct ath12k_reg_freq reg_freq_6ghz; const struct ath12k_mem_profile_based_param *profile_param; + enum ath12k_qmi_mem_mode target_mem_mode; /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); @@ -1365,6 +1366,7 @@ void ath12k_fw_stats_free(struct ath12k_fw_stats *stats); void ath12k_fw_stats_reset(struct ath12k *ar); struct reserved_mem *ath12k_core_get_reserved_mem(struct ath12k_base *ab, int index); +enum ath12k_qmi_mem_mode ath12k_core_get_memory_mode(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/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 1f3cfd9b89fd..b4e7e77518dd 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -1595,6 +1595,7 @@ static int ath12k_pci_probe(struct pci_dev *pdev, ab->hal_rx_ops = &hal_rx_qcn9274_ops; ath12k_pci_read_hw_version(ab, &soc_hw_version_major, &soc_hw_version_minor); + ab->target_mem_mode = ath12k_core_get_memory_mode(ab); switch (soc_hw_version_major) { case ATH12K_PCI_SOC_HW_VERSION_2: ab->hw_rev = ATH12K_HW_QCN9274_HW20; @@ -1618,6 +1619,7 @@ static int ath12k_pci_probe(struct pci_dev *pdev, ab->hal_rx_ops = &hal_rx_wcn7850_ops; ath12k_pci_read_hw_version(ab, &soc_hw_version_major, &soc_hw_version_minor); + ab->target_mem_mode = ATH12K_QMI_MEMORY_MODE_DEFAULT; switch (soc_hw_version_major) { case ATH12K_PCI_SOC_HW_VERSION_2: ab->hw_rev = ATH12K_HW_WCN7850_HW20; diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 5e8943060443..7c611a1fd6d0 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -3856,7 +3856,7 @@ int ath12k_qmi_init_service(struct ath12k_base *ab) memset(&ab->qmi.target_mem, 0, sizeof(struct target_mem_chunk)); ab->qmi.ab = ab; - ab->qmi.target_mem_mode = ATH12K_QMI_MEMORY_MODE_DEFAULT; + ab->qmi.target_mem_mode = ab->target_mem_mode; ret = qmi_handle_init(&ab->qmi.handle, ATH12K_QMI_RESP_LEN_MAX, &ath12k_qmi_ops, ath12k_qmi_msg_handlers); if (ret < 0) { From 9d2abd4162fca8a1eb46f664268dffad35c8ad20 Mon Sep 17 00:00:00 2001 From: Sriram R Date: Fri, 11 Jul 2025 14:47:04 +0530 Subject: [PATCH 089/199] wifi: ath12k: Add support to enqueue management frame at MLD level A multi-link client can use any link for transmissions. It can decide to put one link in power save mode for longer periods while listening on the other links as per MLD listen interval. Unicast management frames sent to that link station might get dropped if that link station is in power save mode or inactive. In such cases, firmware can take decision on which link to use. Allow the firmware to decide on which link management frame should be sent on, by filling the hardware link with maximum value of u32, so that the firmware will not have a specific link to transmit data on and so the management frames will be link agnostic. For QCN devices, all action frames are marked as link agnostic. For WCN devices, if the device is configured as an AP, then all frames other than probe response frames, authentication frames, association response frames, re-association response frames and ADDBA response frames are marked as link agnostic and if the device is configured as a station, then all frames other than probe request frames, authentication frames, de-authentication frames and ADDBA response frames are marked as link agnostic. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-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 Co-developed-by: Roopni Devanathan Signed-off-by: Roopni Devanathan Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250711091704.3704379-1-quic_rdevanat@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/core.h | 1 + drivers/net/wireless/ath/ath12k/hw.c | 55 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/hw.h | 2 + drivers/net/wireless/ath/ath12k/mac.c | 5 ++- drivers/net/wireless/ath/ath12k/peer.c | 2 +- drivers/net/wireless/ath/ath12k/peer.h | 2 + drivers/net/wireless/ath/ath12k/wmi.c | 56 ++++++++++++++++++++++++-- drivers/net/wireless/ath/ath12k/wmi.h | 16 +++++++- 8 files changed, 131 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 3e55b7b89eae..519f826f56c8 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -116,6 +116,7 @@ static inline u64 ath12k_le32hilo_to_u64(__le32 hi, __le32 lo) enum ath12k_skb_flags { ATH12K_SKB_HW_80211_ENCAP = BIT(0), ATH12K_SKB_CIPHER_SET = BIT(1), + ATH12K_SKB_MLO_STA = BIT(2), }; struct ath12k_skb_cb { diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index ec77ad498b33..6791ae1d64e5 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -14,6 +14,7 @@ #include "hw.h" #include "mhi.h" #include "dp_rx.h" +#include "peer.h" static const guid_t wcn7850_uuid = GUID_INIT(0xf634f534, 0x6147, 0x11ec, 0x90, 0xd6, 0x02, 0x42, @@ -49,6 +50,12 @@ static bool ath12k_dp_srng_is_comp_ring_qcn9274(int ring_num) return false; } +static bool ath12k_is_frame_link_agnostic_qcn9274(struct ath12k_link_vif *arvif, + struct ieee80211_mgmt *mgmt) +{ + return ieee80211_is_action(mgmt->frame_control); +} + static int ath12k_hw_mac_id_to_pdev_id_wcn7850(const struct ath12k_hw_params *hw, int mac_id) { @@ -74,6 +81,52 @@ static bool ath12k_dp_srng_is_comp_ring_wcn7850(int ring_num) return false; } +static bool ath12k_is_addba_resp_action_code(struct ieee80211_mgmt *mgmt) +{ + if (!ieee80211_is_action(mgmt->frame_control)) + return false; + + if (mgmt->u.action.category != WLAN_CATEGORY_BACK) + return false; + + if (mgmt->u.action.u.addba_resp.action_code != WLAN_ACTION_ADDBA_RESP) + return false; + + return true; +} + +static bool ath12k_is_frame_link_agnostic_wcn7850(struct ath12k_link_vif *arvif, + struct ieee80211_mgmt *mgmt) +{ + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ath12k_hw *ah = ath12k_ar_to_ah(arvif->ar); + struct ath12k_base *ab = arvif->ar->ab; + __le16 fc = mgmt->frame_control; + + spin_lock_bh(&ab->base_lock); + if (!ath12k_peer_find_by_addr(ab, mgmt->da) && + !ath12k_peer_ml_find(ah, mgmt->da)) { + spin_unlock_bh(&ab->base_lock); + return false; + } + spin_unlock_bh(&ab->base_lock); + + if (vif->type == NL80211_IFTYPE_STATION) + return arvif->is_up && + (vif->valid_links == vif->active_links) && + !ieee80211_is_probe_req(fc) && + !ieee80211_is_auth(fc) && + !ieee80211_is_deauth(fc) && + !ath12k_is_addba_resp_action_code(mgmt); + + if (vif->type == NL80211_IFTYPE_AP) + return !(ieee80211_is_probe_resp(fc) || ieee80211_is_auth(fc) || + ieee80211_is_assoc_resp(fc) || ieee80211_is_reassoc_resp(fc) || + ath12k_is_addba_resp_action_code(mgmt)); + + return false; +} + static const struct ath12k_hw_ops qcn9274_ops = { .get_hw_mac_from_pdev_id = ath12k_hw_qcn9274_mac_from_pdev_id, .mac_id_to_pdev_id = ath12k_hw_mac_id_to_pdev_id_qcn9274, @@ -81,6 +134,7 @@ static const struct ath12k_hw_ops qcn9274_ops = { .rxdma_ring_sel_config = ath12k_dp_rxdma_ring_sel_config_qcn9274, .get_ring_selector = ath12k_hw_get_ring_selector_qcn9274, .dp_srng_is_tx_comp_ring = ath12k_dp_srng_is_comp_ring_qcn9274, + .is_frame_link_agnostic = ath12k_is_frame_link_agnostic_qcn9274, }; static const struct ath12k_hw_ops wcn7850_ops = { @@ -90,6 +144,7 @@ static const struct ath12k_hw_ops wcn7850_ops = { .rxdma_ring_sel_config = ath12k_dp_rxdma_ring_sel_config_wcn7850, .get_ring_selector = ath12k_hw_get_ring_selector_wcn7850, .dp_srng_is_tx_comp_ring = ath12k_dp_srng_is_comp_ring_wcn7850, + .is_frame_link_agnostic = ath12k_is_frame_link_agnostic_wcn7850, }; #define ATH12K_TX_RING_MASK_0 0x1 diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 9f4ea5e96150..8ce11c3e6d5c 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -230,6 +230,8 @@ struct ath12k_hw_ops { int (*rxdma_ring_sel_config)(struct ath12k_base *ab); u8 (*get_ring_selector)(struct sk_buff *skb); bool (*dp_srng_is_tx_comp_ring)(int ring_num); + bool (*is_frame_link_agnostic)(struct ath12k_link_vif *arvif, + struct ieee80211_mgmt *mgmt); }; static inline diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 0118c9492e40..8d6f0869f2d5 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -8377,7 +8377,7 @@ static int ath12k_mac_mgmt_tx_wmi(struct ath12k *ar, struct ath12k_link_vif *arv skb_cb->paddr = paddr; - ret = ath12k_wmi_mgmt_send(ar, arvif->vdev_id, buf_id, skb); + ret = ath12k_wmi_mgmt_send(arvif, buf_id, skb); if (ret) { ath12k_warn(ar->ab, "failed to send mgmt frame: %d\n", ret); goto err_unmap_buf; @@ -8871,6 +8871,9 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw, skb_cb->flags |= ATH12K_SKB_HW_80211_ENCAP; } else if (ieee80211_is_mgmt(hdr->frame_control)) { + if (sta && sta->mlo) + skb_cb->flags |= ATH12K_SKB_MLO_STA; + ret = ath12k_mac_mgmt_tx(ar, skb, is_prb_rsp); if (ret) { ath12k_warn(ar->ab, "failed to queue management frame %d\n", diff --git a/drivers/net/wireless/ath/ath12k/peer.c b/drivers/net/wireless/ath/ath12k/peer.c index ec7236bbccc0..eb7aeff01490 100644 --- a/drivers/net/wireless/ath/ath12k/peer.c +++ b/drivers/net/wireless/ath/ath12k/peer.c @@ -8,7 +8,7 @@ #include "peer.h" #include "debug.h" -static struct ath12k_ml_peer *ath12k_peer_ml_find(struct ath12k_hw *ah, const u8 *addr) +struct ath12k_ml_peer *ath12k_peer_ml_find(struct ath12k_hw *ah, const u8 *addr) { struct ath12k_ml_peer *ml_peer; diff --git a/drivers/net/wireless/ath/ath12k/peer.h b/drivers/net/wireless/ath/ath12k/peer.h index 92c4988df2f1..44afc0b7dd53 100644 --- a/drivers/net/wireless/ath/ath12k/peer.h +++ b/drivers/net/wireless/ath/ath12k/peer.h @@ -91,6 +91,8 @@ struct ath12k_peer *ath12k_peer_find_by_ast(struct ath12k_base *ab, int ast_hash int ath12k_peer_ml_create(struct ath12k_hw *ah, struct ieee80211_sta *sta); int ath12k_peer_ml_delete(struct ath12k_hw *ah, struct ieee80211_sta *sta); int ath12k_peer_mlo_link_peers_delete(struct ath12k_vif *ahvif, struct ath12k_sta *ahsta); +struct ath12k_ml_peer *ath12k_peer_ml_find(struct ath12k_hw *ah, + const u8 *addr); static inline struct ath12k_link_sta *ath12k_peer_get_link_sta(struct ath12k_base *ab, struct ath12k_peer *peer) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 2f0a310ec57d..ed3c08dbd899 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -785,20 +785,46 @@ struct sk_buff *ath12k_wmi_alloc_skb(struct ath12k_wmi_base *wmi_ab, u32 len) return skb; } -int ath12k_wmi_mgmt_send(struct ath12k *ar, u32 vdev_id, u32 buf_id, +int ath12k_wmi_mgmt_send(struct ath12k_link_vif *arvif, u32 buf_id, struct sk_buff *frame) { + struct ath12k *ar = arvif->ar; 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 ieee80211_hdr *hdr = (struct ieee80211_hdr *)frame->data; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + int cmd_len = sizeof(struct ath12k_wmi_mgmt_send_tx_params); + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)hdr; + struct ath12k_wmi_mlo_mgmt_send_params *ml_params; + struct ath12k_base *ab = ar->ab; + struct wmi_tlv *frame_tlv, *tlv; + struct ath12k_skb_cb *skb_cb; + u32 buf_len, buf_len_aligned; + u32 vdev_id = arvif->vdev_id; + bool link_agnostic = false; struct sk_buff *skb; - u32 buf_len; int ret, len; + void *ptr; buf_len = min_t(int, frame->len, WMI_MGMT_SEND_DOWNLD_LEN); - len = sizeof(*cmd) + sizeof(*frame_tlv) + roundup(buf_len, 4); + buf_len_aligned = roundup(buf_len, sizeof(u32)); + + len = sizeof(*cmd) + sizeof(*frame_tlv) + buf_len_aligned; + + if (ieee80211_vif_is_mld(vif)) { + skb_cb = ATH12K_SKB_CB(frame); + if ((skb_cb->flags & ATH12K_SKB_MLO_STA) && + ab->hw_params->hw_ops->is_frame_link_agnostic && + ab->hw_params->hw_ops->is_frame_link_agnostic(arvif, mgmt)) { + len += cmd_len + TLV_HDR_SIZE + sizeof(*ml_params); + ath12k_generic_dbg(ATH12K_DBG_MGMT, + "Sending Mgmt Frame fc 0x%0x as link agnostic", + mgmt->frame_control); + link_agnostic = true; + } + } skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) @@ -821,6 +847,28 @@ int ath12k_wmi_mgmt_send(struct ath12k *ar, u32 vdev_id, u32 buf_id, memcpy(frame_tlv->value, frame->data, buf_len); + if (!link_agnostic) + goto send; + + ptr = skb->data + sizeof(*cmd) + sizeof(*frame_tlv) + buf_len_aligned; + + tlv = ptr; + + /* Tx params not used currently */ + tlv->header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_TX_SEND_PARAMS, cmd_len); + ptr += cmd_len; + + tlv = ptr; + tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, sizeof(*ml_params)); + ptr += TLV_HDR_SIZE; + + ml_params = ptr; + ml_params->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_MLO_TX_SEND_PARAMS, + sizeof(*ml_params)); + + ml_params->hw_link_id = cpu_to_le32(WMI_MGMT_LINK_AGNOSTIC_ID); + +send: ret = ath12k_wmi_cmd_send(wmi, skb, WMI_MGMT_TX_SEND_CMDID); if (ret) { ath12k_warn(ar->ab, diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 967a7cc1e3d5..5b782258f870 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -4018,6 +4018,7 @@ struct wmi_scan_chan_list_cmd { } __packed; #define WMI_MGMT_SEND_DOWNLD_LEN 64 +#define WMI_MGMT_LINK_AGNOSTIC_ID 0xFFFFFFFF #define WMI_TX_PARAMS_DWORD0_POWER GENMASK(7, 0) #define WMI_TX_PARAMS_DWORD0_MCS_MASK GENMASK(19, 8) @@ -4043,7 +4044,18 @@ struct wmi_mgmt_send_cmd { /* This TLV is followed by struct wmi_mgmt_frame */ - /* Followed by struct wmi_mgmt_send_params */ + /* Followed by struct ath12k_wmi_mlo_mgmt_send_params */ +} __packed; + +struct ath12k_wmi_mlo_mgmt_send_params { + __le32 tlv_header; + __le32 hw_link_id; +} __packed; + +struct ath12k_wmi_mgmt_send_tx_params { + __le32 tlv_header; + __le32 tx_param_dword0; + __le32 tx_param_dword1; } __packed; struct wmi_sta_powersave_mode_cmd { @@ -6277,7 +6289,7 @@ void ath12k_wmi_init_wcn7850(struct ath12k_base *ab, int ath12k_wmi_cmd_send(struct ath12k_wmi_pdev *wmi, struct sk_buff *skb, u32 cmd_id); 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, +int ath12k_wmi_mgmt_send(struct ath12k_link_vif *arvif, u32 buf_id, struct sk_buff *frame); int ath12k_wmi_p2p_go_bcn_ie(struct ath12k *ar, u32 vdev_id, const u8 *p2p_ie); From 75bb7774a16b1e835f67baff6f5174ca17491db6 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 9 Jul 2025 14:50:03 +0800 Subject: [PATCH 090/199] wifi: rtw89: regd/acpi: support country CA by BIT(1) in 6 GHz SP conf ACPI DSM function 7 is used to decide whether 6 GHz Standard Power (SP) is allowed on given countries. Now, add BIT(1) for country CA. Besides, for searching country index, replace for-loop with index getter function. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250709065006.32028-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/acpi.h | 1 + drivers/net/wireless/realtek/rtw89/regd.c | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/acpi.h b/drivers/net/wireless/realtek/rtw89/acpi.h index 8c918ee02d2e..8217cdfbbc49 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.h +++ b/drivers/net/wireless/realtek/rtw89/acpi.h @@ -56,6 +56,7 @@ struct rtw89_acpi_policy_6ghz { enum rtw89_acpi_conf_6ghz_sp { RTW89_ACPI_CONF_6GHZ_SP_US = BIT(0), + RTW89_ACPI_CONF_6GHZ_SP_CA = BIT(1), }; struct rtw89_acpi_policy_6ghz_sp { diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index 3ad14cab1f58..c91a86332b17 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -490,12 +490,11 @@ out: static void rtw89_regd_setup_policy_6ghz_sp(struct rtw89_dev *rtwdev) { struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; - const struct rtw89_regd_ctrl *regd_ctrl = ®ulatory->ctrl; const struct rtw89_acpi_policy_6ghz_sp *ptr; struct rtw89_acpi_dsm_result res = {}; - bool enable_by_us; + bool enable; + u8 index; int ret; - int i; ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP, &res); if (ret) { @@ -520,14 +519,15 @@ static void rtw89_regd_setup_policy_6ghz_sp(struct rtw89_dev *rtwdev) bitmap_fill(regulatory->block_6ghz_sp, RTW89_REGD_MAX_COUNTRY_NUM); - enable_by_us = u8_get_bits(ptr->conf, RTW89_ACPI_CONF_6GHZ_SP_US); + index = rtw89_regd_get_index_by_name(rtwdev, "US"); + enable = u8_get_bits(ptr->conf, RTW89_ACPI_CONF_6GHZ_SP_US); + if (enable && index != RTW89_REGD_MAX_COUNTRY_NUM) + clear_bit(index, regulatory->block_6ghz_sp); - for (i = 0; i < regd_ctrl->nr; i++) { - const struct rtw89_regd *tmp = ®d_ctrl->map[i]; - - if (enable_by_us && memcmp(tmp->alpha2, "US", 2) == 0) - clear_bit(i, regulatory->block_6ghz_sp); - } + index = rtw89_regd_get_index_by_name(rtwdev, "CA"); + enable = u8_get_bits(ptr->conf, RTW89_ACPI_CONF_6GHZ_SP_CA); + if (enable && index != RTW89_REGD_MAX_COUNTRY_NUM) + clear_bit(index, regulatory->block_6ghz_sp); out: kfree(ptr); From 01186c303ba363262d546eadd0adde6f37df91b2 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 9 Jul 2025 14:50:04 +0800 Subject: [PATCH 091/199] wifi: rtw89: regd/acpi: update field definition to specific country in UNII-4 conf Originally, fields of ACPI DSM function 6 were handled for countries following specific regulatory. BIT(0) for countries following FCC regulatory BIT(1) for countries following IC regulatory Now, update to the following (one field for one specific country). BIT(0) for country US BIT(1) for country CA Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250709065006.32028-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/acpi.h | 4 +-- drivers/net/wireless/realtek/rtw89/regd.c | 34 ++++++++--------------- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/acpi.h b/drivers/net/wireless/realtek/rtw89/acpi.h index 8217cdfbbc49..8cf261505539 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.h +++ b/drivers/net/wireless/realtek/rtw89/acpi.h @@ -22,8 +22,8 @@ enum rtw89_acpi_dsm_func { }; enum rtw89_acpi_conf_unii4 { - RTW89_ACPI_CONF_UNII4_FCC = BIT(0), - RTW89_ACPI_CONF_UNII4_IC = BIT(1), + RTW89_ACPI_CONF_UNII4_US = BIT(0), + RTW89_ACPI_CONF_UNII4_CA = BIT(1), }; enum rtw89_acpi_policy_mode { diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index c91a86332b17..ea44b8311cb2 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -360,15 +360,13 @@ static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev, struct wiphy *wiphy) { struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; - const struct rtw89_regd_ctrl *regd_ctrl = ®ulatory->ctrl; const struct rtw89_chip_info *chip = rtwdev->chip; struct ieee80211_supported_band *sband; struct rtw89_acpi_dsm_result res = {}; - bool enable_by_fcc; - bool enable_by_ic; + bool enable; + u8 index; int ret; u8 val; - int i; sband = wiphy->bands[NL80211_BAND_5GHZ]; if (!sband) @@ -385,35 +383,25 @@ static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev, if (ret) { rtw89_debug(rtwdev, RTW89_DBG_REGD, "acpi: cannot eval unii 4: %d\n", ret); - enable_by_fcc = true; - enable_by_ic = false; + val = u8_encode_bits(1, RTW89_ACPI_CONF_UNII4_US); goto bottom; } val = res.u.value; - enable_by_fcc = u8_get_bits(val, RTW89_ACPI_CONF_UNII4_FCC); - enable_by_ic = u8_get_bits(val, RTW89_ACPI_CONF_UNII4_IC); rtw89_debug(rtwdev, RTW89_DBG_REGD, "acpi: eval if allow unii-4: 0x%x\n", val); bottom: - for (i = 0; i < regd_ctrl->nr; i++) { - const struct rtw89_regd *regd = ®d_ctrl->map[i]; + index = rtw89_regd_get_index_by_name(rtwdev, "US"); + enable = u8_get_bits(val, RTW89_ACPI_CONF_UNII4_US); + if (enable && index != RTW89_REGD_MAX_COUNTRY_NUM) + clear_bit(index, regulatory->block_unii4); - switch (regd->txpwr_regd[RTW89_BAND_5G]) { - case RTW89_FCC: - if (enable_by_fcc) - clear_bit(i, regulatory->block_unii4); - break; - case RTW89_IC: - if (enable_by_ic) - clear_bit(i, regulatory->block_unii4); - break; - default: - break; - } - } + index = rtw89_regd_get_index_by_name(rtwdev, "CA"); + enable = u8_get_bits(val, RTW89_ACPI_CONF_UNII4_CA); + if (enable && index != RTW89_REGD_MAX_COUNTRY_NUM) + clear_bit(index, regulatory->block_unii4); } static void __rtw89_regd_setup_policy_6ghz(struct rtw89_dev *rtwdev, bool block, From 08fbc2b6881b5228cb961b1efa6cb4bf41193105 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 9 Jul 2025 14:50:05 +0800 Subject: [PATCH 092/199] wifi: rtw89: regd/acpi: support regulatory rules via ACPI DSM and parse rule of regd_UK ACPI DSM function 10 is defined for the enablement for Realtek regulatory rules. The first rule is whether to allow regd_UK regulatory settings or not. If not, the strict one, i.e. regd_ETSI, regulatory settings will be used on country GB. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250709065006.32028-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/acpi.c | 48 +++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/acpi.h | 13 ++++++ drivers/net/wireless/realtek/rtw89/regd.c | 27 ++++++++++++- 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/acpi.c b/drivers/net/wireless/realtek/rtw89/acpi.c index 581d6d4154d3..c35a36e0f4d9 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.c +++ b/drivers/net/wireless/realtek/rtw89/acpi.c @@ -279,6 +279,51 @@ static int rtw89_acpi_dsm_get_policy_tas(struct rtw89_dev *rtwdev, return 0; } +static +bool chk_acpi_policy_reg_rules_sig(const struct rtw89_acpi_policy_reg_rules *p) +{ + return p->signature[0] == 0x52 && + p->signature[1] == 0x54 && + p->signature[2] == 0x4B && + p->signature[3] == 0x0A; +} + +static +int rtw89_acpi_dsm_get_policy_reg_rules(struct rtw89_dev *rtwdev, + union acpi_object *obj, + struct rtw89_acpi_policy_reg_rules **policy) +{ + const struct rtw89_acpi_policy_reg_rules *ptr; + u32 buf_len; + + if (obj->type != ACPI_TYPE_BUFFER) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, + "acpi: expect buffer but type: %d\n", obj->type); + return -EINVAL; + } + + buf_len = obj->buffer.length; + if (buf_len < sizeof(*ptr)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n", + __func__, buf_len); + return -EINVAL; + } + + ptr = (typeof(ptr))obj->buffer.pointer; + if (!chk_acpi_policy_reg_rules_sig(ptr)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__); + return -EINVAL; + } + + *policy = kmemdup(ptr, sizeof(*ptr), GFP_KERNEL); + if (!*policy) + return -ENOMEM; + + rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_reg_rules: ", *policy, + sizeof(*ptr)); + return 0; +} + int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, enum rtw89_acpi_dsm_func func, struct rtw89_acpi_dsm_result *res) @@ -302,6 +347,9 @@ int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, &res->u.policy_6ghz_sp); else if (func == RTW89_ACPI_DSM_FUNC_TAS_EN) ret = rtw89_acpi_dsm_get_policy_tas(rtwdev, obj, &res->u.policy_tas); + else if (func == RTW89_ACPI_DSM_FUNC_REG_RULES_EN) + ret = rtw89_acpi_dsm_get_policy_reg_rules(rtwdev, obj, + &res->u.policy_reg_rules); else ret = rtw89_acpi_dsm_get_value(rtwdev, obj, &res->u.value); diff --git a/drivers/net/wireless/realtek/rtw89/acpi.h b/drivers/net/wireless/realtek/rtw89/acpi.h index 8cf261505539..5811afebc2e6 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.h +++ b/drivers/net/wireless/realtek/rtw89/acpi.h @@ -19,6 +19,7 @@ enum rtw89_acpi_dsm_func { RTW89_ACPI_DSM_FUNC_TAS_EN = 5, RTW89_ACPI_DSM_FUNC_UNII4_SUP = 6, RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP = 7, + RTW89_ACPI_DSM_FUNC_REG_RULES_EN = 10, }; enum rtw89_acpi_conf_unii4 { @@ -75,6 +76,17 @@ struct rtw89_acpi_policy_tas { u8 rsvd[3]; } __packed; +enum rtw89_acpi_conf_reg_rules { + RTW89_ACPI_CONF_REG_RULE_REGD_UK = BIT(0), +}; + +struct rtw89_acpi_policy_reg_rules { + u8 signature[4]; + u8 revision; + u8 conf; + u8 rsvd[3]; +} __packed; + struct rtw89_acpi_dsm_result { union { u8 value; @@ -82,6 +94,7 @@ struct rtw89_acpi_dsm_result { struct rtw89_acpi_policy_6ghz *policy_6ghz; struct rtw89_acpi_policy_6ghz_sp *policy_6ghz_sp; struct rtw89_acpi_policy_tas *policy_tas; + struct rtw89_acpi_policy_reg_rules *policy_reg_rules; } u; }; diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index ea44b8311cb2..42678ff2a045 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -608,6 +608,30 @@ const char *rtw89_regd_get_string(enum rtw89_regulation_type regd) return rtw89_regd_string[regd]; } +static void rtw89_regd_setup_reg_rules(struct rtw89_dev *rtwdev) +{ + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + const struct rtw89_acpi_policy_reg_rules *ptr; + struct rtw89_acpi_dsm_result res = {}; + int ret; + + regulatory->txpwr_uk_follow_etsi = true; + + ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_REG_RULES_EN, &res); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "acpi: cannot eval policy reg-rules: %d\n", ret); + return; + } + + ptr = res.u.policy_reg_rules; + + regulatory->txpwr_uk_follow_etsi = + !u8_get_bits(ptr->conf, RTW89_ACPI_CONF_REG_RULE_REGD_UK); + + kfree(ptr); +} + int rtw89_regd_setup(struct rtw89_dev *rtwdev) { struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; @@ -624,7 +648,8 @@ int rtw89_regd_setup(struct rtw89_dev *rtwdev) } regulatory->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; - regulatory->txpwr_uk_follow_etsi = true; + + rtw89_regd_setup_reg_rules(rtwdev); if (!wiphy) return -EINVAL; From b99d7cd36da835544da02d75b6398eb7b26412ee Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 9 Jul 2025 14:50:06 +0800 Subject: [PATCH 093/199] wifi: rtw89: regd/acpi: support 6 GHz VLP policy via ACPI DSM Process ACPI DSM function 11 to get 6 GHz VLP support by country. If not allowed, return error to block the connection. By default, i.e. ACPI DSM function is not configured, disallow 6 GHz VLP on country US and country CA, because some platform-level certifications are needed in FCC regulation before operating on 6 GHz VLP connection. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250709065006.32028-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/acpi.c | 47 ++++++++++++++++ drivers/net/wireless/realtek/rtw89/acpi.h | 15 +++++ drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/regd.c | 68 +++++++++++++++++++++++ 4 files changed, 131 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/acpi.c b/drivers/net/wireless/realtek/rtw89/acpi.c index c35a36e0f4d9..f1e758a5f32b 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.c +++ b/drivers/net/wireless/realtek/rtw89/acpi.c @@ -236,6 +236,50 @@ int rtw89_acpi_dsm_get_policy_6ghz_sp(struct rtw89_dev *rtwdev, return 0; } +static bool chk_acpi_policy_6ghz_vlp_sig(const struct rtw89_acpi_policy_6ghz_vlp *p) +{ + return p->signature[0] == 0x52 && + p->signature[1] == 0x54 && + p->signature[2] == 0x4B && + p->signature[3] == 0x0B; +} + +static +int rtw89_acpi_dsm_get_policy_6ghz_vlp(struct rtw89_dev *rtwdev, + union acpi_object *obj, + struct rtw89_acpi_policy_6ghz_vlp **policy) +{ + const struct rtw89_acpi_policy_6ghz_vlp *ptr; + u32 buf_len; + + if (obj->type != ACPI_TYPE_BUFFER) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, + "acpi: expect buffer but type: %d\n", obj->type); + return -EINVAL; + } + + buf_len = obj->buffer.length; + if (buf_len < sizeof(*ptr)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n", + __func__, buf_len); + return -EINVAL; + } + + ptr = (typeof(ptr))obj->buffer.pointer; + if (!chk_acpi_policy_6ghz_vlp_sig(ptr)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__); + return -EINVAL; + } + + *policy = kmemdup(ptr, sizeof(*ptr), GFP_KERNEL); + if (!*policy) + return -ENOMEM; + + rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_6ghz_vlp: ", *policy, + sizeof(*ptr)); + return 0; +} + static bool chk_acpi_policy_tas_sig(const struct rtw89_acpi_policy_tas *p) { return p->signature[0] == 0x52 && @@ -345,6 +389,9 @@ int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, else if (func == RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP) ret = rtw89_acpi_dsm_get_policy_6ghz_sp(rtwdev, obj, &res->u.policy_6ghz_sp); + else if (func == RTW89_ACPI_DSM_FUNC_6GHZ_VLP_SUP) + ret = rtw89_acpi_dsm_get_policy_6ghz_vlp(rtwdev, obj, + &res->u.policy_6ghz_vlp); else if (func == RTW89_ACPI_DSM_FUNC_TAS_EN) ret = rtw89_acpi_dsm_get_policy_tas(rtwdev, obj, &res->u.policy_tas); else if (func == RTW89_ACPI_DSM_FUNC_REG_RULES_EN) diff --git a/drivers/net/wireless/realtek/rtw89/acpi.h b/drivers/net/wireless/realtek/rtw89/acpi.h index 5811afebc2e6..48a46f2005b1 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.h +++ b/drivers/net/wireless/realtek/rtw89/acpi.h @@ -20,6 +20,7 @@ enum rtw89_acpi_dsm_func { RTW89_ACPI_DSM_FUNC_UNII4_SUP = 6, RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP = 7, RTW89_ACPI_DSM_FUNC_REG_RULES_EN = 10, + RTW89_ACPI_DSM_FUNC_6GHZ_VLP_SUP = 11, }; enum rtw89_acpi_conf_unii4 { @@ -68,6 +69,19 @@ struct rtw89_acpi_policy_6ghz_sp { u8 rsvd; } __packed; +enum rtw89_acpi_conf_6ghz_vlp { + RTW89_ACPI_CONF_6GHZ_VLP_US = BIT(0), + RTW89_ACPI_CONF_6GHZ_VLP_CA = BIT(1), +}; + +struct rtw89_acpi_policy_6ghz_vlp { + u8 signature[4]; + u8 revision; + u8 override; + u8 conf; + u8 rsvd; +} __packed; + struct rtw89_acpi_policy_tas { u8 signature[4]; u8 revision; @@ -93,6 +107,7 @@ struct rtw89_acpi_dsm_result { /* caller needs to free it after using */ struct rtw89_acpi_policy_6ghz *policy_6ghz; struct rtw89_acpi_policy_6ghz_sp *policy_6ghz_sp; + struct rtw89_acpi_policy_6ghz_vlp *policy_6ghz_vlp; struct rtw89_acpi_policy_tas *policy_tas; struct rtw89_acpi_policy_reg_rules *policy_reg_rules; } u; diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 1d8f89e83c9a..8c53c5db0cbc 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -5386,6 +5386,7 @@ struct rtw89_regulatory_info { DECLARE_BITMAP(block_unii4, RTW89_REGD_MAX_COUNTRY_NUM); DECLARE_BITMAP(block_6ghz, RTW89_REGD_MAX_COUNTRY_NUM); DECLARE_BITMAP(block_6ghz_sp, RTW89_REGD_MAX_COUNTRY_NUM); + DECLARE_BITMAP(block_6ghz_vlp, RTW89_REGD_MAX_COUNTRY_NUM); }; enum rtw89_ifs_clm_application { diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index 42678ff2a045..58582f8d2b74 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -521,6 +521,55 @@ out: kfree(ptr); } +static void rtw89_regd_setup_policy_6ghz_vlp(struct rtw89_dev *rtwdev) +{ + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + const struct rtw89_acpi_policy_6ghz_vlp *ptr = NULL; + struct rtw89_acpi_dsm_result res = {}; + bool enable; + u8 index; + int ret; + u8 val; + + /* By default, allow 6 GHz VLP on all countries except US and CA. */ + val = ~(RTW89_ACPI_CONF_6GHZ_VLP_US | RTW89_ACPI_CONF_6GHZ_VLP_CA); + + ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6GHZ_VLP_SUP, &res); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "acpi: cannot eval policy 6ghz-vlp: %d\n", ret); + goto bottom; + } + + ptr = res.u.policy_6ghz_vlp; + + switch (ptr->override) { + default: + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "%s: unknown override case: %d\n", __func__, + ptr->override); + fallthrough; + case 0: + break; + case 1: + val = ptr->conf; + break; + } + +bottom: + index = rtw89_regd_get_index_by_name(rtwdev, "US"); + enable = u8_get_bits(val, RTW89_ACPI_CONF_6GHZ_VLP_US); + if (!enable && index != RTW89_REGD_MAX_COUNTRY_NUM) + set_bit(index, regulatory->block_6ghz_vlp); + + index = rtw89_regd_get_index_by_name(rtwdev, "CA"); + enable = u8_get_bits(val, RTW89_ACPI_CONF_6GHZ_VLP_CA); + if (!enable && index != RTW89_REGD_MAX_COUNTRY_NUM) + set_bit(index, regulatory->block_6ghz_vlp); + + kfree(ptr); +} + static void rtw89_regd_setup_6ghz(struct rtw89_dev *rtwdev, struct wiphy *wiphy) { const struct rtw89_chip_info *chip = rtwdev->chip; @@ -564,6 +613,7 @@ bottom: if (regd_allow_6ghz) { rtw89_regd_setup_policy_6ghz(rtwdev); rtw89_regd_setup_policy_6ghz_sp(rtwdev); + rtw89_regd_setup_policy_6ghz_vlp(rtwdev); return; } @@ -1059,7 +1109,16 @@ static int rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool active, unsigned int *changed) { + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + const struct rtw89_regd *regd = regulatory->regd; + bool blocked[NUM_OF_RTW89_REG_6GHZ_POWER] = {}; + u8 index = rtw89_regd_get_index(rtwdev, regd); struct ieee80211_bss_conf *bss_conf; + bool dflt = false; + + if (index == RTW89_REGD_MAX_COUNTRY_NUM || + test_bit(index, regulatory->block_6ghz_vlp)) + blocked[RTW89_REG_6GHZ_POWER_VLP] = true; rcu_read_lock(); @@ -1078,6 +1137,7 @@ static int rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev, break; default: rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; + dflt = true; break; } } else { @@ -1086,6 +1146,14 @@ static int rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev, rcu_read_unlock(); + if (!dflt && blocked[rtwvif_link->reg_6ghz_power]) { + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "%c%c 6 GHz power type-%u is blocked by policy\n", + regd->alpha2[0], regd->alpha2[1], + rtwvif_link->reg_6ghz_power); + return -EINVAL; + } + *changed += __rtw89_reg_6ghz_power_recalc(rtwdev); return 0; } From ad22869bc5a64a5a51f27951ced772499b2bf4bc Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 10 Jul 2025 12:24:10 +0800 Subject: [PATCH 094/199] wifi: rtw89: mcc: add H2C command to support different PD level in MCC Packet detection(PD) lower bound is the threshold for sensing packet, and it is dynamically calculated based on RSSI. In MCC, the two interfaces have different RSSI values, so it is necessary to set different values to ensure packets can be received. Therefore, add H2C command to let firmware to switch PD lower bound when MCC mode. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 25 +++ drivers/net/wireless/realtek/rtw89/chan.h | 5 + drivers/net/wireless/realtek/rtw89/fw.c | 53 ++++++ drivers/net/wireless/realtek/rtw89/fw.h | 25 +++ drivers/net/wireless/realtek/rtw89/phy.c | 188 ++++++++++++++++++---- 5 files changed, 265 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 6f10235647a1..32cd09f77e37 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -2371,6 +2371,7 @@ static void rtw89_mcc_stop(struct rtw89_dev *rtwdev, rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_STOP); rtw89_mcc_stop_beacon_noa(rtwdev); + rtw89_fw_h2c_mcc_dig(rtwdev, RTW89_CHANCTX_0, 0, 0, false); rtw89_mcc_prepare(rtwdev, false); } @@ -2622,6 +2623,30 @@ static void rtw89_mcc_update_limit(struct rtw89_dev *rtwdev) rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_upd_lmt_iterator, NULL); } +static int rtw89_mcc_get_links_iterator(struct rtw89_dev *rtwdev, + struct rtw89_mcc_role *mcc_role, + unsigned int ordered_idx, + void *data) +{ + struct rtw89_mcc_links_info *info = data; + + info->links[ordered_idx] = mcc_role->rtwvif_link; + return 0; +} + +void rtw89_mcc_get_links(struct rtw89_dev *rtwdev, struct rtw89_mcc_links_info *info) +{ + enum rtw89_entity_mode mode; + + memset(info, 0, sizeof(*info)); + + mode = rtw89_get_entity_mode(rtwdev); + if (unlikely(mode != RTW89_ENTITY_MODE_MCC)) + return; + + rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_get_links_iterator, info); +} + void rtw89_chanctx_work(struct wiphy *wiphy, struct wiphy_work *work) { struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev, diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h index 57355cb3d765..0e2ffb920455 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.h +++ b/drivers/net/wireless/realtek/rtw89/chan.h @@ -178,6 +178,11 @@ const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev, #define rtw89_mgnt_chan_get(rtwdev, link_index) \ __rtw89_mgnt_chan_get(rtwdev, __func__, link_index) +struct rtw89_mcc_links_info { + struct rtw89_vif_link *links[NUM_OF_RTW89_MCC_ROLES]; +}; + +void rtw89_mcc_get_links(struct rtw89_dev *rtwdev, struct rtw89_mcc_links_info *info); void rtw89_mcc_prepare_done_work(struct wiphy *wiphy, struct wiphy_work *work); int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index c613431e754f..3a3109ab7111 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -5985,6 +5985,59 @@ fail: } EXPORT_SYMBOL(rtw89_fw_h2c_rf_ntfy_mcc); +int rtw89_fw_h2c_mcc_dig(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_idx chanctx_idx, + u8 mcc_role_idx, u8 pd_val, bool en) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, chanctx_idx); + const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs; + struct rtw89_h2c_mcc_dig *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c mcc_dig\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_mcc_dig *)skb->data; + + h2c->w0 = le32_encode_bits(1, RTW89_H2C_MCC_DIG_W0_REG_CNT) | + le32_encode_bits(en, RTW89_H2C_MCC_DIG_W0_DM_EN) | + le32_encode_bits(mcc_role_idx, RTW89_H2C_MCC_DIG_W0_IDX) | + le32_encode_bits(1, RTW89_H2C_MCC_DIG_W0_SET) | + le32_encode_bits(1, RTW89_H2C_MCC_DIG_W0_PHY0_EN) | + le32_encode_bits(chan->channel, RTW89_H2C_MCC_DIG_W0_CENTER_CH) | + le32_encode_bits(chan->band_type, RTW89_H2C_MCC_DIG_W0_BAND_TYPE); + h2c->w1 = le32_encode_bits(dig_regs->seg0_pd_reg, + RTW89_H2C_MCC_DIG_W1_ADDR_LSB) | + le32_encode_bits(dig_regs->seg0_pd_reg >> 8, + RTW89_H2C_MCC_DIG_W1_ADDR_MSB) | + le32_encode_bits(dig_regs->pd_lower_bound_mask, + RTW89_H2C_MCC_DIG_W1_BMASK_LSB) | + le32_encode_bits(dig_regs->pd_lower_bound_mask >> 8, + RTW89_H2C_MCC_DIG_W1_BMASK_MSB); + h2c->w2 = le32_encode_bits(pd_val, RTW89_H2C_MCC_DIG_W2_VAL_LSB); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, H2C_CL_OUTSRC_DM, + H2C_FUNC_FW_MCC_DIG, 0, 0, len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} + int rtw89_fw_h2c_rf_ps_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { const struct rtw89_chip_info *chip = rtwdev->chip; diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 24d2e8b0d079..22b2b2a716ef 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -4341,6 +4341,7 @@ enum rtw89_mrc_h2c_func { #define H2C_FUNC_OUTSRC_RA_MACIDCFG 0x0 #define H2C_CL_OUTSRC_DM 0x2 +#define H2C_FUNC_FW_MCC_DIG 0x6 #define H2C_FUNC_FW_LPS_CH_INFO 0xb #define H2C_FUNC_FW_LPS_ML_CMN_INFO 0xe @@ -4378,6 +4379,27 @@ struct rtw89_fw_h2c_rf_get_mccch_v0 { __le32 current_band_type; } __packed; +struct rtw89_h2c_mcc_dig { + __le32 w0; + __le32 w1; + __le32 w2; +} __packed; + +#define RTW89_H2C_MCC_DIG_W0_REG_CNT GENMASK(7, 0) +#define RTW89_H2C_MCC_DIG_W0_DM_EN BIT(8) +#define RTW89_H2C_MCC_DIG_W0_IDX GENMASK(10, 9) +#define RTW89_H2C_MCC_DIG_W0_SET BIT(11) +#define RTW89_H2C_MCC_DIG_W0_PHY0_EN BIT(12) +#define RTW89_H2C_MCC_DIG_W0_PHY1_EN BIT(13) +#define RTW89_H2C_MCC_DIG_W0_CENTER_CH GENMASK(23, 16) +#define RTW89_H2C_MCC_DIG_W0_BAND_TYPE GENMASK(31, 24) +#define RTW89_H2C_MCC_DIG_W1_ADDR_LSB GENMASK(7, 0) +#define RTW89_H2C_MCC_DIG_W1_ADDR_MSB GENMASK(15, 8) +#define RTW89_H2C_MCC_DIG_W1_BMASK_LSB GENMASK(23, 16) +#define RTW89_H2C_MCC_DIG_W1_BMASK_MSB GENMASK(31, 24) +#define RTW89_H2C_MCC_DIG_W2_VAL_LSB GENMASK(7, 0) +#define RTW89_H2C_MCC_DIG_W2_VAL_MSB GENMASK(15, 8) + #define NUM_OF_RTW89_FW_RFK_PATH 2 #define NUM_OF_RTW89_FW_RFK_TBL 3 @@ -4774,6 +4796,9 @@ int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_rf_ps_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +int rtw89_fw_h2c_mcc_dig(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_idx chanctx_idx, + u8 mcc_role_idx, u8 pd_val, bool en); int rtw89_fw_h2c_rf_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, const struct rtw89_chan *chan, enum rtw89_tssi_mode tssi_mode); int rtw89_fw_h2c_rf_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 7d005db211e5..a7412d139902 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -6316,18 +6316,13 @@ static void rtw89_phy_dig_config_igi(struct rtw89_dev *rtwdev, } } -static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, - struct rtw89_bb_ctx *bb, - u8 rssi, bool enable) +static u8 rtw89_phy_dig_cal_under_region(struct rtw89_dev *rtwdev, + struct rtw89_bb_ctx *bb, + const struct rtw89_chan *chan) { - const struct rtw89_chan *chan = rtw89_mgnt_chan_get(rtwdev, bb->phy_idx); - const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs; enum rtw89_bandwidth cbw = chan->band_width; struct rtw89_dig_info *dig = &bb->dig; - u8 final_rssi = 0, under_region = dig->pd_low_th_ofst; - u8 ofdm_cca_th; - s8 cck_cca_th; - u32 pd_val = 0; + u8 under_region = dig->pd_low_th_ofst; if (rtwdev->chip->chip_gen == RTW89_CHIP_AX) under_region += PD_TH_SB_FLTR_CMP_VAL; @@ -6349,6 +6344,20 @@ static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, break; } + return under_region; +} + +static u32 __rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, + struct rtw89_bb_ctx *bb, + u8 rssi, bool enable, + const struct rtw89_chan *chan) +{ + struct rtw89_dig_info *dig = &bb->dig; + u8 ofdm_cca_th, under_region; + u8 final_rssi; + u32 pd_val; + + under_region = rtw89_phy_dig_cal_under_region(rtwdev, bb, chan); dig->dyn_pd_th_max = dig->igi_rssi; final_rssi = min_t(u8, rssi, dig->igi_rssi); @@ -6361,10 +6370,27 @@ static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, "igi=%d, ofdm_ccaTH=%d, backoff=%d, PD_low=%d\n", final_rssi, ofdm_cca_th, under_region, pd_val); } else { + pd_val = 0; rtw89_debug(rtwdev, RTW89_DBG_DIG, "Dynamic PD th disabled, Set PD_low_bd=0\n"); } + return pd_val; +} + +static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, + struct rtw89_bb_ctx *bb, + u8 rssi, bool enable) +{ + const struct rtw89_chan *chan = rtw89_mgnt_chan_get(rtwdev, bb->phy_idx); + const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs; + struct rtw89_dig_info *dig = &bb->dig; + u8 final_rssi, under_region = dig->pd_low_th_ofst; + s8 cck_cca_th; + u32 pd_val; + + pd_val = __rtw89_phy_dig_dyn_pd_th(rtwdev, bb, rssi, enable, chan); + rtw89_phy_write32_idx(rtwdev, dig_regs->seg0_pd_reg, dig_regs->pd_lower_bound_mask, pd_val, bb->phy_idx); rtw89_phy_write32_idx(rtwdev, dig_regs->seg0_pd_reg, @@ -6373,6 +6399,8 @@ static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, if (!rtwdev->hal.support_cckpd) return; + final_rssi = min_t(u8, rssi, dig->igi_rssi); + under_region = rtw89_phy_dig_cal_under_region(rtwdev, bb, chan); cck_cca_th = max_t(s8, final_rssi - under_region, CCKPD_TH_MIN_RSSI); pd_val = (u32)(cck_cca_th - IGI_RSSI_MAX); @@ -6400,32 +6428,12 @@ void rtw89_phy_dig_reset(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) #define IGI_RSSI_MIN 10 #define ABS_IGI_MIN 0xc -static void __rtw89_phy_dig(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) +static +void rtw89_phy_cal_igi_fa_rssi(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) { struct rtw89_dig_info *dig = &bb->dig; - bool is_linked = rtwdev->total_sta_assoc > 0; u8 igi_min; - if (unlikely(dig->bypass_dig)) { - dig->bypass_dig = false; - return; - } - - rtw89_debug(rtwdev, RTW89_DBG_DIG, "BB-%d dig track\n", bb->phy_idx); - - rtw89_phy_dig_update_rssi_info(rtwdev, bb); - - if (!dig->is_linked_pre && is_linked) { - rtw89_debug(rtwdev, RTW89_DBG_DIG, "First connected\n"); - rtw89_phy_dig_update_para(rtwdev, bb); - dig->igi_fa_rssi = dig->igi_rssi; - } else if (dig->is_linked_pre && !is_linked) { - rtw89_debug(rtwdev, RTW89_DBG_DIG, "First disconnected\n"); - rtw89_phy_dig_update_para(rtwdev, bb); - dig->igi_fa_rssi = dig->igi_rssi; - } - dig->is_linked_pre = is_linked; - rtw89_phy_dig_igi_offset_by_env(rtwdev, bb); igi_min = max_t(int, dig->igi_rssi - IGI_RSSI_MIN, 0); @@ -6439,6 +6447,124 @@ static void __rtw89_phy_dig(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) } else { dig->igi_fa_rssi = dig->dyn_igi_max; } +} + +struct rtw89_phy_iter_mcc_dig { + struct rtw89_vif_link *rtwvif_link; + bool has_sta; + u8 rssi_min; +}; + +static void rtw89_phy_set_mcc_dig(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_bb_ctx *bb, + u8 rssi_min, u8 mcc_role_idx, + bool is_linked) +{ + struct rtw89_dig_info *dig = &bb->dig; + const struct rtw89_chan *chan; + u8 pd_val; + + if (is_linked) { + dig->igi_rssi = rssi_min >> 1; + dig->igi_fa_rssi = dig->igi_rssi; + } else { + rtw89_debug(rtwdev, RTW89_DBG_DIG, "RSSI update : NO Link\n"); + dig->igi_rssi = rssi_nolink; + dig->igi_fa_rssi = dig->igi_rssi; + } + + chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); + rtw89_phy_cal_igi_fa_rssi(rtwdev, bb); + pd_val = __rtw89_phy_dig_dyn_pd_th(rtwdev, bb, dig->igi_fa_rssi, + is_linked, chan); + rtw89_fw_h2c_mcc_dig(rtwdev, rtwvif_link->chanctx_idx, + mcc_role_idx, pd_val, true); + + rtw89_debug(rtwdev, RTW89_DBG_DIG, + "MCC chanctx_idx %d chan %d rssi %d pd_val %d", + rtwvif_link->chanctx_idx, chan->primary_channel, + dig->igi_rssi, pd_val); +} + +static void rtw89_phy_set_mcc_dig_iter(void *data, struct ieee80211_sta *sta) +{ + struct rtw89_phy_iter_mcc_dig *mcc_dig = (struct rtw89_phy_iter_mcc_dig *)data; + unsigned int link_id = mcc_dig->rtwvif_link->link_id; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_sta_link *rtwsta_link; + + if (rtwsta->rtwvif != mcc_dig->rtwvif_link->rtwvif) + return; + + rtwsta_link = rtwsta->links[link_id]; + if (!rtwsta_link) + return; + + mcc_dig->has_sta = true; + if (ewma_rssi_read(&rtwsta_link->avg_rssi) < mcc_dig->rssi_min) + mcc_dig->rssi_min = ewma_rssi_read(&rtwsta_link->avg_rssi); +} + +static void rtw89_phy_dig_mcc(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) +{ + struct rtw89_phy_iter_mcc_dig mcc_dig; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_mcc_links_info info; + int i; + + rtw89_mcc_get_links(rtwdev, &info); + for (i = 0; i < ARRAY_SIZE(info.links); i++) { + rtwvif_link = info.links[i]; + if (!rtwvif_link) + continue; + + memset(&mcc_dig, 0, sizeof(mcc_dig)); + mcc_dig.rtwvif_link = rtwvif_link; + mcc_dig.has_sta = false; + mcc_dig.rssi_min = U8_MAX; + ieee80211_iterate_stations_atomic(rtwdev->hw, + rtw89_phy_set_mcc_dig_iter, + &mcc_dig); + + rtw89_phy_set_mcc_dig(rtwdev, rtwvif_link, bb, + mcc_dig.rssi_min, i, mcc_dig.has_sta); + } +} + +static void __rtw89_phy_dig(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) +{ + struct rtw89_dig_info *dig = &bb->dig; + bool is_linked = rtwdev->total_sta_assoc > 0; + enum rtw89_entity_mode mode; + + if (unlikely(dig->bypass_dig)) { + dig->bypass_dig = false; + return; + } + + rtw89_debug(rtwdev, RTW89_DBG_DIG, "BB-%d dig track\n", bb->phy_idx); + + rtw89_phy_dig_update_rssi_info(rtwdev, bb); + + mode = rtw89_get_entity_mode(rtwdev); + if (mode == RTW89_ENTITY_MODE_MCC) { + rtw89_phy_dig_mcc(rtwdev, bb); + return; + } + + if (!dig->is_linked_pre && is_linked) { + rtw89_debug(rtwdev, RTW89_DBG_DIG, "First connected\n"); + rtw89_phy_dig_update_para(rtwdev, bb); + dig->igi_fa_rssi = dig->igi_rssi; + } else if (dig->is_linked_pre && !is_linked) { + rtw89_debug(rtwdev, RTW89_DBG_DIG, "First disconnected\n"); + rtw89_phy_dig_update_para(rtwdev, bb); + dig->igi_fa_rssi = dig->igi_rssi; + } + dig->is_linked_pre = is_linked; + + rtw89_phy_cal_igi_fa_rssi(rtwdev, bb); rtw89_debug(rtwdev, RTW89_DBG_DIG, "rssi=%03d, dyn_joint(max,min)=(%d,%d), final_rssi=%d\n", From 9126020ab03c60053819c19294f46fc6ce11b52e Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 10 Jul 2025 12:24:11 +0800 Subject: [PATCH 095/199] wifi: rtw89: add DIG suspend/resume flow when scan and connection The PD lower bound set after one interface is connected, If second interface needs to connect, packets might not be detected because the PD lower bound is too high. Therefore, a DIG suspend/resume flow is added to decrease the PD lower bound during scanning or connection, and the original PD level is resumed afterward. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 4 ++ drivers/net/wireless/realtek/rtw89/core.c | 2 + drivers/net/wireless/realtek/rtw89/core.h | 2 + drivers/net/wireless/realtek/rtw89/fw.c | 2 + drivers/net/wireless/realtek/rtw89/phy.c | 50 +++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/phy.h | 2 + 6 files changed, 62 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 32cd09f77e37..1277b1af2a4c 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -7,6 +7,7 @@ #include "debug.h" #include "fw.h" #include "mac.h" +#include "phy.h" #include "ps.h" #include "sar.h" #include "util.h" @@ -2281,6 +2282,7 @@ static int rtw89_mcc_start(struct rtw89_dev *rtwdev) rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_START); rtw89_mcc_start_beacon_noa(rtwdev); + rtw89_phy_dig_suspend(rtwdev); rtw89_mcc_prepare(rtwdev, true); return 0; @@ -2372,6 +2374,7 @@ static void rtw89_mcc_stop(struct rtw89_dev *rtwdev, rtw89_mcc_stop_beacon_noa(rtwdev); rtw89_fw_h2c_mcc_dig(rtwdev, RTW89_CHANCTX_0, 0, 0, false); + rtw89_phy_dig_resume(rtwdev, true); rtw89_mcc_prepare(rtwdev, false); } @@ -2715,6 +2718,7 @@ void rtw89_queue_chanctx_change(struct rtw89_dev *rtwdev, return; case RTW89_ENTITY_MODE_MCC_PREPARE: delay = ieee80211_tu_to_usec(RTW89_CHANCTX_TIME_MCC_PREPARE); + rtw89_phy_dig_suspend(rtwdev); break; case RTW89_ENTITY_MODE_MCC: delay = ieee80211_tu_to_usec(RTW89_CHANCTX_TIME_MCC); diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 23d050041583..da82a88cce98 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -4082,6 +4082,7 @@ int rtw89_core_sta_link_add(struct rtw89_dev *rtwdev, &rtwsta_link->tx_retry); rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta_link, false, 60); } + rtw89_phy_dig_suspend(rtwdev); } else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { ret = rtw89_mac_set_macid_pause(rtwdev, rtwsta_link->mac_id, false); if (ret) { @@ -4270,6 +4271,7 @@ int rtw89_core_sta_link_assoc(struct rtw89_dev *rtwdev, if (vif->p2p) rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta_link, false, rtwsta_link->tx_retry); + rtw89_phy_dig_resume(rtwdev, false); } rtw89_assoc_link_set(rtwsta_link); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 8c53c5db0cbc..e0992c12c4ca 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -5243,8 +5243,10 @@ struct rtw89_dig_info { s8 tia_gain_a[TIA_GAIN_NUM]; s8 tia_gain_g[TIA_GAIN_NUM]; s8 *tia_gain; + u32 bak_dig; bool is_linked_pre; bool bypass_dig; + bool pause_dig; }; enum rtw89_multi_cfo_mode { diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 3a3109ab7111..ae38ea640384 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -7798,6 +7798,7 @@ int rtw89_hw_scan_start(struct rtw89_dev *rtwdev, rtw89_write32_mask(rtwdev, reg, B_AX_RX_FLTR_CFG_MASK, rx_fltr); rtw89_chanctx_pause(rtwdev, &pause_parm); + rtw89_phy_dig_suspend(rtwdev); if (mode == RTW89_ENTITY_MODE_MCC) rtw89_hw_scan_update_beacon_noa(rtwdev, req); @@ -7831,6 +7832,7 @@ static int rtw89_hw_scan_complete_cb(struct rtw89_dev *rtwdev, void *data) ieee80211_wake_queues(rtwdev->hw); rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif_link, true); rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, true); + rtw89_phy_dig_resume(rtwdev, true); rtw89_hw_scan_cleanup(rtwdev, rtwvif_link); diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index a7412d139902..d607577b353c 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -6390,6 +6390,7 @@ static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, u32 pd_val; pd_val = __rtw89_phy_dig_dyn_pd_th(rtwdev, bb, rssi, enable, chan); + dig->bak_dig = pd_val; rtw89_phy_write32_idx(rtwdev, dig_regs->seg0_pd_reg, dig_regs->pd_lower_bound_mask, pd_val, bb->phy_idx); @@ -6532,6 +6533,52 @@ static void rtw89_phy_dig_mcc(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) } } +static void rtw89_phy_dig_ctrl(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb, + bool pause_dig, bool restore) +{ + const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs; + struct rtw89_dig_info *dig = &bb->dig; + bool en_dig; + u32 pd_val; + + if (dig->pause_dig == pause_dig) + return; + + if (pause_dig) { + en_dig = false; + pd_val = 0; + } else { + en_dig = rtwdev->total_sta_assoc > 0; + pd_val = restore ? dig->bak_dig : 0; + } + + rtw89_debug(rtwdev, RTW89_DBG_DIG, "%s <%s> PD_low=%d", __func__, + pause_dig ? "suspend" : "resume", pd_val); + + rtw89_phy_write32_idx(rtwdev, dig_regs->seg0_pd_reg, + dig_regs->pd_lower_bound_mask, pd_val, bb->phy_idx); + rtw89_phy_write32_idx(rtwdev, dig_regs->seg0_pd_reg, + dig_regs->pd_spatial_reuse_en, en_dig, bb->phy_idx); + + dig->pause_dig = pause_dig; +} + +void rtw89_phy_dig_suspend(struct rtw89_dev *rtwdev) +{ + struct rtw89_bb_ctx *bb; + + rtw89_for_each_active_bb(rtwdev, bb) + rtw89_phy_dig_ctrl(rtwdev, bb, true, false); +} + +void rtw89_phy_dig_resume(struct rtw89_dev *rtwdev, bool restore) +{ + struct rtw89_bb_ctx *bb; + + rtw89_for_each_active_bb(rtwdev, bb) + rtw89_phy_dig_ctrl(rtwdev, bb, false, restore); +} + static void __rtw89_phy_dig(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) { struct rtw89_dig_info *dig = &bb->dig; @@ -6553,6 +6600,9 @@ static void __rtw89_phy_dig(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) return; } + if (unlikely(dig->pause_dig)) + return; + if (!dig->is_linked_pre && is_linked) { rtw89_debug(rtwdev, RTW89_DBG_DIG, "First connected\n"); rtw89_phy_dig_update_para(rtwdev, bb); diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 63cc33c16c9a..dc156376d951 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -1010,6 +1010,8 @@ void rtw89_phy_set_phy_regs(struct rtw89_dev *rtwdev, u32 addr, u32 mask, u32 val); void rtw89_phy_dig_reset(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb); void rtw89_phy_dig(struct rtw89_dev *rtwdev); +void rtw89_phy_dig_suspend(struct rtw89_dev *rtwdev); +void rtw89_phy_dig_resume(struct rtw89_dev *rtwdev, bool restore); void rtw89_phy_tx_path_div_track(struct rtw89_dev *rtwdev); void rtw89_phy_antdiv_parse(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu); From 025e39032df5cc5c110de3693f63e81cf49968be Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 10 Jul 2025 12:24:12 +0800 Subject: [PATCH 096/199] wifi: rtw89: mcc: enlarge GO NoA duration to cover channel switching time MCC require time to switch channel when changing timeslot. If GC TX nulldata 0 while GO is switching channel, GO can't receive it. Therefore, enlarge the GO NoA duration to cover the channel switching time. However, the enlarged NoA duration might cause GC's timeslot less than minimum of RX beacon time. Therefore, adjust strict and anchor pattern condition to avoid it. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 7 ++++--- drivers/net/wireless/realtek/rtw89/chan.h | 4 ++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 1277b1af2a4c..e5ef4f6ab5ca 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -1116,7 +1116,7 @@ static int __rtw89_mcc_calc_pattern_strict(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *ref = &mcc->role_ref; struct rtw89_mcc_role *aux = &mcc->role_aux; struct rtw89_mcc_config *config = &mcc->config; - u16 min_tob = RTW89_MCC_EARLY_RX_BCN_TIME; + u16 min_tob = RTW89_MCC_EARLY_RX_BCN_TIME + RTW89_MCC_SWITCH_CH_TIME; u16 min_toa = RTW89_MCC_MIN_RX_BCN_TIME; u16 bcn_ofst = config->beacon_offset; s16 upper_toa_ref, lower_toa_ref; @@ -1272,11 +1272,11 @@ static int __rtw89_mcc_calc_pattern_anchor(struct rtw89_dev *rtwdev, u16 bcn_ofst = config->beacon_offset; bool small_bcn_ofst; - if (bcn_ofst < RTW89_MCC_MIN_RX_BCN_TIME) + if (bcn_ofst < RTW89_MCC_MIN_RX_BCN_WITH_SWITCH_CH_TIME) small_bcn_ofst = true; else if (bcn_ofst < aux->duration - aux->limit.max_toa) small_bcn_ofst = true; - else if (mcc_intvl - bcn_ofst < RTW89_MCC_MIN_RX_BCN_TIME) + else if (mcc_intvl - bcn_ofst < RTW89_MCC_MIN_RX_BCN_WITH_SWITCH_CH_TIME) small_bcn_ofst = false; else return -EPERM; @@ -2171,6 +2171,7 @@ static void rtw89_mcc_handle_beacon_noa(struct rtw89_dev *rtwdev, bool enable) rtw89_p2p_noa_renew(rtwvif_go); if (enable) { + duration += RTW89_MCC_SWITCH_CH_TIME; noa_desc.start_time = cpu_to_le32(start_time); noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(interval)); noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(duration)); diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h index 0e2ffb920455..9a62b7c98b83 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.h +++ b/drivers/net/wireless/realtek/rtw89/chan.h @@ -18,6 +18,7 @@ #define RTW89_MCC_EARLY_RX_BCN_TIME 5 #define RTW89_MCC_MIN_RX_BCN_TIME 10 #define RTW89_MCC_DFLT_BCN_OFST_TIME 40 +#define RTW89_MCC_SWITCH_CH_TIME 3 #define RTW89_MCC_PROBE_TIMEOUT 100 #define RTW89_MCC_PROBE_MAX_TRIES 3 @@ -28,6 +29,9 @@ #define RTW89_MCC_MIN_STA_DURATION \ (RTW89_MCC_EARLY_RX_BCN_TIME + RTW89_MCC_MIN_RX_BCN_TIME) +#define RTW89_MCC_MIN_RX_BCN_WITH_SWITCH_CH_TIME \ + (RTW89_MCC_MIN_RX_BCN_TIME + RTW89_MCC_SWITCH_CH_TIME) + #define RTW89_MCC_DFLT_GROUP 0 #define RTW89_MCC_NEXT_GROUP(cur) (((cur) + 1) % 4) From 6332feafe37fdd0a336ab01b42fdfb5e6b8ee083 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 10 Jul 2025 12:24:13 +0800 Subject: [PATCH 097/199] wifi: rtw89: mcc: when MCC stop forcing to stay at GO role MCC stop might triggered by scan, and need to force to stay at GO role to keep TX beacon. Also, AX chips need to TX more 3 beacons to ensure GC can receive once NoA beacon before scan when GC in courtesy mode. BE chips no needs to TX 3 more beacon because it can TX beacon every 200TU during scan, even GC in courtesy mode can receive beacon every 600TU. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 8 ++++++++ drivers/net/wireless/realtek/rtw89/core.h | 3 ++- drivers/net/wireless/realtek/rtw89/fw.c | 21 ++++++++++++++++++--- drivers/net/wireless/realtek/rtw89/mac.c | 1 + drivers/net/wireless/realtek/rtw89/wow.c | 2 +- 5 files changed, 30 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index e5ef4f6ab5ca..6c80e08ae99d 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -2336,9 +2336,11 @@ static void rtw89_mcc_stop(struct rtw89_dev *rtwdev, struct rtw89_hal *hal = &rtwdev->hal; struct rtw89_mcc_info *mcc = &rtwdev->mcc; struct rtw89_mcc_role *ref = &mcc->role_ref; + struct rtw89_mcc_role *aux = &mcc->role_aux; struct rtw89_mcc_stop_sel sel = { .hint.target = pause ? pause->trigger : NULL, }; + bool rsn_scan; int ret; if (!pause) { @@ -2346,6 +2348,12 @@ static void rtw89_mcc_stop(struct rtw89_dev *rtwdev, bitmap_zero(hal->changes, NUM_OF_RTW89_CHANCTX_CHANGES); } + rsn_scan = pause && pause->rsn == RTW89_CHANCTX_PAUSE_REASON_HW_SCAN; + if (rsn_scan && ref->is_go) + sel.hint.target = ref->rtwvif_link; + else if (rsn_scan && aux->is_go) + sel.hint.target = aux->rtwvif_link; + /* by default, stop at ref */ rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_stop_sel_iterator, &sel); if (!sel.filled) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index e0992c12c4ca..c003a31477bb 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3860,7 +3860,7 @@ struct rtw89_scan_option { u16 slow_pd; u16 norm_cy; u8 opch_end; - u16 delay; + u16 delay; /* in unit of ms */ u64 prohib_chan; enum rtw89_phy_idx band; enum rtw89_scan_be_operation operation; @@ -5550,6 +5550,7 @@ struct rtw89_hw_scan_info { struct rtw89_hw_scan_extra_op extra_op; bool connected; bool abort; + u16 delay; /* in unit of ms */ }; enum rtw89_phy_bb_gain_band { diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index ae38ea640384..1fd88dc7da85 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -5583,7 +5583,6 @@ int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num, return 0; } -#define RTW89_SCAN_DELAY_TSF_UNIT 1000000 int rtw89_fw_h2c_scan_offload_ax(struct rtw89_dev *rtwdev, struct rtw89_scan_option *option, struct rtw89_vif_link *rtwvif_link, @@ -5615,7 +5614,7 @@ int rtw89_fw_h2c_scan_offload_ax(struct rtw89_dev *rtwdev, scan_mode = RTW89_SCAN_IMMEDIATE; } else { scan_mode = RTW89_SCAN_DELAY; - tsf += (u64)option->delay * RTW89_SCAN_DELAY_TSF_UNIT; + tsf += (u64)option->delay * 1000; } } @@ -5781,7 +5780,7 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, RTW89_H2C_SCANOFLD_BE_W4_PROBE_5G) | le32_encode_bits(probe_id[NL80211_BAND_6GHZ], RTW89_H2C_SCANOFLD_BE_W4_PROBE_6G) | - le32_encode_bits(option->delay, RTW89_H2C_SCANOFLD_BE_W4_DELAY_START); + le32_encode_bits(option->delay / 1000, RTW89_H2C_SCANOFLD_BE_W4_DELAY_START); h2c->w5 = le32_encode_bits(option->mlo_mode, RTW89_H2C_SCANOFLD_BE_W5_MLO_MODE); @@ -6826,6 +6825,7 @@ static void rtw89_hw_scan_cleanup(struct rtw89_dev *rtwdev, scan_info->scanning_vif = NULL; scan_info->abort = false; scan_info->connected = false; + scan_info->delay = 0; } static bool rtw89_is_6ghz_wildcard_probe_req(struct rtw89_dev *rtwdev, @@ -7628,9 +7628,22 @@ static void rtw89_hw_scan_update_link_beacon_noa(struct rtw89_dev *rtwdev, u16 tu) { struct ieee80211_p2p_noa_desc noa_desc = {}; + struct ieee80211_bss_conf *bss_conf; + u16 beacon_int; u64 tsf; int ret; + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + beacon_int = bss_conf->beacon_int; + + rcu_read_unlock(); + + tu += beacon_int * 3; + if (rtwdev->chip->chip_gen == RTW89_CHIP_AX) + rtwdev->scan_info.delay = ieee80211_tu_to_usec(beacon_int * 3) / 1000; + ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif_link, &tsf); if (ret) { rtw89_warn(rtwdev, "%s: failed to get tsf\n", __func__); @@ -7770,6 +7783,7 @@ int rtw89_hw_scan_start(struct rtw89_dev *rtwdev, rtwdev->scan_info.connected = rtw89_is_any_vif_connected_or_connecting(rtwdev); rtwdev->scan_info.scanning_vif = rtwvif_link; rtwdev->scan_info.abort = false; + rtwdev->scan_info.delay = 0; rtwvif->scan_ies = &scan_req->ies; rtwvif->scan_req = req; @@ -7912,6 +7926,7 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, connected = rtwdev->scan_info.connected; opt.enable = enable; opt.target_ch_mode = connected; + opt.delay = rtwdev->scan_info.delay; if (enable) { ret = mac->add_chan_list(rtwdev, rtwvif_link); if (ret) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index ff4335ef4033..37b113e3bd26 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -5049,6 +5049,7 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, if (rtwvif_link && rtwvif->scan_req && !list_empty(&rtwdev->scan_info.chan_list)) { + rtwdev->scan_info.delay = 0; ret = rtw89_hw_scan_offload(rtwdev, rtwvif_link, true); if (ret) { rtw89_hw_scan_abort(rtwdev, rtwvif_link); diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index c935d6683d83..4f759c75389e 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -1477,7 +1477,7 @@ static int rtw89_pno_scan_offload(struct rtw89_dev *rtwdev, bool enable) opt.enable = enable; opt.repeat = RTW89_SCAN_NORMAL; opt.norm_pd = max(interval, 1) * 10; /* in unit of 100ms */ - opt.delay = max(rtw_wow->nd_config->delay, 1); + opt.delay = max(rtw_wow->nd_config->delay, 1) * 1000; if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) { opt.operation = enable ? RTW89_SCAN_OP_START : RTW89_SCAN_OP_STOP; From d0b87d9eaf76703b81e511d05db29a5e7ef6c3e0 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 10 Jul 2025 12:24:14 +0800 Subject: [PATCH 098/199] wifi: rtw89: extend HW scan of WiFi 7 chips for extra OP chan when concurrency HW scan of WiFi 7 chips supports multiple op channel configurations. When concurrency, fill two channels info to HW scan to avoid packet lost. However, the OP chan timing is arranged by FW, and the actual stay period depends on AP. It's hard to calculate total scan time for once NoA in advance. Therefore, change the scan back to GO OP channel every 200TU and TX beacon to ensure GC doesn't beacon loss. Additionally, add a period NoA with large duration to ensure GC doesn't TX packet during GO scanning and can still listen beacon at TBTT to update the new NoA info after scan complete. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 2 + drivers/net/wireless/realtek/rtw89/fw.c | 88 ++++++++++++++++++----- drivers/net/wireless/realtek/rtw89/fw.h | 1 + 3 files changed, 73 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index c003a31477bb..2faf0889f7df 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -5539,7 +5539,9 @@ struct rtw89_early_h2c { struct rtw89_hw_scan_extra_op { bool set; u8 macid; + u8 port; struct rtw89_chan chan; + struct rtw89_vif_link *rtwvif_link; }; struct rtw89_hw_scan_info { diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 1fd88dc7da85..20b7b4b15450 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -5700,26 +5700,47 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, { struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + const struct rtw89_hw_scan_extra_op *ext = &scan_info->extra_op; struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; struct cfg80211_scan_request *req = rtwvif->scan_req; struct rtw89_h2c_scanofld_be_macc_role *macc_role; + struct rtw89_hw_scan_extra_op scan_op[2] = {}; struct rtw89_chan *op = &scan_info->op_chan; struct rtw89_h2c_scanofld_be_opch *opch; struct rtw89_pktofld_info *pkt_info; struct rtw89_h2c_scanofld_be *h2c; + struct ieee80211_vif *vif; struct sk_buff *skb; u8 macc_role_size = sizeof(*macc_role) * option->num_macc_role; u8 opch_size = sizeof(*opch) * option->num_opch; + enum rtw89_scan_be_opmode opmode; u8 probe_id[NUM_NL80211_BANDS]; u8 scan_offload_ver = U8_MAX; u8 cfg_len = sizeof(*h2c); unsigned int cond; + u8 ap_idx = U8_MAX; u8 ver = U8_MAX; + u8 policy_val; void *ptr; + u8 txbcn; int ret; u32 len; u8 i; + scan_op[0].macid = rtwvif_link->mac_id; + scan_op[0].port = rtwvif_link->port; + scan_op[0].chan = *op; + vif = rtwvif_to_vif(rtwvif_link->rtwvif); + if (vif->type == NL80211_IFTYPE_AP) + ap_idx = 0; + + if (ext->set) { + scan_op[1] = *ext; + vif = rtwvif_to_vif(ext->rtwvif_link->rtwvif); + if (vif->type == NL80211_IFTYPE_AP) + ap_idx = 1; + } + rtw89_scan_get_6g_disabled_chan(rtwdev, option); if (RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD_BE_V0, &rtwdev->fw)) { @@ -5822,29 +5843,35 @@ flex_member: } for (i = 0; i < option->num_opch; i++) { + bool is_ap_idx = i == ap_idx; + + opmode = is_ap_idx ? RTW89_SCAN_OPMODE_TBTT : RTW89_SCAN_OPMODE_INTV; + policy_val = is_ap_idx ? 2 : RTW89_OFF_CHAN_TIME / 10; + txbcn = is_ap_idx ? 1 : 0; + opch = ptr; - opch->w0 = le32_encode_bits(rtwvif_link->mac_id, + opch->w0 = le32_encode_bits(scan_op[i].macid, RTW89_H2C_SCANOFLD_BE_OPCH_W0_MACID) | le32_encode_bits(option->band, RTW89_H2C_SCANOFLD_BE_OPCH_W0_BAND) | - le32_encode_bits(rtwvif_link->port, + le32_encode_bits(scan_op[i].port, RTW89_H2C_SCANOFLD_BE_OPCH_W0_PORT) | - le32_encode_bits(RTW89_SCAN_OPMODE_INTV, + le32_encode_bits(opmode, RTW89_H2C_SCANOFLD_BE_OPCH_W0_POLICY) | le32_encode_bits(true, RTW89_H2C_SCANOFLD_BE_OPCH_W0_TXNULL) | - le32_encode_bits(RTW89_OFF_CHAN_TIME / 10, + le32_encode_bits(policy_val, RTW89_H2C_SCANOFLD_BE_OPCH_W0_POLICY_VAL); - opch->w1 = le32_encode_bits(op->band_type, + opch->w1 = le32_encode_bits(scan_op[i].chan.band_type, RTW89_H2C_SCANOFLD_BE_OPCH_W1_CH_BAND) | - le32_encode_bits(op->band_width, + le32_encode_bits(scan_op[i].chan.band_width, RTW89_H2C_SCANOFLD_BE_OPCH_W1_BW) | le32_encode_bits(0x3, RTW89_H2C_SCANOFLD_BE_OPCH_W1_NOTIFY) | - le32_encode_bits(op->primary_channel, + le32_encode_bits(scan_op[i].chan.primary_channel, RTW89_H2C_SCANOFLD_BE_OPCH_W1_PRI_CH) | - le32_encode_bits(op->channel, + le32_encode_bits(scan_op[i].chan.channel, RTW89_H2C_SCANOFLD_BE_OPCH_W1_CENTRAL_CH); opch->w2 = le32_encode_bits(0, @@ -5852,7 +5879,9 @@ flex_member: le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_OPCH_W2_SW_DEF) | le32_encode_bits(rtw89_is_mlo_1_1(rtwdev) ? 1 : 2, - RTW89_H2C_SCANOFLD_BE_OPCH_W2_SS); + RTW89_H2C_SCANOFLD_BE_OPCH_W2_SS) | + le32_encode_bits(txbcn, + RTW89_H2C_SCANOFLD_BE_OPCH_W2_TXBCN); opch->w3 = le32_encode_bits(RTW89_SCANOFLD_PKT_NONE, RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT0) | @@ -7625,7 +7654,7 @@ out: static void rtw89_hw_scan_update_link_beacon_noa(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, - u16 tu) + u16 tu, bool scan) { struct ieee80211_p2p_noa_desc noa_desc = {}; struct ieee80211_bss_conf *bss_conf; @@ -7651,17 +7680,24 @@ static void rtw89_hw_scan_update_link_beacon_noa(struct rtw89_dev *rtwdev, } noa_desc.start_time = cpu_to_le32(tsf); - noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(tu)); - noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(tu)); - noa_desc.count = 1; + if (rtwdev->chip->chip_gen == RTW89_CHIP_AX) { + noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(tu)); + noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(tu)); + noa_desc.count = 1; + } else { + noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(20000)); + noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(20000)); + noa_desc.count = 255; + } rtw89_p2p_noa_renew(rtwvif_link); - rtw89_p2p_noa_append(rtwvif_link, &noa_desc); + if (scan) + rtw89_p2p_noa_append(rtwvif_link, &noa_desc); + rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_link); } -static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev, - const struct cfg80211_scan_request *req) +static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev, bool scan) { const struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt; const struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; @@ -7676,6 +7712,9 @@ static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev, lockdep_assert_wiphy(rtwdev->hw->wiphy); + if (!scan) + goto update; + list_for_each_safe(pos, tmp, &scan_info->chan_list) { switch (chip->chip_gen) { case RTW89_CHIP_AX: @@ -7699,6 +7738,7 @@ static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev, return; } +update: list_for_each_entry(rtwvif, &mgnt->active_list, mgnt_entry) { unsigned int link_id; @@ -7707,7 +7747,8 @@ static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev, continue; rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) - rtw89_hw_scan_update_link_beacon_noa(rtwdev, rtwvif_link, tu); + rtw89_hw_scan_update_link_beacon_noa(rtwdev, rtwvif_link, + tu, scan); } } @@ -7742,7 +7783,9 @@ static void rtw89_hw_scan_set_extra_op_info(struct rtw89_dev *rtwdev, *ext = (struct rtw89_hw_scan_extra_op){ .set = true, .macid = tmp_link->mac_id, + .port = tmp_link->port, .chan = *tmp_chan, + .rtwvif_link = tmp_link, }; rtw89_debug(rtwdev, RTW89_DBG_HW_SCAN, @@ -7815,7 +7858,7 @@ int rtw89_hw_scan_start(struct rtw89_dev *rtwdev, rtw89_phy_dig_suspend(rtwdev); if (mode == RTW89_ENTITY_MODE_MCC) - rtw89_hw_scan_update_beacon_noa(rtwdev, req); + rtw89_hw_scan_update_beacon_noa(rtwdev, true); return 0; } @@ -7828,6 +7871,7 @@ struct rtw89_hw_scan_complete_cb_data { static int rtw89_hw_scan_complete_cb(struct rtw89_dev *rtwdev, void *data) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + enum rtw89_entity_mode mode = rtw89_get_entity_mode(rtwdev); struct rtw89_hw_scan_complete_cb_data *cb_data = data; struct rtw89_vif_link *rtwvif_link = cb_data->rtwvif_link; struct cfg80211_scan_info info = { @@ -7850,6 +7894,9 @@ static int rtw89_hw_scan_complete_cb(struct rtw89_dev *rtwdev, void *data) rtw89_hw_scan_cleanup(rtwdev, rtwvif_link); + if (mode == RTW89_ENTITY_MODE_MCC) + rtw89_hw_scan_update_beacon_noa(rtwdev, false); + return 0; } @@ -7916,6 +7963,8 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, bool enable) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + const struct rtw89_hw_scan_extra_op *ext = &scan_info->extra_op; struct rtw89_scan_option opt = {0}; bool connected; int ret = 0; @@ -7940,6 +7989,9 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, opt.num_macc_role = 0; opt.mlo_mode = rtwdev->mlo_dbcc_mode; opt.num_opch = connected ? 1 : 0; + if (connected && ext->set) + opt.num_opch++; + opt.opch_end = connected ? 0 : RTW89_CHAN_INVALID; } diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 22b2b2a716ef..479a9f980b7f 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -2817,6 +2817,7 @@ struct rtw89_h2c_scanofld_be_opch { #define RTW89_H2C_SCANOFLD_BE_OPCH_W2_PKTS_CTRL GENMASK(7, 0) #define RTW89_H2C_SCANOFLD_BE_OPCH_W2_SW_DEF GENMASK(15, 8) #define RTW89_H2C_SCANOFLD_BE_OPCH_W2_SS GENMASK(18, 16) +#define RTW89_H2C_SCANOFLD_BE_OPCH_W2_TXBCN BIT(19) #define RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT0 GENMASK(7, 0) #define RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT1 GENMASK(15, 8) #define RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT2 GENMASK(23, 16) From 83f84f263420b4a11c1b3c1ba0723c3d374b33ad Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 10 Jul 2025 12:24:15 +0800 Subject: [PATCH 099/199] wifi: rtw89: mcc: solve GO's TBTT change and TBTT too close to NoA issue For some implementation acting as GO under MCC(GO+STA), the GO's TBTT might change after STA roams to another AP. This could result the new GO beacon TX at the STA timeslot of GC+STA, causing GC beacon loss. Therefore, if the GC detects beacon loss, it will pause MCC and remain on the GO side for 100 TU to detect the new TBTT beacon. Additionally, some implementation acting as GO under MCC might TX beacon too close to the NoA period. The GC calculates timeslot pattern the TOB (time offset behind) or TOA(time offset ahead) less than the minimum RX beacon time, which leads to beacon loss. Therefore, disable the beacon filter in this case. Then, if the GO's TBTT changed, the pattern TOB/TOA greater than the minimum RX beacon time, the beacon filter should be retriggered during MCC update. Moreover, if the beacon filter is disabled initially but the GO timeslot change, causing QoS null data detection fail, also pause MCC to detect new TBTT beacon. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 143 ++++++++++++++++-- drivers/net/wireless/realtek/rtw89/chan.h | 6 + drivers/net/wireless/realtek/rtw89/core.h | 4 + drivers/net/wireless/realtek/rtw89/mac.c | 10 +- drivers/net/wireless/realtek/rtw89/mac80211.c | 5 + 5 files changed, 154 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 6c80e08ae99d..ed0d89ac3495 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -1000,6 +1000,11 @@ static void rtw89_mcc_assign_pattern(struct rtw89_dev *rtwdev, *pattern = *new; memset(&pattern->courtesy, 0, sizeof(pattern->courtesy)); + if (RTW89_MCC_REQ_COURTESY(pattern, aux) && aux->is_gc) + aux->ignore_bcn = true; + else + aux->ignore_bcn = false; + if (RTW89_MCC_REQ_COURTESY(pattern, aux) && rtw89_mcc_can_courtesy(ref, aux)) { crtz = &pattern->courtesy.ref; ref->crtz = crtz; @@ -1014,6 +1019,11 @@ static void rtw89_mcc_assign_pattern(struct rtw89_dev *rtwdev, ref->crtz = NULL; } + if (RTW89_MCC_REQ_COURTESY(pattern, ref) && ref->is_gc) + ref->ignore_bcn = true; + else + ref->ignore_bcn = false; + if (RTW89_MCC_REQ_COURTESY(pattern, ref) && rtw89_mcc_can_courtesy(aux, ref)) { crtz = &pattern->courtesy.aux; aux->crtz = crtz; @@ -2255,15 +2265,6 @@ static int rtw89_mcc_start(struct rtw89_dev *rtwdev) else mcc->mode = RTW89_MCC_MODE_GC_STA; - if (rtw89_mcc_ignore_bcn(rtwdev, ref)) { - rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, false); - } else if (rtw89_mcc_ignore_bcn(rtwdev, aux)) { - rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, false); - } else { - rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, true); - rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, true); - } - rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC sel mode: %d\n", mcc->mode); mcc->group = RTW89_MCC_DFLT_GROUP; @@ -2272,6 +2273,15 @@ static int rtw89_mcc_start(struct rtw89_dev *rtwdev) if (ret) return ret; + if (rtw89_mcc_ignore_bcn(rtwdev, ref) || aux->ignore_bcn) { + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, false); + } else if (rtw89_mcc_ignore_bcn(rtwdev, aux) || ref->ignore_bcn) { + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, false); + } else { + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, true); + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, true); + } + if (rtw89_concurrent_via_mrc(rtwdev)) ret = __mrc_fw_start(rtwdev, false); else @@ -2391,7 +2401,11 @@ static void rtw89_mcc_stop(struct rtw89_dev *rtwdev, static int rtw89_mcc_update(struct rtw89_dev *rtwdev) { struct rtw89_mcc_info *mcc = &rtwdev->mcc; + bool old_ref_ignore_bcn = mcc->role_ref.ignore_bcn; + bool old_aux_ignore_bcn = mcc->role_aux.ignore_bcn; struct rtw89_mcc_config *config = &mcc->config; + struct rtw89_mcc_role *ref = &mcc->role_ref; + struct rtw89_mcc_role *aux = &mcc->role_aux; struct rtw89_mcc_config old_cfg = *config; bool courtesy_changed; bool sync_changed; @@ -2406,6 +2420,11 @@ static int rtw89_mcc_update(struct rtw89_dev *rtwdev) if (ret) return ret; + if (old_ref_ignore_bcn != ref->ignore_bcn) + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, !ref->ignore_bcn); + else if (old_aux_ignore_bcn != aux->ignore_bcn) + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, !aux->ignore_bcn); + if (memcmp(&old_cfg.pattern.courtesy, &config->pattern.courtesy, sizeof(old_cfg.pattern.courtesy)) == 0) courtesy_changed = false; @@ -2441,10 +2460,105 @@ static int rtw89_mcc_update(struct rtw89_dev *rtwdev) return 0; } +static int rtw89_mcc_search_gc_iterator(struct rtw89_dev *rtwdev, + struct rtw89_mcc_role *mcc_role, + unsigned int ordered_idx, + void *data) +{ + struct rtw89_mcc_role **role = data; + + if (mcc_role->is_gc) + *role = mcc_role; + + return 0; +} + +static struct rtw89_mcc_role *rtw89_mcc_get_gc_role(struct rtw89_dev *rtwdev) +{ + struct rtw89_mcc_info *mcc = &rtwdev->mcc; + struct rtw89_mcc_role *role = NULL; + + if (mcc->mode != RTW89_MCC_MODE_GC_STA) + return NULL; + + rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_search_gc_iterator, &role); + + return role; +} + +void rtw89_mcc_gc_detect_beacon_work(struct wiphy *wiphy, struct wiphy_work *work) +{ + struct rtw89_vif_link *rtwvif_link = container_of(work, struct rtw89_vif_link, + mcc_gc_detect_beacon_work.work); + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + enum rtw89_entity_mode mode; + struct rtw89_dev *rtwdev; + + lockdep_assert_wiphy(wiphy); + + rtwdev = rtwvif_link->rtwvif->rtwdev; + + mode = rtw89_get_entity_mode(rtwdev); + if (mode != RTW89_ENTITY_MODE_MCC) + return; + + if (READ_ONCE(rtwvif_link->sync_bcn_tsf) > rtwvif_link->last_sync_bcn_tsf) + rtwvif_link->detect_bcn_count = 0; + else + rtwvif_link->detect_bcn_count++; + + if (rtwvif_link->detect_bcn_count < RTW89_MCC_DETECT_BCN_MAX_TRIES) + rtw89_chanctx_proceed(rtwdev, NULL); + else + ieee80211_connection_loss(vif); +} + +bool rtw89_mcc_detect_go_bcn(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + enum rtw89_entity_mode mode = rtw89_get_entity_mode(rtwdev); + struct rtw89_chanctx_pause_parm pause_parm = { + .rsn = RTW89_CHANCTX_PAUSE_REASON_GC_BCN_LOSS, + .trigger = rtwvif_link, + }; + struct ieee80211_bss_conf *bss_conf; + struct rtw89_mcc_role *role; + u16 bcn_int; + + if (mode != RTW89_ENTITY_MODE_MCC) + return false; + + role = rtw89_mcc_get_gc_role(rtwdev); + if (!role) + return false; + + if (role->rtwvif_link != rtwvif_link) + return false; + + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MCC GC beacon loss, pause MCC to detect GO beacon\n"); + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + bcn_int = bss_conf->beacon_int; + + rcu_read_unlock(); + + rtw89_chanctx_pause(rtwdev, &pause_parm); + rtwvif_link->last_sync_bcn_tsf = READ_ONCE(rtwvif_link->sync_bcn_tsf); + wiphy_delayed_work_queue(rtwdev->hw->wiphy, + &rtwvif_link->mcc_gc_detect_beacon_work, + usecs_to_jiffies(ieee80211_tu_to_usec(bcn_int))); + + return true; +} + static void rtw89_mcc_detect_connection(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role) { struct ieee80211_vif *vif; + bool start_detect; int ret; ret = rtw89_core_send_nullfunc(rtwdev, role->rtwvif_link, true, false, @@ -2458,7 +2572,12 @@ static void rtw89_mcc_detect_connection(struct rtw89_dev *rtwdev, return; rtw89_debug(rtwdev, RTW89_DBG_CHAN, - "MCC can not detect AP\n", role->rtwvif_link->mac_id); + "MCC can not detect AP/GO\n", role->rtwvif_link->mac_id); + + start_detect = rtw89_mcc_detect_go_bcn(rtwdev, role->rtwvif_link); + if (start_detect) + return; + vif = rtwvif_link_to_vif(role->rtwvif_link); ieee80211_connection_loss(vif); } @@ -2474,9 +2593,9 @@ static void rtw89_mcc_track(struct rtw89_dev *rtwdev) u16 bcn_ofst; u16 diff; - if (rtw89_mcc_ignore_bcn(rtwdev, ref)) + if (rtw89_mcc_ignore_bcn(rtwdev, ref) || aux->ignore_bcn) rtw89_mcc_detect_connection(rtwdev, aux); - else if (rtw89_mcc_ignore_bcn(rtwdev, aux)) + else if (rtw89_mcc_ignore_bcn(rtwdev, aux) || ref->ignore_bcn) rtw89_mcc_detect_connection(rtwdev, ref); if (mcc->mode != RTW89_MCC_MODE_GC_STA) diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h index 9a62b7c98b83..b1175419f92b 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.h +++ b/drivers/net/wireless/realtek/rtw89/chan.h @@ -23,6 +23,8 @@ #define RTW89_MCC_PROBE_TIMEOUT 100 #define RTW89_MCC_PROBE_MAX_TRIES 3 +#define RTW89_MCC_DETECT_BCN_MAX_TRIES 2 + #define RTW89_MCC_MIN_GO_DURATION \ (RTW89_MCC_EARLY_TX_BCN_TIME + RTW89_MCC_MIN_RX_BCN_TIME) @@ -94,6 +96,7 @@ struct rtw89_mr_chanctx_info { enum rtw89_chanctx_pause_reasons { RTW89_CHANCTX_PAUSE_REASON_HW_SCAN, RTW89_CHANCTX_PAUSE_REASON_ROC, + RTW89_CHANCTX_PAUSE_REASON_GC_BCN_LOSS, }; struct rtw89_chanctx_pause_parm { @@ -188,6 +191,9 @@ struct rtw89_mcc_links_info { void rtw89_mcc_get_links(struct rtw89_dev *rtwdev, struct rtw89_mcc_links_info *info); void rtw89_mcc_prepare_done_work(struct wiphy *wiphy, struct wiphy_work *work); +void rtw89_mcc_gc_detect_beacon_work(struct wiphy *wiphy, struct wiphy_work *work); +bool rtw89_mcc_detect_go_bcn(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link); int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev, struct ieee80211_chanctx_conf *ctx); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 2faf0889f7df..2e5f129ff4f8 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3597,6 +3597,7 @@ struct rtw89_vif_link { u8 hit_rule; u8 last_noa_nr; u64 sync_bcn_tsf; + u64 last_sync_bcn_tsf; bool rand_tsf_done; bool trigger; bool lsig_txop; @@ -3620,6 +3621,8 @@ struct rtw89_vif_link { struct list_head general_pkt_list; struct rtw89_p2p_noa_setter p2p_noa; struct rtw89_ps_noa_once_handler noa_once; + struct wiphy_delayed_work mcc_gc_detect_beacon_work; + u8 detect_bcn_count; }; enum rtw89_lv1_rcvy_step { @@ -5778,6 +5781,7 @@ struct rtw89_mcc_role { bool is_2ghz; bool is_go; bool is_gc; + bool ignore_bcn; }; struct rtw89_mcc_bt_role { diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 37b113e3bd26..f6bbc796329c 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -5088,6 +5088,7 @@ rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_l const struct rtw89_c2h_mac_bcnfltr_rpt *c2h = (const struct rtw89_c2h_mac_bcnfltr_rpt *)skb->data; u8 type, event, mac_id; + bool start_detect; s8 sig; type = le32_get_bits(c2h->w2, RTW89_C2H_MAC_BCNFLTR_RPT_W2_TYPE); @@ -5105,10 +5106,15 @@ rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_l switch (type) { case RTW89_BCN_FLTR_BEACON_LOSS: if (!rtwdev->scanning && !rtwvif->offchan && - !rtwvif_link->noa_once.in_duration) + !rtwvif_link->noa_once.in_duration) { + start_detect = rtw89_mcc_detect_go_bcn(rtwdev, rtwvif_link); + if (start_detect) + return; + ieee80211_connection_loss(vif); - else + } else { rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true); + } return; case RTW89_BCN_FLTR_NOTIFY: nl_event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index c982ad633b4a..c1ca6d741b32 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -113,6 +113,8 @@ static int __rtw89_ops_add_iface_link(struct rtw89_dev *rtwdev, wiphy_work_init(&rtwvif_link->update_beacon_work, rtw89_core_update_beacon_work); wiphy_delayed_work_init(&rtwvif_link->csa_beacon_work, rtw89_core_csa_beacon_work); + wiphy_delayed_work_init(&rtwvif_link->mcc_gc_detect_beacon_work, + rtw89_mcc_gc_detect_beacon_work); INIT_LIST_HEAD(&rtwvif_link->general_pkt_list); @@ -124,6 +126,7 @@ static int __rtw89_ops_add_iface_link(struct rtw89_dev *rtwdev, rtwvif_link->chanctx_idx = RTW89_CHANCTX_0; rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; rtwvif_link->rand_tsf_done = false; + rtwvif_link->detect_bcn_count = 0; rcu_read_lock(); @@ -147,6 +150,8 @@ static void __rtw89_ops_remove_iface_link(struct rtw89_dev *rtwdev, wiphy_work_cancel(rtwdev->hw->wiphy, &rtwvif_link->update_beacon_work); wiphy_delayed_work_cancel(rtwdev->hw->wiphy, &rtwvif_link->csa_beacon_work); + wiphy_delayed_work_cancel(rtwdev->hw->wiphy, + &rtwvif_link->mcc_gc_detect_beacon_work); rtw89_p2p_noa_once_deinit(rtwvif_link); From 65093fab65cb79d6ae6abaefc5ebe0427cbd1c5a Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 10 Jul 2025 12:24:16 +0800 Subject: [PATCH 100/199] wifi: rtw89: check LPS H2C command complete by C2H reg instead of done ack 8852B after FW 0.29.127, 8852BT after FW 0.29.127 and 8922A after FW 0.35.76 driver check LPS H2C command received by FW using C2H reg instead of done ack. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/fw.c | 11 ++++++++- drivers/net/wireless/realtek/rtw89/fw.h | 4 ++++ drivers/net/wireless/realtek/rtw89/ps.c | 28 ++++++++++++++++++++++- 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 2e5f129ff4f8..7afb84ea0e26 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4608,6 +4608,7 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_BEACON_LOSS_COUNT_V1, RTW89_FW_FEATURE_SCAN_OFFLOAD_EXTRA_OP, RTW89_FW_FEATURE_RFK_NTFY_MCC_V0, + RTW89_FW_FEATURE_LPS_DACK_BY_C2H_REG, }; struct rtw89_fw_suit { diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 20b7b4b15450..8157774b2bb1 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -827,11 +827,13 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 7, BEACON_FILTER), __CFG_FW_FEAT(RTL8852B, lt, 0, 29, 30, 0, NO_WOW_CPU_IO_RX), + __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, NO_LPS_PG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, TX_WAKE), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 90, 0, CRASH_TRIGGER), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 91, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 110, 0, BEACON_FILTER), + __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8852C, le, 0, 27, 33, 0, NO_DEEP_PS), __CFG_FW_FEAT(RTL8852C, ge, 0, 0, 0, 0, RFK_NTFY_MCC_V0), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 34, 0, TX_WAKE), @@ -856,6 +858,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 51, 0, NO_PHYCAP_P1), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 64, 0, NO_POWER_DIFFERENCE), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 71, 0, BEACON_LOSS_COUNT_V1), + __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 76, 0, LPS_DACK_BY_C2H_REG), }; static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw, @@ -2824,8 +2827,14 @@ int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, struct rtw89_lps_parm *lps_param) { struct sk_buff *skb; + bool done_ack; int ret; + if (RTW89_CHK_FW_FEATURE(LPS_DACK_BY_C2H_REG, &rtwdev->fw)) + done_ack = false; + else + done_ack = !lps_param->psmode; + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LPS_PARM_LEN); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); @@ -2847,7 +2856,7 @@ int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_PS, - H2C_FUNC_MAC_LPS_PARM, 0, !lps_param->psmode, + H2C_FUNC_MAC_LPS_PARM, 0, done_ack, H2C_LPS_PARM_LEN); ret = rtw89_h2c_tx(rtwdev, skb, false); diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 479a9f980b7f..629e54adcb83 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -87,6 +87,9 @@ struct rtw89_c2hreg_phycap { #define RTW89_C2HREG_AOAC_RPT_2_W3_IGTK_IPN_IV_6 GENMASK(7, 0) #define RTW89_C2HREG_AOAC_RPT_2_W3_IGTK_IPN_IV_7 GENMASK(15, 8) +#define RTW89_C2HREG_PS_LEAVE_ACK_RET GENMASK(7, 0) +#define RTW89_C2HREG_PS_LEAVE_ACK_MACID GENMASK(31, 16) + struct rtw89_h2creg_hdr { u32 w0; }; @@ -154,6 +157,7 @@ enum rtw89_mac_c2h_type { RTW89_FWCMD_C2HREG_FUNC_TX_PAUSE_RPT, RTW89_FWCMD_C2HREG_FUNC_WOW_CPUIO_RX_ACK = 0xA, RTW89_FWCMD_C2HREG_FUNC_PHY_CAP_PART1 = 0xC, + RTW89_FWCMD_C2HREG_FUNC_PS_LEAVE_ACK = 0xD, RTW89_FWCMD_C2HREG_FUNC_NULL = 0xFF, }; diff --git a/drivers/net/wireless/realtek/rtw89/ps.c b/drivers/net/wireless/realtek/rtw89/ps.c index 3411d642c84a..652f8fc81b79 100644 --- a/drivers/net/wireless/realtek/rtw89/ps.c +++ b/drivers/net/wireless/realtek/rtw89/ps.c @@ -13,6 +13,31 @@ #include "reg.h" #include "util.h" +static int rtw89_fw_receive_lps_h2c_check(struct rtw89_dev *rtwdev, u8 macid) +{ + struct rtw89_mac_c2h_info c2h_info = {}; + u16 c2hreg_macid; + u32 c2hreg_ret; + int ret; + + if (!RTW89_CHK_FW_FEATURE(LPS_DACK_BY_C2H_REG, &rtwdev->fw)) + return 0; + + c2h_info.id = RTW89_FWCMD_C2HREG_FUNC_PS_LEAVE_ACK; + ret = rtw89_fw_msg_reg(rtwdev, NULL, &c2h_info); + if (ret) + return ret; + + c2hreg_macid = u32_get_bits(c2h_info.u.c2hreg[0], + RTW89_C2HREG_PS_LEAVE_ACK_MACID); + c2hreg_ret = u32_get_bits(c2h_info.u.c2hreg[1], RTW89_C2HREG_PS_LEAVE_ACK_RET); + + if (macid != c2hreg_macid || c2hreg_ret) + rtw89_warn(rtwdev, "rtw89: check lps h2c received by firmware fail\n"); + + return 0; +} + static int rtw89_fw_leave_lps_check(struct rtw89_dev *rtwdev, u8 macid) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; @@ -106,7 +131,8 @@ static void __rtw89_leave_lps(struct rtw89_dev *rtwdev, }; rtw89_fw_h2c_lps_parm(rtwdev, &lps_param); - rtw89_fw_leave_lps_check(rtwdev, 0); + rtw89_fw_receive_lps_h2c_check(rtwdev, rtwvif_link->mac_id); + rtw89_fw_leave_lps_check(rtwdev, rtwvif_link->mac_id); rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_ON); rtw89_chip_digital_pwr_comp(rtwdev, rtwvif_link->phy_idx); } From 5693bdd58de48bc91831d8d2e60f78595205c6eb Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Thu, 10 Jul 2025 12:24:17 +0800 Subject: [PATCH 101/199] wifi: rtw89: introduce fw feature group and redefine CRASH_TRIGGER Some FW features may have variants on how to deal with in leaf functions, e.g. H2C commands. However, from SW component point of view, it might not matter which variant is supported exactly. In some cases, SW component may just care whether any of the variants is supported or not. So, introduce a concept of FW feature group which can manage a set of FW features and can easily be checked if at least one of them is supported. Since CRASH_TRIGGER will have variants and then matches the case mentioned above, so redefine CRASH_TRIGGER as a FW feature group and add a variant of type 0 for original handling. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-9-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 15 ++++++++++++++- drivers/net/wireless/realtek/rtw89/debug.c | 2 +- drivers/net/wireless/realtek/rtw89/fw.c | 12 ++++++------ 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 7afb84ea0e26..7bc473411190 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4583,11 +4583,20 @@ enum rtw89_fw_type { RTW89_FW_LOGFMT = 255, }; +#define RTW89_FW_FEATURE_GROUP(_grp, _features...) \ + RTW89_FW_FEATURE_##_grp##_MIN, \ + __RTW89_FW_FEATURE_##_grp##_S = RTW89_FW_FEATURE_##_grp##_MIN - 1, \ + _features \ + __RTW89_FW_FEATURE_##_grp##_E, \ + RTW89_FW_FEATURE_##_grp##_MAX = __RTW89_FW_FEATURE_##_grp##_E - 1 + enum rtw89_fw_feature { RTW89_FW_FEATURE_OLD_HT_RA_FORMAT, RTW89_FW_FEATURE_SCAN_OFFLOAD, RTW89_FW_FEATURE_TX_WAKE, - RTW89_FW_FEATURE_CRASH_TRIGGER, + RTW89_FW_FEATURE_GROUP(CRASH_TRIGGER, + RTW89_FW_FEATURE_CRASH_TRIGGER_TYPE_0, + ), RTW89_FW_FEATURE_NO_PACKET_DROP, RTW89_FW_FEATURE_NO_DEEP_PS, RTW89_FW_FEATURE_NO_LPS_PG, @@ -4706,6 +4715,10 @@ struct rtw89_fw_info { #define RTW89_CHK_FW_FEATURE(_feat, _fw) \ (!!((_fw)->feature_map & BIT(RTW89_FW_FEATURE_ ## _feat))) +#define RTW89_CHK_FW_FEATURE_GROUP(_grp, _fw) \ + (!!((_fw)->feature_map & GENMASK(RTW89_FW_FEATURE_ ## _grp ## _MAX, \ + RTW89_FW_FEATURE_ ## _grp ## _MIN))) + #define RTW89_SET_FW_FEATURE(_fw_feature, _fw) \ ((_fw)->feature_map |= BIT(_fw_feature)) diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index 4acb567b3ad4..afdfb9647fc1 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -3596,7 +3596,7 @@ rtw89_debug_priv_fw_crash_set(struct rtw89_dev *rtwdev, switch (crash_type) { case RTW89_DBG_SIM_CPU_EXCEPTION: - if (!RTW89_CHK_FW_FEATURE(CRASH_TRIGGER, &rtwdev->fw)) + if (!RTW89_CHK_FW_FEATURE_GROUP(CRASH_TRIGGER, &rtwdev->fw)) return -EOPNOTSUPP; sim = rtw89_fw_h2c_trigger_cpu_exception; break; diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 8157774b2bb1..fca79212e34f 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -814,23 +814,23 @@ struct __fw_feat_cfg { static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, TX_WAKE), __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, SCAN_OFFLOAD), - __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 41, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 41, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852A, le, 0, 13, 29, 0, OLD_HT_RA_FORMAT), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, TX_WAKE), - __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 36, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 36, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852A, lt, 0, 13, 37, 0, NO_WOW_CPU_IO_RX), __CFG_FW_FEAT(RTL8852A, lt, 0, 13, 38, 0, NO_PACKET_DROP), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 26, 0, NO_LPS_PG), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 26, 0, TX_WAKE), - __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 7, BEACON_FILTER), __CFG_FW_FEAT(RTL8852B, lt, 0, 29, 30, 0, NO_WOW_CPU_IO_RX), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, NO_LPS_PG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, TX_WAKE), - __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 90, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 90, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 91, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 110, 0, BEACON_FILTER), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), @@ -838,11 +838,11 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852C, ge, 0, 0, 0, 0, RFK_NTFY_MCC_V0), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 34, 0, TX_WAKE), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 36, 0, SCAN_OFFLOAD), - __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 40, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 40, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 56, 10, BEACON_FILTER), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 80, 0, WOW_REASON_V1), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 128, 0, BEACON_LOSS_COUNT_V1), - __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 11, 0, MACID_PAUSE_SLEEP), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 35, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 21, 0, SCAN_OFFLOAD_BE_V0), From e044f5d40f49bfd4beab517e7fe2988d3d8ce66d Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 10 Jul 2025 12:24:18 +0800 Subject: [PATCH 102/199] wifi: rtw89: update SER L2 type default value 8852BT after FW 0.29.127, 8852B after FW 0.29.128 and 8922A after FW 0.35.79, the SER L2 flow determines different L2 types by parameter, the zero value will trigger FW SER L2 assert. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-10-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/fw.c | 36 +++++++++++++++-------- drivers/net/wireless/realtek/rtw89/fw.h | 9 +++--- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 7bc473411190..59ec81adac7e 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4596,6 +4596,7 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_TX_WAKE, RTW89_FW_FEATURE_GROUP(CRASH_TRIGGER, RTW89_FW_FEATURE_CRASH_TRIGGER_TYPE_0, + RTW89_FW_FEATURE_CRASH_TRIGGER_TYPE_1, ), RTW89_FW_FEATURE_NO_PACKET_DROP, RTW89_FW_FEATURE_NO_DEEP_PS, diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index fca79212e34f..6b94445577fd 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -828,12 +828,14 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 7, BEACON_FILTER), __CFG_FW_FEAT(RTL8852B, lt, 0, 29, 30, 0, NO_WOW_CPU_IO_RX), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), + __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 128, 0, CRASH_TRIGGER_TYPE_1), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, NO_LPS_PG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, TX_WAKE), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 90, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 91, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 110, 0, BEACON_FILTER), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), + __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, CRASH_TRIGGER_TYPE_1), __CFG_FW_FEAT(RTL8852C, le, 0, 27, 33, 0, NO_DEEP_PS), __CFG_FW_FEAT(RTL8852C, ge, 0, 0, 0, 0, RFK_NTFY_MCC_V0), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 34, 0, TX_WAKE), @@ -859,6 +861,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 64, 0, NO_POWER_DIFFERENCE), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 71, 0, BEACON_LOSS_COUNT_V1), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 76, 0, LPS_DACK_BY_C2H_REG), + __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 79, 0, CRASH_TRIGGER_TYPE_1), }; static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw, @@ -8009,41 +8012,50 @@ out: return ret; } -#define H2C_FW_CPU_EXCEPTION_LEN 4 -#define H2C_FW_CPU_EXCEPTION_TYPE_DEF 0x5566 +#define H2C_FW_CPU_EXCEPTION_TYPE_0 0x5566 +#define H2C_FW_CPU_EXCEPTION_TYPE_1 0x0 int rtw89_fw_h2c_trigger_cpu_exception(struct rtw89_dev *rtwdev) { + struct rtw89_h2c_trig_cpu_except *h2c; + u32 cpu_exception_type_def; + u32 len = sizeof(*h2c); struct sk_buff *skb; int ret; - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_FW_CPU_EXCEPTION_LEN); + if (RTW89_CHK_FW_FEATURE(CRASH_TRIGGER_TYPE_1, &rtwdev->fw)) + cpu_exception_type_def = H2C_FW_CPU_EXCEPTION_TYPE_1; + else if (RTW89_CHK_FW_FEATURE(CRASH_TRIGGER_TYPE_0, &rtwdev->fw)) + cpu_exception_type_def = H2C_FW_CPU_EXCEPTION_TYPE_0; + else + return -EOPNOTSUPP; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for fw cpu exception\n"); return -ENOMEM; } - skb_put(skb, H2C_FW_CPU_EXCEPTION_LEN); - RTW89_SET_FWCMD_CPU_EXCEPTION_TYPE(skb->data, - H2C_FW_CPU_EXCEPTION_TYPE_DEF); + skb_put(skb, len); + h2c = (struct rtw89_h2c_trig_cpu_except *)skb->data; + + h2c->w0 = le32_encode_bits(cpu_exception_type_def, + RTW89_H2C_CPU_EXCEPTION_TYPE); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_TEST, H2C_CL_FW_STATUS_TEST, H2C_FUNC_CPU_EXCEPTION, 0, 0, - H2C_FW_CPU_EXCEPTION_LEN); + len); ret = rtw89_h2c_tx(rtwdev, skb, false); if (ret) { rtw89_err(rtwdev, "failed to send h2c\n"); - goto fail; + dev_kfree_skb_any(skb); + return ret; } return 0; - -fail: - dev_kfree_skb_any(skb); - return ret; } #define H2C_PKT_DROP_LEN 24 diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 629e54adcb83..98be7e72c685 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -1833,10 +1833,11 @@ struct rtw89_h2c_lps_ml_cmn_info { u8 dup_bcn_ofst[RTW89_PHY_NUM]; } __packed; -static inline void RTW89_SET_FWCMD_CPU_EXCEPTION_TYPE(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)cmd, val, GENMASK(31, 0)); -} +struct rtw89_h2c_trig_cpu_except { + __le32 w0; +} __packed; + +#define RTW89_H2C_CPU_EXCEPTION_TYPE GENMASK(31, 0) static inline void RTW89_SET_FWCMD_PKT_DROP_SEL(void *cmd, u32 val) { From 094bb62c580dc6608736c6df4d4f238386050bf4 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 10 Jul 2025 12:24:19 +0800 Subject: [PATCH 103/199] wifi: rtw89: tweak tx wake notify matching condition 8852BT needs to call TX wake notify once entering Leisure Power Save. 8852C needs to call TX wake notify after entering low power mode. Other AX chips only MGMT packets needs to call TX wake after entering low power mode. BE chips no need to call TX wake. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-11-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index da82a88cce98..57590f5577a3 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -994,13 +994,25 @@ rtw89_core_tx_wake(struct rtw89_dev *rtwdev, if (!RTW89_CHK_FW_FEATURE(TX_WAKE, &rtwdev->fw)) return; - if (!test_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags)) - return; + switch (chip->chip_id) { + case RTL8852BT: + if (test_bit(RTW89_FLAG_LEISURE_PS, rtwdev->flags)) + goto notify; + break; + case RTL8852C: + if (test_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags)) + goto notify; + break; + default: + if (test_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags) && + tx_req->tx_type == RTW89_CORE_TX_TYPE_MGMT) + goto notify; + break; + } - if (chip->chip_id != RTL8852C && - tx_req->tx_type != RTW89_CORE_TX_TYPE_MGMT) - return; + return; +notify: rtw89_mac_notify_wake(rtwdev); } From 868676662b08f43cd26a2bc3492d6a7fa1eb3414 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Thu, 10 Jul 2025 12:24:20 +0800 Subject: [PATCH 104/199] wifi: rtw89: 8852bt: configure FW version for SCAN_OFFLOAD_EXTRA_OP feature After v0.29.127.0, RTL8852BT FW supports SCAN_OFFLOAD_EXTRA_OP feature. With it, FW can do back-op and TX NULL frames on the second connection. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-12-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 6b94445577fd..0b0d1fd7b02b 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -834,6 +834,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 90, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 91, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 110, 0, BEACON_FILTER), + __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, SCAN_OFFLOAD_EXTRA_OP), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, CRASH_TRIGGER_TYPE_1), __CFG_FW_FEAT(RTL8852C, le, 0, 27, 33, 0, NO_DEEP_PS), From 21911ad80512f9e4e642b9e8ecd7130e32cb63d3 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Thu, 10 Jul 2025 12:24:21 +0800 Subject: [PATCH 105/199] wifi: rtw89: 8852bt: implement RFK multi-channel handling and support chanctx up to 2 To support multiple channels, 2 for this case, RFK requires to record each calibration result for each channel in different RFK tables, and also needs to notify FW. Then, when FW runs in MCC (multi-channel concurrency), it can switch to the corresponding calibration result according to the channel. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-13-pkshih@realtek.com --- .../net/wireless/realtek/rtw89/rtw8852bt.c | 12 +++- .../wireless/realtek/rtw89/rtw8852bt_rfk.c | 69 ++++++++++++++----- .../wireless/realtek/rtw89/rtw8852bt_rfk.h | 3 + 3 files changed, 65 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c index 10d09c12f318..06a06c190553 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c @@ -533,8 +533,11 @@ static void rtw8852bt_set_channel_help(struct rtw89_dev *rtwdev, bool enter, static void rtw8852bt_rfk_init(struct rtw89_dev *rtwdev) { + struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + rtwdev->is_tssi_mode[RF_PATH_A] = false; rtwdev->is_tssi_mode[RF_PATH_B] = false; + memset(rfk_mcc, 0, sizeof(*rfk_mcc)); rtw8852bt_dpk_init(rtwdev); rtw8852bt_rck(rtwdev); @@ -548,6 +551,7 @@ static void rtw8852bt_rfk_channel(struct rtw89_dev *rtwdev, enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx; enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx; + rtw8852bt_mcc_get_ch_info(rtwdev, phy_idx); rtw89_btc_ntfy_conn_rfk(rtwdev, true); rtw8852bt_rx_dck(rtwdev, phy_idx, chanctx_idx); @@ -558,6 +562,7 @@ static void rtw8852bt_rfk_channel(struct rtw89_dev *rtwdev, rtw8852bt_dpk(rtwdev, phy_idx, chanctx_idx); rtw89_btc_ntfy_conn_rfk(rtwdev, false); + rtw89_fw_h2c_rf_ntfy_mcc(rtwdev); } static void rtw8852bt_rfk_band_changed(struct rtw89_dev *rtwdev, @@ -727,6 +732,10 @@ static const struct rtw89_chip_ops rtw8852bt_chip_ops = { .btc_set_policy = rtw89_btc_set_policy_v1, }; +static const struct rtw89_chanctx_listener rtw8852bt_chanctx_listener = { + .callbacks[RTW89_CHANCTX_CALLBACK_RFK] = rtw8852bt_rfk_chanctx_cb, +}; + #ifdef CONFIG_PM static const struct wiphy_wowlan_support rtw_wowlan_stub_8852bt = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, @@ -769,6 +778,7 @@ const struct rtw89_chip_info rtw8852bt_chip_info = { .nctl_post_table = NULL, .dflt_parms = NULL, .rfe_parms_conf = NULL, + .chanctx_listener = &rtw8852bt_chanctx_listener, .txpwr_factor_bb = 3, .txpwr_factor_rf = 2, .txpwr_factor_mac = 1, @@ -777,7 +787,7 @@ const struct rtw89_chip_info rtw8852bt_chip_info = { .tssi_dbw_table = NULL, .support_macid_num = RTW89_MAX_MAC_ID_NUM, .support_link_num = 0, - .support_chanctx_num = 1, + .support_chanctx_num = 2, .support_rnr = false, .support_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c index 6e6889eea9a0..d0e299803225 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c @@ -2,6 +2,7 @@ /* Copyright(c) 2024 Realtek Corporation */ +#include "chan.h" #include "coex.h" #include "debug.h" #include "fw.h" @@ -1529,26 +1530,11 @@ static void _iqk_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, u enum rtw89_chanctx_idx chanctx_idx) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, chanctx_idx); + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; - u8 get_empty_table = false; + u8 idx = rfk_mcc->table_idx; u32 reg_rf18; u32 reg_35c; - u8 idx; - - for (idx = 0; idx < RTW89_IQK_CHS_NR; idx++) { - if (iqk_info->iqk_mcc_ch[idx][path] == 0) { - get_empty_table = true; - break; - } - } - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] (1)idx = %x\n", idx); - - if (!get_empty_table) { - idx = iqk_info->iqk_table_idx[path] + 1; - if (idx > 1) - idx = 0; - } - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] (2)idx = %x\n", idx); reg_rf18 = rtw89_read_rf(rtwdev, path, RR_CFGCH, RFREG_MASK); reg_35c = rtw89_phy_read32_mask(rtwdev, R_CIRST, B_CIRST_SYN); @@ -1640,7 +1626,8 @@ static void _iqk_afebb_restore(struct rtw89_dev *rtwdev, static void _iqk_preset(struct rtw89_dev *rtwdev, u8 path) { - u8 idx = 0; + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; + u8 idx = rfk_mcc->table_idx; rtw89_phy_write32_mask(rtwdev, R_COEF_SEL + (path << 8), 0x00000001, idx); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), 0x00000008, idx); @@ -4252,3 +4239,49 @@ void rtw8852bt_set_channel_rf(struct rtw89_dev *rtwdev, rtw8852bt_ctrl_bw_ch(rtwdev, phy_idx, chan->channel, chan->band_type, chan->band_width); } + +void rtw8852bt_mcc_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + const struct rtw89_chan *chan = rtw89_mgnt_chan_get(rtwdev, 0); + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; + struct rtw89_rfk_chan_desc desc[__RTW89_RFK_CHS_NR_V0] = {}; + u8 idx; + + for (idx = 0; idx < ARRAY_SIZE(desc); idx++) { + struct rtw89_rfk_chan_desc *p = &desc[idx]; + + p->ch = rfk_mcc->ch[idx]; + + p->has_band = true; + p->band = rfk_mcc->band[idx]; + } + + idx = rtw89_rfk_chan_lookup(rtwdev, desc, ARRAY_SIZE(desc), chan); + + rfk_mcc->ch[idx] = chan->channel; + rfk_mcc->band[idx] = chan->band_type; + rfk_mcc->table_idx = idx; +} + +void rtw8852bt_rfk_chanctx_cb(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_state state) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + u8 path; + + switch (state) { + case RTW89_CHANCTX_STATE_MCC_START: + dpk->is_dpk_enable = false; + for (path = 0; path < RTW8852BT_SS; path++) + _dpk_onoff(rtwdev, path, false); + break; + case RTW89_CHANCTX_STATE_MCC_STOP: + dpk->is_dpk_enable = true; + for (path = 0; path < RTW8852BT_SS; path++) + _dpk_onoff(rtwdev, path, false); + rtw8852bt_dpk(rtwdev, RTW89_PHY_0, RTW89_CHANCTX_0); + break; + default: + break; + } +} diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h index e34560b4905f..a663bbda4075 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h @@ -27,5 +27,8 @@ void rtw8852bt_wifi_scan_notify(struct rtw89_dev *rtwdev, bool scan_start, void rtw8852bt_set_channel_rf(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx); +void rtw8852bt_mcc_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +void rtw8852bt_rfk_chanctx_cb(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_state state); #endif From 504937dbaddb2149d5031e924100e285d7325eef Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Thu, 10 Jul 2025 12:24:22 +0800 Subject: [PATCH 106/199] wifi: rtw89: 8852b: configure FW version for SCAN_OFFLOAD_EXTRA_OP feature After v0.29.128.0, RTL8852B FW supports SCAN_OFFLOAD_EXTRA_OP feature. With it, FW can do back-op and TX NULL frames on the second connection. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-14-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 0b0d1fd7b02b..73a4ec988d16 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -829,6 +829,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852B, lt, 0, 29, 30, 0, NO_WOW_CPU_IO_RX), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 128, 0, CRASH_TRIGGER_TYPE_1), + __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 128, 0, SCAN_OFFLOAD_EXTRA_OP), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, NO_LPS_PG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, TX_WAKE), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 90, 0, CRASH_TRIGGER_TYPE_0), From cefcf74ae02623a80acffe5f662ed6523575ed46 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Thu, 10 Jul 2025 12:24:23 +0800 Subject: [PATCH 107/199] wifi: rtw89: 8852b: implement RFK multi-channel handling and support chanctx up to 2 To support multiple channels, 2 for this case, RFK requires to record each calibration result for each channel in different RFK tables, and also needs to notify FW. Then, when FW runs in MCC (multi-channel concurrency), it can switch to the corresponding calibration result according to the channel. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-15-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 12 ++- .../net/wireless/realtek/rtw89/rtw8852b_rfk.c | 77 +++++++++++++------ .../net/wireless/realtek/rtw89/rtw8852b_rfk.h | 3 + 3 files changed, 68 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 33ab71d84ffc..389dfac26028 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -628,8 +628,11 @@ static void rtw8852b_set_channel_help(struct rtw89_dev *rtwdev, bool enter, static void rtw8852b_rfk_init(struct rtw89_dev *rtwdev) { + struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + rtwdev->is_tssi_mode[RF_PATH_A] = false; rtwdev->is_tssi_mode[RF_PATH_B] = false; + memset(rfk_mcc, 0, sizeof(*rfk_mcc)); rtw8852b_dpk_init(rtwdev); rtw8852b_rck(rtwdev); @@ -643,6 +646,7 @@ static void rtw8852b_rfk_channel(struct rtw89_dev *rtwdev, enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx; enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx; + rtw8852b_mcc_get_ch_info(rtwdev, phy_idx); rtw89_btc_ntfy_conn_rfk(rtwdev, true); rtw8852b_rx_dck(rtwdev, phy_idx, chanctx_idx); @@ -653,6 +657,7 @@ static void rtw8852b_rfk_channel(struct rtw89_dev *rtwdev, rtw8852b_dpk(rtwdev, phy_idx, chanctx_idx); rtw89_btc_ntfy_conn_rfk(rtwdev, false); + rtw89_fw_h2c_rf_ntfy_mcc(rtwdev); } static void rtw8852b_rfk_band_changed(struct rtw89_dev *rtwdev, @@ -861,6 +866,10 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .btc_set_policy = rtw89_btc_set_policy_v1, }; +static const struct rtw89_chanctx_listener rtw8852b_chanctx_listener = { + .callbacks[RTW89_CHANCTX_CALLBACK_RFK] = rtw8852b_rfk_chanctx_cb, +}; + #ifdef CONFIG_PM static const struct wiphy_wowlan_support rtw_wowlan_stub_8852b = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, @@ -909,6 +918,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .nctl_post_table = NULL, .dflt_parms = &rtw89_8852b_dflt_parms, .rfe_parms_conf = NULL, + .chanctx_listener = &rtw8852b_chanctx_listener, .txpwr_factor_bb = 3, .txpwr_factor_rf = 2, .txpwr_factor_mac = 1, @@ -917,7 +927,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .tssi_dbw_table = NULL, .support_macid_num = RTW89_MAX_MAC_ID_NUM, .support_link_num = 0, - .support_chanctx_num = 0, + .support_chanctx_num = 2, .support_rnr = false, .support_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c index fbf82d42687b..4796588c0256 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c @@ -2,6 +2,7 @@ /* Copyright(c) 2019-2022 Realtek Corporation */ +#include "chan.h" #include "coex.h" #include "debug.h" #include "mac.h" @@ -1145,19 +1146,19 @@ static void _lok_res_table(struct rtw89_dev *rtwdev, u8 path, u8 ibias) static bool _lok_finetune_check(struct rtw89_dev *rtwdev, u8 path) { + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + u8 ch = rfk_mcc->table_idx; bool is_fail1, is_fail2; u32 vbuff_i; u32 vbuff_q; u32 core_i; u32 core_q; u32 tmp; - u8 ch; tmp = rtw89_read_rf(rtwdev, path, RR_TXMO, RFREG_MASK); core_i = FIELD_GET(RR_TXMO_COI, tmp); core_q = FIELD_GET(RR_TXMO_COQ, tmp); - ch = (iqk_info->iqk_times / 2) % RTW89_IQK_CHS_NR; if (core_i < 0x2 || core_i > 0x1d || core_q < 0x2 || core_q > 0x1d) is_fail1 = true; @@ -1386,26 +1387,11 @@ static void _iqk_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, u enum rtw89_chanctx_idx chanctx_idx) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, chanctx_idx); + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + u8 idx = rfk_mcc->table_idx; u32 reg_rf18; u32 reg_35c; - u8 idx; - u8 get_empty_table = false; - - for (idx = 0; idx < RTW89_IQK_CHS_NR; idx++) { - if (iqk_info->iqk_mcc_ch[idx][path] == 0) { - get_empty_table = true; - break; - } - } - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] (1)idx = %x\n", idx); - - if (!get_empty_table) { - idx = iqk_info->iqk_table_idx[path] + 1; - if (idx > 1) - idx = 0; - } - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] (2)idx = %x\n", idx); reg_rf18 = rtw89_read_rf(rtwdev, path, RR_CFGCH, RFREG_MASK); reg_35c = rtw89_phy_read32_mask(rtwdev, R_CIRST, B_CIRST_SYN); @@ -1506,11 +1492,10 @@ static void _iqk_afebb_restore(struct rtw89_dev *rtwdev, static void _iqk_preset(struct rtw89_dev *rtwdev, u8 path) { - struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; - u8 idx; + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; + u8 idx = rfk_mcc->table_idx; - idx = iqk_info->iqk_table_idx[path]; - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] (3)idx = %x\n", idx); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] idx = %x\n", idx); rtw89_phy_write32_mask(rtwdev, R_COEF_SEL + (path << 8), B_COEF_SEL_IQC, idx); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), B_CFIR_LUT_G3, idx); @@ -4179,3 +4164,49 @@ void rtw8852b_set_channel_rf(struct rtw89_dev *rtwdev, rtw8852b_ctrl_bw_ch(rtwdev, phy_idx, chan->channel, chan->band_type, chan->band_width); } + +void rtw8852b_mcc_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + const struct rtw89_chan *chan = rtw89_mgnt_chan_get(rtwdev, 0); + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; + struct rtw89_rfk_chan_desc desc[__RTW89_RFK_CHS_NR_V0] = {}; + u8 idx; + + for (idx = 0; idx < ARRAY_SIZE(desc); idx++) { + struct rtw89_rfk_chan_desc *p = &desc[idx]; + + p->ch = rfk_mcc->ch[idx]; + + p->has_band = true; + p->band = rfk_mcc->band[idx]; + } + + idx = rtw89_rfk_chan_lookup(rtwdev, desc, ARRAY_SIZE(desc), chan); + + rfk_mcc->ch[idx] = chan->channel; + rfk_mcc->band[idx] = chan->band_type; + rfk_mcc->table_idx = idx; +} + +void rtw8852b_rfk_chanctx_cb(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_state state) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + u8 path; + + switch (state) { + case RTW89_CHANCTX_STATE_MCC_START: + dpk->is_dpk_enable = false; + for (path = 0; path < RTW8852B_DPK_RF_PATH; path++) + _dpk_onoff(rtwdev, path, false); + break; + case RTW89_CHANCTX_STATE_MCC_STOP: + dpk->is_dpk_enable = true; + for (path = 0; path < RTW8852B_DPK_RF_PATH; path++) + _dpk_onoff(rtwdev, path, false); + rtw8852b_dpk(rtwdev, RTW89_PHY_0, RTW89_CHANCTX_0); + break; + default: + break; + } +} diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.h index c31ba446e6e0..5fae980d5e2c 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.h @@ -27,5 +27,8 @@ void rtw8852b_wifi_scan_notify(struct rtw89_dev *rtwdev, bool scan_start, void rtw8852b_set_channel_rf(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx); +void rtw8852b_mcc_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +void rtw8852b_rfk_chanctx_cb(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_state state); #endif From d76a1abcf57734d2bcd4a7ec051617edd4513d7f Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Wed, 9 Jul 2025 14:15:22 +0200 Subject: [PATCH 108/199] wifi: rtl8xxxu: Fix RX skb size for aggregation disabled Commit 1e5b3b3fe9e0 ("rtl8xxxu: Adjust RX skb size to include space for phystats") increased the skb size when aggregation is enabled but decreased it for the aggregation disabled case. As a result, if a frame near the maximum size is received, rtl8xxxu_rx_complete() is called with status -EOVERFLOW and then the driver starts to malfunction and no further communication is possible. Restore the skb size in the aggregation disabled case. Fixes: 1e5b3b3fe9e0 ("rtl8xxxu: Adjust RX skb size to include space for phystats") Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250709121522.1992366-1-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/core.c b/drivers/net/wireless/realtek/rtl8xxxu/core.c index 496836f716aa..f6f169d2062d 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/core.c @@ -6618,7 +6618,7 @@ static int rtl8xxxu_submit_rx_urb(struct rtl8xxxu_priv *priv, skb_size = fops->rx_agg_buf_size; skb_size += (rx_desc_sz + sizeof(struct rtl8723au_phy_stats)); } else { - skb_size = IEEE80211_MAX_FRAME_LEN; + skb_size = IEEE80211_MAX_FRAME_LEN + rx_desc_sz; } skb = __netdev_alloc_skb(NULL, skb_size, GFP_KERNEL); From 5f936768300f65d5856d6adf0f8591e2ae716727 Mon Sep 17 00:00:00 2001 From: Andrey Skvortsov Date: Fri, 11 Jul 2025 11:47:40 +0300 Subject: [PATCH 109/199] wifi: rtw88: enable TX reports for the management queue This is needed for AP mode. Otherwise client sees the network, but can't connect to it. REG_FWHW_TXQ_CTRL+1 is set to WLAN_TXQ_RPT_EN (0x1F) in common mac init function (__rtw8723x_mac_init), but the value was overwritten from mac table later. Tables with register values for phy parameters initialization are copied from vendor driver usually. When table will be regenerated, manual modifications to it may be lost. To avoid regressions in this case new callback mac_postinit is introduced, that is called after parameters from table are set. Tested on rtl8723cs, that reuses rtw8703b driver. Signed-off-by: Andrey Skvortsov Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250711084740.3396766-1-andrej.skvortzov@gmail.com --- drivers/net/wireless/realtek/rtw88/mac.c | 10 ++++++++++ drivers/net/wireless/realtek/rtw88/mac.h | 1 + drivers/net/wireless/realtek/rtw88/main.c | 6 ++++++ drivers/net/wireless/realtek/rtw88/main.h | 1 + drivers/net/wireless/realtek/rtw88/rtw8703b.c | 1 + drivers/net/wireless/realtek/rtw88/rtw8723d.c | 1 + drivers/net/wireless/realtek/rtw88/rtw8723x.c | 9 ++++++++- drivers/net/wireless/realtek/rtw88/rtw8723x.h | 6 ++++++ drivers/net/wireless/realtek/rtw88/rtw8812a.c | 1 + drivers/net/wireless/realtek/rtw88/rtw8814a.c | 1 + drivers/net/wireless/realtek/rtw88/rtw8821a.c | 1 + drivers/net/wireless/realtek/rtw88/rtw8821c.c | 1 + drivers/net/wireless/realtek/rtw88/rtw8822b.c | 1 + drivers/net/wireless/realtek/rtw88/rtw8822c.c | 1 + 14 files changed, 40 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c index 011b81c82f3b..eaa928bab240 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.c +++ b/drivers/net/wireless/realtek/rtw88/mac.c @@ -1409,3 +1409,13 @@ int rtw_mac_init(struct rtw_dev *rtwdev) return 0; } + +int rtw_mac_postinit(struct rtw_dev *rtwdev) +{ + const struct rtw_chip_info *chip = rtwdev->chip; + + if (!chip->ops->mac_postinit) + return 0; + + return chip->ops->mac_postinit(rtwdev); +} diff --git a/drivers/net/wireless/realtek/rtw88/mac.h b/drivers/net/wireless/realtek/rtw88/mac.h index e92b1483728d..b73af90ee1d7 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.h +++ b/drivers/net/wireless/realtek/rtw88/mac.h @@ -38,6 +38,7 @@ void rtw_write_firmware_page(struct rtw_dev *rtwdev, u32 page, const u8 *data, u32 size); int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw); int rtw_mac_init(struct rtw_dev *rtwdev); +int rtw_mac_postinit(struct rtw_dev *rtwdev); void rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop); int rtw_set_trx_fifo_info(struct rtw_dev *rtwdev); int rtw_ddma_to_fw_fifo(struct rtw_dev *rtwdev, u32 ocp_src, u32 size); diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 97756bdf57b2..b706c5a21a6c 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1412,6 +1412,12 @@ int rtw_power_on(struct rtw_dev *rtwdev) chip->ops->phy_set_param(rtwdev); + ret = rtw_mac_postinit(rtwdev); + if (ret) { + rtw_err(rtwdev, "failed to configure mac in postinit\n"); + goto err_off; + } + ret = rtw_hci_start(rtwdev); if (ret) { rtw_err(rtwdev, "failed to start hci\n"); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index b42538cce359..43ed6d6b4291 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -858,6 +858,7 @@ struct rtw_chip_ops { int (*power_on)(struct rtw_dev *rtwdev); void (*power_off)(struct rtw_dev *rtwdev); int (*mac_init)(struct rtw_dev *rtwdev); + int (*mac_postinit)(struct rtw_dev *rtwdev); int (*dump_fw_crash)(struct rtw_dev *rtwdev); void (*shutdown)(struct rtw_dev *rtwdev); int (*read_efuse)(struct rtw_dev *rtwdev, u8 *map); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8703b.c b/drivers/net/wireless/realtek/rtw88/rtw8703b.c index 03475af973b5..821c28d9cb5d 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8703b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8703b.c @@ -1832,6 +1832,7 @@ static const struct rtw_chip_ops rtw8703b_ops = { .power_on = rtw_power_on, .power_off = rtw_power_off, .mac_init = rtw8723x_mac_init, + .mac_postinit = rtw8723x_mac_postinit, .dump_fw_crash = NULL, .shutdown = NULL, .read_efuse = rtw8703b_read_efuse, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c index bf69f5b06ce2..8715e0435f17 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c @@ -1397,6 +1397,7 @@ static const struct rtw_chip_ops rtw8723d_ops = { .query_phy_status = query_phy_status, .set_channel = rtw8723d_set_channel, .mac_init = rtw8723x_mac_init, + .mac_postinit = rtw8723x_mac_postinit, .shutdown = rtw8723d_shutdown, .read_rf = rtw_phy_read_rf_sipi, .write_rf = rtw_phy_write_rf_reg_sipi, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723x.c b/drivers/net/wireless/realtek/rtw88/rtw8723x.c index 4c77963fdd37..3f3e9b0c44e8 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723x.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723x.c @@ -353,7 +353,6 @@ static int __rtw8723x_read_efuse(struct rtw_dev *rtwdev, u8 *log_map) static int __rtw8723x_mac_init(struct rtw_dev *rtwdev) { - rtw_write8(rtwdev, REG_FWHW_TXQ_CTRL + 1, WLAN_TXQ_RPT_EN); rtw_write32(rtwdev, REG_TCR, BIT_TCR_CFG); rtw_write16(rtwdev, REG_RXFLTMAP0, WLAN_RX_FILTER0); @@ -370,6 +369,13 @@ static int __rtw8723x_mac_init(struct rtw_dev *rtwdev) return 0; } +static int __rtw8723x_mac_postinit(struct rtw_dev *rtwdev) +{ + rtw_write8(rtwdev, REG_FWHW_TXQ_CTRL + 1, WLAN_TXQ_RPT_EN); + + return 0; +} + static void __rtw8723x_cfg_ldo25(struct rtw_dev *rtwdev, bool enable) { u8 ldo_pwr; @@ -760,6 +766,7 @@ const struct rtw8723x_common rtw8723x_common = { .lck = __rtw8723x_lck, .read_efuse = __rtw8723x_read_efuse, .mac_init = __rtw8723x_mac_init, + .mac_postinit = __rtw8723x_mac_postinit, .cfg_ldo25 = __rtw8723x_cfg_ldo25, .set_tx_power_index = __rtw8723x_set_tx_power_index, .efuse_grant = __rtw8723x_efuse_grant, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723x.h b/drivers/net/wireless/realtek/rtw88/rtw8723x.h index a99af527c92c..0fc70dfdfc8b 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723x.h +++ b/drivers/net/wireless/realtek/rtw88/rtw8723x.h @@ -137,6 +137,7 @@ struct rtw8723x_common { void (*lck)(struct rtw_dev *rtwdev); int (*read_efuse)(struct rtw_dev *rtwdev, u8 *log_map); int (*mac_init)(struct rtw_dev *rtwdev); + int (*mac_postinit)(struct rtw_dev *rtwdev); void (*cfg_ldo25)(struct rtw_dev *rtwdev, bool enable); void (*set_tx_power_index)(struct rtw_dev *rtwdev); void (*efuse_grant)(struct rtw_dev *rtwdev, bool on); @@ -383,6 +384,11 @@ static inline int rtw8723x_mac_init(struct rtw_dev *rtwdev) return rtw8723x_common.mac_init(rtwdev); } +static inline int rtw8723x_mac_postinit(struct rtw_dev *rtwdev) +{ + return rtw8723x_common.mac_postinit(rtwdev); +} + static inline void rtw8723x_cfg_ldo25(struct rtw_dev *rtwdev, bool enable) { rtw8723x_common.cfg_ldo25(rtwdev, enable); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c index 03b441639611..2078eb6e3628 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8812a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c @@ -919,6 +919,7 @@ static const struct rtw_chip_ops rtw8812a_ops = { .query_phy_status = rtw8812a_query_phy_status, .set_channel = rtw88xxa_set_channel, .mac_init = NULL, + .mac_postinit = NULL, .read_rf = rtw88xxa_phy_read_rf, .write_rf = rtw_phy_write_rf_reg_sipi, .set_antenna = NULL, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8814a.c b/drivers/net/wireless/realtek/rtw88/rtw8814a.c index 4a1f850d05c8..ca1079e12023 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8814a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8814a.c @@ -2055,6 +2055,7 @@ static const struct rtw_chip_ops rtw8814a_ops = { .query_phy_status = rtw8814a_query_phy_status, .set_channel = rtw8814a_set_channel, .mac_init = rtw8814a_mac_init, + .mac_postinit = NULL, .read_rf = rtw_phy_read_rf, .write_rf = rtw_phy_write_rf_reg_sipi, .set_tx_power_index = rtw8814a_set_tx_power_index, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.c b/drivers/net/wireless/realtek/rtw88/rtw8821a.c index 1d02ea400b2e..414b77eef07c 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.c @@ -865,6 +865,7 @@ static const struct rtw_chip_ops rtw8821a_ops = { .query_phy_status = rtw8821a_query_phy_status, .set_channel = rtw88xxa_set_channel, .mac_init = NULL, + .mac_postinit = NULL, .read_rf = rtw88xxa_phy_read_rf, .write_rf = rtw_phy_write_rf_reg_sipi, .set_antenna = NULL, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c index a2a358d6033f..2078b067562e 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c @@ -1663,6 +1663,7 @@ static const struct rtw_chip_ops rtw8821c_ops = { .query_phy_status = query_phy_status, .set_channel = rtw8821c_set_channel, .mac_init = rtw8821c_mac_init, + .mac_postinit = NULL, .read_rf = rtw_phy_read_rf, .write_rf = rtw_phy_write_rf_reg_sipi, .set_antenna = NULL, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index bb5c41905afe..89b6485b229a 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -2154,6 +2154,7 @@ static const struct rtw_chip_ops rtw8822b_ops = { .query_phy_status = query_phy_status, .set_channel = rtw8822b_set_channel, .mac_init = rtw8822b_mac_init, + .mac_postinit = NULL, .read_rf = rtw_phy_read_rf, .write_rf = rtw_phy_write_rf_reg_sipi, .set_tx_power_index = rtw8822b_set_tx_power_index, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 58c1958e6170..28c121cf1e68 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -4964,6 +4964,7 @@ static const struct rtw_chip_ops rtw8822c_ops = { .query_phy_status = query_phy_status, .set_channel = rtw8822c_set_channel, .mac_init = rtw8822c_mac_init, + .mac_postinit = NULL, .dump_fw_crash = rtw8822c_dump_fw_crash, .read_rf = rtw_phy_read_rf, .write_rf = rtw_phy_write_rf_reg_mix, From 526b000991b557c40ea53e64ba24bb9e0fff0071 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sun, 13 Jul 2025 22:27:32 +0300 Subject: [PATCH 110/199] wifi: rtw88: Fix macid assigned to TDLS station When working in station mode, TDLS peers are assigned macid 0, even though 0 was already assigned to the AP. This causes the connection with the AP to stop working after the TDLS connection is torn down. Assign the next available macid to TDLS peers, same as client stations in AP mode. Fixes: 902cb7b11f9a ("wifi: rtw88: assign mac_id for vif/sta and update to TX desc") Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/58648c09-8553-4bcc-a977-9dc9afd63780@gmail.com --- drivers/net/wireless/realtek/rtw88/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index b706c5a21a6c..fa0ed39cb199 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -349,7 +349,7 @@ int rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; int i; - if (vif->type == NL80211_IFTYPE_STATION) { + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { si->mac_id = rtwvif->mac_id; } else { si->mac_id = rtw_acquire_macid(rtwdev); @@ -386,7 +386,7 @@ void rtw_sta_remove(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, cancel_work_sync(&si->rc_work); - if (vif->type != NL80211_IFTYPE_STATION) + if (vif->type != NL80211_IFTYPE_STATION || sta->tdls) rtw_release_macid(rtwdev, si->mac_id); if (fw_exist) rtw_fw_media_status_report(rtwdev, si->mac_id, false); From 66b3ebc77d23d6574a965bdbfe41de8aeb7f384e Mon Sep 17 00:00:00 2001 From: Aaradhana Sahu Date: Fri, 11 Jul 2025 09:24:20 +0530 Subject: [PATCH 111/199] wifi: ath12k: Use HTT_TCL_METADATA_VER_V1 in FTM mode Currently host sends HTT_TCL_METADATA_VER_V2 to the firmware regardless of the operating mode (Mission or FTM). Firmware expects additional software information (like peer ID, vdev ID, and link ID) in Tx packets when HTT_TCL_METADATA_VER_V2 is set. However, in FTM (Factory Test Mode) mode, no vdev is created on the host side (this is expected). As a result, the firmware fails to find the expected vdev during packet processing and ends up dropping packets. To fix this, send HTT_TCL_METADATA_VER_V1 in FTM mode because FTM mode doesn't support HTT_TCL_METADATA_VER_V2. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.5-01651-QCAHKSWPL_SILICONZ-1 Fixes: 5d964966bd3f ("wifi: ath12k: Update HTT_TCL_METADATA version and bit mask definitions") Signed-off-by: Aaradhana Sahu Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250711035420.1509029-1-aaradhana.sahu@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/dp.h | 1 + drivers/net/wireless/ath/ath12k/dp_tx.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index 623facc2cce7..7baa48b86f7a 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -474,6 +474,7 @@ enum htt_h2t_msg_type { }; #define HTT_VER_REQ_INFO_MSG_ID GENMASK(7, 0) +#define HTT_OPTION_TCL_METADATA_VER_V1 1 #define HTT_OPTION_TCL_METADATA_VER_V2 2 #define HTT_OPTION_TAG GENMASK(7, 0) #define HTT_OPTION_LEN GENMASK(15, 8) diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index 0e93afbc4866..7005f05d3aaa 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -1200,6 +1200,7 @@ int ath12k_dp_tx_htt_h2t_ver_req_msg(struct ath12k_base *ab) struct sk_buff *skb; struct htt_ver_req_cmd *cmd; int len = sizeof(*cmd); + u32 metadata_version; int ret; init_completion(&dp->htt_tgt_version_received); @@ -1212,12 +1213,14 @@ int ath12k_dp_tx_htt_h2t_ver_req_msg(struct ath12k_base *ab) cmd = (struct htt_ver_req_cmd *)skb->data; cmd->ver_reg_info = le32_encode_bits(HTT_H2T_MSG_TYPE_VERSION_REQ, HTT_OPTION_TAG); + metadata_version = ath12k_ftm_mode ? HTT_OPTION_TCL_METADATA_VER_V1 : + HTT_OPTION_TCL_METADATA_VER_V2; cmd->tcl_metadata_version = le32_encode_bits(HTT_TAG_TCL_METADATA_VERSION, HTT_OPTION_TAG) | le32_encode_bits(HTT_TCL_METADATA_VER_SZ, HTT_OPTION_LEN) | - le32_encode_bits(HTT_OPTION_TCL_METADATA_VER_V2, + le32_encode_bits(metadata_version, HTT_OPTION_VALUE); ret = ath12k_htc_send(&ab->htc, dp->eid, skb); From 136aad17e14250c815dcfc2e3cf9926e763b7436 Mon Sep 17 00:00:00 2001 From: Sriram R Date: Mon, 14 Jul 2025 16:44:38 +0530 Subject: [PATCH 112/199] wifi: ath12k: Validate peer_id before searching for peer In RX WBM error path, error packet is received with invalid peer_id (0x3FFF) as there is no peer associated with that packet. However, this invalid peer_id coincides with the ML peer_id valid bit mask, causing an unnecessary search in the ML peer list. Prevent searching the peer list for invalid peer_id and return NULL. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Signed-off-by: Sriram R Signed-off-by: Nagarajan Maran Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250714111438.1134438-1-nagarajan.maran@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/peer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/peer.c b/drivers/net/wireless/ath/ath12k/peer.c index eb7aeff01490..f1ae9e5b5af7 100644 --- a/drivers/net/wireless/ath/ath12k/peer.c +++ b/drivers/net/wireless/ath/ath12k/peer.c @@ -100,6 +100,9 @@ struct ath12k_peer *ath12k_peer_find_by_id(struct ath12k_base *ab, lockdep_assert_held(&ab->base_lock); + if (peer_id == HAL_INVALID_PEERID) + return NULL; + if (peer_id & ATH12K_PEER_ML_ID_VALID) return ath12k_peer_find_by_ml_id(ab, peer_id); From 8ac2a383d4ce9e6229494c2a36df876800e6750e Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 15 Jul 2025 10:07:35 +0800 Subject: [PATCH 113/199] wifi: ath12k: remove unneeded semicolon in ath12k_mac_parse_tx_pwr_env() Kernel bot warns about this unneeded semicolon: drivers/net/wireless/ath/ath12k/mac.c:9785:2-3: Unneeded semicolon Remove it. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00284.1-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202507132355.ljWuxxjd-lkp@intel.com/ Signed-off-by: Baochen Qiang Link: https://patch.msgid.link/20250715-ath12k-unneed-semicolon-v1-1-9972fd4cef07@oss.qualcomm.com Signed-off-by: Jeff Johnson --- 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 8d6f0869f2d5..bf612079b8bd 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -11427,7 +11427,7 @@ static void ath12k_mac_parse_tx_pwr_env(struct ath12k *ar, "no transmit power envelope match client power type %d\n", client_type); return; - }; + } if (psd_valid) { tpc_info->is_psd_power = true; From 5dceb7dc745c755d61e01ae4d214a800025044fd Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Tue, 15 Jul 2025 20:16:48 +0800 Subject: [PATCH 114/199] wifi: ath5k: Use max() to improve code Use max() to reduce the code and improve its readability. Reviewed-by: Jiri Slaby Signed-off-by: Qianfeng Rong Link: https://patch.msgid.link/20250715121721.266713-3-rongqianfeng@vivo.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath5k/phy.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 4825f9cb9cb8..66b2dee39155 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -3116,10 +3116,7 @@ ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah, pd_gain_overlap; /* Force each power step to be at least 0.5 dB */ - if ((pdadc_tmp[1] - pdadc_tmp[0]) > 1) - pwr_step = pdadc_tmp[1] - pdadc_tmp[0]; - else - pwr_step = 1; + pwr_step = max(pdadc_tmp[1] - pdadc_tmp[0], 1); /* If pdadc_0 is negative, we need to extrapolate * below this pdgain by a number of pwr_steps */ @@ -3144,11 +3141,8 @@ ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah, continue; /* Force each power step to be at least 0.5 dB */ - if ((pdadc_tmp[table_size - 1] - pdadc_tmp[table_size - 2]) > 1) - pwr_step = pdadc_tmp[table_size - 1] - - pdadc_tmp[table_size - 2]; - else - pwr_step = 1; + pwr_step = max(pdadc_tmp[table_size - 1] - + pdadc_tmp[table_size - 2], 1); /* Extrapolate above */ while ((pdadc_0 < (s16) pdadc_n) && From 65c12b104cb942d588a1a093acc4537fb3d3b129 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 3 Jun 2025 10:25:28 +0800 Subject: [PATCH 115/199] wifi: ath11k: fix sleeping-in-atomic in ath11k_mac_op_set_bitrate_mask() ath11k_mac_disable_peer_fixed_rate() is passed as the iterator to ieee80211_iterate_stations_atomic(). Note in this case the iterator is required to be atomic, however ath11k_mac_disable_peer_fixed_rate() does not follow it as it might sleep. Consequently below warning is seen: BUG: sleeping function called from invalid context at wmi.c:304 Call Trace: dump_stack_lvl __might_resched.cold ath11k_wmi_cmd_send ath11k_wmi_set_peer_param ath11k_mac_disable_peer_fixed_rate ieee80211_iterate_stations_atomic ath11k_mac_op_set_bitrate_mask.cold Change to ieee80211_iterate_stations_mtx() to fix this issue. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30 Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices") Signed-off-by: Baochen Qiang Link: https://patch.msgid.link/20250603-ath11k-use-non-atomic-iterator-v1-1-d75762068d56@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath11k/mac.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 758ef6f26432..7dde21289a52 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -8744,9 +8744,9 @@ ath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, arvif->vdev_id, ret); return ret; } - ieee80211_iterate_stations_atomic(ar->hw, - ath11k_mac_disable_peer_fixed_rate, - arvif); + ieee80211_iterate_stations_mtx(ar->hw, + ath11k_mac_disable_peer_fixed_rate, + arvif); } else if (ath11k_mac_bitrate_mask_get_single_nss(ar, arvif, band, mask, &single_nss)) { rate = WMI_FIXED_RATE_NONE; @@ -8813,9 +8813,9 @@ ath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, } mutex_lock(&ar->conf_mutex); - ieee80211_iterate_stations_atomic(ar->hw, - ath11k_mac_disable_peer_fixed_rate, - arvif); + ieee80211_iterate_stations_mtx(ar->hw, + ath11k_mac_disable_peer_fixed_rate, + arvif); arvif->bitrate_mask = *mask; ieee80211_iterate_stations_atomic(ar->hw, From cbf510e21e0ce3d75b099528859526cc24ebf628 Mon Sep 17 00:00:00 2001 From: Chia-Yuan Li Date: Tue, 15 Jul 2025 11:52:55 +0800 Subject: [PATCH 116/199] wifi: rtw89: trigger TX stuck if FIFO full In order for the situation where the dispatcher blocking causes HAXIDMA to be unable to TX to be reported as a TX stuck, so that subsequent recovery can be handled. Signed-off-by: Chia-Yuan Li Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250715035259.45061-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 597de632e364..a669f2f843aa 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -2638,6 +2638,10 @@ static void rtw89_pci_set_dbg(struct rtw89_dev *rtwdev) rtw89_write32_set(rtwdev, R_AX_PCIE_DBG_CTRL, B_AX_ASFF_FULL_NO_STK | B_AX_EN_STUCK_DBG); + rtw89_write32_mask(rtwdev, R_AX_PCIE_EXP_CTRL, + B_AX_EN_STUCK_DBG | B_AX_ASFF_FULL_NO_STK, + B_AX_EN_STUCK_DBG); + if (rtwdev->chip->chip_id == RTL8852A) rtw89_write32_set(rtwdev, R_AX_PCIE_EXP_CTRL, B_AX_EN_CHKDSC_NO_RX_STUCK); From 8552f2b3153eb8d49450f1661adf62457c410660 Mon Sep 17 00:00:00 2001 From: Chia-Yuan Li Date: Tue, 15 Jul 2025 11:52:56 +0800 Subject: [PATCH 117/199] wifi: rtw89: mac: reduce PPDU status length for WiFi 6 chips Since the RX counter in the PPDU status is not used, it is disabled to reduce the waste of DLE quota. Signed-off-by: Chia-Yuan Li Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250715035259.45061-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index f6bbc796329c..3de3ea1e13ad 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -5865,7 +5865,7 @@ int rtw89_mac_cfg_ppdu_status_ax(struct rtw89_dev *rtwdev, u8 mac_idx, bool enab rtw89_write32(rtwdev, reg, B_AX_PPDU_STAT_RPT_EN | B_AX_APP_MAC_INFO_RPT | - B_AX_APP_RX_CNT_RPT | B_AX_APP_PLCP_HDR_RPT | + B_AX_APP_PLCP_HDR_RPT | B_AX_PPDU_STAT_RPT_CRC32); rtw89_write32_mask(rtwdev, R_AX_HW_RPT_FWD, B_AX_FWD_PPDU_STAT_MASK, RTW89_PRPT_DEST_HOST); From b552a3ef8a3d722470593349333c9b19bfe40767 Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Tue, 15 Jul 2025 11:52:57 +0800 Subject: [PATCH 118/199] wifi: rtw89: dynamically update EHT preamble puncturing When the 'Disabled Subchannel Bitmap' within the EHT Operation element is changed, mac80211 parse and pass it to the driver. The driver is then updated with this puncturing bitmap to optimize bandwidth usage and prevent interference from degrading performance across the entire channel. Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250715035259.45061-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 47 +++++++++++++++++++ drivers/net/wireless/realtek/rtw89/core.h | 3 ++ drivers/net/wireless/realtek/rtw89/fw.c | 43 +++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 16 +++++++ drivers/net/wireless/realtek/rtw89/rtw8851b.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852a.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852b.c | 1 + .../net/wireless/realtek/rtw89/rtw8852bt.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852c.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8922a.c | 1 + 10 files changed, 115 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index ed0d89ac3495..f7d1c5d3b92e 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -129,6 +129,48 @@ void rtw89_chan_create(struct rtw89_chan *chan, u8 center_chan, u8 primary_chan, bandwidth); } +static void _rtw89_chan_update_punctured(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + const struct cfg80211_chan_def *chandef) +{ + struct ieee80211_bss_conf *bss_conf; + + if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION && + rtwvif_link->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT) + return; + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + if (!bss_conf->eht_support) { + rcu_read_unlock(); + return; + } + + rcu_read_unlock(); + + rtw89_chip_h2c_punctured_cmac_tbl(rtwdev, rtwvif_link, chandef->punctured); +} + +static void rtw89_chan_update_punctured(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_idx idx, + const struct cfg80211_chan_def *chandef) +{ + struct rtw89_vif_link *rtwvif_link; + struct rtw89_vif *rtwvif; + unsigned int link_id; + + rtw89_for_each_rtwvif(rtwdev, rtwvif) { + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { + if (!rtwvif_link->chanctx_assigned || + rtwvif_link->chanctx_idx != idx) + continue; + + _rtw89_chan_update_punctured(rtwdev, rtwvif_link, chandef); + } + } +} + bool rtw89_assign_entity_chan(struct rtw89_dev *rtwdev, enum rtw89_chanctx_idx idx, const struct rtw89_chan *new) @@ -3245,6 +3287,9 @@ void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev, rtw89_config_entity_chandef(rtwdev, idx, &ctx->def); rtw89_set_channel(rtwdev); } + + if (changed & IEEE80211_CHANCTX_CHANGE_PUNCTURING) + rtw89_chan_update_punctured(rtwdev, idx, &ctx->def); } int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev, @@ -3388,5 +3433,7 @@ assign: return ret; } + _rtw89_chan_update_punctured(rtwdev, rtwvif_link, &new_ctx->def); + return 0; } diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 59ec81adac7e..a99a0dc710d8 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3779,6 +3779,9 @@ struct rtw89_chip_ops { struct rtw89_sta_link *rtwsta_link); int (*h2c_txtime_cmac_tbl)(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); + int (*h2c_punctured_cmac_tbl)(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + u16 punctured); int (*h2c_default_dmac_tbl)(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link); diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 73a4ec988d16..8230115c29b4 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -3745,6 +3745,49 @@ fail: } EXPORT_SYMBOL(rtw89_fw_h2c_txtime_cmac_tbl_g7); +int rtw89_fw_h2c_punctured_cmac_tbl_g7(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + u16 punctured) +{ + struct rtw89_h2c_cctlinfo_ud_g7 *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for punctured cmac g7\n"); + return -ENOMEM; + } + + skb_put(skb, len); + h2c = (struct rtw89_h2c_cctlinfo_ud_g7 *)skb->data; + + h2c->c0 = le32_encode_bits(rtwvif_link->mac_id, CCTLINFO_G7_C0_MACID) | + le32_encode_bits(1, CCTLINFO_G7_C0_OP); + + h2c->w4 = le32_encode_bits(~punctured, CCTLINFO_G7_W4_ACT_SUBCH_CBW); + h2c->m4 = cpu_to_le32(CCTLINFO_G7_W4_ACT_SUBCH_CBW); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_CCTLINFO_UD_G7, 0, 1, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} +EXPORT_SYMBOL(rtw89_fw_h2c_punctured_cmac_tbl_g7); + int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link) { diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 98be7e72c685..b64edc9e8abe 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -4736,6 +4736,9 @@ int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_txtime_cmac_tbl_g7(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); +int rtw89_fw_h2c_punctured_cmac_tbl_g7(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + u16 punctured); int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, @@ -5038,6 +5041,19 @@ int rtw89_chip_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, return chip->ops->h2c_txtime_cmac_tbl(rtwdev, rtwsta_link); } +static inline +int rtw89_chip_h2c_punctured_cmac_tbl(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + u16 punctured) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + if (!chip->ops->h2c_punctured_cmac_tbl) + return 0; + + return chip->ops->h2c_punctured_cmac_tbl(rtwdev, rtwvif_link, punctured); +} + static inline int rtw89_chip_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, bool valid, struct ieee80211_ampdu_params *params) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 96edaf8e9ec4..393df2b0dcae 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2546,6 +2546,7 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, .h2c_txtime_cmac_tbl = rtw89_fw_h2c_txtime_cmac_tbl, + .h2c_punctured_cmac_tbl = NULL, .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 0496deb7278f..3bbe2a808844 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2151,6 +2151,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, .h2c_txtime_cmac_tbl = rtw89_fw_h2c_txtime_cmac_tbl, + .h2c_punctured_cmac_tbl = NULL, .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 389dfac26028..7ede07f7b1eb 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -851,6 +851,7 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, .h2c_txtime_cmac_tbl = rtw89_fw_h2c_txtime_cmac_tbl, + .h2c_punctured_cmac_tbl = NULL, .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c index 06a06c190553..9427823aca2f 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c @@ -717,6 +717,7 @@ static const struct rtw89_chip_ops rtw8852bt_chip_ops = { .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, .h2c_txtime_cmac_tbl = rtw89_fw_h2c_txtime_cmac_tbl, + .h2c_punctured_cmac_tbl = NULL, .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 6e27f1ff94dc..88cf8ea13e7c 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2971,6 +2971,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = { .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, .h2c_txtime_cmac_tbl = rtw89_fw_h2c_txtime_cmac_tbl, + .h2c_punctured_cmac_tbl = NULL, .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index e23655f3e4c1..36c641e3bc13 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -2826,6 +2826,7 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl_g7, .h2c_ampdu_cmac_tbl = rtw89_fw_h2c_ampdu_cmac_tbl_g7, .h2c_txtime_cmac_tbl = rtw89_fw_h2c_txtime_cmac_tbl_g7, + .h2c_punctured_cmac_tbl = rtw89_fw_h2c_punctured_cmac_tbl_g7, .h2c_default_dmac_tbl = rtw89_fw_h2c_default_dmac_tbl_v2, .h2c_update_beacon = rtw89_fw_h2c_update_beacon_be, .h2c_ba_cam = rtw89_fw_h2c_ba_cam_v1, From f1000385d47be9e0a1d1d622a2e2e28ffd0fe384 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 15 Jul 2025 11:52:58 +0800 Subject: [PATCH 119/199] wifi: rtw89: purge obsoleted scan events with software sequence number The queued and obsoleted scan events can be wrongly treated as events of new scan request, causing unexpected scan result. Attach a software sequence number to scan request and its corresponding events. When a new scan request is acknowledged by firmware, purge the scan events if its sequence number is not belong to current request. Normal case: mac80211 event work event BH ------------- ---------- -------- scan req #1 ---->o | <----o <...........................o o | <--------------------------+ ieee80211_scan_completed() Abnormal case (late event work): mac80211 event work event BH ------------- ---------- -------- scan req #1 ---->o | <----o <...........................o o #1 scan cancel #2 ->o | <----o <...........................o o #2 | (patch to avoid this) scan req #3 ---->o | | | <----o <..........|................o | o #3 <--------------------------+ ieee80211_scan_completed() Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250715035259.45061-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/fw.c | 31 ++++++++++++++++++++++- drivers/net/wireless/realtek/rtw89/fw.h | 3 +++ drivers/net/wireless/realtek/rtw89/mac.c | 8 ++++++ drivers/net/wireless/realtek/rtw89/mac.h | 25 ++++++++++++++++++ drivers/net/wireless/realtek/rtw89/wow.c | 2 +- 6 files changed, 68 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index a99a0dc710d8..43e10278e14d 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -5574,6 +5574,7 @@ struct rtw89_hw_scan_info { bool connected; bool abort; u16 delay; /* in unit of ms */ + u8 seq: 2; }; enum rtw89_phy_bb_gain_band { diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 8230115c29b4..d26626bed960 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -6759,6 +6759,34 @@ void rtw89_fw_c2h_work(struct wiphy *wiphy, struct wiphy_work *work) } } +void rtw89_fw_c2h_purge_obsoleted_scan_events(struct rtw89_dev *rtwdev) +{ + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + struct sk_buff *skb, *tmp; + int limit; + + lockdep_assert_wiphy(rtwdev->hw->wiphy); + + limit = skb_queue_len(&rtwdev->c2h_queue); + + skb_queue_walk_safe(&rtwdev->c2h_queue, skb, tmp) { + struct rtw89_fw_c2h_attr *attr = RTW89_SKB_C2H_CB(skb); + + if (--limit < 0) + return; + + if (!attr->is_scan_event || attr->scan_seq == scan_info->seq) + continue; + + rtw89_debug(rtwdev, RTW89_DBG_HW_SCAN, + "purge obsoleted scan event with seq=%d (cur=%d)\n", + attr->scan_seq, scan_info->seq); + + skb_unlink(skb, &rtwdev->c2h_queue); + dev_kfree_skb_any(skb); + } +} + static int rtw89_fw_write_h2c_reg(struct rtw89_dev *rtwdev, struct rtw89_mac_h2c_info *info) { @@ -8052,7 +8080,8 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, opt.opch_end = connected ? 0 : RTW89_CHAN_INVALID; } - ret = mac->scan_offload(rtwdev, &opt, rtwvif_link, false); + ret = rtw89_mac_scan_offload(rtwdev, &opt, rtwvif_link, false); + out: return ret; } diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index b64edc9e8abe..7a4ad7a416b8 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3570,6 +3570,8 @@ struct rtw89_fw_c2h_attr { u8 class; u8 func; u16 len; + u8 is_scan_event: 1; + u8 scan_seq: 2; }; static inline struct rtw89_fw_c2h_attr *RTW89_SKB_C2H_CB(struct sk_buff *skb) @@ -4755,6 +4757,7 @@ int rtw89_fw_h2c_dctl_sec_cam_v2(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); void rtw89_fw_c2h_irqsafe(struct rtw89_dev *rtwdev, struct sk_buff *c2h); void rtw89_fw_c2h_work(struct wiphy *wiphy, struct wiphy_work *work); +void rtw89_fw_c2h_purge_obsoleted_scan_events(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link, diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 3de3ea1e13ad..65d36fcad8b2 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -5165,6 +5165,7 @@ rtw89_mac_c2h_done_ack(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 le { /* N.B. This will run in interrupt context. */ struct rtw89_wait_info *fw_ofld_wait = &rtwdev->mac.fw_ofld_wait; + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; struct rtw89_wait_info *ps_wait = &rtwdev->mac.ps_wait; const struct rtw89_c2h_done_ack *c2h = (const struct rtw89_c2h_done_ack *)skb_c2h->data; @@ -5207,9 +5208,11 @@ rtw89_mac_c2h_done_ack(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 le h2c_return &= RTW89_C2H_SCAN_DONE_ACK_RETURN; break; case H2C_FUNC_SCANOFLD: + scan_info->seq++; cond = RTW89_SCANOFLD_WAIT_COND_START; break; case H2C_FUNC_SCANOFLD_BE: + scan_info->seq++; cond = RTW89_SCANOFLD_BE_WAIT_COND_START; h2c_return &= RTW89_C2H_SCAN_DONE_ACK_RETURN; break; @@ -5706,10 +5709,15 @@ static void rtw89_mac_c2h_scanofld_rsp_atomic(struct rtw89_dev *rtwdev, const struct rtw89_c2h_scanofld *c2h = (const struct rtw89_c2h_scanofld *)skb->data; struct rtw89_wait_info *fw_ofld_wait = &rtwdev->mac.fw_ofld_wait; + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + struct rtw89_fw_c2h_attr *attr = RTW89_SKB_C2H_CB(skb); struct rtw89_completion_data data = {}; unsigned int cond; u8 status, reason; + attr->is_scan_event = 1; + attr->scan_seq = scan_info->seq; + status = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_STATUS); reason = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_RSN); data.err = status != RTW89_SCAN_STATUS_SUCCESS; diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 9f596a06b3d0..241e89983c4a 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -6,6 +6,7 @@ #define __RTW89_MAC_H__ #include "core.h" +#include "fw.h" #include "reg.h" #define MAC_MEM_DUMP_PAGE_SIZE_AX 0x40000 @@ -1583,4 +1584,28 @@ void rtw89_fwdl_secure_idmem_share_mode(struct rtw89_dev *rtwdev, u8 mode) return mac->fwdl_secure_idmem_share_mode(rtwdev, mode); } + +static inline +int rtw89_mac_scan_offload(struct rtw89_dev *rtwdev, + struct rtw89_scan_option *option, + struct rtw89_vif_link *rtwvif_link, + bool wowlan) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + int ret; + + ret = mac->scan_offload(rtwdev, option, rtwvif_link, wowlan); + + if (option->enable) { + /* + * At this point, new scan request is acknowledged by firmware, + * so scan events of previous scan request become obsoleted. + * Purge the queued scan events to prevent interference to + * current new request. + */ + rtw89_fw_c2h_purge_obsoleted_scan_events(rtwdev); + } + + return ret; +} #endif diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 4f759c75389e..4dd471b6dd30 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -1489,7 +1489,7 @@ static int rtw89_pno_scan_offload(struct rtw89_dev *rtwdev, bool enable) opt.opch_end = RTW89_CHAN_INVALID; } - mac->scan_offload(rtwdev, &opt, rtwvif_link, true); + rtw89_mac_scan_offload(rtwdev, &opt, rtwvif_link, true); return 0; } From 8b4a0277388137ac31728ee69d9e388a0fa52287 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 15 Jul 2025 11:52:59 +0800 Subject: [PATCH 120/199] wifi: rtw89: check path range before using in rtw89_fw_h2c_rf_ps_info() The variable 'path' from rtw89_phy_get_syn_sel() as index of array could be 3, but array size is 2. Fortunately, current chip->rf_path_num is smaller or equal to 2, so it is safe. To prevent mistakes in the future, add a checking and avoid Coverity warnings. Addresses-Coverity-ID: linux-next: 1644716 ("Out-of-bounds write") Addresses-Coverity-ID: linux-next: 1644717 ("Out-of-bounds write") Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250715035259.45061-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index d26626bed960..a26465ff6a68 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -6153,7 +6153,7 @@ int rtw89_fw_h2c_rf_ps_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) path = rtw89_phy_get_syn_sel(rtwdev, rtwvif_link->phy_idx); val = rtw89_chip_chan_to_rf18_val(rtwdev, chan); - if (path >= chip->rf_path_num) { + if (path >= chip->rf_path_num || path >= NUM_OF_RTW89_FW_RFK_PATH) { rtw89_err(rtwdev, "unsupported rf path (%d)\n", path); ret = -ENOENT; goto fail; From 671be46afd1f03de9dc6e4679c88e1a7a81cdff6 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Tue, 15 Jul 2025 22:44:47 +0300 Subject: [PATCH 121/199] wifi: rtw89: Lower the timeout in rtw89_fw_read_c2h_reg() for USB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This read_poll_timeout_atomic() with a delay of 1 µs and a timeout of 1000000 µs can take ~250 seconds in the worst case because sending a USB control message takes ~250 µs. Lower the timeout to 4000 for USB in order to reduce the maximum polling time to ~1 second. This problem was observed with RTL8851BU while suspending to RAM with WOWLAN enabled. The computer sat for 4 minutes with a black screen before suspending. Signed-off-by: Bitterblue Smith Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/09313da6-c865-4e91-b758-4cb38a878796@gmail.com --- drivers/net/wireless/realtek/rtw89/fw.c | 9 +++++++-- drivers/net/wireless/realtek/rtw89/fw.h | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index a26465ff6a68..16e59a4a486e 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -6826,13 +6826,18 @@ static int rtw89_fw_read_c2h_reg(struct rtw89_dev *rtwdev, const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_fw_info *fw_info = &rtwdev->fw; const u32 *c2h_reg = chip->c2h_regs; - u32 ret; + u32 ret, timeout; u8 i, val; info->id = RTW89_FWCMD_C2HREG_FUNC_NULL; + if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) + timeout = RTW89_C2H_TIMEOUT_USB; + else + timeout = RTW89_C2H_TIMEOUT; + ret = read_poll_timeout_atomic(rtw89_read8, val, val, 1, - RTW89_C2H_TIMEOUT, false, rtwdev, + timeout, false, rtwdev, chip->c2h_ctrl_reg); if (ret) { rtw89_warn(rtwdev, "c2h reg timeout\n"); diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 7a4ad7a416b8..7865930299c8 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -115,6 +115,8 @@ struct rtw89_h2creg_sch_tx_en { #define RTW89_C2HREG_HDR_LEN 2 #define RTW89_H2CREG_HDR_LEN 2 #define RTW89_C2H_TIMEOUT 1000000 +#define RTW89_C2H_TIMEOUT_USB 4000 + struct rtw89_mac_c2h_info { u8 id; u8 content_len; From 12322a02603071d09df652bbc11864e23de0b83e Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Tue, 15 Jul 2025 22:46:20 +0300 Subject: [PATCH 122/199] wifi: rtw89: Lower the timeout in rtw89_fwdl_check_path_ready_ax() for USB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the chip is not powered on correctly (like during driver development) rtw89_fwdl_check_path_ready_ax() can fail. read_poll_timeout_atomic() with a delay of 1 µs and a timeout of 400000 µs can take 50 seconds with USB because of the time it takes to send a USB control message. The firmware upload is tried 5 times, so in total it takes 250 seconds. Lower the timeout to 3200 for USB in order to reduce the time rtw89_fwdl_check_path_ready_ax() takes from 50 seconds to less than 1 second. Signed-off-by: Bitterblue Smith Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/af0b25d0-ea67-455e-91f2-8e4c18ae4328@gmail.com --- drivers/net/wireless/realtek/rtw89/fw.h | 1 + drivers/net/wireless/realtek/rtw89/mac.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 7865930299c8..3de29137b113 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -4699,6 +4699,7 @@ struct rtw89_c2h_rf_tas_info { #define RTW89_FW_BACKTRACE_KEY 0xBACEBACE #define FWDL_WAIT_CNT 400000 +#define FWDL_WAIT_CNT_USB 3200 int rtw89_fw_check_rdy(struct rtw89_dev *rtwdev, enum rtw89_fwdl_check_type type); int rtw89_fw_recognize(struct rtw89_dev *rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 65d36fcad8b2..5a5da9d9c0c5 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -6940,10 +6940,16 @@ int rtw89_fwdl_check_path_ready_ax(struct rtw89_dev *rtwdev, bool h2c_or_fwdl) { u8 check = h2c_or_fwdl ? B_AX_H2C_PATH_RDY : B_AX_FWDL_PATH_RDY; + u32 timeout; u8 val; + if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) + timeout = FWDL_WAIT_CNT_USB; + else + timeout = FWDL_WAIT_CNT; + return read_poll_timeout_atomic(rtw89_read8, val, val & check, - 1, FWDL_WAIT_CNT, false, + 1, timeout, false, rtwdev, R_AX_WCPU_FW_CTRL); } From 37c23874d13eb369d8b384a1ce5992ff6c23d56f Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Wed, 16 Jul 2025 20:29:26 +0800 Subject: [PATCH 123/199] wifi: rtw89: wow: Add Basic Rate IE to probe request in scheduled scan mode In scheduled scan mode, the current probe request only includes the SSID IE, but omits the Basic Rate IE. Some APs do not respond to such incomplete probe requests, causing net-detect failures. To improve interoperability and ensure APs respond correctly, add the Basic Rate IE to the probe request in driver. Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250716122926.6709-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/wow.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 4dd471b6dd30..071c7577df52 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -1412,6 +1412,8 @@ static void rtw89_fw_release_pno_pkt_list(struct rtw89_dev *rtwdev, static int rtw89_pno_scan_update_probe_req(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { + static const u8 basic_rate_ie[] = {WLAN_EID_SUPP_RATES, 0x08, + 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c}; struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct cfg80211_sched_scan_request *nd_config = rtw_wow->nd_config; u8 num = nd_config->n_match_sets, i; @@ -1423,10 +1425,11 @@ static int rtw89_pno_scan_update_probe_req(struct rtw89_dev *rtwdev, skb = ieee80211_probereq_get(rtwdev->hw, rtwvif_link->mac_addr, nd_config->match_sets[i].ssid.ssid, nd_config->match_sets[i].ssid.ssid_len, - nd_config->ie_len); + nd_config->ie_len + sizeof(basic_rate_ie)); if (!skb) return -ENOMEM; + skb_put_data(skb, basic_rate_ie, sizeof(basic_rate_ie)); skb_put_data(skb, nd_config->ie, nd_config->ie_len); info = kzalloc(sizeof(*info), GFP_KERNEL); From 94cd0ba1842ece06acc15bba5f2bff6b6043eb1d Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Tue, 15 Jul 2025 20:16:53 +0800 Subject: [PATCH 124/199] wifi: rtlwifi: Use min()/max() to improve code Use min()/max() to reduce the code and improve its readability. Acked-by: Ping-Ke Shih Signed-off-by: Qianfeng Rong Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250715121721.266713-8-rongqianfeng@vivo.com --- .../wireless/realtek/rtlwifi/rtl8192ce/hw.c | 19 +++---------------- .../wireless/realtek/rtlwifi/rtl8192cu/hw.c | 17 +++-------------- .../wireless/realtek/rtlwifi/rtl8192ee/dm.c | 5 +---- .../wireless/realtek/rtlwifi/rtl8723ae/hw.c | 15 +++------------ .../wireless/realtek/rtlwifi/rtl8723be/dm.c | 5 +---- .../wireless/realtek/rtlwifi/rtl8821ae/dm.c | 5 +---- 6 files changed, 12 insertions(+), 54 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c index 5ca6b49e73c7..4354ae67a379 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c @@ -1487,22 +1487,9 @@ _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, rtlefuse->txpwrlevel_ht40_1s[rf_path][i] = rtlefuse-> eeprom_chnlarea_txpwr_ht40_1s[rf_path][index]; - - if ((rtlefuse-> - eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] - - rtlefuse-> - eprom_chnl_txpwr_ht40_2sdf[rf_path][index]) - > 0) { - rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = - rtlefuse-> - eeprom_chnlarea_txpwr_ht40_1s[rf_path] - [index] - - rtlefuse-> - eprom_chnl_txpwr_ht40_2sdf[rf_path] - [index]; - } else { - rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = 0; - } + rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = + max(rtlefuse->eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] - + rtlefuse->eprom_chnl_txpwr_ht40_2sdf[rf_path][index], 0); } for (i = 0; i < 14; i++) { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c index ec5d558609fe..989e7cff8e20 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c @@ -163,20 +163,9 @@ _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, rtlefuse->txpwrlevel_ht40_1s[rf_path][i] = rtlefuse-> eeprom_chnlarea_txpwr_ht40_1s[rf_path][index]; - if ((rtlefuse-> - eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] - - rtlefuse-> - eprom_chnl_txpwr_ht40_2sdf[rf_path][index]) - > 0) { - rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = - rtlefuse-> - eeprom_chnlarea_txpwr_ht40_1s[rf_path] - [index] - rtlefuse-> - eprom_chnl_txpwr_ht40_2sdf[rf_path] - [index]; - } else { - rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = 0; - } + rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = + max(rtlefuse->eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] - + rtlefuse->eprom_chnl_txpwr_ht40_2sdf[rf_path][index], 0); } for (i = 0; i < 14; i++) { RTPRINT(rtlpriv, FINIT, INIT_TXPOWER, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c index 17486e3f322c..0108850bb9e5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c @@ -223,10 +223,7 @@ static void rtl92ee_dm_dig(struct ieee80211_hw *hw) if (mac->link_state >= MAC80211_LINKED) { if (bfirstconnect) { - if (dm_dig->rssi_val_min <= dig_maxofmin) - current_igi = dm_dig->rssi_val_min; - else - current_igi = dig_maxofmin; + current_igi = min(dm_dig->rssi_val_min, dig_maxofmin); dm_dig->large_fa_hit = 0; } else { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c index 21b827f519b6..bd45d9bd40bb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c @@ -1449,18 +1449,9 @@ _rtl8723e_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, rtlefuse->eeprom_chnlarea_txpwr_ht40_1s [rf_path][index]; - if ((rtlefuse->eeprom_chnlarea_txpwr_ht40_1s - [rf_path][index] - - rtlefuse->eprom_chnl_txpwr_ht40_2sdf - [rf_path][index]) > 0) { - rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = - rtlefuse->eeprom_chnlarea_txpwr_ht40_1s - [rf_path][index] - - rtlefuse->eprom_chnl_txpwr_ht40_2sdf - [rf_path][index]; - } else { - rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = 0; - } + rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = + max(rtlefuse->eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] - + rtlefuse->eprom_chnl_txpwr_ht40_2sdf[rf_path][index], 0); } for (i = 0; i < 14; i++) { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c index c53f95144812..c65d14fb914f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c @@ -468,10 +468,7 @@ static void rtl8723be_dm_dig(struct ieee80211_hw *hw) if (mac->link_state >= MAC80211_LINKED) { if (bfirstconnect) { - if (dm_digtable->rssi_val_min <= dig_maxofmin) - current_igi = dm_digtable->rssi_val_min; - else - current_igi = dig_maxofmin; + current_igi = min(dm_digtable->rssi_val_min, dig_maxofmin); dm_digtable->large_fa_hit = 0; } else { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c index 76b5395539d0..f8b159c74658 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c @@ -756,10 +756,7 @@ static void rtl8821ae_dm_dig(struct ieee80211_hw *hw) rtl_dbg(rtlpriv, COMP_DIG, DBG_LOUD, "DIG AfterLink\n"); if (first_connect) { - if (dm_digtable->rssi_val_min <= dig_max_of_min) - current_igi = dm_digtable->rssi_val_min; - else - current_igi = dig_max_of_min; + current_igi = min(dm_digtable->rssi_val_min, dig_max_of_min); rtl_dbg(rtlpriv, COMP_DIG, DBG_LOUD, "First Connect\n"); } else { From 765e98e918ebe0685abbd47994ecc9354163ba24 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 18 Jul 2025 10:32:36 +0200 Subject: [PATCH 125/199] wifi: cfg80211/mac80211: remove wrong scan request n_channels This (partially) reverts commits - 838c7b8f1f27 ("wifi: nl80211: Avoid address calculations via out of bounds array indexing") - f1d3334d604c ("wifi: cfg80211: sme: init n_channels before channels[] access") - 82bbe02b2500 ("wifi: mac80211: Set n_channels after allocating struct cfg80211_scan_request") These commits all set the structure to be in an inconsistent state, setting n_channels to some value before them actually being filled in. That's fine for what the code does now, but with the removal of __counted_by() in 444020f4bf06 ("wifi: cfg80211: remove scan request n_channels counted_by") it's no longer needed and it does leave a bit of a landmine there since breaking out of some code to send the scan or something would leave it wrong. Remove the now superfluous n_channels settings. Link: https://patch.msgid.link/20250718103237.59510b2384c5.Ied5ba9c5c49efc008f4491c8ca7a45858a83f064@changeid Signed-off-by: Johannes Berg --- net/mac80211/main.c | 1 - net/wireless/nl80211.c | 1 - net/wireless/sme.c | 1 - 3 files changed, 3 deletions(-) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index ec60b82af007..351564360c26 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1334,7 +1334,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) GFP_KERNEL); if (!local->int_scan_req) return -ENOMEM; - local->int_scan_req->n_channels = channels; eth_broadcast_addr(local->int_scan_req->bssid); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 63f015ce9ad4..20bc0f052c16 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -9975,7 +9975,6 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) request = kzalloc(size, GFP_KERNEL); if (!request) return -ENOMEM; - request->req.n_channels = n_channels; if (n_ssids) request->req.ssids = (void *)request + ssids_offset; diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 6d7a7e7f0fc2..826ec0a6355f 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -83,7 +83,6 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) if (!request) return -ENOMEM; - request->req.n_channels = n_channels; if (wdev->conn->params.channel) { enum nl80211_band band = wdev->conn->params.channel->band; struct ieee80211_supported_band *sband = From f562f6a5899d91940fd5ef78e3f6042f56abe3e2 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Fri, 18 Jul 2025 11:38:34 +0530 Subject: [PATCH 126/199] wifi: mac80211: fix macro scoping in for_each_link_data The for_each_link_data() macro currently declares a local variable __sdata directly, which could lead to compiler warnings or errors when reused in the same function or within switch-case blocks due to variable redefinition or invalid scoping. To address this, restructure the macro to use an outer for-loop that runs only once, allowing safe declaration of __sdata without polluting the outer scope. This ensures compatibility with static analyzers. No functional changes; this is purely a cleanup to improve macro hygiene. Signed-off-by: Aditya Kumar Singh Signed-off-by: Maharaja Kennadyrajan Link: https://patch.msgid.link/20250718060837.59371-2-maharaja.kennadyrajan@oss.qualcomm.com Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 084e2673a27e..7c18c51966d0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1242,7 +1242,9 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p) if ((_link = rcu_dereference((___sdata)->link[___link_id]))) #define for_each_link_data(sdata, __link) \ - struct ieee80211_sub_if_data *__sdata = sdata; \ + /* outer loop just to define the variable ... */ \ + for (struct ieee80211_sub_if_data *__sdata = (sdata); __sdata; \ + __sdata = NULL /* always stop */) \ for (int __link_id = 0; \ __link_id < ARRAY_SIZE((__sdata)->link); __link_id++) \ if ((!(__sdata)->vif.valid_links || \ From 4e1916dec9850cd49dd5792200ab649061cbedc1 Mon Sep 17 00:00:00 2001 From: Maharaja Kennadyrajan Date: Fri, 18 Jul 2025 11:38:35 +0530 Subject: [PATCH 127/199] wifi: mac80211: Add link iteration macro for link data with rcu_dereference Currently, the existing macro for_each_link_data() uses sdata_dereference() which requires the wiphy lock. This lock cannot be used in atomic or RCU read-side contexts, such as in the RX path. Introduce a new macro, for_each_link_data_rcu(), that iterates over link of sdata using rcu_dereference(), making it safe to use in RCU contexts. This allows callers to access link data without requiring the wiphy lock. The macro takes into account the vif.valid_links bitmap and ensures only valid links are accessed safely. Callers are responsible for ensuring that rcu_read_lock() is held when using this macro. Signed-off-by: Maharaja Kennadyrajan Link: https://patch.msgid.link/20250718060837.59371-3-maharaja.kennadyrajan@oss.qualcomm.com Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 7c18c51966d0..9c0603eb580f 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1252,6 +1252,19 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p) ((__link) = sdata_dereference((__sdata)->link[__link_id], \ (__sdata)))) +/* + * for_each_link_data_rcu should be used under RCU read lock. + */ +#define for_each_link_data_rcu(sdata, __link) \ + /* outer loop just to define the variable ... */ \ + for (struct ieee80211_sub_if_data *__sdata = (sdata); __sdata; \ + __sdata = NULL /* always stop */) \ + for (int __link_id = 0; \ + __link_id < ARRAY_SIZE((__sdata)->link); __link_id++) \ + if ((!(__sdata)->vif.valid_links || \ + (__sdata)->vif.valid_links & BIT(__link_id)) && \ + ((__link) = rcu_dereference((__sdata)->link[__link_id]))) \ + static inline int ieee80211_get_mbssid_beacon_len(struct cfg80211_mbssid_elems *elems, struct cfg80211_rnr_elems *rnr_elems, From 66e53e117f41df05d3fd4f8c65810e148fc23669 Mon Sep 17 00:00:00 2001 From: Maharaja Kennadyrajan Date: Fri, 18 Jul 2025 11:38:36 +0530 Subject: [PATCH 128/199] wifi: mac80211: extend beacon monitoring for MLO Currently, reset beacon monitor (ieee80211_sta_reset_beacon_monitor()) timer is handled only for non-AP non-MLD STA and do not support non-AP MLD STA. When the beacon loss occurs in non-AP MLD STA with the current implementation, it is treated as a single link and the timer will reset based on the timeout of the deflink, without checking all the links. Check the CSA flags for all the links in the MLO and decide whether to schedule the work queue for beacon loss. If any of the links has CSA active, then beacon loss work is not scheduled. Also, call the functions ieee80211_sta_reset_beacon_monitor() and ieee80211_sta_reset_conn_monitor() from ieee80211_csa_switch_work() only when all the links are CSA active. Signed-off-by: Maharaja Kennadyrajan Link: https://patch.msgid.link/20250718060837.59371-4-maharaja.kennadyrajan@oss.qualcomm.com Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5298dbbb5341..86b69bd94b4c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2505,6 +2505,21 @@ static void ieee80211_csa_switch_work(struct wiphy *wiphy, } } + /* + * It is not necessary to reset these timers if any link does not + * have an active CSA and that link still receives the beacons + * when other links have active CSA. + */ + for_each_link_data(sdata, link) { + if (!link->conf->csa_active) + return; + } + + /* + * Reset the beacon monitor and connection monitor timers when CSA + * is active for all links in MLO when channel switch occurs in all + * the links. + */ ieee80211_sta_reset_beacon_monitor(sdata); ieee80211_sta_reset_conn_monitor(sdata); } @@ -8473,16 +8488,32 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) } } +static bool +ieee80211_is_csa_in_progress(struct ieee80211_sub_if_data *sdata) +{ + /* + * In MLO, check the CSA flags 'active' and 'waiting_bcn' for all + * the links. + */ + struct ieee80211_link_data *link; + + guard(rcu)(); + + for_each_link_data_rcu(sdata, link) { + if (!(link->conf->csa_active && + !link->u.mgd.csa.waiting_bcn)) + return false; + } + + return true; +} + static void ieee80211_sta_bcn_mon_timer(struct timer_list *t) { struct ieee80211_sub_if_data *sdata = timer_container_of(sdata, t, u.mgd.bcn_mon_timer); - if (WARN_ON(ieee80211_vif_is_mld(&sdata->vif))) - return; - - if (sdata->vif.bss_conf.csa_active && - !sdata->deflink.u.mgd.csa.waiting_bcn) + if (ieee80211_is_csa_in_progress(sdata)) return; if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER) From 1bc892d76a6f8778945eaa44af4e7f95faf5fbd4 Mon Sep 17 00:00:00 2001 From: Maharaja Kennadyrajan Date: Fri, 18 Jul 2025 11:38:37 +0530 Subject: [PATCH 129/199] wifi: mac80211: extend connection monitoring for MLO Currently, reset connection monitor (ieee80211_sta_reset_conn_monitor()) timer is handled only for non-AP non-MLD STA and do not support non-AP MLD STA. The current implementation checks for the CSA active and update the monitor timer with the timeout value of deflink and reset the timer based on the deflink's timeout value else schedule the connection loss work when the deflink is timed out and it won't work for the non-AP MLD STA. Handle the reset connection monitor timer for non-AP MLD STA by updating the monitor timer with the timeout value which is determined based on the link that will expire last among all the links in MLO. If at least one link has not timed out, the timer is updated accordingly with the latest timeout value else schedule the connection loss work when all links have timed out. Remove the MLO-related WARN_ON() checks in the beacon and connection monitoring logic code paths as they support MLO now. Signed-off-by: Maharaja Kennadyrajan Link: https://patch.msgid.link/20250718060837.59371-5-maharaja.kennadyrajan@oss.qualcomm.com Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 76 +++++++++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 24 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 86b69bd94b4c..b4b7ea52c65e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4367,9 +4367,6 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) lockdep_assert_wiphy(sdata->local->hw.wiphy); - if (WARN_ON(ieee80211_vif_is_mld(&sdata->vif))) - return; - /* * Try sending broadcast probe requests for the last three * probe requests after the first ones failed since some @@ -4415,9 +4412,6 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, lockdep_assert_wiphy(sdata->local->hw.wiphy); - if (WARN_ON_ONCE(ieee80211_vif_is_mld(&sdata->vif))) - return; - if (!ieee80211_sdata_running(sdata)) return; @@ -8524,36 +8518,70 @@ static void ieee80211_sta_bcn_mon_timer(struct timer_list *t) &sdata->u.mgd.beacon_connection_loss_work); } +static unsigned long +ieee80211_latest_active_link_conn_timeout(struct ieee80211_sub_if_data *sdata) +{ + unsigned long latest_timeout; + unsigned int link_id; + struct sta_info *sta; + + guard(rcu)(); + + sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr); + if (!sta) + return 0; + + for (link_id = 0; link_id < ARRAY_SIZE(sta->link); + link_id++) { + struct link_sta_info *link_sta; + unsigned long timeout; + + link_sta = rcu_dereference(sta->link[link_id]); + if (!link_sta) + continue; + + timeout = link_sta->status_stats.last_ack; + if (time_before(timeout, link_sta->rx_stats.last_rx)) + timeout = link_sta->rx_stats.last_rx; + + timeout += IEEE80211_CONNECTION_IDLE_TIME; + + /* + * latest_timeout holds the timeout of the link + * that will expire last among all links in an + * non-AP MLD STA. This ensures that the connection + * monitor timer is only reset if at least one link + * is still active, and it is scheduled to fire at + * the latest possible timeout. + */ + if (time_is_after_jiffies(timeout) && + time_after(timeout, latest_timeout)) + latest_timeout = timeout; + } + + return latest_timeout; +} + static void ieee80211_sta_conn_mon_timer(struct timer_list *t) { struct ieee80211_sub_if_data *sdata = timer_container_of(sdata, t, u.mgd.conn_mon_timer); struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - struct sta_info *sta; - unsigned long timeout; + unsigned long latest_timeout; - if (WARN_ON(ieee80211_vif_is_mld(&sdata->vif))) + if (ieee80211_is_csa_in_progress(sdata)) return; - if (sdata->vif.bss_conf.csa_active && - !sdata->deflink.u.mgd.csa.waiting_bcn) - return; + latest_timeout = ieee80211_latest_active_link_conn_timeout(sdata); - sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr); - if (!sta) - return; - - timeout = sta->deflink.status_stats.last_ack; - if (time_before(sta->deflink.status_stats.last_ack, sta->deflink.rx_stats.last_rx)) - timeout = sta->deflink.rx_stats.last_rx; - timeout += IEEE80211_CONNECTION_IDLE_TIME; - - /* If timeout is after now, then update timer to fire at + /* + * If latest timeout is after now, then update timer to fire at * the later date, but do not actually probe at this time. */ - if (time_is_after_jiffies(timeout)) { - mod_timer(&ifmgd->conn_mon_timer, round_jiffies_up(timeout)); + if (latest_timeout) { + mod_timer(&ifmgd->conn_mon_timer, + round_jiffies_up(latest_timeout)); return; } From 81284e86bf8849f8e98e8ead3ff5811926b2107f Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 15 Jul 2025 19:45:23 -0700 Subject: [PATCH 130/199] wifi: brcmsmac: Remove const from tbl_ptr parameter in wlc_lcnphy_common_read_table() A new warning in clang [1] complains that diq_start in wlc_lcnphy_tx_iqlo_cal() is passed uninitialized as a const pointer to wlc_lcnphy_common_read_table(): drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c:2728:13: error: variable 'diq_start' is uninitialized when passed as a const pointer argument here [-Werror,-Wuninitialized-const-pointer] 2728 | &diq_start, 1, 16, 69); | ^~~~~~~~~ The table pointer passed to wlc_lcnphy_common_read_table() should not be considered constant, as wlc_phy_read_table() is ultimately going to update it. Remove the const qualifier from the tbl_ptr to clear up the warning. Cc: stable@vger.kernel.org Closes: https://github.com/ClangBuiltLinux/linux/issues/2108 Fixes: 5b435de0d786 ("net: wireless: add brcm80211 drivers") Link: https://github.com/llvm/llvm-project/commit/00dacf8c22f065cb52efb14cd091d441f19b319e [1] Signed-off-by: Nathan Chancellor Acked-by: Arend van Spriel > Link: https://patch.msgid.link/20250715-brcmsmac-fix-uninit-const-pointer-v1-1-16e6a51a8ef4@kernel.org Signed-off-by: Johannes Berg --- drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c index d0faba240561..b4bba67a45ec 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c @@ -919,7 +919,7 @@ void wlc_lcnphy_read_table(struct brcms_phy *pi, struct phytbl_info *pti) static void wlc_lcnphy_common_read_table(struct brcms_phy *pi, u32 tbl_id, - const u16 *tbl_ptr, u32 tbl_len, + u16 *tbl_ptr, u32 tbl_len, u32 tbl_width, u32 tbl_offset) { struct phytbl_info tab; From 16ecdab5446f15a61ec88eb0d23d25d009821db0 Mon Sep 17 00:00:00 2001 From: Moon Hee Lee Date: Tue, 15 Jul 2025 16:09:05 -0700 Subject: [PATCH 131/199] wifi: mac80211: reject TDLS operations when station is not associated syzbot triggered a WARN in ieee80211_tdls_oper() by sending NL80211_TDLS_ENABLE_LINK immediately after NL80211_CMD_CONNECT, before association completed and without prior TDLS setup. This left internal state like sdata->u.mgd.tdls_peer uninitialized, leading to a WARN_ON() in code paths that assumed it was valid. Reject the operation early if not in station mode or not associated. Reported-by: syzbot+f73f203f8c9b19037380@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=f73f203f8c9b19037380 Fixes: 81dd2b882241 ("mac80211: move TDLS data to mgd private part") Tested-by: syzbot+f73f203f8c9b19037380@syzkaller.appspotmail.com Signed-off-by: Moon Hee Lee Link: https://patch.msgid.link/20250715230904.661092-2-moonhee.lee.ca@gmail.com Signed-off-by: Johannes Berg --- net/mac80211/tdls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 94714f8ffd22..ba5fbacbeeda 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -1422,7 +1422,7 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) return -EOPNOTSUPP; - if (sdata->vif.type != NL80211_IFTYPE_STATION) + if (sdata->vif.type != NL80211_IFTYPE_STATION || !sdata->vif.cfg.assoc) return -EINVAL; switch (oper) { From 6d0a67c600a61c42308e8b78864492752c4f69a2 Mon Sep 17 00:00:00 2001 From: WangYuli Date: Tue, 15 Jul 2025 21:44:04 +0800 Subject: [PATCH 132/199] wifi: brcmfmac: Fix typo "notifer" There is a spelling mistake of 'notifer' in the comment which should be 'notifier'. Signed-off-by: WangYuli Acked-by: Arend van Spriel > Link: https://patch.msgid.link/F92035B0A9123150+20250715134407.540483-5-wangyuli@uniontech.com [remove prior link] Signed-off-by: Johannes Berg --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 40a9a8177de6..a324bfec0b69 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -8330,7 +8330,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, cfg->d11inf.io_type = (u8)io_type; brcmu_d11_attach(&cfg->d11inf); - /* regulatory notifer below needs access to cfg so + /* regulatory notifier below needs access to cfg so * assign it now. */ drvr->config = cfg; From b60c49590a1e268305d1da4f8593d2b54468b6c4 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Tue, 15 Jul 2025 20:16:50 +0800 Subject: [PATCH 133/199] wifi: brcm80211: Use min() to improve code Use min() to reduce the code and improve its readability. Signed-off-by: Qianfeng Rong Acked-by: Arend van Spriel > Link: https://patch.msgid.link/20250715121721.266713-5-rongqianfeng@vivo.com Signed-off-by: Johannes Berg --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 5 +---- .../net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c | 6 ++---- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c index b056336d5da6..f0129d10d2b9 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c @@ -927,10 +927,7 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen) /* Wait until the usb device reports it received all * the bytes we sent */ if ((rdlbytes == sent) && (rdlbytes != dllen)) { - if ((dllen-sent) < TRX_RDL_CHUNK) - sendlen = dllen-sent; - else - sendlen = TRX_RDL_CHUNK; + sendlen = min(dllen - sent, TRX_RDL_CHUNK); /* simply avoid having to send a ZLP by ensuring we * never have an even diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c index d362c4337616..b679821c7f99 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c @@ -25825,10 +25825,8 @@ wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain, if (mphase) { cal_cnt = pi->mphase_txcal_cmdidx; - if ((cal_cnt + pi->mphase_txcal_numcmds) < max_cal_cmds) - num_cals = cal_cnt + pi->mphase_txcal_numcmds; - else - num_cals = max_cal_cmds; + num_cals = min(cal_cnt + pi->mphase_txcal_numcmds, + max_cal_cmds); } else { cal_cnt = 0; num_cals = max_cal_cmds; From 37fa920819363254d0701c6f3693a81538f99b2e Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Tue, 15 Jul 2025 20:16:51 +0800 Subject: [PATCH 134/199] wifi: mwifiex: Use max_t() to improve code Use max_t() to reduce the code and improve its readability. Signed-off-by: Qianfeng Rong Reviewed-by: Jeff Chen Link: https://patch.msgid.link/20250715121721.266713-6-rongqianfeng@vivo.com Signed-off-by: Johannes Berg --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 286378770e9e..3498743d5ec0 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -4783,10 +4783,9 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta; wiphy->n_iface_combinations = 1; - if (adapter->max_sta_conn > adapter->max_p2p_conn) - wiphy->max_ap_assoc_sta = adapter->max_sta_conn; - else - wiphy->max_ap_assoc_sta = adapter->max_p2p_conn; + wiphy->max_ap_assoc_sta = max_t(typeof(wiphy->max_ap_assoc_sta), + adapter->max_sta_conn, + adapter->max_p2p_conn); /* Initialize cipher suits */ wiphy->cipher_suites = mwifiex_cipher_suites; From 219cbc4d713e26792e93dda596f6e972583aa173 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Tue, 15 Jul 2025 20:16:52 +0800 Subject: [PATCH 135/199] wifi: wilc1000: Use min() to improve code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use min() to reduce the code and improve its readability. Reviewed-by: Alexis Lothoré Signed-off-by: Qianfeng Rong Link: https://patch.msgid.link/20250715121721.266713-7-rongqianfeng@vivo.com Signed-off-by: Johannes Berg --- drivers/net/wireless/microchip/wilc1000/wlan.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c index 9d80adc45d6b..fedc7d59216a 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.c +++ b/drivers/net/wireless/microchip/wilc1000/wlan.c @@ -1287,10 +1287,7 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, offset += 8; while (((int)size) && (offset < buffer_size)) { - if (size <= blksz) - size2 = size; - else - size2 = blksz; + size2 = min(size, blksz); memcpy(dma_buffer, &buffer[offset], size2); ret = wilc->hif_func->hif_block_tx(wilc, addr, From 78e50d88998a4a634eeda3e0d136cb8b9c9bc9d8 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 12 Jul 2025 18:53:07 -0300 Subject: [PATCH 136/199] wifi: brcmfmac: Add support for the SDIO 43751 device Add the SDIO ID and firmware matching for the 43751 device. Based on the previous work from Marc Gonzalez . Tested on an i.MX6DL board connected to an AP6398SV chip with the brcmfmac43752-sdio.bin firmware taken from: https://source.puri.sm/Librem5/firmware-brcm43752-nonfree Signed-off-by: Fabio Estevam Acked-by: Arend van Spriel > Link: https://patch.msgid.link/20250712215307.1310802-1-festevam@gmail.com Signed-off-by: Johannes Berg --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 1 + drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 2 ++ drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 5 ++++- .../net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h | 1 + include/linux/mmc/sdio_ids.h | 1 + 5 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index 6bc107476a2a..8ab7d1e34a6e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -996,6 +996,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354, WCC), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4356, WCC), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4359, WCC), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43751, WCC), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373, CYW), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43012, CYW), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43752, CYW), diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c index 2ef92ef25517..9074ab49e806 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c @@ -739,6 +739,7 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci) case CY_CC_4373_CHIP_ID: return 0x160000; case CY_CC_43752_CHIP_ID: + case BRCM_CC_43751_CHIP_ID: case BRCM_CC_4377_CHIP_ID: return 0x170000; case BRCM_CC_4378_CHIP_ID: @@ -1450,6 +1451,7 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub) reg = chip->ops->read32(chip->ctx, addr); return (reg & CC_SR_CTL0_ENABLE_MASK) != 0; case BRCM_CC_4359_CHIP_ID: + case BRCM_CC_43751_CHIP_ID: case CY_CC_43752_CHIP_ID: case CY_CC_43012_CHIP_ID: addr = CORE_CC_REG(pmu->base, retention_ctl); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index cf26ab15ee0c..8a0bad5119a0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -654,6 +654,7 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354), BRCMF_FW_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356), BRCMF_FW_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359), + BRCMF_FW_ENTRY(BRCM_CC_43751_CHIP_ID, 0xFFFFFFFF, 43752), BRCMF_FW_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373), BRCMF_FW_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012), BRCMF_FW_ENTRY(CY_CC_43439_CHIP_ID, 0xFFFFFFFF, 43439), @@ -3424,7 +3425,8 @@ err: static bool brcmf_sdio_aos_no_decode(struct brcmf_sdio *bus) { - if (bus->ci->chip == CY_CC_43012_CHIP_ID || + if (bus->ci->chip == BRCM_CC_43751_CHIP_ID || + bus->ci->chip == CY_CC_43012_CHIP_ID || bus->ci->chip == CY_CC_43752_CHIP_ID) return true; else @@ -4275,6 +4277,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, bus->hostintmask, NULL); switch (sdiod->func1->device) { + case SDIO_DEVICE_ID_BROADCOM_43751: case SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373: case SDIO_DEVICE_ID_BROADCOM_CYPRESS_43752: brcmf_dbg(INFO, "set F2 watermark to 0x%x*4 bytes\n", diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h index c1e22c589d85..6564616a57df 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h @@ -52,6 +52,7 @@ #define BRCM_CC_43664_CHIP_ID 43664 #define BRCM_CC_43666_CHIP_ID 43666 #define BRCM_CC_4371_CHIP_ID 0x4371 +#define BRCM_CC_43751_CHIP_ID 43751 #define BRCM_CC_43752_CHIP_ID 43752 #define BRCM_CC_4377_CHIP_ID 0x4377 #define BRCM_CC_4378_CHIP_ID 0x4378 diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index 7cddfdac2f57..fe3d6d98f8da 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -76,6 +76,7 @@ #define SDIO_DEVICE_ID_BROADCOM_43430 0xa9a6 #define SDIO_DEVICE_ID_BROADCOM_43439 0xa9af #define SDIO_DEVICE_ID_BROADCOM_43455 0xa9bf +#define SDIO_DEVICE_ID_BROADCOM_43751 0xaae7 #define SDIO_DEVICE_ID_BROADCOM_CYPRESS_43752 0xaae8 #define SDIO_VENDOR_ID_CYPRESS 0x04b4 From 6624a0af82a6e3a4d3609264ef591a8fa3467139 Mon Sep 17 00:00:00 2001 From: Lachlan Hodges Date: Thu, 17 Jul 2025 17:42:02 +1000 Subject: [PATCH 137/199] wifi: cfg80211: support configuring an S1G short beaconing BSS S1G short beacons are an optional frame type used in an S1G BSS that contain a limited set of elements. While they are optional, they are a fundamental part of S1G that enables significant power saving. Expose 2 additional netlink attributes, NL80211_ATTR_S1G_LONG_BEACON_PERIOD which denotes the number of beacon intervals between each long beacon and NL80211_ATTR_S1G_SHORT_BEACON which is a nested attribute containing the short beacon tail and head. We split them as the long beacon period cannot be updated, and is only used when initialisng the interface, whereas the short beacon data can be used to both initialise and update the templates. This follows how things such as the beacon interval and DTIM period currently operate. During the initialisation path, we ensure we have the long beacon period if the short beacon data is being passed down, whereas the update path will simply update the template if its sent down. The short beacon data is validated using the same routines for regular beacons as they support correctly parsing the short beacon format while ensuring the frame is well-formed. Signed-off-by: Lachlan Hodges Link: https://patch.msgid.link/20250717074205.312577-2-lachlan.hodges@morsemicro.com Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 23 ++++++++++++ include/uapi/linux/nl80211.h | 39 +++++++++++++++++++ net/wireless/nl80211.c | 72 ++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 17f2a665dce6..44a1055a81ba 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1423,6 +1423,23 @@ struct cfg80211_unsol_bcast_probe_resp { const u8 *tmpl; }; +/** + * struct cfg80211_s1g_short_beacon - S1G short beacon data. + * + * @update: Set to true if the feature configuration should be updated. + * @short_head: Short beacon head. + * @short_tail: Short beacon tail. + * @short_head_len: Short beacon head len. + * @short_tail_len: Short beacon tail len. + */ +struct cfg80211_s1g_short_beacon { + bool update; + const u8 *short_head; + const u8 *short_tail; + size_t short_head_len; + size_t short_tail_len; +}; + /** * struct cfg80211_ap_settings - AP configuration * @@ -1463,6 +1480,8 @@ struct cfg80211_unsol_bcast_probe_resp { * @fils_discovery: FILS discovery transmission parameters * @unsol_bcast_probe_resp: Unsolicited broadcast probe response parameters * @mbssid_config: AP settings for multiple bssid + * @s1g_long_beacon_period: S1G long beacon period + * @s1g_short_beacon: S1G short beacon data */ struct cfg80211_ap_settings { struct cfg80211_chan_def chandef; @@ -1496,6 +1515,8 @@ struct cfg80211_ap_settings { struct cfg80211_fils_discovery fils_discovery; struct cfg80211_unsol_bcast_probe_resp unsol_bcast_probe_resp; struct cfg80211_mbssid_config mbssid_config; + u8 s1g_long_beacon_period; + struct cfg80211_s1g_short_beacon s1g_short_beacon; }; @@ -1507,11 +1528,13 @@ struct cfg80211_ap_settings { * @beacon: beacon data * @fils_discovery: FILS discovery transmission parameters * @unsol_bcast_probe_resp: Unsolicited broadcast probe response parameters + * @s1g_short_beacon: S1G short beacon data */ struct cfg80211_ap_update { struct cfg80211_beacon_data beacon; struct cfg80211_fils_discovery fils_discovery; struct cfg80211_unsol_bcast_probe_resp unsol_bcast_probe_resp; + struct cfg80211_s1g_short_beacon s1g_short_beacon; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 39460334dafb..d1a14f2892d9 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2915,6 +2915,19 @@ enum nl80211_commands { * applicable to that specific radio only. If the radio id is greater * thank the number of radios, error denoting invalid value is returned. * + * @NL80211_ATTR_S1G_LONG_BEACON_PERIOD: (u8) Integer attribute that represents + * the number of beacon intervals between each long beacon transmission + * for an S1G BSS with short beaconing enabled. This is a required + * attribute for initialising an S1G short beaconing BSS. When updating + * the short beacon data, this is not required. It has a minimum value of + * 2 (i.e 2 beacon intervals). + * + * @NL80211_ATTR_S1G_SHORT_BEACON: Nested attribute containing the short beacon + * head and tail used to set or update the short beacon templates. When + * bringing up a new interface, %NL80211_ATTR_S1G_LONG_BEACON_PERIOD is + * required alongside this attribute. Refer to + * @enum nl80211_s1g_short_beacon_attrs for the attribute definitions. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -3474,6 +3487,9 @@ enum nl80211_attrs { NL80211_ATTR_WIPHY_RADIO_INDEX, + NL80211_ATTR_S1G_LONG_BEACON_PERIOD, + NL80211_ATTR_S1G_SHORT_BEACON, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -8148,4 +8164,27 @@ enum nl80211_wiphy_radio_freq_range { NL80211_WIPHY_RADIO_FREQ_ATTR_MAX = __NL80211_WIPHY_RADIO_FREQ_ATTR_LAST - 1, }; +/** + * enum nl80211_s1g_short_beacon_attrs - S1G short beacon data + * + * @__NL80211_S1G_SHORT_BEACON_ATTR_INVALID: Invalid + * + * @NL80211_S1G_SHORT_BEACON_ATTR_HEAD: Short beacon head (binary). + * @NL80211_S1G_SHORT_BEACON_ATTR_TAIL: Short beacon tail (binary). + * + * @__NL80211_S1G_SHORT_BEACON_ATTR_LAST: Internal + * @NL80211_S1G_SHORT_BEACON_ATTR_MAX: Highest attribute + */ +enum nl80211_s1g_short_beacon_attrs { + __NL80211_S1G_SHORT_BEACON_ATTR_INVALID, + + NL80211_S1G_SHORT_BEACON_ATTR_HEAD, + NL80211_S1G_SHORT_BEACON_ATTR_TAIL, + + /* keep last */ + __NL80211_S1G_SHORT_BEACON_ATTR_LAST, + NL80211_S1G_SHORT_BEACON_ATTR_MAX = + __NL80211_S1G_SHORT_BEACON_ATTR_LAST - 1 +}; + #endif /* __LINUX_NL80211_H */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 20bc0f052c16..1c808b08b747 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -482,6 +482,16 @@ nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] = { [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, }; +static const struct nla_policy +nl80211_s1g_short_beacon[NL80211_S1G_SHORT_BEACON_ATTR_MAX + 1] = { + [NL80211_S1G_SHORT_BEACON_ATTR_HEAD] = + NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_beacon_head, + IEEE80211_MAX_DATA_LEN), + [NL80211_S1G_SHORT_BEACON_ATTR_TAIL] = + NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr, + IEEE80211_MAX_DATA_LEN), +}; + static const struct netlink_range_validation nl80211_punct_bitmap_range = { .min = 0, .max = 0xffff, @@ -858,6 +868,9 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_EPCS] = { .type = NLA_FLAG }, [NL80211_ATTR_ASSOC_MLD_EXT_CAPA_OPS] = { .type = NLA_U16 }, [NL80211_ATTR_WIPHY_RADIO_INDEX] = { .type = NLA_U8 }, + [NL80211_ATTR_S1G_LONG_BEACON_PERIOD] = NLA_POLICY_MIN(NLA_U8, 2), + [NL80211_ATTR_S1G_SHORT_BEACON] = + NLA_POLICY_NESTED(nl80211_s1g_short_beacon), }; /* policy for the key attributes */ @@ -6202,6 +6215,41 @@ static int nl80211_validate_ap_phy_operation(struct cfg80211_ap_settings *params return 0; } +static int +nl80211_parse_s1g_short_beacon(struct cfg80211_registered_device *rdev, + struct nlattr *attrs, + struct cfg80211_s1g_short_beacon *sb) +{ + struct nlattr *tb[NL80211_S1G_SHORT_BEACON_ATTR_MAX + 1]; + int ret; + + if (!rdev->wiphy.bands[NL80211_BAND_S1GHZ]) + return -EINVAL; + + ret = nla_parse_nested(tb, NL80211_S1G_SHORT_BEACON_ATTR_MAX, attrs, + NULL, NULL); + if (ret) + return ret; + + /* Short beacon tail is optional (i.e might only include the TIM) */ + if (!tb[NL80211_S1G_SHORT_BEACON_ATTR_HEAD]) + return -EINVAL; + + sb->short_head = nla_data(tb[NL80211_S1G_SHORT_BEACON_ATTR_HEAD]); + sb->short_head_len = nla_len(tb[NL80211_S1G_SHORT_BEACON_ATTR_HEAD]); + sb->short_tail_len = 0; + + if (tb[NL80211_S1G_SHORT_BEACON_ATTR_TAIL]) { + sb->short_tail = + nla_data(tb[NL80211_S1G_SHORT_BEACON_ATTR_TAIL]); + sb->short_tail_len = + nla_len(tb[NL80211_S1G_SHORT_BEACON_ATTR_TAIL]); + } + + sb->update = true; + return 0; +} + static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; @@ -6442,6 +6490,22 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) goto out; } + if (info->attrs[NL80211_ATTR_S1G_SHORT_BEACON]) { + if (!info->attrs[NL80211_ATTR_S1G_LONG_BEACON_PERIOD]) { + err = -EINVAL; + goto out; + } + + params->s1g_long_beacon_period = nla_get_u8( + info->attrs[NL80211_ATTR_S1G_LONG_BEACON_PERIOD]); + + err = nl80211_parse_s1g_short_beacon( + rdev, info->attrs[NL80211_ATTR_S1G_SHORT_BEACON], + ¶ms->s1g_short_beacon); + if (err) + goto out; + } + err = nl80211_calculate_ap_params(params); if (err) goto out; @@ -6550,6 +6614,14 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info) goto out; } + attr = info->attrs[NL80211_ATTR_S1G_SHORT_BEACON]; + if (attr) { + err = nl80211_parse_s1g_short_beacon(rdev, attr, + ¶ms->s1g_short_beacon); + if (err) + goto out; + } + err = rdev_change_beacon(rdev, dev, params); out: From bbf93a06d73505591db3a93797f44b9c44555d9b Mon Sep 17 00:00:00 2001 From: Lachlan Hodges Date: Thu, 17 Jul 2025 17:42:03 +1000 Subject: [PATCH 138/199] wifi: mac80211: support initialising an S1G short beaconing BSS Introduce the ability to parse the short beacon data and long beacon period. The long beacon period represents the number of beacon intervals between each long beacon transmission. Additionally, as a BSS cannot change its configuration such that short beaconing is dynamically disabled/enabled without tearing down the interface - we ensure we have an existing short beacon before performing the update. Signed-off-by: Lachlan Hodges Link: https://patch.msgid.link/20250717074205.312577-3-lachlan.hodges@morsemicro.com Signed-off-by: Johannes Berg --- include/net/mac80211.h | 4 +++ net/mac80211/cfg.c | 66 ++++++++++++++++++++++++++++++++++++-- net/mac80211/ieee80211_i.h | 9 ++++++ 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 577fd6a8c372..a2dbaad2f6d3 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -758,6 +758,8 @@ struct ieee80211_parsed_tpe { * be updated to 1, even if bss_param_ch_cnt didn't change. This allows * the link to know that it heard the latest value from its own beacon * (as opposed to hearing its value from another link's beacon). + * @s1g_long_beacon_period: number of beacon intervals between each long + * beacon transmission. */ struct ieee80211_bss_conf { struct ieee80211_vif *vif; @@ -857,6 +859,8 @@ struct ieee80211_bss_conf { u8 bss_param_ch_cnt; u8 bss_param_ch_cnt_link_id; + + u8 s1g_long_beacon_period; }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index b99e39cb808b..2f97e2d5bb8b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1071,6 +1071,47 @@ ieee80211_set_unsol_bcast_probe_resp(struct ieee80211_sub_if_data *sdata, return 0; } +static int +ieee80211_set_s1g_short_beacon(struct ieee80211_sub_if_data *sdata, + struct ieee80211_link_data *link, + struct cfg80211_s1g_short_beacon *params) +{ + struct s1g_short_beacon_data *new; + struct s1g_short_beacon_data *old = + sdata_dereference(link->u.ap.s1g_short_beacon, sdata); + size_t new_len = + sizeof(*new) + params->short_head_len + params->short_tail_len; + + if (!params->update) + return 0; + + if (!params->short_head) + return -EINVAL; + + new = kzalloc(new_len, GFP_KERNEL); + if (!new) + return -ENOMEM; + + /* Memory layout: | struct | head | tail | */ + new->short_head = (u8 *)new + sizeof(*new); + new->short_head_len = params->short_head_len; + memcpy(new->short_head, params->short_head, params->short_head_len); + + if (params->short_tail) { + new->short_tail = new->short_head + params->short_head_len; + new->short_tail_len = params->short_tail_len; + memcpy(new->short_tail, params->short_tail, + params->short_tail_len); + } + + rcu_assign_pointer(link->u.ap.s1g_short_beacon, new); + + if (old) + kfree_rcu(old, rcu_head); + + return 0; +} + static int ieee80211_set_ftm_responder_params( struct ieee80211_sub_if_data *sdata, const u8 *lci, size_t lci_len, @@ -1493,8 +1534,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, link_conf->twt_responder = params->twt_responder; link_conf->he_obss_pd = params->he_obss_pd; link_conf->he_bss_color = params->beacon.he_bss_color; - sdata->vif.cfg.s1g = params->chandef.chan->band == - NL80211_BAND_S1GHZ; + link_conf->s1g_long_beacon_period = params->s1g_long_beacon_period; + sdata->vif.cfg.s1g = params->chandef.chan->band == NL80211_BAND_S1GHZ; sdata->vif.cfg.ssid_len = params->ssid_len; if (params->ssid_len) @@ -1541,6 +1582,13 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, if (err < 0) goto error; + if (sdata->vif.cfg.s1g) { + err = ieee80211_set_s1g_short_beacon(sdata, link, + ¶ms->s1g_short_beacon); + if (err < 0) + goto error; + } + err = drv_start_ap(sdata->local, sdata, link_conf); if (err) { old = sdata_dereference(link->u.ap.beacon, sdata); @@ -1619,6 +1667,13 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, if (err < 0) return err; + if (link->u.ap.s1g_short_beacon) { + err = ieee80211_set_s1g_short_beacon(sdata, link, + ¶ms->s1g_short_beacon); + if (err < 0) + return err; + } + if (beacon->he_bss_color_valid && beacon->he_bss_color.enabled != link_conf->he_bss_color.enabled) { link_conf->he_bss_color.enabled = beacon->he_bss_color.enabled; @@ -1650,6 +1705,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, struct probe_resp *old_probe_resp; struct fils_discovery_data *old_fils_discovery; struct unsol_bcast_probe_resp_data *old_unsol_bcast_probe_resp; + struct s1g_short_beacon_data *old_s1g_short_beacon; struct cfg80211_chan_def chandef; struct ieee80211_link_data *link = sdata_dereference(sdata->link[link_id], sdata); @@ -1668,6 +1724,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, old_unsol_bcast_probe_resp = sdata_dereference(link->u.ap.unsol_bcast_probe_resp, sdata); + old_s1g_short_beacon = + sdata_dereference(link->u.ap.s1g_short_beacon, sdata); /* abort any running channel switch or color change */ link_conf->csa_active = false; @@ -1690,6 +1748,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, RCU_INIT_POINTER(link->u.ap.probe_resp, NULL); RCU_INIT_POINTER(link->u.ap.fils_discovery, NULL); RCU_INIT_POINTER(link->u.ap.unsol_bcast_probe_resp, NULL); + RCU_INIT_POINTER(link->u.ap.s1g_short_beacon, NULL); kfree_rcu(old_beacon, rcu_head); if (old_probe_resp) kfree_rcu(old_probe_resp, rcu_head); @@ -1697,6 +1756,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, kfree_rcu(old_fils_discovery, rcu_head); if (old_unsol_bcast_probe_resp) kfree_rcu(old_unsol_bcast_probe_resp, rcu_head); + if (old_s1g_short_beacon) + kfree_rcu(old_s1g_short_beacon, rcu_head); kfree(link_conf->ftmr_params); link_conf->ftmr_params = NULL; @@ -1720,6 +1781,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, link_conf->enable_beacon = false; sdata->beacon_rate_set = false; sdata->vif.cfg.ssid_len = 0; + sdata->vif.cfg.s1g = false; clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); ieee80211_link_info_change_notify(sdata, link, BSS_CHANGED_BEACON_ENABLED); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9c0603eb580f..61cd1cc098ac 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -296,6 +296,14 @@ struct unsol_bcast_probe_resp_data { u8 data[]; }; +struct s1g_short_beacon_data { + struct rcu_head rcu_head; + u8 *short_head; + u8 *short_tail; + int short_head_len; + int short_tail_len; +}; + struct ps_data { /* yes, this looks ugly, but guarantees that we can later use * bitmap_empty :) @@ -1042,6 +1050,7 @@ struct ieee80211_link_data_ap { struct probe_resp __rcu *probe_resp; struct fils_discovery_data __rcu *fils_discovery; struct unsol_bcast_probe_resp_data __rcu *unsol_bcast_probe_resp; + struct s1g_short_beacon_data __rcu *s1g_short_beacon; /* to be used after channel switch. */ struct cfg80211_beacon_data *next_beacon; From 2758b703a9b389158964b3ae6ca171b66bfc883c Mon Sep 17 00:00:00 2001 From: Lachlan Hodges Date: Thu, 17 Jul 2025 17:42:04 +1000 Subject: [PATCH 139/199] wifi: mac80211: support initialising current S1G short beacon index Introduce the sb_count variable which tracks the number of beacon intervals until the next long beacon. To initialise this value, we find the current short beacon index into this period which represents the number of short beacons left to send before the next long beacon. We use the same TSF value used to initialise the DTIM count to ensure the short beacon count and DTIM count are in sync as its common for the long beacon period and DTIM period to be equivalent. Signed-off-by: Lachlan Hodges Link: https://patch.msgid.link/20250717074205.312577-4-lachlan.hodges@morsemicro.com Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 8 +++++++- net/mac80211/debugfs_netdev.c | 2 +- net/mac80211/ieee80211_i.h | 6 +++--- net/mac80211/mesh.c | 2 +- net/mac80211/util.c | 31 ++++++++++++++++++++++++++++--- 5 files changed, 40 insertions(+), 9 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 2f97e2d5bb8b..4f20d57ab913 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1382,6 +1382,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_link_data *link; struct ieee80211_bss_conf *link_conf; struct ieee80211_chan_req chanreq = { .oper = params->chandef }; + u64 tsf; lockdep_assert_wiphy(local->hw.wiphy); @@ -1603,7 +1604,12 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, goto error; } - ieee80211_recalc_dtim(local, sdata); + tsf = drv_get_tsf(local, sdata); + ieee80211_recalc_dtim(sdata, tsf); + + if (link->u.ap.s1g_short_beacon) + ieee80211_recalc_sb_count(sdata, tsf); + ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_SSID); ieee80211_link_info_change_notify(sdata, link, changed); diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 54c479910d05..1dac78271045 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -704,7 +704,7 @@ static ssize_t ieee80211_if_parse_tsf( } } - ieee80211_recalc_dtim(local, sdata); + ieee80211_recalc_dtim(sdata, drv_get_tsf(local, sdata)); return buflen; } IEEE80211_IF_FILE_RW(tsf); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 61cd1cc098ac..8afa2404eaa8 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -314,6 +314,7 @@ struct ps_data { atomic_t num_sta_ps; /* number of stations in PS mode */ int dtim_count; bool dtim_bc_mc; + int sb_count; /* num short beacons til next long beacon */ }; struct ieee80211_if_ap { @@ -2774,9 +2775,8 @@ void ieee80211_dfs_radar_detected_work(struct wiphy *wiphy, struct wiphy_work *work); int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, struct cfg80211_csa_settings *csa_settings); - -void ieee80211_recalc_dtim(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata); +void ieee80211_recalc_sb_count(struct ieee80211_sub_if_data *sdata, u64 tsf); +void ieee80211_recalc_dtim(struct ieee80211_sub_if_data *sdata, u64 tsf); int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, const struct cfg80211_chan_def *chandef, enum ieee80211_chanctx_mode chanmode, diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index d00d9d413c5c..a4a715f6f1c3 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1202,7 +1202,7 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) return -ENOMEM; } - ieee80211_recalc_dtim(local, sdata); + ieee80211_recalc_dtim(sdata, drv_get_tsf(local, sdata)); ieee80211_link_info_change_notify(sdata, &sdata->deflink, changed); netif_carrier_on(sdata->dev); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 0d85a382746f..32f1bc5908c5 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -3913,10 +3913,8 @@ int ieee80211_parse_p2p_noa(const struct ieee80211_p2p_noa_attr *attr, } EXPORT_SYMBOL(ieee80211_parse_p2p_noa); -void ieee80211_recalc_dtim(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata) +void ieee80211_recalc_dtim(struct ieee80211_sub_if_data *sdata, u64 tsf) { - u64 tsf = drv_get_tsf(local, sdata); u64 dtim_count = 0; u32 beacon_int = sdata->vif.bss_conf.beacon_int * 1024; u8 dtim_period = sdata->vif.bss_conf.dtim_period; @@ -3954,6 +3952,33 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local, ps->dtim_count = dtim_count; } +/* + * Given a long beacon period, calculate the current index into + * that period to determine the number of TSBTTs until the next TBTT. + * It is completely valid to have a short beacon period that differs + * from the dtim period (i.e a TBTT thats not a DTIM). + */ +void ieee80211_recalc_sb_count(struct ieee80211_sub_if_data *sdata, u64 tsf) +{ + u32 sb_idx; + struct ps_data *ps = &sdata->bss->ps; + u8 lb_period = sdata->vif.bss_conf.s1g_long_beacon_period; + u32 beacon_int = sdata->vif.bss_conf.beacon_int * 1024; + + /* No mesh / IBSS support for short beaconing */ + if (tsf == -1ULL || !lb_period || + (sdata->vif.type != NL80211_IFTYPE_AP && + sdata->vif.type != NL80211_IFTYPE_AP_VLAN)) + return; + + /* find the current TSBTT index in our lb_period */ + do_div(tsf, beacon_int); + sb_idx = do_div(tsf, lb_period); + + /* num TSBTTs until the next TBTT */ + ps->sb_count = sb_idx ? lb_period - sb_idx : 0; +} + static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local, struct ieee80211_chanctx *ctx) { From f8bf97ad19c48f5e66cf99bd390356ffa1189d62 Mon Sep 17 00:00:00 2001 From: Lachlan Hodges Date: Thu, 17 Jul 2025 17:42:05 +1000 Subject: [PATCH 140/199] wifi: mac80211: support returning the S1G short beacon skb When short beaconing is enabled, check the value of the sb_count to determine whether we are to send a long beacon or short beacon. sb_count represents the number of short beacons until the next long beacon, where if its value is 0 we are to send a long beacon. The value is then reset to the long beacon period, which represents the number of beacon intervals between each long beacon. The decrement process follows the same cadence as the decrement of the DTIM count value. Signed-off-by: Lachlan Hodges Link: https://patch.msgid.link/20250717074205.312577-5-lachlan.hodges@morsemicro.com Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 95 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 84 insertions(+), 11 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 6fa883a9250d..f3a065313a31 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -5290,14 +5290,14 @@ ieee80211_beacon_add_mbssid(struct sk_buff *skb, struct beacon_data *beacon, } static struct sk_buff * -ieee80211_beacon_get_ap(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_link_data *link, - struct ieee80211_mutable_offsets *offs, - bool is_template, - struct beacon_data *beacon, - struct ieee80211_chanctx_conf *chanctx_conf, - u8 ema_index) +__ieee80211_beacon_get_ap(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_link_data *link, + struct ieee80211_mutable_offsets *offs, + bool is_template, + struct beacon_data *beacon, + struct ieee80211_chanctx_conf *chanctx_conf, + u8 ema_index) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); @@ -5358,6 +5358,71 @@ ieee80211_beacon_get_ap(struct ieee80211_hw *hw, return skb; } +static bool ieee80211_s1g_need_long_beacon(struct ieee80211_sub_if_data *sdata, + struct ieee80211_link_data *link) +{ + struct ps_data *ps = &sdata->u.ap.ps; + + if (ps->sb_count == 0) + ps->sb_count = link->conf->s1g_long_beacon_period - 1; + else + ps->sb_count--; + + return ps->sb_count == 0; +} + +static struct sk_buff * +ieee80211_s1g_short_beacon_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_link_data *link, + struct ieee80211_chanctx_conf *chanctx_conf, + struct s1g_short_beacon_data *sb, + bool is_template) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_if_ap *ap = &sdata->u.ap; + struct sk_buff *skb; + + skb = dev_alloc_skb(local->tx_headroom + sb->short_head_len + + sb->short_tail_len + 256 + + local->hw.extra_beacon_tailroom); + if (!skb) + return NULL; + + skb_reserve(skb, local->tx_headroom); + skb_put_data(skb, sb->short_head, sb->short_head_len); + + ieee80211_beacon_add_tim(sdata, link, &ap->ps, skb, is_template); + + if (sb->short_tail) + skb_put_data(skb, sb->short_tail, sb->short_tail_len); + + ieee80211_beacon_get_finish(hw, vif, link, NULL, NULL, skb, + chanctx_conf, 0); + return skb; +} + +static struct sk_buff * +ieee80211_beacon_get_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_link_data *link, + struct ieee80211_mutable_offsets *offs, + bool is_template, struct beacon_data *beacon, + struct ieee80211_chanctx_conf *chanctx_conf, + u8 ema_index, struct s1g_short_beacon_data *s1g_sb) +{ + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + + if (!sdata->vif.cfg.s1g || !s1g_sb || + ieee80211_s1g_need_long_beacon(sdata, link)) + return __ieee80211_beacon_get_ap(hw, vif, link, offs, + is_template, beacon, + chanctx_conf, ema_index); + + return ieee80211_s1g_short_beacon_get(hw, vif, link, chanctx_conf, + s1g_sb, is_template); +} + static struct ieee80211_ema_beacons * ieee80211_beacon_get_ap_ema_list(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -5381,7 +5446,7 @@ ieee80211_beacon_get_ap_ema_list(struct ieee80211_hw *hw, ieee80211_beacon_get_ap(hw, vif, link, &ema->bcn[ema->cnt].offs, is_template, beacon, - chanctx_conf, ema->cnt); + chanctx_conf, ema->cnt, NULL); if (!ema->bcn[ema->cnt].skb) break; } @@ -5410,6 +5475,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, struct ieee80211_sub_if_data *sdata = NULL; struct ieee80211_chanctx_conf *chanctx_conf; struct ieee80211_link_data *link; + struct s1g_short_beacon_data *s1g_short_bcn = NULL; rcu_read_lock(); @@ -5431,6 +5497,13 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, if (!beacon) goto out; + if (vif->cfg.s1g && link->u.ap.s1g_short_beacon) { + s1g_short_bcn = + rcu_dereference(link->u.ap.s1g_short_beacon); + if (!s1g_short_bcn) + goto out; + } + if (ema_beacons) { *ema_beacons = ieee80211_beacon_get_ap_ema_list(hw, vif, link, @@ -5451,8 +5524,8 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, skb = ieee80211_beacon_get_ap(hw, vif, link, offs, is_template, beacon, - chanctx_conf, - ema_index); + chanctx_conf, ema_index, + s1g_short_bcn); } } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; From 3fe79a25c3cd54d25d30bc235c0c57f8a123d9d5 Mon Sep 17 00:00:00 2001 From: Murad Masimov Date: Fri, 21 Mar 2025 21:52:26 +0300 Subject: [PATCH 141/199] wifi: plfxlc: Fix error handling in usb driver probe If probe fails before ieee80211_register_hw() is successfully done, ieee80211_unregister_hw() will be called anyway. This may lead to various bugs as the implementation of ieee80211_unregister_hw() assumes that ieee80211_register_hw() has been called. Divide error handling section into relevant subsections, so that ieee80211_unregister_hw() is called only when it is appropriate. Correct the order of the calls: ieee80211_unregister_hw() should go before plfxlc_mac_release(). Also move ieee80211_free_hw() to plfxlc_mac_release() as it supposed to be the opposite to plfxlc_mac_alloc_hw() that calls ieee80211_alloc_hw(). Found by Linux Verification Center (linuxtesting.org) with Syzkaller. Fixes: 68d57a07bfe5 ("wireless: add plfxlc driver for pureLiFi X, XL, XC devices") Signed-off-by: Murad Masimov Link: https://patch.msgid.link/20250321185226.71-3-m.masimov@mt-integration.ru Signed-off-by: Johannes Berg --- drivers/net/wireless/purelifi/plfxlc/mac.c | 11 ++++---- drivers/net/wireless/purelifi/plfxlc/mac.h | 2 +- drivers/net/wireless/purelifi/plfxlc/usb.c | 29 +++++++++++----------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/purelifi/plfxlc/mac.c b/drivers/net/wireless/purelifi/plfxlc/mac.c index d375ad60167f..a900421753ac 100644 --- a/drivers/net/wireless/purelifi/plfxlc/mac.c +++ b/drivers/net/wireless/purelifi/plfxlc/mac.c @@ -99,11 +99,6 @@ int plfxlc_mac_init_hw(struct ieee80211_hw *hw) return r; } -void plfxlc_mac_release(struct plfxlc_mac *mac) -{ - plfxlc_chip_release(&mac->chip); -} - int plfxlc_op_start(struct ieee80211_hw *hw) { plfxlc_hw_mac(hw)->chip.usb.initialized = 1; @@ -756,3 +751,9 @@ struct ieee80211_hw *plfxlc_mac_alloc_hw(struct usb_interface *intf) SET_IEEE80211_DEV(hw, &intf->dev); return hw; } + +void plfxlc_mac_release_hw(struct ieee80211_hw *hw) +{ + plfxlc_chip_release(&plfxlc_hw_mac(hw)->chip); + ieee80211_free_hw(hw); +} diff --git a/drivers/net/wireless/purelifi/plfxlc/mac.h b/drivers/net/wireless/purelifi/plfxlc/mac.h index 9384acddcf26..56da502999c1 100644 --- a/drivers/net/wireless/purelifi/plfxlc/mac.h +++ b/drivers/net/wireless/purelifi/plfxlc/mac.h @@ -168,7 +168,7 @@ static inline u8 *plfxlc_mac_get_perm_addr(struct plfxlc_mac *mac) } struct ieee80211_hw *plfxlc_mac_alloc_hw(struct usb_interface *intf); -void plfxlc_mac_release(struct plfxlc_mac *mac); +void plfxlc_mac_release_hw(struct ieee80211_hw *hw); int plfxlc_mac_preinit_hw(struct ieee80211_hw *hw, const u8 *hw_address); int plfxlc_mac_init_hw(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/purelifi/plfxlc/usb.c b/drivers/net/wireless/purelifi/plfxlc/usb.c index d8b0b79dea1a..711902a809db 100644 --- a/drivers/net/wireless/purelifi/plfxlc/usb.c +++ b/drivers/net/wireless/purelifi/plfxlc/usb.c @@ -604,7 +604,7 @@ static int probe(struct usb_interface *intf, r = plfxlc_upload_mac_and_serial(intf, hw_address, serial_number); if (r) { dev_err(&intf->dev, "MAC and Serial upload failed (%d)\n", r); - goto error; + goto error_free_hw; } chip->unit_type = STA; @@ -613,13 +613,13 @@ static int probe(struct usb_interface *intf, r = plfxlc_mac_preinit_hw(hw, hw_address); if (r) { dev_err(&intf->dev, "Init mac failed (%d)\n", r); - goto error; + goto error_free_hw; } r = ieee80211_register_hw(hw); if (r) { dev_err(&intf->dev, "Register device failed (%d)\n", r); - goto error; + goto error_free_hw; } if ((le16_to_cpu(interface_to_usbdev(intf)->descriptor.idVendor) == @@ -632,7 +632,7 @@ static int probe(struct usb_interface *intf, } if (r != 0) { dev_err(&intf->dev, "FPGA download failed (%d)\n", r); - goto error; + goto error_unreg_hw; } tx->mac_fifo_full = 0; @@ -642,21 +642,21 @@ static int probe(struct usb_interface *intf, r = plfxlc_usb_init_hw(usb); if (r < 0) { dev_err(&intf->dev, "usb_init_hw failed (%d)\n", r); - goto error; + goto error_unreg_hw; } msleep(PLF_MSLEEP_TIME); r = plfxlc_chip_switch_radio(chip, PLFXLC_RADIO_ON); if (r < 0) { dev_dbg(&intf->dev, "chip_switch_radio_on failed (%d)\n", r); - goto error; + goto error_unreg_hw; } msleep(PLF_MSLEEP_TIME); r = plfxlc_chip_set_rate(chip, 8); if (r < 0) { dev_dbg(&intf->dev, "chip_set_rate failed (%d)\n", r); - goto error; + goto error_unreg_hw; } msleep(PLF_MSLEEP_TIME); @@ -664,7 +664,7 @@ static int probe(struct usb_interface *intf, hw_address, ETH_ALEN, USB_REQ_MAC_WR); if (r < 0) { dev_dbg(&intf->dev, "MAC_WR failure (%d)\n", r); - goto error; + goto error_unreg_hw; } plfxlc_chip_enable_rxtx(chip); @@ -691,12 +691,12 @@ static int probe(struct usb_interface *intf, plfxlc_mac_init_hw(hw); usb->initialized = true; return 0; + +error_unreg_hw: + ieee80211_unregister_hw(hw); +error_free_hw: + plfxlc_mac_release_hw(hw); error: - if (hw) { - plfxlc_mac_release(plfxlc_hw_mac(hw)); - ieee80211_unregister_hw(hw); - ieee80211_free_hw(hw); - } dev_err(&intf->dev, "pureLifi:Device error"); return r; } @@ -730,8 +730,7 @@ static void disconnect(struct usb_interface *intf) */ usb_reset_device(interface_to_usbdev(intf)); - plfxlc_mac_release(mac); - ieee80211_free_hw(hw); + plfxlc_mac_release_hw(hw); } static void plfxlc_usb_resume(struct plfxlc_usb *usb) From 2c5dee15239f3f3e31aa5c8808f18996c039e2c1 Mon Sep 17 00:00:00 2001 From: Alexander Wetzel Date: Thu, 17 Jul 2025 18:25:45 +0200 Subject: [PATCH 142/199] wifi: cfg80211: Add missing lock in cfg80211_check_and_end_cac() Callers of wdev_chandef() must hold the wiphy mutex. But the worker cfg80211_propagate_cac_done_wk() never takes the lock. Which triggers the warning below with the mesh_peer_connected_dfs test from hostapd and not (yet) released mac80211 code changes: WARNING: CPU: 0 PID: 495 at net/wireless/chan.c:1552 wdev_chandef+0x60/0x165 Modules linked in: CPU: 0 UID: 0 PID: 495 Comm: kworker/u4:2 Not tainted 6.14.0-rc5-wt-g03960e6f9d47 #33 13c287eeabfe1efea01c0bcc863723ab082e17cf Workqueue: cfg80211 cfg80211_propagate_cac_done_wk Stack: 00000000 00000001 ffffff00 6093267c 00000000 6002ec30 6d577c50 60037608 00000000 67e8d108 6063717b 00000000 Call Trace: [<6002ec30>] ? _printk+0x0/0x98 [<6003c2b3>] show_stack+0x10e/0x11a [<6002ec30>] ? _printk+0x0/0x98 [<60037608>] dump_stack_lvl+0x71/0xb8 [<6063717b>] ? wdev_chandef+0x60/0x165 [<6003766d>] dump_stack+0x1e/0x20 [<6005d1b7>] __warn+0x101/0x20f [<6005d3a8>] warn_slowpath_fmt+0xe3/0x15d [<600b0c5c>] ? mark_lock.part.0+0x0/0x4ec [<60751191>] ? __this_cpu_preempt_check+0x0/0x16 [<600b11a2>] ? mark_held_locks+0x5a/0x6e [<6005d2c5>] ? warn_slowpath_fmt+0x0/0x15d [<60052e53>] ? unblock_signals+0x3a/0xe7 [<60052f2d>] ? um_set_signals+0x2d/0x43 [<60751191>] ? __this_cpu_preempt_check+0x0/0x16 [<607508b2>] ? lock_is_held_type+0x207/0x21f [<6063717b>] wdev_chandef+0x60/0x165 [<605f89b4>] regulatory_propagate_dfs_state+0x247/0x43f [<60052f00>] ? um_set_signals+0x0/0x43 [<605e6bfd>] cfg80211_propagate_cac_done_wk+0x3a/0x4a [<6007e460>] process_scheduled_works+0x3bc/0x60e [<6007d0ec>] ? move_linked_works+0x4d/0x81 [<6007d120>] ? assign_work+0x0/0xaa [<6007f81f>] worker_thread+0x220/0x2dc [<600786ef>] ? set_pf_worker+0x0/0x57 [<60087c96>] ? to_kthread+0x0/0x43 [<6008ab3c>] kthread+0x2d3/0x2e2 [<6007f5ff>] ? worker_thread+0x0/0x2dc [<6006c05b>] ? calculate_sigpending+0x0/0x56 [<6003b37d>] new_thread_handler+0x4a/0x64 irq event stamp: 614611 hardirqs last enabled at (614621): [<00000000600bc96b>] __up_console_sem+0x82/0xaf hardirqs last disabled at (614630): [<00000000600bc92c>] __up_console_sem+0x43/0xaf softirqs last enabled at (614268): [<00000000606c55c6>] __ieee80211_wake_queue+0x933/0x985 softirqs last disabled at (614266): [<00000000606c52d6>] __ieee80211_wake_queue+0x643/0x985 Fixes: 26ec17a1dc5e ("cfg80211: Fix radar event during another phy CAC") Signed-off-by: Alexander Wetzel Link: https://patch.msgid.link/20250717162547.94582-1-Alexander@wetzel-home.de Signed-off-by: Johannes Berg --- net/wireless/reg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 2524bc187a19..3b0ac3437f81 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -4229,6 +4229,8 @@ static void cfg80211_check_and_end_cac(struct cfg80211_registered_device *rdev) struct wireless_dev *wdev; unsigned int link_id; + guard(wiphy)(&rdev->wiphy); + /* If we finished CAC or received radar, we should end any * CAC running on the same channels. * the check !cfg80211_chandef_dfs_usable contain 2 options: From 11e3e22fa533f5d7cf04e32343b05a27eda3c7a5 Mon Sep 17 00:00:00 2001 From: Alexander Wetzel Date: Thu, 17 Jul 2025 18:25:46 +0200 Subject: [PATCH 143/199] wifi: mac80211: Do not schedule stopped TXQs Ignore TXQs with the flag IEEE80211_TXQ_STOP when scheduling a queue. The flag is only set after all fragments have been dequeued and won't allow dequeueing other frames as long as the flag is set. For drivers using ieee80211_txq_schedule_start() this prevents an loop trying to push the queued frames while IEEE80211_TXQ_STOP is set: After setting IEEE80211_TXQ_STOP the driver will call ieee80211_return_txq(). Which calls __ieee80211_schedule_txq(), detects that there sill are frames in the queue and immediately restarts the stopped TXQ. Which can't dequeue any frame and thus starts over the loop. Signed-off-by: Alexander Wetzel Fixes: ba8c3d6f16a1 ("mac80211: add an intermediate software queue implementation") Link: https://patch.msgid.link/20250717162547.94582-2-Alexander@wetzel-home.de Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index f3a065313a31..adbd640b5672 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -4099,7 +4099,9 @@ void __ieee80211_schedule_txq(struct ieee80211_hw *hw, spin_lock_bh(&local->active_txq_lock[txq->ac]); - has_queue = force || txq_has_queue(txq); + has_queue = force || + (!test_bit(IEEE80211_TXQ_STOP, &txqi->flags) && + txq_has_queue(txq)); if (list_empty(&txqi->schedule_order) && (has_queue || ieee80211_txq_keep_active(txqi))) { /* If airtime accounting is active, always enqueue STAs at the From cb3bb3d88dfcd177a1050c0a009a3ee147b2e5b9 Mon Sep 17 00:00:00 2001 From: Alexander Wetzel Date: Thu, 17 Jul 2025 18:25:47 +0200 Subject: [PATCH 144/199] wifi: mac80211: Don't call fq_flow_idx() for management frames skb_get_hash() can only be used when the skb is linked to a netdev device. Signed-off-by: Alexander Wetzel Fixes: 73bc9e0af594 ("mac80211: don't apply flow control on management frames") Link: https://patch.msgid.link/20250717162547.94582-3-Alexander@wetzel-home.de Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index adbd640b5672..baa9d3108773 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1429,7 +1429,7 @@ static void ieee80211_txq_enqueue(struct ieee80211_local *local, { struct fq *fq = &local->fq; struct fq_tin *tin = &txqi->tin; - u32 flow_idx = fq_flow_idx(fq, skb); + u32 flow_idx; ieee80211_set_skb_enqueue_time(skb); @@ -1445,6 +1445,7 @@ static void ieee80211_txq_enqueue(struct ieee80211_local *local, IEEE80211_TX_INTCFL_NEED_TXPROCESSING; __skb_queue_tail(&txqi->frags, skb); } else { + flow_idx = fq_flow_idx(fq, skb); fq_tin_enqueue(fq, tin, flow_idx, skb, fq_skb_free_func); } From 4037c468d1b3c508d69e6df0ef47fdee3d440e39 Mon Sep 17 00:00:00 2001 From: Remi Pommarel Date: Thu, 17 Jul 2025 17:45:28 +0200 Subject: [PATCH 145/199] wifi: mac80211: Check 802.11 encaps offloading in ieee80211_tx_h_select_key() With 802.11 encapsulation offloading, ieee80211_tx_h_select_key() is called on 802.3 frames. In that case do not try to use skb data as valid 802.11 headers. Reported-by: Bert Karwatzki Closes: https://lore.kernel.org/linux-wireless/20250410215527.3001-1-spasswolf@web.de Fixes: bb42f2d13ffc ("mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue") Signed-off-by: Remi Pommarel Link: https://patch.msgid.link/1af4b5b903a5fca5ebe67333d5854f93b2be5abe.1752765971.git.repk@triplefau.lt Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index baa9d3108773..73ea4d5bf266 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -612,6 +612,12 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) else tx->key = NULL; + if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) { + if (tx->key && tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) + info->control.hw_key = &tx->key->conf; + return TX_CONTINUE; + } + if (tx->key) { bool skip_hw = false; From 754fe848b3b297fc85ec24cd959bad22b6df8cb8 Mon Sep 17 00:00:00 2001 From: Remi Pommarel Date: Thu, 17 Jul 2025 17:45:29 +0200 Subject: [PATCH 146/199] Reapply "wifi: mac80211: Update skb's control block key in ieee80211_tx_dequeue()" This reverts commit 0937cb5f345c ("Revert "wifi: mac80211: Update skb's control block key in ieee80211_tx_dequeue()""). This commit broke TX with 802.11 encapsulation HW offloading, now that this is fixed, reapply it. Fixes: bb42f2d13ffc ("mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue") Signed-off-by: Remi Pommarel Link: https://patch.msgid.link/66b8fc39fb0194fa06c9ca7eeb6ffe0118dcb3ec.1752765971.git.repk@triplefau.lt Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 73ea4d5bf266..00671ae45b2f 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -3884,6 +3884,7 @@ begin: * The key can be removed while the packet was queued, so need to call * this here to get the current key. */ + info->control.hw_key = NULL; r = ieee80211_tx_h_select_key(&tx); if (r != TX_CONTINUE) { ieee80211_free_txskb(&local->hw, skb); From 8f1a078842d4af4877fb686f3907788024d0d1b7 Mon Sep 17 00:00:00 2001 From: Tamizh Chelvam Raja Date: Thu, 17 Jul 2025 23:05:38 +0530 Subject: [PATCH 147/199] wifi: ath12k: fix endianness handling while accessing wmi service bit Currently there is no endian conversion in ath12k_wmi_tlv_services_parser() so the service bit parsing will be incorrect on a big endian platform and to fix this by using appropriate endian conversion. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00217-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Fixes: 342527f35338 ("wifi: ath12k: Add support to parse new WMI event for 6 GHz regulatory") Signed-off-by: Tamizh Chelvam Raja Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250717173539.2523396-2-tamizh.raja@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/wmi.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index ed3c08dbd899..535c9849b98c 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -7581,7 +7581,7 @@ static int ath12k_wmi_tlv_services_parser(struct ath12k_base *ab, void *data) { const struct wmi_service_available_event *ev; - u32 *wmi_ext2_service_bitmap; + __le32 *wmi_ext2_service_bitmap; int i, j; u16 expected_len; @@ -7613,12 +7613,12 @@ static int ath12k_wmi_tlv_services_parser(struct ath12k_base *ab, ev->wmi_service_segment_bitmap[3]); break; case WMI_TAG_ARRAY_UINT32: - wmi_ext2_service_bitmap = (u32 *)ptr; + wmi_ext2_service_bitmap = (__le32 *)ptr; for (i = 0, j = WMI_MAX_EXT_SERVICE; i < WMI_SERVICE_SEGMENT_BM_SIZE32 && j < WMI_MAX_EXT2_SERVICE; i++) { do { - if (wmi_ext2_service_bitmap[i] & + if (__le32_to_cpu(wmi_ext2_service_bitmap[i]) & BIT(j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32)) set_bit(j, ab->wmi_ab.svc_map); } while (++j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32); @@ -7626,8 +7626,10 @@ static int ath12k_wmi_tlv_services_parser(struct ath12k_base *ab, ath12k_dbg(ab, ATH12K_DBG_WMI, "wmi_ext2_service_bitmap 0x%04x 0x%04x 0x%04x 0x%04x", - wmi_ext2_service_bitmap[0], wmi_ext2_service_bitmap[1], - wmi_ext2_service_bitmap[2], wmi_ext2_service_bitmap[3]); + __le32_to_cpu(wmi_ext2_service_bitmap[0]), + __le32_to_cpu(wmi_ext2_service_bitmap[1]), + __le32_to_cpu(wmi_ext2_service_bitmap[2]), + __le32_to_cpu(wmi_ext2_service_bitmap[3])); break; } return 0; From 1a50c5ca394ab1b3a30094eda2354bcfc00f9909 Mon Sep 17 00:00:00 2001 From: Tamizh Chelvam Raja Date: Thu, 17 Jul 2025 23:05:39 +0530 Subject: [PATCH 148/199] wifi: ath12k: Add support to parse max ext2 wmi service bit Update the host logic to dynamically parse WMI extended service bits beyond the current fixed size of 4 * 32 (i.e., 384 bits) after WMI_MAX_EXT_SERVICE (256). The current implementation misses service bits advertised beyond this range, leading to not enabling some of the features supported by firmware. Implement dynamic length parsing to iterate up to the maximum service bit index advertised by the firmware. This ensures all supported features are correctly recognized and enabled. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00217-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: Tamizh Chelvam Raja Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250717173539.2523396-3-tamizh.raja@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/wmi.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 535c9849b98c..a2a493928d08 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -7581,6 +7581,7 @@ static int ath12k_wmi_tlv_services_parser(struct ath12k_base *ab, void *data) { const struct wmi_service_available_event *ev; + u16 wmi_ext2_service_words; __le32 *wmi_ext2_service_bitmap; int i, j; u16 expected_len; @@ -7614,22 +7615,20 @@ static int ath12k_wmi_tlv_services_parser(struct ath12k_base *ab, break; case WMI_TAG_ARRAY_UINT32: wmi_ext2_service_bitmap = (__le32 *)ptr; + wmi_ext2_service_words = len / sizeof(u32); for (i = 0, j = WMI_MAX_EXT_SERVICE; - i < WMI_SERVICE_SEGMENT_BM_SIZE32 && j < WMI_MAX_EXT2_SERVICE; + i < wmi_ext2_service_words && j < WMI_MAX_EXT2_SERVICE; i++) { do { if (__le32_to_cpu(wmi_ext2_service_bitmap[i]) & BIT(j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32)) set_bit(j, ab->wmi_ab.svc_map); } while (++j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32); + ath12k_dbg(ab, ATH12K_DBG_WMI, + "wmi_ext2_service bitmap 0x%08x\n", + __le32_to_cpu(wmi_ext2_service_bitmap[i])); } - ath12k_dbg(ab, ATH12K_DBG_WMI, - "wmi_ext2_service_bitmap 0x%04x 0x%04x 0x%04x 0x%04x", - __le32_to_cpu(wmi_ext2_service_bitmap[0]), - __le32_to_cpu(wmi_ext2_service_bitmap[1]), - __le32_to_cpu(wmi_ext2_service_bitmap[2]), - __le32_to_cpu(wmi_ext2_service_bitmap[3])); break; } return 0; From 192c8e9a131f1772a635c3c5df4cb592bd7b3e8b Mon Sep 17 00:00:00 2001 From: Nithyanantham Paramasivam Date: Fri, 18 Jul 2025 08:25:11 +0530 Subject: [PATCH 149/199] wifi: ath12k: Fix the handling of TX packets in Ethernet mode Currently, in the transmit (TX) direction, EAPOL, QoS NULL, and multicast frames are sent in native Wi-Fi (802.11) format. However, when the virtual interface is configured in Ethernet mode, transmission fails for packets enqueued in native Wi-fi format. To address this issue, the firmware should be instructed to treat these packets as RAW type packets, ensuring proper handling even when the interface operates in Ethernet mode. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00217-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: Nithyanantham Paramasivam Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250718025513.32982-2-nithyanantham.paramasivam@oss.qualcomm.com [fix indentation] Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/dp_tx.c | 38 ++++++++++++++++++++----- drivers/net/wireless/ath/ath12k/mac.c | 1 + 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index 7005f05d3aaa..899d1dc51eae 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -244,6 +244,8 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif, bool msdu_ext_desc = false; bool add_htt_metadata = false; u32 iova_mask = ab->hw_params->iova_mask; + bool is_diff_encap = false; + bool is_null_frame = false; if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) return -ESHUTDOWN; @@ -334,7 +336,19 @@ tcl_ring_sel: switch (ti.encap_type) { case HAL_TCL_ENCAP_TYPE_NATIVE_WIFI: - ath12k_dp_tx_encap_nwifi(skb); + is_null_frame = ieee80211_is_nullfunc(hdr->frame_control); + if (ahvif->vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) { + if (skb->protocol == cpu_to_be16(ETH_P_PAE) || is_null_frame) + is_diff_encap = true; + + /* Firmware expects msdu ext descriptor for nwifi/raw packets + * received in ETH mode. Without this, observed tx fail for + * Multicast packets in ETH mode. + */ + msdu_ext_desc = true; + } else { + ath12k_dp_tx_encap_nwifi(skb); + } break; case HAL_TCL_ENCAP_TYPE_RAW: if (!test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) { @@ -378,15 +392,25 @@ map: goto fail_remove_tx_buf; } - if (!test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags) && - !(skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) && - !(skb_cb->flags & ATH12K_SKB_CIPHER_SET) && - ieee80211_has_protected(hdr->frame_control)) { - /* Add metadata for sw encrypted vlan group traffic */ + if ((!test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags) && + !(skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) && + !(skb_cb->flags & ATH12K_SKB_CIPHER_SET) && + ieee80211_has_protected(hdr->frame_control)) || + is_diff_encap) { + /* Firmware is not expecting meta data for qos null + * nwifi packet received in ETH encap mode. + */ + if (is_null_frame && msdu_ext_desc) + goto skip_htt_meta; + + /* Add metadata for sw encrypted vlan group traffic + * and EAPOL nwifi packet received in ETH encap mode. + */ add_htt_metadata = true; msdu_ext_desc = true; - ti.flags0 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TO_FW); ti.meta_data_flags |= HTT_TCL_META_DATA_VALID_HTT; +skip_htt_meta: + ti.flags0 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TO_FW); ti.encap_type = HAL_TCL_ENCAP_TYPE_RAW; ti.encrypt_type = HAL_ENCRYPT_TYPE_OPEN; } diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index bf612079b8bd..c56201fbee7a 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -8898,6 +8898,7 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw, is_dvlan = true; if (!vif->valid_links || !is_mcast || is_dvlan || + (skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) || test_bit(ATH12K_FLAG_RAW_MODE, &ar->ab->dev_flags)) { ret = ath12k_dp_tx(ar, arvif, skb, false, 0, is_mcast); if (unlikely(ret)) { From 981050b918fc4c36e0ef3bd7392b39d7304ef09b Mon Sep 17 00:00:00 2001 From: Nithyanantham Paramasivam Date: Fri, 18 Jul 2025 08:25:12 +0530 Subject: [PATCH 150/199] wifi: ath12k: Fix TX status reporting to mac80211 when offload is enabled Currently, the ath12k driver supports only the native Wi-Fi frame format. In this mode, the ieee80211_tx_status() function works correctly to report transmission status to mac80211, as it retrieves station information using sta_info_get_by_addrs(). However, this method is not applicable for Ethernet-converted packets, since sta_info_get_by_addrs() cannot extract station information from such formats. Retrieve station information using ath12k_peer_find_by_id() to support all frame formats, including native Wi-Fi, raw, and Ethernet. Report transmission status using ieee80211_tx_status_ext(), and include rate information as part of the datapath TX status report. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00217-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: Nithyanantham Paramasivam Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250718025513.32982-3-nithyanantham.paramasivam@oss.qualcomm.com [changed instances of { 0 } to {}] Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/dp_tx.c | 64 +++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index 899d1dc51eae..d79c2ff77952 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -568,7 +568,8 @@ static void ath12k_dp_tx_htt_tx_complete_buf(struct ath12k_base *ab, struct ath12k_tx_desc_params *desc_params, struct dp_tx_ring *tx_ring, - struct ath12k_dp_htt_wbm_tx_status *ts) + struct ath12k_dp_htt_wbm_tx_status *ts, + u16 peer_id) { struct ieee80211_tx_info *info; struct ath12k_link_vif *arvif; @@ -578,6 +579,8 @@ ath12k_dp_tx_htt_tx_complete_buf(struct ath12k_base *ab, struct ath12k *ar; struct sk_buff *msdu = desc_params->skb; s32 noise_floor; + struct ieee80211_tx_status status = {}; + struct ath12k_peer *peer; skb_cb = ATH12K_SKB_CB(msdu); info = IEEE80211_SKB_CB(msdu); @@ -629,8 +632,25 @@ ath12k_dp_tx_htt_tx_complete_buf(struct ath12k_base *ab, info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; } } + rcu_read_lock(); + spin_lock_bh(&ab->base_lock); + peer = ath12k_peer_find_by_id(ab, peer_id); + if (!peer || !peer->sta) { + ath12k_dbg(ab, ATH12K_DBG_DATA, + "dp_tx: failed to find the peer with peer_id %d\n", peer_id); + spin_unlock_bh(&ab->base_lock); + ieee80211_free_txskb(ath12k_ar_to_hw(ar), msdu); + goto exit; + } else { + status.sta = peer->sta; + } + spin_unlock_bh(&ab->base_lock); - ieee80211_tx_status_skb(ath12k_ar_to_hw(ar), msdu); + status.info = info; + status.skb = msdu; + ieee80211_tx_status_ext(ath12k_ar_to_hw(ar), &status); +exit: + rcu_read_unlock(); } static void @@ -641,6 +661,7 @@ ath12k_dp_tx_process_htt_tx_complete(struct ath12k_base *ab, void *desc, struct htt_tx_wbm_completion *status_desc; struct ath12k_dp_htt_wbm_tx_status ts = {0}; enum hal_wbm_htt_tx_comp_status wbm_status; + u16 peer_id; status_desc = desc; @@ -653,7 +674,11 @@ ath12k_dp_tx_process_htt_tx_complete(struct ath12k_base *ab, void *desc, ts.acked = (wbm_status == HAL_WBM_REL_HTT_TX_COMP_STATUS_OK); ts.ack_rssi = le32_get_bits(status_desc->info2, HTT_TX_WBM_COMP_INFO2_ACK_RSSI); - ath12k_dp_tx_htt_tx_complete_buf(ab, desc_params, tx_ring, &ts); + + peer_id = le32_get_bits(((struct hal_wbm_completion_ring_tx *)desc)-> + info3, HAL_WBM_COMPL_TX_INFO3_PEER_ID); + + ath12k_dp_tx_htt_tx_complete_buf(ab, desc_params, tx_ring, &ts, peer_id); break; case HAL_WBM_REL_HTT_TX_COMP_STATUS_DROP: case HAL_WBM_REL_HTT_TX_COMP_STATUS_TTL: @@ -805,6 +830,12 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar, struct ath12k_vif *ahvif; struct sk_buff *msdu = desc_params->skb; s32 noise_floor; + struct ieee80211_tx_status status = {}; + struct ieee80211_rate_status status_rate = {}; + struct ath12k_peer *peer; + struct ath12k_link_sta *arsta; + struct ath12k_sta *ahsta; + struct rate_info rate; if (WARN_ON_ONCE(ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM)) { /* Must not happen */ @@ -896,7 +927,32 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar, ath12k_dp_tx_update_txcompl(ar, ts); - ieee80211_tx_status_skb(ath12k_ar_to_hw(ar), msdu); + spin_lock_bh(&ab->base_lock); + peer = ath12k_peer_find_by_id(ab, ts->peer_id); + if (!peer || !peer->sta) { + ath12k_err(ab, + "dp_tx: failed to find the peer with peer_id %d\n", + ts->peer_id); + spin_unlock_bh(&ab->base_lock); + ieee80211_free_txskb(ath12k_ar_to_hw(ar), msdu); + goto exit; + } + ahsta = ath12k_sta_to_ahsta(peer->sta); + arsta = &ahsta->deflink; + + spin_unlock_bh(&ab->base_lock); + + status.sta = peer->sta; + status.info = info; + status.skb = msdu; + rate = arsta->last_txrate; + + status_rate.rate_idx = rate; + status_rate.try_count = 1; + + status.rates = &status_rate; + status.n_rates = 1; + ieee80211_tx_status_ext(ath12k_ar_to_hw(ar), &status); exit: rcu_read_unlock(); From d29591d5b52eaa62bc8c07ec83fe63018b5546ea Mon Sep 17 00:00:00 2001 From: Nithyanantham Paramasivam Date: Fri, 18 Jul 2025 08:25:13 +0530 Subject: [PATCH 151/199] wifi: ath12k: Advertise encapsulation/decapsulation offload support to mac80211 Currently, the mac80211 layer handles construction and parsing of 802.11 headers during packet transmission and reception. Offloading encapsulation and decapsulation to hardware can significantly enhance performance. Check the service bit to determine if the firmware supports Ethernet offload. If supported, advertise the capability to mac80211 to bypass software-based 802.11 header processing. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00217-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: Nithyanantham Paramasivam Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250718025513.32982-4-nithyanantham.paramasivam@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 5 +++++ drivers/net/wireless/ath/ath12k/wmi.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index c56201fbee7a..05250fa0600d 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -13755,6 +13755,11 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) ieee80211_hw_set(hw, REPORTS_LOW_ACK); ieee80211_hw_set(hw, NO_VIRTUAL_MONITOR); + if (test_bit(WMI_TLV_SERVICE_ETH_OFFLOAD, ar->wmi->wmi_ab->svc_map)) { + ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD); + ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD); + } + if (cap->nss_ratio_enabled) ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 5b782258f870..f3b0a6f57ec2 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2255,6 +2255,7 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_WMSK_COMPACTION_RX_TLVS = 361, WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT = 365, + WMI_TLV_SERVICE_ETH_OFFLOAD = 461, WMI_MAX_EXT2_SERVICE, }; From 460114eae8284155b51f6e72ed26f627ee338a30 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 21 Jul 2025 09:20:03 +0300 Subject: [PATCH 152/199] wifi: mac80211: remove ieee80211_remove_key It is no longer used, remove it. Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250721091956.e964ceacd85c.Idecab8ef161fa58e000b3969bc936399284b79f0@changeid Signed-off-by: Johannes Berg --- include/net/mac80211.h | 16 +--------------- net/mac80211/key.c | 27 +-------------------------- 2 files changed, 2 insertions(+), 41 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index a2dbaad2f6d3..a0cf976a9117 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -6032,18 +6032,6 @@ void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf, int tid, struct ieee80211_key_seq *seq); -/** - * ieee80211_remove_key - remove the given key - * @keyconf: the parameter passed with the set key - * - * Context: Must be called with the wiphy mutex held. - * - * Remove the given key. If the key was uploaded to the hardware at the - * time this function is called, it is not deleted in the hardware but - * instead assumed to have been removed already. - */ -void ieee80211_remove_key(struct ieee80211_key_conf *keyconf); - /** * ieee80211_gtk_rekey_add - add a GTK key from rekeying during WoWLAN * @vif: the virtual interface to add the key on @@ -6070,9 +6058,7 @@ void ieee80211_remove_key(struct ieee80211_key_conf *keyconf); * for the new key for each TID to set up sequence counters properly. * * IMPORTANT: If this replaces a key that is present in the hardware, - * then it will attempt to remove it during this call. In many cases - * this isn't what you want, so call ieee80211_remove_key() first for - * the key that's being replaced. + * then it will attempt to remove it during this call. */ struct ieee80211_key_conf * ieee80211_gtk_rekey_add(struct ieee80211_vif *vif, diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 997892da8886..9d65013ddac7 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -6,7 +6,7 @@ * Copyright 2007-2008 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2015-2017 Intel Deutschland GmbH - * Copyright 2018-2020, 2022-2024 Intel Corporation + * Copyright 2018-2020, 2022-2025 Intel Corporation */ #include @@ -1354,31 +1354,6 @@ void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf, } EXPORT_SYMBOL_GPL(ieee80211_set_key_rx_seq); -void ieee80211_remove_key(struct ieee80211_key_conf *keyconf) -{ - struct ieee80211_key *key; - - key = container_of(keyconf, struct ieee80211_key, conf); - - lockdep_assert_wiphy(key->local->hw.wiphy); - - /* - * if key was uploaded, we assume the driver will/has remove(d) - * it, so adjust bookkeeping accordingly - */ - if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { - key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; - - if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC | - IEEE80211_KEY_FLAG_PUT_MIC_SPACE | - IEEE80211_KEY_FLAG_RESERVE_TAILROOM))) - increment_tailroom_need_count(key->sdata); - } - - ieee80211_key_free(key, false); -} -EXPORT_SYMBOL_GPL(ieee80211_remove_key); - struct ieee80211_key_conf * ieee80211_gtk_rekey_add(struct ieee80211_vif *vif, struct ieee80211_key_conf *keyconf, From be06a8c7313943109fa870715356503c4c709cbc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 18 Jul 2025 20:23:06 +0200 Subject: [PATCH 153/199] wifi: cfg80211: reject HTC bit for management frames Management frames sent by userspace should never have the order/HTC bit set, reject that. It could also cause some confusion with the length of the buffer and the header so the validation might end up wrong. Link: https://patch.msgid.link/20250718202307.97a0455f0f35.I1805355c7e331352df16611839bc8198c855a33f@changeid Signed-off-by: Johannes Berg --- net/wireless/mlme.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index bb5bc6ff09d4..46394eb2086f 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -867,7 +867,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, mgmt = (const struct ieee80211_mgmt *)params->buf; - if (!ieee80211_is_mgmt(mgmt->frame_control)) + if (!ieee80211_is_mgmt(mgmt->frame_control) || + ieee80211_has_order(mgmt->frame_control)) return -EINVAL; stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; From 579bf8037b70b644a674c126a32bbb2212cf5c21 Mon Sep 17 00:00:00 2001 From: Gokul Sivakumar Date: Thu, 26 Jun 2025 10:37:02 +0530 Subject: [PATCH 154/199] wifi: brcmfmac: fix P2P discovery failure in P2P peer due to missing P2P IE After commit bd99a3013bdc ("brcmfmac: move configuration of probe request IEs"), the probe request MGMT IE addition operation brcmf_vif_set_mgmt_ie() got moved from the brcmf_p2p_scan_prep() to the brcmf_cfg80211_scan(). Because of this, as part of the scan request handler for the P2P Discovery, vif struct used for adding the Probe Request P2P IE in firmware got changed from the P2PAPI_BSSCFG_DEVICE vif to P2PAPI_BSSCFG_PRIMARY vif incorrectly. So the firmware stopped adding P2P IE to the outgoing P2P Discovery probe requests frames and the other P2P peers were unable to discover this device causing a regression on the P2P feature. To fix this, while setting the P2P IE in firmware, properly use the vif of the P2P discovery wdev on which the driver received the P2P scan request. This is done by not changing the vif pointer, until brcmf_vif_set_mgmt_ie() is completed. Fixes: bd99a3013bdc ("brcmfmac: move configuration of probe request IEs") Signed-off-by: Gokul Sivakumar Acked-by: Arend van Spriel Link: https://patch.msgid.link/20250626050706.7271-1-gokulkumar.sivakumar@infineon.com Signed-off-by: Johannes Berg --- .../net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index a324bfec0b69..b8fc387ac361 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -1559,10 +1559,6 @@ brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) return -EAGAIN; } - /* If scan req comes for p2p0, send it over primary I/F */ - if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) - vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; - brcmf_dbg(SCAN, "START ESCAN\n"); cfg->scan_request = request; @@ -1578,6 +1574,10 @@ brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) if (err) goto scan_out; + /* If scan req comes for p2p0, send it over primary I/F */ + if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) + vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; + err = brcmf_do_escan(vif->ifp, request); if (err) goto scan_out; From c639a44ac6c2624f983bbe36483166a4b3afb371 Mon Sep 17 00:00:00 2001 From: Double Lo Date: Tue, 24 Jun 2025 04:34:53 -0500 Subject: [PATCH 155/199] wifi: brcmfmac: support CYW54591 PCIE device CYW54591 is a variant of BCM4355 silicon with the same chipid. In the chipid-fwname mapping table, apply chiprev 13 to identify CYW54591. Skip reading OTP process for CYW chip since it contains vendor specific information which is not common for cypress. Signed-off-by: Double Lo Signed-off-by: Chi-hsien Lin Signed-off-by: Ian Lin Acked-by: Arend van Spriel Link: https://patch.msgid.link/20250624093453.7264-1-ian.lin@infineon.com Signed-off-by: Johannes Berg --- .../broadcom/brcm80211/brcmfmac/pcie.c | 21 ++++++++++++++----- .../broadcom/brcm80211/include/brcm_hw_ids.h | 1 + 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 9747928a3650..6327f4eca500 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -71,6 +71,7 @@ BRCMF_FW_CLM_DEF(4377B3, "brcmfmac4377b3-pcie"); BRCMF_FW_CLM_DEF(4378B1, "brcmfmac4378b1-pcie"); BRCMF_FW_CLM_DEF(4378B3, "brcmfmac4378b3-pcie"); BRCMF_FW_CLM_DEF(4387C2, "brcmfmac4387c2-pcie"); +BRCMF_FW_CLM_DEF(54591, "brcmfmac54591-pcie"); /* firmware config files */ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.txt"); @@ -88,6 +89,7 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_4350_CHIP_ID, 0xFFFFFF00, 4350), BRCMF_FW_ENTRY(BRCM_CC_43525_CHIP_ID, 0xFFFFFFF0, 4365C), BRCMF_FW_ENTRY(BRCM_CC_4355_CHIP_ID, 0x000007FF, 4355), + BRCMF_FW_ENTRY(BRCM_CC_4355_CHIP_ID, 0x00002000, 54591), BRCMF_FW_ENTRY(BRCM_CC_4355_CHIP_ID, 0xFFFFF800, 4355C1), /* rev ID 12/C2 seen */ BRCMF_FW_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356), BRCMF_FW_ENTRY(BRCM_CC_43567_CHIP_ID, 0xFFFFFFFF, 43570), @@ -2522,10 +2524,19 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) goto fail_bus; - ret = brcmf_pcie_read_otp(devinfo); - if (ret) { - brcmf_err(bus, "failed to parse OTP\n"); - goto fail_brcmf; + /* otp read operation */ + switch (bus->fwvid) { + case BRCMF_FWVENDOR_WCC: + case BRCMF_FWVENDOR_BCA: + ret = brcmf_pcie_read_otp(devinfo); + if (ret) { + brcmf_err(bus, "failed to parse OTP\n"); + goto fail_brcmf; + } + break; + case BRCMF_FWVENDOR_CYW: + default: + break; } #ifdef DEBUG @@ -2740,7 +2751,7 @@ static const struct pci_device_id brcmf_pcie_devid_table[] = { BRCMF_PCIE_DEVICE(BRCM_PCIE_4378_DEVICE_ID, WCC_SEED), BRCMF_PCIE_DEVICE(BRCM_PCIE_4387_DEVICE_ID, WCC_SEED), BRCMF_PCIE_DEVICE(BRCM_PCIE_43752_DEVICE_ID, WCC_SEED), - + BRCMF_PCIE_DEVICE(CY_PCIE_54591_DEVICE_ID, CYW), { /* end: all zeroes */ } }; diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h index 6564616a57df..b39c5c1ee18b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h @@ -100,6 +100,7 @@ #define BRCM_PCIE_4377_DEVICE_ID 0x4488 #define BRCM_PCIE_4378_DEVICE_ID 0x4425 #define BRCM_PCIE_4387_DEVICE_ID 0x4433 +#define CY_PCIE_54591_DEVICE_ID 0x4417 /* brcmsmac IDs */ #define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */ From 4970e393eb5d1aed10119532abe36e07f27eec7f Mon Sep 17 00:00:00 2001 From: Michael-CY Lee Date: Mon, 21 Jul 2025 14:29:29 +0800 Subject: [PATCH 156/199] wifi: mac80211: determine missing link_id in ieee80211_rx_for_interface() based on frequency For broadcast frames, every interface might have to process it and therefore the link_id cannot be determined in the driver. In mac80211, when the frame is about to be forwarded to each interface, we can use the member "freq" in struct ieee80211_rx_status to determine the "link_id" for each interface. Signed-off-by: Michael-CY Lee Reviewed-by: Money Wang Link: https://patch.msgid.link/20250721062929.1662700-1-michael-cy.lee@mediatek.com [simplify, remove unnecessary link->conf check] Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b414c9e6e61b..576e399fc99c 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -5106,8 +5106,24 @@ static bool ieee80211_rx_for_interface(struct ieee80211_rx_data *rx, struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); sta = sta_info_get_bss(rx->sdata, hdr->addr2); - if (status->link_valid) + if (status->link_valid) { link_id = status->link_id; + } else if (ieee80211_vif_is_mld(&rx->sdata->vif) && + status->freq) { + struct ieee80211_link_data *link; + struct ieee80211_chanctx_conf *conf; + + for_each_link_data_rcu(rx->sdata, link) { + conf = rcu_dereference(link->conf->chanctx_conf); + if (!conf || !conf->def.chan) + continue; + + if (status->freq == conf->def.chan->center_freq) { + link_id = link->link_id; + break; + } + } + } } if (!ieee80211_rx_data_set_sta(rx, sta, link_id)) From 84b62b72b4c759b51568e44b0e8dc80f4cb8a2b9 Mon Sep 17 00:00:00 2001 From: Michael-CY Lee Date: Mon, 21 Jul 2025 14:51:59 +0800 Subject: [PATCH 157/199] wifi: cfg80211/mac80211: report link ID for unexpected frames The upper layer may require the link ID to properly handle unexpected frames. For instance, if hostapd, operating as an AP MLD, receives a data frame from a non-associated STA, it must send deauthentication to the link on which the STA is operating. Signed-off-by: Michael-CY Lee Reviewed-by: Money Wang Link: https://patch.msgid.link/20250721065159.1740992-1-michael-cy.lee@mediatek.com [edit commit message] Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 10 ++++++---- net/mac80211/rx.c | 10 +++++----- net/wireless/nl80211.c | 22 ++++++++++++---------- net/wireless/trace.h | 17 ++++++++++------- 4 files changed, 33 insertions(+), 26 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 44a1055a81ba..406626ff6cc8 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -9048,6 +9048,7 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index, /** * cfg80211_rx_spurious_frame - inform userspace about a spurious frame * @dev: The device the frame matched to + * @link_id: the link the frame was received on, -1 if not applicable or unknown * @addr: the transmitter address * @gfp: context flags * @@ -9057,13 +9058,14 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index, * Return: %true if the frame was passed to userspace (or this failed * for a reason other than not having a subscription.) */ -bool cfg80211_rx_spurious_frame(struct net_device *dev, - const u8 *addr, gfp_t gfp); +bool cfg80211_rx_spurious_frame(struct net_device *dev, const u8 *addr, + int link_id, gfp_t gfp); /** * cfg80211_rx_unexpected_4addr_frame - inform about unexpected WDS frame * @dev: The device the frame matched to * @addr: the transmitter address + * @link_id: the link the frame was received on, -1 if not applicable or unknown * @gfp: context flags * * This function is used in AP mode (only!) to inform userspace that @@ -9073,8 +9075,8 @@ bool cfg80211_rx_spurious_frame(struct net_device *dev, * Return: %true if the frame was passed to userspace (or this failed * for a reason other than not having a subscription.) */ -bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev, - const u8 *addr, gfp_t gfp); +bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev, const u8 *addr, + int link_id, gfp_t gfp); /** * cfg80211_probe_status - notify userspace about probe status diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 576e399fc99c..4d4ff4d4917a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1532,9 +1532,8 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) } if (rx->sdata->vif.type == NL80211_IFTYPE_AP && - cfg80211_rx_spurious_frame(rx->sdata->dev, - hdr->addr2, - GFP_ATOMIC)) + cfg80211_rx_spurious_frame(rx->sdata->dev, hdr->addr2, + rx->link_id, GFP_ATOMIC)) return RX_DROP_U_SPURIOUS; return RX_DROP; @@ -1872,7 +1871,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) if (!test_and_set_sta_flag(sta, WLAN_STA_4ADDR_EVENT)) cfg80211_rx_unexpected_4addr_frame( rx->sdata->dev, sta->sta.addr, - GFP_ATOMIC); + rx->link_id, GFP_ATOMIC); return RX_DROP_U_UNEXPECTED_4ADDR_FRAME; } /* @@ -3191,7 +3190,8 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) if (rx->sta && !test_and_set_sta_flag(rx->sta, WLAN_STA_4ADDR_EVENT)) cfg80211_rx_unexpected_4addr_frame( - rx->sdata->dev, rx->sta->sta.addr, GFP_ATOMIC); + rx->sdata->dev, rx->sta->sta.addr, rx->link_id, + GFP_ATOMIC); return RX_DROP; } diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1c808b08b747..b4bf44768dc8 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -19755,7 +19755,7 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, EXPORT_SYMBOL(cfg80211_conn_failed); static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, - const u8 *addr, gfp_t gfp) + const u8 *addr, int link_id, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); @@ -19778,7 +19778,9 @@ static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || - nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) || + (link_id >= 0 && + nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id))) goto nla_put_failure; genlmsg_end(msg, hdr); @@ -19790,13 +19792,13 @@ static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, return true; } -bool cfg80211_rx_spurious_frame(struct net_device *dev, - const u8 *addr, gfp_t gfp) +bool cfg80211_rx_spurious_frame(struct net_device *dev, const u8 *addr, + int link_id, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; bool ret; - trace_cfg80211_rx_spurious_frame(dev, addr); + trace_cfg80211_rx_spurious_frame(dev, addr, link_id); if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && wdev->iftype != NL80211_IFTYPE_P2P_GO)) { @@ -19804,19 +19806,19 @@ bool cfg80211_rx_spurious_frame(struct net_device *dev, return false; } ret = __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME, - addr, gfp); + addr, link_id, gfp); trace_cfg80211_return_bool(ret); return ret; } EXPORT_SYMBOL(cfg80211_rx_spurious_frame); -bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev, - const u8 *addr, gfp_t gfp) +bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev, const u8 *addr, + int link_id, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; bool ret; - trace_cfg80211_rx_unexpected_4addr_frame(dev, addr); + trace_cfg80211_rx_unexpected_4addr_frame(dev, addr, link_id); if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && wdev->iftype != NL80211_IFTYPE_P2P_GO && @@ -19826,7 +19828,7 @@ bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev, } ret = __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_4ADDR_FRAME, - addr, gfp); + addr, link_id, gfp); trace_cfg80211_return_bool(ret); return ret; } diff --git a/net/wireless/trace.h b/net/wireless/trace.h index a07d88d61bec..34c584a215e5 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -3570,27 +3570,30 @@ TRACE_EVENT(cfg80211_cac_event, ); DECLARE_EVENT_CLASS(cfg80211_rx_evt, - TP_PROTO(struct net_device *netdev, const u8 *addr), - TP_ARGS(netdev, addr), + TP_PROTO(struct net_device *netdev, const u8 *addr, int link_id), + TP_ARGS(netdev, addr, link_id), TP_STRUCT__entry( NETDEV_ENTRY MAC_ENTRY(addr) + __field(int, link_id) ), TP_fast_assign( NETDEV_ASSIGN; MAC_ASSIGN(addr, addr); + __entry->link_id = link_id; ), - TP_printk(NETDEV_PR_FMT ", %pM", NETDEV_PR_ARG, __entry->addr) + TP_printk(NETDEV_PR_FMT ", %pM, link_id:%d", NETDEV_PR_ARG, + __entry->addr, __entry->link_id) ); DEFINE_EVENT(cfg80211_rx_evt, cfg80211_rx_spurious_frame, - TP_PROTO(struct net_device *netdev, const u8 *addr), - TP_ARGS(netdev, addr) + TP_PROTO(struct net_device *netdev, const u8 *addr, int link_id), + TP_ARGS(netdev, addr, link_id) ); DEFINE_EVENT(cfg80211_rx_evt, cfg80211_rx_unexpected_4addr_frame, - TP_PROTO(struct net_device *netdev, const u8 *addr), - TP_ARGS(netdev, addr) + TP_PROTO(struct net_device *netdev, const u8 *addr, int link_id), + TP_ARGS(netdev, addr, link_id) ); TRACE_EVENT(cfg80211_ibss_joined, From f0b72d15265e877a02427e0062a72ade70ee6f86 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 20 Jul 2025 07:46:15 -0700 Subject: [PATCH 158/199] wifi: ath10k: Prefer {} to {0} in initializers Prefer {} to {0} in initializers since {} works even when the first member is not a scalar. Generated using: sed -i 's/{[[:space:]]*0[[:space:]]*}/{}/g' drivers/net/wireless/ath/ath10k/* Compile tested only. Link: https://patch.msgid.link/20250720-ath10k-zero-brace-v1-1-c1ee818d6238@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath10k/core.c | 2 +- drivers/net/wireless/ath/ath10k/debug.c | 6 +++--- drivers/net/wireless/ath/ath10k/debugfs_sta.c | 7 ++++--- drivers/net/wireless/ath/ath10k/htt_rx.c | 8 ++++---- drivers/net/wireless/ath/ath10k/htt_tx.c | 4 ++-- drivers/net/wireless/ath/ath10k/mac.c | 8 ++++---- drivers/net/wireless/ath/ath10k/pci.c | 3 ++- 7 files changed, 20 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 9c6c07598b3a..6f78f1752cd6 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1565,7 +1565,7 @@ static int ath10k_core_create_board_name(struct ath10k *ar, char *name, bool with_chip_id) { /* strlen(',variant=') + strlen(ar->id.bdf_ext) */ - char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = { 0 }; + char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = {}; if (with_variant && ar->id.bdf_ext[0] != '\0') scnprintf(variant, sizeof(variant), ",variant=%s", diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 6410d3961e76..b7520220465a 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -547,7 +547,7 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file, size_t count, loff_t *ppos) { struct ath10k *ar = file->private_data; - char buf[32] = {0}; + char buf[32] = {}; ssize_t rc; int ret; @@ -983,7 +983,7 @@ static ssize_t ath10k_write_htt_max_amsdu_ampdu(struct file *file, { struct ath10k *ar = file->private_data; int res; - char buf[64] = {0}; + char buf[64] = {}; unsigned int amsdu, ampdu; res = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, @@ -1039,7 +1039,7 @@ static ssize_t ath10k_write_fw_dbglog(struct file *file, { struct ath10k *ar = file->private_data; int ret; - char buf[96] = {0}; + char buf[96] = {}; unsigned int log_level; u64 mask; diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c index 0f6de862c3a9..b9fb192e0b48 100644 --- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c @@ -3,6 +3,7 @@ * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include "core.h" @@ -244,7 +245,7 @@ static ssize_t ath10k_dbg_sta_write_addba(struct file *file, struct ath10k *ar = arsta->arvif->ar; u32 tid, buf_size; int ret; - char buf[64] = {0}; + char buf[64] = {}; ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); @@ -295,7 +296,7 @@ static ssize_t ath10k_dbg_sta_write_addba_resp(struct file *file, struct ath10k *ar = arsta->arvif->ar; u32 tid, status; int ret; - char buf[64] = {0}; + char buf[64] = {}; ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); @@ -345,7 +346,7 @@ static ssize_t ath10k_dbg_sta_write_delba(struct file *file, struct ath10k *ar = arsta->arvif->ar; u32 tid, initiator, reason; int ret; - char buf[64] = {0}; + char buf[64] = {}; ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index f12243d6bee1..d7e429041065 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -1884,7 +1884,7 @@ static bool ath10k_htt_rx_h_frag_pn_check(struct ath10k *ar, enum htt_rx_mpdu_encrypt_type enctype) { struct ath10k_peer *peer; - union htt_rx_pn_t *last_pn, new_pn = {0}; + union htt_rx_pn_t *last_pn, new_pn = {}; struct ieee80211_hdr *hdr; u8 tid, frag_number; u32 seq; @@ -2402,7 +2402,7 @@ static bool ath10k_htt_rx_pn_check_replay_hl(struct ath10k *ar, bool last_pn_valid, pn_invalid = false; enum htt_txrx_sec_cast_type sec_index; enum htt_security_types sec_type; - union htt_rx_pn_t new_pn = {0}; + union htt_rx_pn_t new_pn = {}; struct htt_hl_rx_desc *rx_desc; union htt_rx_pn_t *last_pn; u32 rx_desc_info, tid; @@ -2465,7 +2465,7 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt, struct fw_rx_desc_hl *fw_desc; enum htt_txrx_sec_cast_type sec_index; enum htt_security_types sec_type; - union htt_rx_pn_t new_pn = {0}; + union htt_rx_pn_t new_pn = {}; struct htt_hl_rx_desc *rx_desc; struct ieee80211_hdr *hdr; struct ieee80211_rx_status *rx_status; @@ -2767,7 +2767,7 @@ static bool ath10k_htt_rx_proc_rx_frag_ind_hl(struct ath10k_htt *htt, struct htt_rx_indication_hl *rx_hl; enum htt_security_types sec_type; u32 tid, frag, seq, rx_desc_info; - union htt_rx_pn_t new_pn = {0}; + union htt_rx_pn_t new_pn = {}; struct htt_hl_rx_desc *rx_desc; u16 peer_id, sc, hdr_space; union htt_rx_pn_t *last_pn; diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index c1ddd761af3e..d6f1d85ba871 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -510,7 +510,7 @@ static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx) { struct ath10k *ar = ctx; struct ath10k_htt *htt = &ar->htt; - struct htt_tx_done tx_done = {0}; + struct htt_tx_done tx_done = {}; ath10k_dbg(ar, ATH10K_DBG_HTT, "force cleanup msdu_id %u\n", msdu_id); @@ -560,7 +560,7 @@ void ath10k_htt_op_ep_tx_credits(struct ath10k *ar) void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb) { struct ath10k_htt *htt = &ar->htt; - struct htt_tx_done tx_done = {0}; + struct htt_tx_done tx_done = {}; struct htt_cmd_hdr *htt_hdr; struct htt_data_tx_desc *desc_hdr = NULL; u16 flags1 = 0; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 11569c18204c..24dd794e31ea 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3385,7 +3385,7 @@ static int ath10k_update_channel_list(struct ath10k *ar) struct ieee80211_supported_band **bands; enum nl80211_band band; struct ieee80211_channel *channel; - struct wmi_scan_chan_list_arg arg = {0}; + struct wmi_scan_chan_list_arg arg = {}; struct wmi_channel_arg *ch; bool passive; int len; @@ -4885,7 +4885,7 @@ static int ath10k_mac_get_vht_cap_bf_sound_dim(struct ath10k *ar) static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar) { - struct ieee80211_sta_vht_cap vht_cap = {0}; + struct ieee80211_sta_vht_cap vht_cap = {}; struct ath10k_hw_params *hw = &ar->hw_params; u16 mcs_map; u32 val; @@ -4943,7 +4943,7 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar) static struct ieee80211_sta_ht_cap ath10k_get_ht_cap(struct ath10k *ar) { int i; - struct ieee80211_sta_ht_cap ht_cap = {0}; + struct ieee80211_sta_ht_cap ht_cap = {}; if (!(ar->ht_cap_info & WMI_HT_CAP_ENABLED)) return ht_cap; @@ -5175,7 +5175,7 @@ static int ath10k_start(struct ieee80211_hw *hw) struct ath10k *ar = hw->priv; u32 param; int ret = 0; - struct wmi_bb_timing_cfg_arg bb_timing = {0}; + struct wmi_bb_timing_cfg_arg bb_timing = {}; /* * This makes sense only when restarting hw. It is harmless to call diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 1e6d43285138..97b49bf4ad80 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -63,7 +64,7 @@ static const struct pci_device_id ath10k_pci_id_table[] = { { PCI_VDEVICE(ATHEROS, QCA9984_1_0_DEVICE_ID) }, /* PCI-E QCA9984 V1 */ { PCI_VDEVICE(ATHEROS, QCA9377_1_0_DEVICE_ID) }, /* PCI-E QCA9377 V1 */ { PCI_VDEVICE(ATHEROS, QCA9887_1_0_DEVICE_ID) }, /* PCI-E QCA9887 */ - {0} + {} }; static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = { From 1228d99fac4c103a1ca6af82ddd27ba2c445d0ca Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 20 Jul 2025 08:13:38 -0700 Subject: [PATCH 159/199] wifi: ath11k: Prefer {} to {0} in initializers Prefer {} to {0} in initializers since {} works even when the first member is not a scalar. Generated using: sed -i 's/{[[:space:]]*0[[:space:]]*}/{}/g' drivers/net/wireless/ath/ath11k/* Compile tested only. Link: https://patch.msgid.link/20250720-ath11k-zero-brace-v1-1-6132e2ef1748@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath11k/ahb.c | 2 +- drivers/net/wireless/ath/ath11k/ce.c | 2 +- drivers/net/wireless/ath/ath11k/core.c | 2 +- drivers/net/wireless/ath/ath11k/dbring.c | 3 +- drivers/net/wireless/ath/ath11k/debugfs.c | 38 +++++++++---------- .../wireless/ath/ath11k/debugfs_htt_stats.c | 15 ++++---- drivers/net/wireless/ath/ath11k/debugfs_sta.c | 11 +++--- drivers/net/wireless/ath/ath11k/dp.c | 2 +- drivers/net/wireless/ath/ath11k/dp_rx.c | 20 +++++----- drivers/net/wireless/ath/ath11k/dp_tx.c | 15 ++++---- drivers/net/wireless/ath/ath11k/mac.c | 16 ++++---- drivers/net/wireless/ath/ath11k/pci.c | 4 +- drivers/net/wireless/ath/ath11k/spectral.c | 3 +- drivers/net/wireless/ath/ath11k/wmi.c | 12 +++--- 14 files changed, 75 insertions(+), 70 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index fde1ce43c499..50809cc1dad4 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -988,7 +988,7 @@ static int ath11k_ahb_fw_resources_init(struct ath11k_base *ab) { struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab); struct device *host_dev = ab->dev; - struct platform_device_info info = {0}; + struct platform_device_info info = {}; struct iommu_domain *iommu_dom; struct platform_device *pdev; struct device_node *node; diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c index 878ce30b307c..c65fc9fb539e 100644 --- a/drivers/net/wireless/ath/ath11k/ce.c +++ b/drivers/net/wireless/ath/ath11k/ce.c @@ -554,7 +554,7 @@ static int ath11k_ce_init_ring(struct ath11k_base *ab, struct ath11k_ce_ring *ce_ring, int ce_id, enum hal_ring_type type) { - struct hal_srng_params params = { 0 }; + struct hal_srng_params params = {}; int ret; params.ring_base_paddr = ce_ring->base_addr_ce_space; diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index ad942fad01e9..d49353b6b2e7 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -1393,7 +1393,7 @@ static int __ath11k_core_create_board_name(struct ath11k_base *ab, char *name, enum ath11k_bdf_name_type name_type) { /* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */ - char variant[9 + ATH11K_QMI_BDF_EXT_STR_LENGTH] = { 0 }; + char variant[9 + ATH11K_QMI_BDF_EXT_STR_LENGTH] = {}; if (with_variant && ab->qmi.target.bdf_ext[0] != '\0') scnprintf(variant, sizeof(variant), ",variant=%s", diff --git a/drivers/net/wireless/ath/ath11k/dbring.c b/drivers/net/wireless/ath/ath11k/dbring.c index fbb6e8d8a476..520d8b8662a2 100644 --- a/drivers/net/wireless/ath/ath11k/dbring.c +++ b/drivers/net/wireless/ath/ath11k/dbring.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include "core.h" @@ -153,7 +154,7 @@ int ath11k_dbring_wmi_cfg_setup(struct ath11k *ar, struct ath11k_dbring *ring, enum wmi_direct_buffer_module id) { - struct ath11k_wmi_pdev_dma_ring_cfg_req_cmd param = {0}; + struct ath11k_wmi_pdev_dma_ring_cfg_req_cmd param = {}; int ret; if (id >= WMI_DIRECT_BUF_MAX) diff --git a/drivers/net/wireless/ath/ath11k/debugfs.c b/drivers/net/wireless/ath/ath11k/debugfs.c index 906df3b13f4f..977f945b6e66 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs.c +++ b/drivers/net/wireless/ath/ath11k/debugfs.c @@ -375,7 +375,7 @@ static ssize_t ath11k_write_simulate_fw_crash(struct file *file, struct ath11k_base *ab = file->private_data; struct ath11k_pdev *pdev; struct ath11k *ar = ab->pdevs[0].ar; - char buf[32] = {0}; + char buf[32] = {}; ssize_t rc; int i, ret, radioup = 0; @@ -473,7 +473,7 @@ static ssize_t ath11k_read_enable_extd_tx_stats(struct file *file, size_t count, loff_t *ppos) { - char buf[32] = {0}; + char buf[32] = {}; struct ath11k *ar = file->private_data; int len = 0; @@ -497,7 +497,7 @@ static ssize_t ath11k_write_extd_rx_stats(struct file *file, { struct ath11k *ar = file->private_data; struct ath11k_base *ab = ar->ab; - struct htt_rx_ring_tlv_filter tlv_filter = {0}; + struct htt_rx_ring_tlv_filter tlv_filter = {}; u32 enable, rx_filter = 0, ring_id; int i; int ret; @@ -737,7 +737,7 @@ static ssize_t ath11k_write_fw_dbglog(struct file *file, size_t count, loff_t *ppos) { struct ath11k *ar = file->private_data; - char buf[128] = {0}; + char buf[128] = {}; struct ath11k_fw_dbglog dbglog; unsigned int param, mod_id_index, is_end; u64 value; @@ -950,9 +950,9 @@ static ssize_t ath11k_write_pktlog_filter(struct file *file, { struct ath11k *ar = file->private_data; struct ath11k_base *ab = ar->ab; - struct htt_rx_ring_tlv_filter tlv_filter = {0}; + struct htt_rx_ring_tlv_filter tlv_filter = {}; u32 rx_filter = 0, ring_id, filter, mode; - u8 buf[128] = {0}; + u8 buf[128] = {}; int i, ret, rx_buf_sz = 0; ssize_t rc; @@ -1081,7 +1081,7 @@ static ssize_t ath11k_read_pktlog_filter(struct file *file, size_t count, loff_t *ppos) { - char buf[32] = {0}; + char buf[32] = {}; struct ath11k *ar = file->private_data; int len = 0; @@ -1235,7 +1235,7 @@ static ssize_t ath11k_debugfs_write_enable_dbr_dbg(struct file *file, size_t count, loff_t *ppos) { struct ath11k *ar = file->private_data; - char buf[32] = {0}; + char buf[32] = {}; u32 dbr_id, enable; int ret; @@ -1473,7 +1473,7 @@ int ath11k_debugfs_register(struct ath11k *ar) { struct ath11k_base *ab = ar->ab; char pdev_name[10]; - char buf[100] = {0}; + char buf[100] = {}; snprintf(pdev_name, sizeof(pdev_name), "%s%u", "mac", ar->pdev_idx); @@ -1556,10 +1556,10 @@ static ssize_t ath11k_write_twt_add_dialog(struct file *file, size_t count, loff_t *ppos) { struct ath11k_vif *arvif = file->private_data; - struct wmi_twt_add_dialog_params params = { 0 }; - struct wmi_twt_enable_params twt_params = {0}; + struct wmi_twt_add_dialog_params params = {}; + struct wmi_twt_enable_params twt_params = {}; struct ath11k *ar = arvif->ar; - u8 buf[128] = {0}; + u8 buf[128] = {}; int ret; if (ar->twt_enabled == 0) { @@ -1632,10 +1632,10 @@ static ssize_t ath11k_write_twt_del_dialog(struct file *file, size_t count, loff_t *ppos) { struct ath11k_vif *arvif = file->private_data; - struct wmi_twt_del_dialog_params params = { 0 }; - struct wmi_twt_enable_params twt_params = {0}; + struct wmi_twt_del_dialog_params params = {}; + struct wmi_twt_enable_params twt_params = {}; struct ath11k *ar = arvif->ar; - u8 buf[64] = {0}; + u8 buf[64] = {}; int ret; if (ar->twt_enabled == 0) { @@ -1679,8 +1679,8 @@ static ssize_t ath11k_write_twt_pause_dialog(struct file *file, size_t count, loff_t *ppos) { struct ath11k_vif *arvif = file->private_data; - struct wmi_twt_pause_dialog_params params = { 0 }; - u8 buf[64] = {0}; + struct wmi_twt_pause_dialog_params params = {}; + u8 buf[64] = {}; int ret; if (arvif->ar->twt_enabled == 0) { @@ -1718,8 +1718,8 @@ static ssize_t ath11k_write_twt_resume_dialog(struct file *file, size_t count, loff_t *ppos) { struct ath11k_vif *arvif = file->private_data; - struct wmi_twt_resume_dialog_params params = { 0 }; - u8 buf[64] = {0}; + struct wmi_twt_resume_dialog_params params = {}; + u8 buf[64] = {}; int ret; if (arvif->ar->twt_enabled == 0) { diff --git a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c index 870e86a31bf8..11d28c42227e 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -375,7 +376,7 @@ static inline void htt_print_hw_stats_intr_misc_tlv(const void *tag_buf, u8 *buf = stats_req->buf; u32 len = stats_req->buf_len; u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; - char hw_intr_name[HTT_STATS_MAX_HW_INTR_NAME_LEN + 1] = {0}; + char hw_intr_name[HTT_STATS_MAX_HW_INTR_NAME_LEN + 1] = {}; len += scnprintf(buf + len, buf_len - len, "HTT_HW_STATS_INTR_MISC_TLV:\n"); memcpy(hw_intr_name, &(htt_stats_buf->hw_intr_name[0]), @@ -402,7 +403,7 @@ htt_print_hw_stats_wd_timeout_tlv(const void *tag_buf, u8 *buf = stats_req->buf; u32 len = stats_req->buf_len; u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; - char hw_module_name[HTT_STATS_MAX_HW_MODULE_NAME_LEN + 1] = {0}; + char hw_module_name[HTT_STATS_MAX_HW_MODULE_NAME_LEN + 1] = {}; len += scnprintf(buf + len, buf_len - len, "HTT_HW_STATS_WD_TIMEOUT_TLV:\n"); memcpy(hw_module_name, &(htt_stats_buf->hw_module_name[0]), @@ -514,7 +515,7 @@ static inline void htt_print_tx_tid_stats_tlv(const void *tag_buf, u8 *buf = stats_req->buf; u32 len = stats_req->buf_len; u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; - char tid_name[MAX_HTT_TID_NAME + 1] = {0}; + char tid_name[MAX_HTT_TID_NAME + 1] = {}; len += scnprintf(buf + len, buf_len - len, "HTT_TX_TID_STATS_TLV:\n"); memcpy(tid_name, &(htt_stats_buf->tid_name[0]), MAX_HTT_TID_NAME); @@ -567,7 +568,7 @@ static inline void htt_print_tx_tid_stats_v1_tlv(const void *tag_buf, u8 *buf = stats_req->buf; u32 len = stats_req->buf_len; u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; - char tid_name[MAX_HTT_TID_NAME + 1] = {0}; + char tid_name[MAX_HTT_TID_NAME + 1] = {}; len += scnprintf(buf + len, buf_len - len, "HTT_TX_TID_STATS_V1_TLV:\n"); memcpy(tid_name, &(htt_stats_buf->tid_name[0]), MAX_HTT_TID_NAME); @@ -624,7 +625,7 @@ static inline void htt_print_rx_tid_stats_tlv(const void *tag_buf, u8 *buf = stats_req->buf; u32 len = stats_req->buf_len; u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; - char tid_name[MAX_HTT_TID_NAME + 1] = {0}; + char tid_name[MAX_HTT_TID_NAME + 1] = {}; len += scnprintf(buf + len, buf_len - len, "HTT_RX_TID_STATS_TLV:\n"); len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %lu\n", @@ -4712,7 +4713,7 @@ int ath11k_debugfs_htt_stats_req(struct ath11k *ar) u8 type = stats_req->type; u64 cookie = 0; int ret, pdev_id = ar->pdev->pdev_id; - struct htt_ext_stats_cfg_params cfg_params = { 0 }; + struct htt_ext_stats_cfg_params cfg_params = {}; init_completion(&stats_req->cmpln); @@ -4852,7 +4853,7 @@ static ssize_t ath11k_write_htt_stats_reset(struct file *file, { struct ath11k *ar = file->private_data; u8 type; - struct htt_ext_stats_cfg_params cfg_params = { 0 }; + struct htt_ext_stats_cfg_params cfg_params = {}; int ret; ret = kstrtou8_from_user(user_buf, count, 0, &type); diff --git a/drivers/net/wireless/ath/ath11k/debugfs_sta.c b/drivers/net/wireless/ath/ath11k/debugfs_sta.c index f56a24b6c8da..d89d0f28d890 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -456,7 +457,7 @@ static ssize_t ath11k_dbg_sta_read_peer_pktlog(struct file *file, struct ieee80211_sta *sta = file->private_data; struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta); struct ath11k *ar = arsta->arvif->ar; - char buf[32] = {0}; + char buf[32] = {}; int len; mutex_lock(&ar->conf_mutex); @@ -485,7 +486,7 @@ static ssize_t ath11k_dbg_sta_write_delba(struct file *file, struct ath11k *ar = arsta->arvif->ar; u32 tid, initiator, reason; int ret; - char buf[64] = {0}; + char buf[64] = {}; ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); @@ -536,7 +537,7 @@ static ssize_t ath11k_dbg_sta_write_addba_resp(struct file *file, struct ath11k *ar = arsta->arvif->ar; u32 tid, status; int ret; - char buf[64] = {0}; + char buf[64] = {}; ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); @@ -586,7 +587,7 @@ static ssize_t ath11k_dbg_sta_write_addba(struct file *file, struct ath11k *ar = arsta->arvif->ar; u32 tid, buf_size; int ret; - char buf[64] = {0}; + char buf[64] = {}; ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); @@ -700,7 +701,7 @@ ath11k_write_htt_peer_stats_reset(struct file *file, struct ieee80211_sta *sta = file->private_data; struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta); struct ath11k *ar = arsta->arvif->ar; - struct htt_ext_stats_cfg_params cfg_params = { 0 }; + struct htt_ext_stats_cfg_params cfg_params = {}; int ret; u8 type; diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index 4661e0d64dd9..56b1a657e0b0 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -225,7 +225,7 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, enum hal_ring_type type, int ring_num, int mac_id, int num_entries) { - struct hal_srng_params params = { 0 }; + struct hal_srng_params params = {}; int entry_sz = ath11k_hal_srng_get_entrysize(ab, type); int max_entries = ath11k_hal_srng_get_max_entries(ab, type); int ret; diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 1eec1cc114fe..ffc7482c77b6 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -719,7 +719,7 @@ static void ath11k_dp_reo_cmd_free(struct ath11k_dp *dp, void *ctx, static void ath11k_dp_reo_cache_flush(struct ath11k_base *ab, struct dp_rx_tid *rx_tid) { - struct ath11k_hal_reo_cmd cmd = {0}; + struct ath11k_hal_reo_cmd cmd = {}; unsigned long tot_desc_sz, desc_sz; int ret; @@ -811,7 +811,7 @@ free_desc: void ath11k_peer_rx_tid_delete(struct ath11k *ar, struct ath11k_peer *peer, u8 tid) { - struct ath11k_hal_reo_cmd cmd = {0}; + struct ath11k_hal_reo_cmd cmd = {}; struct dp_rx_tid *rx_tid = &peer->rx_tid[tid]; int ret; @@ -938,7 +938,7 @@ static int ath11k_peer_rx_tid_reo_update(struct ath11k *ar, u32 ba_win_sz, u16 ssn, bool update_ssn) { - struct ath11k_hal_reo_cmd cmd = {0}; + struct ath11k_hal_reo_cmd cmd = {}; int ret; cmd.addr_lo = lower_32_bits(rx_tid->paddr); @@ -1157,7 +1157,7 @@ int ath11k_dp_peer_rx_pn_replay_config(struct ath11k_vif *arvif, { struct ath11k *ar = arvif->ar; struct ath11k_base *ab = ar->ab; - struct ath11k_hal_reo_cmd cmd = {0}; + struct ath11k_hal_reo_cmd cmd = {}; struct ath11k_peer *peer; struct dp_rx_tid *rx_tid; u8 tid; @@ -2591,7 +2591,7 @@ static void ath11k_dp_rx_process_received_packets(struct ath11k_base *ab, { struct sk_buff *msdu; struct ath11k *ar; - struct ieee80211_rx_status rx_status = {0}; + struct ieee80211_rx_status rx_status = {}; int ret; if (skb_queue_empty(msdu_list)) @@ -2626,7 +2626,7 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id, { struct ath11k_dp *dp = &ab->dp; struct dp_rxdma_ring *rx_ring; - int num_buffs_reaped[MAX_RADIOS] = {0}; + int num_buffs_reaped[MAX_RADIOS] = {}; struct sk_buff_head msdu_list[MAX_RADIOS]; struct ath11k_skb_rxcb *rxcb; int total_msdu_reaped = 0; @@ -3224,7 +3224,7 @@ static int ath11k_dp_rx_h_michael_mic(struct crypto_shash *tfm, u8 *key, size_t data_len, u8 *mic) { SHASH_DESC_ON_STACK(desc, tfm); - u8 mic_hdr[16] = {0}; + u8 mic_hdr[16] = {}; u8 tid = 0; int ret; @@ -3818,7 +3818,7 @@ int ath11k_dp_process_rx_err(struct ath11k_base *ab, struct napi_struct *napi, struct dp_link_desc_bank *link_desc_banks; enum hal_rx_buf_return_buf_manager rbm; int tot_n_bufs_reaped, quota, ret, i; - int n_bufs_reaped[MAX_RADIOS] = {0}; + int n_bufs_reaped[MAX_RADIOS] = {}; struct dp_rxdma_ring *rx_ring; struct dp_srng *reo_except; u32 desc_bank, num_msdus; @@ -4099,7 +4099,7 @@ static void ath11k_dp_rx_wbm_err(struct ath11k *ar, struct sk_buff_head *msdu_list) { struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); - struct ieee80211_rx_status rxs = {0}; + struct ieee80211_rx_status rxs = {}; bool drop = true; switch (rxcb->err_rel_src) { @@ -4135,7 +4135,7 @@ int ath11k_dp_rx_process_wbm_err(struct ath11k_base *ab, struct ath11k_skb_rxcb *rxcb; u32 *rx_desc; int buf_id, mac_id; - int num_buffs_reaped[MAX_RADIOS] = {0}; + int num_buffs_reaped[MAX_RADIOS] = {}; int total_num_buffs_reaped = 0; int ret, i; diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c index 8522c67baabf..562aba66582f 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.c +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include "core.h" @@ -84,7 +85,7 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, { struct ath11k_base *ab = ar->ab; struct ath11k_dp *dp = &ab->dp; - struct hal_tx_info ti = {0}; + struct hal_tx_info ti = {}; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb); struct hal_srng *tcl_ring; @@ -316,7 +317,7 @@ ath11k_dp_tx_htt_tx_complete_buf(struct ath11k_base *ab, struct dp_tx_ring *tx_ring, struct ath11k_dp_htt_wbm_tx_status *ts) { - struct ieee80211_tx_status status = { 0 }; + struct ieee80211_tx_status status = {}; struct sk_buff *msdu; struct ieee80211_tx_info *info; struct ath11k_skb_cb *skb_cb; @@ -391,7 +392,7 @@ ath11k_dp_tx_process_htt_tx_complete(struct ath11k_base *ab, u32 msdu_id, struct dp_tx_ring *tx_ring) { struct htt_tx_wbm_completion *status_desc; - struct ath11k_dp_htt_wbm_tx_status ts = {0}; + struct ath11k_dp_htt_wbm_tx_status ts = {}; enum hal_wbm_htt_tx_comp_status wbm_status; status_desc = desc + HTT_TX_WBM_COMP_STATUS_OFFSET; @@ -551,8 +552,8 @@ static void ath11k_dp_tx_complete_msdu(struct ath11k *ar, struct sk_buff *msdu, struct hal_tx_status *ts) { - struct ieee80211_tx_status status = { 0 }; - struct ieee80211_rate_status status_rate = { 0 }; + struct ieee80211_tx_status status = {}; + struct ieee80211_rate_status status_rate = {}; struct ath11k_base *ab = ar->ab; struct ieee80211_tx_info *info; struct ath11k_skb_cb *skb_cb; @@ -690,7 +691,7 @@ void ath11k_dp_tx_completion_handler(struct ath11k_base *ab, int ring_id) int hal_ring_id = dp->tx_ring[ring_id].tcl_comp_ring.ring_id; struct hal_srng *status_ring = &ab->hal.srng_list[hal_ring_id]; struct sk_buff *msdu; - struct hal_tx_status ts = { 0 }; + struct hal_tx_status ts = {}; struct dp_tx_ring *tx_ring = &dp->tx_ring[ring_id]; u32 *desc; u32 msdu_id; @@ -1187,7 +1188,7 @@ int ath11k_dp_tx_htt_monitor_mode_ring_config(struct ath11k *ar, bool reset) { struct ath11k_pdev_dp *dp = &ar->dp; struct ath11k_base *ab = ar->ab; - struct htt_rx_ring_tlv_filter tlv_filter = {0}; + struct htt_rx_ring_tlv_filter tlv_filter = {}; int ret = 0, ring_id = 0, i; if (ab->hw_params.full_monitor_mode) { diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 7dde21289a52..1fadf5faafb8 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1037,7 +1037,7 @@ static int ath11k_mac_monitor_vdev_create(struct ath11k *ar) struct ath11k_pdev *pdev = ar->pdev; struct vdev_create_params param = {}; int bit, ret; - u8 tmp_addr[6] = {0}; + u8 tmp_addr[6] = {}; u16 nss; lockdep_assert_held(&ar->conf_mutex); @@ -3026,7 +3026,7 @@ static bool ath11k_mac_vif_recalc_sta_he_txbf(struct ath11k *ar, struct ieee80211_sta_he_cap *he_cap) { struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); - struct ieee80211_he_cap_elem he_cap_elem = {0}; + struct ieee80211_he_cap_elem he_cap_elem = {}; struct ieee80211_sta_he_cap *cap_band = NULL; struct cfg80211_chan_def def; u32 param = WMI_VDEV_PARAM_SET_HEMU_MODE; @@ -3763,7 +3763,7 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, ath11k_recalculate_mgmt_rate(ar, vif, &def); if (changed & BSS_CHANGED_TWT) { - struct wmi_twt_enable_params twt_params = {0}; + struct wmi_twt_enable_params twt_params = {}; if (info->twt_requester || info->twt_responder) { ath11k_wmi_fill_default_twt_params(&twt_params); @@ -5323,7 +5323,7 @@ static struct ieee80211_sta_ht_cap ath11k_create_ht_cap(struct ath11k *ar, u32 ar_ht_cap, u32 rate_cap_rx_chainmask) { int i; - struct ieee80211_sta_ht_cap ht_cap = {0}; + struct ieee80211_sta_ht_cap ht_cap = {}; u32 ar_vht_cap = ar->pdev->cap.vht_cap; if (!(ar_ht_cap & WMI_HT_CAP_ENABLED)) @@ -5490,7 +5490,7 @@ static struct ieee80211_sta_vht_cap ath11k_create_vht_cap(struct ath11k *ar, u32 rate_cap_tx_chainmask, u32 rate_cap_rx_chainmask) { - struct ieee80211_sta_vht_cap vht_cap = {0}; + struct ieee80211_sta_vht_cap vht_cap = {}; u16 txmcs_map, rxmcs_map; int i; @@ -6159,7 +6159,7 @@ void ath11k_mac_drain_tx(struct ath11k *ar) static int ath11k_mac_config_mon_status_default(struct ath11k *ar, bool enable) { - struct htt_rx_ring_tlv_filter tlv_filter = {0}; + struct htt_rx_ring_tlv_filter tlv_filter = {}; struct ath11k_base *ab = ar->ab; int i, ret = 0; u32 ring_id; @@ -6678,7 +6678,7 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, struct ath11k *ar = hw->priv; struct ath11k_base *ab = ar->ab; struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); - struct vdev_create_params vdev_param = {0}; + struct vdev_create_params vdev_param = {}; struct peer_create_params peer_param; u32 param_id, param_value; u16 nss; @@ -10421,7 +10421,7 @@ int ath11k_mac_register(struct ath11k_base *ab) struct ath11k_pdev *pdev; int i; int ret; - u8 mac_addr[ETH_ALEN] = {0}; + u8 mac_addr[ETH_ALEN] = {}; if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) return 0; diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 78444f8ea153..d8655badd96d 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -37,7 +37,7 @@ static const struct pci_device_id ath11k_pci_id_table[] = { { PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) }, { PCI_VDEVICE(QCOM, WCN6855_DEVICE_ID) }, { PCI_VDEVICE(QCOM, QCN9074_DEVICE_ID) }, - {0} + {} }; MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); @@ -692,7 +692,7 @@ static void ath11k_pci_coredump_download(struct ath11k_base *ab) struct ath11k_tlv_dump_data *dump_tlv; size_t hdr_len = sizeof(*file_data); void *buf; - u32 dump_seg_sz[FW_CRASH_DUMP_TYPE_MAX] = { 0 }; + u32 dump_seg_sz[FW_CRASH_DUMP_TYPE_MAX] = {}; ath11k_mhi_coredump(mhi_ctrl, false); diff --git a/drivers/net/wireless/ath/ath11k/spectral.c b/drivers/net/wireless/ath/ath11k/spectral.c index 79e091134515..b6b0516819a6 100644 --- a/drivers/net/wireless/ath/ath11k/spectral.c +++ b/drivers/net/wireless/ath/ath11k/spectral.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -205,7 +206,7 @@ static int ath11k_spectral_scan_trigger(struct ath11k *ar) static int ath11k_spectral_scan_config(struct ath11k *ar, enum ath11k_spectral_mode mode) { - struct ath11k_wmi_vdev_spectral_conf_param param = { 0 }; + struct ath11k_wmi_vdev_spectral_conf_param param = {}; struct ath11k_vif *arvif; int ret, count; diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 56af2e9634f4..0491e3fd6b5e 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -7542,7 +7542,7 @@ static void ath11k_vdev_stopped_event(struct ath11k_base *ab, struct sk_buff *sk static void ath11k_mgmt_rx_event(struct ath11k_base *ab, struct sk_buff *skb) { - struct mgmt_rx_event_params rx_ev = {0}; + struct mgmt_rx_event_params rx_ev = {}; struct ath11k *ar; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_hdr *hdr; @@ -7657,7 +7657,7 @@ exit: static void ath11k_mgmt_tx_compl_event(struct ath11k_base *ab, struct sk_buff *skb) { - struct wmi_mgmt_tx_compl_event tx_compl_param = {0}; + struct wmi_mgmt_tx_compl_event tx_compl_param = {}; struct ath11k *ar; if (ath11k_pull_mgmt_tx_compl_param_tlv(ab, skb, &tx_compl_param) != 0) { @@ -7712,7 +7712,7 @@ static struct ath11k *ath11k_get_ar_on_scan_state(struct ath11k_base *ab, static void ath11k_scan_event(struct ath11k_base *ab, struct sk_buff *skb) { struct ath11k *ar; - struct wmi_scan_event scan_ev = {0}; + struct wmi_scan_event scan_ev = {}; if (ath11k_pull_scan_ev(ab, skb, &scan_ev) != 0) { ath11k_warn(ab, "failed to extract scan event"); @@ -7884,7 +7884,7 @@ static void ath11k_roam_event(struct ath11k_base *ab, struct sk_buff *skb) static void ath11k_chan_info_event(struct ath11k_base *ab, struct sk_buff *skb) { - struct wmi_chan_info_event ch_info_ev = {0}; + struct wmi_chan_info_event ch_info_ev = {}; struct ath11k *ar; struct survey_info *survey; int idx; @@ -8031,7 +8031,7 @@ exit: static void ath11k_vdev_install_key_compl_event(struct ath11k_base *ab, struct sk_buff *skb) { - struct wmi_vdev_install_key_complete_arg install_key_compl = {0}; + struct wmi_vdev_install_key_complete_arg install_key_compl = {}; struct ath11k *ar; if (ath11k_pull_vdev_install_key_compl_ev(ab, skb, &install_key_compl) != 0) { @@ -8129,7 +8129,7 @@ static void ath11k_service_available_event(struct ath11k_base *ab, struct sk_buf static void ath11k_peer_assoc_conf_event(struct ath11k_base *ab, struct sk_buff *skb) { - struct wmi_peer_assoc_conf_arg peer_assoc_conf = {0}; + struct wmi_peer_assoc_conf_arg peer_assoc_conf = {}; struct ath11k *ar; if (ath11k_pull_peer_assoc_conf_ev(ab, skb, &peer_assoc_conf) != 0) { From 306facc029ba8d217ef5a46e8cf4bd50c70603d0 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 20 Jul 2025 08:24:14 -0700 Subject: [PATCH 160/199] wifi: ath12k: Prefer {} to {0} in initializers Prefer {} to {0} in initializers since {} works even when the first member is not a scalar. Generated using: sed -i 's/{[[:space:]]*0[[:space:]]*}/{}/g' drivers/net/wireless/ath/ath12k/* Compile tested only. Link: https://patch.msgid.link/20250720-ath12k-zero-brace-v1-1-d8c8ca9d40a8@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/ce.c | 2 +- drivers/net/wireless/ath/ath12k/core.c | 2 +- drivers/net/wireless/ath/ath12k/dbring.c | 3 ++- drivers/net/wireless/ath/ath12k/debugfs.c | 8 ++++---- .../wireless/ath/ath12k/debugfs_htt_stats.c | 12 ++++++------ drivers/net/wireless/ath/ath12k/dp.c | 6 +++--- drivers/net/wireless/ath/ath12k/dp_rx.c | 18 +++++++++--------- drivers/net/wireless/ath/ath12k/dp_tx.c | 10 +++++----- drivers/net/wireless/ath/ath12k/mac.c | 16 ++++++++-------- drivers/net/wireless/ath/ath12k/pci.c | 4 ++-- drivers/net/wireless/ath/ath12k/wmi.c | 14 +++++++------- 11 files changed, 48 insertions(+), 47 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/ce.c b/drivers/net/wireless/ath/ath12k/ce.c index f7c15b547504..f93a419abf65 100644 --- a/drivers/net/wireless/ath/ath12k/ce.c +++ b/drivers/net/wireless/ath/ath12k/ce.c @@ -578,7 +578,7 @@ static int ath12k_ce_init_ring(struct ath12k_base *ab, struct ath12k_ce_ring *ce_ring, int ce_id, enum hal_ring_type type) { - struct hal_srng_params params = { 0 }; + struct hal_srng_params params = {}; int ret; params.ring_base_paddr = ce_ring->base_addr_ce_space; diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index bf46acb54268..5d494c5cdc0d 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -218,7 +218,7 @@ static int __ath12k_core_create_board_name(struct ath12k_base *ab, char *name, bool bus_type_mode, bool with_default) { /* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */ - char variant[9 + ATH12K_QMI_BDF_EXT_STR_LENGTH] = { 0 }; + char variant[9 + ATH12K_QMI_BDF_EXT_STR_LENGTH] = {}; if (with_variant && ab->qmi.target.bdf_ext[0] != '\0') scnprintf(variant, sizeof(variant), ",variant=%s", diff --git a/drivers/net/wireless/ath/ath12k/dbring.c b/drivers/net/wireless/ath/ath12k/dbring.c index 788160c84c68..6604dacea2ae 100644 --- a/drivers/net/wireless/ath/ath12k/dbring.c +++ b/drivers/net/wireless/ath/ath12k/dbring.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include "core.h" @@ -117,7 +118,7 @@ int ath12k_dbring_wmi_cfg_setup(struct ath12k *ar, struct ath12k_dbring *ring, enum wmi_direct_buffer_module id) { - struct ath12k_wmi_pdev_dma_ring_cfg_arg arg = {0}; + struct ath12k_wmi_pdev_dma_ring_cfg_arg arg = {}; int ret; if (id >= WMI_DIRECT_BUF_MAX) diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c index 23da93afaa5c..16601a8c3644 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs.c +++ b/drivers/net/wireless/ath/ath12k/debugfs.c @@ -52,7 +52,7 @@ ath12k_write_simulate_fw_crash(struct file *file, struct ath12k_base *ab = file->private_data; struct ath12k_pdev *pdev; struct ath12k *ar = NULL; - char buf[32] = {0}; + char buf[32] = {}; int i, ret; ssize_t rc; @@ -816,7 +816,7 @@ static ssize_t ath12k_write_extd_rx_stats(struct file *file, size_t count, loff_t *ppos) { struct ath12k *ar = file->private_data; - struct htt_rx_ring_tlv_filter tlv_filter = {0}; + struct htt_rx_ring_tlv_filter tlv_filter = {}; u32 ring_id, rx_filter = 0; bool enable; int ret, i; @@ -1217,7 +1217,7 @@ void ath12k_debugfs_pdev_create(struct ath12k_base *ab) void ath12k_debugfs_soc_create(struct ath12k_base *ab) { bool dput_needed; - char soc_name[64] = { 0 }; + char soc_name[64] = {}; struct dentry *debugfs_ath12k; debugfs_ath12k = debugfs_lookup("ath12k", NULL); @@ -1470,7 +1470,7 @@ void ath12k_debugfs_register(struct ath12k *ar) struct ath12k_base *ab = ar->ab; struct ieee80211_hw *hw = ar->ah->hw; char pdev_name[5]; - char buf[100] = {0}; + char buf[100] = {}; scnprintf(pdev_name, sizeof(pdev_name), "%s%d", "mac", ar->pdev_idx); diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c index 96c834b987db..48b010a1b756 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c @@ -2024,7 +2024,7 @@ ath12k_htt_print_stats_string_tlv(const void *tag_buf, u16 tag_len, u8 i; u16 index = 0; u32 datum; - char data[ATH12K_HTT_MAX_STRING_LEN] = {0}; + char data[ATH12K_HTT_MAX_STRING_LEN] = {}; tag_len = tag_len >> 2; @@ -3081,7 +3081,7 @@ ath12k_htt_print_ul_mumimo_trig_stats(const void *tag_buf, u16 tag_len, struct debug_htt_stats_req *stats_req) { const struct ath12k_htt_rx_ul_mumimo_trig_stats_tlv *htt_stats_buf = tag_buf; - char str_buf[ATH12K_HTT_MAX_STRING_LEN] = {0}; + char str_buf[ATH12K_HTT_MAX_STRING_LEN] = {}; u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; u32 len = stats_req->buf_len; u8 *buf = stats_req->buf; @@ -3642,7 +3642,7 @@ ath12k_htt_print_dlpager_stats_tlv(const void *tag_buf, u16 tag_len, u8 *buf = stats_req->buf; u8 pg_locked; u8 pg_unlock; - char str_buf[ATH12K_HTT_MAX_STRING_LEN] = {0}; + char str_buf[ATH12K_HTT_MAX_STRING_LEN] = {}; if (tag_len < sizeof(*stat_buf)) return; @@ -5923,7 +5923,7 @@ static ssize_t ath12k_write_htt_stats_type(struct file *file, { struct ath12k *ar = file->private_data; enum ath12k_dbg_htt_ext_stats_type type; - unsigned int cfg_param[4] = {0}; + unsigned int cfg_param[4] = {}; const int size = 32; int num_args; @@ -5973,7 +5973,7 @@ static int ath12k_debugfs_htt_stats_req(struct ath12k *ar) enum ath12k_dbg_htt_ext_stats_type type = stats_req->type; u64 cookie; int ret, pdev_id; - struct htt_ext_stats_cfg_params cfg_params = { 0 }; + struct htt_ext_stats_cfg_params cfg_params = {}; lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); @@ -6112,7 +6112,7 @@ static ssize_t ath12k_write_htt_stats_reset(struct file *file, { struct ath12k *ar = file->private_data; enum ath12k_dbg_htt_ext_stats_type type; - struct htt_ext_stats_cfg_params cfg_params = { 0 }; + struct htt_ext_stats_cfg_params cfg_params = {}; u8 param_pos; int ret; diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index d80af435959a..d6435dad61a1 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -242,7 +242,7 @@ int ath12k_dp_srng_setup(struct ath12k_base *ab, struct dp_srng *ring, enum hal_ring_type type, int ring_num, int mac_id, int num_entries) { - struct hal_srng_params params = { 0 }; + struct hal_srng_params params = {}; int entry_sz = ath12k_hal_srng_get_entrysize(ab, type); int max_entries = ath12k_hal_srng_get_max_entries(ab, type); int ret; @@ -1084,8 +1084,8 @@ out: int ath12k_dp_htt_connect(struct ath12k_dp *dp) { - struct ath12k_htc_svc_conn_req conn_req = {0}; - struct ath12k_htc_svc_conn_resp conn_resp = {0}; + struct ath12k_htc_svc_conn_req conn_req = {}; + struct ath12k_htc_svc_conn_resp conn_resp = {}; int status; conn_req.ep_ops.ep_tx_complete = ath12k_dp_htt_htc_tx_complete; diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index e44bb2e8490d..dbac95d0bc86 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -671,7 +671,7 @@ static int ath12k_dp_reo_cmd_send(struct ath12k_base *ab, struct ath12k_dp_rx_ti static void ath12k_dp_reo_cache_flush(struct ath12k_base *ab, struct ath12k_dp_rx_tid *rx_tid) { - struct ath12k_hal_reo_cmd cmd = {0}; + struct ath12k_hal_reo_cmd cmd = {}; unsigned long tot_desc_sz, desc_sz; int ret; @@ -828,7 +828,7 @@ static void ath12k_peer_rx_tid_qref_reset(struct ath12k_base *ab, u16 peer_id, u void ath12k_dp_rx_peer_tid_delete(struct ath12k *ar, struct ath12k_peer *peer, u8 tid) { - struct ath12k_hal_reo_cmd cmd = {0}; + struct ath12k_hal_reo_cmd cmd = {}; struct ath12k_dp_rx_tid *rx_tid = &peer->rx_tid[tid]; int ret; @@ -939,7 +939,7 @@ static int ath12k_peer_rx_tid_reo_update(struct ath12k *ar, u32 ba_win_sz, u16 ssn, bool update_ssn) { - struct ath12k_hal_reo_cmd cmd = {0}; + struct ath12k_hal_reo_cmd cmd = {}; int ret; cmd.addr_lo = lower_32_bits(rx_tid->qbuf.paddr_aligned); @@ -1203,7 +1203,7 @@ int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_link_vif *arvif, { struct ath12k *ar = arvif->ar; struct ath12k_base *ab = ar->ab; - struct ath12k_hal_reo_cmd cmd = {0}; + struct ath12k_hal_reo_cmd cmd = {}; struct ath12k_peer *peer; struct ath12k_dp_rx_tid *rx_tid; u8 tid; @@ -2734,7 +2734,7 @@ static void ath12k_dp_rx_process_received_packets(struct ath12k_base *ab, int ring_id) { struct ath12k_hw_group *ag = ab->ag; - struct ieee80211_rx_status rx_status = {0}; + struct ieee80211_rx_status rx_status = {}; struct ath12k_skb_rxcb *rxcb; struct sk_buff *msdu; struct ath12k *ar; @@ -3029,7 +3029,7 @@ static int ath12k_dp_rx_h_michael_mic(struct crypto_shash *tfm, u8 *key, size_t data_len, u8 *mic) { SHASH_DESC_ON_STACK(desc, tfm); - u8 mic_hdr[16] = {0}; + u8 mic_hdr[16] = {}; u8 tid = 0; int ret; @@ -3998,7 +3998,7 @@ static void ath12k_dp_rx_wbm_err(struct ath12k *ar, struct sk_buff_head *msdu_list) { struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); - struct ieee80211_rx_status rxs = {0}; + struct ieee80211_rx_status rxs = {}; struct ath12k_dp_rx_info rx_info; bool drop = true; @@ -4345,7 +4345,7 @@ void ath12k_dp_rx_pdev_free(struct ath12k_base *ab, int mac_id) int ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab) { struct ath12k_dp *dp = &ab->dp; - struct htt_rx_ring_tlv_filter tlv_filter = {0}; + struct htt_rx_ring_tlv_filter tlv_filter = {}; u32 ring_id; int ret; u32 hal_rx_desc_sz = ab->hal.hal_desc_sz; @@ -4386,7 +4386,7 @@ int ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab) int ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab) { struct ath12k_dp *dp = &ab->dp; - struct htt_rx_ring_tlv_filter tlv_filter = {0}; + struct htt_rx_ring_tlv_filter tlv_filter = {}; u32 ring_id; int ret = 0; u32 hal_rx_desc_sz = ab->hal.hal_desc_sz; diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index d79c2ff77952..abc84ca8467a 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -225,7 +225,7 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif, { struct ath12k_base *ab = ar->ab; struct ath12k_dp *dp = &ab->dp; - struct hal_tx_info ti = {0}; + struct hal_tx_info ti = {}; struct ath12k_tx_desc_info *tx_desc; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb); @@ -659,7 +659,7 @@ ath12k_dp_tx_process_htt_tx_complete(struct ath12k_base *ab, void *desc, struct ath12k_tx_desc_params *desc_params) { struct htt_tx_wbm_completion *status_desc; - struct ath12k_dp_htt_wbm_tx_status ts = {0}; + struct ath12k_dp_htt_wbm_tx_status ts = {}; enum hal_wbm_htt_tx_comp_status wbm_status; u16 peer_id; @@ -705,7 +705,7 @@ static void ath12k_dp_tx_update_txcompl(struct ath12k *ar, struct hal_tx_status struct ieee80211_sta *sta; struct ath12k_sta *ahsta; struct ath12k_link_sta *arsta; - struct rate_info txrate = {0}; + struct rate_info txrate = {}; u16 rate, ru_tones; u8 rate_idx = 0; int ret; @@ -1001,7 +1001,7 @@ void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id) int hal_ring_id = dp->tx_ring[ring_id].tcl_comp_ring.ring_id; struct hal_srng *status_ring = &ab->hal.srng_list[hal_ring_id]; struct ath12k_tx_desc_info *tx_desc = NULL; - struct hal_tx_status ts = { 0 }; + struct hal_tx_status ts = {}; struct ath12k_tx_desc_params desc_params; struct dp_tx_ring *tx_ring = &dp->tx_ring[ring_id]; struct hal_wbm_release_ring *desc; @@ -1571,7 +1571,7 @@ int ath12k_dp_tx_htt_monitor_mode_ring_config(struct ath12k *ar, bool reset) int ath12k_dp_tx_htt_rx_monitor_mode_ring_config(struct ath12k *ar, bool reset) { struct ath12k_base *ab = ar->ab; - struct htt_rx_ring_tlv_filter tlv_filter = {0}; + struct htt_rx_ring_tlv_filter tlv_filter = {}; int ret, ring_id, i; tlv_filter.offset_valid = false; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 05250fa0600d..7f80c72611c8 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -6375,7 +6375,7 @@ static int ath12k_mac_station_add(struct ath12k *ar, struct ath12k_base *ab = ar->ab; struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); - struct ath12k_wmi_peer_create_arg peer_param = {0}; + struct ath12k_wmi_peer_create_arg peer_param = {}; int ret; lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); @@ -6719,7 +6719,7 @@ static int ath12k_mac_mlo_sta_set_link_active(struct ath12k_base *ab, u8 *mlo_inactive_vdev_lst, u8 num_mlo_inactive_vdev) { - struct wmi_mlo_link_set_active_arg param = {0}; + struct wmi_mlo_link_set_active_arg param = {}; u32 entry_idx, entry_offset, vdev_idx; u8 vdev_id; @@ -6781,8 +6781,8 @@ static int ath12k_mac_mlo_sta_update_link_active(struct ath12k_base *ab, struct ieee80211_hw *hw, struct ath12k_vif *ahvif) { - u8 mlo_vdev_id_lst[IEEE80211_MLD_MAX_NUM_LINKS] = {0}; - u32 mlo_freq_list[IEEE80211_MLD_MAX_NUM_LINKS] = {0}; + u8 mlo_vdev_id_lst[IEEE80211_MLD_MAX_NUM_LINKS] = {}; + u32 mlo_freq_list[IEEE80211_MLD_MAX_NUM_LINKS] = {}; unsigned long links = ahvif->links_map; enum wmi_mlo_link_force_reason reason; struct ieee80211_chanctx_conf *conf; @@ -7519,7 +7519,7 @@ static struct ieee80211_sta_ht_cap ath12k_create_ht_cap(struct ath12k *ar, u32 ar_ht_cap, u32 rate_cap_rx_chainmask) { int i; - struct ieee80211_sta_ht_cap ht_cap = {0}; + struct ieee80211_sta_ht_cap ht_cap = {}; u32 ar_vht_cap = ar->pdev->cap.vht_cap; if (!(ar_ht_cap & WMI_HT_CAP_ENABLED)) @@ -7675,7 +7675,7 @@ static struct ieee80211_sta_vht_cap ath12k_create_vht_cap(struct ath12k *ar, u32 rate_cap_tx_chainmask, u32 rate_cap_rx_chainmask) { - struct ieee80211_sta_vht_cap vht_cap = {0}; + struct ieee80211_sta_vht_cap vht_cap = {}; u16 txmcs_map, rxmcs_map; int i; @@ -9682,8 +9682,8 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif) struct ieee80211_hw *hw = ah->hw; struct ath12k_vif *ahvif = arvif->ahvif; struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); - struct ath12k_wmi_vdev_create_arg vdev_arg = {0}; - struct ath12k_wmi_peer_create_arg peer_param = {0}; + struct ath12k_wmi_vdev_create_arg vdev_arg = {}; + struct ath12k_wmi_peer_create_arg peer_param = {}; struct ieee80211_bss_conf *link_conf = NULL; u32 param_id, param_value; u16 nss; diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index b4e7e77518dd..c729d5526c75 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -48,7 +48,7 @@ static const struct pci_device_id ath12k_pci_id_table[] = { { PCI_VDEVICE(QCOM, QCN9274_DEVICE_ID) }, { PCI_VDEVICE(QCOM, WCN7850_DEVICE_ID) }, - {0} + {} }; MODULE_DEVICE_TABLE(pci, ath12k_pci_id_table); @@ -1353,7 +1353,7 @@ static void ath12k_pci_coredump_download(struct ath12k_base *ab) struct ath12k_tlv_dump_data *dump_tlv; size_t hdr_len = sizeof(*file_data); void *buf; - u32 dump_seg_sz[FW_CRASH_DUMP_TYPE_MAX] = { 0 }; + u32 dump_seg_sz[FW_CRASH_DUMP_TYPE_MAX] = {}; ath12k_mhi_coredump(mhi_ctrl, false); diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index a2a493928d08..da85c28ec355 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -7039,7 +7039,7 @@ static void ath12k_vdev_stopped_event(struct ath12k_base *ab, struct sk_buff *sk static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb) { - struct ath12k_wmi_mgmt_rx_arg rx_ev = {0}; + struct ath12k_wmi_mgmt_rx_arg rx_ev = {}; struct ath12k *ar; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_hdr *hdr; @@ -7158,7 +7158,7 @@ exit: static void ath12k_mgmt_tx_compl_event(struct ath12k_base *ab, struct sk_buff *skb) { - struct wmi_mgmt_tx_compl_event tx_compl_param = {0}; + struct wmi_mgmt_tx_compl_event tx_compl_param = {}; struct ath12k *ar; if (ath12k_pull_mgmt_tx_compl_param_tlv(ab, skb, &tx_compl_param) != 0) { @@ -7216,7 +7216,7 @@ static struct ath12k *ath12k_get_ar_on_scan_state(struct ath12k_base *ab, static void ath12k_scan_event(struct ath12k_base *ab, struct sk_buff *skb) { struct ath12k *ar; - struct wmi_scan_event scan_ev = {0}; + struct wmi_scan_event scan_ev = {}; if (ath12k_pull_scan_ev(ab, skb, &scan_ev) != 0) { ath12k_warn(ab, "failed to extract scan event"); @@ -7393,7 +7393,7 @@ static void ath12k_roam_event(struct ath12k_base *ab, struct sk_buff *skb) static void ath12k_chan_info_event(struct ath12k_base *ab, struct sk_buff *skb) { - struct wmi_chan_info_event ch_info_ev = {0}; + struct wmi_chan_info_event ch_info_ev = {}; struct ath12k *ar; struct survey_info *survey; int idx; @@ -7541,7 +7541,7 @@ exit: static void ath12k_vdev_install_key_compl_event(struct ath12k_base *ab, struct sk_buff *skb) { - struct wmi_vdev_install_key_complete_arg install_key_compl = {0}; + struct wmi_vdev_install_key_complete_arg install_key_compl = {}; struct ath12k *ar; if (ath12k_pull_vdev_install_key_compl_ev(ab, skb, &install_key_compl) != 0) { @@ -7646,7 +7646,7 @@ static int ath12k_service_available_event(struct ath12k_base *ab, struct sk_buff static void ath12k_peer_assoc_conf_event(struct ath12k_base *ab, struct sk_buff *skb) { - struct wmi_peer_assoc_conf_arg peer_assoc_conf = {0}; + struct wmi_peer_assoc_conf_arg peer_assoc_conf = {}; struct ath12k *ar; if (ath12k_pull_peer_assoc_conf_ev(ab, skb, &peer_assoc_conf) != 0) { @@ -8592,7 +8592,7 @@ ath12k_wmi_pdev_temperature_event(struct ath12k_base *ab, struct sk_buff *skb) { struct ath12k *ar; - struct wmi_pdev_temperature_event ev = {0}; + struct wmi_pdev_temperature_event ev = {}; if (ath12k_pull_pdev_temp_ev(ab, skb, &ev) != 0) { ath12k_warn(ab, "failed to extract pdev temperature event"); From c4825d540f4beb179d552f3aa1f44f8db5095fb6 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Mon, 21 Jul 2025 10:27:26 +0800 Subject: [PATCH 161/199] wifi: ath12k: bring DFS support back for WCN7850 Due to the restrict in MAC80211 that DFS (Dynamic Frequency Selection) can't be enabled on multiple channels, commit 176f3009ae59 ("wifi: ath12k: support 2 channels for single pdev device") removes DFS support in order to support 2 channels concurrently, making AP mode not working on DFS channels [1]. Revert portions of that commit to bring DFS back, and add a new combination to support 2-channels concurrency. This is valid because the MAC80211 restrict works on each individual combination, but does not care about them as a whole, as far as DFS is concerned. This change applies to WCN7850 only, other chips are not affected. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00284.1-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Fixes: 176f3009ae59 ("wifi: ath12k: support 2 channels for single pdev device") Reported-by: Mihai Moldovan Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220346 # 1 Signed-off-by: Baochen Qiang Reviewed-by: Vasanthakumar Thiagarajan Tested-by: Mihai Moldovan Link: https://patch.msgid.link/20250721-ath12k-dfs-v1-1-065c31454f91@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 47 +++++++++++++++++---------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 7f80c72611c8..bd1ec3b2c084 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -13365,16 +13365,12 @@ ath12k_mac_setup_radio_iface_comb(struct ath12k *ar, comb[0].beacon_int_infra_match = true; comb[0].beacon_int_min_gcd = 100; - if (ar->ab->hw_params->single_pdev_only) { - comb[0].num_different_channels = 2; - } else { - comb[0].num_different_channels = 1; - comb[0].radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | - BIT(NL80211_CHAN_WIDTH_20) | - BIT(NL80211_CHAN_WIDTH_40) | - BIT(NL80211_CHAN_WIDTH_80) | - BIT(NL80211_CHAN_WIDTH_160); - } + comb[0].num_different_channels = 1; + comb[0].radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80) | + BIT(NL80211_CHAN_WIDTH_160); return 0; } @@ -13457,25 +13453,42 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah) struct ieee80211_iface_combination *combinations, *comb; struct wiphy *wiphy = ah->hw->wiphy; struct wiphy_radio *radio; + int n_combinations = 1; struct ath12k *ar; int i, ret; - combinations = kzalloc(sizeof(*combinations), GFP_KERNEL); - if (!combinations) - return -ENOMEM; - if (ah->num_radio == 1) { - ret = ath12k_mac_setup_radio_iface_comb(&ah->radio[0], - combinations); + ar = &ah->radio[0]; + + if (ar->ab->hw_params->single_pdev_only) + n_combinations = 2; + + combinations = kcalloc(n_combinations, sizeof(*combinations), + GFP_KERNEL); + if (!combinations) + return -ENOMEM; + + ret = ath12k_mac_setup_radio_iface_comb(ar, combinations); if (ret) { ath12k_hw_warn(ah, "failed to setup radio interface combinations for one radio: %d", ret); goto err_free_combinations; } + if (ar->ab->hw_params->single_pdev_only) { + comb = combinations + 1; + memcpy(comb, combinations, sizeof(*comb)); + comb->num_different_channels = 2; + comb->radar_detect_widths = 0; + } + goto out; } + combinations = kcalloc(n_combinations, sizeof(*combinations), GFP_KERNEL); + if (!combinations) + return -ENOMEM; + /* there are multiple radios */ radio = kcalloc(ah->num_radio, sizeof(*radio), GFP_KERNEL); @@ -13518,7 +13531,7 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah) out: wiphy->iface_combinations = combinations; - wiphy->n_iface_combinations = 1; + wiphy->n_iface_combinations = n_combinations; return 0; From 4a2bf707270f897ab8077baee8ed5842a5321686 Mon Sep 17 00:00:00 2001 From: Sarika Sharma Date: Mon, 21 Jul 2025 11:47:49 +0530 Subject: [PATCH 162/199] wifi: ath12k: Correct tid cleanup when tid setup fails Currently, if any error occurs during ath12k_dp_rx_peer_tid_setup(), the tid value is already incremented, even though the corresponding TID is not actually allocated. Proceed to ath12k_dp_rx_peer_tid_delete() starting from unallocated tid, which might leads to freeing unallocated TID and cause potential crash or out-of-bounds access. Hence, fix by correctly decrementing tid before cleanup to match only the successfully allocated TIDs. Also, remove tid-- from failure case of ath12k_dp_rx_peer_frag_setup(), as decrementing the tid before cleanup in loop will take care of this. Compile tested only. Signed-off-by: Sarika Sharma Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250721061749.886732-1-quic_sarishar@quicinc.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/dp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index d6435dad61a1..f893fce6d9bd 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -84,7 +84,6 @@ int ath12k_dp_peer_setup(struct ath12k *ar, int vdev_id, const u8 *addr) ret = ath12k_dp_rx_peer_frag_setup(ar, addr, vdev_id); if (ret) { ath12k_warn(ab, "failed to setup rx defrag context\n"); - tid--; goto peer_clean; } @@ -102,7 +101,7 @@ peer_clean: return -ENOENT; } - for (; tid >= 0; tid--) + for (tid--; tid >= 0; tid--) ath12k_dp_rx_peer_tid_delete(ar, peer, tid); spin_unlock_bh(&ab->base_lock); From 7b87c542c0115726f67461a6360d2cece1d11896 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Wed, 16 Jul 2025 22:19:11 +0200 Subject: [PATCH 163/199] wifi: iwlwifi: fix cmd length when sending WOWLAN_TSC_RSC_PARAM In iwl_mvm_wowlan_config_rsc_tsc() when calling iwl_mvm_send_cmd_pdu() we are accidentally passing the size of a pointer rather than the size of the object pointed by it. Fix the expression in order to pass the approriate object length. Fixes: 493681d9f95b ("wifi: iwlwifi: remove support of version 4 of iwl_wowlan_rsc_tsc_params_cmd") Address-Coverity-ID: 1647627 ("Incorrect expression (SIZEOF_MISMATCH)") Signed-off-by: Antonio Quartulli Link: https://patch.msgid.link/20250716201911.700-1-antonio@mandelbit.com Signed-off-by: Miri Korenblit --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index ef9bab042902..b8754d7e51c5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -494,7 +494,7 @@ static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm, if (data.have_rsc_tsc) ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_TSC_RSC_PARAM, CMD_ASYNC, - sizeof(data.rsc_tsc), + sizeof(*data.rsc_tsc), data.rsc_tsc); else ret = 0; From 9296cc59b2278a30a44504fd588b119aff7896ae Mon Sep 17 00:00:00 2001 From: WangYuli Date: Tue, 15 Jul 2025 13:58:27 +0800 Subject: [PATCH 164/199] wifi: iwlwifi: Fix typo "ransport" There is a spelling mistake of 'ransport' in comments which should be 'transport'. Link: https://lore.kernel.org/all/03DFEDFFB5729C96+20250714104736.559226-1-wangyuli@uniontech.com/ Signed-off-by: WangYuli Link: https://patch.msgid.link/8F065DF7EF7EEB89+20250715055828.932160-1-wangyuli@uniontech.com Signed-off-by: Miri Korenblit --- drivers/net/wireless/intel/iwlwifi/dvm/agn.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/agn.h b/drivers/net/wireless/intel/iwlwifi/dvm/agn.h index f46c65d75962..9d99374ee093 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/agn.h @@ -388,7 +388,7 @@ static inline void iwl_dvm_set_pmi(struct iwl_priv *priv, bool state) /** * iwl_parse_eeprom_data - parse EEPROM data and return values * - * @trans: ransport we're parsing for, for debug only + * @trans: transport we're parsing for, for debug only * @cfg: device configuration for parsing and overrides * @eeprom: the EEPROM data * @eeprom_size: length of the EEPROM data From d2af710d6d50b3a3e691c4e2b262ed9de3038e96 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 9 Jul 2025 22:47:13 +0300 Subject: [PATCH 165/199] wifi: iwlwifi: mvm/fw: Avoid -Wflex-array-member-not-at-end warnings -Wflex-array-member-not-at-end was introduced in GCC-14, and we are getting ready to enable it, globally. We have a flexible struct iwl_tx_cmd_v6 in the middle of a few structs, but those don't even need the flexible part. So, we add iwl_tx_cmd_v6_params, that will contain everything except the flexible array and use this one for the containing structs. Also, as part of the refactoring remove unused flex array `payload`. So, with these changes, fix the following warnings: drivers/net/wireless/intel/iwlwifi/mld/../fw/api/tdls.h:134:27: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] drivers/net/wireless/intel/iwlwifi/mld/../fw/api/tdls.h:53:27: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] drivers/net/wireless/intel/iwlwifi/mld/../fw/api/tx.h:745:27: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] drivers/net/wireless/intel/iwlwifi/mld/../fw/api/tx.h:764:27: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] drivers/net/wireless/intel/iwlwifi/mvm/../fw/api/tdls.h:134:27: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] drivers/net/wireless/intel/iwlwifi/mvm/../fw/api/tdls.h:53:27: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] drivers/net/wireless/intel/iwlwifi/mvm/../fw/api/tx.h:745:27: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] drivers/net/wireless/intel/iwlwifi/mvm/../fw/api/tx.h:764:27: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] Signed-off-by: Gustavo A. R. Silva Link: https://msgid.link/aCUOQ6wdD1jQjO36@kspp [use iwl_tx_cmd_v6_params as described in the changed commit message] Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250709224608.0785a61b0826.I6da02c2a12a5ed1e6d317045a6995d132850a455@changeid Signed-off-by: Miri Korenblit --- .../net/wireless/intel/iwlwifi/fw/api/tdls.h | 4 +- .../net/wireless/intel/iwlwifi/fw/api/tx.h | 33 ++++--- .../net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 16 ++-- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 15 +-- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 93 ++++++++++--------- .../wireless/intel/iwlwifi/pcie/gen1_2/tx.c | 22 ++--- 6 files changed, 95 insertions(+), 88 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/tdls.h b/drivers/net/wireless/intel/iwlwifi/fw/api/tdls.h index 58d5a6ef633e..08edd1d99992 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/tdls.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/tdls.h @@ -50,7 +50,7 @@ struct iwl_tdls_channel_switch_timing { */ struct iwl_tdls_channel_switch_frame { __le32 switch_time_offset; - struct iwl_tx_cmd_v6 tx_cmd; + struct iwl_tx_cmd_v6_params tx_cmd; u8 data[IWL_TDLS_CH_SW_FRAME_MAX_SIZE]; } __packed; /* TDLS_STA_CHANNEL_SWITCH_FRAME_API_S_VER_1 */ @@ -131,7 +131,7 @@ struct iwl_tdls_config_cmd { struct iwl_tdls_sta_info sta_info[IWL_TDLS_STA_COUNT]; __le32 pti_req_data_offset; - struct iwl_tx_cmd_v6 pti_req_tx_cmd; + struct iwl_tx_cmd_v6_params pti_req_tx_cmd; u8 pti_req_template[]; } __packed; /* TDLS_CONFIG_CMD_API_S_VER_1 */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h index 62bd35a8f680..26d2013905ed 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h @@ -181,8 +181,8 @@ enum iwl_tx_offload_assist_flags_pos { /* TODO: complete documentation for try_cnt and btkill_cnt */ /** - * struct iwl_tx_cmd_v6 - TX command struct to FW - * ( TX_CMD = 0x1c ) + * struct iwl_tx_cmd_v6_params - parameters of the TX + * * @len: in bytes of the payload, see below for details * @offload_assist: TX offload configuration * @tx_flags: combination of TX_CMD_FLG_*, see &enum iwl_tx_flags @@ -205,8 +205,6 @@ enum iwl_tx_offload_assist_flags_pos { * @tid_tspec: TID/tspec * @pm_frame_timeout: PM TX frame timeout * @reserved4: reserved - * @payload: payload (same as @hdr) - * @hdr: 802.11 header (same as @payload) * * The byte count (both len and next_frame_len) includes MAC header * (24/26/30/32 bytes) @@ -217,11 +215,8 @@ enum iwl_tx_offload_assist_flags_pos { * It does not include post-MAC padding, i.e., * MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes. * Range of len: 14-2342 bytes. - * - * After the struct fields the MAC header is placed, plus any padding, - * and then the actial payload. */ -struct iwl_tx_cmd_v6 { +struct iwl_tx_cmd_v6_params { __le16 len; __le16 offload_assist; __le32 tx_flags; @@ -245,10 +240,20 @@ struct iwl_tx_cmd_v6 { u8 tid_tspec; __le16 pm_frame_timeout; __le16 reserved4; - union { - DECLARE_FLEX_ARRAY(u8, payload); - DECLARE_FLEX_ARRAY(struct ieee80211_hdr, hdr); - }; +} __packed; /* TX_CMD_API_S_VER_6 */ + +/** + * struct iwl_tx_cmd_v6 - TX command struct to FW + * ( TX_CMD = 0x1c ) + * @params: parameters of the TX, see &struct iwl_tx_cmd_v6_tx_params + * @hdr: 802.11 header + * + * After ¶ms, the MAC header is placed, plus any padding, + * and then the actual payload. + */ +struct iwl_tx_cmd_v6 { + struct iwl_tx_cmd_v6_params params; + struct ieee80211_hdr hdr[]; } __packed; /* TX_CMD_API_S_VER_6 */ struct iwl_dram_sec_info { @@ -748,7 +753,7 @@ struct iwl_compressed_ba_notif { * @frame: the template of the beacon frame */ struct iwl_mac_beacon_cmd_v6 { - struct iwl_tx_cmd_v6 tx; + struct iwl_tx_cmd_v6_params tx; __le32 template_id; __le32 tim_idx; __le32 tim_size; @@ -767,7 +772,7 @@ struct iwl_mac_beacon_cmd_v6 { * @frame: the template of the beacon frame */ struct iwl_mac_beacon_cmd_v7 { - struct iwl_tx_cmd_v6 tx; + struct iwl_tx_cmd_v6_params tx; __le32 template_id; __le32 tim_idx; __le32 tim_size; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index d9d61e25807a..7d2b496aadc5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -976,7 +976,7 @@ u8 iwl_mvm_mac_ctxt_get_beacon_rate(struct iwl_mvm *mvm, static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct sk_buff *beacon, - struct iwl_tx_cmd_v6 *tx) + struct iwl_tx_cmd_v6_params *tx_params) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_tx_info *info; @@ -986,30 +986,30 @@ static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm, info = IEEE80211_SKB_CB(beacon); /* Set up TX command fields */ - tx->len = cpu_to_le16((u16)beacon->len); - tx->sta_id = mvmvif->deflink.bcast_sta.sta_id; - tx->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); + tx_params->len = cpu_to_le16((u16)beacon->len); + tx_params->sta_id = mvmvif->deflink.bcast_sta.sta_id; + tx_params->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); tx_flags = TX_CMD_FLG_SEQ_CTL | TX_CMD_FLG_TSF; tx_flags |= iwl_mvm_bt_coex_tx_prio(mvm, (void *)beacon->data, info, 0) << TX_CMD_FLG_BT_PRIO_POS; - tx->tx_flags = cpu_to_le32(tx_flags); + tx_params->tx_flags = cpu_to_le32(tx_flags); if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION)) { iwl_mvm_toggle_tx_ant(mvm, &mvm->mgmt_last_antenna_idx); - tx->rate_n_flags = + tx_params->rate_n_flags = cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS); } rate = iwl_mvm_mac_ctxt_get_beacon_rate(mvm, info, vif); - tx->rate_n_flags |= + tx_params->rate_n_flags |= cpu_to_le32(iwl_mvm_mac80211_idx_to_hwrate(mvm->fw, rate)); if (rate == IWL_FIRST_CCK_RATE) - tx->rate_n_flags |= cpu_to_le32(RATE_MCS_CCK_MSK_V1); + tx_params->rate_n_flags |= cpu_to_le32(RATE_MCS_CCK_MSK_V1); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 9e83c671f4e2..af73ff09d609 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1821,11 +1821,12 @@ int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb, struct ieee80211_sta *sta); int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb); void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, - struct iwl_tx_cmd_v6 *tx_cmd, + struct iwl_tx_cmd_v6_params *tx_cmd_params, struct ieee80211_tx_info *info, u8 sta_id); -void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd_v6 *tx_cmd, - struct ieee80211_tx_info *info, - struct ieee80211_sta *sta, __le16 fc); +void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, + struct iwl_tx_cmd_v6_params *tx_cmd_params, + struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, __le16 fc); void iwl_mvm_mac_itxq_xmit(struct ieee80211_hw *hw, struct ieee80211_txq *txq); unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm, struct ieee80211_sta *sta, @@ -1854,12 +1855,12 @@ int iwl_mvm_set_sta_pkt_ext(struct iwl_mvm *mvm, void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm); static inline void iwl_mvm_set_tx_cmd_ccmp(struct ieee80211_tx_info *info, - struct iwl_tx_cmd_v6 *tx_cmd) + struct iwl_tx_cmd_v6_params *tx_cmd_params) { struct ieee80211_key_conf *keyconf = info->control.hw_key; - tx_cmd->sec_ctl = TX_CMD_SEC_CCM; - memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); + tx_cmd_params->sec_ctl = TX_CMD_SEC_CCM; + memcpy(tx_cmd_params->key, keyconf->key, keyconf->keylen); } static inline void iwl_mvm_wait_for_async_handlers(struct iwl_mvm *mvm) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index ac2cf1b8ce23..25d1a882a6a0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -148,12 +148,12 @@ out: * Sets most of the Tx cmd's fields */ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, - struct iwl_tx_cmd_v6 *tx_cmd, + struct iwl_tx_cmd_v6_params *tx_cmd_params, struct ieee80211_tx_info *info, u8 sta_id) { struct ieee80211_hdr *hdr = (void *)skb->data; __le16 fc = hdr->frame_control; - u32 tx_flags = le32_to_cpu(tx_cmd->tx_flags); + u32 tx_flags = le32_to_cpu(tx_cmd_params->tx_flags); u32 len = skb->len + FCS_LEN; bool amsdu = false; u8 ac; @@ -173,7 +173,7 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, if (ieee80211_is_data_qos(fc)) { u8 *qc = ieee80211_get_qos_ctl(hdr); - tx_cmd->tid_tspec = qc[0] & 0xf; + tx_cmd_params->tid_tspec = qc[0] & 0xf; tx_flags &= ~TX_CMD_FLG_SEQ_CTL; amsdu = *qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT; } else if (ieee80211_is_back_req(fc)) { @@ -182,17 +182,17 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, u16 ssn = le16_to_cpu(bar->start_seq_num); tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR; - tx_cmd->tid_tspec = (control & + tx_cmd_params->tid_tspec = (control & IEEE80211_BAR_CTRL_TID_INFO_MASK) >> IEEE80211_BAR_CTRL_TID_INFO_SHIFT; - WARN_ON_ONCE(tx_cmd->tid_tspec >= IWL_MAX_TID_COUNT); - iwl_mvm_bar_check_trigger(mvm, bar->ra, tx_cmd->tid_tspec, + WARN_ON_ONCE(tx_cmd_params->tid_tspec >= IWL_MAX_TID_COUNT); + iwl_mvm_bar_check_trigger(mvm, bar->ra, tx_cmd_params->tid_tspec, ssn); } else { if (ieee80211_is_data(fc)) - tx_cmd->tid_tspec = IWL_TID_NON_QOS; + tx_cmd_params->tid_tspec = IWL_TID_NON_QOS; else - tx_cmd->tid_tspec = IWL_MAX_TID_COUNT; + tx_cmd_params->tid_tspec = IWL_MAX_TID_COUNT; if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) tx_flags |= TX_CMD_FLG_SEQ_CTL; @@ -201,8 +201,8 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, } /* Default to 0 (BE) when tid_spec is set to IWL_MAX_TID_COUNT */ - if (tx_cmd->tid_tspec < IWL_MAX_TID_COUNT) - ac = tid_to_mac80211_ac[tx_cmd->tid_tspec]; + if (tx_cmd_params->tid_tspec < IWL_MAX_TID_COUNT) + ac = tid_to_mac80211_ac[tx_cmd_params->tid_tspec]; else ac = tid_to_mac80211_ac[0]; @@ -211,20 +211,20 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, if (ieee80211_is_mgmt(fc)) { if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc)) - tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_ASSOC); + tx_cmd_params->pm_frame_timeout = cpu_to_le16(PM_FRAME_ASSOC); else if (ieee80211_is_action(fc)) - tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE); + tx_cmd_params->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE); else - tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT); + tx_cmd_params->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT); /* The spec allows Action frames in A-MPDU, we don't support * it */ WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU); } else if (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO) { - tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT); + tx_cmd_params->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT); } else { - tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE); + tx_cmd_params->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE); } if (ieee80211_is_data(fc) && len > mvm->rts_threshold && @@ -236,13 +236,13 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, ieee80211_action_contains_tpc(skb)) tx_flags |= TX_CMD_FLG_WRITE_TX_POWER; - tx_cmd->tx_flags = cpu_to_le32(tx_flags); + tx_cmd_params->tx_flags = cpu_to_le32(tx_flags); /* Total # bytes to be transmitted - PCIe code will adjust for A-MSDU */ - tx_cmd->len = cpu_to_le16((u16)skb->len); - tx_cmd->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); - tx_cmd->sta_id = sta_id; + tx_cmd_params->len = cpu_to_le16((u16)skb->len); + tx_cmd_params->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); + tx_cmd_params->sta_id = sta_id; - tx_cmd->offload_assist = + tx_cmd_params->offload_assist = cpu_to_le16(iwl_mvm_tx_csum(mvm, skb, info, amsdu)); } @@ -395,22 +395,23 @@ static __le32 iwl_mvm_get_tx_rate_n_flags(struct iwl_mvm *mvm, /* * Sets the fields in the Tx cmd that are rate related */ -void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd_v6 *tx_cmd, - struct ieee80211_tx_info *info, - struct ieee80211_sta *sta, __le16 fc) +void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, + struct iwl_tx_cmd_v6_params *tx_cmd_params, + struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, __le16 fc) { /* Set retry limit on RTS packets */ - tx_cmd->rts_retry_limit = IWL_RTS_DFAULT_RETRY_LIMIT; + tx_cmd_params->rts_retry_limit = IWL_RTS_DFAULT_RETRY_LIMIT; /* Set retry limit on DATA packets and Probe Responses*/ if (ieee80211_is_probe_resp(fc)) { - tx_cmd->data_retry_limit = IWL_MGMT_DFAULT_RETRY_LIMIT; - tx_cmd->rts_retry_limit = - min(tx_cmd->data_retry_limit, tx_cmd->rts_retry_limit); + tx_cmd_params->data_retry_limit = IWL_MGMT_DFAULT_RETRY_LIMIT; + tx_cmd_params->rts_retry_limit = + min(tx_cmd_params->data_retry_limit, tx_cmd_params->rts_retry_limit); } else if (ieee80211_is_back_req(fc)) { - tx_cmd->data_retry_limit = IWL_BAR_DFAULT_RETRY_LIMIT; + tx_cmd_params->data_retry_limit = IWL_BAR_DFAULT_RETRY_LIMIT; } else { - tx_cmd->data_retry_limit = IWL_DEFAULT_TX_RETRY; + tx_cmd_params->data_retry_limit = IWL_DEFAULT_TX_RETRY; } /* @@ -423,17 +424,17 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd_v6 *tx_cmd, struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); if (mvmsta->sta_state >= IEEE80211_STA_AUTHORIZED) { - tx_cmd->initial_rate_index = 0; - tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE); + tx_cmd_params->initial_rate_index = 0; + tx_cmd_params->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE); return; } } else if (ieee80211_is_back_req(fc)) { - tx_cmd->tx_flags |= + tx_cmd_params->tx_flags |= cpu_to_le32(TX_CMD_FLG_ACK | TX_CMD_FLG_BAR); } /* Set the rate in the TX cmd */ - tx_cmd->rate_n_flags = iwl_mvm_get_tx_rate_n_flags(mvm, info, sta, fc); + tx_cmd_params->rate_n_flags = iwl_mvm_get_tx_rate_n_flags(mvm, info, sta, fc); } static inline void iwl_mvm_set_tx_cmd_pn(struct ieee80211_tx_info *info, @@ -458,7 +459,7 @@ static inline void iwl_mvm_set_tx_cmd_pn(struct ieee80211_tx_info *info, */ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, struct ieee80211_tx_info *info, - struct iwl_tx_cmd_v6 *tx_cmd, + struct iwl_tx_cmd_v6_params *tx_cmd_params, struct sk_buff *skb_frag, int hdrlen) { @@ -469,26 +470,26 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, switch (keyconf->cipher) { case WLAN_CIPHER_SUITE_CCMP: - iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd); + iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd_params); iwl_mvm_set_tx_cmd_pn(info, crypto_hdr); break; case WLAN_CIPHER_SUITE_TKIP: - tx_cmd->sec_ctl = TX_CMD_SEC_TKIP; + tx_cmd_params->sec_ctl = TX_CMD_SEC_TKIP; pn = atomic64_inc_return(&keyconf->tx_pn); ieee80211_tkip_add_iv(crypto_hdr, keyconf, pn); - ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key); + ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd_params->key); break; case WLAN_CIPHER_SUITE_WEP104: - tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; + tx_cmd_params->sec_ctl |= TX_CMD_SEC_KEY128; fallthrough; case WLAN_CIPHER_SUITE_WEP40: - tx_cmd->sec_ctl |= TX_CMD_SEC_WEP | + tx_cmd_params->sec_ctl |= TX_CMD_SEC_WEP | ((keyconf->keyidx << TX_CMD_SEC_WEP_KEY_IDX_POS) & TX_CMD_SEC_WEP_KEY_IDX_MSK); - memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen); + memcpy(&tx_cmd_params->key[3], keyconf->key, keyconf->keylen); break; case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: @@ -501,12 +502,12 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, * one. * Need to handle this. */ - tx_cmd->sec_ctl |= type | TX_CMD_SEC_KEY_FROM_TABLE; - tx_cmd->key[0] = keyconf->hw_key_idx; + tx_cmd_params->sec_ctl |= type | TX_CMD_SEC_KEY_FROM_TABLE; + tx_cmd_params->key[0] = keyconf->hw_key_idx; iwl_mvm_set_tx_cmd_pn(info, crypto_hdr); break; default: - tx_cmd->sec_ctl |= TX_CMD_SEC_EXT; + tx_cmd_params->sec_ctl |= TX_CMD_SEC_EXT; } } @@ -636,11 +637,11 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, tx_cmd = (struct iwl_tx_cmd_v6 *)dev_cmd->payload; if (info->control.hw_key) - iwl_mvm_set_tx_cmd_crypto(mvm, info, tx_cmd, skb, hdrlen); + iwl_mvm_set_tx_cmd_crypto(mvm, info, &tx_cmd->params, skb, hdrlen); - iwl_mvm_set_tx_cmd(mvm, skb, tx_cmd, info, sta_id); + iwl_mvm_set_tx_cmd(mvm, skb, &tx_cmd->params, info, sta_id); - iwl_mvm_set_tx_cmd_rate(mvm, tx_cmd, info, sta, hdr->frame_control); + iwl_mvm_set_tx_cmd_rate(mvm, &tx_cmd->params, info, sta, hdr->frame_control); /* Copy MAC header from skb into command buffer */ iwl_mvm_copy_hdr(tx_cmd->hdr, hdr, hdrlen, addr3_override); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c index 10a12938d8f8..84a05cc1c27a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c @@ -1963,7 +1963,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, * have in the MPDU by themselves, but that we duplicate into * all the different MSDUs inside the A-MSDU. */ - le16_add_cpu(&tx_cmd->len, -snap_ip_tcp_hdrlen); + le16_add_cpu(&tx_cmd->params.len, -snap_ip_tcp_hdrlen); tso_start(skb, &tso); @@ -2006,7 +2006,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, trace_iwlwifi_dev_tx_tb(trans->dev, skb, start_hdr, hdr_tb_phys, hdr_tb_len); /* add this subframe's headers' length to the tx_cmd */ - le16_add_cpu(&tx_cmd->len, pos_hdr - subf_hdrs_start); + le16_add_cpu(&tx_cmd->params.len, pos_hdr - subf_hdrs_start); /* prepare the start_hdr for the next subframe */ start_hdr = pos_hdr; @@ -2074,11 +2074,11 @@ static void iwl_txq_gen1_update_byte_cnt_tbl(struct iwl_trans *trans, __le16 bc_ent; struct iwl_device_tx_cmd *dev_cmd = txq->entries[txq->write_ptr].cmd; struct iwl_tx_cmd_v6 *tx_cmd = (void *)dev_cmd->payload; - u8 sta_id = tx_cmd->sta_id; + u8 sta_id = tx_cmd->params.sta_id; scd_bc_tbl = trans_pcie->txqs.scd_bc_tbls.addr; - sec_ctl = tx_cmd->sec_ctl; + sec_ctl = tx_cmd->params.sec_ctl; switch (sec_ctl & TX_CMD_SEC_MSK) { case TX_CMD_SEC_CCM: @@ -2185,10 +2185,10 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, tb0_phys = iwl_txq_get_first_tb_dma(txq, txq->write_ptr); scratch_phys = tb0_phys + sizeof(struct iwl_cmd_header) + - offsetof(struct iwl_tx_cmd_v6, scratch); + offsetof(struct iwl_tx_cmd_v6_params, scratch); - tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); - tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); + tx_cmd->params.dram_lsb_ptr = cpu_to_le32(scratch_phys); + tx_cmd->params.dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); /* Set up first empty entry in queue's array of Tx/cmd buffers */ out_meta = &txq->entries[txq->write_ptr].meta; @@ -2210,7 +2210,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, tb1_len = ALIGN(len, 4); /* Tell NIC about any 2-byte padding after MAC header */ if (tb1_len != len) - tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_MH_PAD); + tx_cmd->params.tx_flags |= cpu_to_le32(TX_CMD_FLG_MH_PAD); } else { tb1_len = len; } @@ -2225,7 +2225,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, /* there must be data left over for TB1 or this code must be changed */ BUILD_BUG_ON(sizeof(struct iwl_tx_cmd_v6) < IWL_FIRST_TB_SIZE); BUILD_BUG_ON(sizeof(struct iwl_cmd_header) + - offsetofend(struct iwl_tx_cmd_v6, scratch) > + offsetofend(struct iwl_tx_cmd_v6_params, scratch) > IWL_FIRST_TB_SIZE); /* map the data for TB1 */ @@ -2271,7 +2271,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, tfd = iwl_txq_get_tfd(trans, txq, txq->write_ptr); /* Set up entry for this TFD in Tx byte-count array */ - iwl_txq_gen1_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len), + iwl_txq_gen1_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->params.len), iwl_txq_gen1_tfd_get_num_tbs(tfd)); wait_write_ptr = ieee80211_has_morefrags(fc); @@ -2323,7 +2323,7 @@ static void iwl_txq_gen1_inval_byte_cnt_tbl(struct iwl_trans *trans, WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX); if (txq_id != trans->conf.cmd_queue) - sta_id = tx_cmd->sta_id; + sta_id = tx_cmd->params.sta_id; bc_ent = cpu_to_le16(1 | (sta_id << 12)); From a37192c432adaec9e8ef29e4ddb319ea2f443aa6 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 21 Jul 2025 11:25:22 -0700 Subject: [PATCH 166/199] wifi: mac80211: Write cnt before copying in ieee80211_copy_rnr_beacon() While I caught the need for setting cnt early in nl80211_parse_rnr_elems() in the original annotation of struct cfg80211_rnr_elems with __counted_by, I missed a similar pattern in ieee80211_copy_rnr_beacon(). Fix this by moving the cnt assignment to before the loop. Fixes: 7b6d7087031b ("wifi: cfg80211: Annotate struct cfg80211_rnr_elems with __counted_by") Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Link: https://patch.msgid.link/20250721182521.work.540-kees@kernel.org Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 4f20d57ab913..2ed07fa121ab 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1176,13 +1176,13 @@ ieee80211_copy_rnr_beacon(u8 *pos, struct cfg80211_rnr_elems *dst, { int i, offset = 0; + dst->cnt = src->cnt; for (i = 0; i < src->cnt; i++) { memcpy(pos + offset, src->elem[i].data, src->elem[i].len); dst->elem[i].len = src->elem[i].len; dst->elem[i].data = pos + offset; offset += dst->elem[i].len; } - dst->cnt = src->cnt; return offset; } From 2ed9a9fc9976262109d04f1a3c75c46de8ce4f22 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 21 Jul 2025 11:31:29 -0700 Subject: [PATCH 167/199] wifi: nl80211: Set num_sub_specs before looping through sub_specs The processing of the struct cfg80211_sar_specs::sub_specs flexible array requires its counter, num_sub_specs, to be assigned before the loop in nl80211_set_sar_specs(). Leave the final assignment after the loop in place in case fewer ended up in the array. Fixes: aa4ec06c455d ("wifi: cfg80211: use __counted_by where appropriate") Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Link: https://patch.msgid.link/20250721183125.work.183-kees@kernel.org Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b4bf44768dc8..89519aa52893 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -17559,6 +17559,7 @@ static int nl80211_set_sar_specs(struct sk_buff *skb, struct genl_info *info) if (!sar_spec) return -ENOMEM; + sar_spec->num_sub_specs = specs; sar_spec->type = type; specs = 0; nla_for_each_nested(spec_list, tb[NL80211_SAR_ATTR_SPECS], rem) { From 69fdb084355d6c0b353536024cc51aa5f7ffb62c Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 21 Jul 2025 21:50:49 +0300 Subject: [PATCH 168/199] wifi: mac80211: don't require cipher and keylen in gtk rekey ieee80211_add_gtk_rekey receives a keyconf as an argument, and the cipher and keylen are taken from there to the new allocated key. But in rekey, both the cipher and the keylen should be the same as of the old key, so let ieee80211_add_gtk_rekey find those, so drivers won't have to fill it in. Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250721214922.3c5c023bfae9.Ie6594ae2b4b6d5b3d536e642b349046ebfce7a5d@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mld/d3.c | 7 +++- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 11 +++++-- drivers/net/wireless/realtek/rtw89/wow.c | 7 ++-- include/net/mac80211.h | 7 ++-- net/mac80211/key.c | 36 +++++++++++++++++++-- 5 files changed, 58 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c index 26255246a320..ed0a0f76f1c5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c @@ -762,6 +762,7 @@ iwl_mld_add_mcast_rekey(struct ieee80211_vif *vif, .conf.keyidx = key_data->id, }; int link_id = vif->active_links ? __ffs(vif->active_links) : -1; + u8 key[WOWLAN_KEY_MAX_SIZE]; BUILD_BUG_ON(WLAN_KEY_LEN_CCMP != WLAN_KEY_LEN_GCMP); BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_CCMP); @@ -803,7 +804,11 @@ iwl_mld_add_mcast_rekey(struct ieee80211_vif *vif, } memcpy(conf.conf.key, key_data->key, conf.conf.keylen); - key_config = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id); + + memcpy(key, key_data->key, sizeof(key_data->key)); + + key_config = ieee80211_gtk_rekey_add(vif, key_data->id, key, + sizeof(key), link_id); if (IS_ERR(key_config)) return; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index ef9bab042902..997cdd76b13c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1954,6 +1954,7 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, DEFINE_RAW_FLEX(struct ieee80211_key_conf, conf, key, WOWLAN_KEY_MAX_SIZE); int link_id = vif->active_links ? __ffs(vif->active_links) : -1; + u8 key_data[WOWLAN_KEY_MAX_SIZE]; conf->cipher = gtk_cipher; @@ -1988,8 +1989,10 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, conf->cipher, conf->keyidx); memcpy(conf->key, status->gtk[i].key, sizeof(status->gtk[i].key)); + memcpy(key_data, status->gtk[i].key, sizeof(status->gtk[i].key)); - key = ieee80211_gtk_rekey_add(vif, conf, link_id); + key = ieee80211_gtk_rekey_add(vif, status->gtk[i].id, key_data, + sizeof(key_data), link_id); if (IS_ERR(key)) { /* FW may send also the old keys */ if (PTR_ERR(key) == -EALREADY) @@ -2021,6 +2024,7 @@ iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status, struct ieee80211_key_conf *key_config; struct ieee80211_key_seq seq; int link_id = vif->active_links ? __ffs(vif->active_links) : -1; + u8 key[WOWLAN_KEY_MAX_SIZE]; s8 keyidx = key_data->id; conf->cipher = cipher; @@ -2050,7 +2054,10 @@ iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status, BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < sizeof(key_data->key)); memcpy(conf->key, key_data->key, conf->keylen); - key_config = ieee80211_gtk_rekey_add(vif, conf, link_id); + memcpy(key, key_data->key, sizeof(key_data->key)); + + key_config = ieee80211_gtk_rekey_add(vif, keyidx, key, sizeof(key), + link_id); if (IS_ERR(key_config)) { /* FW may send also the old keys */ return PTR_ERR(key_config) == -EALREADY; diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 071c7577df52..5bb7c1a42f1d 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -619,9 +619,12 @@ static struct ieee80211_key_conf *rtw89_wow_gtk_rekey(struct rtw89_dev *rtwdev, flex_array_size(rekey_conf, key, cipher_info->len)); if (ieee80211_vif_is_mld(wow_vif)) - key = ieee80211_gtk_rekey_add(wow_vif, rekey_conf, rtwvif_link->link_id); + key = ieee80211_gtk_rekey_add(wow_vif, keyidx, gtk, + cipher_info->len, + rtwvif_link->link_id); else - key = ieee80211_gtk_rekey_add(wow_vif, rekey_conf, -1); + key = ieee80211_gtk_rekey_add(wow_vif, keyidx, gtk, + cipher_info->len, -1); kfree(rekey_conf); if (IS_ERR(key)) { diff --git a/include/net/mac80211.h b/include/net/mac80211.h index a0cf976a9117..a45e4bee65d4 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -6035,7 +6035,10 @@ void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf, /** * ieee80211_gtk_rekey_add - add a GTK key from rekeying during WoWLAN * @vif: the virtual interface to add the key on - * @keyconf: new key data + * @idx: the keyidx of the key + * @key_data: the key data + * @key_len: the key data. Might be bigger than the actual key length, + * but not smaller (for the driver convinence) * @link_id: the link id of the key or -1 for non-MLO * * When GTK rekeying was done while the system was suspended, (a) new @@ -6062,7 +6065,7 @@ void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf, */ struct ieee80211_key_conf * ieee80211_gtk_rekey_add(struct ieee80211_vif *vif, - struct ieee80211_key_conf *keyconf, + u8 idx, u8 *key_data, u8 key_len, int link_id); /** diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 9d65013ddac7..b14e9cd9713f 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -1356,11 +1356,12 @@ EXPORT_SYMBOL_GPL(ieee80211_set_key_rx_seq); struct ieee80211_key_conf * ieee80211_gtk_rekey_add(struct ieee80211_vif *vif, - struct ieee80211_key_conf *keyconf, + u8 idx, u8 *key_data, u8 key_len, int link_id) { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); struct ieee80211_local *local = sdata->local; + struct ieee80211_key *prev_key; struct ieee80211_key *key; int err; struct ieee80211_link_data *link_data = @@ -1376,8 +1377,37 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif, if (WARN_ON(vif->type != NL80211_IFTYPE_STATION)) return ERR_PTR(-EINVAL); - key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx, - keyconf->keylen, keyconf->key, + if (WARN_ON(idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS + + NUM_DEFAULT_BEACON_KEYS)) + return ERR_PTR(-EINVAL); + + prev_key = wiphy_dereference(local->hw.wiphy, + link_data->gtk[idx]); + if (!prev_key) { + if (idx < NUM_DEFAULT_KEYS) { + for (int i = 0; i < NUM_DEFAULT_KEYS; i++) { + if (i == idx) + continue; + prev_key = wiphy_dereference(local->hw.wiphy, + link_data->gtk[i]); + if (prev_key) + break; + } + } else { + /* For IGTK we have 4 and 5 and for BIGTK - 6 and 7 */ + prev_key = wiphy_dereference(local->hw.wiphy, + link_data->gtk[idx ^ 1]); + } + } + + if (WARN_ON(!prev_key)) + return ERR_PTR(-EINVAL); + + if (WARN_ON(key_len < prev_key->conf.keylen)) + return ERR_PTR(-EINVAL); + + key = ieee80211_key_alloc(prev_key->conf.cipher, idx, + prev_key->conf.keylen, key_data, 0, NULL); if (IS_ERR(key)) return ERR_CAST(key); From 708243c62efde8241e2c66e9c3f377658855149d Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Tue, 22 Jul 2025 14:06:34 +0200 Subject: [PATCH 169/199] wifi: mac80211: fix unassigned variable access In ieee80211_latest_active_link_conn_timeout() we loop over all sta->links in order to compute the timeout expiring last across all links. Such timeout is stored in `latest_timeout` which is used in the time_after() comparison before having been initialized. Fix this behaviour by initializing the variable to `jiffies` and adapt surrouding conditions accordingly. Note that the caller assumed latest_timeout to be 0 if no active link was found. This is not appropriate because jiffies=0 is a valid (and recurrent, although not often) point in time. By using `jiffies` as default value for latest_timeout, we can fix the caller as well. Address-Coverity-ID: 1647986 ("Uninitialized variables (UNINIT)") Fixes: 1bc892d76a6f ("wifi: mac80211: extend connection monitoring for MLO") Signed-off-by: Antonio Quartulli Link: https://patch.msgid.link/20250722120634.3501-1-antonio@mandelbit.com Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b4b7ea52c65e..1008eb8e9b13 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -8521,7 +8521,7 @@ static void ieee80211_sta_bcn_mon_timer(struct timer_list *t) static unsigned long ieee80211_latest_active_link_conn_timeout(struct ieee80211_sub_if_data *sdata) { - unsigned long latest_timeout; + unsigned long latest_timeout = jiffies; unsigned int link_id; struct sta_info *sta; @@ -8554,8 +8554,7 @@ ieee80211_latest_active_link_conn_timeout(struct ieee80211_sub_if_data *sdata) * is still active, and it is scheduled to fire at * the latest possible timeout. */ - if (time_is_after_jiffies(timeout) && - time_after(timeout, latest_timeout)) + if (time_after(timeout, latest_timeout)) latest_timeout = timeout; } @@ -8579,7 +8578,7 @@ static void ieee80211_sta_conn_mon_timer(struct timer_list *t) * If latest timeout is after now, then update timer to fire at * the later date, but do not actually probe at this time. */ - if (latest_timeout) { + if (time_is_after_jiffies(latest_timeout)) { mod_timer(&ifmgd->conn_mon_timer, round_jiffies_up(latest_timeout)); return; From 204bb852863bf14f343a0801b15bc2173bc318f9 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 21 Jul 2025 11:18:14 -0700 Subject: [PATCH 170/199] wifi: brcmfmac: cyw: Fix __counted_by to be LE variant In brcmf_cyw_mgmt_tx() the "len" counter of the struct brcmf_mf_params_le::data flexible array is stored as little-endian via cpu_to_le16() so the __counted_by_le() variant must be used: struct brcmf_mf_params_le *mf_params; ... mf_params_len = offsetof(struct brcmf_mf_params_le, data) + (len - DOT11_MGMT_HDR_LEN); mf_params = kzalloc(mf_params_len, GFP_KERNEL); ... mf_params->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN); Fixes: 66f909308a7c ("wifi: brcmfmac: cyw: support external SAE authentication in station mode") Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Acked-by: Arend van Spriel > Link: https://patch.msgid.link/20250721181810.work.575-kees@kernel.org Signed-off-by: Johannes Berg --- .../net/wireless/broadcom/brcm80211/brcmfmac/cyw/fwil_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/fwil_types.h index 08c69142495a..669564382e32 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/fwil_types.h @@ -80,7 +80,7 @@ struct brcmf_mf_params_le { u8 da[ETH_ALEN]; u8 bssid[ETH_ALEN]; __le32 packet_id; - u8 data[] __counted_by(len); + u8 data[] __counted_by_le(len); }; #endif /* CYW_FWIL_TYPES_H_ */ From c57e5b9819dfd16d709bcd6cb633301ed0829a66 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 Jul 2025 09:14:19 +0200 Subject: [PATCH 171/199] wifi: mac80211: fix WARN_ON for monitor mode on some devices On devices without WANT_MONITOR_VIF (and probably without channel context support) we get a WARN_ON for changing the per-link setting of a monitor interface. Since we already skip AP_VLAN interfaces and MONITOR with WANT_MONITOR_VIF and/or NO_VIRTUAL_MONITOR should update the settings, catch this in the link change code instead of the warning. Reported-by: Martin Kaistra Link: https://lore.kernel.org/r/a9de62a0-28f1-4981-84df-253489da74ed@linutronix.de/ Fixes: c4382d5ca1af ("wifi: mac80211: update the right link for tx power") Signed-off-by: Johannes Berg --- net/mac80211/main.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 351564360c26..9c8f18b258a6 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -408,9 +408,20 @@ void ieee80211_link_info_change_notify(struct ieee80211_sub_if_data *sdata, WARN_ON_ONCE(changed & BSS_CHANGED_VIF_CFG_FLAGS); - if (!changed || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + if (!changed) return; + switch (sdata->vif.type) { + case NL80211_IFTYPE_AP_VLAN: + return; + case NL80211_IFTYPE_MONITOR: + if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF)) + return; + break; + default: + break; + } + if (!check_sdata_in_driver(sdata)) return; From 311b05e235cf19283185579803e1be6332ab0d41 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Tue, 22 Jul 2025 14:28:50 -0700 Subject: [PATCH 172/199] wifi: rt2x00: add COMPILE_TEST While this driver is for a specific arch, there is nothing preventing it from being compiled on other platforms. Allows the various bots to test compilation and complain if a patch is bad. Signed-off-by: Rosen Penev Acked-by: Stanislaw Gruszka Reviewed-by: Sergio Paracuellos Link: https://patch.msgid.link/20250722212856.11343-2-rosenp@gmail.com Signed-off-by: Johannes Berg --- drivers/net/wireless/ralink/rt2x00/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ralink/rt2x00/Kconfig b/drivers/net/wireless/ralink/rt2x00/Kconfig index d1fd66d44a7e..3a32ceead54f 100644 --- a/drivers/net/wireless/ralink/rt2x00/Kconfig +++ b/drivers/net/wireless/ralink/rt2x00/Kconfig @@ -202,7 +202,7 @@ endif config RT2800SOC tristate "Ralink WiSoC support" - depends on SOC_RT288X || SOC_RT305X || SOC_MT7620 + depends on SOC_RT288X || SOC_RT305X || SOC_MT7620 || COMPILE_TEST select RT2X00_LIB_SOC select RT2X00_LIB_MMIO select RT2X00_LIB_CRYPTO From f1fd79a6475ff550acaa64cf06308a1f57c6ee8f Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Tue, 22 Jul 2025 14:28:51 -0700 Subject: [PATCH 173/199] wifi: rt2x00: remove mod_name from platform_driver mod_name is a legacy debugging feature with no real modern use. An analysis of the underlying MIPS setup code reveals it to also be unused. Signed-off-by: Rosen Penev Reviewed-by: Sergio Paracuellos Acked-by: Stanislaw Gruszka Link: https://patch.msgid.link/20250722212856.11343-3-rosenp@gmail.com Signed-off-by: Johannes Berg --- drivers/net/wireless/ralink/rt2x00/rt2800soc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c index 701ba54bf3e5..e73394cf6ea6 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c @@ -246,7 +246,6 @@ static int rt2800soc_probe(struct platform_device *pdev) static struct platform_driver rt2800soc_driver = { .driver = { .name = "rt2800_wmac", - .mod_name = KBUILD_MODNAME, }, .probe = rt2800soc_probe, .remove = rt2x00soc_remove, From 708e88b9d47522507e330698cea120e0b73b7de0 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Tue, 22 Jul 2025 14:28:52 -0700 Subject: [PATCH 174/199] wifi: rt2800soc: allow loading from OF Add a single binding to help the already present dts files load the driver. More are possible but there doesn't seem to be a significant difference between them to justify this. Use wifi name per dtschema requirements. Added OF dependency to SOC CONFIG as adding of_match_table without OF being present makes no sense. Signed-off-by: Rosen Penev Reviewed-by: Sergio Paracuellos Acked-by: Stanislaw Gruszka Link: https://patch.msgid.link/20250722212856.11343-4-rosenp@gmail.com Signed-off-by: Johannes Berg --- drivers/net/wireless/ralink/rt2x00/Kconfig | 2 +- drivers/net/wireless/ralink/rt2x00/rt2800soc.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ralink/rt2x00/Kconfig b/drivers/net/wireless/ralink/rt2x00/Kconfig index 3a32ceead54f..a0dc9a751234 100644 --- a/drivers/net/wireless/ralink/rt2x00/Kconfig +++ b/drivers/net/wireless/ralink/rt2x00/Kconfig @@ -202,7 +202,7 @@ endif config RT2800SOC tristate "Ralink WiSoC support" - depends on SOC_RT288X || SOC_RT305X || SOC_MT7620 || COMPILE_TEST + depends on OF && (SOC_RT288X || SOC_RT305X || SOC_MT7620 || COMPILE_TEST) select RT2X00_LIB_SOC select RT2X00_LIB_MMIO select RT2X00_LIB_CRYPTO diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c index e73394cf6ea6..8015089c4a39 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c @@ -243,9 +243,16 @@ static int rt2800soc_probe(struct platform_device *pdev) return rt2x00soc_probe(pdev, &rt2800soc_ops); } +static const struct of_device_id rt2880_wmac_match[] = { + { .compatible = "ralink,rt2880-wifi" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rt2880_wmac_match); + static struct platform_driver rt2800soc_driver = { .driver = { .name = "rt2800_wmac", + .of_match_table = rt2880_wmac_match, }, .probe = rt2800soc_probe, .remove = rt2x00soc_remove, From 7f6109086c9e7bbc78ff936dac45626870455c76 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Tue, 22 Jul 2025 14:28:53 -0700 Subject: [PATCH 175/199] wifi: rt2800: move 2x00soc to 2800soc This driver was written with multiple SOC platforms in mind. However since Ralink was aquired by Mediatek, it only effectively got used by older platforms. As such, we can slim down the driver slightly by moving all of rt2x00soc to rt2800soc in order to benefit from inlining. Signed-off-by: Rosen Penev Acked-by: Stanislaw Gruszka Reviewed-by: Sergio Paracuellos Link: https://patch.msgid.link/20250722212856.11343-5-rosenp@gmail.com Signed-off-by: Johannes Berg --- drivers/net/wireless/ralink/rt2x00/Kconfig | 5 - drivers/net/wireless/ralink/rt2x00/Makefile | 1 - .../net/wireless/ralink/rt2x00/rt2800soc.c | 119 +++++++++++++- .../net/wireless/ralink/rt2x00/rt2x00soc.c | 151 ------------------ .../net/wireless/ralink/rt2x00/rt2x00soc.h | 29 ---- 5 files changed, 118 insertions(+), 187 deletions(-) delete mode 100644 drivers/net/wireless/ralink/rt2x00/rt2x00soc.c delete mode 100644 drivers/net/wireless/ralink/rt2x00/rt2x00soc.h diff --git a/drivers/net/wireless/ralink/rt2x00/Kconfig b/drivers/net/wireless/ralink/rt2x00/Kconfig index a0dc9a751234..4d98b7723c56 100644 --- a/drivers/net/wireless/ralink/rt2x00/Kconfig +++ b/drivers/net/wireless/ralink/rt2x00/Kconfig @@ -203,7 +203,6 @@ endif config RT2800SOC tristate "Ralink WiSoC support" depends on OF && (SOC_RT288X || SOC_RT305X || SOC_MT7620 || COMPILE_TEST) - select RT2X00_LIB_SOC select RT2X00_LIB_MMIO select RT2X00_LIB_CRYPTO select RT2X00_LIB_FIRMWARE @@ -231,10 +230,6 @@ config RT2X00_LIB_PCI tristate select RT2X00_LIB -config RT2X00_LIB_SOC - tristate - select RT2X00_LIB - config RT2X00_LIB_USB tristate select RT2X00_LIB diff --git a/drivers/net/wireless/ralink/rt2x00/Makefile b/drivers/net/wireless/ralink/rt2x00/Makefile index de030ebcdf6e..48d84d243606 100644 --- a/drivers/net/wireless/ralink/rt2x00/Makefile +++ b/drivers/net/wireless/ralink/rt2x00/Makefile @@ -12,7 +12,6 @@ rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o obj-$(CONFIG_RT2X00_LIB_MMIO) += rt2x00mmio.o obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o -obj-$(CONFIG_RT2X00_LIB_SOC) += rt2x00soc.o obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o obj-$(CONFIG_RT2800_LIB) += rt2800lib.o obj-$(CONFIG_RT2800_LIB_MMIO) += rt2800mmio.o diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c index 8015089c4a39..4d06f49ec6d2 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c @@ -22,7 +22,6 @@ #include "rt2x00.h" #include "rt2x00mmio.h" -#include "rt2x00soc.h" #include "rt2800.h" #include "rt2800lib.h" #include "rt2800mmio.h" @@ -131,6 +130,124 @@ static int rt2800soc_write_firmware(struct rt2x00_dev *rt2x00dev, return 0; } +static void rt2x00soc_free_reg(struct rt2x00_dev *rt2x00dev) +{ + kfree(rt2x00dev->rf); + rt2x00dev->rf = NULL; + + kfree(rt2x00dev->eeprom); + rt2x00dev->eeprom = NULL; + + iounmap(rt2x00dev->csr.base); +} + +static int rt2x00soc_alloc_reg(struct rt2x00_dev *rt2x00dev) +{ + struct platform_device *pdev = to_platform_device(rt2x00dev->dev); + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + rt2x00dev->csr.base = ioremap(res->start, resource_size(res)); + if (!rt2x00dev->csr.base) + return -ENOMEM; + + rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL); + if (!rt2x00dev->eeprom) + goto exit; + + rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL); + if (!rt2x00dev->rf) + goto exit; + + return 0; + +exit: + rt2x00_probe_err("Failed to allocate registers\n"); + rt2x00soc_free_reg(rt2x00dev); + + return -ENOMEM; +} + +static int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops) +{ + struct ieee80211_hw *hw; + struct rt2x00_dev *rt2x00dev; + int retval; + + hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw); + if (!hw) { + rt2x00_probe_err("Failed to allocate hardware\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, hw); + + rt2x00dev = hw->priv; + rt2x00dev->dev = &pdev->dev; + rt2x00dev->ops = ops; + rt2x00dev->hw = hw; + rt2x00dev->irq = platform_get_irq(pdev, 0); + rt2x00dev->name = pdev->dev.driver->name; + + rt2x00dev->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(rt2x00dev->clk)) + rt2x00dev->clk = NULL; + + rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC); + + retval = rt2x00soc_alloc_reg(rt2x00dev); + if (retval) + goto exit_free_device; + + retval = rt2x00lib_probe_dev(rt2x00dev); + if (retval) + goto exit_free_reg; + + return 0; + +exit_free_reg: + rt2x00soc_free_reg(rt2x00dev); + +exit_free_device: + ieee80211_free_hw(hw); + + return retval; +} + +static void rt2x00soc_remove(struct platform_device *pdev) +{ + struct ieee80211_hw *hw = platform_get_drvdata(pdev); + struct rt2x00_dev *rt2x00dev = hw->priv; + + /* + * Free all allocated data. + */ + rt2x00lib_remove_dev(rt2x00dev); + rt2x00soc_free_reg(rt2x00dev); + ieee80211_free_hw(hw); +} + +#ifdef CONFIG_PM +static int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct ieee80211_hw *hw = platform_get_drvdata(pdev); + struct rt2x00_dev *rt2x00dev = hw->priv; + + return rt2x00lib_suspend(rt2x00dev); +} + +static int rt2x00soc_resume(struct platform_device *pdev) +{ + struct ieee80211_hw *hw = platform_get_drvdata(pdev); + struct rt2x00_dev *rt2x00dev = hw->priv; + + return rt2x00lib_resume(rt2x00dev); +} +#endif /* CONFIG_PM */ + static const struct ieee80211_ops rt2800soc_mac80211_ops = { .add_chanctx = ieee80211_emulate_add_chanctx, .remove_chanctx = ieee80211_emulate_remove_chanctx, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c b/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c deleted file mode 100644 index f7f3a2340c39..000000000000 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c +++ /dev/null @@ -1,151 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - Copyright (C) 2004 - 2009 Ivo van Doorn - Copyright (C) 2004 - 2009 Felix Fietkau - - - */ - -/* - Module: rt2x00soc - Abstract: rt2x00 generic soc device routines. - */ - -#include -#include -#include -#include -#include - -#include "rt2x00.h" -#include "rt2x00soc.h" - -static void rt2x00soc_free_reg(struct rt2x00_dev *rt2x00dev) -{ - kfree(rt2x00dev->rf); - rt2x00dev->rf = NULL; - - kfree(rt2x00dev->eeprom); - rt2x00dev->eeprom = NULL; - - iounmap(rt2x00dev->csr.base); -} - -static int rt2x00soc_alloc_reg(struct rt2x00_dev *rt2x00dev) -{ - struct platform_device *pdev = to_platform_device(rt2x00dev->dev); - struct resource *res; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - rt2x00dev->csr.base = ioremap(res->start, resource_size(res)); - if (!rt2x00dev->csr.base) - return -ENOMEM; - - rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL); - if (!rt2x00dev->eeprom) - goto exit; - - rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL); - if (!rt2x00dev->rf) - goto exit; - - return 0; - -exit: - rt2x00_probe_err("Failed to allocate registers\n"); - rt2x00soc_free_reg(rt2x00dev); - - return -ENOMEM; -} - -int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops) -{ - struct ieee80211_hw *hw; - struct rt2x00_dev *rt2x00dev; - int retval; - - hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw); - if (!hw) { - rt2x00_probe_err("Failed to allocate hardware\n"); - return -ENOMEM; - } - - platform_set_drvdata(pdev, hw); - - rt2x00dev = hw->priv; - rt2x00dev->dev = &pdev->dev; - rt2x00dev->ops = ops; - rt2x00dev->hw = hw; - rt2x00dev->irq = platform_get_irq(pdev, 0); - rt2x00dev->name = pdev->dev.driver->name; - - rt2x00dev->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(rt2x00dev->clk)) - rt2x00dev->clk = NULL; - - rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC); - - retval = rt2x00soc_alloc_reg(rt2x00dev); - if (retval) - goto exit_free_device; - - retval = rt2x00lib_probe_dev(rt2x00dev); - if (retval) - goto exit_free_reg; - - return 0; - -exit_free_reg: - rt2x00soc_free_reg(rt2x00dev); - -exit_free_device: - ieee80211_free_hw(hw); - - return retval; -} -EXPORT_SYMBOL_GPL(rt2x00soc_probe); - -void rt2x00soc_remove(struct platform_device *pdev) -{ - struct ieee80211_hw *hw = platform_get_drvdata(pdev); - struct rt2x00_dev *rt2x00dev = hw->priv; - - /* - * Free all allocated data. - */ - rt2x00lib_remove_dev(rt2x00dev); - rt2x00soc_free_reg(rt2x00dev); - ieee80211_free_hw(hw); -} -EXPORT_SYMBOL_GPL(rt2x00soc_remove); - -#ifdef CONFIG_PM -int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct ieee80211_hw *hw = platform_get_drvdata(pdev); - struct rt2x00_dev *rt2x00dev = hw->priv; - - return rt2x00lib_suspend(rt2x00dev); -} -EXPORT_SYMBOL_GPL(rt2x00soc_suspend); - -int rt2x00soc_resume(struct platform_device *pdev) -{ - struct ieee80211_hw *hw = platform_get_drvdata(pdev); - struct rt2x00_dev *rt2x00dev = hw->priv; - - return rt2x00lib_resume(rt2x00dev); -} -EXPORT_SYMBOL_GPL(rt2x00soc_resume); -#endif /* CONFIG_PM */ - -/* - * rt2x00soc module information. - */ -MODULE_AUTHOR(DRV_PROJECT); -MODULE_VERSION(DRV_VERSION); -MODULE_DESCRIPTION("rt2x00 soc library"); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00soc.h b/drivers/net/wireless/ralink/rt2x00/rt2x00soc.h deleted file mode 100644 index d6226b8a10e0..000000000000 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00soc.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - Copyright (C) 2004 - 2009 Ivo van Doorn - - - */ - -/* - Module: rt2x00soc - Abstract: Data structures for the rt2x00soc module. - */ - -#ifndef RT2X00SOC_H -#define RT2X00SOC_H - -/* - * SoC driver handlers. - */ -int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops); -void rt2x00soc_remove(struct platform_device *pdev); -#ifdef CONFIG_PM -int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state); -int rt2x00soc_resume(struct platform_device *pdev); -#else -#define rt2x00soc_suspend NULL -#define rt2x00soc_resume NULL -#endif /* CONFIG_PM */ - -#endif /* RT2X00SOC_H */ From ddc19499aee1327ad9fa773a3db62f2d67798836 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Tue, 22 Jul 2025 14:28:54 -0700 Subject: [PATCH 176/199] wifi: rt2x00: soc: modernize probe Remove a bunch of static memory management functions and simplify with devm. Also move allocation before ieee80211_alloc_hw to get rid of goto statements and clarify the error handling a bit more. Signed-off-by: Rosen Penev Acked-by: Stanislaw Gruszka Reviewed-by: Sergio Paracuellos Link: https://patch.msgid.link/20250722212856.11343-6-rosenp@gmail.com Signed-off-by: Johannes Berg --- .../net/wireless/ralink/rt2x00/rt2800soc.c | 187 ++++++++---------- 1 file changed, 82 insertions(+), 105 deletions(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c index 4d06f49ec6d2..8f510a84e7f1 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "rt2x00.h" @@ -130,108 +131,8 @@ static int rt2800soc_write_firmware(struct rt2x00_dev *rt2x00dev, return 0; } -static void rt2x00soc_free_reg(struct rt2x00_dev *rt2x00dev) -{ - kfree(rt2x00dev->rf); - rt2x00dev->rf = NULL; - - kfree(rt2x00dev->eeprom); - rt2x00dev->eeprom = NULL; - - iounmap(rt2x00dev->csr.base); -} - -static int rt2x00soc_alloc_reg(struct rt2x00_dev *rt2x00dev) -{ - struct platform_device *pdev = to_platform_device(rt2x00dev->dev); - struct resource *res; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - rt2x00dev->csr.base = ioremap(res->start, resource_size(res)); - if (!rt2x00dev->csr.base) - return -ENOMEM; - - rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL); - if (!rt2x00dev->eeprom) - goto exit; - - rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL); - if (!rt2x00dev->rf) - goto exit; - - return 0; - -exit: - rt2x00_probe_err("Failed to allocate registers\n"); - rt2x00soc_free_reg(rt2x00dev); - - return -ENOMEM; -} - -static int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops) -{ - struct ieee80211_hw *hw; - struct rt2x00_dev *rt2x00dev; - int retval; - - hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw); - if (!hw) { - rt2x00_probe_err("Failed to allocate hardware\n"); - return -ENOMEM; - } - - platform_set_drvdata(pdev, hw); - - rt2x00dev = hw->priv; - rt2x00dev->dev = &pdev->dev; - rt2x00dev->ops = ops; - rt2x00dev->hw = hw; - rt2x00dev->irq = platform_get_irq(pdev, 0); - rt2x00dev->name = pdev->dev.driver->name; - - rt2x00dev->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(rt2x00dev->clk)) - rt2x00dev->clk = NULL; - - rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC); - - retval = rt2x00soc_alloc_reg(rt2x00dev); - if (retval) - goto exit_free_device; - - retval = rt2x00lib_probe_dev(rt2x00dev); - if (retval) - goto exit_free_reg; - - return 0; - -exit_free_reg: - rt2x00soc_free_reg(rt2x00dev); - -exit_free_device: - ieee80211_free_hw(hw); - - return retval; -} - -static void rt2x00soc_remove(struct platform_device *pdev) -{ - struct ieee80211_hw *hw = platform_get_drvdata(pdev); - struct rt2x00_dev *rt2x00dev = hw->priv; - - /* - * Free all allocated data. - */ - rt2x00lib_remove_dev(rt2x00dev); - rt2x00soc_free_reg(rt2x00dev); - ieee80211_free_hw(hw); -} - #ifdef CONFIG_PM -static int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state) +static int rt2800soc_suspend(struct platform_device *pdev, pm_message_t state) { struct ieee80211_hw *hw = platform_get_drvdata(pdev); struct rt2x00_dev *rt2x00dev = hw->priv; @@ -239,7 +140,7 @@ static int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state) return rt2x00lib_suspend(rt2x00dev); } -static int rt2x00soc_resume(struct platform_device *pdev) +static int rt2800soc_resume(struct platform_device *pdev) { struct ieee80211_hw *hw = platform_get_drvdata(pdev); struct rt2x00_dev *rt2x00dev = hw->priv; @@ -355,11 +256,85 @@ static const struct rt2x00_ops rt2800soc_ops = { #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ }; +static int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops) +{ + struct rt2x00_dev *rt2x00dev; + struct ieee80211_hw *hw; + void __iomem *mem; + struct clk *clk; + __le16 *eeprom; + int retval; + u32 *rf; + int irq; + + mem = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(mem)) + return PTR_ERR(mem); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + clk = devm_clk_get_optional(&pdev->dev, NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + eeprom = devm_kzalloc(&pdev->dev, ops->eeprom_size, GFP_KERNEL); + if (!eeprom) + return -ENOMEM; + + rf = devm_kzalloc(&pdev->dev, ops->rf_size, GFP_KERNEL); + if (!rf) + return -ENOMEM; + + hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw); + if (!hw) + return dev_err_probe(&pdev->dev, -ENOMEM, "Failed to allocate hardware"); + + platform_set_drvdata(pdev, hw); + + rt2x00dev = hw->priv; + rt2x00dev->dev = &pdev->dev; + rt2x00dev->ops = ops; + rt2x00dev->hw = hw; + rt2x00dev->irq = irq; + rt2x00dev->clk = clk; + rt2x00dev->eeprom = eeprom; + rt2x00dev->rf = rf; + rt2x00dev->name = pdev->dev.driver->name; + rt2x00dev->csr.base = mem; + + rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC); + + retval = rt2x00lib_probe_dev(rt2x00dev); + if (retval) + goto exit_free_device; + + return 0; + +exit_free_device: + ieee80211_free_hw(hw); + + return retval; +} + static int rt2800soc_probe(struct platform_device *pdev) { return rt2x00soc_probe(pdev, &rt2800soc_ops); } +static void rt2800soc_remove(struct platform_device *pdev) +{ + struct ieee80211_hw *hw = platform_get_drvdata(pdev); + struct rt2x00_dev *rt2x00dev = hw->priv; + + /* + * Free all allocated data. + */ + rt2x00lib_remove_dev(rt2x00dev); + ieee80211_free_hw(hw); +} + static const struct of_device_id rt2880_wmac_match[] = { { .compatible = "ralink,rt2880-wifi" }, {}, @@ -372,9 +347,11 @@ static struct platform_driver rt2800soc_driver = { .of_match_table = rt2880_wmac_match, }, .probe = rt2800soc_probe, - .remove = rt2x00soc_remove, - .suspend = rt2x00soc_suspend, - .resume = rt2x00soc_resume, + .remove = rt2800soc_remove, +#ifdef CONFIG_PM + .suspend = rt2800soc_suspend, + .resume = rt2800soc_resume, +#endif }; module_platform_driver(rt2800soc_driver); From fdd544482e405a933aab2537d2db42079d639f82 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Tue, 22 Jul 2025 14:28:55 -0700 Subject: [PATCH 177/199] MIPS: dts: ralink: mt7620a: add wifi MT7620A devices all contain a wifi device as part of the SOC. Add it here to get it working. Signed-off-by: Rosen Penev Reviewed-by: Sergio Paracuellos Link: https://patch.msgid.link/20250722212856.11343-7-rosenp@gmail.com Signed-off-by: Johannes Berg --- arch/mips/boot/dts/ralink/mt7620a.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/mips/boot/dts/ralink/mt7620a.dtsi b/arch/mips/boot/dts/ralink/mt7620a.dtsi index d66045948a83..460164bdd430 100644 --- a/arch/mips/boot/dts/ralink/mt7620a.dtsi +++ b/arch/mips/boot/dts/ralink/mt7620a.dtsi @@ -62,4 +62,14 @@ reg-shift = <2>; }; }; + + wmac: wifi@10180000 { + compatible = "ralink,rt2880-wifi"; + reg = <0x10180000 0x40000>; + + clocks = <&sysc 16>; + + interrupt-parent = <&cpuintc>; + interrupts = <6>; + }; }; From cac6599b2d68caa6327ee04861572add8fd20004 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Tue, 22 Jul 2025 14:28:56 -0700 Subject: [PATCH 178/199] dt-bindings: net: wireless: rt2800: add SOC Wifi Add device-tree bindings for the RT2800 SOC wifi device found in older Ralink/Mediatek devices. Signed-off-by: Rosen Penev Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250722212856.11343-8-rosenp@gmail.com Signed-off-by: Johannes Berg --- .../bindings/net/wireless/ralink,rt2880.yaml | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/wireless/ralink,rt2880.yaml diff --git a/Documentation/devicetree/bindings/net/wireless/ralink,rt2880.yaml b/Documentation/devicetree/bindings/net/wireless/ralink,rt2880.yaml new file mode 100644 index 000000000000..04dc5bb2edcc --- /dev/null +++ b/Documentation/devicetree/bindings/net/wireless/ralink,rt2880.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/wireless/ralink,rt2880.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Ralink RT2880 wireless device + +maintainers: + - Stanislaw Gruszka + +description: | + This node provides properties for configuring RT2880 SOC wifi devices. + The node is expected to be specified as a root node of the device. + +allOf: + - $ref: ieee80211.yaml# + +properties: + compatible: + enum: + - ralink,rt2880-wifi + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - interrupts + +additionalProperties: false + +examples: + - | + wifi@110180000 { + compatible = "ralink,rt2880-wifi"; + reg = <0x10180000 0x40000>; + clocks = <&sysc 16>; + interrupt-parent = <&cpuintc>; + interrupts = <6>; + }; From fc3475fa461114c148df61a9b0a4d49787eb3cd3 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 23 Jul 2025 09:45:02 +0300 Subject: [PATCH 179/199] wifi: iwlwifi: mld: disable RX aggregation if requested The user can request to disable RX aggregations via the module parameter enable_11n. Honor this request and reject addba. Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250723094230.40746586ade7.Ibf5877df76ea2f1eee614166b3194843fd9898cd@changeid --- drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 59be9923c3b2..d929cf2e73fd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -1918,6 +1918,10 @@ iwl_mld_mac80211_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: + if (!iwl_enable_rx_ampdu()) { + ret = -EINVAL; + break; + } ret = iwl_mld_ampdu_rx_start(mld, sta, tid, ssn, buf_size, timeout); break; From 0dd86ab21dbbcef7cd7cb1eb303e1803ed32a5f3 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 23 Jul 2025 09:45:03 +0300 Subject: [PATCH 180/199] wifi: iwlwifi: mld: support channel survey collection for ACS scans The firmware is able to collect channel statistics when doing passive scans. Enable the flag when doing a passive scan on an AP interface and collect the survey information. Signed-off-by: Benjamin Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250723094230.a659ef1b1fd8.I24a9a0383327c231f36be170968bc7bac801f9f2@changeid --- .../net/wireless/intel/iwlwifi/mld/mac80211.c | 1 + drivers/net/wireless/intel/iwlwifi/mld/mld.c | 9 + drivers/net/wireless/intel/iwlwifi/mld/mld.h | 2 + .../net/wireless/intel/iwlwifi/mld/notif.c | 6 + drivers/net/wireless/intel/iwlwifi/mld/scan.c | 156 +++++++++++++++++- drivers/net/wireless/intel/iwlwifi/mld/scan.h | 37 +++++ 6 files changed, 210 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index d929cf2e73fd..c6e61c843f77 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -2675,6 +2675,7 @@ const struct ieee80211_ops iwl_mld_hw_ops = { .mgd_complete_tx = iwl_mld_mac_mgd_complete_tx, .sta_state = iwl_mld_mac80211_sta_state, .sta_statistics = iwl_mld_mac80211_sta_statistics, + .get_survey = iwl_mld_mac80211_get_survey, .flush = iwl_mld_mac80211_flush, .flush_sta = iwl_mld_mac80211_flush_sta, .ampdu_action = iwl_mld_mac80211_ampdu_action, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.c b/drivers/net/wireless/intel/iwlwifi/mld/mld.c index e7cbfb9009af..e78e7a4f39d1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.c @@ -259,6 +259,13 @@ static const struct iwl_hcmd_names iwl_mld_data_path_names[] = { HCMD_NAME(MU_GROUP_MGMT_NOTIF), }; +/* Please keep this array *SORTED* by hex value. + * Access is done through binary search + */ +static const struct iwl_hcmd_names iwl_mld_scan_names[] = { + HCMD_NAME(CHANNEL_SURVEY_NOTIF), +}; + /* Please keep this array *SORTED* by hex value. * Access is done through binary search */ @@ -310,6 +317,7 @@ const struct iwl_hcmd_arr iwl_mld_groups[] = { [SYSTEM_GROUP] = HCMD_ARR(iwl_mld_system_names), [MAC_CONF_GROUP] = HCMD_ARR(iwl_mld_mac_conf_names), [DATA_PATH_GROUP] = HCMD_ARR(iwl_mld_data_path_names), + [SCAN_GROUP] = HCMD_ARR(iwl_mld_scan_names), [LOCATION_GROUP] = HCMD_ARR(iwl_mld_location_names), [REGULATORY_AND_NVM_GROUP] = HCMD_ARR(iwl_mld_reg_and_nvm_names), [DEBUG_GROUP] = HCMD_ARR(iwl_mld_debug_names), @@ -507,6 +515,7 @@ iwl_op_mode_mld_stop(struct iwl_op_mode *op_mode) kfree(mld->nvm_data); kfree(mld->scan.cmd); + kfree(mld->channel_survey); kfree(mld->error_recovery_buf); kfree(mld->mcast_filter_cmd); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.h b/drivers/net/wireless/intel/iwlwifi/mld/mld.h index 8bc4749599ca..94dc9da6360d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.h @@ -160,6 +160,7 @@ * device * @addresses: device MAC addresses. * @scan: instance of the scan object + * @channel_survey: channel survey information collected during scan * @wowlan: WoWLAN support data. * @debug_max_sleep: maximum sleep time in D3 (for debug purposes) * @led: the led device @@ -253,6 +254,7 @@ struct iwl_mld { struct mac_address addresses[IWL_MLD_MAX_ADDRESSES]; struct iwl_mld_scan scan; + struct iwl_mld_survey *channel_survey; #ifdef CONFIG_PM_SLEEP struct wiphy_wowlan_support wowlan; u32 debug_max_sleep; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/notif.c b/drivers/net/wireless/intel/iwlwifi/mld/notif.c index 262d8e25e62a..3cb700a9708e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/notif.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/notif.c @@ -295,6 +295,8 @@ CMD_VERSIONS(scan_complete_notif, CMD_VER_ENTRY(1, iwl_umac_scan_complete)) CMD_VERSIONS(scan_iter_complete_notif, CMD_VER_ENTRY(2, iwl_umac_scan_iter_complete_notif)) +CMD_VERSIONS(channel_survey_notif, + CMD_VER_ENTRY(1, iwl_umac_scan_channel_survey_notif)) CMD_VERSIONS(mfuart_notif, CMD_VER_ENTRY(2, iwl_mfuart_load_notif)) CMD_VERSIONS(update_mcc, @@ -415,6 +417,10 @@ const struct iwl_rx_handler iwl_mld_rx_handlers[] = { RX_HANDLER_NO_VAL(LEGACY_GROUP, MATCH_FOUND_NOTIFICATION, match_found_notif, RX_HANDLER_SYNC) + RX_HANDLER_NO_OBJECT(SCAN_GROUP, CHANNEL_SURVEY_NOTIF, + channel_survey_notif, + RX_HANDLER_ASYNC) + RX_HANDLER_NO_OBJECT(STATISTICS_GROUP, STATISTICS_OPER_NOTIF, stats_oper_notif, RX_HANDLER_ASYNC) RX_HANDLER_NO_OBJECT(STATISTICS_GROUP, STATISTICS_OPER_PART1_NOTIF, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.c b/drivers/net/wireless/intel/iwlwifi/mld/scan.c index 479a76a94aa8..62f97a18a16c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.c @@ -4,6 +4,8 @@ */ #include +#include "iwl-utils.h" + #include "mld.h" #include "scan.h" #include "hcmd.h" @@ -482,7 +484,9 @@ iwl_mld_scan_get_cmd_gen_flags(struct iwl_mld *mld, static u8 iwl_mld_scan_get_cmd_gen_flags2(struct iwl_mld *mld, struct iwl_mld_scan_params *params, - struct ieee80211_vif *vif, u16 gen_flags) + struct ieee80211_vif *vif, + enum iwl_mld_scan_status scan_status, + u16 gen_flags) { u8 flags = 0; @@ -494,6 +498,17 @@ iwl_mld_scan_get_cmd_gen_flags2(struct iwl_mld *mld, if (params->scan_6ghz) flags |= IWL_UMAC_SCAN_GEN_PARAMS_FLAGS2_DONT_TOGGLE_ANT; + /* For AP interfaces, request survey data for regular scans and if + * it is supported. For non-AP interfaces, EBS will be enabled and + * the results may be missing information for some channels. + */ + if (scan_status == IWL_MLD_SCAN_REGULAR && + ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_AP && + gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE && + iwl_fw_lookup_notif_ver(mld->fw, SCAN_GROUP, + CHANNEL_SURVEY_NOTIF, 0) >= 1) + flags |= IWL_UMAC_SCAN_GEN_FLAGS2_COLLECT_CHANNEL_STATS; + return flags; } @@ -544,6 +559,7 @@ iwl_mld_scan_cmd_set_gen_params(struct iwl_mld *mld, u16 gen_flags = iwl_mld_scan_get_cmd_gen_flags(mld, params, vif, scan_status); u8 gen_flags2 = iwl_mld_scan_get_cmd_gen_flags2(mld, params, vif, + scan_status, gen_flags); IWL_DEBUG_SCAN(mld, "General: flags=0x%x, flags2=0x%x\n", @@ -1752,6 +1768,11 @@ int iwl_mld_regular_scan_start(struct iwl_mld *mld, struct ieee80211_vif *vif, struct cfg80211_scan_request *req, struct ieee80211_scan_ies *ies) { + /* Clear survey data when starting the first part of a regular scan */ + if (req->first_part && mld->channel_survey) + memset(mld->channel_survey->channels, 0, + sizeof(mld->channel_survey->channels[0]) * + mld->channel_survey->n_channels); if (vif->type == NL80211_IFTYPE_P2P_DEVICE) iwl_mld_emlsr_block_tmp_non_bss(mld); @@ -2025,3 +2046,136 @@ int iwl_mld_alloc_scan_cmd(struct iwl_mld *mld) return 0; } + +static int iwl_mld_chanidx_from_phy(struct iwl_mld *mld, + enum nl80211_band band, + u16 phy_chan_num) +{ + struct ieee80211_supported_band *sband = mld->wiphy->bands[band]; + + if (WARN_ON_ONCE(!sband)) + return -EINVAL; + + for (int chan_idx = 0; chan_idx < sband->n_channels; chan_idx++) { + struct ieee80211_channel *channel = &sband->channels[chan_idx]; + + if (channel->hw_value == phy_chan_num) + return chan_idx; + } + + return -EINVAL; +} + +void iwl_mld_handle_channel_survey_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt) +{ + const struct iwl_umac_scan_channel_survey_notif *notif = + (void *)pkt->data; + struct iwl_mld_survey_channel *info; + enum nl80211_band band; + int chan_idx; + + if (!mld->channel_survey) { + size_t n_channels = 0; + + for (band = 0; band < NUM_NL80211_BANDS; band++) { + if (!mld->wiphy->bands[band]) + continue; + + n_channels += mld->wiphy->bands[band]->n_channels; + } + + mld->channel_survey = kzalloc(struct_size(mld->channel_survey, + channels, n_channels), + GFP_KERNEL); + + if (!mld->channel_survey) + return; + + mld->channel_survey->n_channels = n_channels; + n_channels = 0; + for (band = 0; band < NUM_NL80211_BANDS; band++) { + if (!mld->wiphy->bands[band]) + continue; + + mld->channel_survey->bands[band] = + &mld->channel_survey->channels[n_channels]; + n_channels += mld->wiphy->bands[band]->n_channels; + } + } + + band = iwl_mld_phy_band_to_nl80211(le32_to_cpu(notif->band)); + chan_idx = iwl_mld_chanidx_from_phy(mld, band, + le32_to_cpu(notif->channel)); + if (WARN_ON_ONCE(chan_idx < 0)) + return; + + IWL_DEBUG_SCAN(mld, "channel survey received for freq %d\n", + mld->wiphy->bands[band]->channels[chan_idx].center_freq); + + info = &mld->channel_survey->bands[band][chan_idx]; + + /* Times are all in ms */ + info->time = le32_to_cpu(notif->active_time); + info->time_busy = le32_to_cpu(notif->busy_time); + info->noise = + iwl_average_neg_dbm(notif->noise, ARRAY_SIZE(notif->noise)); +} + +int iwl_mld_mac80211_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey) +{ + struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); + int curr_idx = 0; + + if (!mld->channel_survey) + return -ENOENT; + + /* Iterate bands/channels to find the requested index. + * Logically this returns the entry with index "idx" from a flattened + * survey result array that only contains channels with information. + * The current index into this flattened array is tracked in curr_idx. + */ + for (enum nl80211_band band = 0; band < NUM_NL80211_BANDS; band++) { + struct ieee80211_supported_band *sband = + mld->wiphy->bands[band]; + + if (!sband) + continue; + + for (int per_band_idx = 0; + per_band_idx < sband->n_channels; + per_band_idx++) { + struct iwl_mld_survey_channel *info = + &mld->channel_survey->bands[band][per_band_idx]; + + /* Skip entry entirely, it was not reported/scanned, + * do not increase curr_idx for this entry. + */ + if (!info->time) + continue; + + /* Search did not reach the requested entry yet, + * increment curr_idx and continue. + */ + if (idx != curr_idx) { + curr_idx++; + continue; + } + + /* Found (the next) channel to report */ + survey->channel = &sband->channels[per_band_idx]; + survey->filled = SURVEY_INFO_TIME | + SURVEY_INFO_TIME_BUSY; + survey->time = info->time; + survey->time_busy = info->time_busy; + survey->noise = info->noise; + if (survey->noise < 0) + survey->filled |= SURVEY_INFO_NOISE_DBM; + + return 0; + } + } + + return -ENOENT; +} diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.h b/drivers/net/wireless/intel/iwlwifi/mld/scan.h index 4044cac3f086..69110f0cfc8e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.h @@ -30,6 +30,12 @@ void iwl_mld_handle_match_found_notif(struct iwl_mld *mld, void iwl_mld_handle_scan_complete_notif(struct iwl_mld *mld, struct iwl_rx_packet *pkt); +int iwl_mld_mac80211_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey); + +void iwl_mld_handle_channel_survey_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt); + #define WFA_TPC_IE_LEN 9 static inline int iwl_mld_scan_max_template_size(void) @@ -133,4 +139,35 @@ struct iwl_mld_scan { u64 last_mlo_scan_time; }; +/** + * struct iwl_mld_survey_channel - per-channel survey information + * + * Driver version of &struct survey_info with just the data we want to report. + * + * @time: time in ms the radio was on the channel + * @time_busy: time in ms the channel was sensed busy + * @noise: channel noise in dBm + */ +struct iwl_mld_survey_channel { + u32 time; + u32 time_busy; + s8 noise; +}; + +/** + * struct iwl_mld_survey - survey information + * + * Survey information for all available channels. + * + * @bands: per-band array for per-channel survey data, points into @channels + * @n_channels: Number of @channels entries that are allocated + * @channels: per-channel information + */ +struct iwl_mld_survey { + struct iwl_mld_survey_channel *bands[NUM_NL80211_BANDS]; + + int n_channels; + struct iwl_mld_survey_channel channels[] __counted_by(n_channels); +}; + #endif /* __iwl_mld_scan_h__ */ From 0636800c8ee1daa55c9f0f00e8af869645dab4df Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 Jul 2025 09:45:04 +0300 Subject: [PATCH 181/199] wifi: iwlwifi: disable certain features for fips_enabled When fips_enabled is set, keys will not be given to the hardware by mac80211 since the hardware isn't certified. In this case, various features cannot work correctly as the firmware needs to handle frames, but it then cannot since no keys are available. Disable features: - WoWLAN since no keys etc. - MFP since some frames need to be handled in firmware - EHT/6GHz since MFP is required Also restrict A-MSDU size since A-MSDUs cannot be split up by hardware and thus need to fit into the RX buffers in one piece. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250723094230.329fade58a27.I0be27dd329643cc5fdf79a8c8b8f6d2e6fb5c175@changeid --- .../wireless/intel/iwlwifi/iwl-nvm-parse.c | 25 ++++++++++++++++--- .../net/wireless/intel/iwlwifi/mld/mac80211.c | 11 +++++++- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 16 +++++++++--- 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 4424443d2328..a67b9572aac3 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -5,6 +5,7 @@ * Copyright (C) 2016-2017 Intel Deutschland GmbH */ #include +#include #include #include #include @@ -543,16 +544,22 @@ static void iwl_init_vht_hw_capab(struct iwl_trans *trans, else vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; + /* + * With fips_enabled crypto is done by software, so the HW cannot + * split up A-MSDUs and the real limit that was set applies. + * Note that EHT doesn't honour this (HE copies the VHT value), + * but EHT is also entirely disabled for fips_enabled. + */ switch (iwlwifi_mod_params.amsdu_size) { case IWL_AMSDU_DEF: - if (trans->mac_cfg->mq_rx_supported) + if (trans->mac_cfg->mq_rx_supported && !fips_enabled) vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; else vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895; break; case IWL_AMSDU_2K: - if (trans->mac_cfg->mq_rx_supported) + if (trans->mac_cfg->mq_rx_supported && !fips_enabled) vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; else @@ -909,7 +916,9 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, bool slow_pcie = (!trans->mac_cfg->integrated && trans->info.pcie_link_speed < PCI_EXP_LNKSTA_CLS_8_0GB); - if (!data->sku_cap_11be_enable || iwlwifi_mod_params.disable_11be) + /* EHT needs WPA3/MFP so cannot do it for fips_enabled */ + if (!data->sku_cap_11be_enable || iwlwifi_mod_params.disable_11be || + fips_enabled) iftype_data->eht_cap.has_eht = false; /* Advertise an A-MPDU exponent extension based on @@ -1197,11 +1206,19 @@ static void iwl_init_sbands(struct iwl_trans *trans, n_used += iwl_init_sband_channels(data, sband, n_channels, NL80211_BAND_6GHZ); - if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax) + /* + * 6 GHz requires WPA3 which requires MFP, which FW cannot do + * when fips_enabled, so don't advertise any 6 GHz channels to + * avoid spending time on scanning those channels and perhaps + * even finding APs there that cannot be used. + */ + if (!fips_enabled && data->sku_cap_11ax_enable && + !iwlwifi_mod_params.disable_11ax) iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains, fw); else sband->n_channels = 0; + if (n_channels != n_used) IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n", n_used, n_channels); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index c6e61c843f77..3ea6d4c1b779 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -4,6 +4,7 @@ */ #include +#include #include #include "mld.h" @@ -156,6 +157,9 @@ static void iwl_mld_hw_set_security(struct iwl_mld *mld) WLAN_CIPHER_SUITE_BIP_GMAC_256 }; + if (fips_enabled) + return; + hw->wiphy->n_cipher_suites = ARRAY_SIZE(mld_ciphers); hw->wiphy->cipher_suites = mld_ciphers; @@ -180,6 +184,9 @@ static void iwl_mld_hw_set_pm(struct iwl_mld *mld) if (!device_can_wakeup(mld->trans->dev)) return; + if (fips_enabled) + return; + mld->wowlan.flags |= WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | WIPHY_WOWLAN_EAP_IDENTITY_REQ | @@ -284,9 +291,11 @@ static void iwl_mac_hw_set_wiphy(struct iwl_mld *mld) WIPHY_FLAG_SUPPORTS_TDLS | WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK; + /* For fips_enabled, don't support WiFi7 due to WPA3/MFP requirements */ if (mld->nvm_data->sku_cap_11be_enable && !iwlwifi_mod_params.disable_11ax && - !iwlwifi_mod_params.disable_11be) + !iwlwifi_mod_params.disable_11be && + !fips_enabled) wiphy->flags |= WIPHY_FLAG_SUPPORTS_MLO; /* the firmware uses u8 for num of iterations, but 0xff is saved for diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index fa9d5e0b6609..55ae1caded53 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -5,6 +5,7 @@ * Copyright (C) 2016-2017 Intel Deutschland GmbH */ #include +#include #include #include #include @@ -461,7 +462,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) IWL_ERR(mvm, "iwlmvm doesn't allow to disable BT Coex, check bt_coex_active module parameter\n"); - ieee80211_hw_set(hw, MFP_CAPABLE); + if (!fips_enabled) + ieee80211_hw_set(hw, MFP_CAPABLE); + mvm->ciphers[hw->wiphy->n_cipher_suites] = WLAN_CIPHER_SUITE_AES_CMAC; hw->wiphy->n_cipher_suites++; if (iwl_mvm_has_new_rx_api(mvm)) { @@ -485,12 +488,17 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->wiphy->pmsr_capa = &iwl_mvm_pmsr_capa; } - if (sec_key_ver && + /* + * beacon protection must be handled by firmware, + * so cannot be done with fips_enabled + */ + if (!fips_enabled && sec_key_ver && fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BIGTK_TX_SUPPORT)) wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION); - else if (fw_has_capa(&mvm->fw->ucode_capa, + else if (!fips_enabled && + fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BIGTK_SUPPORT)) wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT); @@ -730,7 +738,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) #ifdef CONFIG_PM_SLEEP if ((unified || mvm->fw->img[IWL_UCODE_WOWLAN].num_sec) && - device_can_wakeup(mvm->trans->dev)) { + device_can_wakeup(mvm->trans->dev) && !fips_enabled) { mvm->wowlan.flags |= WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | WIPHY_WOWLAN_EAP_IDENTITY_REQ | From 422850b29e05e67c9145895bfe559940caa0caa8 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Wed, 23 Jul 2025 09:45:05 +0300 Subject: [PATCH 182/199] wifi: iwlwifi: mvm: avoid outdated reorder buffer head_sn If no frames are received on a queue for a while, the reorder buffer head_sn may be an old one. When the next frame that is received on that queue and buffered is a subframe of an AMSDU but not the last subframe, it will not update the buffer's head_sn. When the frame release notification arrives, it will not release the buffered frame because it will look like the notification's NSSN is lower than the buffer's head_sn (because of a wraparound). Fix it by updating the head_sn when the first frame is buffered. Signed-off-by: Avraham Stern Reviewed-by: Daniel Gabay Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250723094230.795ec0cb8817.I9ec9a3508e7935e8d1833ea3e086066fdefee644@changeid --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 4b57ca56e1f6..62e76a79f621 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -905,10 +905,15 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, * already ahead and it will be dropped. * If the last sub-frame is not on this queue - we will get frame * release notification with up to date NSSN. + * If this is the first frame that is stored in the buffer, the head_sn + * may be outdated. Update it based on the last NSSN to make sure it + * will be released when the frame release notification arrives. */ if (!amsdu || last_subframe) iwl_mvm_release_frames(mvm, sta, napi, baid_data, buffer, nssn); + else if (buffer->num_stored == 1) + buffer->head_sn = nssn; spin_unlock_bh(&buffer->lock); return true; From 666357bf3e57c6a68be128825775aee14f9a24f7 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Wed, 23 Jul 2025 09:45:06 +0300 Subject: [PATCH 183/199] wifi: iwlwifi: mld: avoid outdated reorder buffer head_sn If no frames are received on a queue for a while, the reorder buffer head_sn may be an old one. When the next frame that is received on that queue and buffered is a subframe of an AMSDU but not the last subframe, it will not update the buffer's head_sn. When the frame release notification arrives, it will not release the buffered frame because it will look like the notification's NSSN is lower than the buffer's head_sn (because of a wraparound). Fix it by updating the head_sn when the first frame is buffered. Signed-off-by: Avraham Stern Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250723094230.e1f62a9a603c.I7b57a481122074b1f40d39cd31db2e5262668eb2@changeid --- drivers/net/wireless/intel/iwlwifi/mld/agg.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/agg.c b/drivers/net/wireless/intel/iwlwifi/mld/agg.c index 6b349270481d..3bf36f8f6874 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/agg.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/agg.c @@ -305,10 +305,15 @@ iwl_mld_reorder(struct iwl_mld *mld, struct napi_struct *napi, * already ahead and it will be dropped. * If the last sub-frame is not on this queue - we will get frame * release notification with up to date NSSN. + * If this is the first frame that is stored in the buffer, the head_sn + * may be outdated. Update it based on the last NSSN to make sure it + * will be released when the frame release notification arrives. */ if (!amsdu || last_subframe) iwl_mld_reorder_release_frames(mld, sta, napi, baid_data, buffer, nssn); + else if (buffer->num_stored == 1) + buffer->head_sn = nssn; return IWL_MLD_BUFFERED_SKB; } From 4459dd6d85b9fbcdbc3803603fba9d78c1cec2c4 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Wed, 23 Jul 2025 09:45:07 +0300 Subject: [PATCH 184/199] wifi: iwlwifi: mvm: Remove NAN support NAN is not officially supported on any of the MVM devices so there is no need to maintain it. Signed-off-by: Ilan Peer Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250723094230.b327adbf35c0.I0357e383ab5df72d8b87e0dee10609a6946865b6@changeid --- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 6 ------ drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c | 9 --------- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 - drivers/net/wireless/intel/iwlwifi/mvm/power.c | 1 - 5 files changed, 1 insertion(+), 18 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 7d2b496aadc5..8805ab344895 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -301,7 +301,7 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) iwl_mvm_init_link(&mvmvif->deflink); - /* No need to allocate data queues to P2P Device MAC and NAN.*/ + /* No need to allocate data queues to P2P Device MAC */ if (vif->type == NL80211_IFTYPE_P2P_DEVICE) return 0; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 55ae1caded53..ed19b82d14fa 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1833,12 +1833,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, rcu_assign_pointer(mvm->vif_id_to_mac[mvmvif->id], vif); - /* Currently not much to do for NAN */ - if (vif->type == NL80211_IFTYPE_NAN) { - ret = 0; - goto out; - } - /* * The AP binding flow can be done only after the beacon * template is configured (which happens only in the mac80211 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c index 3f8b840871d3..2d116a41913c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c @@ -282,9 +282,6 @@ int iwl_mvm_mld_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif) struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ret; - if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN)) - return -EOPNOTSUPP; - if (WARN_ONCE(mvmvif->uploaded, "Adding active MAC %pM/%d\n", vif->addr, ieee80211_vif_type_p2p(vif))) return -EIO; @@ -307,9 +304,6 @@ int iwl_mvm_mld_mac_ctxt_changed(struct iwl_mvm *mvm, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN)) - return -EOPNOTSUPP; - if (WARN_ONCE(!mvmvif->uploaded, "Changing inactive MAC %pM/%d\n", vif->addr, ieee80211_vif_type_p2p(vif))) return -EIO; @@ -327,9 +321,6 @@ int iwl_mvm_mld_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif) }; int ret; - if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN)) - return -EOPNOTSUPP; - if (WARN_ONCE(!mvmvif->uploaded, "Removing inactive MAC %pM/%d\n", vif->addr, ieee80211_vif_type_p2p(vif))) return -EIO; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index af73ff09d609..fdaeefa305e1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1325,7 +1325,6 @@ struct iwl_mvm { u8 range_resp; } cmd_ver; - struct ieee80211_vif *nan_vif; struct iwl_mvm_baid_data __rcu *baid_map[IWL_MAX_BAID]; /* diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index 0057fddf88f0..610de29b7be0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -231,7 +231,6 @@ static void iwl_mvm_allow_uapsd_iterator(void *_data, u8 *mac, switch (vif->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_NAN: data->allow_uapsd = false; break; case NL80211_IFTYPE_STATION: From 5d94c61c9dcffe2ce8da958448ee1c359e3b0b2a Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 23 Jul 2025 09:45:08 +0300 Subject: [PATCH 185/199] wifi: iwlwifi: remove SC2F firmware support The only difference between SC2 and SC2F is that they use a different FSEQ image. The firmware of SC2 implements the logic of selecting the right FSEQ image to load, so there is no need for SC2F firmware image. Stop loading it, and load SC2 image instead. Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250723094230.bf0ec63e49a9.Iffa0a982f90a179566d85c60ccd3dbfc50e293ef@changeid --- drivers/net/wireless/intel/iwlwifi/cfg/sc.c | 4 ---- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 5 ++--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index 7b70640abf53..6d4a3bce49b9 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -27,8 +27,6 @@ #define IWL_SC_A_WH_A_FW_PRE "iwlwifi-sc-a0-wh-a0" #define IWL_SC2_A_FM_C_FW_PRE "iwlwifi-sc2-a0-fm-c0" #define IWL_SC2_A_WH_A_FW_PRE "iwlwifi-sc2-a0-wh-a0" -#define IWL_SC2F_A_FM_C_FW_PRE "iwlwifi-sc2f-a0-fm-c0" -#define IWL_SC2F_A_WH_A_FW_PRE "iwlwifi-sc2f-a0-wh-a0" static const struct iwl_family_base_params iwl_sc_base = { .num_of_queues = 512, @@ -101,5 +99,3 @@ IWL_FW_AND_PNVM(IWL_SC_A_FM_C_FW_PRE, IWL_SC_UCODE_API_MAX); IWL_FW_AND_PNVM(IWL_SC_A_WH_A_FW_PRE, IWL_SC_UCODE_API_MAX); IWL_FW_AND_PNVM(IWL_SC2_A_FM_C_FW_PRE, IWL_SC_UCODE_API_MAX); IWL_FW_AND_PNVM(IWL_SC2_A_WH_A_FW_PRE, IWL_SC_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_SC2F_A_FM_C_FW_PRE, IWL_SC_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_SC2F_A_WH_A_FW_PRE, IWL_SC_UCODE_API_MAX); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 6d983fe2ee44..28aad975434b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -236,10 +236,9 @@ const char *iwl_drv_get_fwname_pre(struct iwl_trans *trans, char *buf) mac = "sc"; break; case IWL_CFG_MAC_TYPE_SC2: - mac = "sc2"; - break; + /* Uses the same firmware as SC2 */ case IWL_CFG_MAC_TYPE_SC2F: - mac = "sc2f"; + mac = "sc2"; break; case IWL_CFG_MAC_TYPE_BR: mac = "br"; From b089c415e0a9e44f4ecba470e189063c1ed7f4d4 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 23 Jul 2025 09:45:09 +0300 Subject: [PATCH 186/199] wifi: iwlwifi: stop supporting iwl_omi_send_status_notif ver 1 This version doesn't provide the sta id, so we need to look it up - assuming that no other sta exists, since one of the conditions of entering OMI is not having P2P/TDLS. But when we leave OMI, because of the P2P/TDLS activation, the P2P/TDLS sta can already exist while we receive the notification from the FW. This causes an error log which is incorrect. Since OMI is only supported in SC, which is not shipped yet, no one will use a FW with the old version. Remove support for it. Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250723094230.b716b9cebaa7.I2a1cc4be441dbbb5566a9a3d2d330d956ff3ed38@changeid --- .../wireless/intel/iwlwifi/fw/api/datapath.h | 9 ----- drivers/net/wireless/intel/iwlwifi/mld/link.c | 40 +++++++------------ .../net/wireless/intel/iwlwifi/mld/notif.c | 1 - 3 files changed, 14 insertions(+), 36 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h index ee822a87c42c..083136a0c456 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h @@ -699,15 +699,6 @@ struct iwl_sec_key_cmd { } __packed u; /* SEC_KEY_OPERATION_API_U_VER_1 */ } __packed; /* SEC_KEY_CMD_API_S_VER_1 */ -/** - * struct iwl_omi_send_status_notif_v1 - OMI status notification - * @success: indicates that the OMI was sent successfully - * (currently always set) - */ -struct iwl_omi_send_status_notif_v1 { - __le32 success; -} __packed; /* OMI_SEND_STATUS_NTFY_API_S_VER_1 */ - /** * struct iwl_omi_send_status_notif - OMI status notification * @success: indicates that the OMI was sent successfully diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.c b/drivers/net/wireless/intel/iwlwifi/mld/link.c index c48cc3909637..9797510cab3f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/link.c @@ -649,40 +649,28 @@ void iwl_mld_omi_ap_changed_bw(struct iwl_mld *mld, void iwl_mld_handle_omi_status_notif(struct iwl_mld *mld, struct iwl_rx_packet *pkt) { - int ver = iwl_fw_lookup_notif_ver(mld->fw, DATA_PATH_GROUP, - OMI_SEND_STATUS_NOTIF, 1); + const struct iwl_omi_send_status_notif *notif = (const void *)pkt->data; struct ieee80211_link_sta *link_sta; struct iwl_mld_link *mld_link; + struct iwl_mld_vif *mld_vif; struct ieee80211_vif *vif; + u32 sta_id; - if (ver == 2) { - const struct iwl_omi_send_status_notif *notif = - (const void *)pkt->data; - u32 sta_id = le32_to_cpu(notif->sta_id); - struct iwl_mld_vif *mld_vif; + sta_id = le32_to_cpu(notif->sta_id); - if (IWL_FW_CHECK(mld, sta_id >= mld->fw->ucode_capa.num_stations, - "Invalid station %d\n", sta_id)) - return; + if (IWL_FW_CHECK(mld, sta_id >= mld->fw->ucode_capa.num_stations, + "Invalid station %d\n", sta_id)) + return; - link_sta = wiphy_dereference(mld->wiphy, - mld->fw_id_to_link_sta[sta_id]); - if (IWL_FW_CHECK(mld, !link_sta, "Station does not exist\n")) - return; + link_sta = wiphy_dereference(mld->wiphy, mld->fw_id_to_link_sta[sta_id]); + if (IWL_FW_CHECK(mld, !link_sta, "Station does not exist\n")) + return; - vif = iwl_mld_sta_from_mac80211(link_sta->sta)->vif; - mld_vif = iwl_mld_vif_from_mac80211(vif); + vif = iwl_mld_sta_from_mac80211(link_sta->sta)->vif; + mld_vif = iwl_mld_vif_from_mac80211(vif); - mld_link = iwl_mld_link_dereference_check(mld_vif, - link_sta->link_id); - if (WARN(!mld_link, "Link %d does not exist\n", - link_sta->link_id)) - return; - } else { - vif = iwl_mld_get_omi_bw_reduction_pointers(mld, &link_sta, - &mld_link); - } - if (IWL_FW_CHECK(mld, !vif, "unexpected OMI notification\n")) + mld_link = iwl_mld_link_dereference_check(mld_vif, link_sta->link_id); + if (WARN(!mld_link, "Link %d does not exist\n", link_sta->link_id)) return; if (IWL_FW_CHECK(mld, !mld_link->rx_omi.bw_in_progress, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/notif.c b/drivers/net/wireless/intel/iwlwifi/mld/notif.c index 3cb700a9708e..e8f10e8145f9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/notif.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/notif.c @@ -351,7 +351,6 @@ CMD_VERSIONS(time_msmt_notif, CMD_VERSIONS(time_sync_confirm_notif, CMD_VER_ENTRY(1, iwl_time_msmt_cfm_notify)) CMD_VERSIONS(omi_status_notif, - CMD_VER_ENTRY(1, iwl_omi_send_status_notif_v1) CMD_VER_ENTRY(2, iwl_omi_send_status_notif)) CMD_VERSIONS(ftm_resp_notif, CMD_VER_ENTRY(10, iwl_tof_range_rsp_ntfy)) CMD_VERSIONS(beacon_filter_notif, CMD_VER_ENTRY(2, iwl_beacon_filter_notif)) From 4b0dccdd81509ba57d1929da9e9395a9006fb98d Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 23 Jul 2025 09:45:10 +0300 Subject: [PATCH 187/199] wifi: iwlwifi: Remove support for rx OMI bandwidth reduction This feature turns out to have an issue: it can take up to 8 seconds to detect high throughput scenarios and to leave RX OMI bandwidth reduction. This leads to throughput degradation. Until the issues are fixed, remove the RX OMI implementation. Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250723094230.a9ccfe210516.Ic87bc7709a6761f593e88f1488a41442c68c1686@changeid --- .../wireless/intel/iwlwifi/fw/api/datapath.h | 17 - .../wireless/intel/iwlwifi/mld/constants.h | 9 - drivers/net/wireless/intel/iwlwifi/mld/link.c | 369 +----------------- drivers/net/wireless/intel/iwlwifi/mld/link.h | 30 -- .../wireless/intel/iwlwifi/mld/low_latency.c | 3 - .../net/wireless/intel/iwlwifi/mld/mac80211.c | 57 --- drivers/net/wireless/intel/iwlwifi/mld/mld.c | 1 - .../net/wireless/intel/iwlwifi/mld/notif.c | 12 - .../net/wireless/intel/iwlwifi/mld/stats.c | 2 - 9 files changed, 4 insertions(+), 496 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h index 083136a0c456..b1c6ee8ae2df 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h @@ -90,12 +90,6 @@ enum iwl_data_path_subcmd_ids { */ SEC_KEY_CMD = 0x18, - /** - * @OMI_SEND_STATUS_NOTIF: notification after OMI was sent - * uses &struct iwl_omi_send_status_notif - */ - OMI_SEND_STATUS_NOTIF = 0xF2, - /** * @ESR_MODE_NOTIF: notification to recommend/force a wanted esr mode, * uses &struct iwl_esr_mode_notif or &struct iwl_esr_mode_notif_v1 @@ -699,15 +693,4 @@ struct iwl_sec_key_cmd { } __packed u; /* SEC_KEY_OPERATION_API_U_VER_1 */ } __packed; /* SEC_KEY_CMD_API_S_VER_1 */ -/** - * struct iwl_omi_send_status_notif - OMI status notification - * @success: indicates that the OMI was sent successfully - * (currently always set) - * @sta_id: sta_id to which the OMI was sent - */ -struct iwl_omi_send_status_notif { - __le32 success; - __le32 sta_id; -} __packed; /* OMI_SEND_STATUS_NTFY_API_S_VER_2 */ - #endif /* __iwl_fw_api_datapath_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mld/constants.h b/drivers/net/wireless/intel/iwlwifi/mld/constants.h index 2a59b29b75cb..49accf96f44b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/constants.h @@ -40,15 +40,6 @@ #define IWL_MLD_TPT_COUNT_WINDOW (5 * HZ) -/* OMI reduced BW thresholds (channel load percentage) */ -#define IWL_MLD_OMI_ENTER_CHAN_LOAD 10 -#define IWL_MLD_OMI_EXIT_CHAN_LOAD_160 20 -#define IWL_MLD_OMI_EXIT_CHAN_LOAD_320 30 -/* time (in milliseconds) to let AP "settle" the OMI */ -#define IWL_MLD_OMI_AP_SETTLE_DELAY 27 -/* time (in milliseconds) to not enter OMI reduced BW after leaving */ -#define IWL_MLD_OMI_EXIT_PROTECTION 5000 - #define IWL_MLD_DIS_RANDOM_FW_ID false #define IWL_MLD_D3_DEBUG false #define IWL_MLD_NON_TRANSMITTING_AP false diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.c b/drivers/net/wireless/intel/iwlwifi/mld/link.c index 9797510cab3f..ca5e73cfe36e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/link.c @@ -242,27 +242,9 @@ static bool iwl_mld_fill_mu_edca(struct iwl_mld *mld, return true; } -static u8 iwl_mld_sta_rx_bw_to_fw(enum ieee80211_sta_rx_bandwidth bw) -{ - switch (bw) { - default: /* potential future values not supported by this hw/driver */ - case IEEE80211_STA_RX_BW_20: - return IWL_LINK_MODIFY_BW_20; - case IEEE80211_STA_RX_BW_40: - return IWL_LINK_MODIFY_BW_40; - case IEEE80211_STA_RX_BW_80: - return IWL_LINK_MODIFY_BW_80; - case IEEE80211_STA_RX_BW_160: - return IWL_LINK_MODIFY_BW_160; - case IEEE80211_STA_RX_BW_320: - return IWL_LINK_MODIFY_BW_320; - } -} - -static int _iwl_mld_change_link_in_fw(struct iwl_mld *mld, - struct ieee80211_bss_conf *link, - enum ieee80211_sta_rx_bandwidth bw, - u32 changes) +int +iwl_mld_change_link_in_fw(struct iwl_mld *mld, struct ieee80211_bss_conf *link, + u32 changes) { struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link); struct ieee80211_vif *vif = link->vif; @@ -318,9 +300,6 @@ static int _iwl_mld_change_link_in_fw(struct iwl_mld *mld, cmd.bi = cpu_to_le32(link->beacon_int); cmd.dtim_interval = cpu_to_le32(link->beacon_int * link->dtim_period); - if (changes & LINK_CONTEXT_MODIFY_BANDWIDTH) - cmd.modify_bandwidth = iwl_mld_sta_rx_bw_to_fw(bw); - /* Configure HE parameters only if HE is supported, and only after * the parameters are set in mac80211 (meaning after assoc) */ @@ -382,29 +361,11 @@ send_cmd: return iwl_mld_send_link_cmd(mld, &cmd, FW_CTXT_ACTION_MODIFY); } -int iwl_mld_change_link_in_fw(struct iwl_mld *mld, - struct ieee80211_bss_conf *link, - u32 changes) -{ - if (WARN_ON(changes & LINK_CONTEXT_MODIFY_BANDWIDTH)) - changes &= ~LINK_CONTEXT_MODIFY_BANDWIDTH; - - return _iwl_mld_change_link_in_fw(mld, link, 0, changes); -} - -int iwl_mld_change_link_omi_bw(struct iwl_mld *mld, - struct ieee80211_bss_conf *link, - enum ieee80211_sta_rx_bandwidth bw) -{ - return _iwl_mld_change_link_in_fw(mld, link, bw, - LINK_CONTEXT_MODIFY_BANDWIDTH); -} - int iwl_mld_activate_link(struct iwl_mld *mld, struct ieee80211_bss_conf *link) { struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link); - struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(mld_link->vif); + struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(link->vif); int ret; lockdep_assert_wiphy(mld->wiphy); @@ -412,7 +373,6 @@ int iwl_mld_activate_link(struct iwl_mld *mld, if (WARN_ON(!mld_link || mld_link->active)) return -EINVAL; - mld_link->rx_omi.exit_ts = jiffies; mld_link->active = true; ret = iwl_mld_change_link_in_fw(mld, link, @@ -477,319 +437,6 @@ iwl_mld_rm_link_from_fw(struct iwl_mld *mld, struct ieee80211_bss_conf *link) iwl_mld_send_link_cmd(mld, &cmd, FW_CTXT_ACTION_REMOVE); } -static void iwl_mld_omi_bw_update(struct iwl_mld *mld, - struct ieee80211_bss_conf *link_conf, - struct iwl_mld_link *mld_link, - struct ieee80211_link_sta *link_sta, - enum ieee80211_sta_rx_bandwidth bw, - bool ap_update) -{ - enum ieee80211_sta_rx_bandwidth apply_bw; - - mld_link->rx_omi.desired_bw = bw; - - /* Can't update OMI while already in progress, desired_bw was - * set so on FW notification the worker will see the change - * and apply new the new desired bw. - */ - if (mld_link->rx_omi.bw_in_progress) - return; - - if (bw == IEEE80211_STA_RX_BW_MAX) - apply_bw = ieee80211_chan_width_to_rx_bw(link_conf->chanreq.oper.width); - else - apply_bw = bw; - - if (!ap_update) { - /* The update isn't due to AP tracking after leaving OMI, - * where the AP could increase BW and then we must tell - * it that we can do the increased BW as well, if we did - * update the chandef. - * In this case, if we want MAX, then we will need to send - * a new OMI to the AP if it increases its own bandwidth as - * we can (due to internal and FW limitations, and being - * worried the AP might break) only send to what we're doing - * at the moment. In this case, set last_max_bw; otherwise - * if we really want to decrease our bandwidth set it to 0 - * to indicate no updates are needed if the AP changes. - */ - if (bw != IEEE80211_STA_RX_BW_MAX) - mld_link->rx_omi.last_max_bw = apply_bw; - else - mld_link->rx_omi.last_max_bw = 0; - } else { - /* Otherwise, if we're already trying to do maximum and - * the AP is changing, set last_max_bw to the new max the - * AP is using, we'll only get to this code path if the - * new bandwidth of the AP is bigger than what we sent it - * previously. This avoids repeatedly sending updates if - * it changes bandwidth, only doing it once on an increase. - */ - mld_link->rx_omi.last_max_bw = apply_bw; - } - - if (ieee80211_prepare_rx_omi_bw(link_sta, bw)) { - mld_link->rx_omi.bw_in_progress = apply_bw; - iwl_mld_change_link_omi_bw(mld, link_conf, apply_bw); - } -} - -static void iwl_mld_omi_bw_finished_work(struct wiphy *wiphy, - struct wiphy_work *work) -{ - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); - struct iwl_mld_link *mld_link = - container_of(work, typeof(*mld_link), rx_omi.finished_work.work); - enum ieee80211_sta_rx_bandwidth desired_bw, switched_to_bw; - struct ieee80211_vif *vif = mld_link->vif; - struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); - struct ieee80211_bss_conf *link_conf; - struct ieee80211_link_sta *link_sta; - - if (!mld_vif->ap_sta) - return; - - link_sta = wiphy_dereference(mld->wiphy, - mld_vif->ap_sta->link[mld_link->link_id]); - if (WARN_ON_ONCE(!link_sta)) - return; - - link_conf = link_conf_dereference_protected(vif, link_sta->link_id); - if (WARN_ON_ONCE(!link_conf)) - return; - - if (WARN_ON(!mld_link->rx_omi.bw_in_progress)) - return; - - desired_bw = mld_link->rx_omi.desired_bw; - switched_to_bw = mld_link->rx_omi.bw_in_progress; - - ieee80211_finalize_rx_omi_bw(link_sta); - mld_link->rx_omi.bw_in_progress = 0; - - if (desired_bw != switched_to_bw) - iwl_mld_omi_bw_update(mld, link_conf, mld_link, link_sta, - desired_bw, false); -} - -static struct ieee80211_vif * -iwl_mld_get_omi_bw_reduction_pointers(struct iwl_mld *mld, - struct ieee80211_link_sta **link_sta, - struct iwl_mld_link **mld_link) -{ - struct iwl_mld_vif *mld_vif; - struct ieee80211_vif *vif; - int n_link_stas = 0; - - *link_sta = NULL; - - if (mld->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_SC) - return NULL; - - vif = iwl_mld_get_bss_vif(mld); - if (!vif) - return NULL; - - for (int i = 0; i < ARRAY_SIZE(mld->fw_id_to_link_sta); i++) { - struct ieee80211_link_sta *tmp; - - tmp = wiphy_dereference(mld->wiphy, mld->fw_id_to_link_sta[i]); - if (IS_ERR_OR_NULL(tmp)) - continue; - - n_link_stas++; - *link_sta = tmp; - } - - /* can't do anything if we have TDLS peers or EMLSR */ - if (n_link_stas != 1) - return NULL; - - mld_vif = iwl_mld_vif_from_mac80211(vif); - *mld_link = iwl_mld_link_dereference_check(mld_vif, - (*link_sta)->link_id); - if (WARN_ON(!*mld_link)) - return NULL; - - return vif; -} - -void iwl_mld_omi_ap_changed_bw(struct iwl_mld *mld, - struct ieee80211_bss_conf *link_conf, - enum ieee80211_sta_rx_bandwidth bw) -{ - struct ieee80211_link_sta *link_sta; - struct iwl_mld_link *mld_link; - struct ieee80211_vif *vif; - - vif = iwl_mld_get_omi_bw_reduction_pointers(mld, &link_sta, &mld_link); - if (!vif) - return; - - if (WARN_ON(link_conf->vif != vif)) - return; - - /* This is 0 if we requested an OMI BW reduction and don't want to - * be sending an OMI when the AP's bandwidth changes. - */ - if (!mld_link->rx_omi.last_max_bw) - return; - - /* We only need to tell the AP if it increases BW over what we last - * told it we were using, if it reduces then our last OMI to it will - * not get used anyway (e.g. we said we want 160 but it's doing 80.) - */ - if (bw < mld_link->rx_omi.last_max_bw) - return; - - iwl_mld_omi_bw_update(mld, link_conf, mld_link, link_sta, bw, true); -} - -void iwl_mld_handle_omi_status_notif(struct iwl_mld *mld, - struct iwl_rx_packet *pkt) -{ - const struct iwl_omi_send_status_notif *notif = (const void *)pkt->data; - struct ieee80211_link_sta *link_sta; - struct iwl_mld_link *mld_link; - struct iwl_mld_vif *mld_vif; - struct ieee80211_vif *vif; - u32 sta_id; - - sta_id = le32_to_cpu(notif->sta_id); - - if (IWL_FW_CHECK(mld, sta_id >= mld->fw->ucode_capa.num_stations, - "Invalid station %d\n", sta_id)) - return; - - link_sta = wiphy_dereference(mld->wiphy, mld->fw_id_to_link_sta[sta_id]); - if (IWL_FW_CHECK(mld, !link_sta, "Station does not exist\n")) - return; - - vif = iwl_mld_sta_from_mac80211(link_sta->sta)->vif; - mld_vif = iwl_mld_vif_from_mac80211(vif); - - mld_link = iwl_mld_link_dereference_check(mld_vif, link_sta->link_id); - if (WARN(!mld_link, "Link %d does not exist\n", link_sta->link_id)) - return; - - if (IWL_FW_CHECK(mld, !mld_link->rx_omi.bw_in_progress, - "OMI notification when not requested\n")) - return; - - wiphy_delayed_work_queue(mld->hw->wiphy, - &mld_link->rx_omi.finished_work, - msecs_to_jiffies(IWL_MLD_OMI_AP_SETTLE_DELAY)); -} - -void iwl_mld_leave_omi_bw_reduction(struct iwl_mld *mld) -{ - struct ieee80211_bss_conf *link_conf; - struct ieee80211_link_sta *link_sta; - struct iwl_mld_link *mld_link; - struct ieee80211_vif *vif; - - vif = iwl_mld_get_omi_bw_reduction_pointers(mld, &link_sta, &mld_link); - if (!vif) - return; - - link_conf = link_conf_dereference_protected(vif, link_sta->link_id); - if (WARN_ON_ONCE(!link_conf)) - return; - - if (!link_conf->he_support) - return; - - mld_link->rx_omi.exit_ts = jiffies; - - iwl_mld_omi_bw_update(mld, link_conf, mld_link, link_sta, - IEEE80211_STA_RX_BW_MAX, false); -} - -void iwl_mld_check_omi_bw_reduction(struct iwl_mld *mld) -{ - enum ieee80211_sta_rx_bandwidth bw = IEEE80211_STA_RX_BW_MAX; - struct ieee80211_chanctx_conf *chanctx; - struct ieee80211_bss_conf *link_conf; - struct ieee80211_link_sta *link_sta; - struct cfg80211_chan_def chandef; - struct iwl_mld_link *mld_link; - struct iwl_mld_vif *mld_vif; - struct ieee80211_vif *vif; - struct iwl_mld_phy *phy; - u16 punctured; - int exit_thr; - - /* not allowed in CAM mode */ - if (iwlmld_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) - return; - - /* must have one BSS connection (no P2P), no TDLS, nor EMLSR */ - vif = iwl_mld_get_omi_bw_reduction_pointers(mld, &link_sta, &mld_link); - if (!vif) - return; - - link_conf = link_conf_dereference_protected(vif, link_sta->link_id); - if (WARN_ON_ONCE(!link_conf)) - return; - - if (!link_conf->he_support) - return; - - chanctx = wiphy_dereference(mld->wiphy, mld_link->chan_ctx); - if (WARN_ON(!chanctx)) - return; - - mld_vif = iwl_mld_vif_from_mac80211(vif); - if (!mld_vif->authorized) - goto apply; - - /* must not be in low-latency mode */ - if (iwl_mld_vif_low_latency(mld_vif)) - goto apply; - - chandef = link_conf->chanreq.oper; - - switch (chandef.width) { - case NL80211_CHAN_WIDTH_320: - exit_thr = IWL_MLD_OMI_EXIT_CHAN_LOAD_320; - break; - case NL80211_CHAN_WIDTH_160: - exit_thr = IWL_MLD_OMI_EXIT_CHAN_LOAD_160; - break; - default: - /* since we reduce to 80 MHz, must have more to start with */ - goto apply; - } - - /* not to be done if primary 80 MHz is punctured */ - if (cfg80211_chandef_primary(&chandef, NL80211_CHAN_WIDTH_80, - &punctured) < 0 || - punctured != 0) - goto apply; - - phy = iwl_mld_phy_from_mac80211(chanctx); - - if (phy->channel_load_by_us > exit_thr) { - /* send OMI for max bandwidth */ - goto apply; - } - - if (phy->channel_load_by_us > IWL_MLD_OMI_ENTER_CHAN_LOAD) { - /* no changes between enter/exit thresholds */ - return; - } - - if (time_is_after_jiffies(mld_link->rx_omi.exit_ts + - msecs_to_jiffies(IWL_MLD_OMI_EXIT_PROTECTION))) - return; - - /* reduce bandwidth to 80 MHz to save power */ - bw = IEEE80211_STA_RX_BW_80; -apply: - iwl_mld_omi_bw_update(mld, link_conf, mld_link, link_sta, bw, false); -} - IWL_MLD_ALLOC_FN(link, bss_conf) /* Constructor function for struct iwl_mld_link */ @@ -797,18 +444,12 @@ static int iwl_mld_init_link(struct iwl_mld *mld, struct ieee80211_bss_conf *link, struct iwl_mld_link *mld_link) { - mld_link->vif = link->vif; - mld_link->link_id = link->link_id; mld_link->average_beacon_energy = 0; iwl_mld_init_internal_sta(&mld_link->bcast_sta); iwl_mld_init_internal_sta(&mld_link->mcast_sta); iwl_mld_init_internal_sta(&mld_link->mon_sta); - if (!mld->fw_status.in_hw_restart) - wiphy_delayed_work_init(&mld_link->rx_omi.finished_work, - iwl_mld_omi_bw_finished_work); - return iwl_mld_allocate_link_fw_id(mld, &mld_link->fw_id, link); } @@ -872,8 +513,6 @@ void iwl_mld_remove_link(struct iwl_mld *mld, RCU_INIT_POINTER(mld_vif->link[bss_conf->link_id], NULL); - wiphy_delayed_work_cancel(mld->wiphy, &link->rx_omi.finished_work); - if (WARN_ON(link->fw_id >= mld->fw->ucode_capa.num_links)) return; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.h b/drivers/net/wireless/intel/iwlwifi/mld/link.h index 881823be07ba..cad2c9426349 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/link.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/link.h @@ -36,11 +36,9 @@ struct iwl_probe_resp_data { * @he_ru_2mhz_block: 26-tone RU OFDMA transmissions should be blocked. * @igtk: fw can only have one IGTK at a time, whereas mac80211 can have two. * This tracks the one IGTK that currently exists in FW. - * @vif: the vif this link belongs to * @bcast_sta: station used for broadcast packets. Used in AP, GO and IBSS. * @mcast_sta: station used for multicast packets. Used in AP, GO and IBSS. * @mon_sta: station used for TX injection in monitor interface. - * @link_id: over the air link ID * @average_beacon_energy: average beacon energy for beacons received during * client connections * @ap_early_keys: The firmware cannot install keys before bcast/mcast STAs, @@ -49,14 +47,6 @@ struct iwl_probe_resp_data { * @silent_deactivation: next deactivation needs to be silent. * @probe_resp_data: data from FW notification to store NOA related data to be * inserted into probe response. - * @rx_omi: data for BW reduction with OMI - * @rx_omi.bw_in_progress: update is in progress (indicates target BW) - * @rx_omi.exit_ts: timestamp of last exit - * @rx_omi.finished_work: work for the delayed reaction to the firmware saying - * the change was applied, and for then applying a new mode if it was - * updated while waiting for firmware/AP settle delay. - * @rx_omi.desired_bw: desired bandwidth - * @rx_omi.last_max_bw: last maximum BW used by firmware, for AP BW changes */ struct iwl_mld_link { struct rcu_head rcu_head; @@ -71,19 +61,9 @@ struct iwl_mld_link { struct ieee80211_key_conf *igtk; ); /* And here fields that survive a fw restart */ - struct ieee80211_vif *vif; struct iwl_mld_int_sta bcast_sta; struct iwl_mld_int_sta mcast_sta; struct iwl_mld_int_sta mon_sta; - u8 link_id; - - struct { - struct wiphy_delayed_work finished_work; - unsigned long exit_ts; - enum ieee80211_sta_rx_bandwidth bw_in_progress, - desired_bw, - last_max_bw; - } rx_omi; /* we can only have 2 GTK + 2 IGTK + 2 BIGTK active at a time */ struct ieee80211_key_conf *ap_early_keys[6]; @@ -123,9 +103,6 @@ int iwl_mld_activate_link(struct iwl_mld *mld, struct ieee80211_bss_conf *link); void iwl_mld_deactivate_link(struct iwl_mld *mld, struct ieee80211_bss_conf *link); -int iwl_mld_change_link_omi_bw(struct iwl_mld *mld, - struct ieee80211_bss_conf *link, - enum ieee80211_sta_rx_bandwidth bw); int iwl_mld_change_link_in_fw(struct iwl_mld *mld, struct ieee80211_bss_conf *link, u32 changes); void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld, @@ -145,13 +122,6 @@ unsigned int iwl_mld_get_chan_load(struct iwl_mld *mld, int iwl_mld_get_chan_load_by_others(struct iwl_mld *mld, struct ieee80211_bss_conf *link_conf, bool expect_active_link); -void iwl_mld_handle_omi_status_notif(struct iwl_mld *mld, - struct iwl_rx_packet *pkt); -void iwl_mld_leave_omi_bw_reduction(struct iwl_mld *mld); -void iwl_mld_check_omi_bw_reduction(struct iwl_mld *mld); -void iwl_mld_omi_ap_changed_bw(struct iwl_mld *mld, - struct ieee80211_bss_conf *link_conf, - enum ieee80211_sta_rx_bandwidth bw); void iwl_mld_handle_beacon_filter_notif(struct iwl_mld *mld, struct iwl_rx_packet *pkt); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/low_latency.c b/drivers/net/wireless/intel/iwlwifi/mld/low_latency.c index f7faa87b8ba6..23362867b400 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/low_latency.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/low_latency.c @@ -224,9 +224,6 @@ void iwl_mld_vif_update_low_latency(struct iwl_mld *mld, return; } - if (low_latency) - iwl_mld_leave_omi_bw_reduction(mld); - if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_P2P_CLIENT) return; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 3ea6d4c1b779..b0bd01914a91 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -1015,8 +1015,6 @@ int iwl_mld_assign_vif_chanctx(struct ieee80211_hw *hw, if (n_active > 1) { struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); - iwl_mld_leave_omi_bw_reduction(mld); - /* Indicate to mac80211 that EML is enabled */ vif->driver_flags |= IEEE80211_VIF_EML_ACTIVE; mld_vif->emlsr.last_entry_ts = jiffies; @@ -1212,20 +1210,6 @@ iwl_mld_mac80211_link_info_changed_sta(struct iwl_mld *mld, if (changes & (BSS_CHANGED_CQM | BSS_CHANGED_BEACON_INFO)) iwl_mld_enable_beacon_filter(mld, link_conf, false); - /* If we have used OMI before to reduce bandwidth to 80 MHz and then - * increased to 160 MHz again, and then the AP changes to 320 MHz, it - * will think that we're limited to 160 MHz right now. Update it by - * requesting a new OMI bandwidth. - */ - if (changes & BSS_CHANGED_BANDWIDTH) { - enum ieee80211_sta_rx_bandwidth bw; - - bw = ieee80211_chan_width_to_rx_bw(link_conf->chanreq.oper.width); - - iwl_mld_omi_ap_changed_bw(mld, link_conf, bw); - - } - if (changes & BSS_CHANGED_BANDWIDTH) iwl_mld_retry_emlsr(mld, vif); } @@ -1428,30 +1412,6 @@ iwl_mld_mac80211_sched_scan_stop(struct ieee80211_hw *hw, return iwl_mld_scan_stop(mld, IWL_MLD_SCAN_SCHED, false); } -static void -iwl_mld_restart_complete_vif(void *data, u8 *mac, struct ieee80211_vif *vif) -{ - struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); - struct ieee80211_bss_conf *link_conf; - struct iwl_mld *mld = data; - int link_id; - - for_each_vif_active_link(vif, link_conf, link_id) { - enum ieee80211_sta_rx_bandwidth bw; - struct iwl_mld_link *mld_link; - - mld_link = wiphy_dereference(mld->wiphy, - mld_vif->link[link_id]); - - if (WARN_ON_ONCE(!mld_link)) - continue; - - bw = mld_link->rx_omi.bw_in_progress; - if (bw) - iwl_mld_change_link_omi_bw(mld, link_conf, bw); - } -} - static void iwl_mld_mac80211_reconfig_complete(struct ieee80211_hw *hw, enum ieee80211_reconfig_type reconfig_type) @@ -1462,11 +1422,6 @@ iwl_mld_mac80211_reconfig_complete(struct ieee80211_hw *hw, case IEEE80211_RECONFIG_TYPE_RESTART: mld->fw_status.in_hw_restart = false; iwl_mld_send_recovery_cmd(mld, ERROR_RECOVERY_END_OF_RECOVERY); - - ieee80211_iterate_interfaces(mld->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mld_restart_complete_vif, mld); - iwl_trans_finish_sw_reset(mld->trans); /* no need to lock, adding in parallel would schedule too */ if (!list_empty(&mld->txqs_to_add)) @@ -1690,18 +1645,6 @@ static int iwl_mld_move_sta_state_up(struct iwl_mld *mld, return -EBUSY; } - /* - * If this is the first STA (i.e. the AP) it won't do - * anything, otherwise must leave for any new STA on - * any other interface, or for TDLS, etc. - * Need to call this _before_ adding the STA so it can - * look up the one STA to use to ask mac80211 to leave - * OMI; in the unlikely event that adding the new STA - * then fails we'll just re-enter OMI later (via the - * statistics notification handling.) - */ - iwl_mld_leave_omi_bw_reduction(mld); - ret = iwl_mld_add_sta(mld, sta, vif, STATION_TYPE_PEER); if (ret) return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.c b/drivers/net/wireless/intel/iwlwifi/mld/mld.c index e78e7a4f39d1..7b46ccc306ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.c @@ -251,7 +251,6 @@ static const struct iwl_hcmd_names iwl_mld_data_path_names[] = { HCMD_NAME(TLC_MNG_CONFIG_CMD), HCMD_NAME(RX_BAID_ALLOCATION_CONFIG_CMD), HCMD_NAME(SCD_QUEUE_CONFIG_CMD), - HCMD_NAME(OMI_SEND_STATUS_NOTIF), HCMD_NAME(ESR_MODE_NOTIF), HCMD_NAME(MONITOR_NOTIF), HCMD_NAME(TLC_MNG_UPDATE_NOTIF), diff --git a/drivers/net/wireless/intel/iwlwifi/mld/notif.c b/drivers/net/wireless/intel/iwlwifi/mld/notif.c index e8f10e8145f9..f17aeca4fae6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/notif.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/notif.c @@ -78,13 +78,6 @@ static bool iwl_mld_cancel_##name##_notif(struct iwl_mld *mld, \ u8: (notif)->id_member); \ } -static bool iwl_mld_always_cancel(struct iwl_mld *mld, - struct iwl_rx_packet *pkt, - u32 obj_id) -{ - return true; -} - /* Currently only defined for the RX_HANDLER_SIZES options. Use this for * notifications that belong to a specific object, and that should be * canceled when the object is removed @@ -350,8 +343,6 @@ CMD_VERSIONS(time_msmt_notif, CMD_VER_ENTRY(1, iwl_time_msmt_notify)) CMD_VERSIONS(time_sync_confirm_notif, CMD_VER_ENTRY(1, iwl_time_msmt_cfm_notify)) -CMD_VERSIONS(omi_status_notif, - CMD_VER_ENTRY(2, iwl_omi_send_status_notif)) CMD_VERSIONS(ftm_resp_notif, CMD_VER_ENTRY(10, iwl_tof_range_rsp_ntfy)) CMD_VERSIONS(beacon_filter_notif, CMD_VER_ENTRY(2, iwl_beacon_filter_notif)) @@ -369,7 +360,6 @@ DEFINE_SIMPLE_CANCELLATION(probe_resp_data, iwl_probe_resp_data_notif, mac_id) DEFINE_SIMPLE_CANCELLATION(uapsd_misbehaving_ap, iwl_uapsd_misbehaving_ap_notif, mac_id) -#define iwl_mld_cancel_omi_status_notif iwl_mld_always_cancel DEFINE_SIMPLE_CANCELLATION(ftm_resp, iwl_tof_range_rsp_ntfy, request_id) DEFINE_SIMPLE_CANCELLATION(beacon_filter, iwl_beacon_filter_notif, link_id) @@ -466,8 +456,6 @@ const struct iwl_rx_handler iwl_mld_rx_handlers[] = { RX_HANDLER_NO_OBJECT(LEGACY_GROUP, WNM_80211V_TIMING_MEASUREMENT_CONFIRM_NOTIFICATION, time_sync_confirm_notif, RX_HANDLER_ASYNC) - RX_HANDLER_OF_LINK(DATA_PATH_GROUP, OMI_SEND_STATUS_NOTIF, - omi_status_notif) RX_HANDLER_OF_LINK(DATA_PATH_GROUP, BEACON_FILTER_IN_NOTIF, beacon_filter_notif) RX_HANDLER_OF_FTM_REQ(LOCATION_GROUP, TOF_RANGE_RESPONSE_NOTIF, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/stats.c b/drivers/net/wireless/intel/iwlwifi/mld/stats.c index f633cb1cf510..cbc64db5eab6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/stats.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/stats.c @@ -508,8 +508,6 @@ void iwl_mld_handle_stats_oper_notif(struct iwl_mld *mld, iwl_mld_process_per_link_stats(mld, stats->per_link, curr_ts_usec); iwl_mld_process_per_sta_stats(mld, stats->per_sta); iwl_mld_process_per_phy_stats(mld, stats->per_phy); - - iwl_mld_check_omi_bw_reduction(mld); } void iwl_mld_handle_stats_oper_part1_notif(struct iwl_mld *mld, From bc404dfddbf6817cae9b170c34556dc72ea975e5 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 23 Jul 2025 09:45:11 +0300 Subject: [PATCH 188/199] wifi: iwlwifi: mld: decode EOF bit for AMPDUs Only the EOF bit handling for single frames was ported to the MLD driver. The code to handle AMPDUs correctly was forgotten. Add it back so that the bit is reported in the radiotap headers again. Fixes: d1e879ec600f ("wifi: iwlwifi: add iwlmld sub-driver") Signed-off-by: Benjamin Berg Reviewed-by: Daniel Gabay Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250723094230.195be86372d5.I4db4abf348f7b6dfc75f869770dd77655a204bc7@changeid --- drivers/net/wireless/intel/iwlwifi/mld/rx.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/rx.c b/drivers/net/wireless/intel/iwlwifi/mld/rx.c index 3d19cec3f696..b6dedd1ecd4d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/rx.c @@ -1089,6 +1089,15 @@ static void iwl_mld_rx_eht(struct iwl_mld *mld, struct sk_buff *skb, rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; } + /* update aggregation data for monitor sake on default queue */ + if (!queue && (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) && + (phy_info & IWL_RX_MPDU_PHY_AMPDU) && phy_data->first_subframe) { + rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; + if (phy_data->data0 & + cpu_to_le32(IWL_RX_PHY_DATA0_EHT_DELIM_EOF)) + rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; + } + if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) iwl_mld_decode_eht_phy_data(mld, phy_data, rx_status, eht, usig); From 170db5f873850a04a8eafd3401b2ea36adb20cea Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 23 Jul 2025 09:45:12 +0300 Subject: [PATCH 189/199] wifi: iwlwifi: mld: use spec link id and not FW link id In missed beacon handling, we compare the FW link id to the bss_param_ch_cnt_link_id, which is a spec link id. Fix it. Reviewed-by: Somashekhar Puttagangaiah Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250723094230.2104f8cac836.I25ed77c2b87bde82a9153e2aa26e09b8a42f6ee3@changeid --- drivers/net/wireless/intel/iwlwifi/mld/link.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.c b/drivers/net/wireless/intel/iwlwifi/mld/link.c index ca5e73cfe36e..782fc41aa1c3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/link.c @@ -524,21 +524,23 @@ void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld, { const struct iwl_missed_beacons_notif *notif = (const void *)pkt->data; union iwl_dbg_tlv_tp_data tp_data = { .fw_pkt = pkt }; - u32 link_id = le32_to_cpu(notif->link_id); + u32 fw_link_id = le32_to_cpu(notif->link_id); u32 missed_bcon = le32_to_cpu(notif->consec_missed_beacons); u32 missed_bcon_since_rx = le32_to_cpu(notif->consec_missed_beacons_since_last_rx); u32 scnd_lnk_bcn_lost = le32_to_cpu(notif->consec_missed_beacons_other_link); struct ieee80211_bss_conf *link_conf = - iwl_mld_fw_id_to_link_conf(mld, link_id); + iwl_mld_fw_id_to_link_conf(mld, fw_link_id); u32 bss_param_ch_cnt_link_id; struct ieee80211_vif *vif; + u8 link_id; if (WARN_ON(!link_conf)) return; vif = link_conf->vif; + link_id = link_conf->link_id; bss_param_ch_cnt_link_id = link_conf->bss_param_ch_cnt_link_id; IWL_DEBUG_INFO(mld, @@ -550,7 +552,7 @@ void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld, mld->trans->dbg.dump_file_name_ext_valid = true; snprintf(mld->trans->dbg.dump_file_name_ext, IWL_FW_INI_MAX_NAME, - "LinkId_%d_MacType_%d", link_id, + "LinkId_%d_MacType_%d", fw_link_id, iwl_mld_mac80211_iftype_to_fw(vif)); iwl_dbg_tlv_time_point(&mld->fwrt, From 3a805afaea9a13f9b5a027efaf17b0138f4abb04 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 23 Jul 2025 09:45:13 +0300 Subject: [PATCH 190/199] wifi: iwlwifi: don't export symbols that we shouldn't Functions that are not called from the opmodes shouldn't be exported. Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250723094230.97b80d0d00b3.Ib8abe63c9b25ef1e4ae1bc167cb23fe34bb3682a@changeid --- drivers/net/wireless/intel/iwlwifi/iwl-io.c | 6 ------ drivers/net/wireless/intel/iwlwifi/iwl-trans.c | 16 ---------------- 2 files changed, 22 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.c b/drivers/net/wireless/intel/iwlwifi/iwl-io.c index ad857a05d3c3..5e483a55a4ba 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.c @@ -75,7 +75,6 @@ u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg) /* return as if we have a HW timeout/failure */ return 0x5a5a5a5a; } -IWL_EXPORT_SYMBOL(iwl_read_direct32); void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value) { @@ -93,7 +92,6 @@ void iwl_write_direct64(struct iwl_trans *trans, u64 reg, u64 value) iwl_trans_release_nic_access(trans); } } -IWL_EXPORT_SYMBOL(iwl_write_direct64); int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask, int timeout) @@ -109,7 +107,6 @@ int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask, return -ETIMEDOUT; } -IWL_EXPORT_SYMBOL(iwl_poll_direct_bit); u32 iwl_read_prph_no_grab(struct iwl_trans *trans, u32 ofs) { @@ -117,14 +114,12 @@ u32 iwl_read_prph_no_grab(struct iwl_trans *trans, u32 ofs) trace_iwlwifi_dev_ioread_prph32(trans->dev, ofs, val); return val; } -IWL_EXPORT_SYMBOL(iwl_read_prph_no_grab); void iwl_write_prph_no_grab(struct iwl_trans *trans, u32 ofs, u32 val) { trace_iwlwifi_dev_iowrite_prph32(trans->dev, ofs, val); iwl_trans_write_prph(trans, ofs, val); } -IWL_EXPORT_SYMBOL(iwl_write_prph_no_grab); void iwl_write_prph64_no_grab(struct iwl_trans *trans, u64 ofs, u64 val) { @@ -132,7 +127,6 @@ void iwl_write_prph64_no_grab(struct iwl_trans *trans, u64 ofs, u64 val) iwl_write_prph_no_grab(trans, ofs, val & 0xffffffff); iwl_write_prph_no_grab(trans, ofs + 4, val >> 32); } -IWL_EXPORT_SYMBOL(iwl_write_prph64_no_grab); u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs) { diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c index 810923053053..3694b41d6621 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c @@ -437,31 +437,26 @@ void iwl_trans_write8(struct iwl_trans *trans, u32 ofs, u8 val) { iwl_trans_pcie_write8(trans, ofs, val); } -IWL_EXPORT_SYMBOL(iwl_trans_write8); void iwl_trans_write32(struct iwl_trans *trans, u32 ofs, u32 val) { iwl_trans_pcie_write32(trans, ofs, val); } -IWL_EXPORT_SYMBOL(iwl_trans_write32); u32 iwl_trans_read32(struct iwl_trans *trans, u32 ofs) { return iwl_trans_pcie_read32(trans, ofs); } -IWL_EXPORT_SYMBOL(iwl_trans_read32); u32 iwl_trans_read_prph(struct iwl_trans *trans, u32 ofs) { return iwl_trans_pcie_read_prph(trans, ofs); } -IWL_EXPORT_SYMBOL(iwl_trans_read_prph); void iwl_trans_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) { return iwl_trans_pcie_write_prph(trans, ofs, val); } -IWL_EXPORT_SYMBOL(iwl_trans_write_prph); int iwl_trans_read_mem(struct iwl_trans *trans, u32 addr, void *buf, int dwords) @@ -502,7 +497,6 @@ int iwl_trans_sw_reset(struct iwl_trans *trans) { return iwl_trans_pcie_sw_reset(trans, true); } -IWL_EXPORT_SYMBOL(iwl_trans_sw_reset); struct iwl_trans_dump_data * iwl_trans_dump_data(struct iwl_trans *trans, u32 dump_mask, @@ -512,7 +506,6 @@ iwl_trans_dump_data(struct iwl_trans *trans, u32 dump_mask, return iwl_trans_pcie_dump_data(trans, dump_mask, sanitize_ops, sanitize_ctx); } -IWL_EXPORT_SYMBOL(iwl_trans_dump_data); int iwl_trans_d3_suspend(struct iwl_trans *trans, bool test, bool reset) { @@ -548,20 +541,17 @@ void iwl_trans_interrupts(struct iwl_trans *trans, bool enable) { iwl_trans_pci_interrupts(trans, enable); } -IWL_EXPORT_SYMBOL(iwl_trans_interrupts); void iwl_trans_sync_nmi(struct iwl_trans *trans) { iwl_trans_pcie_sync_nmi(trans); } -IWL_EXPORT_SYMBOL(iwl_trans_sync_nmi); int iwl_trans_write_imr_mem(struct iwl_trans *trans, u32 dst_addr, u64 src_addr, u32 byte_cnt) { return iwl_trans_pcie_copy_imr(trans, dst_addr, src_addr, byte_cnt); } -IWL_EXPORT_SYMBOL(iwl_trans_write_imr_mem); void iwl_trans_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value) @@ -575,7 +565,6 @@ int iwl_trans_read_config32(struct iwl_trans *trans, u32 ofs, { return iwl_trans_pcie_read_config32(trans, ofs, val); } -IWL_EXPORT_SYMBOL(iwl_trans_read_config32); bool _iwl_trans_grab_nic_access(struct iwl_trans *trans) { @@ -771,7 +760,6 @@ void iwl_trans_debugfs_cleanup(struct iwl_trans *trans) { iwl_trans_pcie_debugfs_cleanup(trans); } -IWL_EXPORT_SYMBOL(iwl_trans_debugfs_cleanup); #endif void iwl_trans_set_q_ptrs(struct iwl_trans *trans, int queue, int ptr) @@ -809,7 +797,6 @@ int iwl_trans_get_rxq_dma_data(struct iwl_trans *trans, int queue, { return iwl_trans_pcie_rxq_dma_data(trans, queue, data); } -IWL_EXPORT_SYMBOL(iwl_trans_get_rxq_dma_data); int iwl_trans_load_pnvm(struct iwl_trans *trans, const struct iwl_pnvm_image *pnvm_data, @@ -824,7 +811,6 @@ void iwl_trans_set_pnvm(struct iwl_trans *trans, { iwl_trans_pcie_ctx_info_v2_set_pnvm(trans, capa); } -IWL_EXPORT_SYMBOL(iwl_trans_set_pnvm); int iwl_trans_load_reduce_power(struct iwl_trans *trans, const struct iwl_pnvm_image *payloads, @@ -833,11 +819,9 @@ int iwl_trans_load_reduce_power(struct iwl_trans *trans, return iwl_trans_pcie_ctx_info_v2_load_reduce_power(trans, payloads, capa); } -IWL_EXPORT_SYMBOL(iwl_trans_load_reduce_power); void iwl_trans_set_reduce_power(struct iwl_trans *trans, const struct iwl_ucode_capabilities *capa) { iwl_trans_pcie_ctx_info_v2_set_reduce_power(trans, capa); } -IWL_EXPORT_SYMBOL(iwl_trans_set_reduce_power); From 343c906522ac93855a76e53b5ad924c2ad55b4b3 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 23 Jul 2025 09:45:14 +0300 Subject: [PATCH 191/199] wifi: iwlwifi: check validity of the FW API range We assume that iwl_mac_cfg and iwl_rf_cfg instances has either both ucode_api_min and ucode_api_max set, or neither. Validate this assumption with a Kunit test. Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250723094230.66502f3f4345.I661f347d3bb29994d8b2ec1d3f31f3383422d68a@changeid --- .../wireless/intel/iwlwifi/tests/devinfo.c | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c b/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c index 4d660cef3de9..c31bbd4e7a4a 100644 --- a/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c +++ b/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c @@ -238,6 +238,33 @@ static void devinfo_no_mac_cfg_dups(struct kunit *test) } } +static void devinfo_api_range(struct kunit *test) +{ + /* Check that all iwl_mac_cfg's have either both min and max set, or neither */ + for (int i = 0; iwl_hw_card_ids[i].vendor; i++) { + const struct iwl_mac_cfg *mac_cfg = + (void *)iwl_hw_card_ids[i].driver_data; + const struct iwl_family_base_params *base = mac_cfg->base; + + KUNIT_EXPECT_EQ_MSG(test, !!base->ucode_api_min, + !!base->ucode_api_max, + "%ps: ucode_api_min (%u) and ucode_api_min (%u) should be both set or neither.\n", + base, base->ucode_api_min, + base->ucode_api_max); + } + + /* Check the same for the iwl_rf_cfg's */ + for (int i = 0; i < iwl_dev_info_table_size; i++) { + const struct iwl_rf_cfg *rf_cfg = iwl_dev_info_table[i].cfg; + + KUNIT_EXPECT_EQ_MSG(test, !!rf_cfg->ucode_api_min, + !!rf_cfg->ucode_api_max, + "%ps: ucode_api_min (%u) and ucode_api_min (%u) should be both set or neither.\n", + rf_cfg, rf_cfg->ucode_api_min, + rf_cfg->ucode_api_max); + } +} + static struct kunit_case devinfo_test_cases[] = { KUNIT_CASE(devinfo_table_order), KUNIT_CASE(devinfo_discrete_match), @@ -248,6 +275,7 @@ static struct kunit_case devinfo_test_cases[] = { KUNIT_CASE(devinfo_check_killer_subdev), KUNIT_CASE(devinfo_pci_ids), KUNIT_CASE(devinfo_no_mac_cfg_dups), + KUNIT_CASE(devinfo_api_range), {} }; From da75f183fea01f2c9f1382655b366ed017891e4e Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 23 Jul 2025 09:45:15 +0300 Subject: [PATCH 192/199] wifi: iwlwifi: Revert "wifi: iwlwifi: remove support of several iwl_ppag_table_cmd versions" It turns out that version 6 is still needed. This change will be brought back once the FW that supports version 6 will no longer be supported. This reverts commit 24bc49d158c7 ("wifi: iwlwifi: remove support of several iwl_ppag_table_cmd versions") Link: https://patch.msgid.link/20250723064515.2084903-2-miriam.rachel.korenblit@intel.com Signed-off-by: Miri Korenblit --- .../net/wireless/intel/iwlwifi/fw/api/power.h | 20 +++++++++++++++---- .../wireless/intel/iwlwifi/fw/regulatory.c | 20 +++++++++++++------ 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h index ab84aac6605d..786b3bf4b448 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h @@ -571,7 +571,8 @@ enum iwl_ppag_flags { /** * union iwl_ppag_table_cmd - union for all versions of PPAG command * @v1: command version 1 structure. - * @v2: command version 5 structure. + * @v2: command version from 2 to 6 are same structure as v2. + * but has a different format of the flags bitmap * @v3: command version 7 structure. * @v1.flags: values from &enum iwl_ppag_flags * @v1.gain: table of antenna gain values per chain and sub-band @@ -592,7 +593,9 @@ union iwl_ppag_table_cmd { __le32 flags; s8 gain[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V2]; s8 reserved[2]; - } __packed v2; /* PER_PLAT_ANTENNA_GAIN_CMD_API_S_VER_5 */ + } __packed v2; /* PER_PLAT_ANTENNA_GAIN_CMD_API_S_VER_2, VER3, VER4, + * VER5, VER6 + */ struct { struct bios_value_u32 ppag_config_info; s8 gain[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V2]; @@ -600,11 +603,20 @@ union iwl_ppag_table_cmd { } __packed v3; /* PER_PLAT_ANTENNA_GAIN_CMD_API_S_VER_7 */ } __packed; -#define IWL_PPAG_CMD_V1_MASK (IWL_PPAG_ETSI_MASK | IWL_PPAG_CHINA_MASK) -#define IWL_PPAG_CMD_V5_MASK (IWL_PPAG_CMD_V1_MASK | \ +#define IWL_PPAG_CMD_V4_MASK (IWL_PPAG_ETSI_MASK | IWL_PPAG_CHINA_MASK) +#define IWL_PPAG_CMD_V5_MASK (IWL_PPAG_CMD_V4_MASK | \ IWL_PPAG_ETSI_LPI_UHB_MASK | \ IWL_PPAG_USA_LPI_UHB_MASK) +#define IWL_PPAG_CMD_V6_MASK (IWL_PPAG_CMD_V5_MASK | \ + IWL_PPAG_ETSI_VLP_UHB_MASK | \ + IWL_PPAG_ETSI_SP_UHB_MASK | \ + IWL_PPAG_USA_VLP_UHB_MASK | \ + IWL_PPAG_USA_SP_UHB_MASK | \ + IWL_PPAG_CANADA_LPI_UHB_MASK | \ + IWL_PPAG_CANADA_VLP_UHB_MASK | \ + IWL_PPAG_CANADA_SP_UHB_MASK) + #define MCC_TO_SAR_OFFSET_TABLE_ROW_SIZE 26 #define MCC_TO_SAR_OFFSET_TABLE_COL_SIZE 13 diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index 80d8373fccfc..3d6d1a85bb51 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -344,18 +344,18 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, num_sub_bands = IWL_NUM_SUB_BANDS_V1; gain = cmd->v1.gain[0]; *cmd_size = sizeof(cmd->v1); - cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags & IWL_PPAG_CMD_V1_MASK); + cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags); if (fwrt->ppag_bios_rev >= 1) { /* in this case FW supports revision 0 */ IWL_DEBUG_RADIO(fwrt, "PPAG table rev is %d, send truncated table\n", fwrt->ppag_bios_rev); } - } else if (cmd_ver == 5) { + } else if (cmd_ver >= 2 && cmd_ver <= 6) { num_sub_bands = IWL_NUM_SUB_BANDS_V2; gain = cmd->v2.gain[0]; *cmd_size = sizeof(cmd->v2); - cmd->v2.flags = cpu_to_le32(fwrt->ppag_flags & IWL_PPAG_CMD_V5_MASK); + cmd->v2.flags = cpu_to_le32(fwrt->ppag_flags); if (fwrt->ppag_bios_rev == 0) { /* in this case FW supports revisions 1,2 or 3 */ IWL_DEBUG_RADIO(fwrt, @@ -378,9 +378,17 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, "PPAG MODE bits were read from bios: %d\n", fwrt->ppag_flags); - if (cmd_ver == 1 && - !fw_has_capa(&fwrt->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) { + if (cmd_ver == 6) + cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V6_MASK); + else if (cmd_ver == 5) + cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V5_MASK); + else if (cmd_ver < 5) + cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V4_MASK); + + if ((cmd_ver == 1 && + !fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) || + (cmd_ver == 2 && fwrt->ppag_bios_rev >= 2)) { cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK); IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n"); } else { From 9edf3f855bca60a3634131e09582ee477199af2a Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 26 Jun 2025 15:08:10 +0100 Subject: [PATCH 193/199] wifi: brcm80211: Remove unused functions This is a subset of unused functions in bcrmsmac phy_cmn.c, They're unused since the original 2010 commit a9533e7ea3c4 ("Staging: Add initial release of brcm80211 - Broadcom 802.11n wireless LAN driver.") Remove them. Then remove two more functions in phy_n.c that were only used by the ones just removed. Signed-off-by: Dr. David Alan Gilbert Acked-by: Arend van Spriel > Link: https://patch.msgid.link/20250626140812.56700-2-linux@treblig.org Signed-off-by: Johannes Berg --- .../broadcom/brcm80211/brcmsmac/phy/phy_cmn.c | 128 ------------------ .../broadcom/brcm80211/brcmsmac/phy/phy_hal.h | 11 -- .../broadcom/brcm80211/brcmsmac/phy/phy_int.h | 8 -- .../broadcom/brcm80211/brcmsmac/phy/phy_n.c | 19 --- 4 files changed, 166 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c index c3d7aa570b4e..2dca926acac6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c @@ -2555,27 +2555,6 @@ end: return rssi; } -void wlc_phy_freqtrack_start(struct brcms_phy_pub *pih) -{ - return; -} - -void wlc_phy_freqtrack_end(struct brcms_phy_pub *pih) -{ - return; -} - -void wlc_phy_set_deaf(struct brcms_phy_pub *ppi, bool user_flag) -{ - struct brcms_phy *pi; - pi = (struct brcms_phy *) ppi; - - if (ISLCNPHY(pi)) - wlc_lcnphy_deaf_mode(pi, true); - else if (ISNPHY(pi)) - wlc_nphy_deaf_mode(pi, true); -} - void wlc_phy_watchdog(struct brcms_phy_pub *pih) { struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); @@ -2636,28 +2615,6 @@ void wlc_phy_watchdog(struct brcms_phy_pub *pih) } } -void wlc_phy_BSSinit(struct brcms_phy_pub *pih, bool bonlyap, int rssi) -{ - struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); - uint i; - uint k; - - for (i = 0; i < MA_WINDOW_SZ; i++) - pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff); - if (ISLCNPHY(pi)) { - for (i = 0; i < MA_WINDOW_SZ; i++) - pi->sh->phy_noise_window[i] = - PHY_NOISE_FIXED_VAL_LCNPHY; - } - pi->sh->phy_noise_index = 0; - - for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) { - for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++) - pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY; - } - pi->nphy_noise_index = 0; -} - void wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag) { @@ -2812,14 +2769,6 @@ void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain) pi->pubpi.phy_corenum = (u8)hweight8(pi->sh->phyrxchain); } -void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, u8 *rxchain) -{ - struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); - - *txchain = pi->sh->phytxchain; - *rxchain = pi->sh->phyrxchain; -} - u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih) { s16 nphy_currtemp; @@ -2852,89 +2801,12 @@ u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih) return active_bitmap; } -s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, u16 chanspec) -{ - struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); - u8 siso_mcs_id, cdd_mcs_id; - - siso_mcs_id = - (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO : - TXP_FIRST_MCS_20_SISO; - cdd_mcs_id = - (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD : - TXP_FIRST_MCS_20_CDD; - - if (pi->tx_power_target[siso_mcs_id] > - (pi->tx_power_target[cdd_mcs_id] + 12)) - return PHY_TXC1_MODE_SISO; - else - return PHY_TXC1_MODE_CDD; -} - const u8 *wlc_phy_get_ofdm_rate_lookup(void) { return ofdm_rate_lookup; } -void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode) -{ - if ((pi->sh->chip == BCMA_CHIP_ID_BCM4313) && - (pi->sh->boardflags & BFL_FEM)) { - if (mode) { - u16 txant = 0; - txant = wlapi_bmac_get_txant(pi->sh->physhim); - if (txant == 1) { - mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2); - - mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2); - - } - - bcma_chipco_gpio_control(&pi->d11core->bus->drv_cc, - 0x0, 0x0); - bcma_chipco_gpio_out(&pi->d11core->bus->drv_cc, - ~0x40, 0x40); - bcma_chipco_gpio_outen(&pi->d11core->bus->drv_cc, - ~0x40, 0x40); - } else { - mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2); - - mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2); - - bcma_chipco_gpio_out(&pi->d11core->bus->drv_cc, - ~0x40, 0x00); - bcma_chipco_gpio_outen(&pi->d11core->bus->drv_cc, - ~0x40, 0x00); - bcma_chipco_gpio_control(&pi->d11core->bus->drv_cc, - 0x0, 0x40); - } - } -} - void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool ldpc) { return; } - -void -wlc_phy_get_pwrdet_offsets(struct brcms_phy *pi, s8 *cckoffset, s8 *ofdmoffset) -{ - *cckoffset = 0; - *ofdmoffset = 0; -} - -s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, u16 chanspec) -{ - - return rssi; -} - -bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *ppi) -{ - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - - if (ISNPHY(pi)) - return wlc_phy_n_txpower_ipa_ison(pi); - else - return false; -} diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h index 1efc92fd1671..8388eea8b17f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h @@ -194,14 +194,9 @@ void wlc_phy_por_inform(struct brcms_phy_pub *ppi); void wlc_phy_noise_sample_intr(struct brcms_phy_pub *ppi); bool wlc_phy_bist_check_phy(struct brcms_phy_pub *ppi); -void wlc_phy_set_deaf(struct brcms_phy_pub *ppi, bool user_flag); - void wlc_phy_switch_radio(struct brcms_phy_pub *ppi, bool on); void wlc_phy_anacore(struct brcms_phy_pub *ppi, bool on); - -void wlc_phy_BSSinit(struct brcms_phy_pub *ppi, bool bonlyap, int rssi); - void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi, bool wide_filter); void wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band, @@ -224,13 +219,10 @@ bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi); void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, bool hwpwrctrl); u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi); u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi); -bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *pih); void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain); void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain); -void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, u8 *rxchain); u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih); -s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, u16 chanspec); void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool val); void wlc_phy_cal_perical(struct brcms_phy_pub *ppi, u8 reason); @@ -257,9 +249,6 @@ void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap); void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end); -void wlc_phy_freqtrack_start(struct brcms_phy_pub *ppi); -void wlc_phy_freqtrack_end(struct brcms_phy_pub *ppi); - const u8 *wlc_phy_get_ofdm_rate_lookup(void); s8 wlc_phy_get_tx_power_offset_by_mcs(struct brcms_phy_pub *ppi, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h index 70a9ec050717..18028f673574 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h @@ -985,7 +985,6 @@ s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode); s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode); void wlc_phy_carrier_suppress_lcnphy(struct brcms_phy *pi); void wlc_lcnphy_crsuprs(struct brcms_phy *pi, int channel); -void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode); void wlc_2064_vco_cal(struct brcms_phy *pi); void wlc_phy_txpower_recalc_target(struct brcms_phy *pi); @@ -1031,7 +1030,6 @@ struct phy_iq_est { }; void wlc_phy_stay_in_carriersearch_nphy(struct brcms_phy *pi, bool enable); -void wlc_nphy_deaf_mode(struct brcms_phy *pi, bool mode); #define wlc_phy_write_table_nphy(pi, pti) \ wlc_phy_write_table(pi, pti, 0x72, 0x74, 0x73) @@ -1115,10 +1113,4 @@ int wlc_phy_rssi_compute_nphy(struct brcms_phy *pi, struct d11rxhdr *rxh); #define NPHY_TESTPATTERN_BPHY_RFCS 1 void wlc_phy_nphy_tkip_rifs_war(struct brcms_phy *pi, u8 rifs); - -void wlc_phy_get_pwrdet_offsets(struct brcms_phy *pi, s8 *cckoffset, - s8 *ofdmoffset); -s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, u16 chanspec); - -bool wlc_phy_n_txpower_ipa_ison(struct brcms_phy *pih); #endif /* _BRCM_PHY_INT_H_ */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c index b679821c7f99..b03d5a1f1a93 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c @@ -19713,11 +19713,6 @@ u8 wlc_phy_rxcore_getstate_nphy(struct brcms_phy_pub *pih) return (u8) rxen_bits; } -bool wlc_phy_n_txpower_ipa_ison(struct brcms_phy *pi) -{ - return PHY_IPA(pi); -} - void wlc_phy_cal_init_nphy(struct brcms_phy *pi) { } @@ -28575,17 +28570,3 @@ void wlc_phy_stay_in_carriersearch_nphy(struct brcms_phy *pi, bool enable) } } } - -void wlc_nphy_deaf_mode(struct brcms_phy *pi, bool mode) -{ - wlapi_suspend_mac_and_wait(pi->sh->physhim); - - if (mode) { - if (pi->nphy_deaf_count == 0) - wlc_phy_stay_in_carriersearch_nphy(pi, true); - } else if (pi->nphy_deaf_count > 0) { - wlc_phy_stay_in_carriersearch_nphy(pi, false); - } - - wlapi_enable_mac(pi->sh->physhim); -} From b83c7f49716b2e04ba525b54cb457259bd6b7ece Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 26 Jun 2025 15:08:11 +0100 Subject: [PATCH 194/199] wifi: brcm80211: Remove more unused functions This is a subset of unused functions in bcrmsmac phy_cmn.c, They're unused since the original 2010 commit a9533e7ea3c4 ("Staging: Add initial release of brcm80211 - Broadcom 802.11n wireless LAN driver.") Remove them. Signed-off-by: Dr. David Alan Gilbert Acked-by: Arend van Spriel > Link: https://patch.msgid.link/20250626140812.56700-3-linux@treblig.org Signed-off-by: Johannes Berg --- .../broadcom/brcm80211/brcmsmac/phy/phy_cmn.c | 186 ------------------ .../broadcom/brcm80211/brcmsmac/phy/phy_hal.h | 12 -- 2 files changed, 198 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c index 2dca926acac6..0dbf239400c3 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c @@ -1308,56 +1308,6 @@ int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, bool *override) return 0; } -void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi, - struct txpwr_limits *txpwr) -{ - bool mac_enabled = false; - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - - memcpy(&pi->tx_user_target[TXP_FIRST_CCK], - &txpwr->cck[0], BRCMS_NUM_RATES_CCK); - - memcpy(&pi->tx_user_target[TXP_FIRST_OFDM], - &txpwr->ofdm[0], BRCMS_NUM_RATES_OFDM); - memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_20_CDD], - &txpwr->ofdm_cdd[0], BRCMS_NUM_RATES_OFDM); - - memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_SISO], - &txpwr->ofdm_40_siso[0], BRCMS_NUM_RATES_OFDM); - memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_CDD], - &txpwr->ofdm_40_cdd[0], BRCMS_NUM_RATES_OFDM); - - memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SISO], - &txpwr->mcs_20_siso[0], BRCMS_NUM_RATES_MCS_1_STREAM); - memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_CDD], - &txpwr->mcs_20_cdd[0], BRCMS_NUM_RATES_MCS_1_STREAM); - memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_STBC], - &txpwr->mcs_20_stbc[0], BRCMS_NUM_RATES_MCS_1_STREAM); - memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SDM], - &txpwr->mcs_20_mimo[0], BRCMS_NUM_RATES_MCS_2_STREAM); - - memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SISO], - &txpwr->mcs_40_siso[0], BRCMS_NUM_RATES_MCS_1_STREAM); - memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_CDD], - &txpwr->mcs_40_cdd[0], BRCMS_NUM_RATES_MCS_1_STREAM); - memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_STBC], - &txpwr->mcs_40_stbc[0], BRCMS_NUM_RATES_MCS_1_STREAM); - memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SDM], - &txpwr->mcs_40_mimo[0], BRCMS_NUM_RATES_MCS_2_STREAM); - - if (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & MCTL_EN_MAC) - mac_enabled = true; - - if (mac_enabled) - wlapi_suspend_mac_and_wait(pi->sh->physhim); - - wlc_phy_txpower_recalc_target(pi); - wlc_phy_cal_txpower_recalc_sw(pi); - - if (mac_enabled) - wlapi_enable_mac(pi->sh->physhim); -} - int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override) { struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); @@ -1441,59 +1391,6 @@ wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint channel, u8 *min_pwr, } } -void -wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi, uint chan, - u8 *max_txpwr, u8 *min_txpwr) -{ - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - u8 tx_pwr_max = 0; - u8 tx_pwr_min = 255; - u8 max_num_rate; - u8 maxtxpwr, mintxpwr, rate, pactrl; - - pactrl = 0; - - max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES : - ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 + - 1) : (TXP_LAST_OFDM + 1); - - for (rate = 0; rate < max_num_rate; rate++) { - - wlc_phy_txpower_sromlimit(ppi, chan, &mintxpwr, &maxtxpwr, - rate); - - maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0; - - maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0; - - tx_pwr_max = max(tx_pwr_max, maxtxpwr); - tx_pwr_min = min(tx_pwr_min, maxtxpwr); - } - *max_txpwr = tx_pwr_max; - *min_txpwr = tx_pwr_min; -} - -void -wlc_phy_txpower_boardlimit_band(struct brcms_phy_pub *ppi, uint bandunit, - s32 *max_pwr, s32 *min_pwr, u32 *step_pwr) -{ - return; -} - -u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi) -{ - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - - return pi->tx_power_min; -} - -u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi) -{ - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - - return pi->tx_power_max; -} - static s8 wlc_phy_env_measure_vbat(struct brcms_phy *pi) { if (ISLCNPHY(pi)) @@ -1797,13 +1694,6 @@ wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi, struct txpwr_limits *txpwr, } } -void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi, u8 txpwr_percent) -{ - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - - pi->txpwr_percent = txpwr_percent; -} - void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap) { struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); @@ -1811,35 +1701,6 @@ void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap) pi->sh->machwcap = machwcap; } -void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end) -{ - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - u16 rxc; - rxc = 0; - - if (start_end == ON) { - if (!ISNPHY(pi)) - return; - - if (NREV_IS(pi->pubpi.phy_rev, 3) - || NREV_IS(pi->pubpi.phy_rev, 4)) { - bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), - 0xa0); - bcma_set16(pi->d11core, D11REGOFFS(phyregdata), - 0x1 << 15); - } - } else { - if (NREV_IS(pi->pubpi.phy_rev, 3) - || NREV_IS(pi->pubpi.phy_rev, 4)) { - bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), - 0xa0); - bcma_write16(pi->d11core, D11REGOFFS(phyregdata), rxc); - } - - wlc_phy_por_inform(ppi); - } -} - void wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr, u16 chanspec) @@ -1940,37 +1801,6 @@ bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi) return pi->hwpwrctrl; } -void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, bool hwpwrctrl) -{ - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - bool suspend; - - if (!pi->hwpwrctrl_capable) - return; - - pi->hwpwrctrl = hwpwrctrl; - pi->nphy_txpwrctrl = hwpwrctrl; - pi->txpwrctrl = hwpwrctrl; - - if (ISNPHY(pi)) { - suspend = (0 == (bcma_read32(pi->d11core, - D11REGOFFS(maccontrol)) & - MCTL_EN_MAC)); - if (!suspend) - wlapi_suspend_mac_and_wait(pi->sh->physhim); - - wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl); - if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) - wlc_phy_txpwr_fixpower_nphy(pi); - else - mod_phy_reg(pi, 0x1e7, (0x7f << 0), - pi->saved_txpwr_idx); - - if (!suspend) - wlapi_enable_mac(pi->sh->physhim); - } -} - void wlc_phy_txpower_ipa_upd(struct brcms_phy *pi) { @@ -2128,13 +1958,6 @@ void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type) pi->antsel_type = antsel_type; } -bool wlc_phy_test_ison(struct brcms_phy_pub *ppi) -{ - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - - return pi->phytest_on; -} - void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val) { struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); @@ -2448,15 +2271,6 @@ done: } -void wlc_phy_noise_sample_request_external(struct brcms_phy_pub *pih) -{ - u8 channel; - - channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih)); - - wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel); -} - static const s8 lcnphy_gain_index_offset_for_pkt_rssi[] = { 8, 8, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h index 8388eea8b17f..1dbec80194a7 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h @@ -205,10 +205,6 @@ u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band); void wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint chan, u8 *_min_, u8 *_max_, int rate); -void wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi, uint chan, - u8 *_max_, u8 *_min_); -void wlc_phy_txpower_boardlimit_band(struct brcms_phy_pub *ppi, uint band, - s32 *, s32 *, u32 *); void wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *, u16 chanspec); int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, bool *override); @@ -216,9 +212,6 @@ int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override); void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi, struct txpwr_limits *); bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi); -void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, bool hwpwrctrl); -u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi); -u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi); void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain); void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain); @@ -226,7 +219,6 @@ u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih); void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool val); void wlc_phy_cal_perical(struct brcms_phy_pub *ppi, u8 reason); -void wlc_phy_noise_sample_request_external(struct brcms_phy_pub *ppi); void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock); void wlc_phy_cal_papd_recal(struct brcms_phy_pub *ppi); @@ -241,14 +233,10 @@ void wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power, uint channel); void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal); -bool wlc_phy_test_ison(struct brcms_phy_pub *ppi); -void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi, u8 txpwr_percent); void wlc_phy_ofdm_rateset_war(struct brcms_phy_pub *pih, bool war); void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih, bool bf_preempt); void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap); -void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end); - const u8 *wlc_phy_get_ofdm_rate_lookup(void); s8 wlc_phy_get_tx_power_offset_by_mcs(struct brcms_phy_pub *ppi, From cb106027444074ed612e45982c32a205697a0381 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 26 Jun 2025 15:08:12 +0100 Subject: [PATCH 195/199] wifi: brcm80211: Remove yet more unused functions This is a subset of unused functions in bcrmsmac phy_cmn.c, They're unused since the original 2010 commit a9533e7ea3c4 ("Staging: Add initial release of brcm80211 - Broadcom 802.11n wireless LAN driver.") Remove them. Signed-off-by: Dr. David Alan Gilbert Acked-by: Arend van Spriel > Link: https://patch.msgid.link/20250626140812.56700-4-linux@treblig.org Signed-off-by: Johannes Berg --- .../broadcom/brcm80211/brcmsmac/phy/phy_cmn.c | 129 ------------------ .../broadcom/brcm80211/brcmsmac/phy/phy_hal.h | 4 - .../broadcom/brcm80211/brcmsmac/phy/phy_int.h | 3 - 3 files changed, 136 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c index 0dbf239400c3..ce6ce2dea39c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c @@ -127,23 +127,6 @@ void wlc_phyreg_exit(struct brcms_phy_pub *pih) wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim); } -void wlc_radioreg_enter(struct brcms_phy_pub *pih) -{ - struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); - wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO); - - udelay(10); -} - -void wlc_radioreg_exit(struct brcms_phy_pub *pih) -{ - struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); - - (void)bcma_read16(pi->d11core, D11REGOFFS(phyversion)); - pi->phy_wreg = 0; - wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, 0); -} - u16 read_radio_reg(struct brcms_phy *pi, u16 addr) { u16 data; @@ -263,11 +246,6 @@ void mod_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val) write_radio_reg(pi, addr, (rval & ~mask) | (val & mask)); } -void write_phy_channel_reg(struct brcms_phy *pi, uint val) -{ - bcma_write16(pi->d11core, D11REGOFFS(phychannel), val); -} - u16 read_phy_reg(struct brcms_phy *pi, u16 addr) { bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr); @@ -692,18 +670,6 @@ void wlc_phy_por_inform(struct brcms_phy_pub *ppi) pi->phy_init_por = true; } -void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock) -{ - struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); - - pi->edcrs_threshold_lock = lock; - - write_phy_reg(pi, 0x22c, 0x46b); - write_phy_reg(pi, 0x22d, 0x46b); - write_phy_reg(pi, 0x22e, 0x3c0); - write_phy_reg(pi, 0x22f, 0x3c0); -} - void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal) { struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); @@ -1083,20 +1049,6 @@ void wlc_phy_mute_upd(struct brcms_phy_pub *pih, bool mute, u32 flags) return; } -void wlc_phy_clear_tssi(struct brcms_phy_pub *pih) -{ - struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); - - if (ISNPHY(pi)) { - return; - } else { - wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_0, NULL_TSSI_W); - wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_1, NULL_TSSI_W); - wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_0, NULL_TSSI_W); - wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_1, NULL_TSSI_W); - } -} - static bool wlc_phy_cal_txpower_recalc_sw(struct brcms_phy *pi) { return false; @@ -1136,13 +1088,6 @@ void wlc_phy_switch_radio(struct brcms_phy_pub *pih, bool on) } } -u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi) -{ - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - - return pi->bw; -} - void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw) { struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); @@ -1182,36 +1127,6 @@ void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, u16 chanspec) } -int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq) -{ - int range = -1; - - if (freq < 2500) - range = WL_CHAN_FREQ_RANGE_2G; - else if (freq <= 5320) - range = WL_CHAN_FREQ_RANGE_5GL; - else if (freq <= 5700) - range = WL_CHAN_FREQ_RANGE_5GM; - else - range = WL_CHAN_FREQ_RANGE_5GH; - - return range; -} - -int wlc_phy_chanspec_bandrange_get(struct brcms_phy *pi, u16 chanspec) -{ - int range = -1; - uint channel = CHSPEC_CHANNEL(chanspec); - uint freq = wlc_phy_channel2freq(channel); - - if (ISNPHY(pi)) - range = wlc_phy_get_chan_freq_range_nphy(pi, channel); - else if (ISLCNPHY(pi)) - range = wlc_phy_chanspec_freq2bandrange_lpssn(freq); - - return range; -} - void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi, bool wide_filter) { @@ -1254,50 +1169,6 @@ wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band, } } -u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band) -{ - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - uint i; - uint channel; - u16 chspec; - - for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) { - channel = chan_info_all[i].chan; - - if (ISNPHY(pi) && pi->bw == WL_CHANSPEC_BW_40) { - uint j; - - for (j = 0; j < ARRAY_SIZE(chan_info_all); j++) { - if (chan_info_all[j].chan == - channel + CH_10MHZ_APART) - break; - } - - if (j == ARRAY_SIZE(chan_info_all)) - continue; - - channel = upper_20_sb(channel); - chspec = channel | WL_CHANSPEC_BW_40 | - WL_CHANSPEC_CTL_SB_LOWER; - if (band == BRCM_BAND_2G) - chspec |= WL_CHANSPEC_BAND_2G; - else - chspec |= WL_CHANSPEC_BAND_5G; - } else - chspec = ch20mhz_chspec(channel); - - if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM) - && (channel <= LAST_REF5_CHANNUM)) - continue; - - if ((band == BRCM_BAND_2G && channel <= CH_MAX_2G_CHANNEL) || - (band == BRCM_BAND_5G && channel > CH_MAX_2G_CHANNEL)) - return chspec; - } - - return (u16) INVCHANSPEC; -} - int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, bool *override) { struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h index 1dbec80194a7..cab08f0669d1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h @@ -186,7 +186,6 @@ void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init); void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, u16 chanspec); u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi); void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi, u16 newch); -u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi); void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw); int wlc_phy_rssi_compute(struct brcms_phy_pub *pih, struct d11rxhdr *rxh); @@ -201,7 +200,6 @@ void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi, bool wide_filter); void wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band, struct brcms_chanvec *channels); -u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band); void wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint chan, u8 *_min_, u8 *_max_, int rate); @@ -219,11 +217,9 @@ u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih); void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool val); void wlc_phy_cal_perical(struct brcms_phy_pub *ppi, u8 reason); -void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock); void wlc_phy_cal_papd_recal(struct brcms_phy_pub *ppi); void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val); -void wlc_phy_clear_tssi(struct brcms_phy_pub *ppi); void wlc_phy_hold_upd(struct brcms_phy_pub *ppi, u32 id, bool val); void wlc_phy_mute_upd(struct brcms_phy_pub *ppi, bool val, u32 flags); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h index 18028f673574..4e80f4d27949 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h @@ -908,8 +908,6 @@ void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val); void wlc_phyreg_enter(struct brcms_phy_pub *pih); void wlc_phyreg_exit(struct brcms_phy_pub *pih); -void wlc_radioreg_enter(struct brcms_phy_pub *pih); -void wlc_radioreg_exit(struct brcms_phy_pub *pih); void wlc_phy_read_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info, @@ -921,7 +919,6 @@ void wlc_phy_table_addr(struct brcms_phy *pi, uint tbl_id, uint tbl_offset, u16 tblAddr, u16 tblDataHi, u16 tblDataLo); void wlc_phy_table_data_write(struct brcms_phy *pi, uint width, u32 val); -void write_phy_channel_reg(struct brcms_phy *pi, uint val); void wlc_phy_txpower_update_shm(struct brcms_phy *pi); u8 wlc_phy_nbits(s32 value); From f2d7c3c380bf0c38c395d50de3a7c1a6275983cb Mon Sep 17 00:00:00 2001 From: Ting-Ying Li Date: Wed, 23 Jul 2025 16:29:17 +0530 Subject: [PATCH 196/199] wifi: brcmfmac: fix EXTSAE WPA3 connection failure due to AUTH TX failure For WPA3-SAE Connection in EXTSAE mode, the userspace daemon is allowed to generate the SAE Auth frames. The driver uses the "mgmt_frame" FW IOVAR to transmit this MGMT frame. Before sending the IOVAR, the Driver is incorrectly treating the channel number read from the FW as a frequency value and again attempts to convert this into a channel number using ieee80211_frequency_to_channel(). This added an invalid channel number as part of the IOVAR request to the FW And some FW which strictly expects a valid channel would return BAD_CHAN error, while failing to transmit the driver requested SAE Auth MGMT frame. Fix this in the CYW vendor specific MGMT TX cfg80211 ops handler, by not treating the channel number read from the FW as frequency value and skip the attempt to convert it again into a channel number. Also fix this in the generic MGMT TX cfg80211 ops handler. Fixes: c2ff8cad6423 ("brcm80211: make mgmt_tx in brcmfmac accept a NULL channel") Fixes: 66f909308a7c ("wifi: brcmfmac: cyw: support external SAE authentication in station mode") Signed-off-by: Ting-Ying Li Signed-off-by: Gokul Sivakumar Acked-by: Arend van Spriel > Link: https://patch.msgid.link/20250723105918.5229-1-gokulkumar.sivakumar@infineon.com Signed-off-by: Johannes Berg --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 30 ++++++++++++------- .../broadcom/brcm80211/brcmfmac/cyw/core.c | 26 +++++++++------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index b8fc387ac361..e12389a2cb47 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -5544,8 +5544,7 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct brcmf_fil_action_frame_le *action_frame; struct brcmf_fil_af_params_le *af_params; bool ack; - s32 chan_nr; - u32 freq; + __le32 hw_ch; brcmf_dbg(TRACE, "Enter\n"); @@ -5606,25 +5605,34 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, /* Add the channel. Use the one specified as parameter if any or * the current one (got from the firmware) otherwise */ - if (chan) - freq = chan->center_freq; - else - brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL, - &freq); - chan_nr = ieee80211_frequency_to_channel(freq); - af_params->channel = cpu_to_le32(chan_nr); + if (chan) { + hw_ch = cpu_to_le32(chan->hw_value); + } else { + err = brcmf_fil_cmd_data_get(vif->ifp, + BRCMF_C_GET_CHANNEL, + &hw_ch, sizeof(hw_ch)); + if (err) { + bphy_err(drvr, + "unable to get current hw channel\n"); + goto free; + } + } + af_params->channel = hw_ch; + af_params->dwell_time = cpu_to_le32(params->wait); memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], le16_to_cpu(action_frame->len)); - brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n", - *cookie, le16_to_cpu(action_frame->len), freq); + brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, channel=%d\n", + *cookie, le16_to_cpu(action_frame->len), + le32_to_cpu(af_params->channel)); ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg), af_params); cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack, GFP_KERNEL); +free: kfree(af_params); } else { brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c index c9537fb597ce..4f0ea4347840 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c @@ -112,8 +112,7 @@ int brcmf_cyw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct brcmf_cfg80211_vif *vif; s32 err = 0; bool ack = false; - s32 chan_nr; - u32 freq; + __le16 hw_ch; struct brcmf_mf_params_le *mf_params; u32 mf_params_len; s32 ready; @@ -143,13 +142,18 @@ int brcmf_cyw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, mf_params->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN); mf_params->frame_control = mgmt->frame_control; - if (chan) - freq = chan->center_freq; - else - brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL, - &freq); - chan_nr = ieee80211_frequency_to_channel(freq); - mf_params->channel = cpu_to_le16(chan_nr); + if (chan) { + hw_ch = cpu_to_le16(chan->hw_value); + } else { + err = brcmf_fil_cmd_data_get(vif->ifp, BRCMF_C_GET_CHANNEL, + &hw_ch, sizeof(hw_ch)); + if (err) { + bphy_err(drvr, "unable to get current hw channel\n"); + goto free; + } + } + mf_params->channel = hw_ch; + memcpy(&mf_params->da[0], &mgmt->da[0], ETH_ALEN); memcpy(&mf_params->bssid[0], &mgmt->bssid[0], ETH_ALEN); mf_params->packet_id = cpu_to_le32(*cookie); @@ -159,7 +163,8 @@ int brcmf_cyw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, brcmf_dbg(TRACE, "Auth frame, cookie=%d, fc=%04x, len=%d, channel=%d\n", le32_to_cpu(mf_params->packet_id), le16_to_cpu(mf_params->frame_control), - le16_to_cpu(mf_params->len), chan_nr); + le16_to_cpu(mf_params->len), + le16_to_cpu(mf_params->channel)); vif->mgmt_tx_id = le32_to_cpu(mf_params->packet_id); set_bit(BRCMF_MGMT_TX_SEND_FRAME, &vif->mgmt_tx_status); @@ -185,6 +190,7 @@ int brcmf_cyw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, tx_status: cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack, GFP_KERNEL); +free: kfree(mf_params); return err; } From 26b1d003c6aac1d6673e735994ee524451d501e4 Mon Sep 17 00:00:00 2001 From: Liu Song Date: Wed, 23 Jul 2025 17:30:04 +0800 Subject: [PATCH 197/199] wifi: brcmsmac: Use str_true_false() helper Remove hard-coded strings by using the str_true_false() helper function. Signed-off-by: Liu Song Acked-by: Arend van Spriel > Link: https://patch.msgid.link/20250723173004776P6QSjcW7NrlpGYLTFM-yP@zte.com.cn Signed-off-by: Johannes Berg --- .../broadcom/brcm80211/brcmsmac/mac80211_if.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c index 8ab452cf48c4..aadcff1e2b5d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include "phy/phy_int.h" @@ -540,13 +541,13 @@ static int brcms_ops_config(struct ieee80211_hw *hw, int radio_idx, conf->listen_interval); } if (changed & IEEE80211_CONF_CHANGE_MONITOR) - brcms_dbg_info(core, "%s: change monitor mode: %s\n", - __func__, conf->flags & IEEE80211_CONF_MONITOR ? - "true" : "false"); + brcms_dbg_info(core, "%s: change monitor mode: %s\n", __func__, + str_true_false(conf->flags & + IEEE80211_CONF_MONITOR)); if (changed & IEEE80211_CONF_CHANGE_PS) brcms_err(core, "%s: change power-save mode: %s (implement)\n", - __func__, conf->flags & IEEE80211_CONF_PS ? - "true" : "false"); + __func__, + str_true_false(conf->flags & IEEE80211_CONF_PS)); if (changed & IEEE80211_CONF_CHANGE_POWER) { err = brcms_c_set_tx_power(wl->wlc, conf->power_level); @@ -697,7 +698,7 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BEACON_ENABLED) { /* Beaconing should be enabled/disabled (beaconing modes) */ brcms_err(core, "%s: Beacon enabled: %s\n", __func__, - info->enable_beacon ? "true" : "false"); + str_true_false(info->enable_beacon)); if (info->enable_beacon && hw->wiphy->flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) { brcms_c_enable_probe_resp(wl->wlc, true); @@ -716,7 +717,7 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_IBSS) { /* IBSS join status changed */ brcms_err(core, "%s: IBSS joined: %s (implement)\n", - __func__, vif->cfg.ibss_joined ? "true" : "false"); + __func__, str_true_false(vif->cfg.ibss_joined)); } if (changed & BSS_CHANGED_ARP_FILTER) { @@ -731,7 +732,7 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw, * Note that it is only ever disabled for station mode. */ brcms_err(core, "%s: qos enabled: %s (implement)\n", - __func__, info->qos ? "true" : "false"); + __func__, str_true_false(info->qos)); } return; } @@ -908,7 +909,7 @@ static void brcms_ops_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct brcms_info *wl = hw->priv; int ret; - no_printk("%s: drop = %s\n", __func__, drop ? "true" : "false"); + no_printk("%s: drop = %s\n", __func__, str_true_false(drop)); ret = wait_event_timeout(wl->tx_flush_wq, brcms_tx_flush_completed(wl), From 41469ff94c052b4900af85f1c62a17aff6236f42 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 23 Jul 2025 15:17:17 -0500 Subject: [PATCH 198/199] wifi: Fix typos Fix typos in comments and error messages. Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250723201741.2908456-1-helgaas@kernel.org Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/hw.h | 8 +++---- drivers/net/wireless/ath/ath5k/reg.h | 2 +- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 6 ++--- .../broadcom/brcm80211/brcmfmac/common.c | 4 ++-- .../broadcom/brcm80211/brcmfmac/common.h | 4 ++-- .../broadcom/brcm80211/brcmfmac/core.h | 2 +- .../broadcom/brcm80211/brcmfmac/p2p.c | 4 ++-- .../net/wireless/intel/iwlegacy/commands.h | 2 +- .../intel/iwlwifi/fw/api/time-event.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 4 ++-- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 6 ++--- drivers/net/wireless/intersil/p54/p54spi.c | 4 ++-- drivers/net/wireless/marvell/libertas/cfg.c | 4 ++-- drivers/net/wireless/marvell/mwifiex/fw.h | 4 ++-- .../net/wireless/ralink/rt2x00/rt2800lib.c | 2 +- .../net/wireless/ralink/rt2x00/rt2x00dev.c | 4 ++-- .../net/wireless/ralink/rt2x00/rt2x00queue.c | 2 +- drivers/net/wireless/realtek/rtl8xxxu/core.c | 2 +- .../wireless/realtek/rtlwifi/rtl8192de/rf.c | 2 +- .../wireless/realtek/rtlwifi/rtl8192se/rf.c | 2 +- .../wireless/realtek/rtlwifi/rtl8821ae/hw.c | 22 +++++++++---------- drivers/net/wireless/ti/wl1251/reg.h | 6 ++--- drivers/net/wireless/ti/wl12xx/reg.h | 6 ++--- drivers/net/wireless/zydas/zd1211rw/zd_usb.c | 2 +- 25 files changed, 55 insertions(+), 55 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index fec56b916497..da71dce9babf 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -473,8 +473,8 @@ enum ath10k_hw_cc_wraparound_type { */ ATH10K_HW_CC_WRAP_SHIFTED_ALL = 1, - /* Each hw counter wrapsaround independently. When the - * counter overflows the repestive counter is right shifted + /* Each hw counter wraps around independently. When the + * counter overflows the respective counter is right shifted * by 1, i.e reset to 0x7fffffff, and other counters will be * running unaffected. In this type of wraparound, it should * be possible to report accurate Rx busy time unlike the @@ -837,7 +837,7 @@ ath10k_is_rssi_enable(struct ath10k_hw_params *hw, #define TARGET_10_4_NUM_TDLS_BUFFER_STA 1 #define TARGET_10_4_NUM_TDLS_SLEEP_STA 1 -/* Maximum number of Copy Engine's supported */ +/* Maximum number of Copy Engines supported */ #define CE_COUNT_MAX 12 /* Number of Copy Engines supported */ @@ -1134,7 +1134,7 @@ ath10k_is_rssi_enable(struct ath10k_hw_params *hw, #define RTC_STATE_V_GET(x) (((x) & RTC_STATE_V_MASK) >> RTC_STATE_V_LSB) /* Register definitions for first generation ath10k cards. These cards include - * a mac thich has a register allocation similar to ath9k and at least some + * a mac which has a register allocation similar to ath9k and at least some * registers including the ones relevant for modifying the coverage class are * identical to the ath9k definitions. * These registers are usually managed by the ath10k firmware. However by diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index 0ea1608b47fd..22101c96713f 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -543,7 +543,7 @@ * Queue control unit (QCU) registers [5211+] * * Card has 12 TX Queues but i see that only 0-9 are used (?) - * both in binary HAL (see ah.h) and ar5k. Each queue has it's own + * both in binary HAL (see ah.h) and ar5k. Each queue has its own * TXDP at addresses 0x0800 - 0x082c, a CBR (Constant Bit Rate) * configuration register (0x08c0 - 0x08ec), a ready time configuration * register (0x0900 - 0x092c), a misc configuration register (0x09c0 - diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index e12389a2cb47..8af402555b5e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -3878,7 +3878,7 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, brcmf_dbg(SCAN, "Enter\n"); if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) { - brcmf_dbg(SCAN, "Event data to small. Ignore\n"); + brcmf_dbg(SCAN, "Event data too small. Ignore\n"); return 0; } @@ -4046,7 +4046,7 @@ brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e, brcmf_dbg(SCAN, "Enter\n"); if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) { - brcmf_dbg(SCAN, "Event data to small. Ignore\n"); + brcmf_dbg(SCAN, "Event data too small. Ignore\n"); return 0; } @@ -4308,7 +4308,7 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, brcmf_set_mpc(ifp, 1); } else { - /* Configure WOWL paramaters */ + /* Configure WOWL parameters */ brcmf_configure_wowl(cfg, ifp, wowl); /* Prevent disassociation due to inactivity with keep-alive */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index 75f101622db1..688f16c51319 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -525,7 +525,7 @@ struct brcmf_mp_device *brcmf_get_module_param(struct device *dev, if (!settings) return NULL; - /* start by using the module paramaters */ + /* start by using the module parameters */ settings->p2p_enable = !!brcmf_p2p_enable; settings->feature_disable = brcmf_feature_disable; settings->fcmode = brcmf_fcmode; @@ -612,7 +612,7 @@ static int __init brcmfmac_module_init(void) if (err == -ENODEV) brcmf_dbg(INFO, "No platform data available.\n"); - /* Initialize global module paramaters */ + /* Initialize global module parameters */ brcmf_mp_attach(); /* Continue the initialization by registering the different busses */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h index 2be2986d2110..3bdb6984b2dd 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h @@ -20,7 +20,7 @@ */ /** - * struct brcmf_mp_global_t - Global module paramaters. + * struct brcmf_mp_global_t - Global module parameters. * * @firmware_path: Alternative firmware path. */ @@ -31,7 +31,7 @@ struct brcmf_mp_global_t { extern struct brcmf_mp_global_t brcmf_mp_global; /** - * struct brcmf_mp_device - Device module paramaters. + * struct brcmf_mp_device - Device module parameters. * * @p2p_enable: Legacy P2P0 enable (old wpa_supplicant). * @feature_disable: Feature_disable bitmask. diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h index d53839f855d7..399b6810e394 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h @@ -67,7 +67,7 @@ struct brcmf_ampdu_rx_reorder { /* Forward decls for struct brcmf_pub (see below) */ struct brcmf_proto; /* device communication protocol info */ struct brcmf_fws_info; /* firmware signalling info */ -struct brcmf_mp_device; /* module paramateres, device specific */ +struct brcmf_mp_device; /* module parameters, device specific */ /* * struct brcmf_rev_info diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index 6e0c90f4718b..0dc9d28cd77b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -1403,7 +1403,7 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, u8 action; if (e->datalen < sizeof(*rxframe)) { - brcmf_dbg(SCAN, "Event data to small. Ignore\n"); + brcmf_dbg(SCAN, "Event data too small. Ignore\n"); return 0; } @@ -1949,7 +1949,7 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, e->reason); if (e->datalen < sizeof(*rxframe)) { - brcmf_dbg(SCAN, "Event data to small. Ignore\n"); + brcmf_dbg(SCAN, "Event data too small. Ignore\n"); return 0; } diff --git a/drivers/net/wireless/intel/iwlegacy/commands.h b/drivers/net/wireless/intel/iwlegacy/commands.h index 4a9fa8b83f0f..b61b8f377702 100644 --- a/drivers/net/wireless/intel/iwlegacy/commands.h +++ b/drivers/net/wireless/intel/iwlegacy/commands.h @@ -2229,7 +2229,7 @@ struct il_spectrum_notification { u8 channel; u8 type; /* see enum il_measurement_type */ u8 reserved1; - /* NOTE: cca_ofdm, cca_cck, basic_type, and histogram are only only + /* NOTE: cca_ofdm, cca_cck, basic_type, and histogram are only * valid if applicable for measurement type requested. */ __le32 cca_ofdm; /* cca fraction time in 40Mhz clock periods */ __le32 cca_cck; /* cca fraction time in 44Mhz clock periods */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h index f586379d66dd..46d35ef4751e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h @@ -452,7 +452,7 @@ struct iwl_roc_notif { * listen mode. Will be fragmented. Valid only on the P2P Device MAC. * Valid only on the P2P Device MAC. The firmware will take into account * the duration, the interval and the repetition count. - * @SESSION_PROTECT_CONF_P2P_GO_NEGOTIATION: Schedule the P2P Device to be be + * @SESSION_PROTECT_CONF_P2P_GO_NEGOTIATION: Schedule the P2P Device to be * able to run the GO Negotiation. Will not be fragmented and not * repetitive. Valid only on the P2P Device MAC. Only the duration will * be taken into account. diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index d231819ee4c6..029c846a236f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -250,7 +250,7 @@ static void iwl_mvm_wowlan_get_rsc_tsc_data(struct ieee80211_hw *hw, /* * For non-QoS this relies on the fact that both the uCode and - * mac80211 use TID 0 (as they need to to avoid replay attacks) + * mac80211 use TID 0 (as they need to avoid replay attacks) * for checking the IV in the frames. */ for (i = 0; i < IWL_NUM_RSC; i++) { @@ -386,7 +386,7 @@ static void iwl_mvm_wowlan_get_rsc_v5_data(struct ieee80211_hw *hw, /* * For non-QoS this relies on the fact that both the uCode and - * mac80211 use TID 0 (as they need to to avoid replay attacks) + * mac80211 use TID 0 (as they need to avoid replay attacks) * for checking the IV in the frames. */ for (i = 0; i < IWL_MAX_TID_COUNT; i++) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index ed19b82d14fa..4ad3d32683d8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -3332,7 +3332,7 @@ void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw, * us to stop a hw_scan when it's already stopped. This can * happen, for instance, if we stopped the scan ourselves, * called ieee80211_scan_completed() and the userspace called - * cancel scan scan before ieee80211_scan_work() could run. + * cancel scan before ieee80211_scan_work() could run. * To handle that, simply return if the scan is not running. */ if (mvm->scan_status & IWL_MVM_SCAN_REGULAR) @@ -4345,7 +4345,7 @@ int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw, * us to stop a sched_scan when it's already stopped. This * can happen, for instance, if we stopped the scan ourselves, * called ieee80211_sched_scan_stopped() and the userspace called - * stop sched scan scan before ieee80211_sched_scan_stopped_work() + * stop sched scan before ieee80211_sched_scan_stopped_work() * could run. To handle this, simply return if the scan is * not running. */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 5f6797598998..11c6b86db4ec 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2461,7 +2461,7 @@ void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm, mvmvif->deflink.bcast_sta.tfd_queue_msk &= ~BIT(queue); } -/* Send the FW a request to remove the station from it's internal data +/* Send the FW a request to remove the station from its internal data * structures, but DO NOT remove the entry from the local data structures. */ int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -2524,7 +2524,7 @@ void iwl_mvm_dealloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) } /* - * Send the FW a request to remove the station from it's internal data + * Send the FW a request to remove the station from its internal data * structures, and in addition remove it from the local data structure. */ int iwl_mvm_rm_p2p_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) @@ -2677,7 +2677,7 @@ static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id, } /* - * Send the FW a request to remove the station from it's internal data + * Send the FW a request to remove the station from its internal data * structures, and in addition remove it from the local data structure. */ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) diff --git a/drivers/net/wireless/intersil/p54/p54spi.c b/drivers/net/wireless/intersil/p54/p54spi.c index 27f44a9f0bc1..9d66dcae54e0 100644 --- a/drivers/net/wireless/intersil/p54/p54spi.c +++ b/drivers/net/wireless/intersil/p54/p54spi.c @@ -32,7 +32,7 @@ MODULE_FIRMWARE("3826.eeprom"); /* gpios should be handled in board files and provided via platform data, * but because it's currently impossible for p54spi to have a header file - * in include/linux, let's use module paramaters for now + * in include/linux, let's use module parameters for now */ static int p54spi_gpio_power = 97; @@ -155,7 +155,7 @@ static int p54spi_request_firmware(struct ieee80211_hw *dev) struct p54s_priv *priv = dev->priv; int ret; - /* FIXME: should driver use it's own struct device? */ + /* FIXME: should driver use its own struct device? */ ret = request_firmware(&priv->firmware, "3826.arm", &priv->spi->dev); if (ret < 0) { diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c index 2e2c193716d9..94dd488becaf 100644 --- a/drivers/net/wireless/marvell/libertas/cfg.c +++ b/drivers/net/wireless/marvell/libertas/cfg.c @@ -2146,8 +2146,8 @@ static void lbs_reg_notifier(struct wiphy *wiphy, } /* - * This function get's called after lbs_setup_firmware() determined the - * firmware capabities. So we can setup the wiphy according to our + * This function gets called after lbs_setup_firmware() determined the + * firmware capabilities. So we can setup the wiphy according to our * hardware/firmware. */ int lbs_cfg_register(struct lbs_private *priv) diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index 91458f3bd14a..e9e896606912 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -1119,7 +1119,7 @@ struct host_cmd_ds_get_hw_spec { __le32 fw_cap_info; __le32 dot_11n_dev_cap; u8 dev_mcs_support; - __le16 mp_end_port; /* SDIO only, reserved for other interfacces */ + __le16 mp_end_port; /* SDIO only, reserved for other interfaces */ __le16 mgmt_buf_count; /* mgmt IE buffer count */ __le32 reserved_5; __le32 reserved_6; @@ -1739,7 +1739,7 @@ struct host_cmd_ds_11n_cfg { struct host_cmd_ds_txbuf_cfg { __le16 action; __le16 buff_size; - __le16 mp_end_port; /* SDIO only, reserved for other interfacces */ + __le16 mp_end_port; /* SDIO only, reserved for other interfaces */ __le16 reserved3; } __packed; diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 4b5a7c9b6499..b264ed0af923 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -639,7 +639,7 @@ static bool rt2800_check_firmware_crc(const u8 *data, const size_t len) /* * Use the crc ccitt algorithm. * This will return the same value as the legacy driver which - * used bit ordering reversion on the both the firmware bytes + * used bit ordering reversion on both the firmware bytes * before input input as well as on the final output. * Obviously using crc ccitt directly is much more efficient. */ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c index 432ddfac2c33..7db29e90eb4f 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c @@ -357,7 +357,7 @@ static void rt2x00lib_fill_tx_status(struct rt2x00_dev *rt2x00dev, } /* - * Every single frame has it's own tx status, hence report + * Every single frame has its own tx status, hence report * every frame as ampdu of size 1. * * TODO: if we can find out how many frames were aggregated @@ -496,7 +496,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, /* * If the IV/EIV data was stripped from the frame before it was * passed to the hardware, we should now reinsert it again because - * mac80211 will expect the same data to be present it the + * mac80211 will expect the same data to be present in the * frame as it was passed to us. */ if (rt2x00_has_cap_hw_crypto(rt2x00dev)) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c index 013003777fee..13e48b1e7356 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c @@ -45,7 +45,7 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry, gfp_t gfp) /* * For IV/EIV/ICV assembly we must make sure there is - * at least 8 bytes bytes available in headroom for IV/EIV + * at least 8 bytes available in headroom for IV/EIV * and 8 bytes for ICV data as tailroon. */ if (rt2x00_has_cap_hw_crypto(rt2x00dev)) { diff --git a/drivers/net/wireless/realtek/rtl8xxxu/core.c b/drivers/net/wireless/realtek/rtl8xxxu/core.c index f6f169d2062d..831b5025c634 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/core.c @@ -1163,7 +1163,7 @@ static void rtl8xxxu_start_tx_beacon(struct rtl8xxxu_priv *priv) /* - * The rtl8723a has 3 channel groups for it's efuse settings. It only + * The rtl8723a has 3 channel groups for its efuse settings. It only * supports the 2.4GHz band, so channels 1 - 14: * group 0: channels 1 - 3 * group 1: channels 4 - 9 diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/rf.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/rf.c index eb7d8b070cc7..494b2706abee 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/rf.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/rf.c @@ -84,7 +84,7 @@ bool rtl92d_phy_rf6052_config(struct ieee80211_hw *hw) rtlphy->num_total_rfpath = 2; /* Single phy mode: use radio_a radio_b config path_A path_B */ - /* seperately by MAC0, and MAC1 needn't configure RF; */ + /* separately by MAC0, and MAC1 needn't configure RF; */ /* Dual PHY mode:MAC0 use radio_a config 1st phy path_A, */ /* MAC1 use radio_b config 2nd PHY path_A. */ /* DMDP,MAC0 on G band,MAC1 on A band. */ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/rf.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/rf.c index 5a493602aaf2..17d29249a711 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/rf.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/rf.c @@ -438,7 +438,7 @@ bool rtl92s_phy_rf6052_config(struct ieee80211_hw *hw) rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2, B3WIRE_DATALENGTH, 0x0); - /* Initialize RF fom connfiguration file */ + /* Initialize RF from configuration file */ switch (rfpath) { case RF90_PATH_A: rtstatus = rtl92s_phy_config_rf(hw, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c index a5a34b5edcfd..3a4a33476205 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c @@ -1026,7 +1026,7 @@ static void _rtl8821ae_hw_configure(struct ieee80211_hw *hw) /*Set retry limit*/ rtl_write_word(rtlpriv, REG_RL, 0x0707); - /* Set Data / Response auto rate fallack retry count*/ + /* Set Data / Response auto rate fallback retry count*/ rtl_write_dword(rtlpriv, REG_DARFRC, 0x01000000); rtl_write_dword(rtlpriv, REG_DARFRC + 4, 0x07060504); rtl_write_dword(rtlpriv, REG_RARFRC, 0x01000000); @@ -1295,12 +1295,12 @@ static bool _rtl8821ae_reset_pcie_interface_dma(struct ieee80211_hw *hw, rtl_write_byte(rtlpriv, REG_CR, 0xFF); /* We should init LLT & RQPN and - * prepare Tx/Rx descrptor address later + * prepare Tx/Rx descriptor address later * because MAC function is reset.*/ } /* 7. Restore PCIe autoload down bit */ - /* 8812AE does not has the defination. */ + /* 8812AE does not have the definition. */ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { /* write 0xF8 bit[17] = 1'b1 */ tmp = rtl_read_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL + 2); @@ -1308,7 +1308,7 @@ static bool _rtl8821ae_reset_pcie_interface_dma(struct ieee80211_hw *hw, rtl_write_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL + 2, tmp); } - /* In MAC power on state, BB and RF maybe in ON state, + /* In MAC power on state, BB and RF may be in ON state, * if we release TRx DMA here. * it will cause packets to be started to Tx/Rx, * so we release Tx/Rx DMA later.*/ @@ -1713,7 +1713,7 @@ static bool _rtl8821ae_wowlan_initialize_adapter(struct ieee80211_hw *hw) _rtl8821ae_get_wakeup_reason(hw); /* Patch Pcie Rx DMA hang after S3/S4 several times. - * The root cause has not be found. */ + * The root cause has not been found. */ if (_rtl8821ae_check_pcie_dma_hang(hw)) _rtl8821ae_reset_pcie_interface_dma(hw, true, false); @@ -1926,7 +1926,7 @@ int rtl8821ae_hw_init(struct ieee80211_hw *hw) rtl8821ae_phy_mac_config(hw); /* because last function modify RCR, so we update * rcr var here, or TP will unstable for receive_config - * is wrong, RX RCR_ACRC32 will cause TP unstabel & Rx + * is wrong, RX RCR_ACRC32 will cause TP unstable & Rx * RCR_APP_ICV will cause mac80211 unassoc for cisco 1252 rtlpci->receive_config = rtl_read_dword(rtlpriv, REG_RCR); rtlpci->receive_config &= ~(RCR_ACRC32 | RCR_AICV); @@ -2332,7 +2332,7 @@ void rtl8821ae_card_disable(struct ieee80211_hw *hw) if (_rtl8821ae_dynamic_rqpn(hw, 0xE0, 0x3, 0x80c20d0d)) rtlhal->re_init_llt_table = true; - /* 3 <2> Set Fw releted H2C cmd. */ + /* 3 <2> Set Fw related H2C cmd. */ /* Set WoWLAN related security information. */ rtl8821ae_set_fw_global_info_cmd(hw); @@ -2357,8 +2357,8 @@ void rtl8821ae_card_disable(struct ieee80211_hw *hw) /* 3 <3> Hw Configutations */ - /* Wait untill Rx DMA Finished before host sleep. - * FW Pause Rx DMA may happens when received packet doing dma. + /* Wait until Rx DMA Finished before host sleep. + * FW Pause Rx DMA may happen when received packet doing DMA. */ rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, BIT(2)); @@ -3927,7 +3927,7 @@ void rtl8821ae_resume(struct ieee80211_hw *hw) { } -/* Turn on AAP (RCR:bit 0) for promicuous mode. */ +/* Turn on AAP (RCR:bit 0) for promiscuous mode. */ void rtl8821ae_allow_all_destaddr(struct ieee80211_hw *hw, bool allow_all_da, bool write_into_reg) { @@ -3964,7 +3964,7 @@ void rtl8821ae_add_wowlan_pattern(struct ieee80211_hw *hw, /* RX page size = 128 byte */ offset = MAX_RX_DMA_BUFFER_SIZE_8812 / 128; - /* We should start from the boundry */ + /* We should start from the boundary */ cam_start = offset * 128; /* Enable Rx packet buffer access. */ diff --git a/drivers/net/wireless/ti/wl1251/reg.h b/drivers/net/wireless/ti/wl1251/reg.h index 890176c915ab..bfe35754f33a 100644 --- a/drivers/net/wireless/ti/wl1251/reg.h +++ b/drivers/net/wireless/ti/wl1251/reg.h @@ -205,7 +205,7 @@ enum wl12xx_acx_int_reg { the burst read starts at EEPROM address 0. Otherwise, it starts at the address following the address of the previous access. - TheWlan hardware hardware clears this bit automatically. + TheWlan hardware clears this bit automatically. Default: 0x00000000 *================================================*/ @@ -353,13 +353,13 @@ enum wl12xx_acx_int_reg { loads a single byte of data into the EE_DATA register from the EEPROM location specified in the EE_ADDR register. - The Wlan hardware hardware clears this bit automatically. + The Wlan hardware clears this bit automatically. EE_DATA is valid when this bit is cleared. 0 EE_WRITE - EEPROM Write Request - Setting this bit writes a single byte of data from the EE_DATA register into the EEPROM location specified in the EE_ADDR register. - The Wlan hardware hardware clears this bit automatically. + The Wlan hardware clears this bit automatically. *===============================================*/ #define EE_CTL (REGISTERS_BASE + 0x2000) #define ACX_EE_CTL_REG EE_CTL diff --git a/drivers/net/wireless/ti/wl12xx/reg.h b/drivers/net/wireless/ti/wl12xx/reg.h index 8ff018808020..601305a26141 100644 --- a/drivers/net/wireless/ti/wl12xx/reg.h +++ b/drivers/net/wireless/ti/wl12xx/reg.h @@ -168,7 +168,7 @@ the burst read starts at EEPROM address 0. Otherwise, it starts at the address following the address of the previous access. - TheWlan hardware hardware clears this bit automatically. + TheWlan hardware clears this bit automatically. Default: 0x00000000 *================================================*/ @@ -276,13 +276,13 @@ loads a single byte of data into the EE_DATA register from the EEPROM location specified in the EE_ADDR register. - The Wlan hardware hardware clears this bit automatically. + The Wlan hardware clears this bit automatically. EE_DATA is valid when this bit is cleared. 0 EE_WRITE - EEPROM Write Request - Setting this bit writes a single byte of data from the EE_DATA register into the EEPROM location specified in the EE_ADDR register. - The Wlan hardware hardware clears this bit automatically. + The Wlan hardware clears this bit automatically. *===============================================*/ #define ACX_EE_CTL_REG EE_CTL #define EE_WRITE 0x00000001ul diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c index 9ae10f65f2af..2faa0de2a36e 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c @@ -445,7 +445,7 @@ static void int_urb_complete(struct urb *urb) } if (urb->actual_length < sizeof(hdr)) { - dev_dbg_f(urb_dev(urb), "error: urb %p to small\n", urb); + dev_dbg_f(urb_dev(urb), "error: urb %p too small\n", urb); goto resubmit; } From 55c172c13718b93300d3808b65ec326b5287c766 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 23 Jul 2025 16:12:57 +0200 Subject: [PATCH 199/199] ssb: use new GPIO line value setter callbacks for the second GPIO chip Because the other chip is guarded in an unlikely ifdef, I missed it when converting this driver. Fix it now. Fixes: 757259db79fc ("ssb: use new GPIO line value setter callbacks") Signed-off-by: Bartosz Golaszewski Link: https://patch.msgid.link/20250723141257.51412-1-brgl@bgdev.pl Signed-off-by: Johannes Berg --- drivers/ssb/driver_gpio.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/ssb/driver_gpio.c b/drivers/ssb/driver_gpio.c index 14ad57954a66..e1f5f0a9c8a2 100644 --- a/drivers/ssb/driver_gpio.c +++ b/drivers/ssb/driver_gpio.c @@ -267,12 +267,14 @@ static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned int gpio) return !!ssb_extif_gpio_in(&bus->extif, 1 << gpio); } -static void ssb_gpio_extif_set_value(struct gpio_chip *chip, unsigned int gpio, - int value) +static int ssb_gpio_extif_set_value(struct gpio_chip *chip, unsigned int gpio, + int value) { struct ssb_bus *bus = gpiochip_get_data(chip); ssb_extif_gpio_out(&bus->extif, 1 << gpio, value ? 1 << gpio : 0); + + return 0; } static int ssb_gpio_extif_direction_input(struct gpio_chip *chip, @@ -420,7 +422,7 @@ static int ssb_gpio_extif_init(struct ssb_bus *bus) chip->label = "ssb_extif_gpio"; chip->owner = THIS_MODULE; chip->get = ssb_gpio_extif_get_value; - chip->set = ssb_gpio_extif_set_value; + chip->set_rv = ssb_gpio_extif_set_value; chip->direction_input = ssb_gpio_extif_direction_input; chip->direction_output = ssb_gpio_extif_direction_output; #if IS_ENABLED(CONFIG_SSB_EMBEDDED)