From 4938ba733ee2147724c4b10025fe0d349d3b605f Mon Sep 17 00:00:00 2001 From: Rameshkumar Sundaram Date: Tue, 11 Jun 2024 09:42:31 +0300 Subject: [PATCH 001/204] wifi: ath12k: modify remain on channel for single wiphy When multiple radios are advertised as a single wiphy which supports various bands, vdev creation for the vif is deferred until channel is assigned to it. If a remain on channel (RoC) request is received from mac80211, select the corresponding radio (ar) based on channel and create a vdev on that radio to initiate an RoC scan. Note that on RoC completion this vdev is not deleted. If a new RoC/hw scan request is seen on that same vif for a different band the vdev will be deleted and created on the new radio supporting the request. Also if the RoC scan is requested when the vdev is in started state, no switching to new radio is allowed and RoC request can be accepted only on channels within same radio. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Rameshkumar Sundaram Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240528082739.1226758-1-quic_ramess@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 68 ++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 509c02bffdae..d1529612fddd 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -3372,7 +3372,7 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, static struct ath12k* ath12k_mac_select_scan_device(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_scan_request *req) + u32 center_freq) { struct ath12k_hw *ah = hw->priv; enum nl80211_band band; @@ -3389,9 +3389,9 @@ ath12k_mac_select_scan_device(struct ieee80211_hw *hw, * split the hw request and perform multiple scans */ - if (req->req.channels[0]->center_freq < ATH12K_MIN_5G_FREQ) + if (center_freq < ATH12K_MIN_5G_FREQ) band = NL80211_BAND_2GHZ; - else if (req->req.channels[0]->center_freq < ATH12K_MIN_6G_FREQ) + else if (center_freq < ATH12K_MIN_6G_FREQ) band = NL80211_BAND_5GHZ; else band = NL80211_BAND_6GHZ; @@ -3591,7 +3591,7 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, /* Since the targeted scan device could depend on the frequency * requested in the hw_req, select the corresponding radio */ - ar = ath12k_mac_select_scan_device(hw, vif, hw_req); + ar = ath12k_mac_select_scan_device(hw, vif, hw_req->req.channels[0]->center_freq); if (!ar) return -EINVAL; @@ -8416,12 +8416,68 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k_wmi_scan_req_arg arg; - struct ath12k *ar; + struct ath12k *ar, *prev_ar; u32 scan_time_msec; + bool create = true; int ret; - ar = ath12k_ah_to_ar(ah, 0); + if (ah->num_radio == 1) { + WARN_ON(!arvif->is_created); + ar = ath12k_ah_to_ar(ah, 0); + goto scan; + } + ar = ath12k_mac_select_scan_device(hw, vif, chan->center_freq); + if (!ar) + return -EINVAL; + + /* If the vif is already assigned to a specific vdev of an ar, + * check whether its already started, vdev which is started + * are not allowed to switch to a new radio. + * If the vdev is not started, but was earlier created on a + * different ar, delete that vdev and create a new one. We don't + * delete at the scan stop as an optimization to avoid redundant + * delete-create vdev's for the same ar, in case the request is + * always on the same band for the vif + */ + if (arvif->is_created) { + if (WARN_ON(!arvif->ar)) + return -EINVAL; + + if (ar != arvif->ar && arvif->is_started) + return -EBUSY; + + if (ar != arvif->ar) { + /* backup the previously used ar ptr, since the vdev delete + * would assign the arvif->ar to NULL after the call + */ + prev_ar = arvif->ar; + mutex_lock(&prev_ar->conf_mutex); + ret = ath12k_mac_vdev_delete(prev_ar, vif); + mutex_unlock(&prev_ar->conf_mutex); + if (ret) { + ath12k_warn(prev_ar->ab, + "unable to delete scan vdev for roc: %d\n", + ret); + return ret; + } + } else { + create = false; + } + } + + if (create) { + mutex_lock(&ar->conf_mutex); + ret = ath12k_mac_vdev_create(ar, vif); + mutex_unlock(&ar->conf_mutex); + if (ret) { + ath12k_warn(ar->ab, "unable to create scan vdev for roc: %d\n", + ret); + return -EINVAL; + } + } + +scan: mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); From 8b2a12749b08726f006303814ecc1c37024d3617 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 11 Jun 2024 09:42:33 +0300 Subject: [PATCH 002/204] wifi: ath12k: fix ACPI warning when resume Currently ACPI notification handler is installed when driver loads and only gets removed when driver unloads. During resume after firmware is reloaded, ath12k tries to install it by default. Since it is installed already, ACPI subsystem rejects it and returns an error: [ 83.094206] ath12k_pci 0000:03:00.0: failed to install DSM notify callback: 7 Fix it by removing that handler when going to suspend. This also avoid any possible ACPI call to firmware before firmware is reloaded/reinitialized. Note ab->acpi also needs to be cleared in ath12k_acpi_stop() such that we are in a clean state when ACPI structures are reinitialized in ath12k_acpi_start(). Tested-on: WCN7850 HW2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Fixes: 576771c9fa21 ("wifi: ath12k: ACPI TAS support") Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240531024000.9291-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/acpi.c | 2 ++ drivers/net/wireless/ath/ath12k/core.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c index 443ba12e01f3..0555d35aab47 100644 --- a/drivers/net/wireless/ath/ath12k/acpi.c +++ b/drivers/net/wireless/ath/ath12k/acpi.c @@ -391,4 +391,6 @@ void ath12k_acpi_stop(struct ath12k_base *ab) acpi_remove_notify_handler(ACPI_HANDLE(ab->dev), ACPI_DEVICE_NOTIFY, ath12k_acpi_dsm_notify); + + memset(&ab->acpi, 0, sizeof(ab->acpi)); } diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 4c3eab4686c2..da02d3528737 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -83,6 +83,8 @@ int ath12k_core_suspend_late(struct ath12k_base *ab) if (!ab->hw_params->supports_suspend) return -EOPNOTSUPP; + ath12k_acpi_stop(ab); + ath12k_hif_irq_disable(ab); ath12k_hif_ce_irq_disable(ab); From 53d7c99719e29819eaeb9f373d262a6b56ea7cce Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 11 Jun 2024 09:42:33 +0300 Subject: [PATCH 003/204] wifi: ath11k: fix RCU documentation in ath11k_mac_op_ipv6_changed() Current documentation on RCU in ath11k_mac_op_ipv6_changed() says: /* Note: read_lock_bh() calls rcu_read_lock() */ read_lock_bh(&idev->lock); This is wrong because without enabling CONFIG_PREEMPT_RT rcu_read_lock() is not called by read_lock_bh(). The reason why current code works even in a CONFIG_PREEMPT_RT=n kernel is because atomic_notifier_call_chain() already does that for us, see: int atomic_notifier_call_chain() { ... rcu_read_lock(); ret = notifier_call_chain(&nh->head, val, v, -1, NULL); rcu_read_unlock(); ... } and backtrace: ath11k_mac_op_ipv6_changed ieee80211_ifa6_changed notifier_call_chain atomic_notifier_call_chain So update the comment to make it correct. This is found during code review, compile tested only. Fixes: feafe59c8975 ("wifi: ath11k: use RCU when accessing struct inet6_dev::ac_list") Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240531022411.6543-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index a1800c75d32b..29af015a16f9 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -9020,7 +9020,12 @@ static void ath11k_mac_op_ipv6_changed(struct ieee80211_hw *hw, offload = &arvif->arp_ns_offload; count = 0; - /* Note: read_lock_bh() calls rcu_read_lock() */ + /* The _ipv6_changed() is called with RCU lock already held in + * atomic_notifier_call_chain(), so we don't need to call + * rcu_read_lock() again here. But note that with CONFIG_PREEMPT_RT + * enabled, read_lock_bh() also calls rcu_read_lock(). This is OK + * because RCU read critical section is allowed to get nested. + */ read_lock_bh(&idev->lock); memset(offload->ipv6_addr, 0, sizeof(offload->ipv6_addr)); From 65a8368bf34e51b4499205658d7015d40e5a3f80 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 11 Jun 2024 09:42:33 +0300 Subject: [PATCH 004/204] wifi: ath11k: use 'time_left' variable with wait_event_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_event_timeout() causing patterns like: timeout = wait_event_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Fix to the proper variable type 'long' while here. Signed-off-by: Wolfram Sang Signed-off-by: Kalle Valo Link: https://msgid.link/20240603091541.8367-2-wsa+renesas@sang-engineering.com --- drivers/net/wireless/ath/ath11k/qmi.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index aa160e6fe24f..1bc648920ab6 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -2859,7 +2859,7 @@ int ath11k_qmi_firmware_start(struct ath11k_base *ab, int ath11k_qmi_fwreset_from_cold_boot(struct ath11k_base *ab) { - int timeout; + long time_left; if (!ath11k_core_coldboot_cal_support(ab) || ab->hw_params.cbcal_restart_fw == 0) @@ -2867,11 +2867,11 @@ int ath11k_qmi_fwreset_from_cold_boot(struct ath11k_base *ab) ath11k_dbg(ab, ATH11K_DBG_QMI, "wait for cold boot done\n"); - timeout = wait_event_timeout(ab->qmi.cold_boot_waitq, - (ab->qmi.cal_done == 1), - ATH11K_COLD_BOOT_FW_RESET_DELAY); + time_left = wait_event_timeout(ab->qmi.cold_boot_waitq, + (ab->qmi.cal_done == 1), + ATH11K_COLD_BOOT_FW_RESET_DELAY); - if (timeout <= 0) { + if (time_left <= 0) { ath11k_warn(ab, "Coldboot Calibration timed out\n"); return -ETIMEDOUT; } @@ -2886,7 +2886,7 @@ EXPORT_SYMBOL(ath11k_qmi_fwreset_from_cold_boot); static int ath11k_qmi_process_coldboot_calibration(struct ath11k_base *ab) { - int timeout; + long time_left; int ret; ret = ath11k_qmi_wlanfw_mode_send(ab, ATH11K_FIRMWARE_MODE_COLD_BOOT); @@ -2897,10 +2897,10 @@ static int ath11k_qmi_process_coldboot_calibration(struct ath11k_base *ab) ath11k_dbg(ab, ATH11K_DBG_QMI, "Coldboot calibration wait started\n"); - timeout = wait_event_timeout(ab->qmi.cold_boot_waitq, - (ab->qmi.cal_done == 1), - ATH11K_COLD_BOOT_FW_RESET_DELAY); - if (timeout <= 0) { + time_left = wait_event_timeout(ab->qmi.cold_boot_waitq, + (ab->qmi.cal_done == 1), + ATH11K_COLD_BOOT_FW_RESET_DELAY); + if (time_left <= 0) { ath11k_warn(ab, "coldboot calibration timed out\n"); return 0; } From 9e32058ae62f1d8fdf1ee7b177a1307f90335fbd Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 11 Jun 2024 09:42:33 +0300 Subject: [PATCH 005/204] wifi: ath12k: avoid unnecessary MSDU drop in the Rx error process Currently, in the Rx error processing handler, once an MSDU drop is detected, the subsequent MSDUs get unintentionally dropped due to the previous drop flag being retained across all MSDU processing, leading to the discarding of valid MSDUs. To resolve this issue, the drop flag should be reset to false before processing each descriptor. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240604062641.2956288-1-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_rx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index cb1f308f096b..54aea3c22311 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -3402,7 +3402,7 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, struct ath12k *ar; dma_addr_t paddr; bool is_frag; - bool drop = false; + bool drop; int pdev_id; tot_n_bufs_reaped = 0; @@ -3420,7 +3420,9 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, while (budget && (reo_desc = ath12k_hal_srng_dst_get_next_entry(ab, srng))) { + drop = false; ab->soc_stats.err_ring_pkts++; + ret = ath12k_hal_desc_reo_parse_err(ab, reo_desc, &paddr, &desc_bank); if (ret) { From d2b0ca38d362ebf16ca79cd7f309d5bb8b581deb Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 11 Jun 2024 09:42:34 +0300 Subject: [PATCH 006/204] wifi: ath11k: fix wrong handling of CCMP256 and GCMP ciphers Currently for CCMP256, GCMP128 and GCMP256 ciphers, in ath11k_install_key() IEEE80211_KEY_FLAG_GENERATE_IV_MGMT is not set. And in ath11k_mac_mgmt_tx_wmi() a length of IEEE80211_CCMP_MIC_LEN is reserved for all ciphers. This results in unexpected management frame drop in case either of above 3 ciphers is used. The reason is, without IEEE80211_KEY_FLAG_GENERATE_IV_MGMT set, mac80211 will not generate CCMP/GCMP headers in frame for ath11k. Also MIC length reserved is wrong. Such frame is dropped later by hardware: ath11k_pci 0000:5a:00.0: mac tx mgmt frame, buf id 0 ath11k_pci 0000:5a:00.0: mgmt tx compl ev pdev_id 1, desc_id 0, status 1 From user point of view, we have observed very low throughput due to this issue: action frames are all dropped so ADDBA response from DUT never reaches AP. AP can not use aggregation thus throughput is low. Fix this by setting IEEE80211_KEY_FLAG_GENERATE_IV_MGMT flag and by reserving proper MIC length for those ciphers. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30 Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices") Reported-by: Yaroslav Isakov Tested-by: Yaroslav Isakov Closes: https://lore.kernel.org/all/CADS+iDX5=JtJr0apAtAQ02WWBxgOFEv8G063vuGYwDTC8AVZaw@mail.gmail.com Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240605014826.22498-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/dp_rx.c | 3 +-- drivers/net/wireless/ath/ath11k/dp_rx.h | 3 +++ drivers/net/wireless/ath/ath11k/mac.c | 15 +++++++++++---- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 198fb359a688..86485580dd89 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -1877,8 +1877,7 @@ static void ath11k_dp_rx_h_csum_offload(struct ath11k *ar, struct sk_buff *msdu) CHECKSUM_NONE : CHECKSUM_UNNECESSARY; } -static int ath11k_dp_rx_crypto_mic_len(struct ath11k *ar, - enum hal_encrypt_type enctype) +int ath11k_dp_rx_crypto_mic_len(struct ath11k *ar, enum hal_encrypt_type enctype) { switch (enctype) { case HAL_ENCRYPT_TYPE_OPEN: diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.h b/drivers/net/wireless/ath/ath11k/dp_rx.h index 623da3bf9dc8..c322e30caa96 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.h +++ b/drivers/net/wireless/ath/ath11k/dp_rx.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_DP_RX_H #define ATH11K_DP_RX_H @@ -95,4 +96,6 @@ int ath11k_peer_rx_frag_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id int ath11k_dp_rx_pktlog_start(struct ath11k_base *ab); int ath11k_dp_rx_pktlog_stop(struct ath11k_base *ab, bool stop_timer); +int ath11k_dp_rx_crypto_mic_len(struct ath11k *ar, enum hal_encrypt_type enctype); + #endif /* ATH11K_DP_RX_H */ diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 29af015a16f9..bb56160048ba 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -4229,6 +4229,7 @@ static int ath11k_install_key(struct ath11k_vif *arvif, switch (key->cipher) { case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_CCMP_256: arg.key_cipher = WMI_CIPHER_AES_CCM; /* TODO: Re-check if flag is valid */ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT; @@ -4238,12 +4239,10 @@ static int ath11k_install_key(struct ath11k_vif *arvif, arg.key_txmic_len = 8; arg.key_rxmic_len = 8; break; - case WLAN_CIPHER_SUITE_CCMP_256: - arg.key_cipher = WMI_CIPHER_AES_CCM; - break; case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: arg.key_cipher = WMI_CIPHER_AES_GCM; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT; break; default: ath11k_warn(ar->ab, "cipher %d is not supported\n", key->cipher); @@ -5903,7 +5902,10 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif, { struct ath11k_base *ab = ar->ab; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb); struct ieee80211_tx_info *info; + enum hal_encrypt_type enctype; + unsigned int mic_len; dma_addr_t paddr; int buf_id; int ret; @@ -5927,7 +5929,12 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif, ieee80211_is_deauth(hdr->frame_control) || ieee80211_is_disassoc(hdr->frame_control)) && ieee80211_has_protected(hdr->frame_control)) { - skb_put(skb, IEEE80211_CCMP_MIC_LEN); + if (!(skb_cb->flags & ATH11K_SKB_CIPHER_SET)) + ath11k_warn(ab, "WMI management tx frame without ATH11K_SKB_CIPHER_SET"); + + enctype = ath11k_dp_tx_get_encrypt_type(skb_cb->cipher); + mic_len = ath11k_dp_rx_crypto_mic_len(ar, enctype); + skb_put(skb, mic_len); } } From 8dd65ccbdf91e2fe3ab6e4da158b38f81746c3b4 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Tue, 11 Jun 2024 09:42:32 +0300 Subject: [PATCH 007/204] wifi: ath12k: fix per pdev debugfs registration Function ath12k_debugfs_register() is called once inside the function ath12k_mac_hw_register(). However, with single wiphy model, there could be multiple pdevs registered under single hardware. Hence, need to register debugfs for each one of them. Move the caller inside the loop which iterates over all underlying pdevs. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Fixes: f8bde02a26b9 ("wifi: ath12k: initial debugfs support") Signed-off-by: Aditya Kumar Singh Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240529043043.2488031-2-quic_adisi@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index d1529612fddd..4b71dfbfe728 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -9133,9 +9133,9 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) ath12k_err(ar->ab, "ath12k regd update failed: %d\n", ret); goto err_unregister_hw; } - } - ath12k_debugfs_register(ar); + ath12k_debugfs_register(ar); + } return 0; From 4e1eff38d37a27328251ea47602703b811a028e1 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Tue, 11 Jun 2024 09:42:32 +0300 Subject: [PATCH 008/204] wifi: ath12k: unregister per pdev debugfs During normal de-initialization path or if any error happens while registering the hardware, there is no support to unregister the per pdev debugfs. Add support for the same. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aditya Kumar Singh Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240529043043.2488031-3-quic_adisi@quicinc.com --- drivers/net/wireless/ath/ath12k/debugfs.c | 10 ++++++++++ drivers/net/wireless/ath/ath12k/debugfs.h | 6 +++++- drivers/net/wireless/ath/ath12k/mac.c | 7 ++++++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c index 8d8ba951093b..3b464cd40da6 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs.c +++ b/drivers/net/wireless/ath/ath12k/debugfs.c @@ -88,3 +88,13 @@ void ath12k_debugfs_register(struct ath12k *ar) &fops_simulate_radar); } } + +void ath12k_debugfs_unregister(struct ath12k *ar) +{ + if (!ar->debug.debugfs_pdev) + return; + + /* TODO: Remove symlink under ieee80211/phy* */ + debugfs_remove_recursive(ar->debug.debugfs_pdev); + ar->debug.debugfs_pdev = NULL; +} diff --git a/drivers/net/wireless/ath/ath12k/debugfs.h b/drivers/net/wireless/ath/ath12k/debugfs.h index a62f2a550b23..8d64ba03aa9a 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs.h +++ b/drivers/net/wireless/ath/ath12k/debugfs.h @@ -11,7 +11,7 @@ void ath12k_debugfs_soc_create(struct ath12k_base *ab); void ath12k_debugfs_soc_destroy(struct ath12k_base *ab); void ath12k_debugfs_register(struct ath12k *ar); - +void ath12k_debugfs_unregister(struct ath12k *ar); #else static inline void ath12k_debugfs_soc_create(struct ath12k_base *ab) { @@ -25,6 +25,10 @@ static inline void ath12k_debugfs_register(struct ath12k *ar) { } +static inline void ath12k_debugfs_unregister(struct ath12k *ar) +{ +} + #endif /* CONFIG_ATH12K_DEBUGFS */ #endif /* _ATH12K_DEBUGFS_H_ */ diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 4b71dfbfe728..2259ce22cc8b 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -8892,8 +8892,10 @@ static void ath12k_mac_hw_unregister(struct ath12k_hw *ah) struct ath12k *ar; int i; - for_each_ar(ah, ar, i) + for_each_ar(ah, ar, i) { cancel_work_sync(&ar->regd_update_work); + ath12k_debugfs_unregister(ar); + } ieee80211_unregister_hw(hw); @@ -9140,6 +9142,9 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) return 0; err_unregister_hw: + for_each_ar(ah, ar, i) + ath12k_debugfs_unregister(ar); + ieee80211_unregister_hw(hw); err_free_if_combs: From 5a16da9cfb40d45e797df3ae1523ac64fe0b98ae Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Tue, 11 Jun 2024 09:42:33 +0300 Subject: [PATCH 009/204] wifi: ath12k: handle symlink cleanup for per pdev debugfs dentry Whenever per pdev debugfs directory is created, a symlink to it is also placed in ieee80211/phy* directory. During clean up of per pdev debugfs, this symlink also needs to be cleaned up. Add changes to clean up the symlink whenever the per pdev debugfs is removed. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aditya Kumar Singh Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240529043043.2488031-4-quic_adisi@quicinc.com --- drivers/net/wireless/ath/ath12k/core.h | 1 + drivers/net/wireless/ath/ath12k/debugfs.c | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index d03326a68a9f..b483899ca136 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -474,6 +474,7 @@ struct ath12k_fw_stats { struct ath12k_debug { struct dentry *debugfs_pdev; + struct dentry *debugfs_pdev_symlink; }; struct ath12k_per_peer_tx_stats { diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c index 3b464cd40da6..751a9b04386a 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs.c +++ b/drivers/net/wireless/ath/ath12k/debugfs.c @@ -80,7 +80,9 @@ void ath12k_debugfs_register(struct ath12k *ar) /* Create a symlink under ieee80211/phy* */ scnprintf(buf, sizeof(buf), "../../ath12k/%pd2", ar->debug.debugfs_pdev); - debugfs_create_symlink("ath12k", hw->wiphy->debugfsdir, buf); + ar->debug.debugfs_pdev_symlink = debugfs_create_symlink("ath12k", + hw->wiphy->debugfsdir, + buf); if (ar->mac.sbands[NL80211_BAND_5GHZ].channels) { debugfs_create_file("dfs_simulate_radar", 0200, @@ -94,7 +96,9 @@ void ath12k_debugfs_unregister(struct ath12k *ar) if (!ar->debug.debugfs_pdev) return; - /* TODO: Remove symlink under ieee80211/phy* */ + /* Remove symlink under ieee80211/phy* */ + debugfs_remove(ar->debug.debugfs_pdev_symlink); debugfs_remove_recursive(ar->debug.debugfs_pdev); + ar->debug.debugfs_pdev_symlink = NULL; ar->debug.debugfs_pdev = NULL; } From 3d530eeaf8e79770048e35b1b93f8ffb36a8a133 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 3 Jun 2024 11:15:38 +0200 Subject: [PATCH 010/204] wifi: rtw89: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://msgid.link/20240603091541.8367-6-wsa+renesas@sang-engineering.com --- drivers/net/wireless/realtek/rtw89/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 3e99b63a7995..fe403fb7e8a2 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -4054,15 +4054,15 @@ void rtw89_core_update_beacon_work(struct work_struct *work) int rtw89_wait_for_cond(struct rtw89_wait_info *wait, unsigned int cond) { struct completion *cmpl = &wait->completion; - unsigned long timeout; + unsigned long time_left; unsigned int cur; cur = atomic_cmpxchg(&wait->cond, RTW89_WAIT_COND_IDLE, cond); if (cur != RTW89_WAIT_COND_IDLE) return -EBUSY; - timeout = wait_for_completion_timeout(cmpl, RTW89_WAIT_FOR_COND_TIMEOUT); - if (timeout == 0) { + time_left = wait_for_completion_timeout(cmpl, RTW89_WAIT_FOR_COND_TIMEOUT); + if (time_left == 0) { atomic_set(&wait->cond, RTW89_WAIT_COND_IDLE); return -ETIMEDOUT; } From 5a72e198a6e965eb5c658e63711c889430075839 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 7 Jun 2024 15:06:57 +0800 Subject: [PATCH 011/204] wifi: rtw89: 8852bx: move common code from 8852b to 8852b_common New upcoming chip is RTL8852BE-VT (or RTL8852BTE; 8852BT PCIE interface), which is a variant of 8852B, and many codes excepting to RF calibration can be shared, so move common code to an new kernel module named rtw89_8852b_common.ko. No logic change. Signed-off-by: Ping-Ke Shih Link: https://msgid.link/20240607070659.80263-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/Kconfig | 4 + drivers/net/wireless/realtek/rtw89/Makefile | 3 + drivers/net/wireless/realtek/rtw89/rtw8852b.c | 1691 +--------------- drivers/net/wireless/realtek/rtw89/rtw8852b.h | 122 -- .../wireless/realtek/rtw89/rtw8852b_common.c | 1701 +++++++++++++++++ .../wireless/realtek/rtw89/rtw8852b_common.h | 339 ++++ .../net/wireless/realtek/rtw89/rtw8852b_rfk.c | 19 +- 7 files changed, 2079 insertions(+), 1800 deletions(-) create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852b_common.c create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852b_common.h diff --git a/drivers/net/wireless/realtek/rtw89/Kconfig b/drivers/net/wireless/realtek/rtw89/Kconfig index eaea4eaeb361..3c9f864805b1 100644 --- a/drivers/net/wireless/realtek/rtw89/Kconfig +++ b/drivers/net/wireless/realtek/rtw89/Kconfig @@ -22,6 +22,9 @@ config RTW89_8851B config RTW89_8852A tristate +config RTW89_8852B_COMMON + tristate + config RTW89_8852B tristate @@ -59,6 +62,7 @@ config RTW89_8852BE select RTW89_CORE select RTW89_PCI select RTW89_8852B + select RTW89_8852B_COMMON help Select this option will enable support for 8852BE chipset diff --git a/drivers/net/wireless/realtek/rtw89/Makefile b/drivers/net/wireless/realtek/rtw89/Makefile index 86a553fb0136..688847ce7084 100644 --- a/drivers/net/wireless/realtek/rtw89/Makefile +++ b/drivers/net/wireless/realtek/rtw89/Makefile @@ -39,6 +39,9 @@ rtw89_8852a-objs := rtw8852a.o \ obj-$(CONFIG_RTW89_8852AE) += rtw89_8852ae.o rtw89_8852ae-objs := rtw8852ae.o +obj-$(CONFIG_RTW89_8852B_COMMON) += rtw89_8852b_common.o +rtw89_8852b_common-objs := rtw8852b_common.o + obj-$(CONFIG_RTW89_8852B) += rtw89_8852b.o rtw89_8852b-objs := rtw8852b.o \ rtw8852b_table.o \ diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 517ad1a763fa..381c881fee69 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -8,6 +8,7 @@ #include "phy.h" #include "reg.h" #include "rtw8852b.h" +#include "rtw8852b_common.h" #include "rtw8852b_rfk.h" #include "rtw8852b_table.h" #include "txrx.h" @@ -65,167 +66,6 @@ static const struct rtw89_dle_mem rtw8852b_dle_mem_pcie[] = { NULL}, }; -static const struct rtw89_reg3_def rtw8852b_pmac_ht20_mcs7_tbl[] = { - {0x4580, 0x0000ffff, 0x0}, - {0x4580, 0xffff0000, 0x0}, - {0x4584, 0x0000ffff, 0x0}, - {0x4584, 0xffff0000, 0x0}, - {0x4580, 0x0000ffff, 0x1}, - {0x4578, 0x00ffffff, 0x2018b}, - {0x4570, 0x03ffffff, 0x7}, - {0x4574, 0x03ffffff, 0x32407}, - {0x45b8, 0x00000010, 0x0}, - {0x45b8, 0x00000100, 0x0}, - {0x45b8, 0x00000080, 0x0}, - {0x45b8, 0x00000008, 0x0}, - {0x45a0, 0x0000ff00, 0x0}, - {0x45a0, 0xff000000, 0x1}, - {0x45a4, 0x0000ff00, 0x2}, - {0x45a4, 0xff000000, 0x3}, - {0x45b8, 0x00000020, 0x0}, - {0x4568, 0xe0000000, 0x0}, - {0x45b8, 0x00000002, 0x1}, - {0x456c, 0xe0000000, 0x0}, - {0x45b4, 0x00006000, 0x0}, - {0x45b4, 0x00001800, 0x1}, - {0x45b8, 0x00000040, 0x0}, - {0x45b8, 0x00000004, 0x0}, - {0x45b8, 0x00000200, 0x0}, - {0x4598, 0xf8000000, 0x0}, - {0x45b8, 0x00100000, 0x0}, - {0x45a8, 0x00000fc0, 0x0}, - {0x45b8, 0x00200000, 0x0}, - {0x45b0, 0x00000038, 0x0}, - {0x45b0, 0x000001c0, 0x0}, - {0x45a0, 0x000000ff, 0x0}, - {0x45b8, 0x00400000, 0x0}, - {0x4590, 0x000007ff, 0x0}, - {0x45b0, 0x00000e00, 0x0}, - {0x45ac, 0x0000001f, 0x0}, - {0x45b8, 0x00800000, 0x0}, - {0x45a8, 0x0003f000, 0x0}, - {0x45b8, 0x01000000, 0x0}, - {0x45b0, 0x00007000, 0x0}, - {0x45b0, 0x00038000, 0x0}, - {0x45a0, 0x00ff0000, 0x0}, - {0x45b8, 0x02000000, 0x0}, - {0x4590, 0x003ff800, 0x0}, - {0x45b0, 0x001c0000, 0x0}, - {0x45ac, 0x000003e0, 0x0}, - {0x45b8, 0x04000000, 0x0}, - {0x45a8, 0x00fc0000, 0x0}, - {0x45b8, 0x08000000, 0x0}, - {0x45b0, 0x00e00000, 0x0}, - {0x45b0, 0x07000000, 0x0}, - {0x45a4, 0x000000ff, 0x0}, - {0x45b8, 0x10000000, 0x0}, - {0x4594, 0x000007ff, 0x0}, - {0x45b0, 0x38000000, 0x0}, - {0x45ac, 0x00007c00, 0x0}, - {0x45b8, 0x20000000, 0x0}, - {0x45a8, 0x3f000000, 0x0}, - {0x45b8, 0x40000000, 0x0}, - {0x45b4, 0x00000007, 0x0}, - {0x45b4, 0x00000038, 0x0}, - {0x45a4, 0x00ff0000, 0x0}, - {0x45b8, 0x80000000, 0x0}, - {0x4594, 0x003ff800, 0x0}, - {0x45b4, 0x000001c0, 0x0}, - {0x4598, 0xf8000000, 0x0}, - {0x45b8, 0x00100000, 0x0}, - {0x45a8, 0x00000fc0, 0x7}, - {0x45b8, 0x00200000, 0x0}, - {0x45b0, 0x00000038, 0x0}, - {0x45b0, 0x000001c0, 0x0}, - {0x45a0, 0x000000ff, 0x0}, - {0x45b4, 0x06000000, 0x0}, - {0x45b0, 0x00000007, 0x0}, - {0x45b8, 0x00080000, 0x0}, - {0x45a8, 0x0000003f, 0x0}, - {0x457c, 0xffe00000, 0x1}, - {0x4530, 0xffffffff, 0x0}, - {0x4588, 0x00003fff, 0x0}, - {0x4598, 0x000001ff, 0x0}, - {0x4534, 0xffffffff, 0x0}, - {0x4538, 0xffffffff, 0x0}, - {0x453c, 0xffffffff, 0x0}, - {0x4588, 0x0fffc000, 0x0}, - {0x4598, 0x0003fe00, 0x0}, - {0x4540, 0xffffffff, 0x0}, - {0x4544, 0xffffffff, 0x0}, - {0x4548, 0xffffffff, 0x0}, - {0x458c, 0x00003fff, 0x0}, - {0x4598, 0x07fc0000, 0x0}, - {0x454c, 0xffffffff, 0x0}, - {0x4550, 0xffffffff, 0x0}, - {0x4554, 0xffffffff, 0x0}, - {0x458c, 0x0fffc000, 0x0}, - {0x459c, 0x000001ff, 0x0}, - {0x4558, 0xffffffff, 0x0}, - {0x455c, 0xffffffff, 0x0}, - {0x4530, 0xffffffff, 0x4e790001}, - {0x4588, 0x00003fff, 0x0}, - {0x4598, 0x000001ff, 0x1}, - {0x4534, 0xffffffff, 0x0}, - {0x4538, 0xffffffff, 0x4b}, - {0x45ac, 0x38000000, 0x7}, - {0x4588, 0xf0000000, 0x0}, - {0x459c, 0x7e000000, 0x0}, - {0x45b8, 0x00040000, 0x0}, - {0x45b8, 0x00020000, 0x0}, - {0x4590, 0xffc00000, 0x0}, - {0x45b8, 0x00004000, 0x0}, - {0x4578, 0xff000000, 0x0}, - {0x45b8, 0x00000400, 0x0}, - {0x45b8, 0x00000800, 0x0}, - {0x45b8, 0x00001000, 0x0}, - {0x45b8, 0x00002000, 0x0}, - {0x45b4, 0x00018000, 0x0}, - {0x45ac, 0x07800000, 0x0}, - {0x45b4, 0x00000600, 0x2}, - {0x459c, 0x0001fe00, 0x80}, - {0x45ac, 0x00078000, 0x3}, - {0x459c, 0x01fe0000, 0x1}, -}; - -static const struct rtw89_reg3_def rtw8852b_btc_preagc_en_defs[] = { - {0x46D0, GENMASK(1, 0), 0x3}, - {0x4790, GENMASK(1, 0), 0x3}, - {0x4AD4, GENMASK(31, 0), 0xf}, - {0x4AE0, GENMASK(31, 0), 0xf}, - {0x4688, GENMASK(31, 24), 0x80}, - {0x476C, GENMASK(31, 24), 0x80}, - {0x4694, GENMASK(7, 0), 0x80}, - {0x4694, GENMASK(15, 8), 0x80}, - {0x4778, GENMASK(7, 0), 0x80}, - {0x4778, GENMASK(15, 8), 0x80}, - {0x4AE4, GENMASK(23, 0), 0x780D1E}, - {0x4AEC, GENMASK(23, 0), 0x780D1E}, - {0x469C, GENMASK(31, 26), 0x34}, - {0x49F0, GENMASK(31, 26), 0x34}, -}; - -static DECLARE_PHY_REG3_TBL(rtw8852b_btc_preagc_en_defs); - -static const struct rtw89_reg3_def rtw8852b_btc_preagc_dis_defs[] = { - {0x46D0, GENMASK(1, 0), 0x0}, - {0x4790, GENMASK(1, 0), 0x0}, - {0x4AD4, GENMASK(31, 0), 0x60}, - {0x4AE0, GENMASK(31, 0), 0x60}, - {0x4688, GENMASK(31, 24), 0x1a}, - {0x476C, GENMASK(31, 24), 0x1a}, - {0x4694, GENMASK(7, 0), 0x2a}, - {0x4694, GENMASK(15, 8), 0x2a}, - {0x4778, GENMASK(7, 0), 0x2a}, - {0x4778, GENMASK(15, 8), 0x2a}, - {0x4AE4, GENMASK(23, 0), 0x79E99E}, - {0x4AEC, GENMASK(23, 0), 0x79E99E}, - {0x469C, GENMASK(31, 26), 0x26}, - {0x49F0, GENMASK(31, 26), 0x26}, -}; - -static DECLARE_PHY_REG3_TBL(rtw8852b_btc_preagc_dis_defs); - 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 @@ -591,806 +431,6 @@ static int rtw8852b_pwr_off_func(struct rtw89_dev *rtwdev) return 0; } -static void rtw8852be_efuse_parsing(struct rtw89_efuse *efuse, - struct rtw8852b_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 rtw8852b_efuse_parsing_tssi(struct rtw89_dev *rtwdev, - struct rtw8852b_efuse *map) -{ - struct rtw89_tssi_info *tssi = &rtwdev->tssi; - struct rtw8852b_tssi_offset *ofst[] = {&map->path_a_tssi, &map->path_b_tssi}; - u8 i, j; - - tssi->thermal[RF_PATH_A] = map->path_a_therm; - tssi->thermal[RF_PATH_B] = map->path_b_therm; - - for (i = 0; i < RF_PATH_NUM_8852B; i++) { - memcpy(tssi->tssi_cck[i], ofst[i]->cck_tssi, - sizeof(ofst[i]->cck_tssi)); - - for (j = 0; j < TSSI_CCK_CH_GROUP_NUM; j++) - rtw89_debug(rtwdev, RTW89_DBG_TSSI, - "[TSSI][EFUSE] path=%d cck[%d]=0x%x\n", - i, j, tssi->tssi_cck[i][j]); - - memcpy(tssi->tssi_mcs[i], ofst[i]->bw40_tssi, - sizeof(ofst[i]->bw40_tssi)); - memcpy(tssi->tssi_mcs[i] + TSSI_MCS_2G_CH_GROUP_NUM, - ofst[i]->bw40_1s_tssi_5g, sizeof(ofst[i]->bw40_1s_tssi_5g)); - - for (j = 0; j < TSSI_MCS_CH_GROUP_NUM; j++) - rtw89_debug(rtwdev, RTW89_DBG_TSSI, - "[TSSI][EFUSE] path=%d mcs[%d]=0x%x\n", - i, j, tssi->tssi_mcs[i][j]); - } -} - -static bool _decode_efuse_gain(u8 data, s8 *high, s8 *low) -{ - if (high) - *high = sign_extend32(FIELD_GET(GENMASK(7, 4), data), 3); - if (low) - *low = sign_extend32(FIELD_GET(GENMASK(3, 0), data), 3); - - return data != 0xff; -} - -static void rtw8852b_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev, - struct rtw8852b_efuse *map) -{ - struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain; - bool valid = false; - - valid |= _decode_efuse_gain(map->rx_gain_2g_cck, - &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_2G_CCK], - &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_2G_CCK]); - valid |= _decode_efuse_gain(map->rx_gain_2g_ofdm, - &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_2G_OFDM], - &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_2G_OFDM]); - valid |= _decode_efuse_gain(map->rx_gain_5g_low, - &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_LOW], - &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_LOW]); - valid |= _decode_efuse_gain(map->rx_gain_5g_mid, - &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_MID], - &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_MID]); - valid |= _decode_efuse_gain(map->rx_gain_5g_high, - &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_HIGH], - &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_HIGH]); - - gain->offset_valid = valid; -} - -static int rtw8852b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, - enum rtw89_efuse_block block) -{ - struct rtw89_efuse *efuse = &rtwdev->efuse; - struct rtw8852b_efuse *map; - - map = (struct rtw8852b_efuse *)log_map; - - efuse->country_code[0] = map->country_code[0]; - efuse->country_code[1] = map->country_code[1]; - rtw8852b_efuse_parsing_tssi(rtwdev, map); - rtw8852b_efuse_parsing_gain_offset(rtwdev, map); - - switch (rtwdev->hci.type) { - case RTW89_HCI_TYPE_PCIE: - rtw8852be_efuse_parsing(efuse, map); - break; - default: - return -EOPNOTSUPP; - } - - rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); - - return 0; -} - -static void rtw8852b_phycap_parsing_power_cal(struct rtw89_dev *rtwdev, u8 *phycap_map) -{ -#define PWR_K_CHK_OFFSET 0x5E9 -#define PWR_K_CHK_VALUE 0xAA - u32 offset = PWR_K_CHK_OFFSET - rtwdev->chip->phycap_addr; - - if (phycap_map[offset] == PWR_K_CHK_VALUE) - rtwdev->efuse.power_k_valid = true; -} - -static void rtw8852b_phycap_parsing_tssi(struct rtw89_dev *rtwdev, u8 *phycap_map) -{ - struct rtw89_tssi_info *tssi = &rtwdev->tssi; - static const u32 tssi_trim_addr[RF_PATH_NUM_8852B] = {0x5D6, 0x5AB}; - u32 addr = rtwdev->chip->phycap_addr; - bool pg = false; - u32 ofst; - u8 i, j; - - for (i = 0; i < RF_PATH_NUM_8852B; i++) { - for (j = 0; j < TSSI_TRIM_CH_GROUP_NUM; j++) { - /* addrs are in decreasing order */ - ofst = tssi_trim_addr[i] - addr - j; - tssi->tssi_trim[i][j] = phycap_map[ofst]; - - if (phycap_map[ofst] != 0xff) - pg = true; - } - } - - if (!pg) { - memset(tssi->tssi_trim, 0, sizeof(tssi->tssi_trim)); - rtw89_debug(rtwdev, RTW89_DBG_TSSI, - "[TSSI][TRIM] no PG, set all trim info to 0\n"); - } - - for (i = 0; i < RF_PATH_NUM_8852B; i++) - for (j = 0; j < TSSI_TRIM_CH_GROUP_NUM; j++) - rtw89_debug(rtwdev, RTW89_DBG_TSSI, - "[TSSI] path=%d idx=%d trim=0x%x addr=0x%x\n", - i, j, tssi->tssi_trim[i][j], - tssi_trim_addr[i] - j); -} - -static void rtw8852b_phycap_parsing_thermal_trim(struct rtw89_dev *rtwdev, - u8 *phycap_map) -{ - struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; - static const u32 thm_trim_addr[RF_PATH_NUM_8852B] = {0x5DF, 0x5DC}; - u32 addr = rtwdev->chip->phycap_addr; - u8 i; - - for (i = 0; i < RF_PATH_NUM_8852B; i++) { - info->thermal_trim[i] = phycap_map[thm_trim_addr[i] - addr]; - - rtw89_debug(rtwdev, RTW89_DBG_RFK, - "[THERMAL][TRIM] path=%d thermal_trim=0x%x\n", - i, info->thermal_trim[i]); - - if (info->thermal_trim[i] != 0xff) - info->pg_thermal_trim = true; - } -} - -static void rtw8852b_thermal_trim(struct rtw89_dev *rtwdev) -{ -#define __thm_setting(raw) \ -({ \ - u8 __v = (raw); \ - ((__v & 0x1) << 3) | ((__v & 0x1f) >> 1); \ -}) - struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; - u8 i, val; - - if (!info->pg_thermal_trim) { - rtw89_debug(rtwdev, RTW89_DBG_RFK, - "[THERMAL][TRIM] no PG, do nothing\n"); - - return; - } - - for (i = 0; i < RF_PATH_NUM_8852B; i++) { - val = __thm_setting(info->thermal_trim[i]); - rtw89_write_rf(rtwdev, i, RR_TM2, RR_TM2_OFF, val); - - rtw89_debug(rtwdev, RTW89_DBG_RFK, - "[THERMAL][TRIM] path=%d thermal_setting=0x%x\n", - i, val); - } -#undef __thm_setting -} - -static void rtw8852b_phycap_parsing_pa_bias_trim(struct rtw89_dev *rtwdev, - u8 *phycap_map) -{ - struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; - static const u32 pabias_trim_addr[RF_PATH_NUM_8852B] = {0x5DE, 0x5DB}; - u32 addr = rtwdev->chip->phycap_addr; - u8 i; - - for (i = 0; i < RF_PATH_NUM_8852B; i++) { - info->pa_bias_trim[i] = phycap_map[pabias_trim_addr[i] - addr]; - - rtw89_debug(rtwdev, RTW89_DBG_RFK, - "[PA_BIAS][TRIM] path=%d pa_bias_trim=0x%x\n", - i, info->pa_bias_trim[i]); - - if (info->pa_bias_trim[i] != 0xff) - info->pg_pa_bias_trim = true; - } -} - -static void rtw8852b_pa_bias_trim(struct rtw89_dev *rtwdev) -{ - struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; - u8 pabias_2g, pabias_5g; - u8 i; - - if (!info->pg_pa_bias_trim) { - rtw89_debug(rtwdev, RTW89_DBG_RFK, - "[PA_BIAS][TRIM] no PG, do nothing\n"); - - return; - } - - for (i = 0; i < RF_PATH_NUM_8852B; i++) { - pabias_2g = FIELD_GET(GENMASK(3, 0), info->pa_bias_trim[i]); - pabias_5g = FIELD_GET(GENMASK(7, 4), info->pa_bias_trim[i]); - - rtw89_debug(rtwdev, RTW89_DBG_RFK, - "[PA_BIAS][TRIM] path=%d 2G=0x%x 5G=0x%x\n", - i, pabias_2g, pabias_5g); - - rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASA_TXG, pabias_2g); - rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASA_TXA, pabias_5g); - } -} - -static void rtw8852b_phycap_parsing_gain_comp(struct rtw89_dev *rtwdev, u8 *phycap_map) -{ - static const u32 comp_addrs[][RTW89_SUBBAND_2GHZ_5GHZ_NR] = { - {0x5BB, 0x5BA, 0, 0x5B9, 0x5B8}, - {0x590, 0x58F, 0, 0x58E, 0x58D}, - }; - struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain; - u32 phycap_addr = rtwdev->chip->phycap_addr; - bool valid = false; - int path, i; - u8 data; - - for (path = 0; path < 2; path++) - for (i = 0; i < RTW89_SUBBAND_2GHZ_5GHZ_NR; i++) { - if (comp_addrs[path][i] == 0) - continue; - - data = phycap_map[comp_addrs[path][i] - phycap_addr]; - valid |= _decode_efuse_gain(data, NULL, - &gain->comp[path][i]); - } - - gain->comp_valid = valid; -} - -static int rtw8852b_read_phycap(struct rtw89_dev *rtwdev, u8 *phycap_map) -{ - rtw8852b_phycap_parsing_power_cal(rtwdev, phycap_map); - rtw8852b_phycap_parsing_tssi(rtwdev, phycap_map); - rtw8852b_phycap_parsing_thermal_trim(rtwdev, phycap_map); - rtw8852b_phycap_parsing_pa_bias_trim(rtwdev, phycap_map); - rtw8852b_phycap_parsing_gain_comp(rtwdev, phycap_map); - - return 0; -} - -static void rtw8852b_power_trim(struct rtw89_dev *rtwdev) -{ - rtw8852b_thermal_trim(rtwdev); - rtw8852b_pa_bias_trim(rtwdev); -} - -static void rtw8852b_set_channel_mac(struct rtw89_dev *rtwdev, - const struct rtw89_chan *chan, - u8 mac_idx) -{ - u32 rf_mod = rtw89_mac_reg_by_idx(rtwdev, R_AX_WMAC_RFMOD, mac_idx); - u32 sub_carr = rtw89_mac_reg_by_idx(rtwdev, R_AX_TX_SUB_CARRIER_VALUE, mac_idx); - u32 chk_rate = rtw89_mac_reg_by_idx(rtwdev, R_AX_TXRATE_CHK, mac_idx); - u8 txsc20 = 0, txsc40 = 0; - - switch (chan->band_width) { - case RTW89_CHANNEL_WIDTH_80: - txsc40 = rtw89_phy_get_txsc(rtwdev, chan, RTW89_CHANNEL_WIDTH_40); - fallthrough; - case RTW89_CHANNEL_WIDTH_40: - txsc20 = rtw89_phy_get_txsc(rtwdev, chan, RTW89_CHANNEL_WIDTH_20); - break; - default: - break; - } - - switch (chan->band_width) { - case RTW89_CHANNEL_WIDTH_80: - rtw89_write8_mask(rtwdev, rf_mod, B_AX_WMAC_RFMOD_MASK, BIT(1)); - rtw89_write32(rtwdev, sub_carr, txsc20 | (txsc40 << 4)); - break; - case RTW89_CHANNEL_WIDTH_40: - rtw89_write8_mask(rtwdev, rf_mod, B_AX_WMAC_RFMOD_MASK, BIT(0)); - rtw89_write32(rtwdev, sub_carr, txsc20); - break; - case RTW89_CHANNEL_WIDTH_20: - rtw89_write8_clr(rtwdev, rf_mod, B_AX_WMAC_RFMOD_MASK); - rtw89_write32(rtwdev, sub_carr, 0); - break; - default: - break; - } - - if (chan->channel > 14) { - rtw89_write8_clr(rtwdev, chk_rate, B_AX_BAND_MODE); - rtw89_write8_set(rtwdev, chk_rate, - B_AX_CHECK_CCK_EN | B_AX_RTS_LIMIT_IN_OFDM6); - } else { - rtw89_write8_set(rtwdev, chk_rate, B_AX_BAND_MODE); - rtw89_write8_clr(rtwdev, chk_rate, - B_AX_CHECK_CCK_EN | B_AX_RTS_LIMIT_IN_OFDM6); - } -} - -static const u32 rtw8852b_sco_barker_threshold[14] = { - 0x1cfea, 0x1d0e1, 0x1d1d7, 0x1d2cd, 0x1d3c3, 0x1d4b9, 0x1d5b0, 0x1d6a6, - 0x1d79c, 0x1d892, 0x1d988, 0x1da7f, 0x1db75, 0x1ddc4 -}; - -static const u32 rtw8852b_sco_cck_threshold[14] = { - 0x27de3, 0x27f35, 0x28088, 0x281da, 0x2832d, 0x2847f, 0x285d2, 0x28724, - 0x28877, 0x289c9, 0x28b1c, 0x28c6e, 0x28dc1, 0x290ed -}; - -static void rtw8852b_ctrl_sco_cck(struct rtw89_dev *rtwdev, u8 primary_ch) -{ - u8 ch_element = primary_ch - 1; - - rtw89_phy_write32_mask(rtwdev, R_RXSCOBC, B_RXSCOBC_TH, - rtw8852b_sco_barker_threshold[ch_element]); - rtw89_phy_write32_mask(rtwdev, R_RXSCOCCK, B_RXSCOCCK_TH, - rtw8852b_sco_cck_threshold[ch_element]); -} - -static u8 rtw8852b_sco_mapping(u8 central_ch) -{ - if (central_ch == 1) - return 109; - else if (central_ch >= 2 && central_ch <= 6) - return 108; - else if (central_ch >= 7 && central_ch <= 10) - return 107; - else if (central_ch >= 11 && central_ch <= 14) - return 106; - else if (central_ch == 36 || central_ch == 38) - return 51; - else if (central_ch >= 40 && central_ch <= 58) - return 50; - else if (central_ch >= 60 && central_ch <= 64) - return 49; - else if (central_ch == 100 || central_ch == 102) - return 48; - else if (central_ch >= 104 && central_ch <= 126) - return 47; - else if (central_ch >= 128 && central_ch <= 151) - return 46; - else if (central_ch >= 153 && central_ch <= 177) - return 45; - else - return 0; -} - -struct rtw8852b_bb_gain { - u32 gain_g[BB_PATH_NUM_8852B]; - u32 gain_a[BB_PATH_NUM_8852B]; - u32 gain_mask; -}; - -static const struct rtw8852b_bb_gain bb_gain_lna[LNA_GAIN_NUM] = { - { .gain_g = {0x4678, 0x475C}, .gain_a = {0x45DC, 0x4740}, - .gain_mask = 0x00ff0000 }, - { .gain_g = {0x4678, 0x475C}, .gain_a = {0x45DC, 0x4740}, - .gain_mask = 0xff000000 }, - { .gain_g = {0x467C, 0x4760}, .gain_a = {0x4660, 0x4744}, - .gain_mask = 0x000000ff }, - { .gain_g = {0x467C, 0x4760}, .gain_a = {0x4660, 0x4744}, - .gain_mask = 0x0000ff00 }, - { .gain_g = {0x467C, 0x4760}, .gain_a = {0x4660, 0x4744}, - .gain_mask = 0x00ff0000 }, - { .gain_g = {0x467C, 0x4760}, .gain_a = {0x4660, 0x4744}, - .gain_mask = 0xff000000 }, - { .gain_g = {0x4680, 0x4764}, .gain_a = {0x4664, 0x4748}, - .gain_mask = 0x000000ff }, -}; - -static const struct rtw8852b_bb_gain bb_gain_tia[TIA_GAIN_NUM] = { - { .gain_g = {0x4680, 0x4764}, .gain_a = {0x4664, 0x4748}, - .gain_mask = 0x00ff0000 }, - { .gain_g = {0x4680, 0x4764}, .gain_a = {0x4664, 0x4748}, - .gain_mask = 0xff000000 }, -}; - -static void rtw8852b_set_gain_error(struct rtw89_dev *rtwdev, - enum rtw89_subband subband, - enum rtw89_rf_path path) -{ - const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; - u8 gain_band = rtw89_subband_to_bb_gain_band(subband); - s32 val; - u32 reg; - u32 mask; - int i; - - for (i = 0; i < LNA_GAIN_NUM; i++) { - if (subband == RTW89_CH_2G) - reg = bb_gain_lna[i].gain_g[path]; - else - reg = bb_gain_lna[i].gain_a[path]; - - mask = bb_gain_lna[i].gain_mask; - val = gain->lna_gain[gain_band][path][i]; - rtw89_phy_write32_mask(rtwdev, reg, mask, val); - } - - for (i = 0; i < TIA_GAIN_NUM; i++) { - if (subband == RTW89_CH_2G) - reg = bb_gain_tia[i].gain_g[path]; - else - reg = bb_gain_tia[i].gain_a[path]; - - mask = bb_gain_tia[i].gain_mask; - val = gain->tia_gain[gain_band][path][i]; - rtw89_phy_write32_mask(rtwdev, reg, mask, val); - } -} - -static void rtw8852b_set_gain_offset(struct rtw89_dev *rtwdev, - enum rtw89_subband subband, - enum rtw89_phy_idx phy_idx) -{ - static const u32 gain_err_addr[2] = {R_P0_AGC_RSVD, R_P1_AGC_RSVD}; - static const u32 rssi_ofst_addr[2] = {R_PATH0_G_TIA1_LNA6_OP1DB_V1, - R_PATH1_G_TIA1_LNA6_OP1DB_V1}; - struct rtw89_hal *hal = &rtwdev->hal; - struct rtw89_phy_efuse_gain *efuse_gain = &rtwdev->efuse_gain; - enum rtw89_gain_offset gain_ofdm_band; - s32 offset_a, offset_b; - s32 offset_ofdm, offset_cck; - s32 tmp; - u8 path; - - if (!efuse_gain->comp_valid) - goto next; - - for (path = RF_PATH_A; path < BB_PATH_NUM_8852B; path++) { - tmp = efuse_gain->comp[path][subband]; - tmp = clamp_t(s32, tmp << 2, S8_MIN, S8_MAX); - rtw89_phy_write32_mask(rtwdev, gain_err_addr[path], MASKBYTE0, tmp); - } - -next: - if (!efuse_gain->offset_valid) - return; - - gain_ofdm_band = rtw89_subband_to_gain_offset_band_of_ofdm(subband); - - offset_a = -efuse_gain->offset[RF_PATH_A][gain_ofdm_band]; - offset_b = -efuse_gain->offset[RF_PATH_B][gain_ofdm_band]; - - tmp = -((offset_a << 2) + (efuse_gain->offset_base[RTW89_PHY_0] >> 2)); - tmp = clamp_t(s32, tmp, S8_MIN, S8_MAX); - rtw89_phy_write32_mask(rtwdev, rssi_ofst_addr[RF_PATH_A], B_PATH0_R_G_OFST_MASK, tmp); - - tmp = -((offset_b << 2) + (efuse_gain->offset_base[RTW89_PHY_0] >> 2)); - tmp = clamp_t(s32, tmp, S8_MIN, S8_MAX); - rtw89_phy_write32_mask(rtwdev, rssi_ofst_addr[RF_PATH_B], B_PATH0_R_G_OFST_MASK, tmp); - - if (hal->antenna_rx == RF_B) { - offset_ofdm = -efuse_gain->offset[RF_PATH_B][gain_ofdm_band]; - offset_cck = -efuse_gain->offset[RF_PATH_B][0]; - } else { - offset_ofdm = -efuse_gain->offset[RF_PATH_A][gain_ofdm_band]; - offset_cck = -efuse_gain->offset[RF_PATH_A][0]; - } - - tmp = (offset_ofdm << 4) + efuse_gain->offset_base[RTW89_PHY_0]; - tmp = clamp_t(s32, tmp, S8_MIN, S8_MAX); - rtw89_phy_write32_idx(rtwdev, R_P0_RPL1, B_P0_RPL1_BIAS_MASK, tmp, phy_idx); - - tmp = (offset_ofdm << 4) + efuse_gain->rssi_base[RTW89_PHY_0]; - tmp = clamp_t(s32, tmp, S8_MIN, S8_MAX); - rtw89_phy_write32_idx(rtwdev, R_P1_RPL1, B_P0_RPL1_BIAS_MASK, tmp, phy_idx); - - if (subband == RTW89_CH_2G) { - tmp = (offset_cck << 3) + (efuse_gain->offset_base[RTW89_PHY_0] >> 1); - tmp = clamp_t(s32, tmp, S8_MIN >> 1, S8_MAX >> 1); - rtw89_phy_write32_mask(rtwdev, R_RX_RPL_OFST, - B_RX_RPL_OFST_CCK_MASK, tmp); - } -} - -static -void rtw8852b_set_rxsc_rpl_comp(struct rtw89_dev *rtwdev, enum rtw89_subband subband) -{ - const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; - u8 band = rtw89_subband_to_bb_gain_band(subband); - u32 val; - - val = FIELD_PREP(B_P0_RPL1_20_MASK, (gain->rpl_ofst_20[band][RF_PATH_A] + - gain->rpl_ofst_20[band][RF_PATH_B]) / 2) | - FIELD_PREP(B_P0_RPL1_40_MASK, (gain->rpl_ofst_40[band][RF_PATH_A][0] + - gain->rpl_ofst_40[band][RF_PATH_B][0]) / 2) | - FIELD_PREP(B_P0_RPL1_41_MASK, (gain->rpl_ofst_40[band][RF_PATH_A][1] + - gain->rpl_ofst_40[band][RF_PATH_B][1]) / 2); - val >>= B_P0_RPL1_SHIFT; - rtw89_phy_write32_mask(rtwdev, R_P0_RPL1, B_P0_RPL1_MASK, val); - rtw89_phy_write32_mask(rtwdev, R_P1_RPL1, B_P0_RPL1_MASK, val); - - val = FIELD_PREP(B_P0_RTL2_42_MASK, (gain->rpl_ofst_40[band][RF_PATH_A][2] + - gain->rpl_ofst_40[band][RF_PATH_B][2]) / 2) | - FIELD_PREP(B_P0_RTL2_80_MASK, (gain->rpl_ofst_80[band][RF_PATH_A][0] + - gain->rpl_ofst_80[band][RF_PATH_B][0]) / 2) | - FIELD_PREP(B_P0_RTL2_81_MASK, (gain->rpl_ofst_80[band][RF_PATH_A][1] + - gain->rpl_ofst_80[band][RF_PATH_B][1]) / 2) | - FIELD_PREP(B_P0_RTL2_8A_MASK, (gain->rpl_ofst_80[band][RF_PATH_A][10] + - gain->rpl_ofst_80[band][RF_PATH_B][10]) / 2); - rtw89_phy_write32(rtwdev, R_P0_RPL2, val); - rtw89_phy_write32(rtwdev, R_P1_RPL2, val); - - val = FIELD_PREP(B_P0_RTL3_82_MASK, (gain->rpl_ofst_80[band][RF_PATH_A][2] + - gain->rpl_ofst_80[band][RF_PATH_B][2]) / 2) | - FIELD_PREP(B_P0_RTL3_83_MASK, (gain->rpl_ofst_80[band][RF_PATH_A][3] + - gain->rpl_ofst_80[band][RF_PATH_B][3]) / 2) | - FIELD_PREP(B_P0_RTL3_84_MASK, (gain->rpl_ofst_80[band][RF_PATH_A][4] + - gain->rpl_ofst_80[band][RF_PATH_B][4]) / 2) | - FIELD_PREP(B_P0_RTL3_89_MASK, (gain->rpl_ofst_80[band][RF_PATH_A][9] + - gain->rpl_ofst_80[band][RF_PATH_B][9]) / 2); - rtw89_phy_write32(rtwdev, R_P0_RPL3, val); - rtw89_phy_write32(rtwdev, R_P1_RPL3, val); -} - -static void rtw8852b_ctrl_ch(struct rtw89_dev *rtwdev, - const struct rtw89_chan *chan, - enum rtw89_phy_idx phy_idx) -{ - u8 central_ch = chan->channel; - u8 subband = chan->subband_type; - u8 sco_comp; - bool is_2g = central_ch <= 14; - - /* Path A */ - if (is_2g) - rtw89_phy_write32_idx(rtwdev, R_PATH0_BAND_SEL_V1, - B_PATH0_BAND_SEL_MSK_V1, 1, phy_idx); - else - rtw89_phy_write32_idx(rtwdev, R_PATH0_BAND_SEL_V1, - B_PATH0_BAND_SEL_MSK_V1, 0, phy_idx); - - /* Path B */ - if (is_2g) - rtw89_phy_write32_idx(rtwdev, R_PATH1_BAND_SEL_V1, - B_PATH1_BAND_SEL_MSK_V1, 1, phy_idx); - else - rtw89_phy_write32_idx(rtwdev, R_PATH1_BAND_SEL_V1, - B_PATH1_BAND_SEL_MSK_V1, 0, phy_idx); - - /* SCO compensate FC setting */ - sco_comp = rtw8852b_sco_mapping(central_ch); - rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_INV, sco_comp, phy_idx); - - if (chan->band_type == RTW89_BAND_6G) - return; - - /* CCK parameters */ - if (central_ch == 14) { - rtw89_phy_write32_mask(rtwdev, R_TXFIR0, B_TXFIR_C01, 0x3b13ff); - rtw89_phy_write32_mask(rtwdev, R_TXFIR2, B_TXFIR_C23, 0x1c42de); - rtw89_phy_write32_mask(rtwdev, R_TXFIR4, B_TXFIR_C45, 0xfdb0ad); - rtw89_phy_write32_mask(rtwdev, R_TXFIR6, B_TXFIR_C67, 0xf60f6e); - rtw89_phy_write32_mask(rtwdev, R_TXFIR8, B_TXFIR_C89, 0xfd8f92); - rtw89_phy_write32_mask(rtwdev, R_TXFIRA, B_TXFIR_CAB, 0x2d011); - rtw89_phy_write32_mask(rtwdev, R_TXFIRC, B_TXFIR_CCD, 0x1c02c); - rtw89_phy_write32_mask(rtwdev, R_TXFIRE, B_TXFIR_CEF, 0xfff00a); - } else { - rtw89_phy_write32_mask(rtwdev, R_TXFIR0, B_TXFIR_C01, 0x3d23ff); - rtw89_phy_write32_mask(rtwdev, R_TXFIR2, B_TXFIR_C23, 0x29b354); - rtw89_phy_write32_mask(rtwdev, R_TXFIR4, B_TXFIR_C45, 0xfc1c8); - rtw89_phy_write32_mask(rtwdev, R_TXFIR6, B_TXFIR_C67, 0xfdb053); - rtw89_phy_write32_mask(rtwdev, R_TXFIR8, B_TXFIR_C89, 0xf86f9a); - rtw89_phy_write32_mask(rtwdev, R_TXFIRA, B_TXFIR_CAB, 0xfaef92); - rtw89_phy_write32_mask(rtwdev, R_TXFIRC, B_TXFIR_CCD, 0xfe5fcc); - rtw89_phy_write32_mask(rtwdev, R_TXFIRE, B_TXFIR_CEF, 0xffdff5); - } - - rtw8852b_set_gain_error(rtwdev, subband, RF_PATH_A); - rtw8852b_set_gain_error(rtwdev, subband, RF_PATH_B); - rtw8852b_set_gain_offset(rtwdev, subband, phy_idx); - rtw8852b_set_rxsc_rpl_comp(rtwdev, subband); -} - -static void rtw8852b_bw_setting(struct rtw89_dev *rtwdev, u8 bw, u8 path) -{ - static const u32 adc_sel[2] = {0xC0EC, 0xC1EC}; - static const u32 wbadc_sel[2] = {0xC0E4, 0xC1E4}; - - switch (bw) { - case RTW89_CHANNEL_WIDTH_5: - rtw89_phy_write32_mask(rtwdev, adc_sel[path], 0x6000, 0x1); - rtw89_phy_write32_mask(rtwdev, wbadc_sel[path], 0x30, 0x0); - break; - case RTW89_CHANNEL_WIDTH_10: - rtw89_phy_write32_mask(rtwdev, adc_sel[path], 0x6000, 0x2); - rtw89_phy_write32_mask(rtwdev, wbadc_sel[path], 0x30, 0x1); - break; - case RTW89_CHANNEL_WIDTH_20: - rtw89_phy_write32_mask(rtwdev, adc_sel[path], 0x6000, 0x0); - rtw89_phy_write32_mask(rtwdev, wbadc_sel[path], 0x30, 0x2); - break; - case RTW89_CHANNEL_WIDTH_40: - rtw89_phy_write32_mask(rtwdev, adc_sel[path], 0x6000, 0x0); - rtw89_phy_write32_mask(rtwdev, wbadc_sel[path], 0x30, 0x2); - break; - case RTW89_CHANNEL_WIDTH_80: - rtw89_phy_write32_mask(rtwdev, adc_sel[path], 0x6000, 0x0); - rtw89_phy_write32_mask(rtwdev, wbadc_sel[path], 0x30, 0x2); - break; - default: - rtw89_warn(rtwdev, "Fail to set ADC\n"); - } -} - -static void rtw8852b_ctrl_bw(struct rtw89_dev *rtwdev, u8 pri_ch, u8 bw, - enum rtw89_phy_idx phy_idx) -{ - u32 rx_path_0; - - switch (bw) { - case RTW89_CHANNEL_WIDTH_5: - rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x0, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_SBW, 0x1, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, 0x0, phy_idx); - - /*Set RF mode at 3 */ - rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX, - B_P0_RFMODE_ORI_RX_ALL, 0x333, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, - B_P1_RFMODE_ORI_RX_ALL, 0x333, phy_idx); - break; - case RTW89_CHANNEL_WIDTH_10: - rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x0, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_SBW, 0x2, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, 0x0, phy_idx); - - /*Set RF mode at 3 */ - rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX, - B_P0_RFMODE_ORI_RX_ALL, 0x333, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, - B_P1_RFMODE_ORI_RX_ALL, 0x333, phy_idx); - break; - case RTW89_CHANNEL_WIDTH_20: - rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x0, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_SBW, 0x0, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, 0x0, phy_idx); - - /*Set RF mode at 3 */ - rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX, - B_P0_RFMODE_ORI_RX_ALL, 0x333, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, - B_P1_RFMODE_ORI_RX_ALL, 0x333, phy_idx); - break; - case RTW89_CHANNEL_WIDTH_40: - rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x1, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_SBW, 0x0, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, - pri_ch, phy_idx); - - /*Set RF mode at 3 */ - rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX, - B_P0_RFMODE_ORI_RX_ALL, 0x333, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, - B_P1_RFMODE_ORI_RX_ALL, 0x333, phy_idx); - /*CCK primary channel */ - if (pri_ch == RTW89_SC_20_UPPER) - rtw89_phy_write32_mask(rtwdev, R_RXSC, B_RXSC_EN, 1); - else - rtw89_phy_write32_mask(rtwdev, R_RXSC, B_RXSC_EN, 0); - - break; - case RTW89_CHANNEL_WIDTH_80: - rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x2, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_SBW, 0x0, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, - pri_ch, phy_idx); - - /*Set RF mode at A */ - rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX, - B_P0_RFMODE_ORI_RX_ALL, 0xaaa, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, - B_P1_RFMODE_ORI_RX_ALL, 0xaaa, phy_idx); - break; - default: - rtw89_warn(rtwdev, "Fail to switch bw (bw:%d, pri ch:%d)\n", bw, - pri_ch); - } - - rtw8852b_bw_setting(rtwdev, bw, RF_PATH_A); - rtw8852b_bw_setting(rtwdev, bw, RF_PATH_B); - - rx_path_0 = rtw89_phy_read32_idx(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, - phy_idx); - if (rx_path_0 == 0x1) - rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, - B_P1_RFMODE_ORI_RX_ALL, 0x111, phy_idx); - else if (rx_path_0 == 0x2) - rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX, - B_P0_RFMODE_ORI_RX_ALL, 0x111, phy_idx); -} - -static void rtw8852b_ctrl_cck_en(struct rtw89_dev *rtwdev, bool cck_en) -{ - if (cck_en) { - rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, B_ENABLE_CCK, 1); - rtw89_phy_write32_mask(rtwdev, R_RXCCA, B_RXCCA_DIS, 0); - } else { - rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, B_ENABLE_CCK, 0); - rtw89_phy_write32_mask(rtwdev, R_RXCCA, B_RXCCA_DIS, 1); - } -} - -static void rtw8852b_5m_mask(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, - enum rtw89_phy_idx phy_idx) -{ - u8 pri_ch = chan->pri_ch_idx; - bool mask_5m_low; - bool mask_5m_en; - - switch (chan->band_width) { - case RTW89_CHANNEL_WIDTH_40: - /* Prich=1: Mask 5M High, Prich=2: Mask 5M Low */ - mask_5m_en = true; - mask_5m_low = pri_ch == RTW89_SC_20_LOWER; - break; - case RTW89_CHANNEL_WIDTH_80: - /* Prich=3: Mask 5M High, Prich=4: Mask 5M Low, Else: Disable */ - mask_5m_en = pri_ch == RTW89_SC_20_UPMOST || - pri_ch == RTW89_SC_20_LOWEST; - mask_5m_low = pri_ch == RTW89_SC_20_LOWEST; - break; - default: - mask_5m_en = false; - break; - } - - if (!mask_5m_en) { - rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_EN, 0x0); - rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_EN, 0x0); - rtw89_phy_write32_idx(rtwdev, R_ASSIGN_SBD_OPT_V1, - B_ASSIGN_SBD_OPT_EN_V1, 0x0, phy_idx); - return; - } - - if (mask_5m_low) { - rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_TH, 0x4); - rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_EN, 0x1); - rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_SB2, 0x0); - rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_SB0, 0x1); - rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_TH, 0x4); - rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_EN, 0x1); - rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_SB2, 0x0); - rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_SB0, 0x1); - } else { - rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_TH, 0x4); - rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_EN, 0x1); - rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_SB2, 0x1); - rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_SB0, 0x0); - rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_TH, 0x4); - rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_EN, 0x1); - rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_SB2, 0x1); - rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_SB0, 0x0); - } - rtw89_phy_write32_idx(rtwdev, R_ASSIGN_SBD_OPT_V1, - B_ASSIGN_SBD_OPT_EN_V1, 0x1, phy_idx); -} - -static void rtw8852b_bb_reset_all(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) -{ - rtw89_phy_write32_idx(rtwdev, R_S0_HW_SI_DIS, B_S0_HW_SI_DIS_W_R_TRIG, 0x7, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_S1_HW_SI_DIS, B_S1_HW_SI_DIS_W_R_TRIG, 0x7, phy_idx); - fsleep(1); - rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 1, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 0, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_S0_HW_SI_DIS, B_S0_HW_SI_DIS_W_R_TRIG, 0x0, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_S1_HW_SI_DIS, B_S1_HW_SI_DIS_W_R_TRIG, 0x0, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 1, phy_idx); -} - static void rtw8852b_bb_reset_en(struct rtw89_dev *rtwdev, enum rtw89_band band, enum rtw89_phy_idx phy_idx, bool en) { @@ -1422,87 +462,20 @@ static void rtw8852b_bb_reset(struct rtw89_dev *rtwdev, rtw89_phy_write32_set(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_TRK_EN); rtw89_phy_write32_set(rtwdev, R_P1_TXPW_RSTB, B_P1_TXPW_RSTB_MANON); rtw89_phy_write32_set(rtwdev, R_P1_TSSI_TRK, B_P1_TSSI_TRK_EN); - rtw8852b_bb_reset_all(rtwdev, phy_idx); + rtw8852bx_bb_reset_all(rtwdev, phy_idx); rtw89_phy_write32_clr(rtwdev, R_P0_TXPW_RSTB, B_P0_TXPW_RSTB_MANON); rtw89_phy_write32_clr(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_TRK_EN); rtw89_phy_write32_clr(rtwdev, R_P1_TXPW_RSTB, B_P1_TXPW_RSTB_MANON); rtw89_phy_write32_clr(rtwdev, R_P1_TSSI_TRK, B_P1_TSSI_TRK_EN); } -static void rtw8852b_bb_macid_ctrl_init(struct rtw89_dev *rtwdev, - enum rtw89_phy_idx phy_idx) -{ - u32 addr; - - for (addr = R_AX_PWR_MACID_LMT_TABLE0; - addr <= R_AX_PWR_MACID_LMT_TABLE127; addr += 4) - rtw89_mac_txpwr_write32(rtwdev, phy_idx, addr, 0); -} - -static void rtw8852b_bb_sethw(struct rtw89_dev *rtwdev) -{ - struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain; - - rtw89_phy_write32_clr(rtwdev, R_P0_EN_SOUND_WO_NDP, B_P0_EN_SOUND_WO_NDP); - rtw89_phy_write32_clr(rtwdev, R_P1_EN_SOUND_WO_NDP, B_P1_EN_SOUND_WO_NDP); - - rtw8852b_bb_macid_ctrl_init(rtwdev, RTW89_PHY_0); - - /* read these registers after loading BB parameters */ - gain->offset_base[RTW89_PHY_0] = - rtw89_phy_read32_mask(rtwdev, R_P0_RPL1, B_P0_RPL1_BIAS_MASK); - gain->rssi_base[RTW89_PHY_0] = - rtw89_phy_read32_mask(rtwdev, R_P1_RPL1, B_P0_RPL1_BIAS_MASK); -} - -static void rtw8852b_bb_set_pop(struct rtw89_dev *rtwdev) -{ - if (rtwdev->hw->conf.flags & IEEE80211_CONF_MONITOR) - rtw89_phy_write32_clr(rtwdev, R_PKT_CTRL, B_PKT_POP_EN); -} - -static void rtw8852b_set_channel_bb(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, - enum rtw89_phy_idx phy_idx) -{ - bool cck_en = chan->channel <= 14; - u8 pri_ch_idx = chan->pri_ch_idx; - u8 band = chan->band_type, chan_idx; - - if (cck_en) - rtw8852b_ctrl_sco_cck(rtwdev, chan->primary_channel); - - rtw8852b_ctrl_ch(rtwdev, chan, phy_idx); - rtw8852b_ctrl_bw(rtwdev, pri_ch_idx, chan->band_width, phy_idx); - rtw8852b_ctrl_cck_en(rtwdev, cck_en); - if (chan->band_type == RTW89_BAND_5G) { - rtw89_phy_write32_mask(rtwdev, R_PATH0_BT_SHARE_V1, - B_PATH0_BT_SHARE_V1, 0x0); - rtw89_phy_write32_mask(rtwdev, R_PATH0_BTG_PATH_V1, - B_PATH0_BTG_PATH_V1, 0x0); - rtw89_phy_write32_mask(rtwdev, R_PATH1_BT_SHARE_V1, - B_PATH1_BT_SHARE_V1, 0x0); - rtw89_phy_write32_mask(rtwdev, R_PATH1_BTG_PATH_V1, - B_PATH1_BTG_PATH_V1, 0x0); - rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_BT_SHARE, 0x0); - rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_BT_SEG0, 0x0); - rtw89_phy_write32_mask(rtwdev, R_BT_DYN_DC_EST_EN_V1, - B_BT_DYN_DC_EST_EN_MSK, 0x0); - rtw89_phy_write32_mask(rtwdev, R_GNT_BT_WGT_EN, B_GNT_BT_WGT_EN, 0x0); - } - chan_idx = rtw89_encode_chan_idx(rtwdev, chan->primary_channel, band); - rtw89_phy_write32_mask(rtwdev, R_MAC_PIN_SEL, B_CH_IDX_SEG0, chan_idx); - rtw8852b_5m_mask(rtwdev, chan, phy_idx); - rtw8852b_bb_set_pop(rtwdev); - rtw8852b_bb_reset_all(rtwdev, phy_idx); -} - static void rtw8852b_set_channel(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_mac_idx mac_idx, enum rtw89_phy_idx phy_idx) { - rtw8852b_set_channel_mac(rtwdev, chan, mac_idx); - rtw8852b_set_channel_bb(rtwdev, chan, phy_idx); + rtw8852bx_set_channel_mac(rtwdev, chan, mac_idx); + rtw8852bx_set_channel_bb(rtwdev, chan, phy_idx); rtw8852b_set_channel_rf(rtwdev, chan, phy_idx); } @@ -1602,540 +575,6 @@ static void rtw8852b_rfk_track(struct rtw89_dev *rtwdev) rtw8852b_dpk_track(rtwdev); } -static u32 rtw8852b_bb_cal_txpwr_ref(struct rtw89_dev *rtwdev, - enum rtw89_phy_idx phy_idx, s16 ref) -{ - const u16 tssi_16dbm_cw = 0x12c; - const u8 base_cw_0db = 0x27; - const s8 ofst_int = 0; - s16 pwr_s10_3; - s16 rf_pwr_cw; - u16 bb_pwr_cw; - u32 pwr_cw; - u32 tssi_ofst_cw; - - pwr_s10_3 = (ref << 1) + (s16)(ofst_int) + (s16)(base_cw_0db << 3); - bb_pwr_cw = FIELD_GET(GENMASK(2, 0), pwr_s10_3); - rf_pwr_cw = FIELD_GET(GENMASK(8, 3), pwr_s10_3); - rf_pwr_cw = clamp_t(s16, rf_pwr_cw, 15, 63); - pwr_cw = (rf_pwr_cw << 3) | bb_pwr_cw; - - tssi_ofst_cw = (u32)((s16)tssi_16dbm_cw + (ref << 1) - (16 << 3)); - rtw89_debug(rtwdev, RTW89_DBG_TXPWR, - "[TXPWR] tssi_ofst_cw=%d rf_cw=0x%x bb_cw=0x%x\n", - tssi_ofst_cw, rf_pwr_cw, bb_pwr_cw); - - return FIELD_PREP(B_DPD_TSSI_CW, tssi_ofst_cw) | - FIELD_PREP(B_DPD_PWR_CW, pwr_cw) | - FIELD_PREP(B_DPD_REF, ref); -} - -static void rtw8852b_set_txpwr_ref(struct rtw89_dev *rtwdev, - enum rtw89_phy_idx phy_idx) -{ - static const u32 addr[RF_PATH_NUM_8852B] = {0x5800, 0x7800}; - const u32 mask = B_DPD_TSSI_CW | B_DPD_PWR_CW | B_DPD_REF; - const u8 ofst_ofdm = 0x4; - const u8 ofst_cck = 0x8; - const s16 ref_ofdm = 0; - const s16 ref_cck = 0; - u32 val; - u8 i; - - rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set txpwr reference\n"); - - rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_AX_PWR_RATE_CTRL, - B_AX_PWR_REF, 0x0); - - rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set bb ofdm txpwr ref\n"); - val = rtw8852b_bb_cal_txpwr_ref(rtwdev, phy_idx, ref_ofdm); - - for (i = 0; i < RF_PATH_NUM_8852B; i++) - rtw89_phy_write32_idx(rtwdev, addr[i] + ofst_ofdm, mask, val, - phy_idx); - - rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set bb cck txpwr ref\n"); - val = rtw8852b_bb_cal_txpwr_ref(rtwdev, phy_idx, ref_cck); - - for (i = 0; i < RF_PATH_NUM_8852B; i++) - rtw89_phy_write32_idx(rtwdev, addr[i] + ofst_cck, mask, val, - phy_idx); -} - -static void rtw8852b_bb_set_tx_shape_dfir(struct rtw89_dev *rtwdev, - const struct rtw89_chan *chan, - u8 tx_shape_idx, - enum rtw89_phy_idx phy_idx) -{ -#define __DFIR_CFG_ADDR(i) (R_TXFIR0 + ((i) << 2)) -#define __DFIR_CFG_MASK 0xffffffff -#define __DFIR_CFG_NR 8 -#define __DECL_DFIR_PARAM(_name, _val...) \ - static const u32 param_ ## _name[] = {_val}; \ - static_assert(ARRAY_SIZE(param_ ## _name) == __DFIR_CFG_NR) - - __DECL_DFIR_PARAM(flat, - 0x023D23FF, 0x0029B354, 0x000FC1C8, 0x00FDB053, - 0x00F86F9A, 0x06FAEF92, 0x00FE5FCC, 0x00FFDFF5); - __DECL_DFIR_PARAM(sharp, - 0x023D83FF, 0x002C636A, 0x0013F204, 0x00008090, - 0x00F87FB0, 0x06F99F83, 0x00FDBFBA, 0x00003FF5); - __DECL_DFIR_PARAM(sharp_14, - 0x023B13FF, 0x001C42DE, 0x00FDB0AD, 0x00F60F6E, - 0x00FD8F92, 0x0602D011, 0x0001C02C, 0x00FFF00A); - u8 ch = chan->channel; - const u32 *param; - u32 addr; - int i; - - if (ch > 14) { - rtw89_warn(rtwdev, - "set tx shape dfir by unknown ch: %d on 2G\n", ch); - return; - } - - if (ch == 14) - param = param_sharp_14; - else - param = tx_shape_idx == 0 ? param_flat : param_sharp; - - for (i = 0; i < __DFIR_CFG_NR; i++) { - addr = __DFIR_CFG_ADDR(i); - rtw89_debug(rtwdev, RTW89_DBG_TXPWR, - "set tx shape dfir: 0x%x: 0x%x\n", addr, param[i]); - rtw89_phy_write32_idx(rtwdev, addr, __DFIR_CFG_MASK, param[i], - phy_idx); - } - -#undef __DECL_DFIR_PARAM -#undef __DFIR_CFG_NR -#undef __DFIR_CFG_MASK -#undef __DECL_CFG_ADDR -} - -static void rtw8852b_set_tx_shape(struct rtw89_dev *rtwdev, - const struct rtw89_chan *chan, - enum rtw89_phy_idx phy_idx) -{ - const struct rtw89_rfe_parms *rfe_parms = rtwdev->rfe_parms; - u8 band = chan->band_type; - u8 regd = rtw89_regd_get(rtwdev, band); - u8 tx_shape_cck = (*rfe_parms->tx_shape.lmt)[band][RTW89_RS_CCK][regd]; - u8 tx_shape_ofdm = (*rfe_parms->tx_shape.lmt)[band][RTW89_RS_OFDM][regd]; - - if (band == RTW89_BAND_2G) - rtw8852b_bb_set_tx_shape_dfir(rtwdev, chan, tx_shape_cck, phy_idx); - - rtw89_phy_write32_mask(rtwdev, R_DCFO_OPT, B_TXSHAPE_TRIANGULAR_CFG, - tx_shape_ofdm); -} - -static void rtw8852b_set_txpwr(struct rtw89_dev *rtwdev, - const struct rtw89_chan *chan, - enum rtw89_phy_idx phy_idx) -{ - rtw89_phy_set_txpwr_byrate(rtwdev, chan, phy_idx); - rtw89_phy_set_txpwr_offset(rtwdev, chan, phy_idx); - rtw8852b_set_tx_shape(rtwdev, chan, phy_idx); - rtw89_phy_set_txpwr_limit(rtwdev, chan, phy_idx); - rtw89_phy_set_txpwr_limit_ru(rtwdev, chan, phy_idx); -} - -static void rtw8852b_set_txpwr_ctrl(struct rtw89_dev *rtwdev, - enum rtw89_phy_idx phy_idx) -{ - rtw8852b_set_txpwr_ref(rtwdev, phy_idx); -} - -static -void rtw8852b_set_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev, - s8 pw_ofst, enum rtw89_mac_idx mac_idx) -{ - u32 reg; - - if (pw_ofst < -16 || pw_ofst > 15) { - rtw89_warn(rtwdev, "[ULTB] Err pwr_offset=%d\n", pw_ofst); - return; - } - - reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_CTRL, mac_idx); - rtw89_write32_set(rtwdev, reg, B_AX_PWR_UL_TB_CTRL_EN); - - reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_1T, mac_idx); - rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_1T_MASK, pw_ofst); - - pw_ofst = max_t(s8, pw_ofst - 3, -16); - reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_2T, mac_idx); - rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_2T_MASK, pw_ofst); -} - -static int -rtw8852b_init_txpwr_unit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) -{ - int ret; - - ret = rtw89_mac_txpwr_write32(rtwdev, phy_idx, R_AX_PWR_UL_CTRL2, 0x07763333); - if (ret) - return ret; - - ret = rtw89_mac_txpwr_write32(rtwdev, phy_idx, R_AX_PWR_COEXT_CTRL, 0x01ebf000); - if (ret) - return ret; - - ret = rtw89_mac_txpwr_write32(rtwdev, phy_idx, R_AX_PWR_UL_CTRL0, 0x0002f8ff); - if (ret) - return ret; - - rtw8852b_set_txpwr_ul_tb_offset(rtwdev, 0, phy_idx == RTW89_PHY_1 ? - RTW89_MAC_1 : RTW89_MAC_0); - - return 0; -} - -void rtw8852b_bb_set_plcp_tx(struct rtw89_dev *rtwdev) -{ - const struct rtw89_reg3_def *def = rtw8852b_pmac_ht20_mcs7_tbl; - u8 i; - - for (i = 0; i < ARRAY_SIZE(rtw8852b_pmac_ht20_mcs7_tbl); i++, def++) - rtw89_phy_write32_mask(rtwdev, def->addr, def->mask, def->data); -} - -static void rtw8852b_stop_pmac_tx(struct rtw89_dev *rtwdev, - struct rtw8852b_bb_pmac_info *tx_info, - enum rtw89_phy_idx idx) -{ - rtw89_debug(rtwdev, RTW89_DBG_TSSI, "PMAC Stop Tx"); - if (tx_info->mode == CONT_TX) - rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_PRD, B_PMAC_CTX_EN, 0, idx); - else if (tx_info->mode == PKTS_TX) - rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_PRD, B_PMAC_PTX_EN, 0, idx); -} - -static void rtw8852b_start_pmac_tx(struct rtw89_dev *rtwdev, - struct rtw8852b_bb_pmac_info *tx_info, - enum rtw89_phy_idx idx) -{ - enum rtw8852b_pmac_mode mode = tx_info->mode; - u32 pkt_cnt = tx_info->tx_cnt; - u16 period = tx_info->period; - - if (mode == CONT_TX && !tx_info->is_cck) { - rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_PRD, B_PMAC_CTX_EN, 1, idx); - rtw89_debug(rtwdev, RTW89_DBG_TSSI, "PMAC CTx Start"); - } else if (mode == PKTS_TX) { - rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_PRD, B_PMAC_PTX_EN, 1, idx); - rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_PRD, - B_PMAC_TX_PRD_MSK, period, idx); - rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_CNT, B_PMAC_TX_CNT_MSK, - pkt_cnt, idx); - rtw89_debug(rtwdev, RTW89_DBG_TSSI, "PMAC PTx Start"); - } - - rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_CTRL, B_PMAC_TXEN_DIS, 1, idx); - rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_CTRL, B_PMAC_TXEN_DIS, 0, idx); -} - -void rtw8852b_bb_set_pmac_tx(struct rtw89_dev *rtwdev, - struct rtw8852b_bb_pmac_info *tx_info, - enum rtw89_phy_idx idx) -{ - const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); - - if (!tx_info->en_pmac_tx) { - rtw8852b_stop_pmac_tx(rtwdev, tx_info, idx); - rtw89_phy_write32_idx(rtwdev, R_PD_CTRL, B_PD_HIT_DIS, 0, idx); - if (chan->band_type == RTW89_BAND_2G) - rtw89_phy_write32_clr(rtwdev, R_RXCCA, B_RXCCA_DIS); - return; - } - - rtw89_debug(rtwdev, RTW89_DBG_TSSI, "PMAC Tx Enable"); - - rtw89_phy_write32_idx(rtwdev, R_PMAC_GNT, B_PMAC_GNT_TXEN, 1, idx); - rtw89_phy_write32_idx(rtwdev, R_PMAC_GNT, B_PMAC_GNT_RXEN, 1, idx); - rtw89_phy_write32_idx(rtwdev, R_PMAC_RX_CFG1, B_PMAC_OPT1_MSK, 0x3f, idx); - rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 0, idx); - rtw89_phy_write32_idx(rtwdev, R_PD_CTRL, B_PD_HIT_DIS, 1, idx); - rtw89_phy_write32_set(rtwdev, R_RXCCA, B_RXCCA_DIS); - rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 1, idx); - - rtw8852b_start_pmac_tx(rtwdev, tx_info, idx); -} - -void rtw8852b_bb_set_pmac_pkt_tx(struct rtw89_dev *rtwdev, u8 enable, - u16 tx_cnt, u16 period, u16 tx_time, - enum rtw89_phy_idx idx) -{ - struct rtw8852b_bb_pmac_info tx_info = {0}; - - tx_info.en_pmac_tx = enable; - tx_info.is_cck = 0; - tx_info.mode = PKTS_TX; - tx_info.tx_cnt = tx_cnt; - tx_info.period = period; - tx_info.tx_time = tx_time; - - rtw8852b_bb_set_pmac_tx(rtwdev, &tx_info, idx); -} - -void rtw8852b_bb_set_power(struct rtw89_dev *rtwdev, s16 pwr_dbm, - enum rtw89_phy_idx idx) -{ - rtw89_debug(rtwdev, RTW89_DBG_TSSI, "PMAC CFG Tx PWR = %d", pwr_dbm); - - rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_PWR_EN, 1, idx); - rtw89_phy_write32_idx(rtwdev, R_TXPWR, B_TXPWR_MSK, pwr_dbm, idx); -} - -void rtw8852b_bb_cfg_tx_path(struct rtw89_dev *rtwdev, u8 tx_path) -{ - rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_MOD, 7, RTW89_PHY_0); - - rtw89_debug(rtwdev, RTW89_DBG_TSSI, "PMAC CFG Tx Path = %d", tx_path); - - if (tx_path == RF_PATH_A) { - rtw89_phy_write32_mask(rtwdev, R_TXPATH_SEL, B_TXPATH_SEL_MSK, 1); - rtw89_phy_write32_mask(rtwdev, R_TXNSS_MAP, B_TXNSS_MAP_MSK, 0); - } else if (tx_path == RF_PATH_B) { - rtw89_phy_write32_mask(rtwdev, R_TXPATH_SEL, B_TXPATH_SEL_MSK, 2); - rtw89_phy_write32_mask(rtwdev, R_TXNSS_MAP, B_TXNSS_MAP_MSK, 0); - } else if (tx_path == RF_PATH_AB) { - rtw89_phy_write32_mask(rtwdev, R_TXPATH_SEL, B_TXPATH_SEL_MSK, 3); - rtw89_phy_write32_mask(rtwdev, R_TXNSS_MAP, B_TXNSS_MAP_MSK, 4); - } else { - rtw89_debug(rtwdev, RTW89_DBG_TSSI, "Error Tx Path"); - } -} - -void rtw8852b_bb_tx_mode_switch(struct rtw89_dev *rtwdev, - enum rtw89_phy_idx idx, u8 mode) -{ - if (mode != 0) - return; - - rtw89_debug(rtwdev, RTW89_DBG_TSSI, "Tx mode switch"); - - rtw89_phy_write32_idx(rtwdev, R_PMAC_GNT, B_PMAC_GNT_TXEN, 0, idx); - rtw89_phy_write32_idx(rtwdev, R_PMAC_GNT, B_PMAC_GNT_RXEN, 0, idx); - rtw89_phy_write32_idx(rtwdev, R_PMAC_RX_CFG1, B_PMAC_OPT1_MSK, 0, idx); - rtw89_phy_write32_idx(rtwdev, R_PMAC_RXMOD, B_PMAC_RXMOD_MSK, 0, idx); - rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_DPD_EN, 0, idx); - rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_MOD, 0, idx); - rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_PWR_EN, 0, idx); -} - -void rtw8852b_bb_backup_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx idx, - struct rtw8852b_bb_tssi_bak *bak) -{ - s32 tmp; - - bak->tx_path = rtw89_phy_read32_idx(rtwdev, R_TXPATH_SEL, B_TXPATH_SEL_MSK, idx); - bak->rx_path = rtw89_phy_read32_idx(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, idx); - bak->p0_rfmode = rtw89_phy_read32_idx(rtwdev, R_P0_RFMODE, MASKDWORD, idx); - bak->p0_rfmode_ftm = rtw89_phy_read32_idx(rtwdev, R_P0_RFMODE_FTM_RX, MASKDWORD, idx); - bak->p1_rfmode = rtw89_phy_read32_idx(rtwdev, R_P1_RFMODE, MASKDWORD, idx); - bak->p1_rfmode_ftm = rtw89_phy_read32_idx(rtwdev, R_P1_RFMODE_FTM_RX, MASKDWORD, idx); - tmp = rtw89_phy_read32_idx(rtwdev, R_TXPWR, B_TXPWR_MSK, idx); - bak->tx_pwr = sign_extend32(tmp, 8); -} - -void rtw8852b_bb_restore_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx idx, - const struct rtw8852b_bb_tssi_bak *bak) -{ - rtw89_phy_write32_idx(rtwdev, R_TXPATH_SEL, B_TXPATH_SEL_MSK, bak->tx_path, idx); - if (bak->tx_path == RF_AB) - rtw89_phy_write32_mask(rtwdev, R_TXNSS_MAP, B_TXNSS_MAP_MSK, 0x4); - else - rtw89_phy_write32_mask(rtwdev, R_TXNSS_MAP, B_TXNSS_MAP_MSK, 0x0); - rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, bak->rx_path, idx); - rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_PWR_EN, 1, idx); - rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE, MASKDWORD, bak->p0_rfmode, idx); - rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_FTM_RX, MASKDWORD, bak->p0_rfmode_ftm, idx); - rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE, MASKDWORD, bak->p1_rfmode, idx); - rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_FTM_RX, MASKDWORD, bak->p1_rfmode_ftm, idx); - rtw89_phy_write32_idx(rtwdev, R_TXPWR, B_TXPWR_MSK, bak->tx_pwr, idx); -} - -static void rtw8852b_ctrl_nbtg_bt_tx(struct rtw89_dev *rtwdev, bool en, - enum rtw89_phy_idx phy_idx) -{ - rtw89_phy_write_reg3_tbl(rtwdev, en ? &rtw8852b_btc_preagc_en_defs_tbl : - &rtw8852b_btc_preagc_dis_defs_tbl); -} - -static void rtw8852b_ctrl_btg_bt_rx(struct rtw89_dev *rtwdev, bool en, - enum rtw89_phy_idx phy_idx) -{ - if (en) { - rtw89_phy_write32_mask(rtwdev, R_PATH0_BT_SHARE_V1, - B_PATH0_BT_SHARE_V1, 0x1); - rtw89_phy_write32_mask(rtwdev, R_PATH0_BTG_PATH_V1, - B_PATH0_BTG_PATH_V1, 0x0); - rtw89_phy_write32_mask(rtwdev, R_PATH1_G_LNA6_OP1DB_V1, - B_PATH1_G_LNA6_OP1DB_V1, 0x20); - rtw89_phy_write32_mask(rtwdev, R_PATH1_G_TIA0_LNA6_OP1DB_V1, - B_PATH1_G_TIA0_LNA6_OP1DB_V1, 0x30); - rtw89_phy_write32_mask(rtwdev, R_PATH1_BT_SHARE_V1, - B_PATH1_BT_SHARE_V1, 0x1); - rtw89_phy_write32_mask(rtwdev, R_PATH1_BTG_PATH_V1, - B_PATH1_BTG_PATH_V1, 0x1); - rtw89_phy_write32_mask(rtwdev, R_PMAC_GNT, B_PMAC_GNT_P1, 0x0); - rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_BT_SHARE, 0x1); - rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_BT_SEG0, 0x2); - rtw89_phy_write32_mask(rtwdev, R_BT_DYN_DC_EST_EN_V1, - B_BT_DYN_DC_EST_EN_MSK, 0x1); - rtw89_phy_write32_mask(rtwdev, R_GNT_BT_WGT_EN, B_GNT_BT_WGT_EN, 0x1); - } else { - rtw89_phy_write32_mask(rtwdev, R_PATH0_BT_SHARE_V1, - B_PATH0_BT_SHARE_V1, 0x0); - rtw89_phy_write32_mask(rtwdev, R_PATH0_BTG_PATH_V1, - B_PATH0_BTG_PATH_V1, 0x0); - rtw89_phy_write32_mask(rtwdev, R_PATH1_G_LNA6_OP1DB_V1, - B_PATH1_G_LNA6_OP1DB_V1, 0x1a); - rtw89_phy_write32_mask(rtwdev, R_PATH1_G_TIA0_LNA6_OP1DB_V1, - B_PATH1_G_TIA0_LNA6_OP1DB_V1, 0x2a); - rtw89_phy_write32_mask(rtwdev, R_PATH1_BT_SHARE_V1, - B_PATH1_BT_SHARE_V1, 0x0); - rtw89_phy_write32_mask(rtwdev, R_PATH1_BTG_PATH_V1, - B_PATH1_BTG_PATH_V1, 0x0); - rtw89_phy_write32_mask(rtwdev, R_PMAC_GNT, B_PMAC_GNT_P1, 0xc); - rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_BT_SHARE, 0x0); - rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_BT_SEG0, 0x0); - rtw89_phy_write32_mask(rtwdev, R_BT_DYN_DC_EST_EN_V1, - B_BT_DYN_DC_EST_EN_MSK, 0x1); - rtw89_phy_write32_mask(rtwdev, R_GNT_BT_WGT_EN, B_GNT_BT_WGT_EN, 0x0); - } -} - -void rtw8852b_bb_ctrl_rx_path(struct rtw89_dev *rtwdev, - enum rtw89_rf_path_bit rx_path) -{ - const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); - u32 rst_mask0; - u32 rst_mask1; - - if (rx_path == RF_A) { - rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, 1); - rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_1RCCA_SEG0, 1); - rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_1RCCA_SEG1, 1); - rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT, B_RXHT_MCS_LIMIT, 0); - rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT, B_RXVHT_MCS_LIMIT, 0); - rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_USER_MAX, 4); - rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS, 0); - rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS, 0); - } else if (rx_path == RF_B) { - rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, 2); - rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_1RCCA_SEG0, 2); - rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_1RCCA_SEG1, 2); - rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT, B_RXHT_MCS_LIMIT, 0); - rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT, B_RXVHT_MCS_LIMIT, 0); - rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_USER_MAX, 4); - rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS, 0); - rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS, 0); - } else if (rx_path == RF_AB) { - rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, 3); - rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_1RCCA_SEG0, 3); - rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_1RCCA_SEG1, 3); - rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT, B_RXHT_MCS_LIMIT, 1); - rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT, B_RXVHT_MCS_LIMIT, 1); - rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_USER_MAX, 4); - rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS, 1); - rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS, 1); - } - - rtw8852b_set_gain_offset(rtwdev, chan->subband_type, RTW89_PHY_0); - - if (chan->band_type == RTW89_BAND_2G && - (rx_path == RF_B || rx_path == RF_AB)) - rtw8852b_ctrl_btg_bt_rx(rtwdev, true, RTW89_PHY_0); - else - rtw8852b_ctrl_btg_bt_rx(rtwdev, false, RTW89_PHY_0); - - rst_mask0 = B_P0_TXPW_RSTB_MANON | B_P0_TXPW_RSTB_TSSI; - rst_mask1 = B_P1_TXPW_RSTB_MANON | B_P1_TXPW_RSTB_TSSI; - if (rx_path == RF_A) { - rtw89_phy_write32_mask(rtwdev, R_P0_TXPW_RSTB, rst_mask0, 1); - rtw89_phy_write32_mask(rtwdev, R_P0_TXPW_RSTB, rst_mask0, 3); - } else { - rtw89_phy_write32_mask(rtwdev, R_P1_TXPW_RSTB, rst_mask1, 1); - rtw89_phy_write32_mask(rtwdev, R_P1_TXPW_RSTB, rst_mask1, 3); - } -} - -static void rtw8852b_bb_ctrl_rf_mode_rx_path(struct rtw89_dev *rtwdev, - enum rtw89_rf_path_bit rx_path) -{ - if (rx_path == RF_A) { - rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE, - B_P0_RFMODE_ORI_TXRX_FTM_TX, 0x1233312); - rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE_FTM_RX, - B_P0_RFMODE_FTM_RX, 0x333); - rtw89_phy_write32_mask(rtwdev, R_P1_RFMODE, - B_P1_RFMODE_ORI_TXRX_FTM_TX, 0x1111111); - rtw89_phy_write32_mask(rtwdev, R_P1_RFMODE_FTM_RX, - B_P1_RFMODE_FTM_RX, 0x111); - } else if (rx_path == RF_B) { - rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE, - B_P0_RFMODE_ORI_TXRX_FTM_TX, 0x1111111); - rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE_FTM_RX, - B_P0_RFMODE_FTM_RX, 0x111); - rtw89_phy_write32_mask(rtwdev, R_P1_RFMODE, - B_P1_RFMODE_ORI_TXRX_FTM_TX, 0x1233312); - rtw89_phy_write32_mask(rtwdev, R_P1_RFMODE_FTM_RX, - B_P1_RFMODE_FTM_RX, 0x333); - } else if (rx_path == RF_AB) { - rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE, - B_P0_RFMODE_ORI_TXRX_FTM_TX, 0x1233312); - rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE_FTM_RX, - B_P0_RFMODE_FTM_RX, 0x333); - rtw89_phy_write32_mask(rtwdev, R_P1_RFMODE, - B_P1_RFMODE_ORI_TXRX_FTM_TX, 0x1233312); - rtw89_phy_write32_mask(rtwdev, R_P1_RFMODE_FTM_RX, - B_P1_RFMODE_FTM_RX, 0x333); - } -} - -static void rtw8852b_bb_cfg_txrx_path(struct rtw89_dev *rtwdev) -{ - struct rtw89_hal *hal = &rtwdev->hal; - enum rtw89_rf_path_bit rx_path = hal->antenna_rx ? hal->antenna_rx : RF_AB; - - rtw8852b_bb_ctrl_rx_path(rtwdev, rx_path); - rtw8852b_bb_ctrl_rf_mode_rx_path(rtwdev, rx_path); - - if (rtwdev->hal.rx_nss == 1) { - rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT, B_RXHT_MCS_LIMIT, 0); - rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT, B_RXVHT_MCS_LIMIT, 0); - rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS, 0); - rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS, 0); - } else { - rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT, B_RXHT_MCS_LIMIT, 1); - rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT, B_RXVHT_MCS_LIMIT, 1); - rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS, 1); - rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS, 1); - } - - rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_MOD, 0x0, RTW89_PHY_0); -} - -static u8 rtw8852b_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path) -{ - if (rtwdev->is_tssi_mode[rf_path]) { - u32 addr = 0x1c10 + (rf_path << 13); - - return rtw89_phy_read32_mask(rtwdev, addr, 0x3F000000); - } - - rtw89_write_rf(rtwdev, rf_path, RR_TM, RR_TM_TRI, 0x1); - rtw89_write_rf(rtwdev, rf_path, RR_TM, RR_TM_TRI, 0x0); - rtw89_write_rf(rtwdev, rf_path, RR_TM, RR_TM_TRI, 0x1); - - fsleep(200); - - return rtw89_read_rf(rtwdev, rf_path, RR_TM, RR_TM_VAL); -} - static void rtw8852b_btc_set_rfe(struct rtw89_dev *rtwdev) { const struct rtw89_btc_ver *ver = rtwdev->btc.ver; @@ -2402,15 +841,15 @@ static void rtw8852b_btc_set_wl_rx_gain(struct rtw89_dev *rtwdev, u32 level) switch (level) { case 0: /* original */ default: - rtw8852b_ctrl_nbtg_bt_tx(rtwdev, false, RTW89_PHY_0); + rtw8852bx_ctrl_nbtg_bt_tx(rtwdev, false, RTW89_PHY_0); btc->dm.wl_lna2 = 0; break; case 1: /* for FDD free-run */ - rtw8852b_ctrl_nbtg_bt_tx(rtwdev, true, RTW89_PHY_0); + rtw8852bx_ctrl_nbtg_bt_tx(rtwdev, true, RTW89_PHY_0); btc->dm.wl_lna2 = 0; break; case 2: /* for BTG Co-Rx*/ - rtw8852b_ctrl_nbtg_bt_tx(rtwdev, false, RTW89_PHY_0); + rtw8852bx_ctrl_nbtg_bt_tx(rtwdev, false, RTW89_PHY_0); btc->dm.wl_lna2 = 1; break; } @@ -2418,105 +857,19 @@ static void rtw8852b_btc_set_wl_rx_gain(struct rtw89_dev *rtwdev, u32 level) rtw8852b_btc_set_wl_lna2(rtwdev, btc->dm.wl_lna2); } -static void rtw8852b_fill_freq_with_ppdu(struct rtw89_dev *rtwdev, - struct rtw89_rx_phy_ppdu *phy_ppdu, - struct ieee80211_rx_status *status) -{ - u16 chan = phy_ppdu->chan_idx; - enum nl80211_band band; - u8 ch; - - if (chan == 0) - return; - - rtw89_decode_chan_idx(rtwdev, chan, &ch, &band); - status->freq = ieee80211_channel_to_frequency(ch, band); - status->band = band; -} - -static void rtw8852b_query_ppdu(struct rtw89_dev *rtwdev, - struct rtw89_rx_phy_ppdu *phy_ppdu, - struct ieee80211_rx_status *status) -{ - u8 path; - u8 *rx_power = phy_ppdu->rssi; - - status->signal = RTW89_RSSI_RAW_TO_DBM(max(rx_power[RF_PATH_A], rx_power[RF_PATH_B])); - for (path = 0; path < rtwdev->chip->rf_path_num; path++) { - status->chains |= BIT(path); - status->chain_signal[path] = RTW89_RSSI_RAW_TO_DBM(rx_power[path]); - } - if (phy_ppdu->valid) - rtw8852b_fill_freq_with_ppdu(rtwdev, phy_ppdu, status); -} - -static int rtw8852b_mac_enable_bb_rf(struct rtw89_dev *rtwdev) -{ - int ret; - - rtw89_write8_set(rtwdev, R_AX_SYS_FUNC_EN, - B_AX_FEN_BBRSTB | B_AX_FEN_BB_GLB_RSTN); - rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_ON_CTRL0, B_AX_REG_ZCDC_H_MASK, 0x1); - rtw89_write32_set(rtwdev, R_AX_WLRF_CTRL, B_AX_AFC_AFEDIG); - rtw89_write32_clr(rtwdev, R_AX_WLRF_CTRL, B_AX_AFC_AFEDIG); - rtw89_write32_set(rtwdev, R_AX_WLRF_CTRL, B_AX_AFC_AFEDIG); - - ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S0, 0xC7, - FULL_BIT_MASK); - if (ret) - return ret; - - ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S1, 0xC7, - FULL_BIT_MASK); - if (ret) - return ret; - - rtw89_write8(rtwdev, R_AX_PHYREG_SET, PHYREG_SET_XYN_CYCLE); - - return 0; -} - -static int rtw8852b_mac_disable_bb_rf(struct rtw89_dev *rtwdev) -{ - u8 wl_rfc_s0; - u8 wl_rfc_s1; - int ret; - - rtw89_write32_clr(rtwdev, R_AX_WLRF_CTRL, B_AX_AFC_AFEDIG); - rtw89_write8_clr(rtwdev, R_AX_SYS_FUNC_EN, - B_AX_FEN_BBRSTB | B_AX_FEN_BB_GLB_RSTN); - - ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_WL_RFC_S0, &wl_rfc_s0); - if (ret) - return ret; - wl_rfc_s0 &= ~XTAL_SI_RF00S_EN; - ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S0, wl_rfc_s0, - FULL_BIT_MASK); - if (ret) - return ret; - - ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_WL_RFC_S1, &wl_rfc_s1); - if (ret) - return ret; - wl_rfc_s1 &= ~XTAL_SI_RF10S_EN; - ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S1, wl_rfc_s1, - FULL_BIT_MASK); - return ret; -} - static const struct rtw89_chip_ops rtw8852b_chip_ops = { - .enable_bb_rf = rtw8852b_mac_enable_bb_rf, - .disable_bb_rf = rtw8852b_mac_disable_bb_rf, + .enable_bb_rf = rtw8852bx_mac_enable_bb_rf, + .disable_bb_rf = rtw8852bx_mac_disable_bb_rf, .bb_preinit = NULL, .bb_postinit = NULL, .bb_reset = rtw8852b_bb_reset, - .bb_sethw = rtw8852b_bb_sethw, + .bb_sethw = rtw8852bx_bb_sethw, .read_rf = rtw89_phy_read_rf_v1, .write_rf = rtw89_phy_write_rf_v1, .set_channel = rtw8852b_set_channel, .set_channel_help = rtw8852b_set_channel_help, - .read_efuse = rtw8852b_read_efuse, - .read_phycap = rtw8852b_read_phycap, + .read_efuse = rtw8852bx_read_efuse, + .read_phycap = rtw8852bx_read_phycap, .fem_setup = NULL, .rfe_gpio = NULL, .rfk_hw_init = NULL, @@ -2526,16 +879,16 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .rfk_band_changed = rtw8852b_rfk_band_changed, .rfk_scan = rtw8852b_rfk_scan, .rfk_track = rtw8852b_rfk_track, - .power_trim = rtw8852b_power_trim, - .set_txpwr = rtw8852b_set_txpwr, - .set_txpwr_ctrl = rtw8852b_set_txpwr_ctrl, - .init_txpwr_unit = rtw8852b_init_txpwr_unit, - .get_thermal = rtw8852b_get_thermal, - .ctrl_btg_bt_rx = rtw8852b_ctrl_btg_bt_rx, - .query_ppdu = rtw8852b_query_ppdu, - .ctrl_nbtg_bt_tx = rtw8852b_ctrl_nbtg_bt_tx, - .cfg_txrx_path = rtw8852b_bb_cfg_txrx_path, - .set_txpwr_ul_tb_offset = rtw8852b_set_txpwr_ul_tb_offset, + .power_trim = rtw8852bx_power_trim, + .set_txpwr = rtw8852bx_set_txpwr, + .set_txpwr_ctrl = rtw8852bx_set_txpwr_ctrl, + .init_txpwr_unit = rtw8852bx_init_txpwr_unit, + .get_thermal = rtw8852bx_get_thermal, + .ctrl_btg_bt_rx = rtw8852bx_ctrl_btg_bt_rx, + .query_ppdu = rtw8852bx_query_ppdu, + .ctrl_nbtg_bt_tx = rtw8852bx_ctrl_nbtg_bt_tx, + .cfg_txrx_path = rtw8852bx_bb_cfg_txrx_path, + .set_txpwr_ul_tb_offset = rtw8852bx_set_txpwr_ul_tb_offset, .pwr_on_func = rtw8852b_pwr_on_func, .pwr_off_func = rtw8852b_pwr_off_func, .query_rxdesc = rtw89_core_query_rxdesc, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.h b/drivers/net/wireless/realtek/rtw89/rtw8852b.h index 4f9b3d476879..5ec7180fd355 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.h @@ -10,128 +10,6 @@ #define RF_PATH_NUM_8852B 2 #define BB_PATH_NUM_8852B 2 -enum rtw8852b_pmac_mode { - NONE_TEST, - PKTS_TX, - PKTS_RX, - CONT_TX -}; - -struct rtw8852b_u_efuse { - u8 rsvd[0x88]; - u8 mac_addr[ETH_ALEN]; -}; - -struct rtw8852b_e_efuse { - u8 mac_addr[ETH_ALEN]; -}; - -struct rtw8852b_tssi_offset { - u8 cck_tssi[TSSI_CCK_CH_GROUP_NUM]; - u8 bw40_tssi[TSSI_MCS_2G_CH_GROUP_NUM]; - u8 rsvd[7]; - u8 bw40_1s_tssi_5g[TSSI_MCS_5G_CH_GROUP_NUM]; -} __packed; - -struct rtw8852b_efuse { - u8 rsvd[0x210]; - struct rtw8852b_tssi_offset path_a_tssi; - u8 rsvd1[10]; - struct rtw8852b_tssi_offset path_b_tssi; - u8 rsvd2[94]; - u8 channel_plan; - u8 xtal_k; - u8 rsvd3; - u8 iqk_lck; - u8 rsvd4[5]; - u8 reg_setting:2; - u8 tx_diversity:1; - u8 rx_diversity:2; - u8 ac_mode:1; - u8 module_type:2; - u8 rsvd5; - u8 shared_ant:1; - u8 coex_type:3; - u8 ant_iso:1; - u8 radio_on_off:1; - u8 rsvd6:2; - u8 eeprom_version; - u8 customer_id; - u8 tx_bb_swing_2g; - u8 tx_bb_swing_5g; - u8 tx_cali_pwr_trk_mode; - u8 trx_path_selection; - u8 rfe_type; - u8 country_code[2]; - u8 rsvd7[3]; - u8 path_a_therm; - u8 path_b_therm; - u8 rsvd8[2]; - u8 rx_gain_2g_ofdm; - u8 rsvd9; - u8 rx_gain_2g_cck; - u8 rsvd10; - u8 rx_gain_5g_low; - u8 rsvd11; - u8 rx_gain_5g_mid; - u8 rsvd12; - u8 rx_gain_5g_high; - u8 rsvd13[35]; - u8 path_a_cck_pwr_idx[6]; - u8 path_a_bw40_1tx_pwr_idx[5]; - u8 path_a_ofdm_1tx_pwr_idx_diff:4; - u8 path_a_bw20_1tx_pwr_idx_diff:4; - u8 path_a_bw20_2tx_pwr_idx_diff:4; - u8 path_a_bw40_2tx_pwr_idx_diff:4; - u8 path_a_cck_2tx_pwr_idx_diff:4; - u8 path_a_ofdm_2tx_pwr_idx_diff:4; - u8 rsvd14[0xf2]; - union { - struct rtw8852b_u_efuse u; - struct rtw8852b_e_efuse e; - }; -} __packed; - -struct rtw8852b_bb_pmac_info { - u8 en_pmac_tx:1; - u8 is_cck:1; - u8 mode:3; - u8 rsvd:3; - u16 tx_cnt; - u16 period; - u16 tx_time; - u8 duty_cycle; -}; - -struct rtw8852b_bb_tssi_bak { - u8 tx_path; - u8 rx_path; - u32 p0_rfmode; - u32 p0_rfmode_ftm; - u32 p1_rfmode; - u32 p1_rfmode_ftm; - s16 tx_pwr; /* S9 */ -}; - extern const struct rtw89_chip_info rtw8852b_chip_info; -void rtw8852b_bb_set_plcp_tx(struct rtw89_dev *rtwdev); -void rtw8852b_bb_set_pmac_tx(struct rtw89_dev *rtwdev, - struct rtw8852b_bb_pmac_info *tx_info, - enum rtw89_phy_idx idx); -void rtw8852b_bb_set_pmac_pkt_tx(struct rtw89_dev *rtwdev, u8 enable, - u16 tx_cnt, u16 period, u16 tx_time, - enum rtw89_phy_idx idx); -void rtw8852b_bb_set_power(struct rtw89_dev *rtwdev, s16 pwr_dbm, - enum rtw89_phy_idx idx); -void rtw8852b_bb_cfg_tx_path(struct rtw89_dev *rtwdev, u8 tx_path); -void rtw8852b_bb_ctrl_rx_path(struct rtw89_dev *rtwdev, - enum rtw89_rf_path_bit rx_path); -void rtw8852b_bb_tx_mode_switch(struct rtw89_dev *rtwdev, - enum rtw89_phy_idx idx, u8 mode); -void rtw8852b_bb_backup_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx idx, - struct rtw8852b_bb_tssi_bak *bak); -void rtw8852b_bb_restore_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx idx, - const struct rtw8852b_bb_tssi_bak *bak); - #endif diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c new file mode 100644 index 000000000000..0826d257ddba --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c @@ -0,0 +1,1701 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2024 Realtek Corporation + */ + +#include "debug.h" +#include "mac.h" +#include "phy.h" +#include "reg.h" +#include "rtw8852b_common.h" + +static const struct rtw89_reg3_def rtw8852bx_pmac_ht20_mcs7_tbl[] = { + {0x4580, 0x0000ffff, 0x0}, + {0x4580, 0xffff0000, 0x0}, + {0x4584, 0x0000ffff, 0x0}, + {0x4584, 0xffff0000, 0x0}, + {0x4580, 0x0000ffff, 0x1}, + {0x4578, 0x00ffffff, 0x2018b}, + {0x4570, 0x03ffffff, 0x7}, + {0x4574, 0x03ffffff, 0x32407}, + {0x45b8, 0x00000010, 0x0}, + {0x45b8, 0x00000100, 0x0}, + {0x45b8, 0x00000080, 0x0}, + {0x45b8, 0x00000008, 0x0}, + {0x45a0, 0x0000ff00, 0x0}, + {0x45a0, 0xff000000, 0x1}, + {0x45a4, 0x0000ff00, 0x2}, + {0x45a4, 0xff000000, 0x3}, + {0x45b8, 0x00000020, 0x0}, + {0x4568, 0xe0000000, 0x0}, + {0x45b8, 0x00000002, 0x1}, + {0x456c, 0xe0000000, 0x0}, + {0x45b4, 0x00006000, 0x0}, + {0x45b4, 0x00001800, 0x1}, + {0x45b8, 0x00000040, 0x0}, + {0x45b8, 0x00000004, 0x0}, + {0x45b8, 0x00000200, 0x0}, + {0x4598, 0xf8000000, 0x0}, + {0x45b8, 0x00100000, 0x0}, + {0x45a8, 0x00000fc0, 0x0}, + {0x45b8, 0x00200000, 0x0}, + {0x45b0, 0x00000038, 0x0}, + {0x45b0, 0x000001c0, 0x0}, + {0x45a0, 0x000000ff, 0x0}, + {0x45b8, 0x00400000, 0x0}, + {0x4590, 0x000007ff, 0x0}, + {0x45b0, 0x00000e00, 0x0}, + {0x45ac, 0x0000001f, 0x0}, + {0x45b8, 0x00800000, 0x0}, + {0x45a8, 0x0003f000, 0x0}, + {0x45b8, 0x01000000, 0x0}, + {0x45b0, 0x00007000, 0x0}, + {0x45b0, 0x00038000, 0x0}, + {0x45a0, 0x00ff0000, 0x0}, + {0x45b8, 0x02000000, 0x0}, + {0x4590, 0x003ff800, 0x0}, + {0x45b0, 0x001c0000, 0x0}, + {0x45ac, 0x000003e0, 0x0}, + {0x45b8, 0x04000000, 0x0}, + {0x45a8, 0x00fc0000, 0x0}, + {0x45b8, 0x08000000, 0x0}, + {0x45b0, 0x00e00000, 0x0}, + {0x45b0, 0x07000000, 0x0}, + {0x45a4, 0x000000ff, 0x0}, + {0x45b8, 0x10000000, 0x0}, + {0x4594, 0x000007ff, 0x0}, + {0x45b0, 0x38000000, 0x0}, + {0x45ac, 0x00007c00, 0x0}, + {0x45b8, 0x20000000, 0x0}, + {0x45a8, 0x3f000000, 0x0}, + {0x45b8, 0x40000000, 0x0}, + {0x45b4, 0x00000007, 0x0}, + {0x45b4, 0x00000038, 0x0}, + {0x45a4, 0x00ff0000, 0x0}, + {0x45b8, 0x80000000, 0x0}, + {0x4594, 0x003ff800, 0x0}, + {0x45b4, 0x000001c0, 0x0}, + {0x4598, 0xf8000000, 0x0}, + {0x45b8, 0x00100000, 0x0}, + {0x45a8, 0x00000fc0, 0x7}, + {0x45b8, 0x00200000, 0x0}, + {0x45b0, 0x00000038, 0x0}, + {0x45b0, 0x000001c0, 0x0}, + {0x45a0, 0x000000ff, 0x0}, + {0x45b4, 0x06000000, 0x0}, + {0x45b0, 0x00000007, 0x0}, + {0x45b8, 0x00080000, 0x0}, + {0x45a8, 0x0000003f, 0x0}, + {0x457c, 0xffe00000, 0x1}, + {0x4530, 0xffffffff, 0x0}, + {0x4588, 0x00003fff, 0x0}, + {0x4598, 0x000001ff, 0x0}, + {0x4534, 0xffffffff, 0x0}, + {0x4538, 0xffffffff, 0x0}, + {0x453c, 0xffffffff, 0x0}, + {0x4588, 0x0fffc000, 0x0}, + {0x4598, 0x0003fe00, 0x0}, + {0x4540, 0xffffffff, 0x0}, + {0x4544, 0xffffffff, 0x0}, + {0x4548, 0xffffffff, 0x0}, + {0x458c, 0x00003fff, 0x0}, + {0x4598, 0x07fc0000, 0x0}, + {0x454c, 0xffffffff, 0x0}, + {0x4550, 0xffffffff, 0x0}, + {0x4554, 0xffffffff, 0x0}, + {0x458c, 0x0fffc000, 0x0}, + {0x459c, 0x000001ff, 0x0}, + {0x4558, 0xffffffff, 0x0}, + {0x455c, 0xffffffff, 0x0}, + {0x4530, 0xffffffff, 0x4e790001}, + {0x4588, 0x00003fff, 0x0}, + {0x4598, 0x000001ff, 0x1}, + {0x4534, 0xffffffff, 0x0}, + {0x4538, 0xffffffff, 0x4b}, + {0x45ac, 0x38000000, 0x7}, + {0x4588, 0xf0000000, 0x0}, + {0x459c, 0x7e000000, 0x0}, + {0x45b8, 0x00040000, 0x0}, + {0x45b8, 0x00020000, 0x0}, + {0x4590, 0xffc00000, 0x0}, + {0x45b8, 0x00004000, 0x0}, + {0x4578, 0xff000000, 0x0}, + {0x45b8, 0x00000400, 0x0}, + {0x45b8, 0x00000800, 0x0}, + {0x45b8, 0x00001000, 0x0}, + {0x45b8, 0x00002000, 0x0}, + {0x45b4, 0x00018000, 0x0}, + {0x45ac, 0x07800000, 0x0}, + {0x45b4, 0x00000600, 0x2}, + {0x459c, 0x0001fe00, 0x80}, + {0x45ac, 0x00078000, 0x3}, + {0x459c, 0x01fe0000, 0x1}, +}; + +static const struct rtw89_reg3_def rtw8852bx_btc_preagc_en_defs[] = { + {0x46D0, GENMASK(1, 0), 0x3}, + {0x4790, GENMASK(1, 0), 0x3}, + {0x4AD4, GENMASK(31, 0), 0xf}, + {0x4AE0, GENMASK(31, 0), 0xf}, + {0x4688, GENMASK(31, 24), 0x80}, + {0x476C, GENMASK(31, 24), 0x80}, + {0x4694, GENMASK(7, 0), 0x80}, + {0x4694, GENMASK(15, 8), 0x80}, + {0x4778, GENMASK(7, 0), 0x80}, + {0x4778, GENMASK(15, 8), 0x80}, + {0x4AE4, GENMASK(23, 0), 0x780D1E}, + {0x4AEC, GENMASK(23, 0), 0x780D1E}, + {0x469C, GENMASK(31, 26), 0x34}, + {0x49F0, GENMASK(31, 26), 0x34}, +}; + +static DECLARE_PHY_REG3_TBL(rtw8852bx_btc_preagc_en_defs); + +static const struct rtw89_reg3_def rtw8852bx_btc_preagc_dis_defs[] = { + {0x46D0, GENMASK(1, 0), 0x0}, + {0x4790, GENMASK(1, 0), 0x0}, + {0x4AD4, GENMASK(31, 0), 0x60}, + {0x4AE0, GENMASK(31, 0), 0x60}, + {0x4688, GENMASK(31, 24), 0x1a}, + {0x476C, GENMASK(31, 24), 0x1a}, + {0x4694, GENMASK(7, 0), 0x2a}, + {0x4694, GENMASK(15, 8), 0x2a}, + {0x4778, GENMASK(7, 0), 0x2a}, + {0x4778, GENMASK(15, 8), 0x2a}, + {0x4AE4, GENMASK(23, 0), 0x79E99E}, + {0x4AEC, GENMASK(23, 0), 0x79E99E}, + {0x469C, GENMASK(31, 26), 0x26}, + {0x49F0, GENMASK(31, 26), 0x26}, +}; + +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) +{ + struct rtw89_tssi_info *tssi = &rtwdev->tssi; + struct rtw8852bx_tssi_offset *ofst[] = {&map->path_a_tssi, &map->path_b_tssi}; + u8 i, j; + + tssi->thermal[RF_PATH_A] = map->path_a_therm; + tssi->thermal[RF_PATH_B] = map->path_b_therm; + + for (i = 0; i < RF_PATH_NUM_8852BX; i++) { + memcpy(tssi->tssi_cck[i], ofst[i]->cck_tssi, + sizeof(ofst[i]->cck_tssi)); + + for (j = 0; j < TSSI_CCK_CH_GROUP_NUM; j++) + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][EFUSE] path=%d cck[%d]=0x%x\n", + i, j, tssi->tssi_cck[i][j]); + + memcpy(tssi->tssi_mcs[i], ofst[i]->bw40_tssi, + sizeof(ofst[i]->bw40_tssi)); + memcpy(tssi->tssi_mcs[i] + TSSI_MCS_2G_CH_GROUP_NUM, + ofst[i]->bw40_1s_tssi_5g, sizeof(ofst[i]->bw40_1s_tssi_5g)); + + for (j = 0; j < TSSI_MCS_CH_GROUP_NUM; j++) + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][EFUSE] path=%d mcs[%d]=0x%x\n", + i, j, tssi->tssi_mcs[i][j]); + } +} + +static bool _decode_efuse_gain(u8 data, s8 *high, s8 *low) +{ + if (high) + *high = sign_extend32(FIELD_GET(GENMASK(7, 4), data), 3); + if (low) + *low = sign_extend32(FIELD_GET(GENMASK(3, 0), data), 3); + + return data != 0xff; +} + +static void rtw8852bx_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev, + struct rtw8852bx_efuse *map) +{ + struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain; + bool valid = false; + + valid |= _decode_efuse_gain(map->rx_gain_2g_cck, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_2G_CCK], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_2G_CCK]); + valid |= _decode_efuse_gain(map->rx_gain_2g_ofdm, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_2G_OFDM], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_2G_OFDM]); + valid |= _decode_efuse_gain(map->rx_gain_5g_low, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_LOW], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_LOW]); + valid |= _decode_efuse_gain(map->rx_gain_5g_mid, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_MID], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_MID]); + valid |= _decode_efuse_gain(map->rx_gain_5g_high, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_HIGH], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_HIGH]); + + gain->offset_valid = valid; +} + +static int __rtw8852bx_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, + enum rtw89_efuse_block block) +{ + struct rtw89_efuse *efuse = &rtwdev->efuse; + struct rtw8852bx_efuse *map; + + map = (struct rtw8852bx_efuse *)log_map; + + efuse->country_code[0] = map->country_code[0]; + efuse->country_code[1] = map->country_code[1]; + rtw8852bx_efuse_parsing_tssi(rtwdev, map); + rtw8852bx_efuse_parsing_gain_offset(rtwdev, map); + + switch (rtwdev->hci.type) { + case RTW89_HCI_TYPE_PCIE: + rtw8852be_efuse_parsing(efuse, map); + break; + default: + return -EOPNOTSUPP; + } + + rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); + + return 0; +} + +static void rtw8852bx_phycap_parsing_power_cal(struct rtw89_dev *rtwdev, u8 *phycap_map) +{ +#define PWR_K_CHK_OFFSET 0x5E9 +#define PWR_K_CHK_VALUE 0xAA + u32 offset = PWR_K_CHK_OFFSET - rtwdev->chip->phycap_addr; + + if (phycap_map[offset] == PWR_K_CHK_VALUE) + rtwdev->efuse.power_k_valid = true; +} + +static void rtw8852bx_phycap_parsing_tssi(struct rtw89_dev *rtwdev, u8 *phycap_map) +{ + struct rtw89_tssi_info *tssi = &rtwdev->tssi; + static const u32 tssi_trim_addr[RF_PATH_NUM_8852BX] = {0x5D6, 0x5AB}; + u32 addr = rtwdev->chip->phycap_addr; + bool pg = false; + u32 ofst; + u8 i, j; + + for (i = 0; i < RF_PATH_NUM_8852BX; i++) { + for (j = 0; j < TSSI_TRIM_CH_GROUP_NUM; j++) { + /* addrs are in decreasing order */ + ofst = tssi_trim_addr[i] - addr - j; + tssi->tssi_trim[i][j] = phycap_map[ofst]; + + if (phycap_map[ofst] != 0xff) + pg = true; + } + } + + if (!pg) { + memset(tssi->tssi_trim, 0, sizeof(tssi->tssi_trim)); + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM] no PG, set all trim info to 0\n"); + } + + for (i = 0; i < RF_PATH_NUM_8852BX; i++) + for (j = 0; j < TSSI_TRIM_CH_GROUP_NUM; j++) + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI] path=%d idx=%d trim=0x%x addr=0x%x\n", + i, j, tssi->tssi_trim[i][j], + tssi_trim_addr[i] - j); +} + +static void rtw8852bx_phycap_parsing_thermal_trim(struct rtw89_dev *rtwdev, + u8 *phycap_map) +{ + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + static const u32 thm_trim_addr[RF_PATH_NUM_8852BX] = {0x5DF, 0x5DC}; + u32 addr = rtwdev->chip->phycap_addr; + u8 i; + + for (i = 0; i < RF_PATH_NUM_8852BX; i++) { + info->thermal_trim[i] = phycap_map[thm_trim_addr[i] - addr]; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[THERMAL][TRIM] path=%d thermal_trim=0x%x\n", + i, info->thermal_trim[i]); + + if (info->thermal_trim[i] != 0xff) + info->pg_thermal_trim = true; + } +} + +static void rtw8852bx_thermal_trim(struct rtw89_dev *rtwdev) +{ +#define __thm_setting(raw) \ +({ \ + u8 __v = (raw); \ + ((__v & 0x1) << 3) | ((__v & 0x1f) >> 1); \ +}) + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + u8 i, val; + + if (!info->pg_thermal_trim) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[THERMAL][TRIM] no PG, do nothing\n"); + + return; + } + + for (i = 0; i < RF_PATH_NUM_8852BX; i++) { + val = __thm_setting(info->thermal_trim[i]); + rtw89_write_rf(rtwdev, i, RR_TM2, RR_TM2_OFF, val); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[THERMAL][TRIM] path=%d thermal_setting=0x%x\n", + i, val); + } +#undef __thm_setting +} + +static void rtw8852bx_phycap_parsing_pa_bias_trim(struct rtw89_dev *rtwdev, + u8 *phycap_map) +{ + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + static const u32 pabias_trim_addr[RF_PATH_NUM_8852BX] = {0x5DE, 0x5DB}; + u32 addr = rtwdev->chip->phycap_addr; + u8 i; + + for (i = 0; i < RF_PATH_NUM_8852BX; i++) { + info->pa_bias_trim[i] = phycap_map[pabias_trim_addr[i] - addr]; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[PA_BIAS][TRIM] path=%d pa_bias_trim=0x%x\n", + i, info->pa_bias_trim[i]); + + if (info->pa_bias_trim[i] != 0xff) + info->pg_pa_bias_trim = true; + } +} + +static void rtw8852bx_pa_bias_trim(struct rtw89_dev *rtwdev) +{ + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + u8 pabias_2g, pabias_5g; + u8 i; + + if (!info->pg_pa_bias_trim) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[PA_BIAS][TRIM] no PG, do nothing\n"); + + return; + } + + for (i = 0; i < RF_PATH_NUM_8852BX; i++) { + pabias_2g = FIELD_GET(GENMASK(3, 0), info->pa_bias_trim[i]); + pabias_5g = FIELD_GET(GENMASK(7, 4), info->pa_bias_trim[i]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[PA_BIAS][TRIM] path=%d 2G=0x%x 5G=0x%x\n", + i, pabias_2g, pabias_5g); + + rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASA_TXG, pabias_2g); + rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASA_TXA, pabias_5g); + } +} + +static void rtw8852bx_phycap_parsing_gain_comp(struct rtw89_dev *rtwdev, u8 *phycap_map) +{ + static const u32 comp_addrs[][RTW89_SUBBAND_2GHZ_5GHZ_NR] = { + {0x5BB, 0x5BA, 0, 0x5B9, 0x5B8}, + {0x590, 0x58F, 0, 0x58E, 0x58D}, + }; + struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain; + u32 phycap_addr = rtwdev->chip->phycap_addr; + bool valid = false; + int path, i; + u8 data; + + for (path = 0; path < 2; path++) + for (i = 0; i < RTW89_SUBBAND_2GHZ_5GHZ_NR; i++) { + if (comp_addrs[path][i] == 0) + continue; + + data = phycap_map[comp_addrs[path][i] - phycap_addr]; + valid |= _decode_efuse_gain(data, NULL, + &gain->comp[path][i]); + } + + gain->comp_valid = valid; +} + +static int __rtw8852bx_read_phycap(struct rtw89_dev *rtwdev, u8 *phycap_map) +{ + rtw8852bx_phycap_parsing_power_cal(rtwdev, phycap_map); + rtw8852bx_phycap_parsing_tssi(rtwdev, phycap_map); + rtw8852bx_phycap_parsing_thermal_trim(rtwdev, phycap_map); + rtw8852bx_phycap_parsing_pa_bias_trim(rtwdev, phycap_map); + rtw8852bx_phycap_parsing_gain_comp(rtwdev, phycap_map); + + return 0; +} + +static void __rtw8852bx_power_trim(struct rtw89_dev *rtwdev) +{ + rtw8852bx_thermal_trim(rtwdev); + rtw8852bx_pa_bias_trim(rtwdev); +} + +static void __rtw8852bx_set_channel_mac(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + u8 mac_idx) +{ + u32 rf_mod = rtw89_mac_reg_by_idx(rtwdev, R_AX_WMAC_RFMOD, mac_idx); + u32 sub_carr = rtw89_mac_reg_by_idx(rtwdev, R_AX_TX_SUB_CARRIER_VALUE, mac_idx); + u32 chk_rate = rtw89_mac_reg_by_idx(rtwdev, R_AX_TXRATE_CHK, mac_idx); + u8 txsc20 = 0, txsc40 = 0; + + switch (chan->band_width) { + case RTW89_CHANNEL_WIDTH_80: + txsc40 = rtw89_phy_get_txsc(rtwdev, chan, RTW89_CHANNEL_WIDTH_40); + fallthrough; + case RTW89_CHANNEL_WIDTH_40: + txsc20 = rtw89_phy_get_txsc(rtwdev, chan, RTW89_CHANNEL_WIDTH_20); + break; + default: + break; + } + + switch (chan->band_width) { + case RTW89_CHANNEL_WIDTH_80: + rtw89_write8_mask(rtwdev, rf_mod, B_AX_WMAC_RFMOD_MASK, BIT(1)); + rtw89_write32(rtwdev, sub_carr, txsc20 | (txsc40 << 4)); + break; + case RTW89_CHANNEL_WIDTH_40: + rtw89_write8_mask(rtwdev, rf_mod, B_AX_WMAC_RFMOD_MASK, BIT(0)); + rtw89_write32(rtwdev, sub_carr, txsc20); + break; + case RTW89_CHANNEL_WIDTH_20: + rtw89_write8_clr(rtwdev, rf_mod, B_AX_WMAC_RFMOD_MASK); + rtw89_write32(rtwdev, sub_carr, 0); + break; + default: + break; + } + + if (chan->channel > 14) { + rtw89_write8_clr(rtwdev, chk_rate, B_AX_BAND_MODE); + rtw89_write8_set(rtwdev, chk_rate, + B_AX_CHECK_CCK_EN | B_AX_RTS_LIMIT_IN_OFDM6); + } else { + rtw89_write8_set(rtwdev, chk_rate, B_AX_BAND_MODE); + rtw89_write8_clr(rtwdev, chk_rate, + B_AX_CHECK_CCK_EN | B_AX_RTS_LIMIT_IN_OFDM6); + } +} + +static const u32 rtw8852bx_sco_barker_threshold[14] = { + 0x1cfea, 0x1d0e1, 0x1d1d7, 0x1d2cd, 0x1d3c3, 0x1d4b9, 0x1d5b0, 0x1d6a6, + 0x1d79c, 0x1d892, 0x1d988, 0x1da7f, 0x1db75, 0x1ddc4 +}; + +static const u32 rtw8852bx_sco_cck_threshold[14] = { + 0x27de3, 0x27f35, 0x28088, 0x281da, 0x2832d, 0x2847f, 0x285d2, 0x28724, + 0x28877, 0x289c9, 0x28b1c, 0x28c6e, 0x28dc1, 0x290ed +}; + +static void rtw8852bx_ctrl_sco_cck(struct rtw89_dev *rtwdev, u8 primary_ch) +{ + u8 ch_element = primary_ch - 1; + + rtw89_phy_write32_mask(rtwdev, R_RXSCOBC, B_RXSCOBC_TH, + rtw8852bx_sco_barker_threshold[ch_element]); + rtw89_phy_write32_mask(rtwdev, R_RXSCOCCK, B_RXSCOCCK_TH, + rtw8852bx_sco_cck_threshold[ch_element]); +} + +static u8 rtw8852bx_sco_mapping(u8 central_ch) +{ + if (central_ch == 1) + return 109; + else if (central_ch >= 2 && central_ch <= 6) + return 108; + else if (central_ch >= 7 && central_ch <= 10) + return 107; + else if (central_ch >= 11 && central_ch <= 14) + return 106; + else if (central_ch == 36 || central_ch == 38) + return 51; + else if (central_ch >= 40 && central_ch <= 58) + return 50; + else if (central_ch >= 60 && central_ch <= 64) + return 49; + else if (central_ch == 100 || central_ch == 102) + return 48; + else if (central_ch >= 104 && central_ch <= 126) + return 47; + else if (central_ch >= 128 && central_ch <= 151) + return 46; + else if (central_ch >= 153 && central_ch <= 177) + return 45; + else + return 0; +} + +struct rtw8852bx_bb_gain { + u32 gain_g[BB_PATH_NUM_8852BX]; + u32 gain_a[BB_PATH_NUM_8852BX]; + u32 gain_mask; +}; + +static const struct rtw8852bx_bb_gain bb_gain_lna[LNA_GAIN_NUM] = { + { .gain_g = {0x4678, 0x475C}, .gain_a = {0x45DC, 0x4740}, + .gain_mask = 0x00ff0000 }, + { .gain_g = {0x4678, 0x475C}, .gain_a = {0x45DC, 0x4740}, + .gain_mask = 0xff000000 }, + { .gain_g = {0x467C, 0x4760}, .gain_a = {0x4660, 0x4744}, + .gain_mask = 0x000000ff }, + { .gain_g = {0x467C, 0x4760}, .gain_a = {0x4660, 0x4744}, + .gain_mask = 0x0000ff00 }, + { .gain_g = {0x467C, 0x4760}, .gain_a = {0x4660, 0x4744}, + .gain_mask = 0x00ff0000 }, + { .gain_g = {0x467C, 0x4760}, .gain_a = {0x4660, 0x4744}, + .gain_mask = 0xff000000 }, + { .gain_g = {0x4680, 0x4764}, .gain_a = {0x4664, 0x4748}, + .gain_mask = 0x000000ff }, +}; + +static const struct rtw8852bx_bb_gain bb_gain_tia[TIA_GAIN_NUM] = { + { .gain_g = {0x4680, 0x4764}, .gain_a = {0x4664, 0x4748}, + .gain_mask = 0x00ff0000 }, + { .gain_g = {0x4680, 0x4764}, .gain_a = {0x4664, 0x4748}, + .gain_mask = 0xff000000 }, +}; + +static void rtw8852bx_set_gain_error(struct rtw89_dev *rtwdev, + enum rtw89_subband subband, + enum rtw89_rf_path path) +{ + const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; + u8 gain_band = rtw89_subband_to_bb_gain_band(subband); + s32 val; + u32 reg; + u32 mask; + int i; + + for (i = 0; i < LNA_GAIN_NUM; i++) { + if (subband == RTW89_CH_2G) + reg = bb_gain_lna[i].gain_g[path]; + else + reg = bb_gain_lna[i].gain_a[path]; + + mask = bb_gain_lna[i].gain_mask; + val = gain->lna_gain[gain_band][path][i]; + rtw89_phy_write32_mask(rtwdev, reg, mask, val); + } + + for (i = 0; i < TIA_GAIN_NUM; i++) { + if (subband == RTW89_CH_2G) + reg = bb_gain_tia[i].gain_g[path]; + else + reg = bb_gain_tia[i].gain_a[path]; + + mask = bb_gain_tia[i].gain_mask; + val = gain->tia_gain[gain_band][path][i]; + rtw89_phy_write32_mask(rtwdev, reg, mask, val); + } +} + +static void rtw8852bx_set_gain_offset(struct rtw89_dev *rtwdev, + enum rtw89_subband subband, + enum rtw89_phy_idx phy_idx) +{ + static const u32 gain_err_addr[2] = {R_P0_AGC_RSVD, R_P1_AGC_RSVD}; + static const u32 rssi_ofst_addr[2] = {R_PATH0_G_TIA1_LNA6_OP1DB_V1, + R_PATH1_G_TIA1_LNA6_OP1DB_V1}; + struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_phy_efuse_gain *efuse_gain = &rtwdev->efuse_gain; + enum rtw89_gain_offset gain_ofdm_band; + s32 offset_a, offset_b; + s32 offset_ofdm, offset_cck; + s32 tmp; + u8 path; + + if (!efuse_gain->comp_valid) + goto next; + + for (path = RF_PATH_A; path < BB_PATH_NUM_8852BX; path++) { + tmp = efuse_gain->comp[path][subband]; + tmp = clamp_t(s32, tmp << 2, S8_MIN, S8_MAX); + rtw89_phy_write32_mask(rtwdev, gain_err_addr[path], MASKBYTE0, tmp); + } + +next: + if (!efuse_gain->offset_valid) + return; + + gain_ofdm_band = rtw89_subband_to_gain_offset_band_of_ofdm(subband); + + offset_a = -efuse_gain->offset[RF_PATH_A][gain_ofdm_band]; + offset_b = -efuse_gain->offset[RF_PATH_B][gain_ofdm_band]; + + tmp = -((offset_a << 2) + (efuse_gain->offset_base[RTW89_PHY_0] >> 2)); + tmp = clamp_t(s32, tmp, S8_MIN, S8_MAX); + rtw89_phy_write32_mask(rtwdev, rssi_ofst_addr[RF_PATH_A], B_PATH0_R_G_OFST_MASK, tmp); + + tmp = -((offset_b << 2) + (efuse_gain->offset_base[RTW89_PHY_0] >> 2)); + tmp = clamp_t(s32, tmp, S8_MIN, S8_MAX); + rtw89_phy_write32_mask(rtwdev, rssi_ofst_addr[RF_PATH_B], B_PATH0_R_G_OFST_MASK, tmp); + + if (hal->antenna_rx == RF_B) { + offset_ofdm = -efuse_gain->offset[RF_PATH_B][gain_ofdm_band]; + offset_cck = -efuse_gain->offset[RF_PATH_B][0]; + } else { + offset_ofdm = -efuse_gain->offset[RF_PATH_A][gain_ofdm_band]; + offset_cck = -efuse_gain->offset[RF_PATH_A][0]; + } + + tmp = (offset_ofdm << 4) + efuse_gain->offset_base[RTW89_PHY_0]; + tmp = clamp_t(s32, tmp, S8_MIN, S8_MAX); + rtw89_phy_write32_idx(rtwdev, R_P0_RPL1, B_P0_RPL1_BIAS_MASK, tmp, phy_idx); + + tmp = (offset_ofdm << 4) + efuse_gain->rssi_base[RTW89_PHY_0]; + tmp = clamp_t(s32, tmp, S8_MIN, S8_MAX); + rtw89_phy_write32_idx(rtwdev, R_P1_RPL1, B_P0_RPL1_BIAS_MASK, tmp, phy_idx); + + if (subband == RTW89_CH_2G) { + tmp = (offset_cck << 3) + (efuse_gain->offset_base[RTW89_PHY_0] >> 1); + tmp = clamp_t(s32, tmp, S8_MIN >> 1, S8_MAX >> 1); + rtw89_phy_write32_mask(rtwdev, R_RX_RPL_OFST, + B_RX_RPL_OFST_CCK_MASK, tmp); + } +} + +static +void rtw8852bx_set_rxsc_rpl_comp(struct rtw89_dev *rtwdev, enum rtw89_subband subband) +{ + const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; + u8 band = rtw89_subband_to_bb_gain_band(subband); + u32 val; + + val = u32_encode_bits((gain->rpl_ofst_20[band][RF_PATH_A] + + gain->rpl_ofst_20[band][RF_PATH_B]) >> 1, B_P0_RPL1_20_MASK) | + u32_encode_bits((gain->rpl_ofst_40[band][RF_PATH_A][0] + + gain->rpl_ofst_40[band][RF_PATH_B][0]) >> 1, B_P0_RPL1_40_MASK) | + u32_encode_bits((gain->rpl_ofst_40[band][RF_PATH_A][1] + + gain->rpl_ofst_40[band][RF_PATH_B][1]) >> 1, B_P0_RPL1_41_MASK); + val >>= B_P0_RPL1_SHIFT; + rtw89_phy_write32_mask(rtwdev, R_P0_RPL1, B_P0_RPL1_MASK, val); + rtw89_phy_write32_mask(rtwdev, R_P1_RPL1, B_P0_RPL1_MASK, val); + + val = u32_encode_bits((gain->rpl_ofst_40[band][RF_PATH_A][2] + + gain->rpl_ofst_40[band][RF_PATH_B][2]) >> 1, B_P0_RTL2_42_MASK) | + u32_encode_bits((gain->rpl_ofst_80[band][RF_PATH_A][0] + + gain->rpl_ofst_80[band][RF_PATH_B][0]) >> 1, B_P0_RTL2_80_MASK) | + u32_encode_bits((gain->rpl_ofst_80[band][RF_PATH_A][1] + + gain->rpl_ofst_80[band][RF_PATH_B][1]) >> 1, B_P0_RTL2_81_MASK) | + u32_encode_bits((gain->rpl_ofst_80[band][RF_PATH_A][10] + + gain->rpl_ofst_80[band][RF_PATH_B][10]) >> 1, B_P0_RTL2_8A_MASK); + rtw89_phy_write32(rtwdev, R_P0_RPL2, val); + rtw89_phy_write32(rtwdev, R_P1_RPL2, val); + + val = u32_encode_bits((gain->rpl_ofst_80[band][RF_PATH_A][2] + + gain->rpl_ofst_80[band][RF_PATH_B][2]) >> 1, B_P0_RTL3_82_MASK) | + u32_encode_bits((gain->rpl_ofst_80[band][RF_PATH_A][3] + + gain->rpl_ofst_80[band][RF_PATH_B][3]) >> 1, B_P0_RTL3_83_MASK) | + u32_encode_bits((gain->rpl_ofst_80[band][RF_PATH_A][4] + + gain->rpl_ofst_80[band][RF_PATH_B][4]) >> 1, B_P0_RTL3_84_MASK) | + u32_encode_bits((gain->rpl_ofst_80[band][RF_PATH_A][9] + + gain->rpl_ofst_80[band][RF_PATH_B][9]) >> 1, B_P0_RTL3_89_MASK); + rtw89_phy_write32(rtwdev, R_P0_RPL3, val); + rtw89_phy_write32(rtwdev, R_P1_RPL3, val); +} + +static void rtw8852bx_ctrl_ch(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + u8 central_ch = chan->channel; + u8 subband = chan->subband_type; + u8 sco_comp; + bool is_2g = central_ch <= 14; + + /* Path A */ + if (is_2g) + rtw89_phy_write32_idx(rtwdev, R_PATH0_BAND_SEL_V1, + B_PATH0_BAND_SEL_MSK_V1, 1, phy_idx); + else + rtw89_phy_write32_idx(rtwdev, R_PATH0_BAND_SEL_V1, + B_PATH0_BAND_SEL_MSK_V1, 0, phy_idx); + + /* Path B */ + if (is_2g) + rtw89_phy_write32_idx(rtwdev, R_PATH1_BAND_SEL_V1, + B_PATH1_BAND_SEL_MSK_V1, 1, phy_idx); + else + rtw89_phy_write32_idx(rtwdev, R_PATH1_BAND_SEL_V1, + B_PATH1_BAND_SEL_MSK_V1, 0, phy_idx); + + /* SCO compensate FC setting */ + sco_comp = rtw8852bx_sco_mapping(central_ch); + rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_INV, sco_comp, phy_idx); + + if (chan->band_type == RTW89_BAND_6G) + return; + + /* CCK parameters */ + if (central_ch == 14) { + rtw89_phy_write32_mask(rtwdev, R_TXFIR0, B_TXFIR_C01, 0x3b13ff); + rtw89_phy_write32_mask(rtwdev, R_TXFIR2, B_TXFIR_C23, 0x1c42de); + rtw89_phy_write32_mask(rtwdev, R_TXFIR4, B_TXFIR_C45, 0xfdb0ad); + rtw89_phy_write32_mask(rtwdev, R_TXFIR6, B_TXFIR_C67, 0xf60f6e); + rtw89_phy_write32_mask(rtwdev, R_TXFIR8, B_TXFIR_C89, 0xfd8f92); + rtw89_phy_write32_mask(rtwdev, R_TXFIRA, B_TXFIR_CAB, 0x2d011); + rtw89_phy_write32_mask(rtwdev, R_TXFIRC, B_TXFIR_CCD, 0x1c02c); + rtw89_phy_write32_mask(rtwdev, R_TXFIRE, B_TXFIR_CEF, 0xfff00a); + } else { + rtw89_phy_write32_mask(rtwdev, R_TXFIR0, B_TXFIR_C01, 0x3d23ff); + rtw89_phy_write32_mask(rtwdev, R_TXFIR2, B_TXFIR_C23, 0x29b354); + rtw89_phy_write32_mask(rtwdev, R_TXFIR4, B_TXFIR_C45, 0xfc1c8); + rtw89_phy_write32_mask(rtwdev, R_TXFIR6, B_TXFIR_C67, 0xfdb053); + rtw89_phy_write32_mask(rtwdev, R_TXFIR8, B_TXFIR_C89, 0xf86f9a); + rtw89_phy_write32_mask(rtwdev, R_TXFIRA, B_TXFIR_CAB, 0xfaef92); + rtw89_phy_write32_mask(rtwdev, R_TXFIRC, B_TXFIR_CCD, 0xfe5fcc); + rtw89_phy_write32_mask(rtwdev, R_TXFIRE, B_TXFIR_CEF, 0xffdff5); + } + + rtw8852bx_set_gain_error(rtwdev, subband, RF_PATH_A); + rtw8852bx_set_gain_error(rtwdev, subband, RF_PATH_B); + rtw8852bx_set_gain_offset(rtwdev, subband, phy_idx); + rtw8852bx_set_rxsc_rpl_comp(rtwdev, subband); +} + +static void rtw8852b_bw_setting(struct rtw89_dev *rtwdev, u8 bw, u8 path) +{ + static const u32 adc_sel[2] = {0xC0EC, 0xC1EC}; + static const u32 wbadc_sel[2] = {0xC0E4, 0xC1E4}; + + switch (bw) { + case RTW89_CHANNEL_WIDTH_5: + rtw89_phy_write32_mask(rtwdev, adc_sel[path], 0x6000, 0x1); + rtw89_phy_write32_mask(rtwdev, wbadc_sel[path], 0x30, 0x0); + break; + case RTW89_CHANNEL_WIDTH_10: + rtw89_phy_write32_mask(rtwdev, adc_sel[path], 0x6000, 0x2); + rtw89_phy_write32_mask(rtwdev, wbadc_sel[path], 0x30, 0x1); + break; + case RTW89_CHANNEL_WIDTH_20: + rtw89_phy_write32_mask(rtwdev, adc_sel[path], 0x6000, 0x0); + rtw89_phy_write32_mask(rtwdev, wbadc_sel[path], 0x30, 0x2); + break; + case RTW89_CHANNEL_WIDTH_40: + rtw89_phy_write32_mask(rtwdev, adc_sel[path], 0x6000, 0x0); + rtw89_phy_write32_mask(rtwdev, wbadc_sel[path], 0x30, 0x2); + break; + case RTW89_CHANNEL_WIDTH_80: + rtw89_phy_write32_mask(rtwdev, adc_sel[path], 0x6000, 0x0); + rtw89_phy_write32_mask(rtwdev, wbadc_sel[path], 0x30, 0x2); + break; + default: + rtw89_warn(rtwdev, "Fail to set ADC\n"); + } +} + +static void rtw8852bx_ctrl_bw(struct rtw89_dev *rtwdev, u8 pri_ch, u8 bw, + enum rtw89_phy_idx phy_idx) +{ + u32 rx_path_0; + + switch (bw) { + case RTW89_CHANNEL_WIDTH_5: + rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_SBW, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, 0x0, phy_idx); + + /*Set RF mode at 3 */ + rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX, + B_P0_RFMODE_ORI_RX_ALL, 0x333, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, + B_P1_RFMODE_ORI_RX_ALL, 0x333, phy_idx); + break; + case RTW89_CHANNEL_WIDTH_10: + rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_SBW, 0x2, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, 0x0, phy_idx); + + /*Set RF mode at 3 */ + rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX, + B_P0_RFMODE_ORI_RX_ALL, 0x333, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, + B_P1_RFMODE_ORI_RX_ALL, 0x333, phy_idx); + break; + case RTW89_CHANNEL_WIDTH_20: + rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_SBW, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, 0x0, phy_idx); + + /*Set RF mode at 3 */ + rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX, + B_P0_RFMODE_ORI_RX_ALL, 0x333, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, + B_P1_RFMODE_ORI_RX_ALL, 0x333, phy_idx); + break; + case RTW89_CHANNEL_WIDTH_40: + rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_SBW, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, + pri_ch, phy_idx); + + /*Set RF mode at 3 */ + rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX, + B_P0_RFMODE_ORI_RX_ALL, 0x333, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, + B_P1_RFMODE_ORI_RX_ALL, 0x333, phy_idx); + /*CCK primary channel */ + if (pri_ch == RTW89_SC_20_UPPER) + rtw89_phy_write32_mask(rtwdev, R_RXSC, B_RXSC_EN, 1); + else + rtw89_phy_write32_mask(rtwdev, R_RXSC, B_RXSC_EN, 0); + + break; + case RTW89_CHANNEL_WIDTH_80: + rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x2, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_SBW, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, + pri_ch, phy_idx); + + /*Set RF mode at A */ + rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX, + B_P0_RFMODE_ORI_RX_ALL, 0xaaa, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, + B_P1_RFMODE_ORI_RX_ALL, 0xaaa, phy_idx); + break; + default: + rtw89_warn(rtwdev, "Fail to switch bw (bw:%d, pri ch:%d)\n", bw, + pri_ch); + } + + rtw8852b_bw_setting(rtwdev, bw, RF_PATH_A); + rtw8852b_bw_setting(rtwdev, bw, RF_PATH_B); + + rx_path_0 = rtw89_phy_read32_idx(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, + phy_idx); + if (rx_path_0 == 0x1) + rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, + B_P1_RFMODE_ORI_RX_ALL, 0x111, phy_idx); + else if (rx_path_0 == 0x2) + rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX, + B_P0_RFMODE_ORI_RX_ALL, 0x111, phy_idx); +} + +static void rtw8852bx_ctrl_cck_en(struct rtw89_dev *rtwdev, bool cck_en) +{ + if (cck_en) { + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, B_ENABLE_CCK, 1); + rtw89_phy_write32_mask(rtwdev, R_RXCCA, B_RXCCA_DIS, 0); + } else { + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, B_ENABLE_CCK, 0); + rtw89_phy_write32_mask(rtwdev, R_RXCCA, B_RXCCA_DIS, 1); + } +} + +static void rtw8852bx_5m_mask(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + u8 pri_ch = chan->pri_ch_idx; + bool mask_5m_low; + bool mask_5m_en; + + switch (chan->band_width) { + case RTW89_CHANNEL_WIDTH_40: + /* Prich=1: Mask 5M High, Prich=2: Mask 5M Low */ + mask_5m_en = true; + mask_5m_low = pri_ch == RTW89_SC_20_LOWER; + break; + case RTW89_CHANNEL_WIDTH_80: + /* Prich=3: Mask 5M High, Prich=4: Mask 5M Low, Else: Disable */ + mask_5m_en = pri_ch == RTW89_SC_20_UPMOST || + pri_ch == RTW89_SC_20_LOWEST; + mask_5m_low = pri_ch == RTW89_SC_20_LOWEST; + break; + default: + mask_5m_en = false; + break; + } + + if (!mask_5m_en) { + rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_EN, 0x0); + rtw89_phy_write32_idx(rtwdev, R_ASSIGN_SBD_OPT_V1, + B_ASSIGN_SBD_OPT_EN_V1, 0x0, phy_idx); + return; + } + + if (mask_5m_low) { + rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_TH, 0x4); + rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_SB2, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_SB0, 0x1); + rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_TH, 0x4); + rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_SB2, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_SB0, 0x1); + } else { + rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_TH, 0x4); + rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_SB2, 0x1); + rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_SB0, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_TH, 0x4); + rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_SB2, 0x1); + rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_SB0, 0x0); + } + rtw89_phy_write32_idx(rtwdev, R_ASSIGN_SBD_OPT_V1, + B_ASSIGN_SBD_OPT_EN_V1, 0x1, phy_idx); +} + +static void __rtw8852bx_bb_reset_all(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + rtw89_phy_write32_idx(rtwdev, R_S0_HW_SI_DIS, B_S0_HW_SI_DIS_W_R_TRIG, 0x7, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_S1_HW_SI_DIS, B_S1_HW_SI_DIS_W_R_TRIG, 0x7, phy_idx); + fsleep(1); + rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_S0_HW_SI_DIS, B_S0_HW_SI_DIS_W_R_TRIG, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_S1_HW_SI_DIS, B_S1_HW_SI_DIS_W_R_TRIG, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 1, phy_idx); +} + +static void rtw8852bx_bb_macid_ctrl_init(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) +{ + u32 addr; + + for (addr = R_AX_PWR_MACID_LMT_TABLE0; + addr <= R_AX_PWR_MACID_LMT_TABLE127; addr += 4) + rtw89_mac_txpwr_write32(rtwdev, phy_idx, addr, 0); +} + +static void __rtw8852bx_bb_sethw(struct rtw89_dev *rtwdev) +{ + struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain; + + rtw89_phy_write32_clr(rtwdev, R_P0_EN_SOUND_WO_NDP, B_P0_EN_SOUND_WO_NDP); + rtw89_phy_write32_clr(rtwdev, R_P1_EN_SOUND_WO_NDP, B_P1_EN_SOUND_WO_NDP); + + rtw8852bx_bb_macid_ctrl_init(rtwdev, RTW89_PHY_0); + + /* read these registers after loading BB parameters */ + gain->offset_base[RTW89_PHY_0] = + rtw89_phy_read32_mask(rtwdev, R_P0_RPL1, B_P0_RPL1_BIAS_MASK); + gain->rssi_base[RTW89_PHY_0] = + rtw89_phy_read32_mask(rtwdev, R_P1_RPL1, B_P0_RPL1_BIAS_MASK); +} + +static void rtw8852bx_bb_set_pop(struct rtw89_dev *rtwdev) +{ + if (rtwdev->hw->conf.flags & IEEE80211_CONF_MONITOR) + rtw89_phy_write32_clr(rtwdev, R_PKT_CTRL, B_PKT_POP_EN); +} + +static +void __rtw8852bx_set_channel_bb(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + bool cck_en = chan->channel <= 14; + u8 pri_ch_idx = chan->pri_ch_idx; + u8 band = chan->band_type, chan_idx; + + if (cck_en) + rtw8852bx_ctrl_sco_cck(rtwdev, chan->primary_channel); + + rtw8852bx_ctrl_ch(rtwdev, chan, phy_idx); + rtw8852bx_ctrl_bw(rtwdev, pri_ch_idx, chan->band_width, phy_idx); + rtw8852bx_ctrl_cck_en(rtwdev, cck_en); + if (chan->band_type == RTW89_BAND_5G) { + rtw89_phy_write32_mask(rtwdev, R_PATH0_BT_SHARE_V1, + B_PATH0_BT_SHARE_V1, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PATH0_BTG_PATH_V1, + B_PATH0_BTG_PATH_V1, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PATH1_BT_SHARE_V1, + B_PATH1_BT_SHARE_V1, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PATH1_BTG_PATH_V1, + B_PATH1_BTG_PATH_V1, 0x0); + rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_BT_SHARE, 0x0); + rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_BT_SEG0, 0x0); + rtw89_phy_write32_mask(rtwdev, R_BT_DYN_DC_EST_EN_V1, + B_BT_DYN_DC_EST_EN_MSK, 0x0); + rtw89_phy_write32_mask(rtwdev, R_GNT_BT_WGT_EN, B_GNT_BT_WGT_EN, 0x0); + } + chan_idx = rtw89_encode_chan_idx(rtwdev, chan->primary_channel, band); + rtw89_phy_write32_mask(rtwdev, R_MAC_PIN_SEL, B_CH_IDX_SEG0, chan_idx); + rtw8852bx_5m_mask(rtwdev, chan, phy_idx); + rtw8852bx_bb_set_pop(rtwdev); + __rtw8852bx_bb_reset_all(rtwdev, phy_idx); +} + +static u32 rtw8852bx_bb_cal_txpwr_ref(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, s16 ref) +{ + const u16 tssi_16dbm_cw = 0x12c; + const u8 base_cw_0db = 0x27; + const s8 ofst_int = 0; + s16 pwr_s10_3; + s16 rf_pwr_cw; + u16 bb_pwr_cw; + u32 pwr_cw; + u32 tssi_ofst_cw; + + pwr_s10_3 = (ref << 1) + (s16)(ofst_int) + (s16)(base_cw_0db << 3); + bb_pwr_cw = u16_get_bits(pwr_s10_3, GENMASK(2, 0)); + rf_pwr_cw = u16_get_bits(pwr_s10_3, GENMASK(8, 3)); + rf_pwr_cw = clamp_t(s16, rf_pwr_cw, 15, 63); + pwr_cw = (rf_pwr_cw << 3) | bb_pwr_cw; + + tssi_ofst_cw = (u32)((s16)tssi_16dbm_cw + (ref << 1) - (16 << 3)); + rtw89_debug(rtwdev, RTW89_DBG_TXPWR, + "[TXPWR] tssi_ofst_cw=%d rf_cw=0x%x bb_cw=0x%x\n", + tssi_ofst_cw, rf_pwr_cw, bb_pwr_cw); + + return u32_encode_bits(tssi_ofst_cw, B_DPD_TSSI_CW) | + u32_encode_bits(pwr_cw, B_DPD_PWR_CW) | + u32_encode_bits(ref, B_DPD_REF); +} + +static void rtw8852bx_set_txpwr_ref(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) +{ + static const u32 addr[RF_PATH_NUM_8852BX] = {0x5800, 0x7800}; + const u32 mask = B_DPD_TSSI_CW | B_DPD_PWR_CW | B_DPD_REF; + const u8 ofst_ofdm = 0x4; + const u8 ofst_cck = 0x8; + const s16 ref_ofdm = 0; + const s16 ref_cck = 0; + u32 val; + u8 i; + + rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set txpwr reference\n"); + + rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_AX_PWR_RATE_CTRL, + B_AX_PWR_REF, 0x0); + + rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set bb ofdm txpwr ref\n"); + val = rtw8852bx_bb_cal_txpwr_ref(rtwdev, phy_idx, ref_ofdm); + + for (i = 0; i < RF_PATH_NUM_8852BX; i++) + rtw89_phy_write32_idx(rtwdev, addr[i] + ofst_ofdm, mask, val, + phy_idx); + + rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set bb cck txpwr ref\n"); + val = rtw8852bx_bb_cal_txpwr_ref(rtwdev, phy_idx, ref_cck); + + for (i = 0; i < RF_PATH_NUM_8852BX; i++) + rtw89_phy_write32_idx(rtwdev, addr[i] + ofst_cck, mask, val, + phy_idx); +} + +static void rtw8852bx_bb_set_tx_shape_dfir(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + u8 tx_shape_idx, + enum rtw89_phy_idx phy_idx) +{ +#define __DFIR_CFG_ADDR(i) (R_TXFIR0 + ((i) << 2)) +#define __DFIR_CFG_MASK 0xffffffff +#define __DFIR_CFG_NR 8 +#define __DECL_DFIR_PARAM(_name, _val...) \ + static const u32 param_ ## _name[] = {_val}; \ + static_assert(ARRAY_SIZE(param_ ## _name) == __DFIR_CFG_NR) + + __DECL_DFIR_PARAM(flat, + 0x023D23FF, 0x0029B354, 0x000FC1C8, 0x00FDB053, + 0x00F86F9A, 0x06FAEF92, 0x00FE5FCC, 0x00FFDFF5); + __DECL_DFIR_PARAM(sharp, + 0x023D83FF, 0x002C636A, 0x0013F204, 0x00008090, + 0x00F87FB0, 0x06F99F83, 0x00FDBFBA, 0x00003FF5); + __DECL_DFIR_PARAM(sharp_14, + 0x023B13FF, 0x001C42DE, 0x00FDB0AD, 0x00F60F6E, + 0x00FD8F92, 0x0602D011, 0x0001C02C, 0x00FFF00A); + u8 ch = chan->channel; + const u32 *param; + u32 addr; + int i; + + if (ch > 14) { + rtw89_warn(rtwdev, + "set tx shape dfir by unknown ch: %d on 2G\n", ch); + return; + } + + if (ch == 14) + param = param_sharp_14; + else + param = tx_shape_idx == 0 ? param_flat : param_sharp; + + for (i = 0; i < __DFIR_CFG_NR; i++) { + addr = __DFIR_CFG_ADDR(i); + rtw89_debug(rtwdev, RTW89_DBG_TXPWR, + "set tx shape dfir: 0x%x: 0x%x\n", addr, param[i]); + rtw89_phy_write32_idx(rtwdev, addr, __DFIR_CFG_MASK, param[i], + phy_idx); + } + +#undef __DECL_DFIR_PARAM +#undef __DFIR_CFG_NR +#undef __DFIR_CFG_MASK +#undef __DECL_CFG_ADDR +} + +static void rtw8852bx_set_tx_shape(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + const struct rtw89_rfe_parms *rfe_parms = rtwdev->rfe_parms; + u8 band = chan->band_type; + u8 regd = rtw89_regd_get(rtwdev, band); + u8 tx_shape_cck = (*rfe_parms->tx_shape.lmt)[band][RTW89_RS_CCK][regd]; + u8 tx_shape_ofdm = (*rfe_parms->tx_shape.lmt)[band][RTW89_RS_OFDM][regd]; + + if (band == RTW89_BAND_2G) + rtw8852bx_bb_set_tx_shape_dfir(rtwdev, chan, tx_shape_cck, phy_idx); + + rtw89_phy_write32_mask(rtwdev, R_DCFO_OPT, B_TXSHAPE_TRIANGULAR_CFG, + tx_shape_ofdm); +} + +static void __rtw8852bx_set_txpwr(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + rtw89_phy_set_txpwr_byrate(rtwdev, chan, phy_idx); + rtw89_phy_set_txpwr_offset(rtwdev, chan, phy_idx); + rtw8852bx_set_tx_shape(rtwdev, chan, phy_idx); + rtw89_phy_set_txpwr_limit(rtwdev, chan, phy_idx); + rtw89_phy_set_txpwr_limit_ru(rtwdev, chan, phy_idx); +} + +static void __rtw8852bx_set_txpwr_ctrl(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) +{ + rtw8852bx_set_txpwr_ref(rtwdev, phy_idx); +} + +static +void __rtw8852bx_set_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev, + s8 pw_ofst, enum rtw89_mac_idx mac_idx) +{ + u32 reg; + + if (pw_ofst < -16 || pw_ofst > 15) { + rtw89_warn(rtwdev, "[ULTB] Err pwr_offset=%d\n", pw_ofst); + return; + } + + reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_CTRL, mac_idx); + rtw89_write32_set(rtwdev, reg, B_AX_PWR_UL_TB_CTRL_EN); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_1T, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_1T_MASK, pw_ofst); + + pw_ofst = max_t(s8, pw_ofst - 3, -16); + reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_2T, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_2T_MASK, pw_ofst); +} + +static int +__rtw8852bx_init_txpwr_unit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + int ret; + + ret = rtw89_mac_txpwr_write32(rtwdev, phy_idx, R_AX_PWR_UL_CTRL2, 0x07763333); + if (ret) + return ret; + + ret = rtw89_mac_txpwr_write32(rtwdev, phy_idx, R_AX_PWR_COEXT_CTRL, 0x01ebf000); + if (ret) + return ret; + + ret = rtw89_mac_txpwr_write32(rtwdev, phy_idx, R_AX_PWR_UL_CTRL0, 0x0002f8ff); + if (ret) + return ret; + + rtw8852bx_set_txpwr_ul_tb_offset(rtwdev, 0, phy_idx == RTW89_PHY_1 ? + RTW89_MAC_1 : RTW89_MAC_0); + + return 0; +} + +static +void __rtw8852bx_bb_set_plcp_tx(struct rtw89_dev *rtwdev) +{ + const struct rtw89_reg3_def *def = rtw8852bx_pmac_ht20_mcs7_tbl; + u8 i; + + for (i = 0; i < ARRAY_SIZE(rtw8852bx_pmac_ht20_mcs7_tbl); i++, def++) + rtw89_phy_write32_mask(rtwdev, def->addr, def->mask, def->data); +} + +static void rtw8852bx_stop_pmac_tx(struct rtw89_dev *rtwdev, + struct rtw8852bx_bb_pmac_info *tx_info, + enum rtw89_phy_idx idx) +{ + rtw89_debug(rtwdev, RTW89_DBG_TSSI, "PMAC Stop Tx"); + if (tx_info->mode == CONT_TX) + rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_PRD, B_PMAC_CTX_EN, 0, idx); + else if (tx_info->mode == PKTS_TX) + rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_PRD, B_PMAC_PTX_EN, 0, idx); +} + +static void rtw8852bx_start_pmac_tx(struct rtw89_dev *rtwdev, + struct rtw8852bx_bb_pmac_info *tx_info, + enum rtw89_phy_idx idx) +{ + enum rtw8852bx_pmac_mode mode = tx_info->mode; + u32 pkt_cnt = tx_info->tx_cnt; + u16 period = tx_info->period; + + if (mode == CONT_TX && !tx_info->is_cck) { + rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_PRD, B_PMAC_CTX_EN, 1, idx); + rtw89_debug(rtwdev, RTW89_DBG_TSSI, "PMAC CTx Start"); + } else if (mode == PKTS_TX) { + rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_PRD, B_PMAC_PTX_EN, 1, idx); + rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_PRD, + B_PMAC_TX_PRD_MSK, period, idx); + rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_CNT, B_PMAC_TX_CNT_MSK, + pkt_cnt, idx); + rtw89_debug(rtwdev, RTW89_DBG_TSSI, "PMAC PTx Start"); + } + + rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_CTRL, B_PMAC_TXEN_DIS, 1, idx); + rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_CTRL, B_PMAC_TXEN_DIS, 0, idx); +} + +static +void rtw8852bx_bb_set_pmac_tx(struct rtw89_dev *rtwdev, + struct rtw8852bx_bb_pmac_info *tx_info, + enum rtw89_phy_idx idx) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + + if (!tx_info->en_pmac_tx) { + rtw8852bx_stop_pmac_tx(rtwdev, tx_info, idx); + rtw89_phy_write32_idx(rtwdev, R_PD_CTRL, B_PD_HIT_DIS, 0, idx); + if (chan->band_type == RTW89_BAND_2G) + rtw89_phy_write32_clr(rtwdev, R_RXCCA, B_RXCCA_DIS); + return; + } + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, "PMAC Tx Enable"); + + rtw89_phy_write32_idx(rtwdev, R_PMAC_GNT, B_PMAC_GNT_TXEN, 1, idx); + rtw89_phy_write32_idx(rtwdev, R_PMAC_GNT, B_PMAC_GNT_RXEN, 1, idx); + rtw89_phy_write32_idx(rtwdev, R_PMAC_RX_CFG1, B_PMAC_OPT1_MSK, 0x3f, idx); + rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 0, idx); + rtw89_phy_write32_idx(rtwdev, R_PD_CTRL, B_PD_HIT_DIS, 1, idx); + rtw89_phy_write32_set(rtwdev, R_RXCCA, B_RXCCA_DIS); + rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 1, idx); + + rtw8852bx_start_pmac_tx(rtwdev, tx_info, idx); +} + +static +void __rtw8852bx_bb_set_pmac_pkt_tx(struct rtw89_dev *rtwdev, u8 enable, + u16 tx_cnt, u16 period, u16 tx_time, + enum rtw89_phy_idx idx) +{ + struct rtw8852bx_bb_pmac_info tx_info = {0}; + + tx_info.en_pmac_tx = enable; + tx_info.is_cck = 0; + tx_info.mode = PKTS_TX; + tx_info.tx_cnt = tx_cnt; + tx_info.period = period; + tx_info.tx_time = tx_time; + + rtw8852bx_bb_set_pmac_tx(rtwdev, &tx_info, idx); +} + +static +void __rtw8852bx_bb_set_power(struct rtw89_dev *rtwdev, s16 pwr_dbm, + enum rtw89_phy_idx idx) +{ + rtw89_debug(rtwdev, RTW89_DBG_TSSI, "PMAC CFG Tx PWR = %d", pwr_dbm); + + rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_PWR_EN, 1, idx); + rtw89_phy_write32_idx(rtwdev, R_TXPWR, B_TXPWR_MSK, pwr_dbm, idx); +} + +static +void __rtw8852bx_bb_cfg_tx_path(struct rtw89_dev *rtwdev, u8 tx_path) +{ + rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_MOD, 7, RTW89_PHY_0); + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, "PMAC CFG Tx Path = %d", tx_path); + + if (tx_path == RF_PATH_A) { + rtw89_phy_write32_mask(rtwdev, R_TXPATH_SEL, B_TXPATH_SEL_MSK, 1); + rtw89_phy_write32_mask(rtwdev, R_TXNSS_MAP, B_TXNSS_MAP_MSK, 0); + } else if (tx_path == RF_PATH_B) { + rtw89_phy_write32_mask(rtwdev, R_TXPATH_SEL, B_TXPATH_SEL_MSK, 2); + rtw89_phy_write32_mask(rtwdev, R_TXNSS_MAP, B_TXNSS_MAP_MSK, 0); + } else if (tx_path == RF_PATH_AB) { + rtw89_phy_write32_mask(rtwdev, R_TXPATH_SEL, B_TXPATH_SEL_MSK, 3); + rtw89_phy_write32_mask(rtwdev, R_TXNSS_MAP, B_TXNSS_MAP_MSK, 4); + } else { + rtw89_debug(rtwdev, RTW89_DBG_TSSI, "Error Tx Path"); + } +} + +static +void __rtw8852bx_bb_tx_mode_switch(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx idx, u8 mode) +{ + if (mode != 0) + return; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, "Tx mode switch"); + + rtw89_phy_write32_idx(rtwdev, R_PMAC_GNT, B_PMAC_GNT_TXEN, 0, idx); + rtw89_phy_write32_idx(rtwdev, R_PMAC_GNT, B_PMAC_GNT_RXEN, 0, idx); + rtw89_phy_write32_idx(rtwdev, R_PMAC_RX_CFG1, B_PMAC_OPT1_MSK, 0, idx); + rtw89_phy_write32_idx(rtwdev, R_PMAC_RXMOD, B_PMAC_RXMOD_MSK, 0, idx); + rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_DPD_EN, 0, idx); + rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_MOD, 0, idx); + rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_PWR_EN, 0, idx); +} + +static +void __rtw8852bx_bb_backup_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx idx, + struct rtw8852bx_bb_tssi_bak *bak) +{ + s32 tmp; + + bak->tx_path = rtw89_phy_read32_idx(rtwdev, R_TXPATH_SEL, B_TXPATH_SEL_MSK, idx); + bak->rx_path = rtw89_phy_read32_idx(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, idx); + bak->p0_rfmode = rtw89_phy_read32_idx(rtwdev, R_P0_RFMODE, MASKDWORD, idx); + bak->p0_rfmode_ftm = rtw89_phy_read32_idx(rtwdev, R_P0_RFMODE_FTM_RX, MASKDWORD, idx); + bak->p1_rfmode = rtw89_phy_read32_idx(rtwdev, R_P1_RFMODE, MASKDWORD, idx); + bak->p1_rfmode_ftm = rtw89_phy_read32_idx(rtwdev, R_P1_RFMODE_FTM_RX, MASKDWORD, idx); + tmp = rtw89_phy_read32_idx(rtwdev, R_TXPWR, B_TXPWR_MSK, idx); + bak->tx_pwr = sign_extend32(tmp, 8); +} + +static +void __rtw8852bx_bb_restore_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx idx, + const struct rtw8852bx_bb_tssi_bak *bak) +{ + rtw89_phy_write32_idx(rtwdev, R_TXPATH_SEL, B_TXPATH_SEL_MSK, bak->tx_path, idx); + if (bak->tx_path == RF_AB) + rtw89_phy_write32_mask(rtwdev, R_TXNSS_MAP, B_TXNSS_MAP_MSK, 0x4); + else + rtw89_phy_write32_mask(rtwdev, R_TXNSS_MAP, B_TXNSS_MAP_MSK, 0x0); + rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, bak->rx_path, idx); + rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_PWR_EN, 1, idx); + rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE, MASKDWORD, bak->p0_rfmode, idx); + rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_FTM_RX, MASKDWORD, bak->p0_rfmode_ftm, idx); + rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE, MASKDWORD, bak->p1_rfmode, idx); + rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_FTM_RX, MASKDWORD, bak->p1_rfmode_ftm, idx); + rtw89_phy_write32_idx(rtwdev, R_TXPWR, B_TXPWR_MSK, bak->tx_pwr, idx); +} + +static void __rtw8852bx_ctrl_nbtg_bt_tx(struct rtw89_dev *rtwdev, bool en, + enum rtw89_phy_idx phy_idx) +{ + rtw89_phy_write_reg3_tbl(rtwdev, en ? &rtw8852bx_btc_preagc_en_defs_tbl : + &rtw8852bx_btc_preagc_dis_defs_tbl); +} + +static void __rtw8852bx_ctrl_btg_bt_rx(struct rtw89_dev *rtwdev, bool en, + enum rtw89_phy_idx phy_idx) +{ + if (en) { + rtw89_phy_write32_mask(rtwdev, R_PATH0_BT_SHARE_V1, + B_PATH0_BT_SHARE_V1, 0x1); + rtw89_phy_write32_mask(rtwdev, R_PATH0_BTG_PATH_V1, + B_PATH0_BTG_PATH_V1, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PATH1_G_LNA6_OP1DB_V1, + B_PATH1_G_LNA6_OP1DB_V1, 0x20); + rtw89_phy_write32_mask(rtwdev, R_PATH1_G_TIA0_LNA6_OP1DB_V1, + B_PATH1_G_TIA0_LNA6_OP1DB_V1, 0x30); + rtw89_phy_write32_mask(rtwdev, R_PATH1_BT_SHARE_V1, + B_PATH1_BT_SHARE_V1, 0x1); + rtw89_phy_write32_mask(rtwdev, R_PATH1_BTG_PATH_V1, + B_PATH1_BTG_PATH_V1, 0x1); + rtw89_phy_write32_mask(rtwdev, R_PMAC_GNT, B_PMAC_GNT_P1, 0x0); + rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_BT_SHARE, 0x1); + rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_BT_SEG0, 0x2); + rtw89_phy_write32_mask(rtwdev, R_BT_DYN_DC_EST_EN_V1, + B_BT_DYN_DC_EST_EN_MSK, 0x1); + rtw89_phy_write32_mask(rtwdev, R_GNT_BT_WGT_EN, B_GNT_BT_WGT_EN, 0x1); + } else { + rtw89_phy_write32_mask(rtwdev, R_PATH0_BT_SHARE_V1, + B_PATH0_BT_SHARE_V1, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PATH0_BTG_PATH_V1, + B_PATH0_BTG_PATH_V1, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PATH1_G_LNA6_OP1DB_V1, + B_PATH1_G_LNA6_OP1DB_V1, 0x1a); + rtw89_phy_write32_mask(rtwdev, R_PATH1_G_TIA0_LNA6_OP1DB_V1, + B_PATH1_G_TIA0_LNA6_OP1DB_V1, 0x2a); + rtw89_phy_write32_mask(rtwdev, R_PATH1_BT_SHARE_V1, + B_PATH1_BT_SHARE_V1, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PATH1_BTG_PATH_V1, + B_PATH1_BTG_PATH_V1, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PMAC_GNT, B_PMAC_GNT_P1, 0xc); + rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_BT_SHARE, 0x0); + rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_BT_SEG0, 0x0); + rtw89_phy_write32_mask(rtwdev, R_BT_DYN_DC_EST_EN_V1, + B_BT_DYN_DC_EST_EN_MSK, 0x1); + rtw89_phy_write32_mask(rtwdev, R_GNT_BT_WGT_EN, B_GNT_BT_WGT_EN, 0x0); + } +} + +static +void __rtw8852bx_bb_ctrl_rx_path(struct rtw89_dev *rtwdev, + enum rtw89_rf_path_bit rx_path) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + u32 rst_mask0; + u32 rst_mask1; + + if (rx_path == RF_A) { + rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, 1); + rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_1RCCA_SEG0, 1); + rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_1RCCA_SEG1, 1); + rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT, B_RXHT_MCS_LIMIT, 0); + rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT, B_RXVHT_MCS_LIMIT, 0); + rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_USER_MAX, 4); + rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS, 0); + rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS, 0); + } else if (rx_path == RF_B) { + rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, 2); + rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_1RCCA_SEG0, 2); + rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_1RCCA_SEG1, 2); + rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT, B_RXHT_MCS_LIMIT, 0); + rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT, B_RXVHT_MCS_LIMIT, 0); + rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_USER_MAX, 4); + rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS, 0); + rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS, 0); + } else if (rx_path == RF_AB) { + rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, 3); + rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_1RCCA_SEG0, 3); + rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_1RCCA_SEG1, 3); + rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT, B_RXHT_MCS_LIMIT, 1); + rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT, B_RXVHT_MCS_LIMIT, 1); + rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_USER_MAX, 4); + rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS, 1); + rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS, 1); + } + + rtw8852bx_set_gain_offset(rtwdev, chan->subband_type, RTW89_PHY_0); + + if (chan->band_type == RTW89_BAND_2G && + (rx_path == RF_B || rx_path == RF_AB)) + rtw8852bx_ctrl_btg_bt_rx(rtwdev, true, RTW89_PHY_0); + else + rtw8852bx_ctrl_btg_bt_rx(rtwdev, false, RTW89_PHY_0); + + rst_mask0 = B_P0_TXPW_RSTB_MANON | B_P0_TXPW_RSTB_TSSI; + rst_mask1 = B_P1_TXPW_RSTB_MANON | B_P1_TXPW_RSTB_TSSI; + if (rx_path == RF_A) { + rtw89_phy_write32_mask(rtwdev, R_P0_TXPW_RSTB, rst_mask0, 1); + rtw89_phy_write32_mask(rtwdev, R_P0_TXPW_RSTB, rst_mask0, 3); + } else { + rtw89_phy_write32_mask(rtwdev, R_P1_TXPW_RSTB, rst_mask1, 1); + rtw89_phy_write32_mask(rtwdev, R_P1_TXPW_RSTB, rst_mask1, 3); + } +} + +static void rtw8852bx_bb_ctrl_rf_mode_rx_path(struct rtw89_dev *rtwdev, + enum rtw89_rf_path_bit rx_path) +{ + if (rx_path == RF_A) { + rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE, + B_P0_RFMODE_ORI_TXRX_FTM_TX, 0x1233312); + rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE_FTM_RX, + B_P0_RFMODE_FTM_RX, 0x333); + rtw89_phy_write32_mask(rtwdev, R_P1_RFMODE, + B_P1_RFMODE_ORI_TXRX_FTM_TX, 0x1111111); + rtw89_phy_write32_mask(rtwdev, R_P1_RFMODE_FTM_RX, + B_P1_RFMODE_FTM_RX, 0x111); + } else if (rx_path == RF_B) { + rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE, + B_P0_RFMODE_ORI_TXRX_FTM_TX, 0x1111111); + rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE_FTM_RX, + B_P0_RFMODE_FTM_RX, 0x111); + rtw89_phy_write32_mask(rtwdev, R_P1_RFMODE, + B_P1_RFMODE_ORI_TXRX_FTM_TX, 0x1233312); + rtw89_phy_write32_mask(rtwdev, R_P1_RFMODE_FTM_RX, + B_P1_RFMODE_FTM_RX, 0x333); + } else if (rx_path == RF_AB) { + rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE, + B_P0_RFMODE_ORI_TXRX_FTM_TX, 0x1233312); + rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE_FTM_RX, + B_P0_RFMODE_FTM_RX, 0x333); + rtw89_phy_write32_mask(rtwdev, R_P1_RFMODE, + B_P1_RFMODE_ORI_TXRX_FTM_TX, 0x1233312); + rtw89_phy_write32_mask(rtwdev, R_P1_RFMODE_FTM_RX, + B_P1_RFMODE_FTM_RX, 0x333); + } +} + +static void __rtw8852bx_bb_cfg_txrx_path(struct rtw89_dev *rtwdev) +{ + struct rtw89_hal *hal = &rtwdev->hal; + enum rtw89_rf_path_bit rx_path = hal->antenna_rx ? hal->antenna_rx : RF_AB; + + rtw8852bx_bb_ctrl_rx_path(rtwdev, rx_path); + rtw8852bx_bb_ctrl_rf_mode_rx_path(rtwdev, rx_path); + + if (rtwdev->hal.rx_nss == 1) { + rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT, B_RXHT_MCS_LIMIT, 0); + rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT, B_RXVHT_MCS_LIMIT, 0); + rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS, 0); + rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS, 0); + } else { + rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT, B_RXHT_MCS_LIMIT, 1); + rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT, B_RXVHT_MCS_LIMIT, 1); + rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS, 1); + rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS, 1); + } + + rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_MOD, 0x0, RTW89_PHY_0); +} + +static u8 __rtw8852bx_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path) +{ + if (rtwdev->is_tssi_mode[rf_path]) { + u32 addr = 0x1c10 + (rf_path << 13); + + return rtw89_phy_read32_mask(rtwdev, addr, 0x3F000000); + } + + rtw89_write_rf(rtwdev, rf_path, RR_TM, RR_TM_TRI, 0x1); + rtw89_write_rf(rtwdev, rf_path, RR_TM, RR_TM_TRI, 0x0); + rtw89_write_rf(rtwdev, rf_path, RR_TM, RR_TM_TRI, 0x1); + + fsleep(200); + + return rtw89_read_rf(rtwdev, rf_path, RR_TM, RR_TM_VAL); +} + +static void rtw8852bx_fill_freq_with_ppdu(struct rtw89_dev *rtwdev, + struct rtw89_rx_phy_ppdu *phy_ppdu, + struct ieee80211_rx_status *status) +{ + u16 chan = phy_ppdu->chan_idx; + enum nl80211_band band; + u8 ch; + + if (chan == 0) + return; + + rtw89_decode_chan_idx(rtwdev, chan, &ch, &band); + status->freq = ieee80211_channel_to_frequency(ch, band); + status->band = band; +} + +static void __rtw8852bx_query_ppdu(struct rtw89_dev *rtwdev, + struct rtw89_rx_phy_ppdu *phy_ppdu, + struct ieee80211_rx_status *status) +{ + u8 path; + u8 *rx_power = phy_ppdu->rssi; + + status->signal = RTW89_RSSI_RAW_TO_DBM(max(rx_power[RF_PATH_A], rx_power[RF_PATH_B])); + for (path = 0; path < rtwdev->chip->rf_path_num; path++) { + status->chains |= BIT(path); + status->chain_signal[path] = RTW89_RSSI_RAW_TO_DBM(rx_power[path]); + } + if (phy_ppdu->valid) + rtw8852bx_fill_freq_with_ppdu(rtwdev, phy_ppdu, status); +} + +static int __rtw8852bx_mac_enable_bb_rf(struct rtw89_dev *rtwdev) +{ + int ret; + + rtw89_write8_set(rtwdev, R_AX_SYS_FUNC_EN, + B_AX_FEN_BBRSTB | B_AX_FEN_BB_GLB_RSTN); + rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_ON_CTRL0, B_AX_REG_ZCDC_H_MASK, 0x1); + rtw89_write32_set(rtwdev, R_AX_WLRF_CTRL, B_AX_AFC_AFEDIG); + rtw89_write32_clr(rtwdev, R_AX_WLRF_CTRL, B_AX_AFC_AFEDIG); + rtw89_write32_set(rtwdev, R_AX_WLRF_CTRL, B_AX_AFC_AFEDIG); + + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S0, 0xC7, + FULL_BIT_MASK); + if (ret) + return ret; + + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S1, 0xC7, + FULL_BIT_MASK); + if (ret) + return ret; + + rtw89_write8(rtwdev, R_AX_PHYREG_SET, PHYREG_SET_XYN_CYCLE); + + return 0; +} + +static int __rtw8852bx_mac_disable_bb_rf(struct rtw89_dev *rtwdev) +{ + u8 wl_rfc_s0; + u8 wl_rfc_s1; + int ret; + + rtw89_write32_clr(rtwdev, R_AX_WLRF_CTRL, B_AX_AFC_AFEDIG); + rtw89_write8_clr(rtwdev, R_AX_SYS_FUNC_EN, + B_AX_FEN_BBRSTB | B_AX_FEN_BB_GLB_RSTN); + + ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_WL_RFC_S0, &wl_rfc_s0); + if (ret) + return ret; + wl_rfc_s0 &= ~XTAL_SI_RF00S_EN; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S0, wl_rfc_s0, + FULL_BIT_MASK); + if (ret) + return ret; + + ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_WL_RFC_S1, &wl_rfc_s1); + if (ret) + return ret; + wl_rfc_s1 &= ~XTAL_SI_RF10S_EN; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S1, wl_rfc_s1, + FULL_BIT_MASK); + return ret; +} + +const struct rtw8852bx_info rtw8852bx_info = { + .mac_enable_bb_rf = __rtw8852bx_mac_enable_bb_rf, + .mac_disable_bb_rf = __rtw8852bx_mac_disable_bb_rf, + .bb_sethw = __rtw8852bx_bb_sethw, + .bb_reset_all = __rtw8852bx_bb_reset_all, + .bb_cfg_txrx_path = __rtw8852bx_bb_cfg_txrx_path, + .bb_cfg_tx_path = __rtw8852bx_bb_cfg_tx_path, + .bb_ctrl_rx_path = __rtw8852bx_bb_ctrl_rx_path, + .bb_set_plcp_tx = __rtw8852bx_bb_set_plcp_tx, + .bb_set_power = __rtw8852bx_bb_set_power, + .bb_set_pmac_pkt_tx = __rtw8852bx_bb_set_pmac_pkt_tx, + .bb_backup_tssi = __rtw8852bx_bb_backup_tssi, + .bb_restore_tssi = __rtw8852bx_bb_restore_tssi, + .bb_tx_mode_switch = __rtw8852bx_bb_tx_mode_switch, + .set_channel_mac = __rtw8852bx_set_channel_mac, + .set_channel_bb = __rtw8852bx_set_channel_bb, + .ctrl_nbtg_bt_tx = __rtw8852bx_ctrl_nbtg_bt_tx, + .ctrl_btg_bt_rx = __rtw8852bx_ctrl_btg_bt_rx, + .query_ppdu = __rtw8852bx_query_ppdu, + .read_efuse = __rtw8852bx_read_efuse, + .read_phycap = __rtw8852bx_read_phycap, + .power_trim = __rtw8852bx_power_trim, + .set_txpwr = __rtw8852bx_set_txpwr, + .set_txpwr_ctrl = __rtw8852bx_set_txpwr_ctrl, + .init_txpwr_unit = __rtw8852bx_init_txpwr_unit, + .set_txpwr_ul_tb_offset = __rtw8852bx_set_txpwr_ul_tb_offset, + .get_thermal = __rtw8852bx_get_thermal, +}; +EXPORT_SYMBOL(rtw8852bx_info); + +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11ax wireless 8852B common routines"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.h b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.h new file mode 100644 index 000000000000..2348a13545ac --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.h @@ -0,0 +1,339 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2024 Realtek Corporation + */ + +#ifndef __RTW89_8852BX_H__ +#define __RTW89_8852BX_H__ + +#include "core.h" + +#define RF_PATH_NUM_8852BX 2 +#define BB_PATH_NUM_8852BX 2 + +enum rtw8852bx_pmac_mode { + NONE_TEST, + PKTS_TX, + PKTS_RX, + CONT_TX +}; + +struct rtw8852bx_u_efuse { + u8 rsvd[0x88]; + u8 mac_addr[ETH_ALEN]; +}; + +struct rtw8852bx_e_efuse { + u8 mac_addr[ETH_ALEN]; +}; + +struct rtw8852bx_tssi_offset { + u8 cck_tssi[TSSI_CCK_CH_GROUP_NUM]; + u8 bw40_tssi[TSSI_MCS_2G_CH_GROUP_NUM]; + u8 rsvd[7]; + u8 bw40_1s_tssi_5g[TSSI_MCS_5G_CH_GROUP_NUM]; +} __packed; + +struct rtw8852bx_efuse { + u8 rsvd[0x210]; + struct rtw8852bx_tssi_offset path_a_tssi; + u8 rsvd1[10]; + struct rtw8852bx_tssi_offset path_b_tssi; + u8 rsvd2[94]; + u8 channel_plan; + u8 xtal_k; + u8 rsvd3; + u8 iqk_lck; + u8 rsvd4[5]; + u8 reg_setting:2; + u8 tx_diversity:1; + u8 rx_diversity:2; + u8 ac_mode:1; + u8 module_type:2; + u8 rsvd5; + u8 shared_ant:1; + u8 coex_type:3; + u8 ant_iso:1; + u8 radio_on_off:1; + u8 rsvd6:2; + u8 eeprom_version; + u8 customer_id; + u8 tx_bb_swing_2g; + u8 tx_bb_swing_5g; + u8 tx_cali_pwr_trk_mode; + u8 trx_path_selection; + u8 rfe_type; + u8 country_code[2]; + u8 rsvd7[3]; + u8 path_a_therm; + u8 path_b_therm; + u8 rsvd8[2]; + u8 rx_gain_2g_ofdm; + u8 rsvd9; + u8 rx_gain_2g_cck; + u8 rsvd10; + u8 rx_gain_5g_low; + u8 rsvd11; + u8 rx_gain_5g_mid; + u8 rsvd12; + u8 rx_gain_5g_high; + u8 rsvd13[35]; + u8 path_a_cck_pwr_idx[6]; + u8 path_a_bw40_1tx_pwr_idx[5]; + u8 path_a_ofdm_1tx_pwr_idx_diff:4; + u8 path_a_bw20_1tx_pwr_idx_diff:4; + u8 path_a_bw20_2tx_pwr_idx_diff:4; + u8 path_a_bw40_2tx_pwr_idx_diff:4; + u8 path_a_cck_2tx_pwr_idx_diff:4; + u8 path_a_ofdm_2tx_pwr_idx_diff:4; + u8 rsvd14[0xf2]; + union { + struct rtw8852bx_u_efuse u; + struct rtw8852bx_e_efuse e; + }; +} __packed; + +struct rtw8852bx_bb_pmac_info { + u8 en_pmac_tx:1; + u8 is_cck:1; + u8 mode:3; + u8 rsvd:3; + u16 tx_cnt; + u16 period; + u16 tx_time; + u8 duty_cycle; +}; + +struct rtw8852bx_bb_tssi_bak { + u8 tx_path; + u8 rx_path; + u32 p0_rfmode; + u32 p0_rfmode_ftm; + u32 p1_rfmode; + u32 p1_rfmode_ftm; + s16 tx_pwr; /* S9 */ +}; + +struct rtw8852bx_info { + int (*mac_enable_bb_rf)(struct rtw89_dev *rtwdev); + int (*mac_disable_bb_rf)(struct rtw89_dev *rtwdev); + void (*bb_sethw)(struct rtw89_dev *rtwdev); + void (*bb_reset_all)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); + void (*bb_cfg_txrx_path)(struct rtw89_dev *rtwdev); + void (*bb_cfg_tx_path)(struct rtw89_dev *rtwdev, u8 tx_path); + void (*bb_ctrl_rx_path)(struct rtw89_dev *rtwdev, + enum rtw89_rf_path_bit rx_path); + void (*bb_set_plcp_tx)(struct rtw89_dev *rtwdev); + void (*bb_set_power)(struct rtw89_dev *rtwdev, s16 pwr_dbm, + enum rtw89_phy_idx idx); + void (*bb_set_pmac_pkt_tx)(struct rtw89_dev *rtwdev, u8 enable, + u16 tx_cnt, u16 period, u16 tx_time, + enum rtw89_phy_idx idx); + void (*bb_backup_tssi)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx idx, + struct rtw8852bx_bb_tssi_bak *bak); + void (*bb_restore_tssi)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx idx, + const struct rtw8852bx_bb_tssi_bak *bak); + void (*bb_tx_mode_switch)(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx idx, u8 mode); + void (*set_channel_mac)(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, u8 mac_idx); + void (*set_channel_bb)(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx); + void (*ctrl_nbtg_bt_tx)(struct rtw89_dev *rtwdev, bool en, + enum rtw89_phy_idx phy_idx); + void (*ctrl_btg_bt_rx)(struct rtw89_dev *rtwdev, bool en, + enum rtw89_phy_idx phy_idx); + void (*query_ppdu)(struct rtw89_dev *rtwdev, + struct rtw89_rx_phy_ppdu *phy_ppdu, + struct ieee80211_rx_status *status); + int (*read_efuse)(struct rtw89_dev *rtwdev, u8 *log_map, + enum rtw89_efuse_block block); + int (*read_phycap)(struct rtw89_dev *rtwdev, u8 *phycap_map); + void (*power_trim)(struct rtw89_dev *rtwdev); + void (*set_txpwr)(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx); + void (*set_txpwr_ctrl)(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx); + int (*init_txpwr_unit)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); + void (*set_txpwr_ul_tb_offset)(struct rtw89_dev *rtwdev, + s8 pw_ofst, enum rtw89_mac_idx mac_idx); + u8 (*get_thermal)(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path); +}; + +extern const struct rtw8852bx_info rtw8852bx_info; + +static inline +int rtw8852bx_mac_enable_bb_rf(struct rtw89_dev *rtwdev) +{ + return rtw8852bx_info.mac_enable_bb_rf(rtwdev); +} + +static inline +int rtw8852bx_mac_disable_bb_rf(struct rtw89_dev *rtwdev) +{ + return rtw8852bx_info.mac_disable_bb_rf(rtwdev); +} + +static inline +void rtw8852bx_bb_sethw(struct rtw89_dev *rtwdev) +{ + rtw8852bx_info.bb_sethw(rtwdev); +} + +static inline +void rtw8852bx_bb_reset_all(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + rtw8852bx_info.bb_reset_all(rtwdev, phy_idx); +} + +static inline +void rtw8852bx_bb_cfg_txrx_path(struct rtw89_dev *rtwdev) +{ + rtw8852bx_info.bb_cfg_txrx_path(rtwdev); +} + +static inline +void rtw8852bx_bb_cfg_tx_path(struct rtw89_dev *rtwdev, u8 tx_path) +{ + rtw8852bx_info.bb_cfg_tx_path(rtwdev, tx_path); +} + +static inline +void rtw8852bx_bb_ctrl_rx_path(struct rtw89_dev *rtwdev, + enum rtw89_rf_path_bit rx_path) +{ + rtw8852bx_info.bb_ctrl_rx_path(rtwdev, rx_path); +} + +static inline +void rtw8852bx_bb_set_plcp_tx(struct rtw89_dev *rtwdev) +{ + rtw8852bx_info.bb_set_plcp_tx(rtwdev); +} + +static inline +void rtw8852bx_bb_set_power(struct rtw89_dev *rtwdev, s16 pwr_dbm, + enum rtw89_phy_idx idx) +{ + rtw8852bx_info.bb_set_power(rtwdev, pwr_dbm, idx); +} + +static inline +void rtw8852bx_bb_set_pmac_pkt_tx(struct rtw89_dev *rtwdev, u8 enable, + u16 tx_cnt, u16 period, u16 tx_time, + enum rtw89_phy_idx idx) +{ + rtw8852bx_info.bb_set_pmac_pkt_tx(rtwdev, enable, tx_cnt, period, tx_time, idx); +} + +static inline +void rtw8852bx_bb_backup_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx idx, + struct rtw8852bx_bb_tssi_bak *bak) +{ + rtw8852bx_info.bb_backup_tssi(rtwdev, idx, bak); +} + +static inline +void rtw8852bx_bb_restore_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx idx, + const struct rtw8852bx_bb_tssi_bak *bak) +{ + rtw8852bx_info.bb_restore_tssi(rtwdev, idx, bak); +} + +static inline +void rtw8852bx_bb_tx_mode_switch(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx idx, u8 mode) +{ + rtw8852bx_info.bb_tx_mode_switch(rtwdev, idx, mode); +} + +static inline +void rtw8852bx_set_channel_mac(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, u8 mac_idx) +{ + rtw8852bx_info.set_channel_mac(rtwdev, chan, mac_idx); +} + +static inline +void rtw8852bx_set_channel_bb(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + rtw8852bx_info.set_channel_bb(rtwdev, chan, phy_idx); +} + +static inline +void rtw8852bx_ctrl_nbtg_bt_tx(struct rtw89_dev *rtwdev, bool en, + enum rtw89_phy_idx phy_idx) +{ + rtw8852bx_info.ctrl_nbtg_bt_tx(rtwdev, en, phy_idx); +} + +static inline +void rtw8852bx_ctrl_btg_bt_rx(struct rtw89_dev *rtwdev, bool en, + enum rtw89_phy_idx phy_idx) +{ + rtw8852bx_info.ctrl_btg_bt_rx(rtwdev, en, phy_idx); +} + +static inline +void rtw8852bx_query_ppdu(struct rtw89_dev *rtwdev, + struct rtw89_rx_phy_ppdu *phy_ppdu, + struct ieee80211_rx_status *status) +{ + rtw8852bx_info.query_ppdu(rtwdev, phy_ppdu, status); +} + +static inline +int rtw8852bx_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, + enum rtw89_efuse_block block) +{ + return rtw8852bx_info.read_efuse(rtwdev, log_map, block); +} + +static inline +int rtw8852bx_read_phycap(struct rtw89_dev *rtwdev, u8 *phycap_map) +{ + return rtw8852bx_info.read_phycap(rtwdev, phycap_map); +} + +static inline +void rtw8852bx_power_trim(struct rtw89_dev *rtwdev) +{ + rtw8852bx_info.power_trim(rtwdev); +} + +static inline +void rtw8852bx_set_txpwr(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + rtw8852bx_info.set_txpwr(rtwdev, chan, phy_idx); +} + +static inline +void rtw8852bx_set_txpwr_ctrl(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) +{ + rtw8852bx_info.set_txpwr_ctrl(rtwdev, phy_idx); +} + +static inline +int rtw8852bx_init_txpwr_unit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + return rtw8852bx_info.init_txpwr_unit(rtwdev, phy_idx); +} + +static inline +void rtw8852bx_set_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev, + s8 pw_ofst, enum rtw89_mac_idx mac_idx) +{ + rtw8852bx_info.set_txpwr_ul_tb_offset(rtwdev, pw_ofst, mac_idx); +} + +static inline +u8 rtw8852bx_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path) +{ + return rtw8852bx_info.get_thermal(rtwdev, rf_path); +} + +#endif diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c index 259df67836a0..7c90e98dc1d9 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c @@ -8,6 +8,7 @@ #include "phy.h" #include "reg.h" #include "rtw8852b.h" +#include "rtw8852b_common.h" #include "rtw8852b_rfk.h" #include "rtw8852b_rfk_table.h" #include "rtw8852b_table.h" @@ -3433,13 +3434,13 @@ static void _tssi_hw_tx(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, rx_path = RF_ABCD; /* don't change path, but still set others */ if (enable) { - rtw8852b_bb_set_plcp_tx(rtwdev); - rtw8852b_bb_cfg_tx_path(rtwdev, path); - rtw8852b_bb_ctrl_rx_path(rtwdev, rx_path); - rtw8852b_bb_set_power(rtwdev, pwr_dbm, phy); + rtw8852bx_bb_set_plcp_tx(rtwdev); + rtw8852bx_bb_cfg_tx_path(rtwdev, path); + rtw8852bx_bb_ctrl_rx_path(rtwdev, rx_path); + rtw8852bx_bb_set_power(rtwdev, pwr_dbm, phy); } - rtw8852b_bb_set_pmac_pkt_tx(rtwdev, enable, cnt, period, 20, phy); + rtw8852bx_bb_set_pmac_pkt_tx(rtwdev, enable, cnt, period, 20, phy); } static void _tssi_backup_bb_registers(struct rtw89_dev *rtwdev, @@ -3578,7 +3579,7 @@ static void _tssi_alimentk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, u32 tssi_cw_rpt[RTW8852B_TSSI_PATH_NR] = {0}; u8 channel = chan->channel; u8 ch_idx = _tssi_ch_to_idx(rtwdev, channel); - struct rtw8852b_bb_tssi_bak tssi_bak; + struct rtw8852bx_bb_tssi_bak tssi_bak; s32 aliment_diff, tssi_cw_default; u32 start_time, finish_time; u32 bb_reg_backup[8] = {0}; @@ -3626,7 +3627,7 @@ static void _tssi_alimentk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, else band = TSSI_ALIMK_2G; - rtw8852b_bb_backup_tssi(rtwdev, phy, &tssi_bak); + rtw8852bx_bb_backup_tssi(rtwdev, phy, &tssi_bak); _tssi_backup_bb_registers(rtwdev, phy, bb_reg, bb_reg_backup, ARRAY_SIZE(bb_reg_backup)); rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_AVG, B_P0_TSSI_AVG, 0x8); @@ -3730,8 +3731,8 @@ static void _tssi_alimentk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, out: _tssi_reload_bb_registers(rtwdev, phy, bb_reg, bb_reg_backup, ARRAY_SIZE(bb_reg_backup)); - rtw8852b_bb_restore_tssi(rtwdev, phy, &tssi_bak); - rtw8852b_bb_tx_mode_switch(rtwdev, phy, 0); + rtw8852bx_bb_restore_tssi(rtwdev, phy, &tssi_bak); + rtw8852bx_bb_tx_mode_switch(rtwdev, phy, 0); finish_time = ktime_get_ns(); tssi_info->tssi_alimk_time += finish_time - start_time; From 2ab298cf638c105e248156d7a7b2301f071f6543 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 7 Jun 2024 15:06:58 +0800 Subject: [PATCH 012/204] wifi: rtw89: 8852bx: add extra handles for 8852BT in 8852b_common The channel configuration of 8852BT is very similar but a little different to 8852B, so use chip ID as condition to add extra handles including external loss compensation, ADC configurations, spur settings and so on. Don't affect existing 8852BE. Signed-off-by: Ping-Ke Shih Link: https://msgid.link/20240607070659.80263-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/Makefile | 3 +- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/phy.h | 1 + drivers/net/wireless/realtek/rtw89/reg.h | 6 + .../wireless/realtek/rtw89/rtw8852b_common.c | 195 +++++++++++++++++- .../wireless/realtek/rtw89/rtw8852b_common.h | 7 + drivers/net/wireless/realtek/rtw89/util.c | 106 ++++++++++ drivers/net/wireless/realtek/rtw89/util.h | 5 + 8 files changed, 315 insertions(+), 9 deletions(-) create mode 100644 drivers/net/wireless/realtek/rtw89/util.c diff --git a/drivers/net/wireless/realtek/rtw89/Makefile b/drivers/net/wireless/realtek/rtw89/Makefile index 688847ce7084..1f1050a7a89d 100644 --- a/drivers/net/wireless/realtek/rtw89/Makefile +++ b/drivers/net/wireless/realtek/rtw89/Makefile @@ -17,7 +17,8 @@ rtw89_core-y += core.o \ ps.o \ chan.o \ ser.o \ - acpi.o + acpi.o \ + util.o rtw89_core-$(CONFIG_PM) += wow.o diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 68221f0b156e..874119b5007d 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -132,6 +132,7 @@ enum rtw89_hci_type { enum rtw89_core_chip_id { RTL8852A, RTL8852B, + RTL8852BT, RTL8852C, RTL8851B, RTL8922A, diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 082231ebbee5..6e53ac9140fb 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -129,6 +129,7 @@ #define EDCCA_HL_DIFF_NORMAL 8 #define RSSI_UNIT_CONVER 110 #define EDCCA_UNIT_CONVER 128 +#define EDCCA_PWROFST_DEFAULT 18 enum rtw89_phy_c2h_ra_func { RTW89_PHY_C2H_FUNC_STS_RPT, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 01cbd0312102..dc78ffc39ae7 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -7872,6 +7872,7 @@ #define B_UPD_CLK_ADC_ON BIT(24) #define B_ENABLE_CCK BIT(5) #define R_RSTB_ASYNC 0x0704 +#define B_RSTB_ASYNC_BW80 GENMASK(9, 8) #define B_RSTB_ASYNC_ALL BIT(1) #define R_P0_ANT_SW 0x0728 #define B_P0_HW_ANTSW_DIS_BY_GNT_BT BIT(12) @@ -8379,6 +8380,7 @@ #define B_CDD_EVM_CHK_EN BIT(0) #define R_PATH0_BAND_SEL_V1 0x4738 #define B_PATH0_BAND_SEL_MSK_V1 BIT(17) +#define B_PATH0_BAND_NRBW_EN_V1 BIT(16) #define R_PATH0_BT_SHARE_V1 0x4738 #define B_PATH0_BT_SHARE_V1 BIT(19) #define R_PATH0_BTG_PATH_V1 0x4738 @@ -8422,6 +8424,7 @@ #define B_PATH1_G_TIA1_LNA6_OP1DB_V1 GENMASK(15, 8) #define R_PATH1_BAND_SEL_V1 0x4AA4 #define B_PATH1_BAND_SEL_MSK_V1 BIT(17) +#define B_PATH1_BAND_NRBW_EN_V1 BIT(16) #define R_PATH1_BT_SHARE_V1 0x4AA4 #define B_PATH1_BT_SHARE_V1 BIT(19) #define R_PATH1_BTG_PATH_V1 0x4AA4 @@ -8442,6 +8445,8 @@ #define B_SEG0R_PD_SPATIAL_REUSE_EN_MSK_V1 BIT(30) #define B_SEG0R_PD_SPATIAL_REUSE_EN_MSK BIT(29) #define B_SEG0R_PD_LOWER_BOUND_MSK GENMASK(10, 6) +#define R_PWOFST 0x488C +#define B_PWOFST GENMASK(21, 17) #define R_2P4G_BAND 0x4970 #define B_2P4G_BAND_SEL BIT(1) #define R_FC0_BW 0x4974 @@ -9095,6 +9100,7 @@ #define R_ADCMOD 0xC0E8 #define B_ADCMOD_LP GENMASK(31, 16) #define R_DCIM 0xC0EC +#define B_DCIM_RC GENMASK(23, 16) #define B_DCIM_FR GENMASK(14, 13) #define R_ADDCK0D 0xC0F0 #define B_ADDCK0D_VAL2 GENMASK(31, 26) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c index 0826d257ddba..60e9bd5b1376 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c @@ -7,6 +7,7 @@ #include "phy.h" #include "reg.h" #include "rtw8852b_common.h" +#include "util.h" static const struct rtw89_reg3_def rtw8852bx_pmac_ht20_mcs7_tbl[] = { {0x4580, 0x0000ffff, 0x0}, @@ -609,6 +610,27 @@ static void rtw8852bx_set_gain_error(struct rtw89_dev *rtwdev, } } +static void rtw8852bt_ext_loss_avg_update(struct rtw89_dev *rtwdev, + s8 ext_loss_a, s8 ext_loss_b) +{ + s8 ext_loss_avg; + u64 linear; + u8 pwrofst; + + if (ext_loss_a == ext_loss_b) { + ext_loss_avg = ext_loss_a; + } else { + linear = rtw89_db_2_linear(abs(ext_loss_a - ext_loss_b)) + 1; + linear = DIV_ROUND_CLOSEST_ULL(linear / 2, 1 << RTW89_LINEAR_FRAC_BITS); + ext_loss_avg = rtw89_linear_2_db(linear); + ext_loss_avg += min(ext_loss_a, ext_loss_b); + } + + pwrofst = max(DIV_ROUND_CLOSEST(ext_loss_avg, 4) + 16, EDCCA_PWROFST_DEFAULT); + + rtw89_phy_write32_mask(rtwdev, R_PWOFST, B_PWOFST, pwrofst); +} + static void rtw8852bx_set_gain_offset(struct rtw89_dev *rtwdev, enum rtw89_subband subband, enum rtw89_phy_idx phy_idx) @@ -619,6 +641,7 @@ static void rtw8852bx_set_gain_offset(struct rtw89_dev *rtwdev, struct rtw89_hal *hal = &rtwdev->hal; struct rtw89_phy_efuse_gain *efuse_gain = &rtwdev->efuse_gain; enum rtw89_gain_offset gain_ofdm_band; + s8 ext_loss_a = 0, ext_loss_b = 0; s32 offset_a, offset_b; s32 offset_ofdm, offset_cck; s32 tmp; @@ -635,7 +658,7 @@ static void rtw8852bx_set_gain_offset(struct rtw89_dev *rtwdev, next: if (!efuse_gain->offset_valid) - return; + goto ext_loss; gain_ofdm_band = rtw89_subband_to_gain_offset_band_of_ofdm(subband); @@ -672,6 +695,13 @@ static void rtw8852bx_set_gain_offset(struct rtw89_dev *rtwdev, rtw89_phy_write32_mask(rtwdev, R_RX_RPL_OFST, B_RX_RPL_OFST_CCK_MASK, tmp); } + + ext_loss_a = (offset_a << 2) + (efuse_gain->offset_base[RTW89_PHY_0] >> 2); + ext_loss_b = (offset_b << 2) + (efuse_gain->offset_base[RTW89_PHY_0] >> 2); + +ext_loss: + if (rtwdev->chip->chip_id == RTL8852BT) + rtw8852bt_ext_loss_avg_update(rtwdev, ext_loss_a, ext_loss_b); } static @@ -804,10 +834,79 @@ static void rtw8852b_bw_setting(struct rtw89_dev *rtwdev, u8 bw, u8 path) } } +static +void rtw8852bt_adc_cfg(struct rtw89_dev *rtwdev, u8 bw, u8 path) +{ + static const u32 rck_reset_count[2] = {0xC0E8, 0xC1E8}; + static const u32 adc_op5_bw_sel[2] = {0xC0D8, 0xC1D8}; + static const u32 adc_sample_td[2] = {0xC0D4, 0xC1D4}; + static const u32 adc_rst_cycle[2] = {0xC0EC, 0xC1EC}; + static const u32 decim_filter[2] = {0xC0EC, 0xC1EC}; + static const u32 rck_offset[2] = {0xC0C4, 0xC1C4}; + static const u32 rx_adc_clk[2] = {0x12A0, 0x32A0}; + static const u32 wbadc_sel[2] = {0xC0E4, 0xC1E4}; + static const u32 idac2_1[2] = {0xC0D4, 0xC1D4}; + static const u32 idac2[2] = {0xC0D4, 0xC1D4}; + static const u32 upd_clk_adc = {0x704}; + + if (rtwdev->chip->chip_id != RTL8852BT) + return; + + rtw89_phy_write32_mask(rtwdev, idac2[path], B_P0_CFCH_CTL, 0x8); + rtw89_phy_write32_mask(rtwdev, rck_reset_count[path], B_ADCMOD_LP, 0x9); + rtw89_phy_write32_mask(rtwdev, wbadc_sel[path], B_WDADC_SEL, 0x2); + rtw89_phy_write32_mask(rtwdev, rx_adc_clk[path], B_P0_RXCK_ADJ, 0x49); + rtw89_phy_write32_mask(rtwdev, decim_filter[path], B_DCIM_FR, 0x0); + + switch (bw) { + case RTW89_CHANNEL_WIDTH_5: + case RTW89_CHANNEL_WIDTH_10: + case RTW89_CHANNEL_WIDTH_20: + case RTW89_CHANNEL_WIDTH_40: + rtw89_phy_write32_mask(rtwdev, idac2_1[path], B_P0_CFCH_EN, 0x2); + rtw89_phy_write32_mask(rtwdev, adc_sample_td[path], B_P0_CFCH_BW0, 0x3); + rtw89_phy_write32_mask(rtwdev, adc_op5_bw_sel[path], B_P0_CFCH_BW1, 0xf); + rtw89_phy_write32_mask(rtwdev, rck_offset[path], B_DRCK_MUL, 0x0); + /* Tx TSSI ADC update */ + rtw89_phy_write32_mask(rtwdev, upd_clk_adc, B_RSTB_ASYNC_BW80, 0); + + if (rtwdev->efuse.rfe_type >= 51) + rtw89_phy_write32_mask(rtwdev, adc_rst_cycle[path], B_DCIM_RC, 0x2); + else + rtw89_phy_write32_mask(rtwdev, adc_rst_cycle[path], B_DCIM_RC, 0x3); + break; + case RTW89_CHANNEL_WIDTH_80: + rtw89_phy_write32_mask(rtwdev, idac2_1[path], B_P0_CFCH_EN, 0x2); + rtw89_phy_write32_mask(rtwdev, adc_sample_td[path], B_P0_CFCH_BW0, 0x2); + rtw89_phy_write32_mask(rtwdev, adc_op5_bw_sel[path], B_P0_CFCH_BW1, 0x8); + rtw89_phy_write32_mask(rtwdev, rck_offset[path], B_DRCK_MUL, 0x0); + rtw89_phy_write32_mask(rtwdev, adc_rst_cycle[path], B_DCIM_RC, 0x3); + /* Tx TSSI ADC update */ + rtw89_phy_write32_mask(rtwdev, upd_clk_adc, B_RSTB_ASYNC_BW80, 1); + break; + case RTW89_CHANNEL_WIDTH_160: + rtw89_phy_write32_mask(rtwdev, idac2_1[path], B_P0_CFCH_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, adc_sample_td[path], B_P0_CFCH_BW0, 0x2); + rtw89_phy_write32_mask(rtwdev, adc_op5_bw_sel[path], B_P0_CFCH_BW1, 0x4); + rtw89_phy_write32_mask(rtwdev, rck_offset[path], B_DRCK_MUL, 0x6); + rtw89_phy_write32_mask(rtwdev, adc_rst_cycle[path], B_DCIM_RC, 0x3); + /* Tx TSSI ADC update */ + rtw89_phy_write32_mask(rtwdev, upd_clk_adc, B_RSTB_ASYNC_BW80, 2); + break; + default: + rtw89_warn(rtwdev, "Fail to set ADC\n"); + break; + } +} + static void rtw8852bx_ctrl_bw(struct rtw89_dev *rtwdev, u8 pri_ch, u8 bw, enum rtw89_phy_idx phy_idx) { + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; u32 rx_path_0; + u32 val; + + rx_path_0 = rtw89_phy_read32_idx(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, phy_idx); switch (bw) { case RTW89_CHANNEL_WIDTH_5: @@ -820,6 +919,12 @@ static void rtw8852bx_ctrl_bw(struct rtw89_dev *rtwdev, u8 pri_ch, u8 bw, B_P0_RFMODE_ORI_RX_ALL, 0x333, phy_idx); rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, B_P1_RFMODE_ORI_RX_ALL, 0x333, phy_idx); + if (chip_id == RTL8852BT) { + rtw89_phy_write32_idx(rtwdev, R_PATH0_BAND_SEL_V1, + B_PATH0_BAND_NRBW_EN_V1, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PATH1_BAND_SEL_V1, + B_PATH1_BAND_NRBW_EN_V1, 0x0, phy_idx); + } break; case RTW89_CHANNEL_WIDTH_10: rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x0, phy_idx); @@ -831,6 +936,12 @@ static void rtw8852bx_ctrl_bw(struct rtw89_dev *rtwdev, u8 pri_ch, u8 bw, B_P0_RFMODE_ORI_RX_ALL, 0x333, phy_idx); rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, B_P1_RFMODE_ORI_RX_ALL, 0x333, phy_idx); + if (chip_id == RTL8852BT) { + rtw89_phy_write32_idx(rtwdev, R_PATH0_BAND_SEL_V1, + B_PATH0_BAND_NRBW_EN_V1, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PATH1_BAND_SEL_V1, + B_PATH1_BAND_NRBW_EN_V1, 0x0, phy_idx); + } break; case RTW89_CHANNEL_WIDTH_20: rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x0, phy_idx); @@ -842,6 +953,12 @@ static void rtw8852bx_ctrl_bw(struct rtw89_dev *rtwdev, u8 pri_ch, u8 bw, B_P0_RFMODE_ORI_RX_ALL, 0x333, phy_idx); rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, B_P1_RFMODE_ORI_RX_ALL, 0x333, phy_idx); + if (chip_id == RTL8852BT) { + rtw89_phy_write32_idx(rtwdev, R_PATH0_BAND_SEL_V1, + B_PATH0_BAND_NRBW_EN_V1, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PATH1_BAND_SEL_V1, + B_PATH1_BAND_NRBW_EN_V1, 0x1, phy_idx); + } break; case RTW89_CHANNEL_WIDTH_40: rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x1, phy_idx); @@ -868,21 +985,25 @@ static void rtw8852bx_ctrl_bw(struct rtw89_dev *rtwdev, u8 pri_ch, u8 bw, pri_ch, phy_idx); /*Set RF mode at A */ + val = chip_id == RTL8852BT ? 0x333 : 0xaaa; rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX, - B_P0_RFMODE_ORI_RX_ALL, 0xaaa, phy_idx); + B_P0_RFMODE_ORI_RX_ALL, val, phy_idx); rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, - B_P1_RFMODE_ORI_RX_ALL, 0xaaa, phy_idx); + B_P1_RFMODE_ORI_RX_ALL, val, phy_idx); break; default: rtw89_warn(rtwdev, "Fail to switch bw (bw:%d, pri ch:%d)\n", bw, pri_ch); } - rtw8852b_bw_setting(rtwdev, bw, RF_PATH_A); - rtw8852b_bw_setting(rtwdev, bw, RF_PATH_B); + if (chip_id == RTL8852B) { + rtw8852b_bw_setting(rtwdev, bw, RF_PATH_A); + rtw8852b_bw_setting(rtwdev, bw, RF_PATH_B); + } else if (chip_id == RTL8852BT) { + rtw8852bt_adc_cfg(rtwdev, bw, RF_PATH_A); + rtw8852bt_adc_cfg(rtwdev, bw, RF_PATH_B); + } - rx_path_0 = rtw89_phy_read32_idx(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, - phy_idx); if (rx_path_0 == 0x1) rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, B_P1_RFMODE_ORI_RX_ALL, 0x111, phy_idx); @@ -1001,10 +1122,56 @@ static void rtw8852bx_bb_set_pop(struct rtw89_dev *rtwdev) rtw89_phy_write32_clr(rtwdev, R_PKT_CTRL, B_PKT_POP_EN); } +static u32 rtw8852bt_spur_freq(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan) +{ + u8 center_chan = chan->channel; + + switch (chan->band_type) { + case RTW89_BAND_5G: + if (center_chan == 151 || center_chan == 153 || + center_chan == 155 || center_chan == 163) + return 5760; + break; + default: + break; + } + + return 0; +} + +#define CARRIER_SPACING_312_5 312500 /* 312.5 kHz */ +#define CARRIER_SPACING_78_125 78125 /* 78.125 kHz */ +#define MAX_TONE_NUM 2048 + +static void rtw8852bt_set_csi_tone_idx(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + s32 freq_diff, csi_idx, csi_tone_idx; + u32 spur_freq; + + spur_freq = rtw8852bt_spur_freq(rtwdev, chan); + if (spur_freq == 0) { + rtw89_phy_write32_idx(rtwdev, R_SEG0CSI_EN_V1, B_SEG0CSI_EN, + 0, phy_idx); + return; + } + + freq_diff = (spur_freq - chan->freq) * 1000000; + csi_idx = s32_div_u32_round_closest(freq_diff, CARRIER_SPACING_78_125); + s32_div_u32_round_down(csi_idx, MAX_TONE_NUM, &csi_tone_idx); + + rtw89_phy_write32_idx(rtwdev, R_SEG0CSI_V1, B_SEG0CSI_IDX, + csi_tone_idx, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_SEG0CSI_EN_V1, B_SEG0CSI_EN, 1, phy_idx); +} + static void __rtw8852bx_set_channel_bb(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx) { + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; bool cck_en = chan->channel <= 14; u8 pri_ch_idx = chan->pri_ch_idx; u8 band = chan->band_type, chan_idx; @@ -1015,7 +1182,9 @@ void __rtw8852bx_set_channel_bb(struct rtw89_dev *rtwdev, const struct rtw89_cha rtw8852bx_ctrl_ch(rtwdev, chan, phy_idx); rtw8852bx_ctrl_bw(rtwdev, pri_ch_idx, chan->band_width, phy_idx); rtw8852bx_ctrl_cck_en(rtwdev, cck_en); - if (chan->band_type == RTW89_BAND_5G) { + if (chip_id == RTL8852BT) + rtw8852bt_set_csi_tone_idx(rtwdev, chan, phy_idx); + if (chip_id == RTL8852B && chan->band_type == RTW89_BAND_5G) { rtw89_phy_write32_mask(rtwdev, R_PATH0_BT_SHARE_V1, B_PATH0_BT_SHARE_V1, 0x0); rtw89_phy_write32_mask(rtwdev, R_PATH0_BTG_PATH_V1, @@ -1614,6 +1783,8 @@ static void __rtw8852bx_query_ppdu(struct rtw89_dev *rtwdev, static int __rtw8852bx_mac_enable_bb_rf(struct rtw89_dev *rtwdev) { + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; + u32 val32; int ret; rtw89_write8_set(rtwdev, R_AX_SYS_FUNC_EN, @@ -1623,6 +1794,13 @@ static int __rtw8852bx_mac_enable_bb_rf(struct rtw89_dev *rtwdev) rtw89_write32_clr(rtwdev, R_AX_WLRF_CTRL, B_AX_AFC_AFEDIG); rtw89_write32_set(rtwdev, R_AX_WLRF_CTRL, B_AX_AFC_AFEDIG); + if (chip_id == RTL8852BT) { + val32 = rtw89_read32(rtwdev, R_AX_AFE_OFF_CTRL1); + val32 = u32_replace_bits(val32, 0x1, B_AX_S0_LDO_VSEL_F_MASK); + val32 = u32_replace_bits(val32, 0x1, B_AX_S1_LDO_VSEL_F_MASK); + rtw89_write32(rtwdev, R_AX_AFE_OFF_CTRL1, val32); + } + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S0, 0xC7, FULL_BIT_MASK); if (ret) @@ -1693,6 +1871,7 @@ const struct rtw8852bx_info rtw8852bx_info = { .init_txpwr_unit = __rtw8852bx_init_txpwr_unit, .set_txpwr_ul_tb_offset = __rtw8852bx_set_txpwr_ul_tb_offset, .get_thermal = __rtw8852bx_get_thermal, + .adc_cfg = rtw8852bt_adc_cfg, }; EXPORT_SYMBOL(rtw8852bx_info); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.h b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.h index 2348a13545ac..b8e3f20ba189 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.h @@ -158,6 +158,7 @@ struct rtw8852bx_info { void (*set_txpwr_ul_tb_offset)(struct rtw89_dev *rtwdev, s8 pw_ofst, enum rtw89_mac_idx mac_idx); u8 (*get_thermal)(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path); + void (*adc_cfg)(struct rtw89_dev *rtwdev, u8 bw, u8 path); }; extern const struct rtw8852bx_info rtw8852bx_info; @@ -336,4 +337,10 @@ u8 rtw8852bx_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path) return rtw8852bx_info.get_thermal(rtwdev, rf_path); } +static inline +void rtw8852bx_adc_cfg(struct rtw89_dev *rtwdev, u8 bw, u8 path) +{ + rtw8852bx_info.adc_cfg(rtwdev, bw, path); +} + #endif diff --git a/drivers/net/wireless/realtek/rtw89/util.c b/drivers/net/wireless/realtek/rtw89/util.c new file mode 100644 index 000000000000..e71956ce9853 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/util.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2024 Realtek Corporation + */ + +#include "util.h" + +#define FRAC_ROWS 3 +#define FRAC_ROW_MAX (FRAC_ROWS - 1) +#define NORM_ROW_MIN FRAC_ROWS + +static const u32 db_invert_table[12][8] = { + /* rows 0~2 in unit of U(32,3) */ + {10, 13, 16, 20, 25, 32, 40, 50}, + {64, 80, 101, 128, 160, 201, 256, 318}, + {401, 505, 635, 800, 1007, 1268, 1596, 2010}, + /* rows 3~11 in unit of U(32,0) */ + {316, 398, 501, 631, 794, 1000, 1259, 1585}, + {1995, 2512, 3162, 3981, 5012, 6310, 7943, 10000}, + {12589, 15849, 19953, 25119, 31623, 39811, 50119, 63098}, + {79433, 100000, 125893, 158489, 199526, 251189, 316228, 398107}, + {501187, 630957, 794328, 1000000, 1258925, 1584893, 1995262, 2511886}, + {3162278, 3981072, 5011872, 6309573, 7943282, 1000000, 12589254, + 15848932}, + {19952623, 25118864, 31622777, 39810717, 50118723, 63095734, 79432823, + 100000000}, + {125892541, 158489319, 199526232, 251188643, 316227766, 398107171, + 501187234, 630957345}, + {794328235, 1000000000, 1258925412, 1584893192, 1995262315, 2511886432U, + 3162277660U, 3981071706U}, +}; + +u32 rtw89_linear_2_db(u64 val) +{ + u8 i, j; + u32 dB; + + for (i = 0; i < 12; i++) { + for (j = 0; j < 8; j++) { + if (i <= FRAC_ROW_MAX && + (val << RTW89_LINEAR_FRAC_BITS) <= db_invert_table[i][j]) + goto cnt; + else if (i > FRAC_ROW_MAX && val <= db_invert_table[i][j]) + goto cnt; + } + } + + return 96; /* maximum 96 dB */ + +cnt: + /* special cases */ + if (j == 0 && i == 0) + goto end; + + if (i == NORM_ROW_MIN && j == 0) { + if (db_invert_table[NORM_ROW_MIN][0] - val > + val - (db_invert_table[FRAC_ROW_MAX][7] >> RTW89_LINEAR_FRAC_BITS)) { + i = FRAC_ROW_MAX; + j = 7; + } + goto end; + } + + if (i <= FRAC_ROW_MAX) + val <<= RTW89_LINEAR_FRAC_BITS; + + /* compare difference to get precise dB */ + if (j == 0) { + if (db_invert_table[i][j] - val > + val - db_invert_table[i - 1][7]) { + i--; + j = 7; + } + } else { + if (db_invert_table[i][j] - val > + val - db_invert_table[i][j - 1]) { + j--; + } + } +end: + dB = (i << 3) + j + 1; + + return dB; +} +EXPORT_SYMBOL(rtw89_linear_2_db); + +u64 rtw89_db_2_linear(u32 db) +{ + u64 linear; + u8 i, j; + + if (db > 96) + db = 96; + else if (db < 1) + return 1; + + i = (db - 1) >> 3; + j = (db - 1) & 0x7; + + linear = db_invert_table[i][j]; + + if (i >= NORM_ROW_MIN) + linear = linear << RTW89_LINEAR_FRAC_BITS; + + return linear; +} +EXPORT_SYMBOL(rtw89_db_2_linear); diff --git a/drivers/net/wireless/realtek/rtw89/util.h b/drivers/net/wireless/realtek/rtw89/util.h index e2ed4565025d..e82e7df052d8 100644 --- a/drivers/net/wireless/realtek/rtw89/util.h +++ b/drivers/net/wireless/realtek/rtw89/util.h @@ -6,6 +6,8 @@ #include "core.h" +#define RTW89_LINEAR_FRAC_BITS 3 + #define rtw89_iterate_vifs_bh(rtwdev, iterator, data) \ ieee80211_iterate_active_interfaces_atomic((rtwdev)->hw, \ IEEE80211_IFACE_ITER_NORMAL, iterator, data) @@ -55,4 +57,7 @@ static inline void ether_addr_copy_mask(u8 *dst, const u8 *src, u8 mask) } } +u32 rtw89_linear_2_db(u64 linear); +u64 rtw89_db_2_linear(u32 db); + #endif From 190dc12d0649b7d8709c98c10926ea0c001f955b Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 7 Jun 2024 15:06:59 +0800 Subject: [PATCH 013/204] wifi: rtw89: 885xbx: apply common settings to 8851B, 8852B and 8852BT Many common settings can share to 8851B, 8852B and 8852BT, so add an inline function rtw89_is_rtl885xb() to be concise. Meanwhile review and align settings for existing chips. Signed-off-by: Ping-Ke Shih Link: https://msgid.link/20240607070659.80263-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/cam.c | 1 + drivers/net/wireless/realtek/rtw89/coex.c | 3 +- drivers/net/wireless/realtek/rtw89/core.c | 2 +- drivers/net/wireless/realtek/rtw89/core.h | 10 +++++ drivers/net/wireless/realtek/rtw89/debug.c | 2 +- drivers/net/wireless/realtek/rtw89/mac.c | 43 +++++++++++----------- drivers/net/wireless/realtek/rtw89/pci.c | 38 +++++++++---------- drivers/net/wireless/realtek/rtw89/phy.c | 2 +- drivers/net/wireless/realtek/rtw89/reg.h | 2 + 9 files changed, 57 insertions(+), 46 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/cam.c b/drivers/net/wireless/realtek/rtw89/cam.c index 35291efbbae9..4557c6e035a9 100644 --- a/drivers/net/wireless/realtek/rtw89/cam.c +++ b/drivers/net/wireless/realtek/rtw89/cam.c @@ -523,6 +523,7 @@ static u8 rtw89_get_addr_cam_entry_size(struct rtw89_dev *rtwdev) case RTL8852A: case RTL8852B: case RTL8851B: + case RTL8852BT: return ADDR_CAM_ENT_SIZE; default: return ADDR_CAM_ENT_SHORT_SIZE; diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index c443b39ab3c6..d8fc93318a51 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -228,6 +228,7 @@ static u32 chip_id_to_bt_rom_code_id(u32 id) case RTL8852A: case RTL8852B: case RTL8852C: + case RTL8852BT: return 0x8852; case RTL8851B: return 0x8851; @@ -9514,7 +9515,7 @@ static void _get_gnt(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_coex_gnt *gnt u32 val, status; if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B || - chip->chip_id == RTL8851B) { + chip->chip_id == RTL8851B || chip->chip_id == RTL8852BT) { rtw89_mac_read_lte(rtwdev, R_AX_LTE_SW_CFG_1, &val); rtw89_mac_read_lte(rtwdev, R_AX_GNT_VAL, &status); diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index fe403fb7e8a2..87c38cdc691b 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -4382,7 +4382,7 @@ static void rtw89_read_chip_ver(struct rtw89_dev *rtwdev) rtwdev->hal.cv = cv; - if (chip->chip_id == RTL8852B || chip->chip_id == RTL8851B) { + if (rtw89_is_rtl885xb(rtwdev)) { ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_CV, &val); if (ret) return; diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 874119b5007d..e8ec0246bccd 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -6421,6 +6421,16 @@ static inline bool rtw89_is_mlo_1_1(struct rtw89_dev *rtwdev) } } +static inline bool rtw89_is_rtl885xb(struct rtw89_dev *rtwdev) +{ + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; + + if (chip_id == RTL8852B || chip_id == RTL8851B || chip_id == RTL8852BT) + return true; + + return false; +} + 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/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index 210f192ac9ec..49bbbd049316 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -2996,7 +2996,7 @@ static bool is_dbg_port_valid(struct rtw89_dev *rtwdev, u32 sel) sel >= RTW89_DBG_PORT_SEL_PCIE_TXDMA && sel <= RTW89_DBG_PORT_SEL_PCIE_MISC2) return false; - if (rtwdev->chip->chip_id == RTL8852B && + if (rtw89_is_rtl885xb(rtwdev) && sel >= RTW89_DBG_PORT_SEL_PTCL_C1 && sel <= RTW89_DBG_PORT_SEL_TXTF_INFOH_C1) return false; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 824ece03d92d..b759fa8fbca9 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1568,6 +1568,8 @@ static int dmac_func_en_ax(struct rtw89_dev *rtwdev) B_AX_DLE_CPUIO_CLK_EN | B_AX_PKT_IN_CLK_EN | B_AX_STA_SCH_CLK_EN | B_AX_TXPKT_CTRL_CLK_EN | B_AX_WD_RLS_CLK_EN | B_AX_BBRPT_CLK_EN); + if (chip_id == RTL8852BT) + val32 |= B_AX_AXIDMA_CLK_EN; rtw89_write32(rtwdev, R_AX_DMAC_CLK_EN, val32); return 0; @@ -1577,7 +1579,7 @@ static int chip_func_en_ax(struct rtw89_dev *rtwdev) { enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; - if (chip_id == RTL8852A || chip_id == RTL8852B) + if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) rtw89_write32_set(rtwdev, R_AX_SPS_DIG_ON_CTRL0, B_AX_OCP_L1_MASK); @@ -2146,8 +2148,8 @@ int rtw89_mac_preload_init(struct rtw89_dev *rtwdev, enum rtw89_mac_idx mac_idx, { const struct rtw89_chip_info *chip = rtwdev->chip; - if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B || - chip->chip_id == RTL8851B || !is_qta_poh(rtwdev)) + if (chip->chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev) || + !is_qta_poh(rtwdev)) return 0; return preload_init_set(rtwdev, mac_idx, mode); @@ -2183,8 +2185,7 @@ static void _patch_ss2f_path(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; - if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B || - chip->chip_id == RTL8851B) + if (chip->chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) return; rtw89_write32_mask(rtwdev, R_AX_SS2FINFO_PATH, B_AX_SS_DEST_QUEUE_MASK, @@ -2360,7 +2361,7 @@ static int scheduler_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) rtw89_write32_mask(rtwdev, reg, B_AX_SIFS_MACTXEN_T1_MASK, SIFS_MACTXEN_T1); - if (rtwdev->chip->chip_id == RTL8852B || rtwdev->chip->chip_id == RTL8851B) { + if (rtw89_is_rtl885xb(rtwdev)) { reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_SCH_EXT_CTRL, mac_idx); rtw89_write32_set(rtwdev, reg, B_AX_PORT_RST_TSF_ADV); } @@ -2588,7 +2589,9 @@ static int trxptcl_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) case RTL8852A: sifs = WMAC_SPEC_SIFS_OFDM_52A; break; + case RTL8851B: case RTL8852B: + case RTL8852BT: sifs = WMAC_SPEC_SIFS_OFDM_52B; break; default: @@ -2632,6 +2635,7 @@ static int rmac_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) #define RX_MAX_LEN_UNIT 512 #define PLD_RLS_MAX_PG 127 #define RX_SPEC_MAX_LEN (11454 + RX_MAX_LEN_UNIT) + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; int ret; u32 reg, rx_max_len, rx_qta; u16 val; @@ -2652,6 +2656,8 @@ static int rmac_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) B_AX_RX_DLK_DATA_TIME_MASK); val = u16_replace_bits(val, TRXCFG_RMAC_CCA_TO, B_AX_RX_DLK_CCA_TIME_MASK); + if (chip_id == RTL8852BT) + val |= B_AX_RX_DLK_RST_EN; rtw89_write16(rtwdev, reg, val); reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_RCR, mac_idx); @@ -2668,8 +2674,7 @@ static int rmac_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) rx_max_len /= RX_MAX_LEN_UNIT; rtw89_write32_mask(rtwdev, reg, B_AX_RX_MPDU_MAX_LEN_MASK, rx_max_len); - if (rtwdev->chip->chip_id == RTL8852A && - rtwdev->hal.cv == CHIP_CBV) { + if (chip_id == RTL8852A && rtwdev->hal.cv == CHIP_CBV) { rtw89_write16_mask(rtwdev, rtw89_mac_reg_by_idx(rtwdev, R_AX_DLK_PROTECT_CTL, mac_idx), B_AX_RX_DLK_CCA_TIME_MASK, 0); @@ -2700,7 +2705,7 @@ static int cmac_com_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) val = u32_replace_bits(val, 0, B_AX_TXSC_80M_MASK); rtw89_write32(rtwdev, reg, val); - if (chip_id == RTL8852A || chip_id == RTL8852B) { + if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) { reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PTCL_RRSR1, mac_idx); rtw89_write32_mask(rtwdev, reg, B_AX_RRSR_RATE_EN_MASK, RRSR_OFDM_CCK_EN); } @@ -2766,11 +2771,10 @@ static int ptcl_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) static int cmac_dma_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) { - enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; u32 reg; int ret; - if (chip_id != RTL8852B) + if (!rtw89_is_rtl885xb(rtwdev)) return 0; ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); @@ -3587,13 +3591,11 @@ static int enable_imr_ax(struct rtw89_dev *rtwdev, u8 mac_idx, static void err_imr_ctrl_ax(struct rtw89_dev *rtwdev, bool en) { - enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; - rtw89_write32(rtwdev, R_AX_DMAC_ERR_IMR, en ? DMAC_ERR_IMR_EN : DMAC_ERR_IMR_DIS); rtw89_write32(rtwdev, R_AX_CMAC_ERR_IMR, en ? CMAC0_ERR_IMR_EN : CMAC0_ERR_IMR_DIS); - if (chip_id != RTL8852B && rtwdev->mac.dle_info.c1_rx_qta) + if (!rtw89_is_rtl885xb(rtwdev) && rtwdev->mac.dle_info.c1_rx_qta) rtw89_write32(rtwdev, R_AX_CMAC_ERR_IMR_C1, en ? CMAC1_ERR_IMR_EN : CMAC1_ERR_IMR_DIS); } @@ -3719,10 +3721,9 @@ static int rtw89_mac_feat_init(struct rtw89_dev *rtwdev) static void rtw89_disable_fw_watchdog(struct rtw89_dev *rtwdev) { - enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; u32 val32; - if (chip_id == RTL8852B || chip_id == RTL8851B) { + if (rtw89_is_rtl885xb(rtwdev)) { rtw89_write32_clr(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_APB_WRAP_EN); rtw89_write32_set(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_APB_WRAP_EN); return; @@ -3818,7 +3819,7 @@ static void rtw89_mac_dmac_func_pre_en_ax(struct rtw89_dev *rtwdev) enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; u32 val; - if (chip_id == RTL8851B) + if (chip_id == RTL8851B || chip_id == RTL8852BT) val = B_AX_DISPATCHER_CLK_EN | B_AX_AXIDMA_CLK_EN; else val = B_AX_DISPATCHER_CLK_EN; @@ -5463,18 +5464,19 @@ void rtw89_mac_flush_txq(struct rtw89_dev *rtwdev, u32 queues, bool drop) int rtw89_mac_coex_init(struct rtw89_dev *rtwdev, const struct rtw89_mac_ax_coex *coex) { + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; u8 val; u16 val16; u32 val32; int ret; rtw89_write8_set(rtwdev, R_AX_GPIO_MUXCFG, B_AX_ENBT); - if (rtwdev->chip->chip_id != RTL8851B) + if (chip_id != RTL8851B && chip_id != RTL8852BT) rtw89_write8_set(rtwdev, R_AX_BTC_FUNC_EN, B_AX_PTA_WL_TX_EN); rtw89_write8_set(rtwdev, R_AX_BT_COEX_CFG_2 + 1, B_AX_GNT_BT_POLARITY >> 8); rtw89_write8_set(rtwdev, R_AX_CSR_MODE, B_AX_STATIS_BT_EN | B_AX_WL_ACT_MSK); rtw89_write8_set(rtwdev, R_AX_CSR_MODE + 2, B_AX_BT_CNT_RST >> 16); - if (rtwdev->chip->chip_id != RTL8851B) + if (chip_id != RTL8851B && chip_id != RTL8852BT) rtw89_write8_clr(rtwdev, R_AX_TRXPTCL_RESP_0 + 3, B_AX_RSP_CHK_BTCCA >> 24); val16 = rtw89_read16(rtwdev, R_AX_CCA_CFG_0); @@ -5757,8 +5759,7 @@ bool rtw89_mac_get_ctrl_path(struct rtw89_dev *rtwdev) if (chip->chip_id == RTL8852C || chip->chip_id == RTL8922A) return false; - else if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B || - chip->chip_id == RTL8851B) + else if (chip->chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) val = rtw89_read8_mask(rtwdev, R_AX_SYS_SDIO_CTRL + 3, B_AX_LTE_MUX_CTRL_PATH >> 24); diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 36cb0e351eea..b189e1ed98a8 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -2039,7 +2039,7 @@ static int rtw89_pci_write_config_byte(struct rtw89_dev *rtwdev, u16 addr, if (!ret) return 0; - if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B) + if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) ret = rtw89_dbi_write8(rtwdev, addr, data); return ret; @@ -2057,7 +2057,7 @@ static int rtw89_pci_read_config_byte(struct rtw89_dev *rtwdev, u16 addr, if (!ret) return 0; - if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B) + if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) ret = rtw89_dbi_read8(rtwdev, addr, value); return ret; @@ -2137,10 +2137,9 @@ __get_target(struct rtw89_dev *rtwdev, u16 *target, enum rtw89_pcie_phy phy_rate static int rtw89_pci_autok_x(struct rtw89_dev *rtwdev) { - enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; int ret; - if (chip_id != RTL8852B && chip_id != RTL8851B) + if (!rtw89_is_rtl885xb(rtwdev)) return 0; ret = rtw89_write16_mdio_mask(rtwdev, RAC_REG_FLD_0, BAC_AUTOK_N_MASK, @@ -2150,14 +2149,13 @@ static int rtw89_pci_autok_x(struct rtw89_dev *rtwdev) static int rtw89_pci_auto_refclk_cal(struct rtw89_dev *rtwdev, bool autook_en) { - enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; enum rtw89_pcie_phy phy_rate; u16 val16, mgn_set, div_set, tar; u8 val8, bdr_ori; bool l1_flag = false; int ret = 0; - if (chip_id != RTL8852B && chip_id != RTL8851B) + if (!rtw89_is_rtl885xb(rtwdev)) return 0; ret = rtw89_pci_read_config_byte(rtwdev, RTW89_PCIE_PHY_RATE, &val8); @@ -2398,7 +2396,7 @@ static void rtw89_pci_l1off_pwroff(struct rtw89_dev *rtwdev) { enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; - if (chip_id != RTL8852A && chip_id != RTL8852B && chip_id != RTL8851B) + if (chip_id != RTL8852A && !rtw89_is_rtl885xb(rtwdev)) return; rtw89_write32_clr(rtwdev, R_AX_PCIE_PS_CTRL, B_AX_L1OFF_PWR_OFF_EN); @@ -2428,7 +2426,7 @@ static void rtw89_pci_aphy_pwrcut(struct rtw89_dev *rtwdev) { enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; - if (chip_id != RTL8852A && chip_id != RTL8852B && chip_id != RTL8851B) + if (chip_id != RTL8852A && !rtw89_is_rtl885xb(rtwdev)) return; rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_PSUS_OFF_CAPC_EN); @@ -2438,7 +2436,7 @@ static void rtw89_pci_hci_ldo(struct rtw89_dev *rtwdev) { enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; - if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B) { + if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) { rtw89_write32_set(rtwdev, R_AX_SYS_SDIO_CTRL, B_AX_PCIE_DIS_L2_CTRL_LDO_HCI); rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL, @@ -2451,9 +2449,7 @@ static void rtw89_pci_hci_ldo(struct rtw89_dev *rtwdev) static int rtw89_pci_dphy_delay(struct rtw89_dev *rtwdev) { - enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; - - if (chip_id != RTL8852B && chip_id != RTL8851B) + if (!rtw89_is_rtl885xb(rtwdev)) return 0; return rtw89_write16_mdio_mask(rtwdev, RAC_REG_REV2, BAC_CMU_EN_DLY_MASK, @@ -2715,7 +2711,7 @@ static int rtw89_pci_mode_op(struct rtw89_dev *rtwdev) B_AX_PCIE_RX_APPLEN_MASK, 0); } - if (chip_id == RTL8852A || chip_id == RTL8852B) { + if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) { rtw89_write32_mask(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_PCIE_MAX_TXDMA_MASK, tx_burst); rtw89_write32_mask(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_PCIE_MAX_RXDMA_MASK, rx_burst); } else if (chip_id == RTL8852C) { @@ -2723,7 +2719,7 @@ static int rtw89_pci_mode_op(struct rtw89_dev *rtwdev) rtw89_write32_mask(rtwdev, R_AX_HAXI_INIT_CFG1, B_AX_HAXI_MAX_RXDMA_MASK, rx_burst); } - if (chip_id == RTL8852A || chip_id == RTL8852B) { + if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) { if (tag_mode == MAC_AX_TAG_SGL) { val32 = rtw89_read32(rtwdev, R_AX_PCIE_INIT_CFG1) & ~B_AX_LATENCY_CONTROL; @@ -2738,7 +2734,7 @@ static int rtw89_pci_mode_op(struct rtw89_dev *rtwdev) rtw89_write32_mask(rtwdev, info->exp_ctrl_reg, info->max_tag_num_mask, info->multi_tag_num); - if (chip_id == RTL8852A || chip_id == RTL8852B) { + if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) { rtw89_write32_mask(rtwdev, R_AX_PCIE_INIT_CFG2, B_AX_WD_ITVL_IDLE, wd_dma_idle_intvl); rtw89_write32_mask(rtwdev, R_AX_PCIE_INIT_CFG2, B_AX_WD_ITVL_ACT, @@ -2951,7 +2947,7 @@ static int rtw89_pci_ops_mac_post_init_ax(struct rtw89_dev *rtwdev) /* ltr sw trigger */ rtw89_write32_set(rtwdev, R_AX_LTR_CTRL_0, B_AX_APP_LTR_ACT); } - if (chip_id == RTL8852A || chip_id == RTL8852B) { + if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) { /* ADDR info 8-byte mode */ rtw89_write32_set(rtwdev, R_AX_TX_ADDRESS_INFO_MODE_SETTING, B_AX_HOST_ADDR_INFO_8B_SEL); @@ -3760,7 +3756,7 @@ static void rtw89_pci_clkreq_set_ax(struct rtw89_dev *rtwdev, bool enable) if (ret) rtw89_err(rtwdev, "failed to set CLKREQ Delay\n"); - if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B) { + if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) { if (enable) ret = rtw89_pci_config_byte_set(rtwdev, RTW89_PCIE_L1_CTRL, @@ -3812,7 +3808,7 @@ static void rtw89_pci_aspm_set_ax(struct rtw89_dev *rtwdev, bool enable) if (ret) rtw89_warn(rtwdev, "failed to read ASPM Delay\n"); - if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B) { + if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) { if (enable) ret = rtw89_pci_config_byte_set(rtwdev, RTW89_PCIE_L1_CTRL, @@ -3911,7 +3907,7 @@ static void rtw89_pci_l1ss_set_ax(struct rtw89_dev *rtwdev, bool enable) enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; int ret; - if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B) { + if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) { if (enable) ret = rtw89_pci_config_byte_set(rtwdev, RTW89_PCIE_TIMER_CTRL, @@ -4108,7 +4104,7 @@ static int __maybe_unused rtw89_pci_suspend(struct device *dev) rtw89_write32_set(rtwdev, R_AX_RSV_CTRL, B_AX_WLOCK_1C_BIT6); rtw89_write32_set(rtwdev, R_AX_RSV_CTRL, B_AX_R_DIS_PRST); rtw89_write32_clr(rtwdev, R_AX_RSV_CTRL, B_AX_WLOCK_1C_BIT6); - if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B) { + if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) { rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL, B_AX_PCIE_DIS_L2_CTRL_LDO_HCI); rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, @@ -4142,7 +4138,7 @@ static int __maybe_unused rtw89_pci_resume(struct device *dev) rtw89_write32_set(rtwdev, R_AX_RSV_CTRL, B_AX_WLOCK_1C_BIT6); rtw89_write32_clr(rtwdev, R_AX_RSV_CTRL, B_AX_R_DIS_PRST); rtw89_write32_clr(rtwdev, R_AX_RSV_CTRL, B_AX_WLOCK_1C_BIT6); - if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B) { + if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) { rtw89_write32_set(rtwdev, R_AX_SYS_SDIO_CTRL, B_AX_PCIE_DIS_L2_CTRL_LDO_HCI); rtw89_write32_clr(rtwdev, R_AX_PCIE_INIT_CFG1, diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index a82b4c56a6f4..60f20e596321 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -1676,7 +1676,7 @@ static void rtw89_phy_preinit_rf_nctl_ax(struct rtw89_dev *rtwdev) rtw89_phy_write32_set(rtwdev, R_P0_PATH_RST, 0x8000000); if (chip->chip_id != RTL8851B) rtw89_phy_write32_set(rtwdev, R_P1_PATH_RST, 0x8000000); - if (chip->chip_id == RTL8852B) + if (chip->chip_id == RTL8852B || chip->chip_id == RTL8852BT) rtw89_phy_write32_set(rtwdev, R_IOQ_IQK_DPK, 0x2); /* check 0x8080 */ diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index dc78ffc39ae7..5a59234301ca 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3169,6 +3169,8 @@ #define R_AX_DLK_PROTECT_CTL_C1 0xEE02 #define B_AX_RX_DLK_CCA_TIME_MASK GENMASK(15, 8) #define B_AX_RX_DLK_DATA_TIME_MASK GENMASK(7, 4) +#define B_AX_RX_DLK_RST_EN BIT(1) +#define B_AX_RX_DLK_INT_EN BIT(0) #define R_AX_PLCP_HDR_FLTR 0xCE04 #define R_AX_PLCP_HDR_FLTR_C1 0xEE04 From 8a00f7dfed62f1f74388bbd659e8d69d66886786 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 7 Jun 2024 22:02:51 +0800 Subject: [PATCH 014/204] wifi: rtw89: adopt firmware whose version is equal or less but closest Version C of 8922AE hardware will use the same firmware of version B, so extend rule of firmware recognition to allow less but closest firmware version. Originally only accept firmware with matched version. Tested on version A/B/C of 8922AE. Signed-off-by: Ping-Ke Shih Link: https://msgid.link/20240607140251.8295-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 34 +++++++++++++++++++------ 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index be39a8468d32..23204b2706c9 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -462,7 +462,7 @@ int rtw89_mfw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type, const u8 *mfw = firmware->data; u32 mfw_len = firmware->size; const struct rtw89_mfw_hdr *mfw_hdr = (const struct rtw89_mfw_hdr *)mfw; - const struct rtw89_mfw_info *mfw_info; + const struct rtw89_mfw_info *mfw_info = NULL, *tmp; int i; if (mfw_hdr->sig != RTW89_MFW_SIG) { @@ -476,15 +476,27 @@ int rtw89_mfw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type, } for (i = 0; i < mfw_hdr->fw_nr; i++) { - mfw_info = &mfw_hdr->info[i]; - if (mfw_info->type == type) { - if (mfw_info->cv == rtwdev->hal.cv && !mfw_info->mp) - goto found; - if (type == RTW89_FW_LOGFMT) - goto found; + tmp = &mfw_hdr->info[i]; + if (tmp->type != type) + continue; + + if (type == RTW89_FW_LOGFMT) { + mfw_info = tmp; + goto found; + } + + /* Version order of WiFi firmware in firmware file are not in order, + * pass all firmware to find the equal or less but closest version. + */ + if (tmp->cv <= rtwdev->hal.cv && !tmp->mp) { + if (!mfw_info || mfw_info->cv < tmp->cv) + mfw_info = tmp; } } + if (mfw_info) + goto found; + if (!nowarn) rtw89_err(rtwdev, "no suitable firmware found\n"); return -ENOENT; @@ -606,10 +618,16 @@ int __rtw89_fw_recognize_from_elm(struct rtw89_dev *rtwdev, struct rtw89_hal *hal = &rtwdev->hal; struct rtw89_fw_suit *fw_suit; - if (hal->cv != elm->u.bbmcu.cv) + /* Version of BB MCU is in decreasing order in firmware file, so take + * first equal or less version, which is equal or less but closest version. + */ + if (hal->cv < elm->u.bbmcu.cv) return 1; /* ignore this element */ fw_suit = rtw89_fw_suit_get(rtwdev, type); + if (fw_suit->data) + return 1; /* ignore this element (a firmware is taken already) */ + fw_suit->data = elm->u.bbmcu.contents; fw_suit->size = le32_to_cpu(elm->size); From 1fd4b3fe52efd5ad1647966f619c10988e7a4457 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 11 Jun 2024 10:19:00 +0800 Subject: [PATCH 015/204] wifi: rtw89: pci: support 36-bit PCI DMA address Modern platforms can install more than 4GB memory, so DMA address can larger than 32 bits. If a platform doesn't enable IOMMU, kernel needs extra works of swiotlb to help DMA that packets reside on memory over 4GB. The DMA addressing capability of Realtek WiFi chips is 36 bits, so set LSB 4 bits of high 32-bit address to register and TX/RX descriptor, which below figure shows 3-level pointers in TX direction, and RX direction is similar but 2-level pointers only. +--------+ | | register to head of TX BD +---|----+ | +---------+ +-----> | TX BD | (in memory) +----|----+ | +---------+ +------> | TX WD | (in memory) +----|----+ | +--------+ +------> | skb | +--------+ Signed-off-by: Ping-Ke Shih Link: https://msgid.link/20240611021901.26394-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 85 ++++++++++++++++--- drivers/net/wireless/realtek/rtw89/pci.h | 24 ++++-- .../net/wireless/realtek/rtw89/rtw8851be.c | 1 + .../net/wireless/realtek/rtw89/rtw8852ae.c | 1 + .../net/wireless/realtek/rtw89/rtw8852be.c | 1 + .../net/wireless/realtek/rtw89/rtw8852ce.c | 1 + .../net/wireless/realtek/rtw89/rtw8922ae.c | 1 + 7 files changed, 95 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index b189e1ed98a8..ccb4bfe1a909 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -1298,10 +1298,12 @@ u32 rtw89_pci_fill_txaddr_info(struct rtw89_dev *rtwdev, dma_addr_t dma, u8 *add_info_nr) { struct rtw89_pci_tx_addr_info_32 *txaddr_info = txaddr_info_addr; + __le16 option; txaddr_info->length = cpu_to_le16(total_len); - txaddr_info->option = cpu_to_le16(RTW89_PCI_ADDR_MSDU_LS | - RTW89_PCI_ADDR_NUM(1)); + option = cpu_to_le16(RTW89_PCI_ADDR_MSDU_LS | RTW89_PCI_ADDR_NUM(1)); + option |= le16_encode_bits(upper_32_bits(dma), RTW89_PCI_ADDR_HIGH_MASK); + txaddr_info->option = option; txaddr_info->dma = cpu_to_le32(dma); *add_info_nr = 1; @@ -1328,6 +1330,8 @@ u32 rtw89_pci_fill_txaddr_info_v1(struct rtw89_dev *rtwdev, length_option = FIELD_PREP(B_PCIADDR_LEN_V1_MASK, len) | FIELD_PREP(B_PCIADDR_HIGH_SEL_V1_MASK, 0) | FIELD_PREP(B_PCIADDR_LS_V1_MASK, remain == 0); + length_option |= u16_encode_bits(upper_32_bits(dma), + B_PCIADDR_HIGH_SEL_V1_MASK); txaddr_info->length_opt = cpu_to_le16(length_option); txaddr_info->dma_low_lsb = cpu_to_le16(FIELD_GET(GENMASK(15, 0), dma)); txaddr_info->dma_low_msb = cpu_to_le16(FIELD_GET(GENMASK(31, 16), dma)); @@ -1418,6 +1422,7 @@ static int rtw89_pci_fwcmd_submit(struct rtw89_dev *rtwdev, struct sk_buff *skb = tx_req->skb; struct rtw89_pci_tx_data *tx_data = RTW89_PCI_TX_SKB_CB(skb); dma_addr_t dma; + __le16 opt; txdesc = skb_push(skb, txdesc_size); memset(txdesc, 0, txdesc_size); @@ -1430,7 +1435,9 @@ static int rtw89_pci_fwcmd_submit(struct rtw89_dev *rtwdev, } tx_data->dma = dma; - txbd->option = cpu_to_le16(RTW89_PCI_TXBD_OPTION_LS); + opt = cpu_to_le16(RTW89_PCI_TXBD_OPT_LS); + opt |= le16_encode_bits(upper_32_bits(dma), RTW89_PCI_TXBD_OPT_DMA_HI); + txbd->opt = opt; txbd->length = cpu_to_le16(skb->len); txbd->dma = cpu_to_le32(tx_data->dma); skb_queue_tail(&rtwpci->h2c_queue, skb); @@ -1446,6 +1453,7 @@ static int rtw89_pci_txbd_submit(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) { struct rtw89_pci_tx_wd *txwd; + __le16 opt; int ret; /* FWCMD queue doesn't have wd pages. Instead, it submits the CMD @@ -1470,7 +1478,9 @@ static int rtw89_pci_txbd_submit(struct rtw89_dev *rtwdev, list_add_tail(&txwd->list, &tx_ring->busy_pages); - txbd->option = cpu_to_le16(RTW89_PCI_TXBD_OPTION_LS); + opt = cpu_to_le16(RTW89_PCI_TXBD_OPT_LS); + opt |= le16_encode_bits(upper_32_bits(txwd->paddr), RTW89_PCI_TXBD_OPT_DMA_HI); + txbd->opt = opt; txbd->length = cpu_to_le16(txwd->len); txbd->dma = cpu_to_le32(txwd->paddr); @@ -1569,6 +1579,25 @@ const struct rtw89_pci_bd_ram rtw89_bd_ram_table_single[RTW89_TXCH_NUM] = { }; EXPORT_SYMBOL(rtw89_bd_ram_table_single); +static void rtw89_pci_init_wp_16sel(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + u32 addr = info->wp_sel_addr; + u32 val; + int i; + + if (!info->wp_sel_addr) + return; + + for (i = 0; i < 16; i += 4) { + val = u32_encode_bits(i + 0, MASKBYTE0) | + u32_encode_bits(i + 1, MASKBYTE1) | + u32_encode_bits(i + 2, MASKBYTE2) | + u32_encode_bits(i + 3, MASKBYTE3); + rtw89_write32(rtwdev, addr + i, val); + } +} + static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; @@ -1607,6 +1636,7 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) rtw89_write32(rtwdev, addr_bdram, val32); } rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma); + rtw89_write32(rtwdev, addr_desa_l + 4, upper_32_bits(bd_ring->dma)); } for (i = 0; i < RTW89_RXCH_NUM; i++) { @@ -1626,10 +1656,13 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) rtw89_write16(rtwdev, addr_num, bd_ring->len); rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma); + rtw89_write32(rtwdev, addr_desa_l + 4, upper_32_bits(bd_ring->dma)); if (info->rx_ring_eq_is_full) rtw89_write16(rtwdev, addr_idx, bd_ring->wp); } + + rtw89_pci_init_wp_16sel(rtwdev); } static void rtw89_pci_release_tx_ring(struct rtw89_dev *rtwdev, @@ -2990,6 +3023,27 @@ static void rtw89_pci_declaim_device(struct rtw89_dev *rtwdev, pci_disable_device(pdev); } +static void rtw89_pci_cfg_dac(struct rtw89_dev *rtwdev) +{ + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + const struct rtw89_chip_info *chip = rtwdev->chip; + + if (!rtwpci->enable_dac) + return; + + switch (chip->chip_id) { + case RTL8852A: + case RTL8852B: + case RTL8851B: + case RTL8852BT: + break; + default: + return; + } + + rtw89_pci_config_byte_set(rtwdev, RTW89_PCIE_L1_CTRL, RTW89_PCIE_BIT_EN_64BITS); +} + static int rtw89_pci_setup_mapping(struct rtw89_dev *rtwdev, struct pci_dev *pdev) { @@ -3004,16 +3058,17 @@ static int rtw89_pci_setup_mapping(struct rtw89_dev *rtwdev, goto err; } - ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) { - rtw89_err(rtwdev, "failed to set dma mask to 32-bit\n"); - goto err_release_regions; - } - - ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) { - rtw89_err(rtwdev, "failed to set consistent dma mask to 32-bit\n"); - goto err_release_regions; + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(36)); + if (!ret) { + rtwpci->enable_dac = true; + rtw89_pci_cfg_dac(rtwdev); + } else { + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + rtw89_err(rtwdev, + "failed to set dma and consistent mask to 32/36-bit\n"); + goto err_release_regions; + } } resource_len = pci_resource_len(pdev, bar_id); @@ -3164,6 +3219,7 @@ static int rtw89_pci_init_rx_bd(struct rtw89_dev *rtwdev, struct pci_dev *pdev, memset(rx_bd, 0, sizeof(*rx_bd)); rx_bd->buf_size = cpu_to_le16(buf_sz); rx_bd->dma = cpu_to_le32(dma); + rx_bd->opt = le16_encode_bits(upper_32_bits(dma), RTW89_PCI_RXBD_OPT_DMA_HI); rx_info->dma = dma; return 0; @@ -4151,6 +4207,7 @@ static int __maybe_unused rtw89_pci_resume(struct device *dev) } rtw89_pci_l2_hci_ldo(rtwdev); rtw89_pci_disable_eq(rtwdev); + rtw89_pci_cfg_dac(rtwdev); rtw89_pci_filter_out(rtwdev); rtw89_pci_link_cfg(rtwdev); rtw89_pci_l1ss_cfg(rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 7666753ae983..48c3ab735db2 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -724,6 +724,11 @@ #define B_AX_CH11_BUSY BIT(1) #define B_AX_CH10_BUSY BIT(0) +#define R_AX_WP_ADDR_H_SEL0_3 0x1334 +#define R_AX_WP_ADDR_H_SEL4_7 0x1338 +#define R_AX_WP_ADDR_H_SEL8_11 0x133C +#define R_AX_WP_ADDR_H_SEL12_15 0x1340 + #define R_BE_HAXI_DMA_STOP1 0xB010 #define B_BE_STOP_WPDMA BIT(31) #define B_BE_STOP_CH14 BIT(14) @@ -823,6 +828,11 @@ #define R_BE_RPQ0_RXBD_DESA_L_V1 0xB308 #define R_BE_RPQ0_RXBD_DESA_H_V1 0xB30C +#define R_BE_WP_ADDR_H_SEL0_3_V1 0xB420 +#define R_BE_WP_ADDR_H_SEL4_7_V1 0xB424 +#define R_BE_WP_ADDR_H_SEL8_11_V1 0xB428 +#define R_BE_WP_ADDR_H_SEL12_15_V1 0xB42C + /* Configure */ #define R_AX_PCIE_INIT_CFG2 0x1004 #define B_AX_WD_ITVL_IDLE GENMASK(27, 24) @@ -1055,6 +1065,7 @@ #define RTW89_PCIE_TIMER_CTRL 0x0718 #define RTW89_PCIE_BIT_L1SUB BIT(5) #define RTW89_PCIE_L1_CTRL 0x0719 +#define RTW89_PCIE_BIT_EN_64BITS BIT(5) #define RTW89_PCIE_BIT_CLK BIT(4) #define RTW89_PCIE_BIT_L1 BIT(3) #define RTW89_PCIE_CLK_CTRL 0x0725 @@ -1304,6 +1315,7 @@ struct rtw89_pci_info { u32 rpwm_addr; u32 cpwm_addr; u32 mit_addr; + u32 wp_sel_addr; u32 tx_dma_ch_mask; const struct rtw89_pci_bd_idx_addr *bd_idx_addr_low_power; const struct rtw89_pci_ch_dma_addr_set *dma_addr_set; @@ -1330,11 +1342,11 @@ struct rtw89_pci_rx_info { u32 fs:1, ls:1, tag:13, len:14; }; -#define RTW89_PCI_TXBD_OPTION_LS BIT(14) - struct rtw89_pci_tx_bd_32 { __le16 length; - __le16 option; + __le16 opt; +#define RTW89_PCI_TXBD_OPT_LS BIT(14) +#define RTW89_PCI_TXBD_OPT_DMA_HI GENMASK(13, 6) __le32 dma; } __packed; @@ -1349,7 +1361,7 @@ struct rtw89_pci_tx_wp_info { #define RTW89_PCI_ADDR_MSDU_LS BIT(15) #define RTW89_PCI_ADDR_LS BIT(14) -#define RTW89_PCI_ADDR_HIGH(a) (((a) << 6) & GENMASK(13, 6)) +#define RTW89_PCI_ADDR_HIGH_MASK GENMASK(13, 6) #define RTW89_PCI_ADDR_NUM(x) ((x) & GENMASK(5, 0)) struct rtw89_pci_tx_addr_info_32 { @@ -1386,7 +1398,8 @@ struct rtw89_pci_rpp_fmt { struct rtw89_pci_rx_bd_32 { __le16 buf_size; - __le16 rsvd; + __le16 opt; +#define RTW89_PCI_RXBD_OPT_DMA_HI GENMASK(13, 6) __le32 dma; } __packed; @@ -1475,6 +1488,7 @@ struct rtw89_pci { bool running; bool low_power; bool under_recovery; + bool enable_dac; struct rtw89_pci_tx_ring tx_rings[RTW89_TXCH_NUM]; struct rtw89_pci_rx_ring rx_rings[RTW89_RXCH_NUM]; struct sk_buff_head h2c_queue; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851be.c b/drivers/net/wireless/realtek/rtw89/rtw8851be.c index ec3629d95fda..d334924faec8 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851be.c @@ -46,6 +46,7 @@ static const struct rtw89_pci_info rtw8851b_pci_info = { .rpwm_addr = R_AX_PCIE_HRPWM, .cpwm_addr = R_AX_CPWM, .mit_addr = R_AX_INT_MIT_RX, + .wp_sel_addr = 0, .tx_dma_ch_mask = BIT(RTW89_TXCH_ACH4) | BIT(RTW89_TXCH_ACH5) | BIT(RTW89_TXCH_ACH6) | BIT(RTW89_TXCH_ACH7) | BIT(RTW89_TXCH_CH10) | BIT(RTW89_TXCH_CH11), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c index fdee5dd4ba14..9a675e2193bc 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c @@ -46,6 +46,7 @@ static const struct rtw89_pci_info rtw8852a_pci_info = { .rpwm_addr = R_AX_PCIE_HRPWM, .cpwm_addr = R_AX_CPWM, .mit_addr = R_AX_INT_MIT_RX, + .wp_sel_addr = 0, .tx_dma_ch_mask = 0, .bd_idx_addr_low_power = NULL, .dma_addr_set = &rtw89_pci_ch_dma_addr_set, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852be.c b/drivers/net/wireless/realtek/rtw89/rtw8852be.c index 5f941122655c..d8f9d92ca0fb 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852be.c @@ -46,6 +46,7 @@ static const struct rtw89_pci_info rtw8852b_pci_info = { .rpwm_addr = R_AX_PCIE_HRPWM, .cpwm_addr = R_AX_CPWM, .mit_addr = R_AX_INT_MIT_RX, + .wp_sel_addr = 0, .tx_dma_ch_mask = BIT(RTW89_TXCH_ACH4) | BIT(RTW89_TXCH_ACH5) | BIT(RTW89_TXCH_ACH6) | BIT(RTW89_TXCH_ACH7) | BIT(RTW89_TXCH_CH10) | BIT(RTW89_TXCH_CH11), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c index e07c7f3ade41..8aaad7d58c0d 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c @@ -55,6 +55,7 @@ static const struct rtw89_pci_info rtw8852c_pci_info = { .rpwm_addr = R_AX_PCIE_HRPWM_V1, .cpwm_addr = R_AX_PCIE_CRPWM, .mit_addr = R_AX_INT_MIT_RX_V1, + .wp_sel_addr = R_AX_WP_ADDR_H_SEL0_3, .tx_dma_ch_mask = 0, .bd_idx_addr_low_power = &rtw8852c_bd_idx_addr_low_power, .dma_addr_set = &rtw89_pci_ch_dma_addr_set_v1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c index ce8aaa9501e1..47f855a7a268 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c @@ -46,6 +46,7 @@ static const struct rtw89_pci_info rtw8922a_pci_info = { .rpwm_addr = R_BE_PCIE_HRPWM, .cpwm_addr = R_BE_PCIE_CRPWM, .mit_addr = R_BE_PCIE_MIT_CH_EN, + .wp_sel_addr = R_BE_WP_ADDR_H_SEL0_3_V1, .tx_dma_ch_mask = 0, .bd_idx_addr_low_power = NULL, .dma_addr_set = &rtw89_pci_ch_dma_addr_set_be, From 94298477f81a1701fc4e1b5a0ce9672acab5dcb2 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 11 Jun 2024 10:19:01 +0800 Subject: [PATCH 016/204] wifi: rtw89: pci: fix RX tag race condition resulting in wrong RX length Read 32 bits RX info to a local variable to fix race condition between reading RX length and RX tag. Another solution is to get RX tag at first statement, but adopted solution can save some memory read, and also save 15 bytes binary code. RX tag, a sequence number, is used to ensure that RX data has been DMA to memory completely, so driver must check sequence number is expected before reading other data. This potential problem happens only after enabling 36-bit DMA. Signed-off-by: Ping-Ke Shih Link: https://msgid.link/20240611021901.26394-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index ccb4bfe1a909..02afeb3acce4 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -183,14 +183,17 @@ static void rtw89_pci_sync_skb_for_device(struct rtw89_dev *rtwdev, static void rtw89_pci_rxbd_info_update(struct rtw89_dev *rtwdev, struct sk_buff *skb) { - struct rtw89_pci_rxbd_info *rxbd_info; struct rtw89_pci_rx_info *rx_info = RTW89_PCI_RX_SKB_CB(skb); + struct rtw89_pci_rxbd_info *rxbd_info; + __le32 info; rxbd_info = (struct rtw89_pci_rxbd_info *)skb->data; - rx_info->fs = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_FS); - rx_info->ls = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_LS); - rx_info->len = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_WRITE_SIZE); - rx_info->tag = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_TAG); + info = rxbd_info->dword; + + rx_info->fs = le32_get_bits(info, RTW89_PCI_RXBD_FS); + rx_info->ls = le32_get_bits(info, RTW89_PCI_RXBD_LS); + rx_info->len = le32_get_bits(info, RTW89_PCI_RXBD_WRITE_SIZE); + rx_info->tag = le32_get_bits(info, RTW89_PCI_RXBD_TAG); } static int rtw89_pci_validate_rx_tag(struct rtw89_dev *rtwdev, From 71839a929d9ee97daab319d370fc0f6720daef43 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 5 Jun 2024 14:21:04 +0200 Subject: [PATCH 017/204] dt-bindings: net: wireless: qcom,ath11k: describe the ath11k on QCA6390 Add a PCI compatible for the ATH11K module on QCA6390 and describe the power inputs from the PMU that it consumes. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Bartosz Golaszewski Signed-off-by: Kalle Valo Link: https://msgid.link/20240605122106.23818-2-brgl@bgdev.pl --- .../net/wireless/qcom,ath11k-pci.yaml | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml index 41d023797d7d..8675d7d0215c 100644 --- a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml @@ -17,6 +17,7 @@ description: | properties: compatible: enum: + - pci17cb,1101 # QCA6390 - pci17cb,1103 # WCN6855 reg: @@ -28,10 +29,55 @@ properties: string to uniquely identify variant of the calibration data for designs with colliding bus and device ids + vddrfacmn-supply: + description: VDD_RFA_CMN supply regulator handle + + vddaon-supply: + description: VDD_AON supply regulator handle + + vddwlcx-supply: + description: VDD_WL_CX supply regulator handle + + vddwlmx-supply: + description: VDD_WL_MX supply regulator handle + + vddrfa0p8-supply: + description: VDD_RFA_0P8 supply regulator handle + + vddrfa1p2-supply: + description: VDD_RFA_1P2 supply regulator handle + + vddrfa1p7-supply: + description: VDD_RFA_1P7 supply regulator handle + + vddpcie0p9-supply: + description: VDD_PCIE_0P9 supply regulator handle + + vddpcie1p8-supply: + description: VDD_PCIE_1P8 supply regulator handle + required: - compatible - reg +allOf: + - if: + properties: + compatible: + contains: + const: pci17cb,1101 + then: + required: + - vddrfacmn-supply + - vddaon-supply + - vddwlcx-supply + - vddwlmx-supply + - vddrfa0p8-supply + - vddrfa1p2-supply + - vddrfa1p7-supply + - vddpcie0p9-supply + - vddpcie1p8-supply + additionalProperties: false examples: From aa17d384971b62a8a7dc901c96f615efc7328a62 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 5 Jun 2024 14:21:05 +0200 Subject: [PATCH 018/204] dt-bindings: net: wireless: describe the ath12k PCI module Add device-tree bindings for the ATH12K module found in the WCN7850 package. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Bartosz Golaszewski Signed-off-by: Kalle Valo Link: https://msgid.link/20240605122106.23818-3-brgl@bgdev.pl --- .../bindings/net/wireless/qcom,ath12k.yaml | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/wireless/qcom,ath12k.yaml diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath12k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath12k.yaml new file mode 100644 index 000000000000..1b5884015b15 --- /dev/null +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath12k.yaml @@ -0,0 +1,99 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2024 Linaro Limited +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/wireless/qcom,ath12k.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies ath12k wireless devices (PCIe) + +maintainers: + - Jeff Johnson + - Kalle Valo + +description: + Qualcomm Technologies IEEE 802.11be PCIe devices. + +properties: + compatible: + enum: + - pci17cb,1107 # WCN7850 + + reg: + maxItems: 1 + + vddaon-supply: + description: VDD_AON supply regulator handle + + vddwlcx-supply: + description: VDD_WLCX supply regulator handle + + vddwlmx-supply: + description: VDD_WLMX supply regulator handle + + vddrfacmn-supply: + description: VDD_RFA_CMN supply regulator handle + + vddrfa0p8-supply: + description: VDD_RFA_0P8 supply regulator handle + + vddrfa1p2-supply: + description: VDD_RFA_1P2 supply regulator handle + + vddrfa1p8-supply: + description: VDD_RFA_1P8 supply regulator handle + + vddpcie0p9-supply: + description: VDD_PCIE_0P9 supply regulator handle + + vddpcie1p8-supply: + description: VDD_PCIE_1P8 supply regulator handle + +required: + - compatible + - reg + - vddaon-supply + - vddwlcx-supply + - vddwlmx-supply + - vddrfacmn-supply + - vddrfa0p8-supply + - vddrfa1p2-supply + - vddrfa1p8-supply + - vddpcie0p9-supply + - vddpcie1p8-supply + +additionalProperties: false + +examples: + - | + #include + #include + pcie { + #address-cells = <3>; + #size-cells = <2>; + + pcie@0 { + device_type = "pci"; + reg = <0x0 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + bus-range = <0x01 0xff>; + + wifi@0 { + compatible = "pci17cb,1107"; + reg = <0x10000 0x0 0x0 0x0 0x0>; + + vddaon-supply = <&vreg_pmu_aon_0p59>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; + vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p8>; + vddpcie0p9-supply = <&vreg_pmu_pcie_0p9>; + vddpcie1p8-supply = <&vreg_pmu_pcie_1p8>; + }; + }; + }; From 670d4949bc8e7178420761130664f563453085bd Mon Sep 17 00:00:00 2001 From: Aaradhana Sahu Date: Mon, 17 Jun 2024 14:12:47 +0300 Subject: [PATCH 019/204] wifi: ath12k: Fix WARN_ON during firmware crash in split-phy Whenever firmware is crashed in split-phy below WARN_ON() triggered: WARNING: CPU: 3 PID: 82 at net/mac80211/driver-ops.c:41 drv_stop+0xac/0xbc Modules linked in: ath12k qmi_helpers CPU: 3 PID: 82 Comm: kworker/3:2 Tainted: G D W 6.9.0-next-20240520-00113-gd981a3784e15 #39 Hardware name: Qualcomm Technologies, Inc. IPQ9574/AP-AL02-C9 (DT) Workqueue: events_freezable ieee80211_restart_work pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : drv_stop+0xac/0xbc lr : ieee80211_stop_device+0x54/0x64 sp : ffff8000848dbb20 x29: ffff8000848dbb20 x28: 0000000000000790 x27: ffff000014d78900 x26: ffff000014d791f8 x25: ffff000007f0d9b0 x24: 0000000000000018 x23: 0000000000000001 x22: 0000000000000000 x21: ffff000014d78e10 x20: ffff800081dc0000 x19: ffff000014d78900 x18: ffffffffffffffff x17: ffff7fffbca84000 x16: ffff800083fe0000 x15: ffff800081dc0b48 x14: 0000000000000076 x13: 0000000000000076 x12: 0000000000000001 x11: 0000000000000000 x10: 0000000000000a60 x9 : ffff8000848db980 x8 : ffff000000dddfc0 x7 : 0000000000000400 x6 : ffff800083b012d8 x5 : ffff800083b012d8 x4 : 0000000000000000 x3 : ffff000014d78398 x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff000014d78900 Call trace: drv_stop+0xac/0xbc ieee80211_stop_device+0x54/0x64 ieee80211_do_stop+0x5a0/0x790 ieee80211_stop+0x4c/0x178 __dev_close_many+0xb0/0x150 dev_close_many+0x88/0x130 dev_close.part.171+0x44/0x74 dev_close+0x1c/0x28 cfg80211_shutdown_all_interfaces+0x44/0xfc ieee80211_restart_work+0xfc/0x14c process_scheduled_works+0x18c/0x2dc worker_thread+0x13c/0x314 kthread+0x118/0x124 ret_from_fork+0x10/0x20 ---[ end trace 0000000000000000 ]--- The warning in question is from drv_stop(): if (WARN_ON(!local->started)) return; The sequence of WARN_ON() is: Thread 1: -Firmware crash calls ath12k_core_reset(). -Call ieee80211_restart_hw() inside ath12k_core_post_reconfigure_recovery() which schedules worker for both hardware. -Wait for completion of ab->recovery_start. Thread 2 (worker thread): -One hardware acquires rtnl_lock() inside ieee80211_restart_hw() and calls ath12k_mac_wait_reconfigure() into ath12k_mac_op_start(). -Hardware is waiting for ab->reconfigure_complete but at this time recovery_start_count value is 1 because another worker thread (local->restart_work) is still waiting for rtnl_lock(). recovery_start_count is not equal to number of radios (2 in split-phy). So ab->recovery_start complete does not set due to this, thread 1 is still waiting and not able to perform hif power down up and firmware reload. -Wait timeout happens for ab->reconfigure_complete and comeback to caller (ath12k_mac_op_start()) and sends WMI command to crashed firmware and gets error. -This returns error to drv_start() and local->started is set to false. -Hardware calls cfg80211_shutdown_all_interfaces() after receiving error inside ieee80211_restart_work() and goes to drv_stop(), here we trigger WARN_ON as local->started is false. To fix this issue call ieee80211_restart_hw() after firmware has been reloaded. Now, each hardware can send WMI command to firmware successfully. With this fix we don't need to wait for ab->recovery_start completion so remove ath12k_mac_wait_reconfigure(). Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00209-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 HW2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Aaradhana Sahu Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240529034405.2863150-1-quic_aarasahu@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 21 ++++++++------------- drivers/net/wireless/ath/ath12k/core.h | 3 --- drivers/net/wireless/ath/ath12k/mac.c | 23 ----------------------- 3 files changed, 8 insertions(+), 39 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index da02d3528737..197099f15e3f 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1061,8 +1061,6 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab) mutex_unlock(&ar->conf_mutex); } - /* Restart after all the link/radio halt */ - ieee80211_restart_hw(ah->hw); break; case ATH12K_HW_STATE_OFF: ath12k_warn(ab, @@ -1089,7 +1087,8 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab) static void ath12k_core_restart(struct work_struct *work) { struct ath12k_base *ab = container_of(work, struct ath12k_base, restart_work); - int ret; + struct ath12k_hw *ah; + int ret, i; ret = ath12k_core_reconfigure_on_crash(ab); if (ret) { @@ -1097,8 +1096,12 @@ static void ath12k_core_restart(struct work_struct *work) return; } - if (ab->is_reset) - complete_all(&ab->reconfigure_complete); + if (ab->is_reset) { + for (i = 0; i < ab->num_hw; i++) { + ah = ab->ah[i]; + ieee80211_restart_hw(ah->hw); + } + } complete(&ab->restart_completed); } @@ -1152,20 +1155,14 @@ static void ath12k_core_reset(struct work_struct *work) ath12k_dbg(ab, ATH12K_DBG_BOOT, "reset starting\n"); ab->is_reset = true; - atomic_set(&ab->recovery_start_count, 0); - reinit_completion(&ab->recovery_start); atomic_set(&ab->recovery_count, 0); ath12k_core_pre_reconfigure_recovery(ab); - reinit_completion(&ab->reconfigure_complete); ath12k_core_post_reconfigure_recovery(ab); ath12k_dbg(ab, ATH12K_DBG_BOOT, "waiting recovery start...\n"); - time_left = wait_for_completion_timeout(&ab->recovery_start, - ATH12K_RECOVER_START_TIMEOUT_HZ); - ath12k_hif_irq_disable(ab); ath12k_hif_ce_irq_disable(ab); @@ -1277,8 +1274,6 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size, mutex_init(&ab->core_lock); spin_lock_init(&ab->base_lock); init_completion(&ab->reset_complete); - init_completion(&ab->reconfigure_complete); - init_completion(&ab->recovery_start); INIT_LIST_HEAD(&ab->peers); init_waitqueue_head(&ab->peer_mapping_wq); diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index b483899ca136..82ec23a7329d 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -849,11 +849,8 @@ struct ath12k_base { struct work_struct reset_work; atomic_t reset_count; atomic_t recovery_count; - atomic_t recovery_start_count; bool is_reset; struct completion reset_complete; - struct completion reconfigure_complete; - struct completion recovery_start; /* continuous recovery fail count */ atomic_t fail_cont_count; unsigned long reset_fail_timeout; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 2259ce22cc8b..1f00a2362ae6 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5834,28 +5834,6 @@ static int ath12k_mac_config_mon_status_default(struct ath12k *ar, bool enable) /* TODO: Need to support new monitor mode */ } -static void ath12k_mac_wait_reconfigure(struct ath12k_base *ab) -{ - int recovery_start_count; - - if (!ab->is_reset) - return; - - recovery_start_count = atomic_inc_return(&ab->recovery_start_count); - - ath12k_dbg(ab, ATH12K_DBG_MAC, "recovery start count %d\n", recovery_start_count); - - if (recovery_start_count == ab->num_radios) { - complete(&ab->recovery_start); - ath12k_dbg(ab, ATH12K_DBG_MAC, "recovery started success\n"); - } - - ath12k_dbg(ab, ATH12K_DBG_MAC, "waiting reconfigure...\n"); - - wait_for_completion_timeout(&ab->reconfigure_complete, - ATH12K_RECONFIGURE_TIMEOUT_HZ); -} - static int ath12k_mac_start(struct ath12k *ar) { struct ath12k_hw *ah = ar->ah; @@ -5987,7 +5965,6 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw) break; case ATH12K_HW_STATE_RESTARTING: ah->state = ATH12K_HW_STATE_RESTARTED; - ath12k_mac_wait_reconfigure(ah->ab); break; case ATH12K_HW_STATE_RESTARTED: case ATH12K_HW_STATE_WEDGED: From 4f15b06e5782e9a44acc652034090b5fc40b49e5 Mon Sep 17 00:00:00 2001 From: Harshitha Prem Date: Mon, 17 Jun 2024 14:12:47 +0300 Subject: [PATCH 020/204] wifi: ath12k: Remove unused ath12k_base from ath12k_hw Currently, device (ab) reference in hardware abstraction (ah) is not used anywhere. Also, with multiple device group abstraction, hardware abstraction would be coupled with device group abstraction rather than single device. Hence, remove the ab reference from hardware abstraction. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Harshitha Prem Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240529060939.4156281-1-quic_hprem@quicinc.com --- drivers/net/wireless/ath/ath12k/core.h | 2 -- drivers/net/wireless/ath/ath12k/mac.c | 1 - 2 files changed, 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 82ec23a7329d..d7a3e8fddb20 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -630,8 +630,6 @@ struct ath12k { struct ath12k_hw { struct ieee80211_hw *hw; - struct ath12k_base *ab; - /* Protect the write operation of the hardware state ath12k_hw::state * between hardware start<=>reconfigure<=>stop transitions. */ diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 1f00a2362ae6..bc2da8530651 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -9254,7 +9254,6 @@ static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_base *ab, ah = ath12k_hw_to_ah(hw); ah->hw = hw; - ah->ab = ab; ah->num_radio = num_pdev_map; mutex_init(&ah->hw_mutex); From 94f228ac4f5b8c22f83865e51d3346c2d44d370d Mon Sep 17 00:00:00 2001 From: Lingbo Kong Date: Tue, 11 Jun 2024 10:25:50 +0800 Subject: [PATCH 021/204] wifi: ath11k: fix ack signal strength calculation Currently, the calculation of ack signal strength is incorrect. This is because before calculating the ack signal strength, ath11k need to determine whether the hardware and firmware support db2dbm. If the hardware and firmware support db2dbm, do not need to add noise floor, otherwise, need to add noise floor. Besides, the value of ack_rssi passed by firmware to ath11k should be a signed number, so change its type to s8. After that, "iw wlan0 station dump" show the correct ack signal strength. Such as: root@CDCCSTEX0799733-LIN:~# iw wlp88s0 station dump Station 00:03:7f:12:df:df (on wlp88s0) inactive time: 75 ms rx bytes: 11599 rx packets: 99 tx bytes: 9029 tx packets: 81 tx retries: 4 tx failed: 0 rx drop misc: 2 signal: -16 dBm signal avg: -24 dBm tx bitrate: 1560.0 MBit/s VHT-MCS 9 80MHz VHT-NSS 4 tx duration: 9230 us rx bitrate: 1560.0 MBit/s VHT-MCS 9 80MHz VHT-NSS 4 rx duration: 7201 us last ack signal:-23 dBm avg ack signal: -22 dBm Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30 Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Lingbo Kong Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240611022550.59078-1-quic_lingbok@quicinc.com --- drivers/net/wireless/ath/ath11k/dp_tx.c | 16 ++++++++++++---- drivers/net/wireless/ath/ath11k/dp_tx.h | 4 ++-- drivers/net/wireless/ath/ath11k/hal_tx.h | 4 ++-- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c index 21819b741701..8522c67baabf 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.c +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c @@ -353,8 +353,12 @@ ath11k_dp_tx_htt_tx_complete_buf(struct ath11k_base *ab, if (ts->acked) { if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { info->flags |= IEEE80211_TX_STAT_ACK; - info->status.ack_signal = ATH11K_DEFAULT_NOISE_FLOOR + - ts->ack_rssi; + 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 += ATH11K_DEFAULT_NOISE_FLOOR; + info->status.flags |= IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; } else { @@ -584,8 +588,12 @@ static void ath11k_dp_tx_complete_msdu(struct ath11k *ar, if (ts->status == HAL_WBM_TQM_REL_REASON_FRAME_ACKED && !(info->flags & IEEE80211_TX_CTL_NO_ACK)) { info->flags |= IEEE80211_TX_STAT_ACK; - info->status.ack_signal = ATH11K_DEFAULT_NOISE_FLOOR + - ts->ack_rssi; + 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 += ATH11K_DEFAULT_NOISE_FLOOR; + info->status.flags |= IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; } diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.h b/drivers/net/wireless/ath/ath11k/dp_tx.h index 61be2265e09f..795fe3b8fa0d 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.h +++ b/drivers/net/wireless/ath/ath11k/dp_tx.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021, 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_DP_TX_H @@ -13,7 +13,7 @@ struct ath11k_dp_htt_wbm_tx_status { u32 msdu_id; bool acked; - int ack_rssi; + s8 ack_rssi; u16 peer_id; }; diff --git a/drivers/net/wireless/ath/ath11k/hal_tx.h b/drivers/net/wireless/ath/ath11k/hal_tx.h index c5e88364afe5..46d17abd808b 100644 --- a/drivers/net/wireless/ath/ath11k/hal_tx.h +++ b/drivers/net/wireless/ath/ath11k/hal_tx.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_HAL_TX_H @@ -54,7 +54,7 @@ struct hal_tx_info { struct hal_tx_status { enum hal_wbm_rel_src_module buf_rel_source; enum hal_wbm_tqm_rel_reason status; - u8 ack_rssi; + s8 ack_rssi; u32 flags; /* %HAL_TX_STATUS_FLAGS_ */ u32 ppdu_id; u8 try_cnt; From aadeee47e9d7ae98f7116f63fa63fcceffffc65c Mon Sep 17 00:00:00 2001 From: Lingbo Kong Date: Sat, 9 Mar 2024 20:11:29 +0800 Subject: [PATCH 022/204] wifi: ath11k: modify the calculation of the average signal strength in station mode Currently, the calculation of the average signal strength in station mode is incorrect. This is because before calculating the average signal strength, ath11k need to determine whether the hardware and firmware support db2dbm, if the hardware and firmware support db2dbm, do not need to add noise floor, otherwise, need to add noise floor. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Lingbo Kong Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240309121129.5379-1-quic_lingbok@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index bb56160048ba..779009774567 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -8984,8 +8984,11 @@ static void ath11k_mac_op_sta_statistics(struct ieee80211_hw *hw, sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); } - sinfo->signal_avg = ewma_avg_rssi_read(&arsta->avg_rssi) + - ATH11K_DEFAULT_NOISE_FLOOR; + sinfo->signal_avg = ewma_avg_rssi_read(&arsta->avg_rssi); + + if (!db2dbm) + sinfo->signal_avg += ATH11K_DEFAULT_NOISE_FLOOR; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG); } From 59ca26c9a6e844204d25299774caa5441c0e68eb Mon Sep 17 00:00:00 2001 From: Aaradhana Sahu Date: Tue, 11 Jun 2024 08:40:16 +0530 Subject: [PATCH 023/204] wifi: ath12k: fix NULL pointer access in ath12k_mac_op_get_survey() Smatch throws below error drivers/net/wireless/ath/ath12k/mac.c:8318 ath12k_mac_op_get_survey() error: we previously assumed 'sband' could be null Currently, we access sband inside the null check of the sband in ath12k_mac_op_get_survey(). Fix this issue by removing the entire if block, because decrement idx is unnecessary since there are no more band to test. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Fixes: 70e3be54bbdd ("wifi: ath12k: fix survey dump collection in 6 GHz") Signed-off-by: Aaradhana Sahu Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240611031017.297927-2-quic_aarasahu@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index bc2da8530651..00a158c22971 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -8291,10 +8291,6 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx, if (!sband) sband = hw->wiphy->bands[NL80211_BAND_6GHZ]; - if (!sband || idx >= sband->n_channels) { - idx -= sband->n_channels; - sband = NULL; - } if (!sband || idx >= sband->n_channels) return -ENOENT; From 19b77e7c656a3e125319cc3ef347b397cf042bf6 Mon Sep 17 00:00:00 2001 From: Aaradhana Sahu Date: Tue, 11 Jun 2024 08:40:17 +0530 Subject: [PATCH 024/204] wifi: ath12k: fix uninitialize symbol error on ath12k_peer_assoc_h_he() Smatch throws following errors drivers/net/wireless/ath/ath12k/mac.c:1922 ath12k_peer_assoc_h_he() error: uninitialized symbol 'rx_mcs_80'. drivers/net/wireless/ath/ath12k/mac.c:1922 ath12k_peer_assoc_h_he() error: uninitialized symbol 'rx_mcs_160'. drivers/net/wireless/ath/ath12k/mac.c:1924 ath12k_peer_assoc_h_he() error: uninitialized symbol 'rx_mcs_80'. In ath12k_peer_assoc_h_he() rx_mcs_80 and rx_mcs_160 variables remain uninitialized in the following conditions: 1. Whenever the value of mcs_80 become equal to IEEE80211_HE_MCS_NOT_SUPPORTED then rx_mcs_80 remains uninitialized. 2. Whenever phy capability is not supported 160 channel width and value of mcs_160 become equal to IEEE80211_HE_MCS_NOT_SUPPORTED then rx_mcs_160 remains uninitialized. Initialize these variables during declaration. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aaradhana Sahu Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240611031017.297927-3-quic_aarasahu@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 00a158c22971..2a4ca73dfc22 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -2050,7 +2050,9 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar, { const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap; int i; - u8 ampdu_factor, rx_mcs_80, rx_mcs_160, max_nss; + 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; bool support_160; u16 v; From 3005c63a3673eaf3202b2e0c951e5092539bf758 Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Wed, 12 Jun 2024 15:53:36 -0700 Subject: [PATCH 025/204] wifi: ath12k: fix legacy peer association due to missing HT or 6 GHz capabilities Currently SMPS configuration failed when the Information Elements (IEs) did not contain HT or 6 GHz capabilities. This caused legacy peer association to fail as legacy peers do not have HT or 6 GHz capabilities. Fix this by not returning an error when SMPS configuration fails due to the absence of HT or 6 GHz capabilities. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Fixes: f0e61dc7ecf9 ("wifi: ath12k: refactor SMPS configuration") Reported-by: Aditya Kumar Singh Reported-by: Zachary Smith Closes: https://lore.kernel.org/all/CAM=znoFPcXrn5GhDmDmo50Syic3-hXpWvD+vkv8KX5o_ZTo8kQ@mail.gmail.com/ Signed-off-by: Pradeep Kumar Chitrapu Reported-by: Aditya Kumar Singh Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240612225336.2303119-1-quic_pradeepc@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 2a4ca73dfc22..af19870eb8c0 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -2257,9 +2257,6 @@ static int ath12k_get_smps_from_capa(const struct ieee80211_sta_ht_cap *ht_cap, const struct ieee80211_he_6ghz_capa *he_6ghz_capa, int *smps) { - if (!ht_cap->ht_supported && !he_6ghz_capa->capa) - return -EOPNOTSUPP; - if (ht_cap->ht_supported) *smps = u16_get_bits(ht_cap->cap, IEEE80211_HT_CAP_SM_PS); else @@ -2279,6 +2276,9 @@ static void ath12k_peer_assoc_h_smps(struct ieee80211_sta *sta, const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap; int smps; + if (!ht_cap->ht_supported && !he_6ghz_capa->capa) + return; + if (ath12k_get_smps_from_capa(ht_cap, he_6ghz_capa, &smps)) return; @@ -2758,6 +2758,9 @@ static int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_vif *arvif, { int smps, ret = 0; + if (!ht_cap->ht_supported && !he_6ghz_capa) + return 0; + ret = ath12k_get_smps_from_capa(ht_cap, he_6ghz_capa, &smps); if (ret < 0) return ret; From db163a463bb93cd3e37e1e7b10b9726fb6f95857 Mon Sep 17 00:00:00 2001 From: Ajith C Date: Thu, 13 Jun 2024 11:05:28 +0530 Subject: [PATCH 026/204] wifi: ath12k: fix firmware crash due to invalid peer nss Currently, if the access point receives an association request containing an Extended HE Capabilities Information Element with an invalid MCS-NSS, it triggers a firmware crash. This issue arises when EHT-PHY capabilities shows support for a bandwidth and MCS-NSS set for that particular bandwidth is filled by zeros and due to this, driver obtains peer_nss as 0 and sending this value to firmware causes crash. Address this issue by implementing a validation step for the peer_nss value before passing it to the firmware. If the value is greater than zero, proceed with forwarding it to the firmware. However, if the value is invalid, reject the association request to prevent potential firmware crashes. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Ajith C Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240613053528.2541645-1-quic_ajithc@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index af19870eb8c0..f9caed8ffd63 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -4092,6 +4092,11 @@ static int ath12k_station_assoc(struct ath12k *ar, ath12k_peer_assoc_prepare(ar, vif, sta, &peer_arg, reassoc); + if (peer_arg.peer_nss < 1) { + ath12k_warn(ar->ab, + "invalid peer NSS %d\n", peer_arg.peer_nss); + return -EINVAL; + } 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", From 253ec89c9013b0e61f5c54344df7c065d54934d1 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Thu, 13 Jun 2024 21:08:13 +0530 Subject: [PATCH 027/204] wifi: ath12k: fix mbssid max interface advertisement The Current method for advertising the maximum MBSSID interface count assumes single radio per wiphy (multi wiphy model). However, this assumption is incorrect for multi radio per wiphy (single wiphy model). Therefore, populate the parameter for each radio present in the MAC abstraction layer (ah). This approach ensure scalability for both single wiphy and multi wiphy models. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Fixes: 519a545cfee7 ("wifi: ath12k: advertise driver capabilities for MBSSID and EMA") Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240613153813.3509837-1-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index f9caed8ffd63..17b7fab03d50 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -8942,6 +8942,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) u32 ht_cap = U32_MAX, antennas_rx = 0, antennas_tx = 0; bool is_6ghz = false, is_raw_mode = false, is_monitor_disable = false; u8 *mac_addr = NULL; + u8 mbssid_max_interfaces = 0; wiphy->max_ap_assoc_sta = 0; @@ -8985,6 +8986,8 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) mac_addr = ar->mac_addr; else mac_addr = ab->mac_addr; + + mbssid_max_interfaces += TARGET_NUM_VDEVS; } wiphy->available_antennas_rx = antennas_rx; @@ -9077,7 +9080,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) wiphy->iftype_ext_capab = ath12k_iftypes_ext_capa; wiphy->num_iftype_ext_capab = ARRAY_SIZE(ath12k_iftypes_ext_capa); - wiphy->mbssid_max_interfaces = TARGET_NUM_VDEVS; + wiphy->mbssid_max_interfaces = mbssid_max_interfaces; wiphy->ema_max_profile_periodicity = TARGET_EMA_MAX_PROFILE_PERIOD; if (is_6ghz) { From d7dd13ea54af8496aca2762a758d817d6813e81c Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sun, 16 Jun 2024 22:27:34 +0300 Subject: [PATCH 028/204] wifi: rtw88: usb: Further limit the TX aggregation Currently the number of frames sent to the chip in a single USB Request Block is limited only by the size of the TX buffer, which is 20 KiB. Testing reveals that as many as 13 frames get aggregated. This is more than what any of the chips would like to receive. RTL8822CU, RTL8822BU, and RTL8821CU want at most 3 frames, and RTL8723DU wants only 1 frame per URB. RTL8723DU in particular reliably malfunctions during a speed test if it receives more than 1 frame per URB. All traffic seems to stop. Pinging the AP no longer works. Fix this problem by limiting the number of frames sent to the chip in a single URB according to what each chip likes. Also configure RTL8822CU, RTL8822BU, and RTL8821CU to expect 3 frames per URB. RTL8703B may or may not be found in USB devices. Declare that it wants only 1 frame per URB, just in case. Tested with RTL8723DU and RTL8811CU. Cc: stable@vger.kernel.org Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/cb46ea35-7e59-4742-9c1f-01ceeaad36fb@gmail.com --- drivers/net/wireless/realtek/rtw88/mac.c | 9 +++++++++ drivers/net/wireless/realtek/rtw88/main.h | 2 ++ drivers/net/wireless/realtek/rtw88/reg.h | 1 + drivers/net/wireless/realtek/rtw88/rtw8703b.c | 1 + drivers/net/wireless/realtek/rtw88/rtw8723d.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 + drivers/net/wireless/realtek/rtw88/usb.c | 4 +++- 9 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c index 0dba8aae7716..564f5988ee82 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.c +++ b/drivers/net/wireless/realtek/rtw88/mac.c @@ -1201,6 +1201,15 @@ static int __priority_queue_cfg(struct rtw_dev *rtwdev, rtw_write16(rtwdev, REG_FIFOPAGE_CTRL_2 + 2, fifo->rsvd_boundary); rtw_write16(rtwdev, REG_BCNQ1_BDNY_V1, fifo->rsvd_boundary); rtw_write32(rtwdev, REG_RXFF_BNDY, chip->rxff_size - C2H_PKT_BUF - 1); + + if (rtwdev->hci.type == RTW_HCI_TYPE_USB) { + rtw_write8_mask(rtwdev, REG_AUTO_LLT_V1, BIT_MASK_BLK_DESC_NUM, + chip->usb_tx_agg_desc_num); + + rtw_write8(rtwdev, REG_AUTO_LLT_V1 + 3, chip->usb_tx_agg_desc_num); + rtw_write8_set(rtwdev, REG_TXDMA_OFFSET_CHK + 1, BIT(1)); + } + rtw_write8_set(rtwdev, REG_AUTO_LLT_V1, BIT_AUTO_INIT_LLT_V1); if (!check_hw_ready(rtwdev, REG_AUTO_LLT_V1, BIT_AUTO_INIT_LLT_V1, 0)) diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 49894331f7b4..49a3fd4fb7dc 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -1197,6 +1197,8 @@ struct rtw_chip_info { u16 fw_fifo_addr[RTW_FW_FIFO_MAX]; const struct rtw_fwcd_segs *fwcd_segs; + u8 usb_tx_agg_desc_num; + u8 default_1ss_tx_path; bool path_div_supported; diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h index b122f226924b..02ef9a77316b 100644 --- a/drivers/net/wireless/realtek/rtw88/reg.h +++ b/drivers/net/wireless/realtek/rtw88/reg.h @@ -270,6 +270,7 @@ #define BIT_MASK_BCN_HEAD_1_V1 0xfff #define REG_AUTO_LLT_V1 0x0208 #define BIT_AUTO_INIT_LLT_V1 BIT(0) +#define BIT_MASK_BLK_DESC_NUM GENMASK(7, 4) #define REG_DWBCN0_CTRL 0x0208 #define BIT_BCN_VALID BIT(16) #define REG_TXDMA_OFFSET_CHK 0x020C diff --git a/drivers/net/wireless/realtek/rtw88/rtw8703b.c b/drivers/net/wireless/realtek/rtw88/rtw8703b.c index 8919f9e11f03..222608de33cd 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8703b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8703b.c @@ -2013,6 +2013,7 @@ const struct rtw_chip_info rtw8703b_hw_spec = { .tx_stbc = false, .max_power_index = 0x3f, .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, + .usb_tx_agg_desc_num = 1, /* Not sure if this chip has USB interface */ .path_div_supported = false, .ht_supported = true, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c index f8df4c84d39f..3fba4054d45f 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c @@ -2171,6 +2171,7 @@ const struct rtw_chip_info rtw8723d_hw_spec = { .band = RTW_BAND_2G, .page_size = TX_PAGE_SIZE, .dig_min = 0x20, + .usb_tx_agg_desc_num = 1, .ht_supported = true, .vht_supported = false, .lps_deep_mode_supported = 0, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c index fe5d8e188350..526e8de77b3e 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c @@ -2008,6 +2008,7 @@ const struct rtw_chip_info rtw8821c_hw_spec = { .band = RTW_BAND_2G | RTW_BAND_5G, .page_size = TX_PAGE_SIZE, .dig_min = 0x1c, + .usb_tx_agg_desc_num = 3, .ht_supported = true, .vht_supported = true, .lps_deep_mode_supported = BIT(LPS_DEEP_MODE_LCLK), diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index 3017a9760da8..2456ff242818 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -2548,6 +2548,7 @@ const struct rtw_chip_info rtw8822b_hw_spec = { .band = RTW_BAND_2G | RTW_BAND_5G, .page_size = TX_PAGE_SIZE, .dig_min = 0x1c, + .usb_tx_agg_desc_num = 3, .ht_supported = true, .vht_supported = true, .lps_deep_mode_supported = BIT(LPS_DEEP_MODE_LCLK), diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index cd965edc29ce..62376d1cca22 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -5366,6 +5366,7 @@ const struct rtw_chip_info rtw8822c_hw_spec = { .band = RTW_BAND_2G | RTW_BAND_5G, .page_size = TX_PAGE_SIZE, .dig_min = 0x20, + .usb_tx_agg_desc_num = 3, .default_1ss_tx_path = BB_PATH_A, .path_div_supported = true, .ht_supported = true, diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c index d204d138afe2..057c0ffbe944 100644 --- a/drivers/net/wireless/realtek/rtw88/usb.c +++ b/drivers/net/wireless/realtek/rtw88/usb.c @@ -379,7 +379,9 @@ static bool rtw_usb_tx_agg_skb(struct rtw_usb *rtwusb, struct sk_buff_head *list skb_iter = skb_peek(list); - if (skb_iter && skb_iter->len + skb_head->len <= RTW_USB_MAX_XMITBUF_SZ) + if (skb_iter && + skb_iter->len + skb_head->len <= RTW_USB_MAX_XMITBUF_SZ && + agg_num < rtwdev->chip->usb_tx_agg_desc_num) __skb_unlink(skb_iter, list); else skb_iter = NULL; From 6c3b5970b0c408e39d776113cf4624c1f551d68b Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Wed, 19 Jun 2024 10:40:17 +0800 Subject: [PATCH 029/204] wifi: rtl8xxxu: use swap() in rtl8xxxu_switch_ports() Use existing swap() function rather than duplicating its implementation. ./drivers/net/wireless/realtek/rtl8xxxu/core.c:6749:30-31: WARNING opportunity for swap(). Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=9358 Signed-off-by: Jiapeng Chong Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240619024017.53246-1-jiapeng.chong@linux.alibaba.com --- drivers/net/wireless/realtek/rtl8xxxu/core.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/core.c b/drivers/net/wireless/realtek/rtl8xxxu/core.c index 89a841b4e8d5..e19fd31edfda 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/core.c @@ -6679,7 +6679,6 @@ static void rtl8xxxu_switch_ports(struct rtl8xxxu_priv *priv) u8 macid[ETH_ALEN], bssid[ETH_ALEN], macid_1[ETH_ALEN], bssid_1[ETH_ALEN]; u8 msr, bcn_ctrl, bcn_ctrl_1, atimwnd[2], atimwnd_1[2]; struct rtl8xxxu_vif *rtlvif; - struct ieee80211_vif *vif; u8 tsftr[8], tsftr_1[8]; int i; @@ -6744,10 +6743,7 @@ static void rtl8xxxu_switch_ports(struct rtl8xxxu_priv *priv) /* write bcn ctl */ rtl8xxxu_write8(priv, REG_BEACON_CTRL, bcn_ctrl_1); rtl8xxxu_write8(priv, REG_BEACON_CTRL_1, bcn_ctrl); - - vif = priv->vifs[0]; - priv->vifs[0] = priv->vifs[1]; - priv->vifs[1] = vif; + swap(priv->vifs[0], priv->vifs[1]); /* priv->vifs[0] is NULL here, based on how this function is currently * called from rtl8xxxu_add_interface(). From 3216b7bcd7197ca5da204d3eea81d308cae2a849 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Wed, 19 Jun 2024 17:21:11 +0300 Subject: [PATCH 030/204] wifi: ath12k: add ATH12K_DBG_WOW log level Currently there is no dedicated log level for WoW, so create it for future use. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240604055407.12506-2-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/debug.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/debug.h b/drivers/net/wireless/ath/ath12k/debug.h index aa685295f8a4..f7005917362c 100644 --- a/drivers/net/wireless/ath/ath12k/debug.h +++ b/drivers/net/wireless/ath/ath12k/debug.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _ATH12K_DEBUG_H_ @@ -25,6 +25,7 @@ enum ath12k_debug_mask { ATH12K_DBG_PCI = 0x00001000, ATH12K_DBG_DP_TX = 0x00002000, ATH12K_DBG_DP_RX = 0x00004000, + ATH12K_DBG_WOW = 0x00008000, ATH12K_DBG_ANY = 0xffffffff, }; From 5931741709195da9abb0fb0b8c0fed5d0898b275 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Wed, 19 Jun 2024 17:21:11 +0300 Subject: [PATCH 031/204] wifi: ath12k: implement WoW enable and wakeup commands Implement WoW enable and WoW wakeup commands which are needed for suspend/resume. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240604055407.12506-3-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/Makefile | 1 + drivers/net/wireless/ath/ath12k/core.c | 2 + drivers/net/wireless/ath/ath12k/core.h | 4 + drivers/net/wireless/ath/ath12k/wmi.c | 105 ++++++++++++++ drivers/net/wireless/ath/ath12k/wmi.h | 174 +++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/wow.c | 79 ++++++++++ drivers/net/wireless/ath/ath12k/wow.h | 30 ++++ 7 files changed, 395 insertions(+) create mode 100644 drivers/net/wireless/ath/ath12k/wow.c create mode 100644 drivers/net/wireless/ath/ath12k/wow.h diff --git a/drivers/net/wireless/ath/ath12k/Makefile b/drivers/net/wireless/ath/ath12k/Makefile index d42480db7463..f0dcc933aa95 100644 --- a/drivers/net/wireless/ath/ath12k/Makefile +++ b/drivers/net/wireless/ath/ath12k/Makefile @@ -26,6 +26,7 @@ ath12k-y += core.o \ ath12k-$(CONFIG_ATH12K_DEBUGFS) += debugfs.o ath12k-$(CONFIG_ACPI) += acpi.o ath12k-$(CONFIG_ATH12K_TRACING) += trace.o +ath12k-$(CONFIG_PM) += wow.o # for tracing framework to find trace.h CFLAGS_trace.o := -I$(src) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 197099f15e3f..7603516500ba 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -16,6 +16,7 @@ #include "hif.h" #include "fw.h" #include "debugfs.h" +#include "wow.h" unsigned int ath12k_debug_mask; module_param_named(debug_mask, ath12k_debug_mask, uint, 0644); @@ -1285,6 +1286,7 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size, timer_setup(&ab->rx_replenish_retry, ath12k_ce_rx_replenish_retry, 0); init_completion(&ab->htc_suspend); init_completion(&ab->restart_completed); + init_completion(&ab->wow.wakeup_completed); ab->dev = dev; ab->hif.bus = bus; diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index d7a3e8fddb20..10aa3aca7250 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -765,6 +765,10 @@ struct ath12k_base { const struct ath12k_hif_ops *ops; } hif; + struct { + struct completion wakeup_completed; + } wow; + struct ath12k_ce ce; struct timer_list rx_replenish_retry; struct ath12k_hal hal; diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index d6e1d1398cdb..3eafa46d737b 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -7030,6 +7030,66 @@ static void ath12k_wmi_twt_disable_event(struct ath12k_base *ab, kfree(tb); } +static int ath12k_wmi_wow_wakeup_host_parse(struct ath12k_base *ab, + u16 tag, u16 len, + const void *ptr, void *data) +{ + const struct wmi_wow_ev_pg_fault_param *pf_param; + const struct wmi_wow_ev_param *param; + struct wmi_wow_ev_arg *arg = data; + int pf_len; + + switch (tag) { + case WMI_TAG_WOW_EVENT_INFO: + param = ptr; + arg->wake_reason = le32_to_cpu(param->wake_reason); + ath12k_dbg(ab, ATH12K_DBG_WMI, "wow wakeup host reason %d %s\n", + arg->wake_reason, wow_reason(arg->wake_reason)); + break; + + case WMI_TAG_ARRAY_BYTE: + if (arg && arg->wake_reason == WOW_REASON_PAGE_FAULT) { + pf_param = ptr; + pf_len = le32_to_cpu(pf_param->len); + if (pf_len > len - sizeof(pf_len) || + pf_len < 0) { + ath12k_warn(ab, "invalid wo reason page fault buffer len %d\n", + pf_len); + return -EINVAL; + } + ath12k_dbg(ab, ATH12K_DBG_WMI, "wow_reason_page_fault len %d\n", + pf_len); + ath12k_dbg_dump(ab, ATH12K_DBG_WMI, + "wow_reason_page_fault packet present", + "wow_pg_fault ", + pf_param->data, + pf_len); + } + break; + default: + break; + } + + return 0; +} + +static void ath12k_wmi_event_wow_wakeup_host(struct ath12k_base *ab, struct sk_buff *skb) +{ + struct wmi_wow_ev_arg arg = { }; + int ret; + + ret = ath12k_wmi_tlv_iter(ab, skb->data, skb->len, + ath12k_wmi_wow_wakeup_host_parse, + &arg); + if (ret) { + ath12k_warn(ab, "failed to parse wmi wow wakeup host event tlv: %d\n", + ret); + return; + } + + complete(&ab->wow.wakeup_completed); +} + static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; @@ -7150,6 +7210,9 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) case WMI_DIAG_EVENTID: ath12k_wmi_diag_event(ab, skb); break; + case WMI_WOW_WAKEUP_HOST_EVENTID: + ath12k_wmi_event_wow_wakeup_host(ab, skb); + break; /* TODO: Add remaining events */ default: ath12k_dbg(ab, ATH12K_DBG_WMI, "Unknown eventid: 0x%x\n", id); @@ -7359,3 +7422,45 @@ void ath12k_wmi_detach(struct ath12k_base *ab) ath12k_wmi_free_dbring_caps(ab); } + +int ath12k_wmi_wow_host_wakeup_ind(struct ath12k *ar) +{ + struct wmi_wow_host_wakeup_cmd *cmd; + struct sk_buff *skb; + size_t len; + + len = sizeof(*cmd); + skb = ath12k_wmi_alloc_skb(ar->wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_wow_host_wakeup_cmd *)skb->data; + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_WOW_HOSTWAKEUP_FROM_SLEEP_CMD, + sizeof(*cmd)); + + ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "wmi tlv wow host wakeup ind\n"); + + return ath12k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID); +} + +int ath12k_wmi_wow_enable(struct ath12k *ar) +{ + struct wmi_wow_enable_cmd *cmd; + struct sk_buff *skb; + int len; + + len = sizeof(*cmd); + skb = ath12k_wmi_alloc_skb(ar->wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_wow_enable_cmd *)skb->data; + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_WOW_ENABLE_CMD, + sizeof(*cmd)); + + cmd->enable = cpu_to_le32(1); + cmd->pause_iface_config = cpu_to_le32(WOW_IFACE_PAUSE_ENABLED); + ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "wmi tlv wow enable\n"); + + return ath12k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ENABLE_CMDID); +} diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index c2b86e187a03..9cee3a114645 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -4902,6 +4902,178 @@ struct wmi_twt_disable_event { __le32 status; } __packed; +/* WOW structures */ +enum wmi_wow_wakeup_event { + WOW_BMISS_EVENT = 0, + WOW_BETTER_AP_EVENT, + WOW_DEAUTH_RECVD_EVENT, + WOW_MAGIC_PKT_RECVD_EVENT, + WOW_GTK_ERR_EVENT, + WOW_FOURWAY_HSHAKE_EVENT, + WOW_EAPOL_RECVD_EVENT, + WOW_NLO_DETECTED_EVENT, + WOW_DISASSOC_RECVD_EVENT, + WOW_PATTERN_MATCH_EVENT, + WOW_CSA_IE_EVENT, + WOW_PROBE_REQ_WPS_IE_EVENT, + WOW_AUTH_REQ_EVENT, + WOW_ASSOC_REQ_EVENT, + WOW_HTT_EVENT, + WOW_RA_MATCH_EVENT, + WOW_HOST_AUTO_SHUTDOWN_EVENT, + WOW_IOAC_MAGIC_EVENT, + WOW_IOAC_SHORT_EVENT, + WOW_IOAC_EXTEND_EVENT, + WOW_IOAC_TIMER_EVENT, + WOW_DFS_PHYERR_RADAR_EVENT, + WOW_BEACON_EVENT, + WOW_CLIENT_KICKOUT_EVENT, + WOW_EVENT_MAX, +}; + +enum wmi_wow_interface_cfg { + WOW_IFACE_PAUSE_ENABLED, + WOW_IFACE_PAUSE_DISABLED +}; + +#define C2S(x) case x: return #x + +static inline const char *wow_wakeup_event(enum wmi_wow_wakeup_event ev) +{ + switch (ev) { + C2S(WOW_BMISS_EVENT); + C2S(WOW_BETTER_AP_EVENT); + C2S(WOW_DEAUTH_RECVD_EVENT); + C2S(WOW_MAGIC_PKT_RECVD_EVENT); + C2S(WOW_GTK_ERR_EVENT); + C2S(WOW_FOURWAY_HSHAKE_EVENT); + C2S(WOW_EAPOL_RECVD_EVENT); + C2S(WOW_NLO_DETECTED_EVENT); + C2S(WOW_DISASSOC_RECVD_EVENT); + C2S(WOW_PATTERN_MATCH_EVENT); + C2S(WOW_CSA_IE_EVENT); + C2S(WOW_PROBE_REQ_WPS_IE_EVENT); + C2S(WOW_AUTH_REQ_EVENT); + C2S(WOW_ASSOC_REQ_EVENT); + C2S(WOW_HTT_EVENT); + C2S(WOW_RA_MATCH_EVENT); + C2S(WOW_HOST_AUTO_SHUTDOWN_EVENT); + C2S(WOW_IOAC_MAGIC_EVENT); + C2S(WOW_IOAC_SHORT_EVENT); + C2S(WOW_IOAC_EXTEND_EVENT); + C2S(WOW_IOAC_TIMER_EVENT); + C2S(WOW_DFS_PHYERR_RADAR_EVENT); + C2S(WOW_BEACON_EVENT); + C2S(WOW_CLIENT_KICKOUT_EVENT); + C2S(WOW_EVENT_MAX); + default: + return NULL; + } +} + +enum wmi_wow_wake_reason { + WOW_REASON_UNSPECIFIED = -1, + WOW_REASON_NLOD = 0, + WOW_REASON_AP_ASSOC_LOST, + WOW_REASON_LOW_RSSI, + WOW_REASON_DEAUTH_RECVD, + WOW_REASON_DISASSOC_RECVD, + WOW_REASON_GTK_HS_ERR, + WOW_REASON_EAP_REQ, + WOW_REASON_FOURWAY_HS_RECV, + WOW_REASON_TIMER_INTR_RECV, + WOW_REASON_PATTERN_MATCH_FOUND, + WOW_REASON_RECV_MAGIC_PATTERN, + WOW_REASON_P2P_DISC, + WOW_REASON_WLAN_HB, + WOW_REASON_CSA_EVENT, + WOW_REASON_PROBE_REQ_WPS_IE_RECV, + WOW_REASON_AUTH_REQ_RECV, + WOW_REASON_ASSOC_REQ_RECV, + WOW_REASON_HTT_EVENT, + WOW_REASON_RA_MATCH, + WOW_REASON_HOST_AUTO_SHUTDOWN, + WOW_REASON_IOAC_MAGIC_EVENT, + WOW_REASON_IOAC_SHORT_EVENT, + WOW_REASON_IOAC_EXTEND_EVENT, + WOW_REASON_IOAC_TIMER_EVENT, + WOW_REASON_ROAM_HO, + WOW_REASON_DFS_PHYERR_RADADR_EVENT, + WOW_REASON_BEACON_RECV, + WOW_REASON_CLIENT_KICKOUT_EVENT, + WOW_REASON_PAGE_FAULT = 0x3a, + WOW_REASON_DEBUG_TEST = 0xFF, +}; + +static inline const char *wow_reason(enum wmi_wow_wake_reason reason) +{ + switch (reason) { + C2S(WOW_REASON_UNSPECIFIED); + C2S(WOW_REASON_NLOD); + C2S(WOW_REASON_AP_ASSOC_LOST); + C2S(WOW_REASON_LOW_RSSI); + C2S(WOW_REASON_DEAUTH_RECVD); + C2S(WOW_REASON_DISASSOC_RECVD); + C2S(WOW_REASON_GTK_HS_ERR); + C2S(WOW_REASON_EAP_REQ); + C2S(WOW_REASON_FOURWAY_HS_RECV); + C2S(WOW_REASON_TIMER_INTR_RECV); + C2S(WOW_REASON_PATTERN_MATCH_FOUND); + C2S(WOW_REASON_RECV_MAGIC_PATTERN); + C2S(WOW_REASON_P2P_DISC); + C2S(WOW_REASON_WLAN_HB); + C2S(WOW_REASON_CSA_EVENT); + C2S(WOW_REASON_PROBE_REQ_WPS_IE_RECV); + C2S(WOW_REASON_AUTH_REQ_RECV); + C2S(WOW_REASON_ASSOC_REQ_RECV); + C2S(WOW_REASON_HTT_EVENT); + C2S(WOW_REASON_RA_MATCH); + C2S(WOW_REASON_HOST_AUTO_SHUTDOWN); + C2S(WOW_REASON_IOAC_MAGIC_EVENT); + C2S(WOW_REASON_IOAC_SHORT_EVENT); + C2S(WOW_REASON_IOAC_EXTEND_EVENT); + C2S(WOW_REASON_IOAC_TIMER_EVENT); + C2S(WOW_REASON_ROAM_HO); + C2S(WOW_REASON_DFS_PHYERR_RADADR_EVENT); + C2S(WOW_REASON_BEACON_RECV); + C2S(WOW_REASON_CLIENT_KICKOUT_EVENT); + C2S(WOW_REASON_PAGE_FAULT); + C2S(WOW_REASON_DEBUG_TEST); + default: + return NULL; + } +} + +#undef C2S + +struct wmi_wow_enable_cmd { + __le32 tlv_header; + __le32 enable; + __le32 pause_iface_config; + __le32 flags; +} __packed; + +struct wmi_wow_host_wakeup_cmd { + __le32 tlv_header; + __le32 reserved; +} __packed; + +struct wmi_wow_ev_param { + __le32 vdev_id; + __le32 flag; + __le32 wake_reason; + __le32 data_len; +} __packed; + +struct wmi_wow_ev_pg_fault_param { + __le32 len; + u8 data[]; +} __packed; + +struct wmi_wow_ev_arg { + enum wmi_wow_wake_reason wake_reason; +}; + 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, @@ -5054,4 +5226,6 @@ ath12k_wmi_mac_phy_get_hw_link_id(const struct ath12k_wmi_mac_phy_caps_params *p WMI_CAPS_PARAMS_HW_LINK_ID); } +int ath12k_wmi_wow_host_wakeup_ind(struct ath12k *ar); +int ath12k_wmi_wow_enable(struct ath12k *ar); #endif diff --git a/drivers/net/wireless/ath/ath12k/wow.c b/drivers/net/wireless/ath/ath12k/wow.c new file mode 100644 index 000000000000..d6d3ed7332ab --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/wow.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include + +#include "mac.h" +#include "core.h" +#include "hif.h" +#include "debug.h" +#include "wmi.h" +#include "wow.h" + +int ath12k_wow_enable(struct ath12k *ar) +{ + struct ath12k_base *ab = ar->ab; + int i, ret; + + clear_bit(ATH12K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags); + + /* The firmware might be busy and it can not enter WoW immediately. + * In that case firmware notifies host with + * ATH12K_HTC_MSG_NACK_SUSPEND message, asking host to try again + * later. Per the firmware team there could be up to 10 loops. + */ + for (i = 0; i < ATH12K_WOW_RETRY_NUM; i++) { + reinit_completion(&ab->htc_suspend); + + ret = ath12k_wmi_wow_enable(ar); + if (ret) { + ath12k_warn(ab, "failed to issue wow enable: %d\n", ret); + return ret; + } + + ret = wait_for_completion_timeout(&ab->htc_suspend, 3 * HZ); + if (ret == 0) { + ath12k_warn(ab, + "timed out while waiting for htc suspend completion\n"); + return -ETIMEDOUT; + } + + if (test_bit(ATH12K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags)) + /* success, suspend complete received */ + return 0; + + ath12k_warn(ab, "htc suspend not complete, retrying (try %d)\n", + i); + msleep(ATH12K_WOW_RETRY_WAIT_MS); + } + + ath12k_warn(ab, "htc suspend not complete, failing after %d tries\n", i); + + return -ETIMEDOUT; +} + +int ath12k_wow_wakeup(struct ath12k *ar) +{ + struct ath12k_base *ab = ar->ab; + int ret; + + reinit_completion(&ab->wow.wakeup_completed); + + ret = ath12k_wmi_wow_host_wakeup_ind(ar); + if (ret) { + ath12k_warn(ab, "failed to send wow wakeup indication: %d\n", + ret); + return ret; + } + + ret = wait_for_completion_timeout(&ab->wow.wakeup_completed, 3 * HZ); + if (ret == 0) { + ath12k_warn(ab, "timed out while waiting for wow wakeup completion\n"); + return -ETIMEDOUT; + } + + return 0; +} diff --git a/drivers/net/wireless/ath/ath12k/wow.h b/drivers/net/wireless/ath/ath12k/wow.h new file mode 100644 index 000000000000..6817ceaa4cfe --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/wow.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef ATH12K_WOW_H +#define ATH12K_WOW_H + +#define ATH12K_WOW_RETRY_NUM 10 +#define ATH12K_WOW_RETRY_WAIT_MS 200 + +#ifdef CONFIG_PM + +int ath12k_wow_enable(struct ath12k *ar); +int ath12k_wow_wakeup(struct ath12k *ar); + +#else + +static inline int ath12k_wow_enable(struct ath12k *ar) +{ + return 0; +} + +static inline int ath12k_wow_wakeup(struct ath12k *ar) +{ + return 0; +} +#endif /* CONFIG_PM */ +#endif /* ATH12K_WOW_H */ From 4a3c212eee0e36c1cd55bfbfb94041a0d3ad265b Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Wed, 19 Jun 2024 17:21:11 +0300 Subject: [PATCH 032/204] wifi: ath12k: add basic WoW functionalities Implement basic WoW functionalities such as magic-packet, disconnect and pattern. The logic is very similar to ath11k. When WoW is configured, ath12k_core_suspend and ath12k_core_resume are skipped (by checking ar->state) as we are not allowed to power cycle firmware. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240604055407.12506-4-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 46 ++- drivers/net/wireless/ath/ath12k/core.h | 5 + drivers/net/wireless/ath/ath12k/htc.c | 6 + drivers/net/wireless/ath/ath12k/mac.c | 14 + drivers/net/wireless/ath/ath12k/wmi.c | 143 +++++++++ drivers/net/wireless/ath/ath12k/wmi.h | 63 ++++ drivers/net/wireless/ath/ath12k/wow.c | 416 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/wow.h | 32 ++ 8 files changed, 717 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 7603516500ba..51252e8bc1ae 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -43,13 +43,37 @@ static int ath12k_core_rfkill_config(struct ath12k_base *ab) return ret; } +/* Check if we need to continue with suspend/resume operation. + * Return: + * a negative value: error happens and don't continue. + * 0: no error but don't continue. + * positive value: no error and do continue. + */ +static int ath12k_core_continue_suspend_resume(struct ath12k_base *ab) +{ + struct ath12k *ar; + + if (!ab->hw_params->supports_suspend) + return -EOPNOTSUPP; + + /* so far single_pdev_only chips have supports_suspend as true + * so pass 0 as a dummy pdev_id here. + */ + ar = ab->pdevs[0].ar; + if (!ar || !ar->ah || ar->ah->state != ATH12K_HW_STATE_OFF) + return 0; + + return 1; +} + int ath12k_core_suspend(struct ath12k_base *ab) { struct ath12k *ar; int ret, i; - if (!ab->hw_params->supports_suspend) - return -EOPNOTSUPP; + ret = ath12k_core_continue_suspend_resume(ab); + if (ret <= 0) + return ret; for (i = 0; i < ab->num_radios; i++) { ar = ab->pdevs[i].ar; @@ -81,8 +105,11 @@ EXPORT_SYMBOL(ath12k_core_suspend); int ath12k_core_suspend_late(struct ath12k_base *ab) { - if (!ab->hw_params->supports_suspend) - return -EOPNOTSUPP; + int ret; + + ret = ath12k_core_continue_suspend_resume(ab); + if (ret <= 0) + return ret; ath12k_acpi_stop(ab); @@ -99,8 +126,9 @@ int ath12k_core_resume_early(struct ath12k_base *ab) { int ret; - if (!ab->hw_params->supports_suspend) - return -EOPNOTSUPP; + ret = ath12k_core_continue_suspend_resume(ab); + if (ret <= 0) + return ret; reinit_completion(&ab->restart_completed); ret = ath12k_hif_power_up(ab); @@ -114,9 +142,11 @@ EXPORT_SYMBOL(ath12k_core_resume_early); int ath12k_core_resume(struct ath12k_base *ab) { long time_left; + int ret; - if (!ab->hw_params->supports_suspend) - return -EOPNOTSUPP; + ret = ath12k_core_continue_suspend_resume(ab); + if (ret <= 0) + return ret; time_left = wait_for_completion_timeout(&ab->restart_completed, ATH12K_RESET_TIMEOUT_HZ); diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 10aa3aca7250..2fd08648cef3 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -28,6 +28,7 @@ #include "dbring.h" #include "fw.h" #include "acpi.h" +#include "wow.h" #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) @@ -607,6 +608,9 @@ struct ath12k { struct work_struct wmi_mgmt_tx_work; struct sk_buff_head wmi_mgmt_tx_queue; + struct ath12k_wow wow; + struct completion target_suspend; + bool target_suspend_ack; struct ath12k_per_peer_tx_stats peer_tx_stats; struct list_head ppdu_stats_info; u32 ppdu_stat_list_depth; @@ -767,6 +771,7 @@ struct ath12k_base { struct { struct completion wakeup_completed; + u32 wmi_conf_rx_decap_mode; } wow; struct ath12k_ce ce; diff --git a/drivers/net/wireless/ath/ath12k/htc.c b/drivers/net/wireless/ath/ath12k/htc.c index 2f2230f565bb..d13616bf07f4 100644 --- a/drivers/net/wireless/ath/ath12k/htc.c +++ b/drivers/net/wireless/ath/ath12k/htc.c @@ -244,6 +244,11 @@ static void ath12k_htc_suspend_complete(struct ath12k_base *ab, bool ack) complete(&ab->htc_suspend); } +static void ath12k_htc_wakeup_from_suspend(struct ath12k_base *ab) +{ + ath12k_dbg(ab, ATH12K_DBG_BOOT, "boot wakeup from suspend is received\n"); +} + void ath12k_htc_rx_completion_handler(struct ath12k_base *ab, struct sk_buff *skb) { @@ -349,6 +354,7 @@ void ath12k_htc_rx_completion_handler(struct ath12k_base *ab, ath12k_htc_suspend_complete(ab, false); break; case ATH12K_HTC_MSG_WAKEUP_FROM_SUSPEND_ID: + ath12k_htc_wakeup_from_suspend(ab); break; default: ath12k_warn(ab, "ignoring unsolicited htc ep0 event %u\n", diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 17b7fab03d50..59662ca241ca 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -15,6 +15,8 @@ #include "dp_rx.h" #include "peer.h" #include "debugfs.h" +#include "hif.h" +#include "wow.h" #define CHAN2G(_channel, _freq, _flags) { \ .band = NL80211_BAND_2GHZ, \ @@ -8578,6 +8580,12 @@ static const struct ieee80211_ops ath12k_ops = { .sta_statistics = ath12k_mac_op_sta_statistics, .remain_on_channel = ath12k_mac_op_remain_on_channel, .cancel_remain_on_channel = ath12k_mac_op_cancel_remain_on_channel, + +#ifdef CONFIG_PM + .suspend = ath12k_wow_op_suspend, + .resume = ath12k_wow_op_resume, + .set_wakeup = ath12k_wow_op_set_wakeup, +#endif }; static void ath12k_mac_update_ch_list(struct ath12k *ar, @@ -9100,6 +9108,12 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); } + ret = ath12k_wow_init(ar); + if (ret) { + ath12k_warn(ar->ab, "failed to init wow: %d\n", ret); + goto err_free_if_combs; + } + ret = ieee80211_register_hw(hw); if (ret) { ath12k_err(ab, "ieee80211 registration failed: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 3eafa46d737b..f72ec153723c 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -3717,6 +3717,7 @@ int ath12k_wmi_cmd_init(struct ath12k_base *ab) arg.res_cfg.is_reg_cc_ext_event_supported = true; ab->hw_params->wmi_init(ab, &arg.res_cfg); + ab->wow.wmi_conf_rx_decap_mode = arg.res_cfg.rx_decap_mode; arg.num_mem_chunks = wmi_ab->num_mem_chunks; arg.hw_mode_id = wmi_ab->preferred_hw_mode; @@ -7464,3 +7465,145 @@ int ath12k_wmi_wow_enable(struct ath12k *ar) return ath12k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ENABLE_CMDID); } + +int ath12k_wmi_wow_add_wakeup_event(struct ath12k *ar, u32 vdev_id, + enum wmi_wow_wakeup_event event, + u32 enable) +{ + struct wmi_wow_add_del_event_cmd *cmd; + struct sk_buff *skb; + size_t len; + + len = sizeof(*cmd); + skb = ath12k_wmi_alloc_skb(ar->wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_wow_add_del_event_cmd *)skb->data; + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_WOW_ADD_DEL_EVT_CMD, + sizeof(*cmd)); + cmd->vdev_id = cpu_to_le32(vdev_id); + cmd->is_add = cpu_to_le32(enable); + cmd->event_bitmap = cpu_to_le32((1 << event)); + + ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "wmi tlv wow add wakeup event %s enable %d vdev_id %d\n", + wow_wakeup_event(event), enable, vdev_id); + + return ath12k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID); +} + +int ath12k_wmi_wow_add_pattern(struct ath12k *ar, u32 vdev_id, u32 pattern_id, + const u8 *pattern, const u8 *mask, + int pattern_len, int pattern_offset) +{ + struct wmi_wow_add_pattern_cmd *cmd; + struct wmi_wow_bitmap_pattern_params *bitmap; + struct wmi_tlv *tlv; + struct sk_buff *skb; + void *ptr; + size_t len; + + len = sizeof(*cmd) + + sizeof(*tlv) + /* array struct */ + sizeof(*bitmap) + /* bitmap */ + sizeof(*tlv) + /* empty ipv4 sync */ + sizeof(*tlv) + /* empty ipv6 sync */ + sizeof(*tlv) + /* empty magic */ + sizeof(*tlv) + /* empty info timeout */ + sizeof(*tlv) + sizeof(u32); /* ratelimit interval */ + + skb = ath12k_wmi_alloc_skb(ar->wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + /* cmd */ + ptr = skb->data; + cmd = ptr; + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_WOW_ADD_PATTERN_CMD, + sizeof(*cmd)); + cmd->vdev_id = cpu_to_le32(vdev_id); + cmd->pattern_id = cpu_to_le32(pattern_id); + cmd->pattern_type = cpu_to_le32(WOW_BITMAP_PATTERN); + + ptr += sizeof(*cmd); + + /* bitmap */ + tlv = ptr; + tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, sizeof(*bitmap)); + + ptr += sizeof(*tlv); + + bitmap = ptr; + bitmap->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_WOW_BITMAP_PATTERN_T, + sizeof(*bitmap)); + memcpy(bitmap->patternbuf, pattern, pattern_len); + memcpy(bitmap->bitmaskbuf, mask, pattern_len); + bitmap->pattern_offset = cpu_to_le32(pattern_offset); + bitmap->pattern_len = cpu_to_le32(pattern_len); + bitmap->bitmask_len = cpu_to_le32(pattern_len); + bitmap->pattern_id = cpu_to_le32(pattern_id); + + ptr += sizeof(*bitmap); + + /* ipv4 sync */ + tlv = ptr; + tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, 0); + + ptr += sizeof(*tlv); + + /* ipv6 sync */ + tlv = ptr; + tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, 0); + + ptr += sizeof(*tlv); + + /* magic */ + tlv = ptr; + tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, 0); + + ptr += sizeof(*tlv); + + /* pattern info timeout */ + tlv = ptr; + tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, 0); + + ptr += sizeof(*tlv); + + /* ratelimit interval */ + tlv = ptr; + tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, sizeof(u32)); + + ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "wmi tlv wow add pattern vdev_id %d pattern_id %d pattern_offset %d pattern_len %d\n", + vdev_id, pattern_id, pattern_offset, pattern_len); + + ath12k_dbg_dump(ar->ab, ATH12K_DBG_WMI, NULL, "wow pattern: ", + bitmap->patternbuf, pattern_len); + ath12k_dbg_dump(ar->ab, ATH12K_DBG_WMI, NULL, "wow bitmask: ", + bitmap->bitmaskbuf, pattern_len); + + return ath12k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ADD_WAKE_PATTERN_CMDID); +} + +int ath12k_wmi_wow_del_pattern(struct ath12k *ar, u32 vdev_id, u32 pattern_id) +{ + struct wmi_wow_del_pattern_cmd *cmd; + struct sk_buff *skb; + size_t len; + + len = sizeof(*cmd); + skb = ath12k_wmi_alloc_skb(ar->wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_wow_del_pattern_cmd *)skb->data; + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_WOW_DEL_PATTERN_CMD, + sizeof(*cmd)); + cmd->vdev_id = cpu_to_le32(vdev_id); + cmd->pattern_id = cpu_to_le32(pattern_id); + cmd->pattern_type = cpu_to_le32(WOW_BITMAP_PATTERN); + + ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "wmi tlv wow del pattern vdev_id %d pattern_id %d\n", + vdev_id, pattern_id); + + return ath12k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_DEL_WAKE_PATTERN_CMDID); +} diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 9cee3a114645..6cb06f6f7df4 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -5046,6 +5046,62 @@ static inline const char *wow_reason(enum wmi_wow_wake_reason reason) #undef C2S +#define WOW_DEFAULT_BITMAP_PATTERN_SIZE 148 +#define WOW_DEFAULT_BITMASK_SIZE 148 + +#define WOW_MIN_PATTERN_SIZE 1 +#define WOW_MAX_PATTERN_SIZE 148 +#define WOW_MAX_PKT_OFFSET 128 +#define WOW_HDR_LEN (sizeof(struct ieee80211_hdr_3addr) + \ + sizeof(struct rfc1042_hdr)) +#define WOW_MAX_REDUCE (WOW_HDR_LEN - sizeof(struct ethhdr) - \ + offsetof(struct ieee80211_hdr_3addr, addr1)) + +struct wmi_wow_bitmap_pattern_params { + __le32 tlv_header; + u8 patternbuf[WOW_DEFAULT_BITMAP_PATTERN_SIZE]; + u8 bitmaskbuf[WOW_DEFAULT_BITMASK_SIZE]; + __le32 pattern_offset; + __le32 pattern_len; + __le32 bitmask_len; + __le32 pattern_id; +} __packed; + +struct wmi_wow_add_pattern_cmd { + __le32 tlv_header; + __le32 vdev_id; + __le32 pattern_id; + __le32 pattern_type; +} __packed; + +struct wmi_wow_del_pattern_cmd { + __le32 tlv_header; + __le32 vdev_id; + __le32 pattern_id; + __le32 pattern_type; +} __packed; + +enum wmi_tlv_pattern_type { + WOW_PATTERN_MIN = 0, + WOW_BITMAP_PATTERN = WOW_PATTERN_MIN, + WOW_IPV4_SYNC_PATTERN, + WOW_IPV6_SYNC_PATTERN, + WOW_WILD_CARD_PATTERN, + WOW_TIMER_PATTERN, + WOW_MAGIC_PATTERN, + WOW_IPV6_RA_PATTERN, + WOW_IOAC_PKT_PATTERN, + WOW_IOAC_TMR_PATTERN, + WOW_PATTERN_MAX +}; + +struct wmi_wow_add_del_event_cmd { + __le32 tlv_header; + __le32 vdev_id; + __le32 is_add; + __le32 event_bitmap; +} __packed; + struct wmi_wow_enable_cmd { __le32 tlv_header; __le32 enable; @@ -5228,4 +5284,11 @@ ath12k_wmi_mac_phy_get_hw_link_id(const struct ath12k_wmi_mac_phy_caps_params *p int ath12k_wmi_wow_host_wakeup_ind(struct ath12k *ar); int ath12k_wmi_wow_enable(struct ath12k *ar); +int ath12k_wmi_wow_del_pattern(struct ath12k *ar, u32 vdev_id, u32 pattern_id); +int ath12k_wmi_wow_add_pattern(struct ath12k *ar, u32 vdev_id, u32 pattern_id, + const u8 *pattern, const u8 *mask, + int pattern_len, int pattern_offset); +int ath12k_wmi_wow_add_wakeup_event(struct ath12k *ar, u32 vdev_id, + enum wmi_wow_wakeup_event event, + u32 enable); #endif diff --git a/drivers/net/wireless/ath/ath12k/wow.c b/drivers/net/wireless/ath/ath12k/wow.c index d6d3ed7332ab..648e7cb970ea 100644 --- a/drivers/net/wireless/ath/ath12k/wow.c +++ b/drivers/net/wireless/ath/ath12k/wow.c @@ -7,12 +7,22 @@ #include #include "mac.h" + +#include #include "core.h" #include "hif.h" #include "debug.h" #include "wmi.h" #include "wow.h" +static const struct wiphy_wowlan_support ath12k_wowlan_support = { + .flags = WIPHY_WOWLAN_DISCONNECT | + WIPHY_WOWLAN_MAGIC_PKT, + .pattern_min_len = WOW_MIN_PATTERN_SIZE, + .pattern_max_len = WOW_MAX_PATTERN_SIZE, + .max_pkt_offset = WOW_MAX_PKT_OFFSET, +}; + int ath12k_wow_enable(struct ath12k *ar) { struct ath12k_base *ab = ar->ab; @@ -77,3 +87,409 @@ int ath12k_wow_wakeup(struct ath12k *ar) return 0; } + +static int ath12k_wow_vif_cleanup(struct ath12k_vif *arvif) +{ + struct ath12k *ar = arvif->ar; + int i, ret; + + for (i = 0; i < WOW_EVENT_MAX; i++) { + ret = ath12k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 0); + if (ret) { + ath12k_warn(ar->ab, "failed to issue wow wakeup for event %s on vdev %i: %d\n", + wow_wakeup_event(i), arvif->vdev_id, ret); + return ret; + } + } + + for (i = 0; i < ar->wow.max_num_patterns; i++) { + ret = ath12k_wmi_wow_del_pattern(ar, arvif->vdev_id, i); + if (ret) { + ath12k_warn(ar->ab, "failed to delete wow pattern %d for vdev %i: %d\n", + i, arvif->vdev_id, ret); + return ret; + } + } + + return 0; +} + +static int ath12k_wow_cleanup(struct ath12k *ar) +{ + struct ath12k_vif *arvif; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + list_for_each_entry(arvif, &ar->arvifs, list) { + ret = ath12k_wow_vif_cleanup(arvif); + if (ret) { + ath12k_warn(ar->ab, "failed to clean wow wakeups on vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + } + + return 0; +} + +/* Convert a 802.3 format to a 802.11 format. + * +------------+-----------+--------+----------------+ + * 802.3: |dest mac(6B)|src mac(6B)|type(2B)| body... | + * +------------+-----------+--------+----------------+ + * |__ |_______ |____________ |________ + * | | | | + * +--+------------+----+-----------+---------------+-----------+ + * 802.11: |4B|dest mac(6B)| 6B |src mac(6B)| 8B |type(2B)| body... | + * +--+------------+----+-----------+---------------+-----------+ + */ +static void +ath12k_wow_convert_8023_to_80211(struct ath12k *ar, + const struct cfg80211_pkt_pattern *eth_pattern, + struct ath12k_pkt_pattern *i80211_pattern) +{ + size_t r1042_eth_ofs = offsetof(struct rfc1042_hdr, eth_type); + size_t a1_ofs = offsetof(struct ieee80211_hdr_3addr, addr1); + size_t a3_ofs = offsetof(struct ieee80211_hdr_3addr, addr3); + size_t i80211_hdr_len = sizeof(struct ieee80211_hdr_3addr); + size_t prot_ofs = offsetof(struct ethhdr, h_proto); + size_t src_ofs = offsetof(struct ethhdr, h_source); + u8 eth_bytemask[WOW_MAX_PATTERN_SIZE] = {}; + const u8 *eth_pat = eth_pattern->pattern; + size_t eth_pat_len = eth_pattern->pattern_len; + size_t eth_pkt_ofs = eth_pattern->pkt_offset; + u8 *bytemask = i80211_pattern->bytemask; + u8 *pat = i80211_pattern->pattern; + size_t pat_len = 0; + size_t pkt_ofs = 0; + size_t delta; + int i; + + /* convert bitmask to bytemask */ + for (i = 0; i < eth_pat_len; i++) + if (eth_pattern->mask[i / 8] & BIT(i % 8)) + eth_bytemask[i] = 0xff; + + if (eth_pkt_ofs < ETH_ALEN) { + pkt_ofs = eth_pkt_ofs + a1_ofs; + + if (eth_pkt_ofs + eth_pat_len < ETH_ALEN) { + memcpy(pat, eth_pat, eth_pat_len); + memcpy(bytemask, eth_bytemask, eth_pat_len); + + pat_len = eth_pat_len; + } else if (eth_pkt_ofs + eth_pat_len < prot_ofs) { + memcpy(pat, eth_pat, ETH_ALEN - eth_pkt_ofs); + memcpy(bytemask, eth_bytemask, ETH_ALEN - eth_pkt_ofs); + + delta = eth_pkt_ofs + eth_pat_len - src_ofs; + memcpy(pat + a3_ofs - pkt_ofs, + eth_pat + ETH_ALEN - eth_pkt_ofs, + delta); + memcpy(bytemask + a3_ofs - pkt_ofs, + eth_bytemask + ETH_ALEN - eth_pkt_ofs, + delta); + + pat_len = a3_ofs - pkt_ofs + delta; + } else { + memcpy(pat, eth_pat, ETH_ALEN - eth_pkt_ofs); + memcpy(bytemask, eth_bytemask, ETH_ALEN - eth_pkt_ofs); + + memcpy(pat + a3_ofs - pkt_ofs, + eth_pat + ETH_ALEN - eth_pkt_ofs, + ETH_ALEN); + memcpy(bytemask + a3_ofs - pkt_ofs, + eth_bytemask + ETH_ALEN - eth_pkt_ofs, + ETH_ALEN); + + delta = eth_pkt_ofs + eth_pat_len - prot_ofs; + memcpy(pat + i80211_hdr_len + r1042_eth_ofs - pkt_ofs, + eth_pat + prot_ofs - eth_pkt_ofs, + delta); + memcpy(bytemask + i80211_hdr_len + r1042_eth_ofs - pkt_ofs, + eth_bytemask + prot_ofs - eth_pkt_ofs, + delta); + + pat_len = i80211_hdr_len + r1042_eth_ofs - pkt_ofs + delta; + } + } else if (eth_pkt_ofs < prot_ofs) { + pkt_ofs = eth_pkt_ofs - ETH_ALEN + a3_ofs; + + if (eth_pkt_ofs + eth_pat_len < prot_ofs) { + memcpy(pat, eth_pat, eth_pat_len); + memcpy(bytemask, eth_bytemask, eth_pat_len); + + pat_len = eth_pat_len; + } else { + memcpy(pat, eth_pat, prot_ofs - eth_pkt_ofs); + memcpy(bytemask, eth_bytemask, prot_ofs - eth_pkt_ofs); + + delta = eth_pkt_ofs + eth_pat_len - prot_ofs; + memcpy(pat + i80211_hdr_len + r1042_eth_ofs - pkt_ofs, + eth_pat + prot_ofs - eth_pkt_ofs, + delta); + memcpy(bytemask + i80211_hdr_len + r1042_eth_ofs - pkt_ofs, + eth_bytemask + prot_ofs - eth_pkt_ofs, + delta); + + pat_len = i80211_hdr_len + r1042_eth_ofs - pkt_ofs + delta; + } + } else { + pkt_ofs = eth_pkt_ofs - prot_ofs + i80211_hdr_len + r1042_eth_ofs; + + memcpy(pat, eth_pat, eth_pat_len); + memcpy(bytemask, eth_bytemask, eth_pat_len); + + pat_len = eth_pat_len; + } + + i80211_pattern->pattern_len = pat_len; + i80211_pattern->pkt_offset = pkt_ofs; +} + +static int ath12k_vif_wow_set_wakeups(struct ath12k_vif *arvif, + struct cfg80211_wowlan *wowlan) +{ + const struct cfg80211_pkt_pattern *patterns = wowlan->patterns; + struct ath12k *ar = arvif->ar; + unsigned long wow_mask = 0; + int pattern_id = 0; + int ret, i; + + /* Setup requested WOW features */ + switch (arvif->vdev_type) { + case WMI_VDEV_TYPE_IBSS: + __set_bit(WOW_BEACON_EVENT, &wow_mask); + fallthrough; + case WMI_VDEV_TYPE_AP: + __set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask); + __set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask); + __set_bit(WOW_PROBE_REQ_WPS_IE_EVENT, &wow_mask); + __set_bit(WOW_AUTH_REQ_EVENT, &wow_mask); + __set_bit(WOW_ASSOC_REQ_EVENT, &wow_mask); + __set_bit(WOW_HTT_EVENT, &wow_mask); + __set_bit(WOW_RA_MATCH_EVENT, &wow_mask); + break; + case WMI_VDEV_TYPE_STA: + if (wowlan->disconnect) { + __set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask); + __set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask); + __set_bit(WOW_BMISS_EVENT, &wow_mask); + __set_bit(WOW_CSA_IE_EVENT, &wow_mask); + } + + if (wowlan->magic_pkt) + __set_bit(WOW_MAGIC_PKT_RECVD_EVENT, &wow_mask); + break; + default: + break; + } + + for (i = 0; i < wowlan->n_patterns; i++) { + const struct cfg80211_pkt_pattern *eth_pattern = &patterns[i]; + struct ath12k_pkt_pattern new_pattern = {}; + + if (WARN_ON(eth_pattern->pattern_len > WOW_MAX_PATTERN_SIZE)) + return -EINVAL; + + if (ar->ab->wow.wmi_conf_rx_decap_mode == + ATH12K_HW_TXRX_NATIVE_WIFI) { + ath12k_wow_convert_8023_to_80211(ar, eth_pattern, + &new_pattern); + + if (WARN_ON(new_pattern.pattern_len > WOW_MAX_PATTERN_SIZE)) + return -EINVAL; + } else { + memcpy(new_pattern.pattern, eth_pattern->pattern, + eth_pattern->pattern_len); + + /* convert bitmask to bytemask */ + for (i = 0; i < eth_pattern->pattern_len; i++) + if (eth_pattern->mask[i / 8] & BIT(i % 8)) + new_pattern.bytemask[i] = 0xff; + + new_pattern.pattern_len = eth_pattern->pattern_len; + new_pattern.pkt_offset = eth_pattern->pkt_offset; + } + + ret = ath12k_wmi_wow_add_pattern(ar, arvif->vdev_id, + pattern_id, + new_pattern.pattern, + new_pattern.bytemask, + new_pattern.pattern_len, + new_pattern.pkt_offset); + if (ret) { + ath12k_warn(ar->ab, "failed to add pattern %i to vdev %i: %d\n", + pattern_id, + arvif->vdev_id, ret); + return ret; + } + + pattern_id++; + __set_bit(WOW_PATTERN_MATCH_EVENT, &wow_mask); + } + + for (i = 0; i < WOW_EVENT_MAX; i++) { + if (!test_bit(i, &wow_mask)) + continue; + ret = ath12k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 1); + if (ret) { + ath12k_warn(ar->ab, "failed to enable wakeup event %s on vdev %i: %d\n", + wow_wakeup_event(i), arvif->vdev_id, ret); + return ret; + } + } + + return 0; +} + +static int ath12k_wow_set_wakeups(struct ath12k *ar, + struct cfg80211_wowlan *wowlan) +{ + struct ath12k_vif *arvif; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + list_for_each_entry(arvif, &ar->arvifs, list) { + ret = ath12k_vif_wow_set_wakeups(arvif, wowlan); + if (ret) { + ath12k_warn(ar->ab, "failed to set wow wakeups on vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + } + + return 0; +} + +int ath12k_wow_op_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan) +{ + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar = ath12k_ah_to_ar(ah, 0); + int ret; + + mutex_lock(&ar->conf_mutex); + + ret = ath12k_wow_cleanup(ar); + if (ret) { + ath12k_warn(ar->ab, "failed to clear wow wakeup events: %d\n", + ret); + goto exit; + } + + ret = ath12k_wow_set_wakeups(ar, wowlan); + if (ret) { + ath12k_warn(ar->ab, "failed to set wow wakeup events: %d\n", + ret); + goto cleanup; + } + + ret = ath12k_mac_wait_tx_complete(ar); + if (ret) { + ath12k_warn(ar->ab, "failed to wait tx complete: %d\n", ret); + goto cleanup; + } + + ret = ath12k_wow_enable(ar); + if (ret) { + ath12k_warn(ar->ab, "failed to start wow: %d\n", ret); + goto cleanup; + } + + ath12k_hif_irq_disable(ar->ab); + ath12k_hif_ce_irq_disable(ar->ab); + + ret = ath12k_hif_suspend(ar->ab); + if (ret) { + ath12k_warn(ar->ab, "failed to suspend hif: %d\n", ret); + goto wakeup; + } + + goto exit; + +wakeup: + ath12k_wow_wakeup(ar); + +cleanup: + ath12k_wow_cleanup(ar); + +exit: + mutex_unlock(&ar->conf_mutex); + return ret ? 1 : 0; +} + +void ath12k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled) +{ + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar = ath12k_ah_to_ar(ah, 0); + + mutex_lock(&ar->conf_mutex); + device_set_wakeup_enable(ar->ab->dev, enabled); + mutex_unlock(&ar->conf_mutex); +} + +int ath12k_wow_op_resume(struct ieee80211_hw *hw) +{ + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar = ath12k_ah_to_ar(ah, 0); + int ret; + + mutex_lock(&ar->conf_mutex); + + ret = ath12k_hif_resume(ar->ab); + if (ret) { + ath12k_warn(ar->ab, "failed to resume hif: %d\n", ret); + goto exit; + } + + ath12k_hif_ce_irq_enable(ar->ab); + ath12k_hif_irq_enable(ar->ab); + + ret = ath12k_wow_wakeup(ar); + if (ret) + ath12k_warn(ar->ab, "failed to wakeup from wow: %d\n", ret); + +exit: + if (ret) { + switch (ah->state) { + case ATH12K_HW_STATE_ON: + ah->state = ATH12K_HW_STATE_RESTARTING; + ret = 1; + break; + case ATH12K_HW_STATE_OFF: + case ATH12K_HW_STATE_RESTARTING: + case ATH12K_HW_STATE_RESTARTED: + case ATH12K_HW_STATE_WEDGED: + ath12k_warn(ar->ab, "encountered unexpected device state %d on resume, cannot recover\n", + ah->state); + ret = -EIO; + break; + } + } + + mutex_unlock(&ar->conf_mutex); + return ret; +} + +int ath12k_wow_init(struct ath12k *ar) +{ + if (WARN_ON(!test_bit(WMI_TLV_SERVICE_WOW, ar->wmi->wmi_ab->svc_map))) + return -EINVAL; + + ar->wow.wowlan_support = ath12k_wowlan_support; + + if (ar->ab->wow.wmi_conf_rx_decap_mode == ATH12K_HW_TXRX_NATIVE_WIFI) { + ar->wow.wowlan_support.pattern_max_len -= WOW_MAX_REDUCE; + ar->wow.wowlan_support.max_pkt_offset -= WOW_MAX_REDUCE; + } + + ar->wow.max_num_patterns = ATH12K_WOW_PATTERNS; + ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns; + ar->ah->hw->wiphy->wowlan = &ar->wow.wowlan_support; + + device_set_wakeup_capable(ar->ab->dev, true); + + return 0; +} diff --git a/drivers/net/wireless/ath/ath12k/wow.h b/drivers/net/wireless/ath/ath12k/wow.h index 6817ceaa4cfe..af9be5fadcc3 100644 --- a/drivers/net/wireless/ath/ath12k/wow.h +++ b/drivers/net/wireless/ath/ath12k/wow.h @@ -9,14 +9,46 @@ #define ATH12K_WOW_RETRY_NUM 10 #define ATH12K_WOW_RETRY_WAIT_MS 200 +#define ATH12K_WOW_PATTERNS 22 + +struct ath12k_wow { + u32 max_num_patterns; + struct completion wakeup_completed; + struct wiphy_wowlan_support wowlan_support; +}; + +struct ath12k_pkt_pattern { + u8 pattern[WOW_MAX_PATTERN_SIZE]; + u8 bytemask[WOW_MAX_PATTERN_SIZE]; + int pattern_len; + int pkt_offset; +}; + +struct rfc1042_hdr { + u8 llc_dsap; + u8 llc_ssap; + u8 llc_ctrl; + u8 snap_oui[3]; + __be16 eth_type; +} __packed; #ifdef CONFIG_PM +int ath12k_wow_init(struct ath12k *ar); +int ath12k_wow_op_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan); +int ath12k_wow_op_resume(struct ieee80211_hw *hw); +void ath12k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled); int ath12k_wow_enable(struct ath12k *ar); int ath12k_wow_wakeup(struct ath12k *ar); #else +static inline int ath12k_wow_init(struct ath12k *ar) +{ + return 0; +} + static inline int ath12k_wow_enable(struct ath12k *ar) { return 0; From 16f474d6d49db5d93e79c2d4bdcc3a730cf1d1f1 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 4 Jun 2024 13:54:03 +0800 Subject: [PATCH 033/204] wifi: ath12k: add WoW net-detect functionality Implement net-detect feature by setting flag WIPHY_WOWLAN_NET_DETECT if firmware supports this feature. Driver sets the related PNO configuration to firmware before entering WoW and firmware then scans periodically and wakes up host if a specific SSID is found. Note that firmware crashes if we enable it for both P2P vdev and station vdev simultaneously because firmware can only support one vdev at a time. Since there is rare scenario for a P2P vdev to do net-detect, skip it for P2P vdevs. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240604055407.12506-5-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/core.h | 2 + drivers/net/wireless/ath/ath12k/mac.c | 12 ++ drivers/net/wireless/ath/ath12k/wmi.c | 145 ++++++++++++++++++ drivers/net/wireless/ath/ath12k/wmi.h | 166 ++++++++++++++++++++ drivers/net/wireless/ath/ath12k/wow.c | 202 ++++++++++++++++++++++++- 5 files changed, 524 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 2fd08648cef3..81c4bfe7792f 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -630,6 +630,8 @@ struct ath12k { u32 freq_low; u32 freq_high; + + bool nlo_enabled; }; struct ath12k_hw { diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 59662ca241ca..cd8fb3797eea 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -9108,6 +9108,18 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); } + if (test_bit(WMI_TLV_SERVICE_NLO, ar->wmi->wmi_ab->svc_map)) { + wiphy->max_sched_scan_ssids = WMI_PNO_MAX_SUPP_NETWORKS; + wiphy->max_match_sets = WMI_PNO_MAX_SUPP_NETWORKS; + wiphy->max_sched_scan_ie_len = WMI_PNO_MAX_IE_LENGTH; + wiphy->max_sched_scan_plans = WMI_PNO_MAX_SCHED_SCAN_PLANS; + wiphy->max_sched_scan_plan_interval = + WMI_PNO_MAX_SCHED_SCAN_PLAN_INT; + wiphy->max_sched_scan_plan_iterations = + WMI_PNO_MAX_SCHED_SCAN_PLAN_ITRNS; + wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR; + } + ret = ath12k_wow_init(ar); if (ret) { ath12k_warn(ar->ab, "failed to init wow: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index f72ec153723c..b69f20495ab4 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -7607,3 +7607,148 @@ int ath12k_wmi_wow_del_pattern(struct ath12k *ar, u32 vdev_id, u32 pattern_id) return ath12k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_DEL_WAKE_PATTERN_CMDID); } + +static struct sk_buff * +ath12k_wmi_op_gen_config_pno_start(struct ath12k *ar, u32 vdev_id, + struct wmi_pno_scan_req_arg *pno) +{ + struct nlo_configured_params *nlo_list; + size_t len, nlo_list_len, channel_list_len; + struct wmi_wow_nlo_config_cmd *cmd; + __le32 *channel_list; + struct wmi_tlv *tlv; + struct sk_buff *skb; + void *ptr; + u32 i; + + len = sizeof(*cmd) + + sizeof(*tlv) + + /* TLV place holder for array of structures + * nlo_configured_params(nlo_list) + */ + sizeof(*tlv); + /* TLV place holder for array of uint32 channel_list */ + + channel_list_len = sizeof(u32) * pno->a_networks[0].channel_count; + len += channel_list_len; + + nlo_list_len = sizeof(*nlo_list) * pno->uc_networks_count; + len += nlo_list_len; + + skb = ath12k_wmi_alloc_skb(ar->wmi->wmi_ab, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = skb->data; + cmd = ptr; + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_NLO_CONFIG_CMD, sizeof(*cmd)); + + cmd->vdev_id = cpu_to_le32(pno->vdev_id); + cmd->flags = cpu_to_le32(WMI_NLO_CONFIG_START | WMI_NLO_CONFIG_SSID_HIDE_EN); + + /* current FW does not support min-max range for dwell time */ + cmd->active_dwell_time = cpu_to_le32(pno->active_max_time); + cmd->passive_dwell_time = cpu_to_le32(pno->passive_max_time); + + if (pno->do_passive_scan) + cmd->flags |= cpu_to_le32(WMI_NLO_CONFIG_SCAN_PASSIVE); + + cmd->fast_scan_period = cpu_to_le32(pno->fast_scan_period); + cmd->slow_scan_period = cpu_to_le32(pno->slow_scan_period); + cmd->fast_scan_max_cycles = cpu_to_le32(pno->fast_scan_max_cycles); + cmd->delay_start_time = cpu_to_le32(pno->delay_start_time); + + if (pno->enable_pno_scan_randomization) { + cmd->flags |= cpu_to_le32(WMI_NLO_CONFIG_SPOOFED_MAC_IN_PROBE_REQ | + WMI_NLO_CONFIG_RANDOM_SEQ_NO_IN_PROBE_REQ); + ether_addr_copy(cmd->mac_addr.addr, pno->mac_addr); + ether_addr_copy(cmd->mac_mask.addr, pno->mac_addr_mask); + } + + ptr += sizeof(*cmd); + + /* nlo_configured_params(nlo_list) */ + cmd->no_of_ssids = cpu_to_le32(pno->uc_networks_count); + tlv = ptr; + tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, nlo_list_len); + + ptr += sizeof(*tlv); + nlo_list = ptr; + for (i = 0; i < pno->uc_networks_count; i++) { + tlv = (struct wmi_tlv *)(&nlo_list[i].tlv_header); + tlv->header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_ARRAY_BYTE, + sizeof(*nlo_list)); + + nlo_list[i].ssid.valid = cpu_to_le32(1); + nlo_list[i].ssid.ssid.ssid_len = + cpu_to_le32(pno->a_networks[i].ssid.ssid_len); + memcpy(nlo_list[i].ssid.ssid.ssid, + pno->a_networks[i].ssid.ssid, + le32_to_cpu(nlo_list[i].ssid.ssid.ssid_len)); + + if (pno->a_networks[i].rssi_threshold && + pno->a_networks[i].rssi_threshold > -300) { + nlo_list[i].rssi_cond.valid = cpu_to_le32(1); + nlo_list[i].rssi_cond.rssi = + cpu_to_le32(pno->a_networks[i].rssi_threshold); + } + + nlo_list[i].bcast_nw_type.valid = cpu_to_le32(1); + nlo_list[i].bcast_nw_type.bcast_nw_type = + cpu_to_le32(pno->a_networks[i].bcast_nw_type); + } + + ptr += nlo_list_len; + cmd->num_of_channels = cpu_to_le32(pno->a_networks[0].channel_count); + tlv = ptr; + tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, channel_list_len); + ptr += sizeof(*tlv); + channel_list = ptr; + + for (i = 0; i < pno->a_networks[0].channel_count; i++) + channel_list[i] = cpu_to_le32(pno->a_networks[0].channels[i]); + + ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "wmi tlv start pno config vdev_id %d\n", + vdev_id); + + return skb; +} + +static struct sk_buff *ath12k_wmi_op_gen_config_pno_stop(struct ath12k *ar, + u32 vdev_id) +{ + struct wmi_wow_nlo_config_cmd *cmd; + struct sk_buff *skb; + size_t len; + + len = sizeof(*cmd); + skb = ath12k_wmi_alloc_skb(ar->wmi->wmi_ab, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + cmd = (struct wmi_wow_nlo_config_cmd *)skb->data; + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_NLO_CONFIG_CMD, len); + + cmd->vdev_id = cpu_to_le32(vdev_id); + cmd->flags = cpu_to_le32(WMI_NLO_CONFIG_STOP); + + ath12k_dbg(ar->ab, ATH12K_DBG_WMI, + "wmi tlv stop pno config vdev_id %d\n", vdev_id); + return skb; +} + +int ath12k_wmi_wow_config_pno(struct ath12k *ar, u32 vdev_id, + struct wmi_pno_scan_req_arg *pno_scan) +{ + struct sk_buff *skb; + + if (pno_scan->enable) + skb = ath12k_wmi_op_gen_config_pno_start(ar, vdev_id, pno_scan); + else + skb = ath12k_wmi_op_gen_config_pno_stop(ar, vdev_id); + + if (IS_ERR_OR_NULL(skb)) + return -ENOMEM; + + return ath12k_wmi_cmd_send(ar->wmi, skb, WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID); +} diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 6cb06f6f7df4..0842ab760f2b 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -5130,6 +5130,170 @@ struct wmi_wow_ev_arg { enum wmi_wow_wake_reason wake_reason; }; +#define WMI_PNO_MAX_SCHED_SCAN_PLANS 2 +#define WMI_PNO_MAX_SCHED_SCAN_PLAN_INT 7200 +#define WMI_PNO_MAX_SCHED_SCAN_PLAN_ITRNS 100 +#define WMI_PNO_MAX_NETW_CHANNELS 26 +#define WMI_PNO_MAX_NETW_CHANNELS_EX 60 +#define WMI_PNO_MAX_SUPP_NETWORKS WLAN_SCAN_PARAMS_MAX_SSID +#define WMI_PNO_MAX_IE_LENGTH WLAN_SCAN_PARAMS_MAX_IE_LEN + +/* size based of dot11 declaration without extra IEs as we will not carry those for PNO */ +#define WMI_PNO_MAX_PB_REQ_SIZE 450 + +#define WMI_PNO_24GHZ_DEFAULT_CH 1 +#define WMI_PNO_5GHZ_DEFAULT_CH 36 + +#define WMI_ACTIVE_MAX_CHANNEL_TIME 40 +#define WMI_PASSIVE_MAX_CHANNEL_TIME 110 + +/* SSID broadcast type */ +enum wmi_ssid_bcast_type { + BCAST_UNKNOWN = 0, + BCAST_NORMAL = 1, + BCAST_HIDDEN = 2, +}; + +#define WMI_NLO_MAX_SSIDS 16 +#define WMI_NLO_MAX_CHAN 48 + +#define WMI_NLO_CONFIG_STOP BIT(0) +#define WMI_NLO_CONFIG_START BIT(1) +#define WMI_NLO_CONFIG_RESET BIT(2) +#define WMI_NLO_CONFIG_SLOW_SCAN BIT(4) +#define WMI_NLO_CONFIG_FAST_SCAN BIT(5) +#define WMI_NLO_CONFIG_SSID_HIDE_EN BIT(6) + +/* This bit is used to indicate if EPNO or supplicant PNO is enabled. + * Only one of them can be enabled at a given time + */ +#define WMI_NLO_CONFIG_ENLO BIT(7) +#define WMI_NLO_CONFIG_SCAN_PASSIVE BIT(8) +#define WMI_NLO_CONFIG_ENLO_RESET BIT(9) +#define WMI_NLO_CONFIG_SPOOFED_MAC_IN_PROBE_REQ BIT(10) +#define WMI_NLO_CONFIG_RANDOM_SEQ_NO_IN_PROBE_REQ BIT(11) +#define WMI_NLO_CONFIG_ENABLE_IE_WHITELIST_IN_PROBE_REQ BIT(12) +#define WMI_NLO_CONFIG_ENABLE_CNLO_RSSI_CONFIG BIT(13) + +struct wmi_nlo_ssid_params { + __le32 valid; + struct ath12k_wmi_ssid_params ssid; +} __packed; + +struct wmi_nlo_enc_params { + __le32 valid; + __le32 enc_type; +} __packed; + +struct wmi_nlo_auth_params { + __le32 valid; + __le32 auth_type; +} __packed; + +struct wmi_nlo_bcast_nw_params { + __le32 valid; + __le32 bcast_nw_type; +} __packed; + +struct wmi_nlo_rssi_params { + __le32 valid; + __le32 rssi; +} __packed; + +struct nlo_configured_params { + /* TLV tag and len;*/ + __le32 tlv_header; + struct wmi_nlo_ssid_params ssid; + struct wmi_nlo_enc_params enc_type; + struct wmi_nlo_auth_params auth_type; + struct wmi_nlo_rssi_params rssi_cond; + + /* indicates if the SSID is hidden or not */ + struct wmi_nlo_bcast_nw_params bcast_nw_type; +} __packed; + +struct wmi_network_type_arg { + struct cfg80211_ssid ssid; + u32 authentication; + u32 encryption; + u32 bcast_nw_type; + u8 channel_count; + u16 channels[WMI_PNO_MAX_NETW_CHANNELS_EX]; + s32 rssi_threshold; +}; + +struct wmi_pno_scan_req_arg { + u8 enable; + u8 vdev_id; + u8 uc_networks_count; + struct wmi_network_type_arg a_networks[WMI_PNO_MAX_SUPP_NETWORKS]; + u32 fast_scan_period; + u32 slow_scan_period; + u8 fast_scan_max_cycles; + + bool do_passive_scan; + + u32 delay_start_time; + u32 active_min_time; + u32 active_max_time; + u32 passive_min_time; + u32 passive_max_time; + + /* mac address randomization attributes */ + u32 enable_pno_scan_randomization; + u8 mac_addr[ETH_ALEN]; + u8 mac_addr_mask[ETH_ALEN]; +}; + +struct wmi_wow_nlo_config_cmd { + __le32 tlv_header; + __le32 flags; + __le32 vdev_id; + __le32 fast_scan_max_cycles; + __le32 active_dwell_time; + __le32 passive_dwell_time; + __le32 probe_bundle_size; + + /* ART = IRT */ + __le32 rest_time; + + /* max value that can be reached after scan_backoff_multiplier */ + __le32 max_rest_time; + + __le32 scan_backoff_multiplier; + __le32 fast_scan_period; + + /* specific to windows */ + __le32 slow_scan_period; + + __le32 no_of_ssids; + + __le32 num_of_channels; + + /* NLO scan start delay time in milliseconds */ + __le32 delay_start_time; + + /* MAC Address to use in Probe Req as SA */ + struct ath12k_wmi_mac_addr_params mac_addr; + + /* Mask on which MAC has to be randomized */ + struct ath12k_wmi_mac_addr_params mac_mask; + + /* IE bitmap to use in Probe Req */ + __le32 ie_bitmap[8]; + + /* Number of vendor OUIs. In the TLV vendor_oui[] */ + __le32 num_vendor_oui; + + /* Number of connected NLO band preferences */ + __le32 num_cnlo_band_pref; + + /* The TLVs will follow. + * nlo_configured_params nlo_list[]; + * u32 channel_list[num_of_channels]; + */ +} __packed; + void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, struct ath12k_wmi_resource_config_arg *config); void ath12k_wmi_init_wcn7850(struct ath12k_base *ab, @@ -5291,4 +5455,6 @@ int ath12k_wmi_wow_add_pattern(struct ath12k *ar, u32 vdev_id, u32 pattern_id, int ath12k_wmi_wow_add_wakeup_event(struct ath12k *ar, u32 vdev_id, enum wmi_wow_wakeup_event event, u32 enable); +int ath12k_wmi_wow_config_pno(struct ath12k *ar, u32 vdev_id, + struct wmi_pno_scan_req_arg *pno_scan); #endif diff --git a/drivers/net/wireless/ath/ath12k/wow.c b/drivers/net/wireless/ath/ath12k/wow.c index 648e7cb970ea..5d4f11028403 100644 --- a/drivers/net/wireless/ath/ath12k/wow.c +++ b/drivers/net/wireless/ath/ath12k/wow.c @@ -23,6 +23,13 @@ static const struct wiphy_wowlan_support ath12k_wowlan_support = { .max_pkt_offset = WOW_MAX_PKT_OFFSET, }; +static inline bool ath12k_wow_is_p2p_vdev(struct ath12k_vif *arvif) +{ + return (arvif->vdev_subtype == WMI_VDEV_SUBTYPE_P2P_DEVICE || + arvif->vdev_subtype == WMI_VDEV_SUBTYPE_P2P_CLIENT || + arvif->vdev_subtype == WMI_VDEV_SUBTYPE_P2P_GO); +} + int ath12k_wow_enable(struct ath12k *ar) { struct ath12k_base *ab = ar->ab; @@ -247,7 +254,101 @@ ath12k_wow_convert_8023_to_80211(struct ath12k *ar, i80211_pattern->pkt_offset = pkt_ofs; } -static int ath12k_vif_wow_set_wakeups(struct ath12k_vif *arvif, +static int +ath12k_wow_pno_check_and_convert(struct ath12k *ar, u32 vdev_id, + const struct cfg80211_sched_scan_request *nd_config, + struct wmi_pno_scan_req_arg *pno) +{ + int i, j; + u8 ssid_len; + + pno->enable = 1; + pno->vdev_id = vdev_id; + pno->uc_networks_count = nd_config->n_match_sets; + + if (!pno->uc_networks_count || + pno->uc_networks_count > WMI_PNO_MAX_SUPP_NETWORKS) + return -EINVAL; + + if (nd_config->n_channels > WMI_PNO_MAX_NETW_CHANNELS_EX) + return -EINVAL; + + /* Filling per profile params */ + for (i = 0; i < pno->uc_networks_count; i++) { + ssid_len = nd_config->match_sets[i].ssid.ssid_len; + + if (ssid_len == 0 || ssid_len > 32) + return -EINVAL; + + pno->a_networks[i].ssid.ssid_len = ssid_len; + + memcpy(pno->a_networks[i].ssid.ssid, + nd_config->match_sets[i].ssid.ssid, + ssid_len); + pno->a_networks[i].authentication = 0; + pno->a_networks[i].encryption = 0; + pno->a_networks[i].bcast_nw_type = 0; + + /* Copying list of valid channel into request */ + pno->a_networks[i].channel_count = nd_config->n_channels; + pno->a_networks[i].rssi_threshold = nd_config->match_sets[i].rssi_thold; + + for (j = 0; j < nd_config->n_channels; j++) { + pno->a_networks[i].channels[j] = + nd_config->channels[j]->center_freq; + } + } + + /* set scan to passive if no SSIDs are specified in the request */ + if (nd_config->n_ssids == 0) + pno->do_passive_scan = true; + else + pno->do_passive_scan = false; + + for (i = 0; i < nd_config->n_ssids; i++) { + for (j = 0; j < pno->uc_networks_count; j++) { + if (pno->a_networks[j].ssid.ssid_len == + nd_config->ssids[i].ssid_len && + !memcmp(pno->a_networks[j].ssid.ssid, + nd_config->ssids[i].ssid, + pno->a_networks[j].ssid.ssid_len)) { + pno->a_networks[j].bcast_nw_type = BCAST_HIDDEN; + break; + } + } + } + + if (nd_config->n_scan_plans == 2) { + pno->fast_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC; + pno->fast_scan_max_cycles = nd_config->scan_plans[0].iterations; + pno->slow_scan_period = + nd_config->scan_plans[1].interval * MSEC_PER_SEC; + } else if (nd_config->n_scan_plans == 1) { + pno->fast_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC; + pno->fast_scan_max_cycles = 1; + pno->slow_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC; + } else { + ath12k_warn(ar->ab, "Invalid number of PNO scan plans: %d", + nd_config->n_scan_plans); + } + + if (nd_config->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { + /* enable mac randomization */ + pno->enable_pno_scan_randomization = 1; + memcpy(pno->mac_addr, nd_config->mac_addr, ETH_ALEN); + memcpy(pno->mac_addr_mask, nd_config->mac_addr_mask, ETH_ALEN); + } + + pno->delay_start_time = nd_config->delay; + + /* Current FW does not support min-max range for dwell time */ + pno->active_max_time = WMI_ACTIVE_MAX_CHANNEL_TIME; + pno->passive_max_time = WMI_PASSIVE_MAX_CHANNEL_TIME; + + return 0; +} + +static int ath12k_wow_vif_set_wakeups(struct ath12k_vif *arvif, struct cfg80211_wowlan *wowlan) { const struct cfg80211_pkt_pattern *patterns = wowlan->patterns; @@ -280,6 +381,26 @@ static int ath12k_vif_wow_set_wakeups(struct ath12k_vif *arvif, if (wowlan->magic_pkt) __set_bit(WOW_MAGIC_PKT_RECVD_EVENT, &wow_mask); + + if (wowlan->nd_config) { + struct wmi_pno_scan_req_arg *pno; + int ret; + + pno = kzalloc(sizeof(*pno), GFP_KERNEL); + if (!pno) + return -ENOMEM; + + ar->nlo_enabled = true; + + ret = ath12k_wow_pno_check_and_convert(ar, arvif->vdev_id, + wowlan->nd_config, pno); + if (!ret) { + ath12k_wmi_wow_config_pno(ar, arvif->vdev_id, pno); + __set_bit(WOW_NLO_DETECTED_EVENT, &wow_mask); + } + + kfree(pno); + } break; default: break; @@ -352,7 +473,9 @@ static int ath12k_wow_set_wakeups(struct ath12k *ar, lockdep_assert_held(&ar->conf_mutex); list_for_each_entry(arvif, &ar->arvifs, list) { - ret = ath12k_vif_wow_set_wakeups(arvif, wowlan); + if (ath12k_wow_is_p2p_vdev(arvif)) + continue; + ret = ath12k_wow_vif_set_wakeups(arvif, wowlan); if (ret) { ath12k_warn(ar->ab, "failed to set wow wakeups on vdev %i: %d\n", arvif->vdev_id, ret); @@ -363,6 +486,66 @@ static int ath12k_wow_set_wakeups(struct ath12k *ar, return 0; } +static int ath12k_wow_vdev_clean_nlo(struct ath12k *ar, u32 vdev_id) +{ + struct wmi_pno_scan_req_arg *pno; + int ret; + + if (!ar->nlo_enabled) + return 0; + + pno = kzalloc(sizeof(*pno), GFP_KERNEL); + if (!pno) + return -ENOMEM; + + pno->enable = 0; + ret = ath12k_wmi_wow_config_pno(ar, vdev_id, pno); + if (ret) { + ath12k_warn(ar->ab, "failed to disable PNO: %d", ret); + goto out; + } + + ar->nlo_enabled = false; + +out: + kfree(pno); + return ret; +} + +static int ath12k_wow_vif_clean_nlo(struct ath12k_vif *arvif) +{ + struct ath12k *ar = arvif->ar; + + switch (arvif->vdev_type) { + case WMI_VDEV_TYPE_STA: + return ath12k_wow_vdev_clean_nlo(ar, arvif->vdev_id); + default: + return 0; + } +} + +static int ath12k_wow_nlo_cleanup(struct ath12k *ar) +{ + struct ath12k_vif *arvif; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + list_for_each_entry(arvif, &ar->arvifs, list) { + if (ath12k_wow_is_p2p_vdev(arvif)) + continue; + + ret = ath12k_wow_vif_clean_nlo(arvif); + if (ret) { + ath12k_warn(ar->ab, "failed to clean nlo settings on vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + } + + return 0; +} + int ath12k_wow_op_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { @@ -448,8 +631,16 @@ int ath12k_wow_op_resume(struct ieee80211_hw *hw) ath12k_hif_irq_enable(ar->ab); ret = ath12k_wow_wakeup(ar); - if (ret) + if (ret) { ath12k_warn(ar->ab, "failed to wakeup from wow: %d\n", ret); + goto exit; + } + + ret = ath12k_wow_nlo_cleanup(ar); + if (ret) { + ath12k_warn(ar->ab, "failed to cleanup nlo: %d\n", ret); + goto exit; + } exit: if (ret) { @@ -485,6 +676,11 @@ int ath12k_wow_init(struct ath12k *ar) ar->wow.wowlan_support.max_pkt_offset -= WOW_MAX_REDUCE; } + if (test_bit(WMI_TLV_SERVICE_NLO, ar->wmi->wmi_ab->svc_map)) { + ar->wow.wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT; + ar->wow.wowlan_support.max_nd_match_sets = WMI_PNO_MAX_SUPP_NETWORKS; + } + ar->wow.max_num_patterns = ATH12K_WOW_PATTERNS; ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns; ar->ah->hw->wiphy->wowlan = &ar->wow.wowlan_support; From 66a9448b1b897793a3237f832b5ce3bb255e28e7 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Wed, 19 Jun 2024 17:21:12 +0300 Subject: [PATCH 034/204] wifi: ath12k: implement hardware data filter Host needs to set hardware data filter before entering WoW to let firmware drop needless broadcast/multicast frames to avoid frequent wakeup. Host clears hardware data filter when leaving WoW. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240604055407.12506-6-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.c | 31 +++++++++++++ drivers/net/wireless/ath/ath12k/wmi.h | 21 +++++++++ drivers/net/wireless/ath/ath12k/wow.c | 66 +++++++++++++++++++++++++++ 3 files changed, 118 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index b69f20495ab4..b1f343efa4b0 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -7424,6 +7424,37 @@ void ath12k_wmi_detach(struct ath12k_base *ab) ath12k_wmi_free_dbring_caps(ab); } +int ath12k_wmi_hw_data_filter_cmd(struct ath12k *ar, struct wmi_hw_data_filter_arg *arg) +{ + struct wmi_hw_data_filter_cmd *cmd; + struct sk_buff *skb; + int len; + + len = sizeof(*cmd); + skb = ath12k_wmi_alloc_skb(ar->wmi->wmi_ab, len); + + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_hw_data_filter_cmd *)skb->data; + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_HW_DATA_FILTER_CMD, + sizeof(*cmd)); + cmd->vdev_id = cpu_to_le32(arg->vdev_id); + cmd->enable = cpu_to_le32(arg->enable ? 1 : 0); + + /* Set all modes in case of disable */ + if (arg->enable) + cmd->hw_filter_bitmap = cpu_to_le32(arg->hw_filter_bitmap); + else + cmd->hw_filter_bitmap = cpu_to_le32((u32)~0U); + + ath12k_dbg(ar->ab, ATH12K_DBG_WMI, + "wmi hw data filter enable %d filter_bitmap 0x%x\n", + arg->enable, arg->hw_filter_bitmap); + + return ath12k_wmi_cmd_send(ar->wmi, skb, WMI_HW_DATA_FILTER_CMDID); +} + int ath12k_wmi_wow_host_wakeup_ind(struct ath12k *ar) { struct wmi_wow_host_wakeup_cmd *cmd; diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 0842ab760f2b..62d7bb9e791d 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -5294,6 +5294,25 @@ struct wmi_wow_nlo_config_cmd { */ } __packed; +/* Definition of HW data filtering */ +enum hw_data_filter_type { + WMI_HW_DATA_FILTER_DROP_NON_ARP_BC = BIT(0), + WMI_HW_DATA_FILTER_DROP_NON_ICMPV6_MC = BIT(1), +}; + +struct wmi_hw_data_filter_cmd { + __le32 tlv_header; + __le32 vdev_id; + __le32 enable; + __le32 hw_filter_bitmap; +} __packed; + +struct wmi_hw_data_filter_arg { + u32 vdev_id; + bool enable; + u32 hw_filter_bitmap; +}; + 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, @@ -5457,4 +5476,6 @@ int ath12k_wmi_wow_add_wakeup_event(struct ath12k *ar, u32 vdev_id, u32 enable); int ath12k_wmi_wow_config_pno(struct ath12k *ar, u32 vdev_id, struct wmi_pno_scan_req_arg *pno_scan); +int ath12k_wmi_hw_data_filter_cmd(struct ath12k *ar, + struct wmi_hw_data_filter_arg *arg); #endif diff --git a/drivers/net/wireless/ath/ath12k/wow.c b/drivers/net/wireless/ath/ath12k/wow.c index 5d4f11028403..146281244f70 100644 --- a/drivers/net/wireless/ath/ath12k/wow.c +++ b/drivers/net/wireless/ath/ath12k/wow.c @@ -546,6 +546,59 @@ static int ath12k_wow_nlo_cleanup(struct ath12k *ar) return 0; } +static int ath12k_wow_set_hw_filter(struct ath12k *ar) +{ + struct wmi_hw_data_filter_arg arg; + struct ath12k_vif *arvif; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + list_for_each_entry(arvif, &ar->arvifs, list) { + if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + continue; + + arg.vdev_id = arvif->vdev_id; + arg.enable = true; + arg.hw_filter_bitmap = WMI_HW_DATA_FILTER_DROP_NON_ICMPV6_MC; + ret = ath12k_wmi_hw_data_filter_cmd(ar, &arg); + if (ret) { + ath12k_warn(ar->ab, "failed to set hw data filter on vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + } + + return 0; +} + +static int ath12k_wow_clear_hw_filter(struct ath12k *ar) +{ + struct wmi_hw_data_filter_arg arg; + struct ath12k_vif *arvif; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + list_for_each_entry(arvif, &ar->arvifs, list) { + if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + continue; + + arg.vdev_id = arvif->vdev_id; + arg.enable = false; + arg.hw_filter_bitmap = 0; + ret = ath12k_wmi_hw_data_filter_cmd(ar, &arg); + + if (ret) { + ath12k_warn(ar->ab, "failed to clear hw data filter on vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + } + + return 0; +} + int ath12k_wow_op_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { @@ -575,6 +628,13 @@ int ath12k_wow_op_suspend(struct ieee80211_hw *hw, goto cleanup; } + ret = ath12k_wow_set_hw_filter(ar); + if (ret) { + ath12k_warn(ar->ab, "failed to set hw filter: %d\n", + ret); + goto cleanup; + } + ret = ath12k_wow_enable(ar); if (ret) { ath12k_warn(ar->ab, "failed to start wow: %d\n", ret); @@ -642,6 +702,12 @@ int ath12k_wow_op_resume(struct ieee80211_hw *hw) goto exit; } + ret = ath12k_wow_clear_hw_filter(ar); + if (ret) { + ath12k_warn(ar->ab, "failed to clear hw filter: %d\n", ret); + goto exit; + } + exit: if (ret) { switch (ah->state) { From 1666108c74c438180dd69973e57909420836fd49 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Wed, 19 Jun 2024 17:21:12 +0300 Subject: [PATCH 035/204] wifi: ath12k: support ARP and NS offload Support ARP and NS offload in WoW state. Tested this way: put machine A with QCA6390 to WoW state, ping/ping6 machine A from another machine B, check sniffer to see any ARP response and Neighbor Advertisement from machine A. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240604055407.12506-7-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 1 + drivers/net/wireless/ath/ath12k/wmi.c | 148 ++++++++++++++++++++ drivers/net/wireless/ath/ath12k/wmi.h | 66 +++++++++ drivers/net/wireless/ath/ath12k/wow.c | 191 ++++++++++++++++++++++++++ 4 files changed, 406 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index cd8fb3797eea..13186496728b 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -6,6 +6,7 @@ #include #include + #include "mac.h" #include "core.h" #include "debug.h" diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index b1f343efa4b0..8b80d5b6bc01 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -7783,3 +7783,151 @@ int ath12k_wmi_wow_config_pno(struct ath12k *ar, u32 vdev_id, return ath12k_wmi_cmd_send(ar->wmi, skb, WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID); } + +static void ath12k_wmi_fill_ns_offload(struct ath12k *ar, + struct wmi_arp_ns_offload_arg *offload, + void **ptr, + bool enable, + bool ext) +{ + struct wmi_ns_offload_params *ns; + struct wmi_tlv *tlv; + void *buf_ptr = *ptr; + u32 ns_cnt, ns_ext_tuples; + int i, max_offloads; + + ns_cnt = offload->ipv6_count; + + tlv = buf_ptr; + + if (ext) { + ns_ext_tuples = offload->ipv6_count - WMI_MAX_NS_OFFLOADS; + tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, + ns_ext_tuples * sizeof(*ns)); + i = WMI_MAX_NS_OFFLOADS; + max_offloads = offload->ipv6_count; + } else { + tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, + WMI_MAX_NS_OFFLOADS * sizeof(*ns)); + i = 0; + max_offloads = WMI_MAX_NS_OFFLOADS; + } + + buf_ptr += sizeof(*tlv); + + for (; i < max_offloads; i++) { + ns = buf_ptr; + ns->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_NS_OFFLOAD_TUPLE, + sizeof(*ns)); + + if (enable) { + if (i < ns_cnt) + ns->flags |= cpu_to_le32(WMI_NSOL_FLAGS_VALID); + + memcpy(ns->target_ipaddr[0], offload->ipv6_addr[i], 16); + memcpy(ns->solicitation_ipaddr, offload->self_ipv6_addr[i], 16); + + if (offload->ipv6_type[i]) + ns->flags |= cpu_to_le32(WMI_NSOL_FLAGS_IS_IPV6_ANYCAST); + + memcpy(ns->target_mac.addr, offload->mac_addr, ETH_ALEN); + + if (!is_zero_ether_addr(ns->target_mac.addr)) + ns->flags |= cpu_to_le32(WMI_NSOL_FLAGS_MAC_VALID); + + ath12k_dbg(ar->ab, ATH12K_DBG_WMI, + "wmi index %d ns_solicited %pI6 target %pI6", + i, ns->solicitation_ipaddr, + ns->target_ipaddr[0]); + } + + buf_ptr += sizeof(*ns); + } + + *ptr = buf_ptr; +} + +static void ath12k_wmi_fill_arp_offload(struct ath12k *ar, + struct wmi_arp_ns_offload_arg *offload, + void **ptr, + bool enable) +{ + struct wmi_arp_offload_params *arp; + struct wmi_tlv *tlv; + void *buf_ptr = *ptr; + int i; + + /* fill arp tuple */ + tlv = buf_ptr; + tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, + WMI_MAX_ARP_OFFLOADS * sizeof(*arp)); + buf_ptr += sizeof(*tlv); + + for (i = 0; i < WMI_MAX_ARP_OFFLOADS; i++) { + arp = buf_ptr; + arp->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_ARP_OFFLOAD_TUPLE, + sizeof(*arp)); + + if (enable && i < offload->ipv4_count) { + /* Copy the target ip addr and flags */ + arp->flags = cpu_to_le32(WMI_ARPOL_FLAGS_VALID); + memcpy(arp->target_ipaddr, offload->ipv4_addr[i], 4); + + ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "wmi arp offload address %pI4", + arp->target_ipaddr); + } + + buf_ptr += sizeof(*arp); + } + + *ptr = buf_ptr; +} + +int ath12k_wmi_arp_ns_offload(struct ath12k *ar, + struct ath12k_vif *arvif, + struct wmi_arp_ns_offload_arg *offload, + bool enable) +{ + struct wmi_set_arp_ns_offload_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + void *buf_ptr; + size_t len; + u8 ns_cnt, ns_ext_tuples = 0; + + ns_cnt = offload->ipv6_count; + + len = sizeof(*cmd) + + sizeof(*tlv) + + WMI_MAX_NS_OFFLOADS * sizeof(struct wmi_ns_offload_params) + + sizeof(*tlv) + + WMI_MAX_ARP_OFFLOADS * sizeof(struct wmi_arp_offload_params); + + if (ns_cnt > WMI_MAX_NS_OFFLOADS) { + ns_ext_tuples = ns_cnt - WMI_MAX_NS_OFFLOADS; + len += sizeof(*tlv) + + ns_ext_tuples * sizeof(struct wmi_ns_offload_params); + } + + skb = ath12k_wmi_alloc_skb(ar->wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + buf_ptr = skb->data; + cmd = buf_ptr; + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_SET_ARP_NS_OFFLOAD_CMD, + sizeof(*cmd)); + cmd->flags = cpu_to_le32(0); + cmd->vdev_id = cpu_to_le32(arvif->vdev_id); + cmd->num_ns_ext_tuples = cpu_to_le32(ns_ext_tuples); + + buf_ptr += sizeof(*cmd); + + ath12k_wmi_fill_ns_offload(ar, offload, &buf_ptr, enable, 0); + ath12k_wmi_fill_arp_offload(ar, offload, &buf_ptr, enable); + + if (ns_ext_tuples) + ath12k_wmi_fill_ns_offload(ar, offload, &buf_ptr, enable, 1); + + return ath12k_wmi_cmd_send(ar->wmi, skb, WMI_SET_ARP_NS_OFFLOAD_CMDID); +} diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 62d7bb9e791d..ac0517f46b72 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -24,6 +24,7 @@ struct ath12k_base; struct ath12k; +struct ath12k_vif; /* There is no signed version of __le32, so for a temporary solution come * up with our own version. The idea is from fs/ntfs/endian.h. @@ -5313,6 +5314,66 @@ struct wmi_hw_data_filter_arg { u32 hw_filter_bitmap; }; +#define WMI_IPV6_UC_TYPE 0 +#define WMI_IPV6_AC_TYPE 1 + +#define WMI_IPV6_MAX_COUNT 16 +#define WMI_IPV4_MAX_COUNT 2 + +struct wmi_arp_ns_offload_arg { + u8 ipv4_addr[WMI_IPV4_MAX_COUNT][4]; + u32 ipv4_count; + u32 ipv6_count; + u8 ipv6_addr[WMI_IPV6_MAX_COUNT][16]; + u8 self_ipv6_addr[WMI_IPV6_MAX_COUNT][16]; + u8 ipv6_type[WMI_IPV6_MAX_COUNT]; + bool ipv6_valid[WMI_IPV6_MAX_COUNT]; + u8 mac_addr[ETH_ALEN]; +}; + +#define WMI_MAX_NS_OFFLOADS 2 +#define WMI_MAX_ARP_OFFLOADS 2 + +#define WMI_ARPOL_FLAGS_VALID BIT(0) +#define WMI_ARPOL_FLAGS_MAC_VALID BIT(1) +#define WMI_ARPOL_FLAGS_REMOTE_IP_VALID BIT(2) + +struct wmi_arp_offload_params { + __le32 tlv_header; + __le32 flags; + u8 target_ipaddr[4]; + u8 remote_ipaddr[4]; + struct ath12k_wmi_mac_addr_params target_mac; +} __packed; + +#define WMI_NSOL_FLAGS_VALID BIT(0) +#define WMI_NSOL_FLAGS_MAC_VALID BIT(1) +#define WMI_NSOL_FLAGS_REMOTE_IP_VALID BIT(2) +#define WMI_NSOL_FLAGS_IS_IPV6_ANYCAST BIT(3) + +#define WMI_NSOL_MAX_TARGET_IPS 2 + +struct wmi_ns_offload_params { + __le32 tlv_header; + __le32 flags; + u8 target_ipaddr[WMI_NSOL_MAX_TARGET_IPS][16]; + u8 solicitation_ipaddr[16]; + u8 remote_ipaddr[16]; + struct ath12k_wmi_mac_addr_params target_mac; +} __packed; + +struct wmi_set_arp_ns_offload_cmd { + __le32 tlv_header; + __le32 flags; + __le32 vdev_id; + __le32 num_ns_ext_tuples; + /* The TLVs follow: + * wmi_ns_offload_params ns[WMI_MAX_NS_OFFLOADS]; + * wmi_arp_offload_params arp[WMI_MAX_ARP_OFFLOADS]; + * wmi_ns_offload_params ns_ext[num_ns_ext_tuples]; + */ +} __packed; + void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, struct ath12k_wmi_resource_config_arg *config); void ath12k_wmi_init_wcn7850(struct ath12k_base *ab, @@ -5478,4 +5539,9 @@ int ath12k_wmi_wow_config_pno(struct ath12k *ar, u32 vdev_id, struct wmi_pno_scan_req_arg *pno_scan); int ath12k_wmi_hw_data_filter_cmd(struct ath12k *ar, struct wmi_hw_data_filter_arg *arg); +int ath12k_wmi_arp_ns_offload(struct ath12k *ar, + struct ath12k_vif *arvif, + struct wmi_arp_ns_offload_arg *offload, + bool enable); + #endif diff --git a/drivers/net/wireless/ath/ath12k/wow.c b/drivers/net/wireless/ath/ath12k/wow.c index 146281244f70..8dfa7853e7a4 100644 --- a/drivers/net/wireless/ath/ath12k/wow.c +++ b/drivers/net/wireless/ath/ath12k/wow.c @@ -5,6 +5,10 @@ */ #include +#include +#include +#include +#include #include "mac.h" @@ -599,6 +603,179 @@ static int ath12k_wow_clear_hw_filter(struct ath12k *ar) return 0; } +static void ath12k_wow_generate_ns_mc_addr(struct ath12k_base *ab, + struct wmi_arp_ns_offload_arg *offload) +{ + int i; + + for (i = 0; i < offload->ipv6_count; i++) { + offload->self_ipv6_addr[i][0] = 0xff; + offload->self_ipv6_addr[i][1] = 0x02; + offload->self_ipv6_addr[i][11] = 0x01; + offload->self_ipv6_addr[i][12] = 0xff; + offload->self_ipv6_addr[i][13] = + offload->ipv6_addr[i][13]; + offload->self_ipv6_addr[i][14] = + offload->ipv6_addr[i][14]; + offload->self_ipv6_addr[i][15] = + offload->ipv6_addr[i][15]; + ath12k_dbg(ab, ATH12K_DBG_WOW, "NS solicited addr %pI6\n", + offload->self_ipv6_addr[i]); + } +} + +static void ath12k_wow_prepare_ns_offload(struct ath12k_vif *arvif, + struct wmi_arp_ns_offload_arg *offload) +{ + struct net_device *ndev = ieee80211_vif_to_wdev(arvif->vif)->netdev; + struct ath12k_base *ab = arvif->ar->ab; + struct inet6_ifaddr *ifa6; + struct ifacaddr6 *ifaca6; + struct inet6_dev *idev; + u32 count = 0, scope; + + if (!ndev) + return; + + idev = in6_dev_get(ndev); + if (!idev) + return; + + ath12k_dbg(ab, ATH12K_DBG_WOW, "wow prepare ns offload\n"); + + read_lock_bh(&idev->lock); + + /* get unicast address */ + list_for_each_entry(ifa6, &idev->addr_list, if_list) { + if (count >= WMI_IPV6_MAX_COUNT) + goto unlock; + + if (ifa6->flags & IFA_F_DADFAILED) + continue; + + scope = ipv6_addr_src_scope(&ifa6->addr); + if (scope != IPV6_ADDR_SCOPE_LINKLOCAL && + scope != IPV6_ADDR_SCOPE_GLOBAL) { + ath12k_dbg(ab, ATH12K_DBG_WOW, + "Unsupported ipv6 scope: %d\n", scope); + continue; + } + + memcpy(offload->ipv6_addr[count], &ifa6->addr.s6_addr, + sizeof(ifa6->addr.s6_addr)); + offload->ipv6_type[count] = WMI_IPV6_UC_TYPE; + ath12k_dbg(ab, ATH12K_DBG_WOW, "mac count %d ipv6 uc %pI6 scope %d\n", + count, offload->ipv6_addr[count], + scope); + count++; + } + + /* get anycast address */ + rcu_read_lock(); + + for (ifaca6 = rcu_dereference(idev->ac_list); ifaca6; + ifaca6 = rcu_dereference(ifaca6->aca_next)) { + if (count >= WMI_IPV6_MAX_COUNT) { + rcu_read_unlock(); + goto unlock; + } + + scope = ipv6_addr_src_scope(&ifaca6->aca_addr); + if (scope != IPV6_ADDR_SCOPE_LINKLOCAL && + scope != IPV6_ADDR_SCOPE_GLOBAL) { + ath12k_dbg(ab, ATH12K_DBG_WOW, + "Unsupported ipv scope: %d\n", scope); + continue; + } + + memcpy(offload->ipv6_addr[count], &ifaca6->aca_addr, + sizeof(ifaca6->aca_addr)); + offload->ipv6_type[count] = WMI_IPV6_AC_TYPE; + ath12k_dbg(ab, ATH12K_DBG_WOW, "mac count %d ipv6 ac %pI6 scope %d\n", + count, offload->ipv6_addr[count], + scope); + count++; + } + + rcu_read_unlock(); + +unlock: + read_unlock_bh(&idev->lock); + + in6_dev_put(idev); + + offload->ipv6_count = count; + ath12k_wow_generate_ns_mc_addr(ab, offload); +} + +static void ath12k_wow_prepare_arp_offload(struct ath12k_vif *arvif, + struct wmi_arp_ns_offload_arg *offload) +{ + struct ieee80211_vif *vif = arvif->vif; + struct ieee80211_vif_cfg vif_cfg = vif->cfg; + struct ath12k_base *ab = arvif->ar->ab; + u32 ipv4_cnt; + + ath12k_dbg(ab, ATH12K_DBG_WOW, "wow prepare arp offload\n"); + + ipv4_cnt = min(vif_cfg.arp_addr_cnt, WMI_IPV4_MAX_COUNT); + memcpy(offload->ipv4_addr, vif_cfg.arp_addr_list, ipv4_cnt * sizeof(u32)); + offload->ipv4_count = ipv4_cnt; + + ath12k_dbg(ab, ATH12K_DBG_WOW, + "wow arp_addr_cnt %d vif->addr %pM, offload_addr %pI4\n", + vif_cfg.arp_addr_cnt, vif->addr, offload->ipv4_addr); +} + +static int ath12k_wow_arp_ns_offload(struct ath12k *ar, bool enable) +{ + struct wmi_arp_ns_offload_arg *offload; + struct ath12k_vif *arvif; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + offload = kmalloc(sizeof(*offload), GFP_KERNEL); + if (!offload) + return -ENOMEM; + + list_for_each_entry(arvif, &ar->arvifs, list) { + if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + continue; + + memset(offload, 0, sizeof(*offload)); + + memcpy(offload->mac_addr, arvif->vif->addr, ETH_ALEN); + ath12k_wow_prepare_ns_offload(arvif, offload); + ath12k_wow_prepare_arp_offload(arvif, offload); + + ret = ath12k_wmi_arp_ns_offload(ar, arvif, offload, enable); + if (ret) { + ath12k_warn(ar->ab, "failed to set arp ns offload vdev %i: enable %d, ret %d\n", + arvif->vdev_id, enable, ret); + return ret; + } + } + + kfree(offload); + + return 0; +} + +static int ath12k_wow_protocol_offload(struct ath12k *ar, bool enable) +{ + int ret; + + ret = ath12k_wow_arp_ns_offload(ar, enable); + if (ret) { + ath12k_warn(ar->ab, "failed to offload ARP and NS %d %d\n", + enable, ret); + return ret; + } + + return 0; +} + int ath12k_wow_op_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { @@ -622,6 +799,13 @@ int ath12k_wow_op_suspend(struct ieee80211_hw *hw, goto cleanup; } + ret = ath12k_wow_protocol_offload(ar, true); + if (ret) { + ath12k_warn(ar->ab, "failed to set wow protocol offload events: %d\n", + ret); + goto cleanup; + } + ret = ath12k_mac_wait_tx_complete(ar); if (ret) { ath12k_warn(ar->ab, "failed to wait tx complete: %d\n", ret); @@ -708,6 +892,13 @@ int ath12k_wow_op_resume(struct ieee80211_hw *hw) goto exit; } + ret = ath12k_wow_protocol_offload(ar, false); + if (ret) { + ath12k_warn(ar->ab, "failed to clear wow protocol offload events: %d\n", + ret); + goto exit; + } + exit: if (ret) { switch (ah->state) { From aab4ae566fa15c19efadad16a8b54306b9b37e10 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Wed, 19 Jun 2024 17:21:12 +0300 Subject: [PATCH 036/204] wifi: ath12k: support GTK rekey offload Host sets GTK related info to firmware before WoW is enabled, and gets rekey replay_count and then disables GTK rekey when WoW quits. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240604055407.12506-8-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/core.h | 8 ++ drivers/net/wireless/ath/ath12k/mac.c | 38 +++++++++ drivers/net/wireless/ath/ath12k/wmi.c | 112 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/wmi.h | 39 +++++++++ drivers/net/wireless/ath/ath12k/wow.c | 46 +++++++++- 5 files changed, 242 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 81c4bfe7792f..9de3df924a1c 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -230,6 +230,13 @@ struct ath12k_vif_cache { u32 bss_conf_changed; }; +struct ath12k_rekey_data { + u8 kck[NL80211_KCK_LEN]; + u8 kek[NL80211_KCK_LEN]; + u64 replay_ctr; + bool enable_offload; +}; + struct ath12k_vif { u32 vdev_id; enum wmi_vdev_type vdev_type; @@ -286,6 +293,7 @@ struct ath12k_vif { u32 punct_bitmap; bool ps; struct ath12k_vif_cache *cache; + struct ath12k_rekey_data rekey_data; }; struct ath12k_vif_iter { diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 13186496728b..261859ad967c 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -2842,6 +2842,7 @@ static void ath12k_bss_assoc(struct ath12k *ar, } arvif->is_up = true; + arvif->rekey_data.enable_offload = false; ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev %d up (associated) bssid %pM aid %d\n", @@ -2889,6 +2890,8 @@ static void ath12k_bss_disassoc(struct ath12k *ar, arvif->is_up = false; + memset(&arvif->rekey_data, 0, sizeof(arvif->rekey_data)); + cancel_delayed_work(&arvif->connection_loss_work); } @@ -8545,6 +8548,40 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, return ret; } +static void ath12k_mac_op_set_rekey_data(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_gtk_rekey_data *data) +{ + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_rekey_data *rekey_data = &arvif->rekey_data; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar = ath12k_ah_to_ar(ah, 0); + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac set rekey data vdev %d\n", + arvif->vdev_id); + + mutex_lock(&ar->conf_mutex); + + memcpy(rekey_data->kck, data->kck, NL80211_KCK_LEN); + memcpy(rekey_data->kek, data->kek, NL80211_KEK_LEN); + + /* The supplicant works on big-endian, the firmware expects it on + * little endian. + */ + rekey_data->replay_ctr = get_unaligned_be64(data->replay_ctr); + + arvif->rekey_data.enable_offload = true; + + ath12k_dbg_dump(ar->ab, ATH12K_DBG_MAC, "kck", NULL, + rekey_data->kck, NL80211_KCK_LEN); + ath12k_dbg_dump(ar->ab, ATH12K_DBG_MAC, "kek", NULL, + rekey_data->kck, NL80211_KEK_LEN); + ath12k_dbg_dump(ar->ab, ATH12K_DBG_MAC, "replay ctr", NULL, + &rekey_data->replay_ctr, sizeof(rekey_data->replay_ctr)); + + mutex_unlock(&ar->conf_mutex); +} + static const struct ieee80211_ops ath12k_ops = { .tx = ath12k_mac_op_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, @@ -8560,6 +8597,7 @@ static const struct ieee80211_ops ath12k_ops = { .hw_scan = ath12k_mac_op_hw_scan, .cancel_hw_scan = ath12k_mac_op_cancel_hw_scan, .set_key = ath12k_mac_op_set_key, + .set_rekey_data = ath12k_mac_op_set_rekey_data, .sta_state = ath12k_mac_op_sta_state, .sta_set_txpwr = ath12k_mac_op_sta_set_txpwr, .sta_rc_update = ath12k_mac_op_sta_rc_update, diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 8b80d5b6bc01..0e41386bca45 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -7091,6 +7091,56 @@ static void ath12k_wmi_event_wow_wakeup_host(struct ath12k_base *ab, struct sk_b complete(&ab->wow.wakeup_completed); } +static void ath12k_wmi_gtk_offload_status_event(struct ath12k_base *ab, + struct sk_buff *skb) +{ + const struct wmi_gtk_offload_status_event *ev; + struct ath12k_vif *arvif; + __be64 replay_ctr_be; + u64 replay_ctr; + const void **tb; + int ret; + + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath12k_warn(ab, "failed to parse tlv: %d\n", ret); + return; + } + + ev = tb[WMI_TAG_GTK_OFFLOAD_STATUS_EVENT]; + if (!ev) { + ath12k_warn(ab, "failed to fetch gtk offload status ev"); + kfree(tb); + return; + } + + rcu_read_lock(); + arvif = ath12k_mac_get_arvif_by_vdev_id(ab, le32_to_cpu(ev->vdev_id)); + if (!arvif) { + rcu_read_unlock(); + ath12k_warn(ab, "failed to get arvif for vdev_id:%d\n", + le32_to_cpu(ev->vdev_id)); + kfree(tb); + return; + } + + replay_ctr = le64_to_cpu(ev->replay_ctr); + arvif->rekey_data.replay_ctr = replay_ctr; + ath12k_dbg(ab, ATH12K_DBG_WMI, "wmi gtk offload event refresh_cnt %d replay_ctr %llu\n", + le32_to_cpu(ev->refresh_cnt), replay_ctr); + + /* supplicant expects big-endian replay counter */ + replay_ctr_be = cpu_to_be64(replay_ctr); + + ieee80211_gtk_rekey_notify(arvif->vif, arvif->bssid, + (void *)&replay_ctr_be, GFP_ATOMIC); + + rcu_read_unlock(); + + kfree(tb); +} + static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; @@ -7214,6 +7264,9 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) case WMI_WOW_WAKEUP_HOST_EVENTID: ath12k_wmi_event_wow_wakeup_host(ab, skb); break; + case WMI_GTK_OFFLOAD_STATUS_EVENTID: + ath12k_wmi_gtk_offload_status_event(ab, skb); + break; /* TODO: Add remaining events */ default: ath12k_dbg(ab, ATH12K_DBG_WMI, "Unknown eventid: 0x%x\n", id); @@ -7931,3 +7984,62 @@ int ath12k_wmi_arp_ns_offload(struct ath12k *ar, return ath12k_wmi_cmd_send(ar->wmi, skb, WMI_SET_ARP_NS_OFFLOAD_CMDID); } + +int ath12k_wmi_gtk_rekey_offload(struct ath12k *ar, + struct ath12k_vif *arvif, bool enable) +{ + struct ath12k_rekey_data *rekey_data = &arvif->rekey_data; + struct wmi_gtk_rekey_offload_cmd *cmd; + struct sk_buff *skb; + __le64 replay_ctr; + int len; + + len = sizeof(*cmd); + skb = ath12k_wmi_alloc_skb(ar->wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_gtk_rekey_offload_cmd *)skb->data; + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_GTK_OFFLOAD_CMD, sizeof(*cmd)); + cmd->vdev_id = cpu_to_le32(arvif->vdev_id); + + if (enable) { + cmd->flags = cpu_to_le32(GTK_OFFLOAD_ENABLE_OPCODE); + + /* the length in rekey_data and cmd is equal */ + memcpy(cmd->kck, rekey_data->kck, sizeof(cmd->kck)); + memcpy(cmd->kek, rekey_data->kek, sizeof(cmd->kek)); + + replay_ctr = cpu_to_le64(rekey_data->replay_ctr); + memcpy(cmd->replay_ctr, &replay_ctr, + sizeof(replay_ctr)); + } else { + cmd->flags = cpu_to_le32(GTK_OFFLOAD_DISABLE_OPCODE); + } + + ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "offload gtk rekey vdev: %d %d\n", + arvif->vdev_id, enable); + return ath12k_wmi_cmd_send(ar->wmi, skb, WMI_GTK_OFFLOAD_CMDID); +} + +int ath12k_wmi_gtk_rekey_getinfo(struct ath12k *ar, + struct ath12k_vif *arvif) +{ + struct wmi_gtk_rekey_offload_cmd *cmd; + struct sk_buff *skb; + int len; + + len = sizeof(*cmd); + skb = ath12k_wmi_alloc_skb(ar->wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_gtk_rekey_offload_cmd *)skb->data; + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_GTK_OFFLOAD_CMD, sizeof(*cmd)); + cmd->vdev_id = cpu_to_le32(arvif->vdev_id); + cmd->flags = cpu_to_le32(GTK_OFFLOAD_REQUEST_STATUS_OPCODE); + + ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "get gtk rekey vdev_id: %d\n", + arvif->vdev_id); + return ath12k_wmi_cmd_send(ar->wmi, skb, WMI_GTK_OFFLOAD_CMDID); +} diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index ac0517f46b72..32f74993b129 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -5374,6 +5374,41 @@ struct wmi_set_arp_ns_offload_cmd { */ } __packed; +#define GTK_OFFLOAD_OPCODE_MASK 0xFF000000 +#define GTK_OFFLOAD_ENABLE_OPCODE 0x01000000 +#define GTK_OFFLOAD_DISABLE_OPCODE 0x02000000 +#define GTK_OFFLOAD_REQUEST_STATUS_OPCODE 0x04000000 + +#define GTK_OFFLOAD_KEK_BYTES 16 +#define GTK_OFFLOAD_KCK_BYTES 16 +#define GTK_REPLAY_COUNTER_BYTES 8 +#define WMI_MAX_KEY_LEN 32 +#define IGTK_PN_SIZE 6 + +struct wmi_gtk_offload_status_event { + __le32 vdev_id; + __le32 flags; + __le32 refresh_cnt; + __le64 replay_ctr; + u8 igtk_key_index; + u8 igtk_key_length; + u8 igtk_key_rsc[IGTK_PN_SIZE]; + u8 igtk_key[WMI_MAX_KEY_LEN]; + u8 gtk_key_index; + u8 gtk_key_length; + u8 gtk_key_rsc[GTK_REPLAY_COUNTER_BYTES]; + u8 gtk_key[WMI_MAX_KEY_LEN]; +} __packed; + +struct wmi_gtk_rekey_offload_cmd { + __le32 tlv_header; + __le32 vdev_id; + __le32 flags; + u8 kek[GTK_OFFLOAD_KEK_BYTES]; + u8 kck[GTK_OFFLOAD_KCK_BYTES]; + u8 replay_ctr[GTK_REPLAY_COUNTER_BYTES]; +} __packed; + void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, struct ath12k_wmi_resource_config_arg *config); void ath12k_wmi_init_wcn7850(struct ath12k_base *ab, @@ -5543,5 +5578,9 @@ int ath12k_wmi_arp_ns_offload(struct ath12k *ar, struct ath12k_vif *arvif, struct wmi_arp_ns_offload_arg *offload, bool enable); +int ath12k_wmi_gtk_rekey_offload(struct ath12k *ar, + struct ath12k_vif *arvif, bool enable); +int ath12k_wmi_gtk_rekey_getinfo(struct ath12k *ar, + struct ath12k_vif *arvif); #endif diff --git a/drivers/net/wireless/ath/ath12k/wow.c b/drivers/net/wireless/ath/ath12k/wow.c index 8dfa7853e7a4..5a7001edafe0 100644 --- a/drivers/net/wireless/ath/ath12k/wow.c +++ b/drivers/net/wireless/ath/ath12k/wow.c @@ -21,7 +21,9 @@ static const struct wiphy_wowlan_support ath12k_wowlan_support = { .flags = WIPHY_WOWLAN_DISCONNECT | - WIPHY_WOWLAN_MAGIC_PKT, + WIPHY_WOWLAN_MAGIC_PKT | + WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | + WIPHY_WOWLAN_GTK_REKEY_FAILURE, .pattern_min_len = WOW_MIN_PATTERN_SIZE, .pattern_max_len = WOW_MAX_PATTERN_SIZE, .max_pkt_offset = WOW_MAX_PKT_OFFSET, @@ -762,6 +764,41 @@ static int ath12k_wow_arp_ns_offload(struct ath12k *ar, bool enable) return 0; } +static int ath12k_gtk_rekey_offload(struct ath12k *ar, bool enable) +{ + struct ath12k_vif *arvif; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + list_for_each_entry(arvif, &ar->arvifs, list) { + if (arvif->vdev_type != WMI_VDEV_TYPE_STA || + !arvif->is_up || + !arvif->rekey_data.enable_offload) + continue; + + /* get rekey info before disable rekey offload */ + if (!enable) { + ret = ath12k_wmi_gtk_rekey_getinfo(ar, arvif); + if (ret) { + ath12k_warn(ar->ab, "failed to request rekey info vdev %i, ret %d\n", + arvif->vdev_id, ret); + return ret; + } + } + + ret = ath12k_wmi_gtk_rekey_offload(ar, arvif, enable); + + if (ret) { + ath12k_warn(ar->ab, "failed to offload gtk reky vdev %i: enable %d, ret %d\n", + arvif->vdev_id, enable, ret); + return ret; + } + } + + return 0; +} + static int ath12k_wow_protocol_offload(struct ath12k *ar, bool enable) { int ret; @@ -773,6 +810,13 @@ static int ath12k_wow_protocol_offload(struct ath12k *ar, bool enable) return ret; } + ret = ath12k_gtk_rekey_offload(ar, enable); + if (ret) { + ath12k_warn(ar->ab, "failed to offload gtk rekey %d %d\n", + enable, ret); + return ret; + } + return 0; } From 7af01e5695295444d47f4ead3e27e91d8c9e60f4 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Wed, 19 Jun 2024 17:21:12 +0300 Subject: [PATCH 037/204] wifi: ath12k: handle keepalive during WoWLAN suspend and resume With WoWLAN enabled and after sleeping for a rather long time, we are seeing that with some APs, it is not able to wake up the STA though the correct wake up pattern has been configured. This is because the host doesn't send keepalive command to firmware, thus firmware will not send any packet to the AP and after a specific time the AP kicks out the STA. So enable keepalive before going to suspend and disable it after resume back. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240604055407.12506-9-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 31 ++++++++++++++++++ drivers/net/wireless/ath/ath12k/mac.h | 4 +++ drivers/net/wireless/ath/ath12k/wmi.c | 38 ++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/wmi.h | 46 +++++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/wow.c | 34 ++++++++++++++++++++ 5 files changed, 153 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 261859ad967c..43801ff5bfd8 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -9418,3 +9418,34 @@ int ath12k_mac_allocate(struct ath12k_base *ab) return ret; } + +int ath12k_mac_vif_set_keepalive(struct ath12k_vif *arvif, + enum wmi_sta_keepalive_method method, + u32 interval) +{ + struct wmi_sta_keepalive_arg arg = {}; + struct ath12k *ar = arvif->ar; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + return 0; + + if (!test_bit(WMI_TLV_SERVICE_STA_KEEP_ALIVE, ar->ab->wmi_ab.svc_map)) + return 0; + + arg.vdev_id = arvif->vdev_id; + arg.enabled = 1; + arg.method = method; + arg.interval = interval; + + ret = ath12k_wmi_sta_keepalive(ar, &arg); + if (ret) { + ath12k_warn(ar->ab, "failed to set keepalive on vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + return 0; +} diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h index 69fd282b9dd3..2c6cb144827a 100644 --- a/drivers/net/wireless/ath/ath12k/mac.h +++ b/drivers/net/wireless/ath/ath12k/mac.h @@ -9,6 +9,7 @@ #include #include +#include "wmi.h" struct ath12k; struct ath12k_base; @@ -81,5 +82,8 @@ int ath12k_mac_rfkill_config(struct ath12k *ar); int ath12k_mac_wait_tx_complete(struct ath12k *ar); void ath12k_mac_handle_beacon(struct ath12k *ar, struct sk_buff *skb); void ath12k_mac_handle_beacon_miss(struct ath12k *ar, u32 vdev_id); +int ath12k_mac_vif_set_keepalive(struct ath12k_vif *arvif, + enum wmi_sta_keepalive_method method, + u32 interval); #endif diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 0e41386bca45..7c5976366615 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -8043,3 +8043,41 @@ int ath12k_wmi_gtk_rekey_getinfo(struct ath12k *ar, arvif->vdev_id); return ath12k_wmi_cmd_send(ar->wmi, skb, WMI_GTK_OFFLOAD_CMDID); } + +int ath12k_wmi_sta_keepalive(struct ath12k *ar, + const struct wmi_sta_keepalive_arg *arg) +{ + struct wmi_sta_keepalive_arp_resp_params *arp; + struct ath12k_wmi_pdev *wmi = ar->wmi; + struct wmi_sta_keepalive_cmd *cmd; + struct sk_buff *skb; + size_t len; + + len = sizeof(*cmd) + sizeof(*arp); + skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_sta_keepalive_cmd *)skb->data; + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_STA_KEEPALIVE_CMD, sizeof(*cmd)); + cmd->vdev_id = cpu_to_le32(arg->vdev_id); + cmd->enabled = cpu_to_le32(arg->enabled); + cmd->interval = cpu_to_le32(arg->interval); + cmd->method = cpu_to_le32(arg->method); + + arp = (struct wmi_sta_keepalive_arp_resp_params *)(cmd + 1); + arp->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_STA_KEEPALVE_ARP_RESPONSE, + sizeof(*arp)); + if (arg->method == WMI_STA_KEEPALIVE_METHOD_UNSOLICITED_ARP_RESPONSE || + arg->method == WMI_STA_KEEPALIVE_METHOD_GRATUITOUS_ARP_REQUEST) { + arp->src_ip4_addr = cpu_to_le32(arg->src_ip4_addr); + arp->dest_ip4_addr = cpu_to_le32(arg->dest_ip4_addr); + ether_addr_copy(arp->dest_mac_addr.addr, arg->dest_mac_addr); + } + + ath12k_dbg(ar->ab, ATH12K_DBG_WMI, + "wmi sta keepalive vdev %d enabled %d method %d interval %d\n", + arg->vdev_id, arg->enabled, arg->method, arg->interval); + + return ath12k_wmi_cmd_send(wmi, skb, WMI_STA_KEEPALIVE_CMDID); +} diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 32f74993b129..0ac7accc45dc 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -5409,6 +5409,50 @@ struct wmi_gtk_rekey_offload_cmd { u8 replay_ctr[GTK_REPLAY_COUNTER_BYTES]; } __packed; +struct wmi_sta_keepalive_cmd { + __le32 tlv_header; + __le32 vdev_id; + __le32 enabled; + + /* WMI_STA_KEEPALIVE_METHOD_ */ + __le32 method; + + /* in seconds */ + __le32 interval; + + /* following this structure is the TLV for struct + * wmi_sta_keepalive_arp_resp_params + */ +} __packed; + +struct wmi_sta_keepalive_arp_resp_params { + __le32 tlv_header; + __le32 src_ip4_addr; + __le32 dest_ip4_addr; + struct ath12k_wmi_mac_addr_params dest_mac_addr; +} __packed; + +struct wmi_sta_keepalive_arg { + u32 vdev_id; + u32 enabled; + u32 method; + u32 interval; + u32 src_ip4_addr; + u32 dest_ip4_addr; + const u8 dest_mac_addr[ETH_ALEN]; +}; + +enum wmi_sta_keepalive_method { + WMI_STA_KEEPALIVE_METHOD_NULL_FRAME = 1, + WMI_STA_KEEPALIVE_METHOD_UNSOLICITED_ARP_RESPONSE = 2, + WMI_STA_KEEPALIVE_METHOD_ETHERNET_LOOPBACK = 3, + WMI_STA_KEEPALIVE_METHOD_GRATUITOUS_ARP_REQUEST = 4, + WMI_STA_KEEPALIVE_METHOD_MGMT_VENDOR_ACTION = 5, +}; + +#define WMI_STA_KEEPALIVE_INTERVAL_DEFAULT 30 +#define WMI_STA_KEEPALIVE_INTERVAL_DISABLE 0 + 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, @@ -5582,5 +5626,7 @@ int ath12k_wmi_gtk_rekey_offload(struct ath12k *ar, struct ath12k_vif *arvif, bool enable); int ath12k_wmi_gtk_rekey_getinfo(struct ath12k *ar, struct ath12k_vif *arvif); +int ath12k_wmi_sta_keepalive(struct ath12k *ar, + const struct wmi_sta_keepalive_arg *arg); #endif diff --git a/drivers/net/wireless/ath/ath12k/wow.c b/drivers/net/wireless/ath/ath12k/wow.c index 5a7001edafe0..685e8e98d845 100644 --- a/drivers/net/wireless/ath/ath12k/wow.c +++ b/drivers/net/wireless/ath/ath12k/wow.c @@ -820,6 +820,24 @@ static int ath12k_wow_protocol_offload(struct ath12k *ar, bool enable) return 0; } +static int ath12k_wow_set_keepalive(struct ath12k *ar, + enum wmi_sta_keepalive_method method, + u32 interval) +{ + struct ath12k_vif *arvif; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + list_for_each_entry(arvif, &ar->arvifs, list) { + ret = ath12k_mac_vif_set_keepalive(arvif, method, interval); + if (ret) + return ret; + } + + return 0; +} + int ath12k_wow_op_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { @@ -863,6 +881,14 @@ int ath12k_wow_op_suspend(struct ieee80211_hw *hw, goto cleanup; } + ret = ath12k_wow_set_keepalive(ar, + WMI_STA_KEEPALIVE_METHOD_NULL_FRAME, + WMI_STA_KEEPALIVE_INTERVAL_DEFAULT); + if (ret) { + ath12k_warn(ar->ab, "failed to enable wow keepalive: %d\n", ret); + goto cleanup; + } + ret = ath12k_wow_enable(ar); if (ret) { ath12k_warn(ar->ab, "failed to start wow: %d\n", ret); @@ -943,6 +969,14 @@ int ath12k_wow_op_resume(struct ieee80211_hw *hw) goto exit; } + ret = ath12k_wow_set_keepalive(ar, + WMI_STA_KEEPALIVE_METHOD_NULL_FRAME, + WMI_STA_KEEPALIVE_INTERVAL_DISABLE); + if (ret) { + ath12k_warn(ar->ab, "failed to disable wow keepalive: %d\n", ret); + goto exit; + } + exit: if (ret) { switch (ah->state) { From 2c7857677d695166e913123b23ed7e55d80f72be Mon Sep 17 00:00:00 2001 From: Lingbo Kong Date: Fri, 21 Jun 2024 15:58:09 +0530 Subject: [PATCH 038/204] wifi: ath12k: Fix pdev id sent to firmware for single phy devices Pdev id from mac phy capabilities will be sent as a part of HTT/WMI command to firmware. This causes issue with single pdev devices where firmware does not respond to the WMI/HTT request sent from host. For single pdev devices firmware expects pdev id as 1 for 5 GHz/6 GHz phy and 2 for 2 GHz band. Add wrapper ath12k_mac_get_target_pdev_id() to help fetch right pdev for single pdev devices. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Lingbo Kong Signed-off-by: Ramya Gnanasekar Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240621102809.3984004-1-quic_rgnanase@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 76 +++++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/mac.h | 1 + 2 files changed, 77 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 43801ff5bfd8..7475dddca8c5 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -673,6 +673,82 @@ static struct ath12k *ath12k_get_ar_by_vif(struct ieee80211_hw *hw, return NULL; } +static struct ath12k_vif *ath12k_mac_get_vif_up(struct ath12k *ar) +{ + struct ath12k_vif *arvif; + + lockdep_assert_held(&ar->conf_mutex); + list_for_each_entry(arvif, &ar->arvifs, list) { + if (arvif->is_up) + return arvif; + } + + return NULL; +} + +static bool ath12k_mac_band_match(enum nl80211_band band1, enum WMI_HOST_WLAN_BAND band2) +{ + switch (band1) { + case NL80211_BAND_2GHZ: + if (band2 & WMI_HOST_WLAN_2G_CAP) + return true; + break; + case NL80211_BAND_5GHZ: + case NL80211_BAND_6GHZ: + if (band2 & WMI_HOST_WLAN_5G_CAP) + return true; + break; + default: + return false; + } + + return false; +} + +static u8 ath12k_mac_get_target_pdev_id_from_vif(struct ath12k_vif *arvif) +{ + struct ath12k *ar = arvif->ar; + struct ath12k_base *ab = ar->ab; + struct ieee80211_vif *vif = arvif->vif; + struct cfg80211_chan_def def; + enum nl80211_band band; + u8 pdev_id = ab->fw_pdev[0].pdev_id; + int i; + + if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) + return pdev_id; + + band = def.chan->band; + + for (i = 0; i < ab->fw_pdev_count; i++) { + if (ath12k_mac_band_match(band, ab->fw_pdev[i].supported_bands)) + return ab->fw_pdev[i].pdev_id; + } + + return pdev_id; +} + +u8 ath12k_mac_get_target_pdev_id(struct ath12k *ar) +{ + struct ath12k_vif *arvif; + struct ath12k_base *ab = ar->ab; + + if (!ab->hw_params->single_pdev_only) + return ar->pdev->pdev_id; + + arvif = ath12k_mac_get_vif_up(ar); + + /* fw_pdev array has pdev ids derived from phy capability + * service ready event (pdev_and_hw_link_ids). + * If no vif is active, return default first index. + */ + if (!arvif) + return ar->ab->fw_pdev[0].pdev_id; + + /* If active vif is found, return the pdev id matching chandef band */ + return ath12k_mac_get_target_pdev_id_from_vif(arvif); +} + static void ath12k_pdev_caps_update(struct ath12k *ar) { struct ath12k_base *ab = ar->ab; diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h index 2c6cb144827a..5efbb6822628 100644 --- a/drivers/net/wireless/ath/ath12k/mac.h +++ b/drivers/net/wireless/ath/ath12k/mac.h @@ -85,5 +85,6 @@ void ath12k_mac_handle_beacon_miss(struct ath12k *ar, u32 vdev_id); int ath12k_mac_vif_set_keepalive(struct ath12k_vif *arvif, enum wmi_sta_keepalive_method method, u32 interval); +u8 ath12k_mac_get_target_pdev_id(struct ath12k *ar); #endif From 1eeafd64c7b455381b77c546e41bc267e13e2809 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Mon, 24 Jun 2024 20:24:18 +0530 Subject: [PATCH 039/204] wifi: ath12k: fix peer metadata parsing Currently, the Rx data path only supports parsing peer metadata of version zero. However, the QCN9274 platform configures the peer metadata version as V1B. When V1B peer metadata is parsed using the version zero logic, invalid data is populated, causing valid packets to be dropped. To address this issue, refactor the peer metadata version and add the version based parsing to populate the data from peer metadata correctly. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Fixes: 287033810990 ("wifi: ath12k: add support for peer meta data version") Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240624145418.2043461-1-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/dp.h | 1 + drivers/net/wireless/ath/ath12k/dp_rx.c | 40 ++++++++++++++++++---- drivers/net/wireless/ath/ath12k/hal_desc.h | 26 ++++++++++++-- drivers/net/wireless/ath/ath12k/hw.h | 2 -- drivers/net/wireless/ath/ath12k/wmi.c | 6 ++-- drivers/net/wireless/ath/ath12k/wmi.h | 11 ++++-- 6 files changed, 72 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index 742094545089..b77497c14ac4 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -333,6 +333,7 @@ struct ath12k_dp { struct dp_srng reo_except_ring; struct dp_srng reo_cmd_ring; struct dp_srng reo_status_ring; + enum ath12k_peer_metadata_version peer_metadata_ver; struct dp_srng reo_dst_ring[DP_REO_DST_RING_MAX]; struct dp_tx_ring tx_ring[DP_TCL_NUM_RING_MAX]; struct hal_wbm_idle_scatter_list scatter_list[DP_IDLE_SCATTER_BUFS_MAX]; diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 54aea3c22311..d7bb412ad391 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -2583,6 +2583,29 @@ static void ath12k_dp_rx_process_received_packets(struct ath12k_base *ab, rcu_read_unlock(); } +static u16 ath12k_dp_rx_get_peer_id(struct ath12k_base *ab, + enum ath12k_peer_metadata_version ver, + __le32 peer_metadata) +{ + switch (ver) { + default: + ath12k_warn(ab, "Unknown peer metadata version: %d", ver); + fallthrough; + case ATH12K_PEER_METADATA_V0: + return le32_get_bits(peer_metadata, + RX_MPDU_DESC_META_DATA_V0_PEER_ID); + case ATH12K_PEER_METADATA_V1: + return le32_get_bits(peer_metadata, + RX_MPDU_DESC_META_DATA_V1_PEER_ID); + case ATH12K_PEER_METADATA_V1A: + return le32_get_bits(peer_metadata, + RX_MPDU_DESC_META_DATA_V1A_PEER_ID); + case ATH12K_PEER_METADATA_V1B: + return le32_get_bits(peer_metadata, + RX_MPDU_DESC_META_DATA_V1B_PEER_ID); + } +} + int ath12k_dp_rx_process(struct ath12k_base *ab, int ring_id, struct napi_struct *napi, int budget) { @@ -2611,6 +2634,8 @@ int ath12k_dp_rx_process(struct ath12k_base *ab, int ring_id, ath12k_hal_srng_access_begin(ab, srng); while ((desc = ath12k_hal_srng_dst_get_next_entry(ab, srng))) { + struct rx_mpdu_desc *mpdu_info; + struct rx_msdu_desc *msdu_info; enum hal_reo_dest_ring_push_reason push_reason; u32 cookie; @@ -2658,16 +2683,19 @@ int ath12k_dp_rx_process(struct ath12k_base *ab, int ring_id, continue; } - rxcb->is_first_msdu = !!(le32_to_cpu(desc->rx_msdu_info.info0) & + msdu_info = &desc->rx_msdu_info; + mpdu_info = &desc->rx_mpdu_info; + + rxcb->is_first_msdu = !!(le32_to_cpu(msdu_info->info0) & RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU); - rxcb->is_last_msdu = !!(le32_to_cpu(desc->rx_msdu_info.info0) & + rxcb->is_last_msdu = !!(le32_to_cpu(msdu_info->info0) & RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU); - rxcb->is_continuation = !!(le32_to_cpu(desc->rx_msdu_info.info0) & + rxcb->is_continuation = !!(le32_to_cpu(msdu_info->info0) & RX_MSDU_DESC_INFO0_MSDU_CONTINUATION); rxcb->mac_id = mac_id; - rxcb->peer_id = le32_get_bits(desc->rx_mpdu_info.peer_meta_data, - RX_MPDU_DESC_META_DATA_PEER_ID); - rxcb->tid = le32_get_bits(desc->rx_mpdu_info.info0, + rxcb->peer_id = ath12k_dp_rx_get_peer_id(ab, dp->peer_metadata_ver, + mpdu_info->peer_meta_data); + rxcb->tid = le32_get_bits(mpdu_info->info0, RX_MPDU_DESC_INFO0_TID); __skb_queue_tail(&msdu_list, msdu); diff --git a/drivers/net/wireless/ath/ath12k/hal_desc.h b/drivers/net/wireless/ath/ath12k/hal_desc.h index 02b7db06b24e..739f73370015 100644 --- a/drivers/net/wireless/ath/ath12k/hal_desc.h +++ b/drivers/net/wireless/ath/ath12k/hal_desc.h @@ -597,8 +597,30 @@ struct hal_tlv_64_hdr { #define RX_MPDU_DESC_INFO0_MPDU_QOS_CTRL_VALID BIT(27) #define RX_MPDU_DESC_INFO0_TID GENMASK(31, 28) -/* TODO revisit after meta data is concluded */ -#define RX_MPDU_DESC_META_DATA_PEER_ID GENMASK(15, 0) +/* Peer Metadata classification */ + +/* Version 0 */ +#define RX_MPDU_DESC_META_DATA_V0_PEER_ID GENMASK(15, 0) +#define RX_MPDU_DESC_META_DATA_V0_VDEV_ID GENMASK(23, 16) + +/* Version 1 */ +#define RX_MPDU_DESC_META_DATA_V1_PEER_ID GENMASK(13, 0) +#define RX_MPDU_DESC_META_DATA_V1_LOGICAL_LINK_ID GENMASK(15, 14) +#define RX_MPDU_DESC_META_DATA_V1_VDEV_ID GENMASK(23, 16) +#define RX_MPDU_DESC_META_DATA_V1_LMAC_ID GENMASK(25, 24) +#define RX_MPDU_DESC_META_DATA_V1_DEVICE_ID GENMASK(28, 26) + +/* Version 1A */ +#define RX_MPDU_DESC_META_DATA_V1A_PEER_ID GENMASK(13, 0) +#define RX_MPDU_DESC_META_DATA_V1A_VDEV_ID GENMASK(21, 14) +#define RX_MPDU_DESC_META_DATA_V1A_LOGICAL_LINK_ID GENMASK(25, 22) +#define RX_MPDU_DESC_META_DATA_V1A_DEVICE_ID GENMASK(28, 26) + +/* Version 1B */ +#define RX_MPDU_DESC_META_DATA_V1B_PEER_ID GENMASK(13, 0) +#define RX_MPDU_DESC_META_DATA_V1B_VDEV_ID GENMASK(21, 14) +#define RX_MPDU_DESC_META_DATA_V1B_HW_LINK_ID GENMASK(25, 22) +#define RX_MPDU_DESC_META_DATA_V1B_DEVICE_ID GENMASK(28, 26) struct rx_mpdu_desc { __le32 info0; /* %RX_MPDU_DESC_INFO */ diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index af33bf11416b..e792eb6b249b 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -78,8 +78,6 @@ #define TARGET_NUM_WDS_ENTRIES 32 #define TARGET_DMA_BURST_SIZE 1 #define TARGET_RX_BATCHMODE 1 -#define TARGET_RX_PEER_METADATA_VER_V1A 2 -#define TARGET_RX_PEER_METADATA_VER_V1B 3 #define TARGET_EMA_MAX_PROFILE_PERIOD 8 #define ATH12K_HW_DEFAULT_QUEUE 0 diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 7c5976366615..9f6be557365e 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -233,7 +233,7 @@ void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, config->beacon_tx_offload_max_vdev += config->ema_max_vap_cnt; if (test_bit(WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT, ab->wmi_ab.svc_map)) - config->dp_peer_meta_data_ver = TARGET_RX_PEER_METADATA_VER_V1B; + config->peer_metadata_ver = ATH12K_PEER_METADATA_V1B; } void ath12k_wmi_init_wcn7850(struct ath12k_base *ab, @@ -3498,7 +3498,7 @@ ath12k_wmi_copy_resource_config(struct ath12k_wmi_resource_config_params *wmi_cf wmi_cfg->sched_params = cpu_to_le32(tg_cfg->sched_params); wmi_cfg->twt_ap_pdev_count = cpu_to_le32(tg_cfg->twt_ap_pdev_count); wmi_cfg->twt_ap_sta_count = cpu_to_le32(tg_cfg->twt_ap_sta_count); - wmi_cfg->flags2 = le32_encode_bits(tg_cfg->dp_peer_meta_data_ver, + wmi_cfg->flags2 = le32_encode_bits(tg_cfg->peer_metadata_ver, WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION); wmi_cfg->host_service_flags = cpu_to_le32(tg_cfg->is_reg_cc_ext_event_supported << WMI_RSRC_CFG_HOST_SVC_FLAG_REG_CC_EXT_SUPPORT_BIT); @@ -3729,6 +3729,8 @@ int ath12k_wmi_cmd_init(struct ath12k_base *ab) arg.num_band_to_mac = ab->num_radios; ath12k_fill_band_to_mac_param(ab, arg.band_to_mac); + ab->dp.peer_metadata_ver = arg.res_cfg.peer_metadata_ver; + return ath12k_init_cmd_send(&wmi_ab->wmi[0], &arg); } diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 0ac7accc45dc..f1f52175a52b 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2294,6 +2294,13 @@ struct ath12k_wmi_host_mem_chunk_arg { u32 req_id; }; +enum ath12k_peer_metadata_version { + ATH12K_PEER_METADATA_V0, + ATH12K_PEER_METADATA_V1, + ATH12K_PEER_METADATA_V1A, + ATH12K_PEER_METADATA_V1B +}; + struct ath12k_wmi_resource_config_arg { u32 num_vdevs; u32 num_peers; @@ -2356,10 +2363,10 @@ struct ath12k_wmi_resource_config_arg { u32 sched_params; u32 twt_ap_pdev_count; u32 twt_ap_sta_count; - bool is_reg_cc_ext_event_supported; - u8 dp_peer_meta_data_ver; + enum ath12k_peer_metadata_version peer_metadata_ver; u32 ema_max_vap_cnt; u32 ema_max_profile_period; + bool is_reg_cc_ext_event_supported; }; struct ath12k_wmi_init_cmd_arg { From 0065199f4303bc2b05467e64779d392f9a29d61d Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 20 Jun 2024 13:58:19 +0800 Subject: [PATCH 040/204] wifi: rtw89: wow: append security header offset for different cipher When creating EAPOL_KEY, SA_QUERY and ARP_RSP packet offload, we need to append security header offset for different cipher as required by the firmware. Only 8852A, 8852B, 8852BT and 8851B need it. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240620055825.17592-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 67 +++++++++++++++--------- drivers/net/wireless/realtek/rtw89/wow.c | 22 +++++--- drivers/net/wireless/realtek/rtw89/wow.h | 30 +++++++++++ 3 files changed, 85 insertions(+), 34 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 23204b2706c9..3c666fd0f8ed 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -13,22 +13,20 @@ #include "ps.h" #include "reg.h" #include "util.h" +#include "wow.h" struct rtw89_eapol_2_of_2 { - struct ieee80211_hdr_3addr hdr; u8 gtkbody[14]; u8 key_des_ver; u8 rsvd[92]; -} __packed __aligned(2); +} __packed; struct rtw89_sa_query { - struct ieee80211_hdr_3addr hdr; u8 category; u8 action; -} __packed __aligned(2); +} __packed; struct rtw89_arp_rsp { - struct ieee80211_hdr_3addr addr; u8 llc_hdr[sizeof(rfc1042_header)]; __be16 llc_type; struct arphdr arp_hdr; @@ -36,7 +34,7 @@ struct rtw89_arp_rsp { __be32 sender_ip; u8 target_hw[ETH_ALEN]; __be32 target_ip; -} __packed __aligned(2); +} __packed; static const u8 mss_signature[] = {0x4D, 0x53, 0x53, 0x4B, 0x50, 0x4F, 0x4F, 0x4C}; @@ -2197,8 +2195,10 @@ static struct sk_buff *rtw89_eapol_get(struct rtw89_dev *rtwdev, 0x8E, 0x01, 0x03, 0x00, 0x5F, 0x02, 0x03}; struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + u8 sec_hdr_len = rtw89_wow_get_sec_hdr_len(rtwdev); struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct rtw89_eapol_2_of_2 *eapol_pkt; + struct ieee80211_hdr_3addr *hdr; struct sk_buff *skb; u8 key_des_ver; @@ -2211,17 +2211,21 @@ static struct sk_buff *rtw89_eapol_get(struct rtw89_dev *rtwdev, else key_des_ver = 0; - skb = dev_alloc_skb(sizeof(*eapol_pkt)); + skb = dev_alloc_skb(sizeof(*hdr) + sec_hdr_len + sizeof(*eapol_pkt)); if (!skb) return NULL; + hdr = skb_put_zero(skb, sizeof(*hdr)); + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_FCTL_TODS | + IEEE80211_FCTL_PROTECTED); + ether_addr_copy(hdr->addr1, bss_conf->bssid); + ether_addr_copy(hdr->addr2, vif->addr); + ether_addr_copy(hdr->addr3, bss_conf->bssid); + + skb_put_zero(skb, sec_hdr_len); + eapol_pkt = skb_put_zero(skb, sizeof(*eapol_pkt)); - eapol_pkt->hdr.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | - IEEE80211_FCTL_TODS | - IEEE80211_FCTL_PROTECTED); - ether_addr_copy(eapol_pkt->hdr.addr1, bss_conf->bssid); - ether_addr_copy(eapol_pkt->hdr.addr2, vif->addr); - ether_addr_copy(eapol_pkt->hdr.addr3, bss_conf->bssid); memcpy(eapol_pkt->gtkbody, gtkbody, sizeof(gtkbody)); eapol_pkt->key_des_ver = key_des_ver; @@ -2233,20 +2237,26 @@ static struct sk_buff *rtw89_sa_query_get(struct rtw89_dev *rtwdev, { struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + u8 sec_hdr_len = rtw89_wow_get_sec_hdr_len(rtwdev); + struct ieee80211_hdr_3addr *hdr; struct rtw89_sa_query *sa_query; struct sk_buff *skb; - skb = dev_alloc_skb(sizeof(*sa_query)); + skb = dev_alloc_skb(sizeof(*hdr) + sec_hdr_len + sizeof(*sa_query)); if (!skb) return NULL; + hdr = skb_put_zero(skb, sizeof(*hdr)); + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ACTION | + IEEE80211_FCTL_PROTECTED); + ether_addr_copy(hdr->addr1, bss_conf->bssid); + ether_addr_copy(hdr->addr2, vif->addr); + ether_addr_copy(hdr->addr3, bss_conf->bssid); + + skb_put_zero(skb, sec_hdr_len); + sa_query = skb_put_zero(skb, sizeof(*sa_query)); - sa_query->hdr.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_ACTION | - IEEE80211_FCTL_PROTECTED); - ether_addr_copy(sa_query->hdr.addr1, bss_conf->bssid); - ether_addr_copy(sa_query->hdr.addr2, vif->addr); - ether_addr_copy(sa_query->hdr.addr3, bss_conf->bssid); sa_query->category = WLAN_CATEGORY_SA_QUERY; sa_query->action = WLAN_ACTION_SA_QUERY_RESPONSE; @@ -2256,17 +2266,19 @@ static struct sk_buff *rtw89_sa_query_get(struct rtw89_dev *rtwdev, static struct sk_buff *rtw89_arp_response_get(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { + u8 sec_hdr_len = rtw89_wow_get_sec_hdr_len(rtwdev); struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct ieee80211_hdr_3addr *hdr; struct rtw89_arp_rsp *arp_skb; struct arphdr *arp_hdr; struct sk_buff *skb; __le16 fc; - skb = dev_alloc_skb(sizeof(struct rtw89_arp_rsp)); + skb = dev_alloc_skb(sizeof(*hdr) + sec_hdr_len + sizeof(*arp_skb)); if (!skb) return NULL; - arp_skb = skb_put_zero(skb, sizeof(*arp_skb)); + hdr = skb_put_zero(skb, sizeof(*hdr)); if (rtw_wow->ptk_alg) fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS | @@ -2274,11 +2286,14 @@ static struct sk_buff *rtw89_arp_response_get(struct rtw89_dev *rtwdev, else fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS); - arp_skb->addr.frame_control = fc; - ether_addr_copy(arp_skb->addr.addr1, rtwvif->bssid); - ether_addr_copy(arp_skb->addr.addr2, rtwvif->mac_addr); - ether_addr_copy(arp_skb->addr.addr3, rtwvif->bssid); + hdr->frame_control = fc; + ether_addr_copy(hdr->addr1, rtwvif->bssid); + ether_addr_copy(hdr->addr2, rtwvif->mac_addr); + ether_addr_copy(hdr->addr3, rtwvif->bssid); + skb_put_zero(skb, sec_hdr_len); + + arp_skb = skb_put_zero(skb, sizeof(*arp_skb)); memcpy(arp_skb->llc_hdr, rfc1042_header, sizeof(rfc1042_header)); arp_skb->llc_type = htons(ETH_P_ARP); diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index fa61484c3839..df22a53b8f41 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -27,17 +27,23 @@ void rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb) rtw_wow->akm = rsn_ie->akm_cipher_suite.type; } +#define RTW89_CIPHER_INFO_DEF(cipher) \ + {WLAN_CIPHER_SUITE_ ## cipher, .fw_alg = RTW89_WOW_FW_ALG_ ## cipher, \ + .len = WLAN_KEY_LEN_ ## cipher} + static const struct rtw89_cipher_info rtw89_cipher_info_defs[] = { - {WLAN_CIPHER_SUITE_WEP40, .fw_alg = 1, .len = WLAN_KEY_LEN_WEP40,}, - {WLAN_CIPHER_SUITE_WEP104, .fw_alg = 2, .len = WLAN_KEY_LEN_WEP104,}, - {WLAN_CIPHER_SUITE_TKIP, .fw_alg = 3, .len = WLAN_KEY_LEN_TKIP,}, - {WLAN_CIPHER_SUITE_CCMP, .fw_alg = 6, .len = WLAN_KEY_LEN_CCMP,}, - {WLAN_CIPHER_SUITE_GCMP, .fw_alg = 8, .len = WLAN_KEY_LEN_GCMP,}, - {WLAN_CIPHER_SUITE_CCMP_256, .fw_alg = 7, .len = WLAN_KEY_LEN_CCMP_256,}, - {WLAN_CIPHER_SUITE_GCMP_256, .fw_alg = 23, .len = WLAN_KEY_LEN_GCMP_256,}, - {WLAN_CIPHER_SUITE_AES_CMAC, .fw_alg = 32, .len = WLAN_KEY_LEN_AES_CMAC,}, + RTW89_CIPHER_INFO_DEF(WEP40), + RTW89_CIPHER_INFO_DEF(WEP104), + RTW89_CIPHER_INFO_DEF(TKIP), + RTW89_CIPHER_INFO_DEF(CCMP), + RTW89_CIPHER_INFO_DEF(GCMP), + RTW89_CIPHER_INFO_DEF(CCMP_256), + RTW89_CIPHER_INFO_DEF(GCMP_256), + RTW89_CIPHER_INFO_DEF(AES_CMAC), }; +#undef RTW89_CIPHER_INFO_DEF + static const struct rtw89_cipher_info *rtw89_cipher_alg_recognize(u32 cipher) { diff --git a/drivers/net/wireless/realtek/rtw89/wow.h b/drivers/net/wireless/realtek/rtw89/wow.h index e595aee0196d..0d90add0e88d 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.h +++ b/drivers/net/wireless/realtek/rtw89/wow.h @@ -35,6 +35,17 @@ enum rtw89_wake_reason { RTW89_WOW_RSN_RX_NLO = 0x55, }; +enum rtw89_fw_alg { + RTW89_WOW_FW_ALG_WEP40 = 0x1, + RTW89_WOW_FW_ALG_WEP104 = 0x2, + RTW89_WOW_FW_ALG_TKIP = 0x3, + RTW89_WOW_FW_ALG_CCMP = 0x6, + RTW89_WOW_FW_ALG_CCMP_256 = 0x7, + RTW89_WOW_FW_ALG_GCMP = 0x8, + RTW89_WOW_FW_ALG_GCMP_256 = 0x9, + RTW89_WOW_FW_ALG_AES_CMAC = 0xa, +}; + struct rtw89_cipher_suite { u8 oui[3]; u8 type; @@ -64,6 +75,25 @@ struct rtw89_set_key_info_iter_data { bool error; }; +static inline int rtw89_wow_get_sec_hdr_len(struct rtw89_dev *rtwdev) +{ + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + + if (!(rtwdev->chip->chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev))) + return 0; + + switch (rtw_wow->ptk_alg) { + case RTW89_WOW_FW_ALG_WEP40: + return 4; + case RTW89_WOW_FW_ALG_TKIP: + case RTW89_WOW_FW_ALG_CCMP: + case RTW89_WOW_FW_ALG_GCMP_256: + return 8; + default: + return 0; + } +} + #ifdef CONFIG_PM int rtw89_wow_suspend(struct rtw89_dev *rtwdev, struct cfg80211_wowlan *wowlan); int rtw89_wow_resume(struct rtw89_dev *rtwdev); From 0e5210217768625b43f099bcaafe627b098655d5 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 20 Jun 2024 13:58:20 +0800 Subject: [PATCH 041/204] wifi: rtw89: wow: update WoWLAN reason register for different FW Need to update WoWLAN wakeup reason register after firmware version 0.35.22.0 for RTL8922A, and 0.27.80.0 for RTL8852CE. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240620055825.17592-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 3 ++- drivers/net/wireless/realtek/rtw89/fw.c | 2 ++ drivers/net/wireless/realtek/rtw89/fw.h | 6 ++++++ drivers/net/wireless/realtek/rtw89/reg.h | 4 ++++ drivers/net/wireless/realtek/rtw89/rtw8851b.c | 6 +++++- drivers/net/wireless/realtek/rtw89/rtw8852a.c | 6 +++++- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 6 +++++- drivers/net/wireless/realtek/rtw89/rtw8852c.c | 6 +++++- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 6 +++++- drivers/net/wireless/realtek/rtw89/wow.c | 7 ++++++- 10 files changed, 45 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index e8ec0246bccd..f1de975c5356 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4236,7 +4236,7 @@ struct rtw89_chip_info { const u32 *c2h_regs; struct rtw89_reg_def c2h_counter_reg; const struct rtw89_page_regs *page_regs; - u32 wow_reason_reg; + const u32 *wow_reason_reg; bool cfo_src_fd; bool cfo_hw_comp; const struct rtw89_reg_def *dcfo_comp; @@ -4346,6 +4346,7 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_NO_LPS_PG, RTW89_FW_FEATURE_BEACON_FILTER, RTW89_FW_FEATURE_MACID_PAUSE_SLEEP, + RTW89_FW_FEATURE_WOW_REASON_V1, }; struct rtw89_fw_suit { diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 3c666fd0f8ed..a907d381ac77 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -675,10 +675,12 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __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, 56, 10, BEACON_FILTER), + __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 80, 0, WOW_REASON_V1), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER), __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, ge, 0, 35, 12, 0, BEACON_FILTER), + __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 22, 0, WOW_REASON_V1), }; static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw, diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 01fea0b004d3..c3b4324c621c 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -4659,4 +4659,10 @@ const struct rtw89_rfe_parms * rtw89_load_rfe_data_from_fw(struct rtw89_dev *rtwdev, const struct rtw89_rfe_parms *init); +enum rtw89_wow_wakeup_ver { + RTW89_WOW_REASON_V0, + RTW89_WOW_REASON_V1, + RTW89_WOW_REASON_NUM, +}; + #endif diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 5a59234301ca..fd81cf863bea 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -311,6 +311,8 @@ #define B_AX_S1_LDO2PWRCUT_F BIT(23) #define B_AX_S0_LDO_VSEL_F_MASK GENMASK(22, 21) +#define R_AX_DBG_WOW 0x0504 + #define R_AX_SEC_CTRL 0x0C00 #define B_AX_SEC_IDMEM_SIZE_CONFIG_MASK GENMASK(17, 16) @@ -4315,6 +4317,8 @@ #define R_BE_WLCPU_PORT_PC 0x03FC +#define R_BE_DBG_WOW 0x0504 + #define R_BE_DCPU_PLATFORM_ENABLE 0x0888 #define B_BE_DCPU_SYM_DPLT_MEM_MUX_EN BIT(10) #define B_BE_DCPU_WARM_EN BIT(9) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 78e276f321c2..40cf84a79c46 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -105,6 +105,10 @@ static const u32 rtw8851b_c2h_regs[RTW89_C2HREG_MAX] = { R_AX_C2HREG_DATA3 }; +static const u32 rtw8851b_wow_wakeup_regs[RTW89_WOW_REASON_NUM] = { + R_AX_C2HREG_DATA3 + 3, R_AX_C2HREG_DATA3 + 3, +}; + static const struct rtw89_page_regs rtw8851b_page_regs = { .hci_fc_ctrl = R_AX_HCI_FC_CTRL, .ch_page_ctrl = R_AX_CH_PAGE_CTRL, @@ -2509,7 +2513,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .c2h_counter_reg = {R_AX_UDM1 + 1, B_AX_UDM1_HALMAC_C2H_ENQ_CNT_MASK >> 8}, .c2h_regs = rtw8851b_c2h_regs, .page_regs = &rtw8851b_page_regs, - .wow_reason_reg = R_AX_C2HREG_DATA3 + 3, + .wow_reason_reg = rtw8851b_wow_wakeup_regs, .cfo_src_fd = true, .cfo_hw_comp = true, .dcfo_comp = &rtw8851b_dcfo_comp, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index aebbceea93f8..08e148328c62 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -398,6 +398,10 @@ static const u32 rtw8852a_c2h_regs[RTW89_C2HREG_MAX] = { R_AX_C2HREG_DATA3 }; +static const u32 rtw8852a_wow_wakeup_regs[RTW89_WOW_REASON_NUM] = { + R_AX_C2HREG_DATA3 + 3, R_AX_C2HREG_DATA3 + 3, +}; + static const struct rtw89_page_regs rtw8852a_page_regs = { .hci_fc_ctrl = R_AX_HCI_FC_CTRL, .ch_page_ctrl = R_AX_CH_PAGE_CTRL, @@ -2225,7 +2229,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .c2h_regs = rtw8852a_c2h_regs, .c2h_counter_reg = {R_AX_UDM1 + 1, B_AX_UDM1_HALMAC_C2H_ENQ_CNT_MASK >> 8}, .page_regs = &rtw8852a_page_regs, - .wow_reason_reg = R_AX_C2HREG_DATA3 + 3, + .wow_reason_reg = rtw8852a_wow_wakeup_regs, .cfo_src_fd = false, .cfo_hw_comp = false, .dcfo_comp = &rtw8852a_dcfo_comp, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 381c881fee69..24f9fd444ca0 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -76,6 +76,10 @@ static const u32 rtw8852b_c2h_regs[RTW89_C2HREG_MAX] = { R_AX_C2HREG_DATA3 }; +static const u32 rtw8852b_wow_wakeup_regs[RTW89_WOW_REASON_NUM] = { + R_AX_C2HREG_DATA3 + 3, R_AX_C2HREG_DATA3 + 3, +}; + static const struct rtw89_page_regs rtw8852b_page_regs = { .hci_fc_ctrl = R_AX_HCI_FC_CTRL, .ch_page_ctrl = R_AX_CH_PAGE_CTRL, @@ -1026,7 +1030,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .c2h_counter_reg = {R_AX_UDM1 + 1, B_AX_UDM1_HALMAC_C2H_ENQ_CNT_MASK >> 8}, .c2h_regs = rtw8852b_c2h_regs, .page_regs = &rtw8852b_page_regs, - .wow_reason_reg = R_AX_C2HREG_DATA3 + 3, + .wow_reason_reg = rtw8852b_wow_wakeup_regs, .cfo_src_fd = true, .cfo_hw_comp = true, .dcfo_comp = &rtw8852b_dcfo_comp, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 544ea1d3b577..193168dc7b6c 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -73,6 +73,10 @@ static const u32 rtw8852c_c2h_regs[RTW89_H2CREG_MAX] = { R_AX_C2HREG_DATA3_V1 }; +static const u32 rtw8852c_wow_wakeup_regs[RTW89_WOW_REASON_NUM] = { + R_AX_C2HREG_DATA3_V1 + 3, R_AX_DBG_WOW, +}; + static const struct rtw89_page_regs rtw8852c_page_regs = { .hci_fc_ctrl = R_AX_HCI_FC_CTRL_V1, .ch_page_ctrl = R_AX_CH_PAGE_CTRL_V1, @@ -3007,7 +3011,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .c2h_counter_reg = {R_AX_UDM1 + 1, B_AX_UDM1_HALMAC_C2H_ENQ_CNT_MASK >> 8}, .c2h_regs = rtw8852c_c2h_regs, .page_regs = &rtw8852c_page_regs, - .wow_reason_reg = R_AX_C2HREG_DATA3_V1 + 3, + .wow_reason_reg = rtw8852c_wow_wakeup_regs, .cfo_src_fd = false, .cfo_hw_comp = false, .dcfo_comp = &rtw8852c_dcfo_comp, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index cc4f251caadd..2af568a3264d 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -85,6 +85,10 @@ static const u32 rtw8922a_c2h_regs[RTW89_H2CREG_MAX] = { R_BE_C2HREG_DATA3 }; +static const u32 rtw8922a_wow_wakeup_regs[RTW89_WOW_REASON_NUM] = { + R_AX_C2HREG_DATA3_V1 + 3, R_BE_DBG_WOW, +}; + static const struct rtw89_page_regs rtw8922a_page_regs = { .hci_fc_ctrl = R_BE_HCI_FC_CTRL, .ch_page_ctrl = R_BE_CH_PAGE_CTRL, @@ -2609,7 +2613,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .c2h_counter_reg = {R_BE_UDM1 + 1, B_BE_UDM1_HALMAC_C2H_ENQ_CNT_MASK >> 8}, .c2h_regs = rtw8922a_c2h_regs, .page_regs = &rtw8922a_page_regs, - .wow_reason_reg = R_AX_C2HREG_DATA3_V1 + 3, + .wow_reason_reg = rtw8922a_wow_wakeup_regs, .cfo_src_fd = true, .cfo_hw_comp = true, .dcfo_comp = NULL, diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index df22a53b8f41..a49265cda98f 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -723,13 +723,18 @@ static void rtw89_wow_show_wakeup_reason(struct rtw89_dev *rtwdev) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct rtw89_wow_aoac_report *aoac_rpt = &rtw_wow->aoac_rpt; - u32 wow_reason_reg = rtwdev->chip->wow_reason_reg; struct cfg80211_wowlan_nd_info nd_info; struct cfg80211_wowlan_wakeup wakeup = { .pattern_idx = -1, }; + u32 wow_reason_reg; u8 reason; + if (RTW89_CHK_FW_FEATURE(WOW_REASON_V1, &rtwdev->fw)) + wow_reason_reg = rtwdev->chip->wow_reason_reg[RTW89_WOW_REASON_V1]; + else + wow_reason_reg = rtwdev->chip->wow_reason_reg[RTW89_WOW_REASON_V0]; + reason = rtw89_read8(rtwdev, wow_reason_reg); switch (reason) { case RTW89_WOW_RSN_RX_DEAUTH: From 6a03a349be1b2b8de06e725329d11448e11766d5 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 20 Jun 2024 13:58:21 +0800 Subject: [PATCH 042/204] wifi: rtw89: wow: update config mac for 802.11ax chip The 802.11ax chip also needs rtw89_mac_cpu_io_rx(), which notifies Firmware to start or stop WoWLAN and waits until Firmware process over. Then, the driver can continue processing to avoid unexpected behavior. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240620055825.17592-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 29 +++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/mac.h | 1 + drivers/net/wireless/realtek/rtw89/mac_be.c | 20 -------------- drivers/net/wireless/realtek/rtw89/reg.h | 1 + 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index b759fa8fbca9..73462f3343e3 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -6320,9 +6320,30 @@ int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev, return ret; } +int rtw89_mac_cpu_io_rx(struct rtw89_dev *rtwdev, bool wow_enable) +{ + struct rtw89_mac_h2c_info h2c_info = {}; + struct rtw89_mac_c2h_info c2h_info = {}; + u32 ret; + + h2c_info.id = RTW89_FWCMD_H2CREG_FUNC_WOW_CPUIO_RX_CTRL; + h2c_info.content_len = sizeof(h2c_info.u.hdr); + h2c_info.u.hdr.w0 = u32_encode_bits(wow_enable, RTW89_H2CREG_WOW_CPUIO_RX_CTRL_EN); + + ret = rtw89_fw_msg_reg(rtwdev, &h2c_info, &c2h_info); + if (ret) + return ret; + + if (c2h_info.id != RTW89_FWCMD_C2HREG_FUNC_WOW_CPUIO_RX_ACK) + ret = -EINVAL; + + return ret; +} + static int rtw89_wow_config_mac_ax(struct rtw89_dev *rtwdev, bool enable_wow) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + const struct rtw89_chip_info *chip = rtwdev->chip; int ret; if (enable_wow) { @@ -6333,12 +6354,19 @@ static int rtw89_wow_config_mac_ax(struct rtw89_dev *rtwdev, bool enable_wow) } rtw89_write32_set(rtwdev, R_AX_RX_FUNCTION_STOP, B_AX_HDR_RX_STOP); + rtw89_mac_cpu_io_rx(rtwdev, enable_wow); rtw89_write32_clr(rtwdev, mac->rx_fltr, B_AX_SNIFFER_MODE); rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, false); rtw89_write32(rtwdev, R_AX_ACTION_FWD0, 0); rtw89_write32(rtwdev, R_AX_ACTION_FWD1, 0); rtw89_write32(rtwdev, R_AX_TF_FWD, 0); rtw89_write32(rtwdev, R_AX_HW_RPT_FWD, 0); + + if (chip->chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) + rtw89_write8(rtwdev, R_BE_DBG_WOW_READY, WOWLAN_NOT_READY); + else + rtw89_write32_set(rtwdev, R_AX_DBG_WOW, + B_AX_DBG_WOW_CPU_IO_RX_EN); } else { ret = rtw89_mac_resize_ple_rx_quota(rtwdev, false); if (ret) { @@ -6346,6 +6374,7 @@ static int rtw89_wow_config_mac_ax(struct rtw89_dev *rtwdev, bool enable_wow) return ret; } + rtw89_mac_cpu_io_rx(rtwdev, enable_wow); rtw89_write32_clr(rtwdev, R_AX_RX_FUNCTION_STOP, B_AX_HDR_RX_STOP); rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true); rtw89_write32(rtwdev, R_AX_ACTION_FWD0, TRXCFG_MPDU_PROC_ACT_FRWD); diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index a580cb719233..cc9f914d440c 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -1446,5 +1446,6 @@ int rtw89_mac_dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mod int rtw89_mac_get_dle_rsvd_qt_cfg(struct rtw89_dev *rtwdev, enum rtw89_mac_dle_rsvd_qt_type type, struct rtw89_mac_dle_rsvd_qt_cfg *cfg); +int rtw89_mac_cpu_io_rx(struct rtw89_dev *rtwdev, bool wow_enable); #endif diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 934bdf3b398f..f212b67771d5 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -2312,26 +2312,6 @@ static void rtw89_mac_dump_qta_lost_be(struct rtw89_dev *rtwdev) dump_err_status_dispatcher_be(rtwdev); } -static int rtw89_mac_cpu_io_rx(struct rtw89_dev *rtwdev, bool wow_enable) -{ - struct rtw89_mac_h2c_info h2c_info = {}; - struct rtw89_mac_c2h_info c2h_info = {}; - u32 ret; - - h2c_info.id = RTW89_FWCMD_H2CREG_FUNC_WOW_CPUIO_RX_CTRL; - h2c_info.content_len = sizeof(h2c_info.u.hdr); - h2c_info.u.hdr.w0 = u32_encode_bits(wow_enable, RTW89_H2CREG_WOW_CPUIO_RX_CTRL_EN); - - ret = rtw89_fw_msg_reg(rtwdev, &h2c_info, &c2h_info); - if (ret) - return ret; - - if (c2h_info.id != RTW89_FWCMD_C2HREG_FUNC_WOW_CPUIO_RX_ACK) - ret = -EINVAL; - - return ret; -} - static int rtw89_wow_config_mac_be(struct rtw89_dev *rtwdev, bool enable_wow) { if (enable_wow) { diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index fd81cf863bea..c9f6bdc84d03 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -312,6 +312,7 @@ #define B_AX_S0_LDO_VSEL_F_MASK GENMASK(22, 21) #define R_AX_DBG_WOW 0x0504 +#define B_AX_DBG_WOW_CPU_IO_RX_EN BIT(8) #define R_AX_SEC_CTRL 0x0C00 #define B_AX_SEC_IDMEM_SIZE_CONFIG_MASK GENMASK(17, 16) From dda364c345913fe03ddbe4d5ae14a2754c100296 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 20 Jun 2024 13:58:22 +0800 Subject: [PATCH 043/204] wifi: rtw89: wow: fix GTK offload H2C skbuff issue We mistakenly put skb too large and that may exceed skb->end. Therefore, we fix it. skbuff: skb_over_panic: text:ffffffffc09e9a9d len:416 put:204 head:ffff8fba04eca780 data:ffff8fba04eca7e0 tail:0x200 end:0x140 dev: ------------[ cut here ]------------ kernel BUG at net/core/skbuff.c:192! invalid opcode: 0000 [#1] PREEMPT SMP PTI CPU: 1 PID: 4747 Comm: kworker/u4:44 Tainted: G O 6.6.30-02659-gc18865c4dfbd #1 86547039b47e46935493f615ee31d0b2d711d35e Hardware name: HP Meep/Meep, BIOS Google_Meep.11297.262.0 03/18/2021 Workqueue: events_unbound async_run_entry_fn RIP: 0010:skb_panic+0x5d/0x60 Code: c6 63 8b 8f bb 4c 0f 45 f6 48 c7 c7 4d 89 8b bb 48 89 ce 44 89 d1 41 56 53 41 53 ff b0 c8 00 00 00 e8 27 5f 23 00 48 83 c4 20 <0f> 0b 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 0f 1f 44 RSP: 0018:ffffaa700144bad0 EFLAGS: 00010282 RAX: 0000000000000089 RBX: 0000000000000140 RCX: 14432c5aad26c900 RDX: 0000000000000000 RSI: 00000000ffffdfff RDI: 0000000000000001 RBP: ffffaa700144bae0 R08: 0000000000000000 R09: ffffaa700144b920 R10: 00000000ffffdfff R11: ffffffffbc28fbc0 R12: ffff8fba4e57a010 R13: 0000000000000000 R14: ffffffffbb8f8b63 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffff8fba7bd00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007999c4ad1000 CR3: 000000015503a000 CR4: 0000000000350ee0 Call Trace: ? __die_body+0x1f/0x70 ? die+0x3d/0x60 ? do_trap+0xa4/0x110 ? skb_panic+0x5d/0x60 ? do_error_trap+0x6d/0x90 ? skb_panic+0x5d/0x60 ? handle_invalid_op+0x30/0x40 ? skb_panic+0x5d/0x60 ? exc_invalid_op+0x3c/0x50 ? asm_exc_invalid_op+0x16/0x20 ? skb_panic+0x5d/0x60 skb_put+0x49/0x50 rtw89_fw_h2c_wow_gtk_ofld+0xbd/0x220 [rtw89_core 778b32de31cd1f14df2d6721ae99ba8a83636fa5] rtw89_wow_resume+0x31f/0x540 [rtw89_core 778b32de31cd1f14df2d6721ae99ba8a83636fa5] rtw89_ops_resume+0x2b/0xa0 [rtw89_core 778b32de31cd1f14df2d6721ae99ba8a83636fa5] ieee80211_reconfig+0x84/0x13e0 [mac80211 818a894e3b77da6298269c59ed7cdff065a4ed52] ? __pfx_wiphy_resume+0x10/0x10 [cfg80211 1a793119e2aeb157c4ca4091ff8e1d9ae233b59d] ? dev_printk_emit+0x51/0x70 ? _dev_info+0x6e/0x90 ? __pfx_wiphy_resume+0x10/0x10 [cfg80211 1a793119e2aeb157c4ca4091ff8e1d9ae233b59d] wiphy_resume+0x89/0x180 [cfg80211 1a793119e2aeb157c4ca4091ff8e1d9ae233b59d] ? __pfx_wiphy_resume+0x10/0x10 [cfg80211 1a793119e2aeb157c4ca4091ff8e1d9ae233b59d] dpm_run_callback+0x3c/0x140 device_resume+0x1f9/0x3c0 ? __pfx_dpm_watchdog_handler+0x10/0x10 async_resume+0x1d/0x30 async_run_entry_fn+0x29/0xd0 process_scheduled_works+0x1d8/0x3d0 worker_thread+0x1fc/0x2f0 kthread+0xed/0x110 ? __pfx_worker_thread+0x10/0x10 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x38/0x50 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1b/0x30 Modules linked in: ccm 8021q r8153_ecm cdc_ether usbnet r8152 mii dm_integrity async_xor xor async_tx lz4 lz4_compress zstd zstd_compress zram zsmalloc uinput rfcomm cmac algif_hash rtw89_8922ae(O) algif_skcipher rtw89_8922a(O) af_alg rtw89_pci(O) rtw89_core(O) btusb(O) snd_soc_sst_bxt_da7219_max98357a btbcm(O) snd_soc_hdac_hdmi btintel(O) snd_soc_intel_hda_dsp_common snd_sof_probes btrtl(O) btmtk(O) snd_hda_codec_hdmi snd_soc_dmic uvcvideo videobuf2_vmalloc uvc videobuf2_memops videobuf2_v4l2 videobuf2_common snd_sof_pci_intel_apl snd_sof_intel_hda_common snd_soc_hdac_hda snd_sof_intel_hda soundwire_intel soundwire_generic_allocation snd_sof_intel_hda_mlink soundwire_cadence snd_sof_pci snd_sof_xtensa_dsp mac80211 snd_soc_acpi_intel_match snd_soc_acpi snd_sof snd_sof_utils soundwire_bus snd_soc_max98357a snd_soc_avs snd_soc_hda_codec snd_hda_ext_core snd_intel_dspcfg snd_intel_sdw_acpi snd_soc_da7219 snd_hda_codec snd_hwdep snd_hda_core veth ip6table_nat xt_MASQUERADE xt_cgroup fuse bluetooth ecdh_generic cfg80211 ecc gsmi: Log Shutdown Reason 0x03 ---[ end trace 0000000000000000 ]--- Fixes: ed9a3c0d4dd9 ("wifi: rtw89: wow: construct EAPoL packet for GTK rekey offload") Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240620055825.17592-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index a907d381ac77..e3fc9f168ae5 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -6767,10 +6767,8 @@ int rtw89_fw_h2c_wow_gtk_ofld(struct rtw89_dev *rtwdev, skb_put(skb, len); h2c = (struct rtw89_h2c_wow_gtk_ofld *)skb->data; - if (!enable) { - skb_put_zero(skb, sizeof(*gtk_info)); + if (!enable) goto hdr; - } ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, RTW89_PKT_OFLD_TYPE_EAPOL_KEY, From 60757f28408bcc63c4c0676b2a69a38adce30fc7 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 20 Jun 2024 13:58:23 +0800 Subject: [PATCH 044/204] wifi: rtw89: wow: prevent to send unexpected H2C during download Firmware While downloading Firmware in the resume flow, it is possible to receive beacon and send H2C to Firmware. However, if Firmware receives unexpected H2C during the download process, it will fail. Therefore, we prevent to send unexpected H2C during download Firmware in WoWLAN mode. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240620055825.17592-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 87c38cdc691b..4acd4301d3c2 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1921,7 +1921,8 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, return; if (ieee80211_is_beacon(hdr->frame_control)) { - if (vif->type == NL80211_IFTYPE_STATION) { + if (vif->type == NL80211_IFTYPE_STATION && + !test_bit(RTW89_FLAG_WOWLAN, rtwdev->flags)) { rtw89_vif_sync_bcn_tsf(rtwvif, hdr, skb->len); rtw89_fw_h2c_rssi_offload(rtwdev, phy_ppdu); } From 2e2564877f57368c69a1ff09504447db63fb0640 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 20 Jun 2024 13:58:24 +0800 Subject: [PATCH 045/204] wifi: rtw89: wow: enable beacon filter after swapping firmware To avoid wake up by AP disconnection, but no beacon filter setting and driver can't disconnect successfully. We need to enable beacon filter after swapping firmware in WoWLAN mode. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240620055825.17592-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/wow.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index a49265cda98f..9882064ef68d 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -1295,12 +1295,16 @@ static int rtw89_wow_disable_trx_pre(struct rtw89_dev *rtwdev) static int rtw89_wow_disable_trx_post(struct rtw89_dev *rtwdev) { + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct ieee80211_vif *vif = rtw_wow->wow_vif; int ret; ret = rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true); if (ret) rtw89_err(rtwdev, "cfg ppdu status\n"); + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, true); + return ret; } From 792586591f446c688821989a21ea3e65f192e6f1 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 20 Jun 2024 13:58:25 +0800 Subject: [PATCH 046/204] wifi: rtw89: add polling for LPS H2C to ensure FW received We add polling after sending LPS H2C to ensure that the Firmware is received and executes RPWM thereafter. Otherwise, if the Firmware executes RPWM without receiving LPS H2C, it will cause beacon loss in WoWLAN mode due to the inability to obtain channel and bandwidth information from H2C. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240620055825.17592-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 7 +++++++ drivers/net/wireless/realtek/rtw89/reg.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index e3fc9f168ae5..fbe08c162b93 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -2496,6 +2496,7 @@ int rtw89_fw_h2c_lps_ch_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) struct rtw89_h2c_lps_ch_info *h2c; u32 len = sizeof(*h2c); struct sk_buff *skb; + u32 done; int ret; if (chip->chip_gen != RTW89_CHIP_BE) @@ -2519,12 +2520,18 @@ int rtw89_fw_h2c_lps_ch_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) H2C_CAT_OUTSRC, H2C_CL_OUTSRC_DM, H2C_FUNC_FW_LPS_CH_INFO, 0, 0, len); + rtw89_phy_write32_mask(rtwdev, R_CHK_LPS_STAT, B_CHK_LPS_STAT, 0); ret = rtw89_h2c_tx(rtwdev, skb, false); if (ret) { rtw89_err(rtwdev, "failed to send h2c\n"); goto fail; } + ret = read_poll_timeout(rtw89_phy_read32_mask, done, done, 50, 5000, + true, rtwdev, R_CHK_LPS_STAT, B_CHK_LPS_STAT); + if (ret) + rtw89_warn(rtwdev, "h2c_lps_ch_info done polling timeout\n"); + return 0; fail: dev_kfree_skb_any(skb); diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index c9f6bdc84d03..897884e9667f 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -7818,6 +7818,8 @@ #define B_UPD_P0_EN BIT(31) #define R_EMLSR 0x0044 #define B_EMLSR_PARM GENMASK(27, 12) +#define R_CHK_LPS_STAT 0x0058 +#define B_CHK_LPS_STAT BIT(0) #define R_SPOOF_CG 0x00B4 #define B_SPOOF_CG_EN BIT(17) #define R_CHINFO_SEG 0x00B4 From 9f8852a92e8270c1684117753fcd114e7563a93d Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 21 Jun 2024 15:34:57 +0800 Subject: [PATCH 047/204] wifi: rtw89: 8852bt: rfk: add TSSI TSSI is transmitter signal strength indication, which is a close-loop hardware circuit to feedback actual transmitting power as a reference for next transmission. It does full calibration when we are going to connect an AP. When switching bands or channels for scanning or some reasons, reset hardware status to prevent use wrong power value feedback from previous transmission. It also loads tables of compensation values reflecting current temperature into registers according to channel and band group to transmit packets with expected power. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240621073458.55187-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 1 + .../net/wireless/realtek/rtw89/rtw8852bt.h | 13 + .../wireless/realtek/rtw89/rtw8852bt_rfk.c | 1207 +++++++++++++++++ .../wireless/realtek/rtw89/rtw8852bt_rfk.h | 15 + .../realtek/rtw89/rtw8852bt_rfk_table.c | 490 +++++++ .../realtek/rtw89/rtw8852bt_rfk_table.h | 38 + 6 files changed, 1764 insertions(+) create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852bt.h create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk_table.c create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk_table.h diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 897884e9667f..ed4964312063 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -9017,6 +9017,7 @@ #define R_IQRSN 0x8220 #define B_IQRSN_K1 BIT(28) #define B_IQRSN_K2 BIT(16) +#define R_DPD_CH0B 0x82BC #define R_RXCFIR_P0C0 0x8D40 #define R_RXCFIR_P0C1 0x8D84 #define R_RXCFIR_P0C2 0x8DC8 diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.h b/drivers/net/wireless/realtek/rtw89/rtw8852bt.h new file mode 100644 index 000000000000..6177f36ad667 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2024 Realtek Corporation + */ + +#ifndef __RTW89_8852BT_H__ +#define __RTW89_8852BT_H__ + +#include "core.h" + +#define RF_PATH_NUM_8852BT 2 +#define BB_PATH_NUM_8852BT 2 + +#endif diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c new file mode 100644 index 000000000000..dcc15797f5db --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c @@ -0,0 +1,1207 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2024 Realtek Corporation + */ + +#include "coex.h" +#include "debug.h" +#include "fw.h" +#include "mac.h" +#include "phy.h" +#include "reg.h" +#include "rtw8852bt.h" +#include "rtw8852bt_rfk.h" +#include "rtw8852bt_rfk_table.h" +#include "rtw8852b_common.h" + +#define RTW8852BT_TSSI_PATH_NR 2 + +#define _TSSI_DE_MASK GENMASK(21, 12) + +static const u32 _tssi_trigger[RTW8852BT_TSSI_PATH_NR] = {0x5820, 0x7820}; +static const u32 _tssi_cw_rpt_addr[RTW8852BT_TSSI_PATH_NR] = {0x1c18, 0x3c18}; +static const u32 _tssi_cw_default_addr[RTW8852BT_TSSI_PATH_NR][4] = { + {0x5634, 0x5630, 0x5630, 0x5630}, + {0x7634, 0x7630, 0x7630, 0x7630} }; +static const u32 _tssi_cw_default_mask[4] = { + 0x000003ff, 0x3ff00000, 0x000ffc00, 0x000003ff}; +static const u32 _tssi_de_cck_long[RF_PATH_NUM_8852BT] = {0x5858, 0x7858}; +static const u32 _tssi_de_cck_short[RF_PATH_NUM_8852BT] = {0x5860, 0x7860}; +static const u32 _tssi_de_mcs_20m[RF_PATH_NUM_8852BT] = {0x5838, 0x7838}; +static const u32 _tssi_de_mcs_40m[RF_PATH_NUM_8852BT] = {0x5840, 0x7840}; +static const u32 _tssi_de_mcs_80m[RF_PATH_NUM_8852BT] = {0x5848, 0x7848}; +static const u32 _tssi_de_mcs_80m_80m[RF_PATH_NUM_8852BT] = {0x5850, 0x7850}; +static const u32 _tssi_de_mcs_5m[RF_PATH_NUM_8852BT] = {0x5828, 0x7828}; +static const u32 _tssi_de_mcs_10m[RF_PATH_NUM_8852BT] = {0x5830, 0x7830}; + +static u8 _kpath(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + u8 val; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RFK]dbcc_en: %x,PHY%d\n", + rtwdev->dbcc_en, phy_idx); + + if (!rtwdev->dbcc_en) { + val = RF_AB; + } else { + if (phy_idx == RTW89_PHY_0) + val = RF_A; + else + val = RF_B; + } + return val; +} + +static void _wait_rx_mode(struct rtw89_dev *rtwdev, u8 kpath) +{ + u32 rf_mode; + u8 path; + int ret; + + for (path = 0; path < RF_PATH_MAX; path++) { + if (!(kpath & BIT(path))) + continue; + + ret = read_poll_timeout_atomic(rtw89_read_rf, rf_mode, + rf_mode != 2, 2, 5000, false, + rtwdev, path, RR_MOD, RR_MOD_MASK); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RFK] Wait S%d to Rx mode!! (ret = %d)\n", path, ret); + } +} + +static void _tmac_tx_pause(struct rtw89_dev *rtwdev, enum rtw89_phy_idx band_idx, + bool is_pause) +{ + if (!is_pause) + return; + + _wait_rx_mode(rtwdev, _kpath(rtwdev, band_idx)); +} + +static void _tssi_dpk_off(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) +{ + rtw89_phy_write32_mask(rtwdev, R_DPD_CH0A, BIT(24), 0x0); + rtw89_phy_write32_mask(rtwdev, R_DPD_CH0B, BIT(24), 0x0); +} + +static void _tssi_rf_setting(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + enum rtw89_band band = chan->band_type; + + if (band == RTW89_BAND_2G) + rtw89_write_rf(rtwdev, path, RR_TXPOW, RR_TXPOW_TXG, 0x1); + else + rtw89_write_rf(rtwdev, path, RR_TXPOW, RR_TXPOW_TXA, 0x1); +} + +static void _tssi_set_sys(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + enum rtw89_band band = chan->band_type; + + rtw89_rfk_parser(rtwdev, &rtw8852bt_tssi_sys_defs_tbl); + + if (chan->band_width == RTW89_CHANNEL_WIDTH_80) + rtw89_phy_write32_mask(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_BW80, 0x1); + else + rtw89_phy_write32_mask(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_BW80, 0x0); + + if (path == RF_PATH_A) + rtw89_rfk_parser_by_cond(rtwdev, band == RTW89_BAND_2G, + &rtw8852bt_tssi_sys_a_defs_2g_tbl, + &rtw8852bt_tssi_sys_a_defs_5g_tbl); + else + rtw89_rfk_parser_by_cond(rtwdev, band == RTW89_BAND_2G, + &rtw8852bt_tssi_sys_b_defs_2g_tbl, + &rtw8852bt_tssi_sys_b_defs_5g_tbl); +} + +static void _tssi_ini_txpwr_ctrl_bb(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + rtw89_rfk_parser_by_cond(rtwdev, path == RF_PATH_A, + &rtw8852bt_tssi_init_txpwr_defs_a_tbl, + &rtw8852bt_tssi_init_txpwr_defs_b_tbl); +} + +static void _tssi_ini_txpwr_ctrl_bb_he_tb(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + rtw89_rfk_parser_by_cond(rtwdev, path == RF_PATH_A, + &rtw8852bt_tssi_init_txpwr_he_tb_defs_a_tbl, + &rtw8852bt_tssi_init_txpwr_he_tb_defs_b_tbl); +} + +static void _tssi_set_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + rtw89_rfk_parser_by_cond(rtwdev, path == RF_PATH_A, + &rtw8852bt_tssi_dck_defs_a_tbl, + &rtw8852bt_tssi_dck_defs_b_tbl); +} + +static void _tssi_set_tmeter_tbl(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ +#define RTW8852BT_TSSI_GET_VAL(ptr, idx) \ +({ \ + s8 *__ptr = (ptr); \ + u8 __idx = (idx), __i, __v; \ + u32 __val = 0; \ + for (__i = 0; __i < 4; __i++) { \ + __v = (__ptr[__idx + __i]); \ + __val |= (__v << (8 * __i)); \ + } \ + __val; \ +}) + struct rtw89_fw_txpwr_track_cfg *trk = rtwdev->fw.elm_info.txpwr_trk; + struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + u8 ch = chan->channel; + u8 subband = chan->subband_type; + const s8 *thm_up_a = NULL; + const s8 *thm_down_a = NULL; + const s8 *thm_up_b = NULL; + const s8 *thm_down_b = NULL; + u8 thermal = 0xff; + s8 thm_ofst[64] = {0}; + u32 tmp = 0; + u8 i, j; + + switch (subband) { + default: + case RTW89_CH_2G: + thm_up_a = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_2GA_P][0]; + thm_down_a = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_2GA_N][0]; + thm_up_b = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_2GB_P][0]; + thm_down_b = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_2GB_N][0]; + break; + case RTW89_CH_5G_BAND_1: + thm_up_a = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GA_P][0]; + thm_down_a = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GA_N][0]; + thm_up_b = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GB_P][0]; + thm_down_b = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GB_N][0]; + break; + case RTW89_CH_5G_BAND_3: + thm_up_a = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GA_P][1]; + thm_down_a = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GA_N][1]; + thm_up_b = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GB_P][1]; + thm_down_b = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GB_N][1]; + break; + case RTW89_CH_5G_BAND_4: + thm_up_a = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GA_P][2]; + thm_down_a = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GA_N][2]; + thm_up_b = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GB_P][2]; + thm_down_b = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GB_N][2]; + break; + } + + if (path == RF_PATH_A) { + thermal = tssi_info->thermal[RF_PATH_A]; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI] ch=%d thermal_pathA=0x%x\n", ch, thermal); + + rtw89_phy_write32_mask(rtwdev, R_P0_TMETER, B_P0_TMETER_DIS, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_TMETER, B_P0_TMETER_TRK, 0x1); + + if (thermal == 0xff) { + rtw89_phy_write32_mask(rtwdev, R_P0_TMETER, B_P0_TMETER, 32); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_VAL, 32); + + for (i = 0; i < 64; i += 4) { + rtw89_phy_write32(rtwdev, R_P0_TSSI_BASE + i, 0x0); + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI] write 0x%x val=0x%08x\n", + R_P0_TSSI_BASE + i, 0x0); + } + + } else { + rtw89_phy_write32_mask(rtwdev, R_P0_TMETER, B_P0_TMETER, + thermal); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_VAL, + thermal); + + i = 0; + for (j = 0; j < 32; j++) + thm_ofst[j] = i < DELTA_SWINGIDX_SIZE ? + -thm_down_a[i++] : + -thm_down_a[DELTA_SWINGIDX_SIZE - 1]; + + i = 1; + for (j = 63; j >= 32; j--) + thm_ofst[j] = i < DELTA_SWINGIDX_SIZE ? + thm_up_a[i++] : + thm_up_a[DELTA_SWINGIDX_SIZE - 1]; + + for (i = 0; i < 64; i += 4) { + tmp = RTW8852BT_TSSI_GET_VAL(thm_ofst, i); + rtw89_phy_write32(rtwdev, R_P0_TSSI_BASE + i, tmp); + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI] write 0x%x val=0x%08x\n", + 0x5c00 + i, tmp); + } + } + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, R_P0_RFCTM_RDY, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, R_P0_RFCTM_RDY, 0x0); + + } else { + thermal = tssi_info->thermal[RF_PATH_B]; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI] ch=%d thermal_pathB=0x%x\n", ch, thermal); + + rtw89_phy_write32_mask(rtwdev, R_P1_TMETER, B_P1_TMETER_DIS, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P1_TMETER, B_P1_TMETER_TRK, 0x1); + + if (thermal == 0xff) { + rtw89_phy_write32_mask(rtwdev, R_P1_TMETER, B_P1_TMETER, 32); + rtw89_phy_write32_mask(rtwdev, R_P1_RFCTM, B_P1_RFCTM_VAL, 32); + + for (i = 0; i < 64; i += 4) { + rtw89_phy_write32(rtwdev, R_TSSI_THOF + i, 0x0); + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI] write 0x%x val=0x%08x\n", + 0x7c00 + i, 0x0); + } + + } else { + rtw89_phy_write32_mask(rtwdev, R_P1_TMETER, B_P1_TMETER, + thermal); + rtw89_phy_write32_mask(rtwdev, R_P1_RFCTM, B_P1_RFCTM_VAL, + thermal); + + i = 0; + for (j = 0; j < 32; j++) + thm_ofst[j] = i < DELTA_SWINGIDX_SIZE ? + -thm_down_b[i++] : + -thm_down_b[DELTA_SWINGIDX_SIZE - 1]; + + i = 1; + for (j = 63; j >= 32; j--) + thm_ofst[j] = i < DELTA_SWINGIDX_SIZE ? + thm_up_b[i++] : + thm_up_b[DELTA_SWINGIDX_SIZE - 1]; + + for (i = 0; i < 64; i += 4) { + tmp = RTW8852BT_TSSI_GET_VAL(thm_ofst, i); + rtw89_phy_write32(rtwdev, R_TSSI_THOF + i, tmp); + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI] write 0x%x val=0x%08x\n", + 0x7c00 + i, tmp); + } + } + rtw89_phy_write32_mask(rtwdev, R_P1_RFCTM, R_P1_RFCTM_RDY, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P1_RFCTM, R_P1_RFCTM_RDY, 0x0); + } +#undef RTW8852BT_TSSI_GET_VAL +} + +static void _tssi_set_dac_gain_tbl(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + rtw89_rfk_parser_by_cond(rtwdev, path == RF_PATH_A, + &rtw8852bt_tssi_dac_gain_defs_a_tbl, + &rtw8852bt_tssi_dac_gain_defs_b_tbl); +} + +static void _tssi_slope_cal_org(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + enum rtw89_band band = chan->band_type; + + if (path == RF_PATH_A) + rtw89_rfk_parser_by_cond(rtwdev, band == RTW89_BAND_2G, + &rtw8852bt_tssi_slope_a_defs_2g_tbl, + &rtw8852bt_tssi_slope_a_defs_5g_tbl); + else + rtw89_rfk_parser_by_cond(rtwdev, band == RTW89_BAND_2G, + &rtw8852bt_tssi_slope_b_defs_2g_tbl, + &rtw8852bt_tssi_slope_b_defs_5g_tbl); +} + +static void _tssi_alignment_default(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, bool all) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + enum rtw89_band band = chan->band_type; + const struct rtw89_rfk_tbl *tbl = NULL; + u8 ch = chan->channel; + + if (path == RF_PATH_A) { + if (band == RTW89_BAND_2G) + tbl = &rtw8852bt_tssi_align_a_2g_all_defs_tbl; + else if (ch >= 36 && ch <= 64) + tbl = &rtw8852bt_tssi_align_a_5g1_all_defs_tbl; + else if (ch >= 100 && ch <= 144) + tbl = &rtw8852bt_tssi_align_a_5g2_all_defs_tbl; + else if (ch >= 149 && ch <= 177) + tbl = &rtw8852bt_tssi_align_a_5g3_all_defs_tbl; + } else { + if (ch >= 1 && ch <= 14) + tbl = &rtw8852bt_tssi_align_b_2g_all_defs_tbl; + else if (ch >= 36 && ch <= 64) + tbl = &rtw8852bt_tssi_align_b_5g1_all_defs_tbl; + else if (ch >= 100 && ch <= 144) + tbl = &rtw8852bt_tssi_align_b_5g2_all_defs_tbl; + else if (ch >= 149 && ch <= 177) + tbl = &rtw8852bt_tssi_align_b_5g3_all_defs_tbl; + } + + if (tbl) + rtw89_rfk_parser(rtwdev, tbl); +} + +static void _tssi_set_tssi_slope(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + rtw89_rfk_parser_by_cond(rtwdev, path == RF_PATH_A, + &rtw8852bt_tssi_slope_defs_a_tbl, + &rtw8852bt_tssi_slope_defs_b_tbl); +} + +static void _tssi_set_tssi_track(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + if (path == RF_PATH_A) + rtw89_phy_write32_mask(rtwdev, R_P0_TSSIC, B_P0_TSSIC_BYPASS, 0x0); + else + rtw89_phy_write32_mask(rtwdev, R_P1_TSSIC, B_P1_TSSIC_BYPASS, 0x0); +} + +static void _tssi_set_txagc_offset_mv_avg(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + rtw89_debug(rtwdev, RTW89_DBG_TSSI, "======>%s path=%d\n", __func__, + path); + + if (path == RF_PATH_A) + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_MV_AVG, + B_P0_TSSI_MV_MIX, 0x010); + else + rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_MV_AVG, + B_P1_RFCTM_DEL, 0x010); +} + +static void _tssi_enable(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) +{ + u8 i; + + for (i = 0; i < RF_PATH_NUM_8852BT; i++) { + _tssi_set_tssi_track(rtwdev, phy, i); + _tssi_set_txagc_offset_mv_avg(rtwdev, phy, i); + + if (i == RF_PATH_A) { + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_MV_AVG, + B_P0_TSSI_MV_CLR, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_AVG, + B_P0_TSSI_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_AVG, + B_P0_TSSI_EN, 0x1); + rtw89_write_rf(rtwdev, i, RR_TXGA_V1, + RR_TXGA_V1_TRK_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, + B_P0_TSSI_RFC, 0x3); + + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, + B_P0_TSSI_OFT, 0xc0); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, + B_P0_TSSI_OFT_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, + B_P0_TSSI_OFT_EN, 0x1); + + rtwdev->is_tssi_mode[RF_PATH_A] = true; + } else { + rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_MV_AVG, + B_P1_TSSI_MV_CLR, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_AVG, + B_P1_TSSI_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_AVG, + B_P1_TSSI_EN, 0x1); + rtw89_write_rf(rtwdev, i, RR_TXGA_V1, + RR_TXGA_V1_TRK_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_TRK, + B_P1_TSSI_RFC, 0x3); + + rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_TRK, + B_P1_TSSI_OFT, 0xc0); + rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_TRK, + B_P1_TSSI_OFT_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_TRK, + B_P1_TSSI_OFT_EN, 0x1); + + rtwdev->is_tssi_mode[RF_PATH_B] = true; + } + } +} + +static void _tssi_disable(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) +{ + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_AVG, B_P0_TSSI_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_RFC, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_MV_AVG, B_P0_TSSI_MV_CLR, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_AVG, B_P1_TSSI_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_TRK, B_P1_TSSI_RFC, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_MV_AVG, B_P1_TSSI_MV_CLR, 0x1); + + rtwdev->is_tssi_mode[RF_PATH_A] = false; + rtwdev->is_tssi_mode[RF_PATH_B] = false; +} + +static u32 _tssi_get_cck_group(struct rtw89_dev *rtwdev, u8 ch) +{ + switch (ch) { + case 1 ... 2: + return 0; + case 3 ... 5: + return 1; + case 6 ... 8: + return 2; + case 9 ... 11: + return 3; + case 12 ... 13: + return 4; + case 14: + return 5; + } + + return 0; +} + +#define TSSI_EXTRA_GROUP_BIT (BIT(31)) +#define TSSI_EXTRA_GROUP(idx) (TSSI_EXTRA_GROUP_BIT | (idx)) +#define IS_TSSI_EXTRA_GROUP(group) ((group) & TSSI_EXTRA_GROUP_BIT) +#define TSSI_EXTRA_GET_GROUP_IDX1(group) ((group) & ~TSSI_EXTRA_GROUP_BIT) +#define TSSI_EXTRA_GET_GROUP_IDX2(group) (TSSI_EXTRA_GET_GROUP_IDX1(group) + 1) + +static u32 _tssi_get_ofdm_group(struct rtw89_dev *rtwdev, u8 ch) +{ + switch (ch) { + case 1 ... 2: + return 0; + case 3 ... 5: + return 1; + case 6 ... 8: + return 2; + case 9 ... 11: + return 3; + case 12 ... 14: + return 4; + case 36 ... 40: + return 5; + case 41 ... 43: + return TSSI_EXTRA_GROUP(5); + case 44 ... 48: + return 6; + case 49 ... 51: + return TSSI_EXTRA_GROUP(6); + case 52 ... 56: + return 7; + case 57 ... 59: + return TSSI_EXTRA_GROUP(7); + case 60 ... 64: + return 8; + case 100 ... 104: + return 9; + case 105 ... 107: + return TSSI_EXTRA_GROUP(9); + case 108 ... 112: + return 10; + case 113 ... 115: + return TSSI_EXTRA_GROUP(10); + case 116 ... 120: + return 11; + case 121 ... 123: + return TSSI_EXTRA_GROUP(11); + case 124 ... 128: + return 12; + case 129 ... 131: + return TSSI_EXTRA_GROUP(12); + case 132 ... 136: + return 13; + case 137 ... 139: + return TSSI_EXTRA_GROUP(13); + case 140 ... 144: + return 14; + case 149 ... 153: + return 15; + case 154 ... 156: + return TSSI_EXTRA_GROUP(15); + case 157 ... 161: + return 16; + case 162 ... 164: + return TSSI_EXTRA_GROUP(16); + case 165 ... 169: + return 17; + case 170 ... 172: + return TSSI_EXTRA_GROUP(17); + case 173 ... 177: + return 18; + } + + return 0; +} + +static u32 _tssi_get_trim_group(struct rtw89_dev *rtwdev, u8 ch) +{ + switch (ch) { + case 1 ... 8: + return 0; + case 9 ... 14: + return 1; + case 36 ... 48: + return 2; + case 52 ... 64: + return 3; + case 100 ... 112: + return 4; + case 116 ... 128: + return 5; + case 132 ... 144: + return 6; + case 149 ... 177: + return 7; + } + + return 0; +} + +static s8 _tssi_get_ofdm_de(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + u8 ch = chan->channel; + u32 gidx, gidx_1st, gidx_2nd; + s8 de_1st; + s8 de_2nd; + s8 val; + + gidx = _tssi_get_ofdm_group(rtwdev, ch); + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs group_idx=0x%x\n", path, gidx); + + if (IS_TSSI_EXTRA_GROUP(gidx)) { + gidx_1st = TSSI_EXTRA_GET_GROUP_IDX1(gidx); + gidx_2nd = TSSI_EXTRA_GET_GROUP_IDX2(gidx); + de_1st = tssi_info->tssi_mcs[path][gidx_1st]; + de_2nd = tssi_info->tssi_mcs[path][gidx_2nd]; + val = (de_1st + de_2nd) / 2; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs de=%d 1st=%d 2nd=%d\n", + path, val, de_1st, de_2nd); + } else { + val = tssi_info->tssi_mcs[path][gidx]; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs de=%d\n", path, val); + } + + return val; +} + +static s8 _tssi_get_ofdm_trim_de(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + u8 ch = chan->channel; + u32 tgidx, tgidx_1st, tgidx_2nd; + s8 tde_1st; + s8 tde_2nd; + s8 val; + + tgidx = _tssi_get_trim_group(rtwdev, ch); + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs trim_group_idx=0x%x\n", + path, tgidx); + + if (IS_TSSI_EXTRA_GROUP(tgidx)) { + tgidx_1st = TSSI_EXTRA_GET_GROUP_IDX1(tgidx); + tgidx_2nd = TSSI_EXTRA_GET_GROUP_IDX2(tgidx); + tde_1st = tssi_info->tssi_trim[path][tgidx_1st]; + tde_2nd = tssi_info->tssi_trim[path][tgidx_2nd]; + val = (tde_1st + tde_2nd) / 2; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs trim_de=%d 1st=%d 2nd=%d\n", + path, val, tde_1st, tde_2nd); + } else { + val = tssi_info->tssi_trim[path][tgidx]; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs trim_de=%d\n", + path, val); + } + + return val; +} + +static void _tssi_set_efuse_to_de(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) +{ + struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + u8 ch = chan->channel; + u8 gidx; + s8 ofdm_de; + s8 trim_de; + s32 val; + u32 i; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, "[TSSI][TRIM]: phy=%d ch=%d\n", + phy, ch); + + for (i = RF_PATH_A; i < RF_PATH_NUM_8852BT; i++) { + gidx = _tssi_get_cck_group(rtwdev, ch); + trim_de = _tssi_get_ofdm_trim_de(rtwdev, phy, i); + val = tssi_info->tssi_cck[i][gidx] + trim_de; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d cck[%d]=0x%x trim=0x%x\n", + i, gidx, tssi_info->tssi_cck[i][gidx], trim_de); + + rtw89_phy_write32_mask(rtwdev, _tssi_de_cck_long[i], _TSSI_DE_MASK, val); + rtw89_phy_write32_mask(rtwdev, _tssi_de_cck_short[i], _TSSI_DE_MASK, val); + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI] Set TSSI CCK DE 0x%x[21:12]=0x%x\n", + _tssi_de_cck_long[i], + rtw89_phy_read32_mask(rtwdev, _tssi_de_cck_long[i], + _TSSI_DE_MASK)); + + ofdm_de = _tssi_get_ofdm_de(rtwdev, phy, i); + trim_de = _tssi_get_ofdm_trim_de(rtwdev, phy, i); + val = ofdm_de + trim_de; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs=0x%x trim=0x%x\n", + i, ofdm_de, trim_de); + + rtw89_phy_write32_mask(rtwdev, _tssi_de_mcs_20m[i], _TSSI_DE_MASK, val); + rtw89_phy_write32_mask(rtwdev, _tssi_de_mcs_40m[i], _TSSI_DE_MASK, val); + rtw89_phy_write32_mask(rtwdev, _tssi_de_mcs_80m[i], _TSSI_DE_MASK, val); + rtw89_phy_write32_mask(rtwdev, _tssi_de_mcs_80m_80m[i], + _TSSI_DE_MASK, val); + rtw89_phy_write32_mask(rtwdev, _tssi_de_mcs_5m[i], _TSSI_DE_MASK, val); + rtw89_phy_write32_mask(rtwdev, _tssi_de_mcs_10m[i], _TSSI_DE_MASK, val); + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI] Set TSSI MCS DE 0x%x[21:12]=0x%x\n", + _tssi_de_mcs_20m[i], + rtw89_phy_read32_mask(rtwdev, _tssi_de_mcs_20m[i], + _TSSI_DE_MASK)); + } +} + +static void _tssi_alimentk_dump_result(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) +{ + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI PA K]\n0x%x = 0x%08x\n0x%x = 0x%08x\n0x%x = 0x%08x\n0x%x = 0x%08x\n" + "0x%x = 0x%08x\n0x%x = 0x%08x\n0x%x = 0x%08x\n0x%x = 0x%08x\n", + R_TSSI_PA_K1 + (path << 13), + rtw89_phy_read32(rtwdev, R_TSSI_PA_K1 + (path << 13)), + R_TSSI_PA_K2 + (path << 13), + rtw89_phy_read32(rtwdev, R_TSSI_PA_K2 + (path << 13)), + R_P0_TSSI_ALIM1 + (path << 13), + rtw89_phy_read32(rtwdev, R_P0_TSSI_ALIM1 + (path << 13)), + R_P0_TSSI_ALIM3 + (path << 13), + rtw89_phy_read32(rtwdev, R_P0_TSSI_ALIM3 + (path << 13)), + R_TSSI_PA_K5 + (path << 13), + rtw89_phy_read32(rtwdev, R_TSSI_PA_K5 + (path << 13)), + R_P0_TSSI_ALIM2 + (path << 13), + rtw89_phy_read32(rtwdev, R_P0_TSSI_ALIM2 + (path << 13)), + R_P0_TSSI_ALIM4 + (path << 13), + rtw89_phy_read32(rtwdev, R_P0_TSSI_ALIM4 + (path << 13)), + R_TSSI_PA_K8 + (path << 13), + rtw89_phy_read32(rtwdev, R_TSSI_PA_K8 + (path << 13))); +} + +static void _tssi_alimentk_done(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy, enum rtw89_rf_path path) +{ + struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + u8 channel = chan->channel; + u8 band; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "======>%s phy=%d path=%d\n", __func__, phy, path); + + if (channel >= 1 && channel <= 14) + band = TSSI_ALIMK_2G; + else if (channel >= 36 && channel <= 64) + band = TSSI_ALIMK_5GL; + else if (channel >= 100 && channel <= 144) + band = TSSI_ALIMK_5GM; + else if (channel >= 149 && channel <= 177) + band = TSSI_ALIMK_5GH; + else + band = TSSI_ALIMK_2G; + + if (tssi_info->alignment_done[path][band]) { + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_ALIM1 + (path << 13), MASKDWORD, + tssi_info->alignment_value[path][band][0]); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_ALIM3 + (path << 13), MASKDWORD, + tssi_info->alignment_value[path][band][1]); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_ALIM2 + (path << 13), MASKDWORD, + tssi_info->alignment_value[path][band][2]); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_ALIM4 + (path << 13), MASKDWORD, + tssi_info->alignment_value[path][band][3]); + } + + _tssi_alimentk_dump_result(rtwdev, path); +} + +static void _tssi_hw_tx(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, u16 cnt, u16 period, s16 pwr_dbm, + u8 enable) +{ + enum rtw89_rf_path_bit rx_path; + + if (path == RF_PATH_A) + rx_path = RF_A; + else if (path == RF_PATH_B) + rx_path = RF_B; + else if (path == RF_PATH_AB) + rx_path = RF_AB; + else + rx_path = RF_ABCD; /* don't change path, but still set others */ + + if (enable) { + rtw8852bx_bb_set_plcp_tx(rtwdev); + rtw8852bx_bb_cfg_tx_path(rtwdev, path); + rtw8852bx_bb_ctrl_rx_path(rtwdev, rx_path); + rtw8852bx_bb_set_power(rtwdev, pwr_dbm, phy); + } + + rtw8852bx_bb_set_pmac_pkt_tx(rtwdev, enable, cnt, period, 20, phy); +} + +static void _tssi_backup_bb_registers(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy, const u32 reg[], + u32 reg_backup[], u32 reg_num) +{ + u32 i; + + for (i = 0; i < reg_num; i++) { + reg_backup[i] = rtw89_phy_read32_mask(rtwdev, reg[i], MASKDWORD); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI] Backup BB 0x%x = 0x%x\n", reg[i], + reg_backup[i]); + } +} + +static void _tssi_reload_bb_registers(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy, const u32 reg[], + u32 reg_backup[], u32 reg_num) + +{ + u32 i; + + for (i = 0; i < reg_num; i++) { + rtw89_phy_write32_mask(rtwdev, reg[i], MASKDWORD, reg_backup[i]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI] Reload BB 0x%x = 0x%x\n", reg[i], + reg_backup[i]); + } +} + +static u8 _tssi_ch_to_idx(struct rtw89_dev *rtwdev, u8 channel) +{ + u8 channel_index; + + if (channel >= 1 && channel <= 14) + channel_index = channel - 1; + else if (channel >= 36 && channel <= 64) + channel_index = (channel - 36) / 2 + 14; + else if (channel >= 100 && channel <= 144) + channel_index = ((channel - 100) / 2) + 15 + 14; + else if (channel >= 149 && channel <= 177) + channel_index = ((channel - 149) / 2) + 38 + 14; + else + channel_index = 0; + + return channel_index; +} + +static bool _tssi_get_cw_report(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, const s16 *power, + u32 *tssi_cw_rpt) +{ + u32 tx_counter, tx_counter_tmp; + const int retry = 100; + u32 tmp; + int j, k; + + for (j = 0; j < RTW8852BT_TSSI_PATH_NR; j++) { + rtw89_phy_write32_mask(rtwdev, _tssi_trigger[path], B_P0_TSSI_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, _tssi_trigger[path], B_P0_TSSI_EN, 0x1); + + tx_counter = rtw89_phy_read32_mask(rtwdev, R_TX_COUNTER, MASKLWORD); + + tmp = rtw89_phy_read32_mask(rtwdev, _tssi_trigger[path], MASKDWORD); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI PA K] 0x%x = 0x%08x path=%d\n", + _tssi_trigger[path], tmp, path); + + if (j == 0) + _tssi_hw_tx(rtwdev, phy, path, 100, 5000, power[j], true); + else + _tssi_hw_tx(rtwdev, phy, RF_PATH_ABCD, 100, 5000, power[j], true); + + tx_counter_tmp = rtw89_phy_read32_mask(rtwdev, R_TX_COUNTER, MASKLWORD); + tx_counter_tmp -= tx_counter; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI PA K] First HWTXcounter=%d path=%d\n", + tx_counter_tmp, path); + + for (k = 0; k < retry; k++) { + tmp = rtw89_phy_read32_mask(rtwdev, _tssi_cw_rpt_addr[path], + B_TSSI_CWRPT_RDY); + if (tmp) + break; + + udelay(30); + + tx_counter_tmp = + rtw89_phy_read32_mask(rtwdev, R_TX_COUNTER, MASKLWORD); + tx_counter_tmp -= tx_counter; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI PA K] Flow k = %d HWTXcounter=%d path=%d\n", + k, tx_counter_tmp, path); + } + + if (k >= retry) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI PA K] TSSI finish bit k > %d mp:100ms normal:30us path=%d\n", + k, path); + + _tssi_hw_tx(rtwdev, phy, path, 100, 5000, power[j], false); + return false; + } + + tssi_cw_rpt[j] = + rtw89_phy_read32_mask(rtwdev, _tssi_cw_rpt_addr[path], + B_TSSI_CWRPT); + + _tssi_hw_tx(rtwdev, phy, path, 100, 5000, power[j], false); + + tx_counter_tmp = rtw89_phy_read32_mask(rtwdev, R_TX_COUNTER, MASKLWORD); + tx_counter_tmp -= tx_counter; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI PA K] Final HWTXcounter=%d path=%d\n", + tx_counter_tmp, path); + } + + return true; +} + +static void _tssi_alimentk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + static const u32 bb_reg[8] = {0x5820, 0x7820, 0x4978, 0x58e4, + 0x78e4, 0x49c0, 0x0d18, 0x0d80}; + static const s16 power_2g[4] = {48, 20, 4, -8}; + static const s16 power_5g[4] = {48, 20, 4, 4}; + struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + s32 tssi_alim_offset_1, tssi_alim_offset_2, tssi_alim_offset_3; + u32 tssi_cw_rpt[RTW8852BT_TSSI_PATH_NR] = {}; + u8 channel = chan->channel; + u8 ch_idx = _tssi_ch_to_idx(rtwdev, channel); + struct rtw8852bx_bb_tssi_bak tssi_bak; + s32 aliment_diff, tssi_cw_default; + u32 start_time, finish_time; + u32 bb_reg_backup[8] = {}; + const s16 *power; + u8 band; + bool ok; + u32 tmp; + u8 j; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "======> %s channel=%d path=%d\n", __func__, channel, + path); + + start_time = ktime_get_ns(); + + if (chan->band_type == RTW89_BAND_2G) + power = power_2g; + else + power = power_5g; + + if (channel >= 1 && channel <= 14) + band = TSSI_ALIMK_2G; + else if (channel >= 36 && channel <= 64) + band = TSSI_ALIMK_5GL; + else if (channel >= 100 && channel <= 144) + band = TSSI_ALIMK_5GM; + else if (channel >= 149 && channel <= 177) + band = TSSI_ALIMK_5GH; + else + band = TSSI_ALIMK_2G; + + rtw8852bx_bb_backup_tssi(rtwdev, phy, &tssi_bak); + _tssi_backup_bb_registers(rtwdev, phy, bb_reg, bb_reg_backup, + ARRAY_SIZE(bb_reg_backup)); + + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_AVG, B_P0_TSSI_AVG, 0x8); + rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_AVG, B_P1_TSSI_AVG, 0x8); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_MV_AVG, B_P0_TSSI_MV_AVG, 0x2); + rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_MV_AVG, B_P1_TSSI_MV_AVG, 0x2); + + ok = _tssi_get_cw_report(rtwdev, phy, path, power, tssi_cw_rpt); + if (!ok) + goto out; + + for (j = 0; j < RTW8852BT_TSSI_PATH_NR; j++) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI PA K] power[%d]=%d tssi_cw_rpt[%d]=%d\n", j, + power[j], j, tssi_cw_rpt[j]); + } + + tmp = rtw89_phy_read32_mask(rtwdev, _tssi_cw_default_addr[path][1], + _tssi_cw_default_mask[1]); + tssi_cw_default = sign_extend32(tmp, 8); + tssi_alim_offset_1 = tssi_cw_rpt[0] - ((power[0] - power[1]) * 2) - + tssi_cw_rpt[1] + tssi_cw_default; + aliment_diff = tssi_alim_offset_1 - tssi_cw_default; + + tmp = rtw89_phy_read32_mask(rtwdev, _tssi_cw_default_addr[path][2], + _tssi_cw_default_mask[2]); + tssi_cw_default = sign_extend32(tmp, 8); + tssi_alim_offset_2 = tssi_cw_default + aliment_diff; + + tmp = rtw89_phy_read32_mask(rtwdev, _tssi_cw_default_addr[path][3], + _tssi_cw_default_mask[3]); + tssi_cw_default = sign_extend32(tmp, 8); + tssi_alim_offset_3 = tssi_cw_default + aliment_diff; + + if (path == RF_PATH_A) { + tmp = FIELD_PREP(B_P1_TSSI_ALIM11, tssi_alim_offset_1) | + FIELD_PREP(B_P1_TSSI_ALIM12, tssi_alim_offset_2) | + FIELD_PREP(B_P1_TSSI_ALIM13, tssi_alim_offset_3); + + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_ALIM1, B_P0_TSSI_ALIM1, tmp); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_ALIM2, B_P0_TSSI_ALIM2, tmp); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI PA K] tssi_alim_offset = 0x%x 0x%x 0x%x 0x%x\n", + rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM3, B_P0_TSSI_ALIM31), + rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM1, B_P0_TSSI_ALIM11), + rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM1, B_P0_TSSI_ALIM12), + rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM1, B_P0_TSSI_ALIM13)); + } else { + tmp = FIELD_PREP(B_P1_TSSI_ALIM11, tssi_alim_offset_1) | + FIELD_PREP(B_P1_TSSI_ALIM12, tssi_alim_offset_2) | + FIELD_PREP(B_P1_TSSI_ALIM13, tssi_alim_offset_3); + + rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_ALIM1, B_P1_TSSI_ALIM1, tmp); + rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_ALIM2, B_P1_TSSI_ALIM2, tmp); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI PA K] tssi_alim_offset = 0x%x 0x%x 0x%x 0x%x\n", + rtw89_phy_read32_mask(rtwdev, R_P1_TSSI_ALIM3, B_P1_TSSI_ALIM31), + rtw89_phy_read32_mask(rtwdev, R_P1_TSSI_ALIM1, B_P1_TSSI_ALIM11), + rtw89_phy_read32_mask(rtwdev, R_P1_TSSI_ALIM1, B_P1_TSSI_ALIM12), + rtw89_phy_read32_mask(rtwdev, R_P1_TSSI_ALIM1, B_P1_TSSI_ALIM13)); + } + + tssi_info->alignment_done[path][band] = true; + tssi_info->alignment_value[path][band][0] = + rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM1 + (path << 13), MASKDWORD); + tssi_info->alignment_value[path][band][1] = + rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM3 + (path << 13), MASKDWORD); + tssi_info->alignment_value[path][band][2] = + rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM2 + (path << 13), MASKDWORD); + tssi_info->alignment_value[path][band][3] = + rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM4 + (path << 13), MASKDWORD); + + tssi_info->check_backup_aligmk[path][ch_idx] = true; + tssi_info->alignment_backup_by_ch[path][ch_idx][0] = + rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM1 + (path << 13), MASKDWORD); + tssi_info->alignment_backup_by_ch[path][ch_idx][1] = + rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM3 + (path << 13), MASKDWORD); + tssi_info->alignment_backup_by_ch[path][ch_idx][2] = + rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM2 + (path << 13), MASKDWORD); + tssi_info->alignment_backup_by_ch[path][ch_idx][3] = + rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM4 + (path << 13), MASKDWORD); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI PA K] tssi_info->alignment_value[path=%d][band=%d][0], 0x%x = 0x%08x\n", + path, band, R_P0_TSSI_ALIM1 + (path << 13), + tssi_info->alignment_value[path][band][0]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI PA K] tssi_info->alignment_value[path=%d][band=%d][1], 0x%x = 0x%08x\n", + path, band, R_P0_TSSI_ALIM3 + (path << 13), + tssi_info->alignment_value[path][band][1]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI PA K] tssi_info->alignment_value[path=%d][band=%d][2], 0x%x = 0x%08x\n", + path, band, R_P0_TSSI_ALIM2 + (path << 13), + tssi_info->alignment_value[path][band][2]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI PA K] tssi_info->alignment_value[path=%d][band=%d][3], 0x%x = 0x%08x\n", + path, band, R_P0_TSSI_ALIM4 + (path << 13), + tssi_info->alignment_value[path][band][3]); + +out: + _tssi_reload_bb_registers(rtwdev, phy, bb_reg, bb_reg_backup, + ARRAY_SIZE(bb_reg_backup)); + rtw8852bx_bb_restore_tssi(rtwdev, phy, &tssi_bak); + rtw8852bx_bb_tx_mode_switch(rtwdev, phy, 0); + + finish_time = ktime_get_ns(); + tssi_info->tssi_alimk_time += finish_time - start_time; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI PA K] %s processing time = %d ms\n", __func__, + tssi_info->tssi_alimk_time); +} + +void rtw8852bt_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool hwtx_en) +{ + static const u32 reg[2] = {R_DPD_CH0A, R_DPD_CH0B}; + u8 phy_map = rtw89_btc_phymap(rtwdev, phy, RF_AB); + u32 reg_backup[2] = {}; + u32 tx_en; + u8 i; + + _tssi_backup_bb_registers(rtwdev, phy, reg, reg_backup, 2); + rtw89_debug(rtwdev, RTW89_DBG_TSSI, "[TSSI] %s: phy=%d\n", __func__, phy); + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_ONESHOT_START); + + _tssi_dpk_off(rtwdev, phy); + _tssi_disable(rtwdev, phy); + + for (i = RF_PATH_A; i < RF_PATH_NUM_8852BT; i++) { + _tssi_rf_setting(rtwdev, phy, i); + _tssi_set_sys(rtwdev, phy, i); + _tssi_ini_txpwr_ctrl_bb(rtwdev, phy, i); + _tssi_ini_txpwr_ctrl_bb_he_tb(rtwdev, phy, i); + _tssi_set_dck(rtwdev, phy, i); + _tssi_set_tmeter_tbl(rtwdev, phy, i); + _tssi_set_dac_gain_tbl(rtwdev, phy, i); + _tssi_slope_cal_org(rtwdev, phy, i); + _tssi_alignment_default(rtwdev, phy, i, true); + _tssi_set_tssi_slope(rtwdev, phy, i); + + rtw89_chip_stop_sch_tx(rtwdev, phy, &tx_en, RTW89_SCH_TX_SEL_ALL); + _tmac_tx_pause(rtwdev, phy, true); + if (hwtx_en) + _tssi_alimentk(rtwdev, phy, i); + _tmac_tx_pause(rtwdev, phy, false); + rtw89_chip_resume_sch_tx(rtwdev, phy, tx_en); + } + + _tssi_enable(rtwdev, phy); + _tssi_set_efuse_to_de(rtwdev, phy); + + _tssi_reload_bb_registers(rtwdev, phy, reg, reg_backup, 2); + + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_ONESHOT_STOP); +} + +void rtw8852bt_tssi_scan(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; + u8 channel = chan->channel; + u8 band; + u32 i; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "======>%s phy=%d channel=%d\n", __func__, phy, channel); + + if (channel >= 1 && channel <= 14) + band = TSSI_ALIMK_2G; + else if (channel >= 36 && channel <= 64) + band = TSSI_ALIMK_5GL; + else if (channel >= 100 && channel <= 144) + band = TSSI_ALIMK_5GM; + else if (channel >= 149 && channel <= 177) + band = TSSI_ALIMK_5GH; + else + band = TSSI_ALIMK_2G; + + _tssi_disable(rtwdev, phy); + + for (i = RF_PATH_A; i < RTW8852BT_TSSI_PATH_NR; i++) { + _tssi_rf_setting(rtwdev, phy, i); + _tssi_set_sys(rtwdev, phy, i); + _tssi_set_tmeter_tbl(rtwdev, phy, i); + + if (tssi_info->alignment_done[i][band]) + _tssi_alimentk_done(rtwdev, phy, i); + else + _tssi_alignment_default(rtwdev, phy, i, true); + } + + _tssi_enable(rtwdev, phy); + _tssi_set_efuse_to_de(rtwdev, phy); +} + +static void rtw8852bt_tssi_default_txagc(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy, bool enable) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + u8 channel = chan->channel; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "======> %s ch=%d\n", + __func__, channel); + + if (enable) + return; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "======>%s 1 SCAN_END Set 0x5818[7:0]=0x%x 0x7818[7:0]=0x%x\n", + __func__, + rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT), + rtw89_phy_read32_mask(rtwdev, R_P1_TSSI_TRK, B_P1_TSSI_OFT)); + + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT, 0xc0); + rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_TRK, B_P1_TSSI_OFT, 0xc0); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_TRK, B_P1_TSSI_OFT_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_TRK, B_P1_TSSI_OFT_EN, 0x1); + + _tssi_alimentk_done(rtwdev, phy, RF_PATH_A); + _tssi_alimentk_done(rtwdev, phy, RF_PATH_B); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "======>%s 2 SCAN_END Set 0x5818[7:0]=0x%x 0x7818[7:0]=0x%x\n", + __func__, + rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT), + rtw89_phy_read32_mask(rtwdev, R_P1_TSSI_TRK, B_P1_TSSI_OFT)); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "======> %s SCAN_END\n", __func__); +} + +void rtw8852bt_wifi_scan_notify(struct rtw89_dev *rtwdev, bool scan_start, + enum rtw89_phy_idx phy_idx) +{ + if (scan_start) + rtw8852bt_tssi_default_txagc(rtwdev, phy_idx, true); + else + rtw8852bt_tssi_default_txagc(rtwdev, phy_idx, false); +} diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h new file mode 100644 index 000000000000..03fad3abe554 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2024 Realtek Corporation + */ + +#ifndef __RTW89_8852BT_RFK_H__ +#define __RTW89_8852BT_RFK_H__ + +#include "core.h" + +void rtw8852bt_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool hwtx_en); +void rtw8852bt_tssi_scan(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy); +void rtw8852bt_wifi_scan_notify(struct rtw89_dev *rtwdev, bool scan_start, + enum rtw89_phy_idx phy_idx); + +#endif diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk_table.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk_table.c new file mode 100644 index 000000000000..782144bb7f49 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk_table.c @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2024 Realtek Corporation + */ + +#include "rtw8852bt_rfk_table.h" + +static const struct rtw89_reg5_def rtw8852bt_tssi_sys_defs[] = { + RTW89_DECL_RFK_WM(0x12a8, 0x0000000f, 0x4), + RTW89_DECL_RFK_WM(0x32a8, 0x0000000f, 0x4), + RTW89_DECL_RFK_WM(0x12bc, 0x000ffff0, 0x5555), + RTW89_DECL_RFK_WM(0x32bc, 0x000ffff0, 0x5555), + RTW89_DECL_RFK_WM(0x0300, 0xff000000, 0x16), + RTW89_DECL_RFK_WM(0x0304, 0x000000ff, 0x19), + RTW89_DECL_RFK_WM(0x0314, 0xffff0000, 0x2041), + RTW89_DECL_RFK_WM(0x0318, 0xffffffff, 0x2041), + RTW89_DECL_RFK_WM(0x0318, 0xffffffff, 0x20012041), + RTW89_DECL_RFK_WM(0x0020, 0x00006000, 0x3), + RTW89_DECL_RFK_WM(0x0024, 0x00006000, 0x3), + RTW89_DECL_RFK_WM(0x0704, 0xffff0000, 0x601e), + RTW89_DECL_RFK_WM(0x2704, 0xffff0000, 0x601e), + RTW89_DECL_RFK_WM(0x0700, 0xf0000000, 0x4), + RTW89_DECL_RFK_WM(0x2700, 0xf0000000, 0x4), + RTW89_DECL_RFK_WM(0x0650, 0x3c000000, 0x0), + RTW89_DECL_RFK_WM(0x2650, 0x3c000000, 0x0), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_sys_defs); + +static const struct rtw89_reg5_def rtw8852bt_tssi_sys_a_defs_2g[] = { + RTW89_DECL_RFK_WM(0x120c, 0x000000ff, 0x33), + RTW89_DECL_RFK_WM(0x12c0, 0x0ff00000, 0x33), + RTW89_DECL_RFK_WM(0x58f8, 0x40000000, 0x1), + RTW89_DECL_RFK_WM(0x0304, 0x0000ff00, 0x1e), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_sys_a_defs_2g); + +static const struct rtw89_reg5_def rtw8852bt_tssi_sys_a_defs_5g[] = { + RTW89_DECL_RFK_WM(0x120c, 0x000000ff, 0x44), + RTW89_DECL_RFK_WM(0x12c0, 0x0ff00000, 0x44), + RTW89_DECL_RFK_WM(0x58f8, 0x40000000, 0x0), + RTW89_DECL_RFK_WM(0x0304, 0x0000ff00, 0x1d), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_sys_a_defs_5g); + +static const struct rtw89_reg5_def rtw8852bt_tssi_sys_b_defs_2g[] = { + RTW89_DECL_RFK_WM(0x32c0, 0x0ff00000, 0x33), + RTW89_DECL_RFK_WM(0x320c, 0x000000ff, 0x33), + RTW89_DECL_RFK_WM(0x78f8, 0x40000000, 0x1), + RTW89_DECL_RFK_WM(0x0304, 0x0000ff00, 0x1e), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_sys_b_defs_2g); + +static const struct rtw89_reg5_def rtw8852bt_tssi_sys_b_defs_5g[] = { + RTW89_DECL_RFK_WM(0x32c0, 0x0ff00000, 0x44), + RTW89_DECL_RFK_WM(0x320c, 0x000000ff, 0x44), + RTW89_DECL_RFK_WM(0x78f8, 0x40000000, 0x0), + RTW89_DECL_RFK_WM(0x0304, 0x0000ff00, 0x1d), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_sys_b_defs_5g); + +static const struct rtw89_reg5_def rtw8852bt_tssi_init_txpwr_defs_a[] = { + RTW89_DECL_RFK_WM(0x566c, 0x00001000, 0x0), + RTW89_DECL_RFK_WM(0x5800, 0xffffffff, 0x003f807f), + RTW89_DECL_RFK_WM(0x580c, 0x0000007f, 0x40), + RTW89_DECL_RFK_WM(0x580c, 0x0fffff00, 0x00040), + RTW89_DECL_RFK_WM(0x5810, 0xffffffff, 0x59010000), + RTW89_DECL_RFK_WM(0x5814, 0x01ffffff, 0x002d000), + RTW89_DECL_RFK_WM(0x5814, 0xf8000000, 0x00), + RTW89_DECL_RFK_WM(0x5818, 0xffffffff, 0x002c1800), + RTW89_DECL_RFK_WM(0x581c, 0x3fffffff, 0x1dc80280), + RTW89_DECL_RFK_WM(0x5820, 0xffffffff, 0x00002080), + RTW89_DECL_RFK_WM(0x580c, 0x10000000, 0x1), + RTW89_DECL_RFK_WM(0x580c, 0x40000000, 0x1), + RTW89_DECL_RFK_WM(0x5834, 0x3fffffff, 0x000115f2), + RTW89_DECL_RFK_WM(0x5838, 0x7fffffff, 0x0000121), + RTW89_DECL_RFK_WM(0x5854, 0x3fffffff, 0x000115f2), + RTW89_DECL_RFK_WM(0x5858, 0x7fffffff, 0x0000121), + RTW89_DECL_RFK_WM(0x5860, 0x80000000, 0x0), + RTW89_DECL_RFK_WM(0x5864, 0x07ffffff, 0x00801ff), + RTW89_DECL_RFK_WM(0x5898, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x589c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x58a4, 0x000000ff, 0x16), + RTW89_DECL_RFK_WM(0x58b0, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x58b4, 0x7fffffff, 0x0a002000), + RTW89_DECL_RFK_WM(0x58b8, 0x7fffffff, 0x00007628), + RTW89_DECL_RFK_WM(0x58bc, 0x07ffffff, 0x7a7807f), + RTW89_DECL_RFK_WM(0x58c0, 0xfffe0000, 0x003f), + RTW89_DECL_RFK_WM(0x58c4, 0xffffffff, 0x0003ffff), + RTW89_DECL_RFK_WM(0x58c8, 0x00ffffff, 0x000000), + RTW89_DECL_RFK_WM(0x58c8, 0xf0000000, 0x0), + RTW89_DECL_RFK_WM(0x58cc, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x58d0, 0x07ffffff, 0x2008101), + RTW89_DECL_RFK_WM(0x58d4, 0x000000ff, 0x00), + RTW89_DECL_RFK_WM(0x58d4, 0x0003fe00, 0x0ff), + RTW89_DECL_RFK_WM(0x58d4, 0x07fc0000, 0x100), + RTW89_DECL_RFK_WM(0x58d8, 0xffffffff, 0x8008016c), + RTW89_DECL_RFK_WM(0x58dc, 0x0001ffff, 0x0807f), + RTW89_DECL_RFK_WM(0x58dc, 0xfff00000, 0xc00), + RTW89_DECL_RFK_WM(0x58f0, 0x0003ffff, 0x001ff), + RTW89_DECL_RFK_WM(0x58f4, 0x000fffff, 0x000), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_init_txpwr_defs_a); + +static const struct rtw89_reg5_def rtw8852bt_tssi_init_txpwr_defs_b[] = { + RTW89_DECL_RFK_WM(0x566c, 0x00001000, 0x0), + RTW89_DECL_RFK_WM(0x7800, 0xffffffff, 0x003f807f), + RTW89_DECL_RFK_WM(0x780c, 0x0000007f, 0x40), + RTW89_DECL_RFK_WM(0x780c, 0x0fffff00, 0x00040), + RTW89_DECL_RFK_WM(0x7810, 0xffffffff, 0x59010000), + RTW89_DECL_RFK_WM(0x7814, 0x01ffffff, 0x002d000), + RTW89_DECL_RFK_WM(0x7814, 0xf8000000, 0x00), + RTW89_DECL_RFK_WM(0x7818, 0xffffffff, 0x002c1800), + RTW89_DECL_RFK_WM(0x781c, 0x3fffffff, 0x1dc80280), + RTW89_DECL_RFK_WM(0x7820, 0xffffffff, 0x00002080), + RTW89_DECL_RFK_WM(0x780c, 0x10000000, 0x1), + RTW89_DECL_RFK_WM(0x780c, 0x40000000, 0x1), + RTW89_DECL_RFK_WM(0x7834, 0x3fffffff, 0x000115f2), + RTW89_DECL_RFK_WM(0x7838, 0x7fffffff, 0x0000121), + RTW89_DECL_RFK_WM(0x7854, 0x3fffffff, 0x000115f2), + RTW89_DECL_RFK_WM(0x7858, 0x7fffffff, 0x0000121), + RTW89_DECL_RFK_WM(0x7860, 0x80000000, 0x0), + RTW89_DECL_RFK_WM(0x7864, 0x07ffffff, 0x00801ff), + RTW89_DECL_RFK_WM(0x7898, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x789c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x78a4, 0x000000ff, 0x16), + RTW89_DECL_RFK_WM(0x78b0, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x78b4, 0x7fffffff, 0x0a002000), + RTW89_DECL_RFK_WM(0x78b8, 0x7fffffff, 0x00007628), + RTW89_DECL_RFK_WM(0x78bc, 0x07ffffff, 0x7a7807f), + RTW89_DECL_RFK_WM(0x78c0, 0xfffe0000, 0x003f), + RTW89_DECL_RFK_WM(0x78c4, 0xffffffff, 0x0003ffff), + RTW89_DECL_RFK_WM(0x78c8, 0x00ffffff, 0x000000), + RTW89_DECL_RFK_WM(0x78c8, 0xf0000000, 0x0), + RTW89_DECL_RFK_WM(0x78cc, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x78d0, 0x07ffffff, 0x2008101), + RTW89_DECL_RFK_WM(0x78d4, 0x000000ff, 0x00), + RTW89_DECL_RFK_WM(0x78d4, 0x0003fe00, 0x0ff), + RTW89_DECL_RFK_WM(0x78d4, 0x07fc0000, 0x100), + RTW89_DECL_RFK_WM(0x78d8, 0xffffffff, 0x8008016c), + RTW89_DECL_RFK_WM(0x78dc, 0x0001ffff, 0x0807f), + RTW89_DECL_RFK_WM(0x78dc, 0xfff00000, 0xc00), + RTW89_DECL_RFK_WM(0x78f0, 0x0003ffff, 0x001ff), + RTW89_DECL_RFK_WM(0x78f4, 0x000fffff, 0x000), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_init_txpwr_defs_b); + +static const struct rtw89_reg5_def rtw8852bt_tssi_init_txpwr_he_tb_defs_a[] = { + RTW89_DECL_RFK_WM(0x58a0, 0xffffffff, 0x000000fe), + RTW89_DECL_RFK_WM(0x58e4, 0x0000007f, 0x1f), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_init_txpwr_he_tb_defs_a); + +static const struct rtw89_reg5_def rtw8852bt_tssi_init_txpwr_he_tb_defs_b[] = { + RTW89_DECL_RFK_WM(0x78a0, 0xffffffff, 0x000000fe), + RTW89_DECL_RFK_WM(0x78e4, 0x0000007f, 0x1f), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_init_txpwr_he_tb_defs_b); + +static const struct rtw89_reg5_def rtw8852bt_tssi_dck_defs_a[] = { + RTW89_DECL_RFK_WM(0x580c, 0x0fff0000, 0x000), + RTW89_DECL_RFK_WM(0x5814, 0x003ff000, 0x0ef), + RTW89_DECL_RFK_WM(0x5814, 0x18000000, 0x0), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_dck_defs_a); + +static const struct rtw89_reg5_def rtw8852bt_tssi_dck_defs_b[] = { + RTW89_DECL_RFK_WM(0x780c, 0x0fff0000, 0x000), + RTW89_DECL_RFK_WM(0x7814, 0x003ff000, 0x0ef), + RTW89_DECL_RFK_WM(0x7814, 0x18000000, 0x0), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_dck_defs_b); + +static const struct rtw89_reg5_def rtw8852bt_tssi_dac_gain_defs_a[] = { + RTW89_DECL_RFK_WM(0x58b0, 0x00000400, 0x1), + RTW89_DECL_RFK_WM(0x58b0, 0x00000fff, 0x000), + RTW89_DECL_RFK_WM(0x58b0, 0x00000800, 0x1), + RTW89_DECL_RFK_WM(0x5a00, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a04, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a08, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a0c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a10, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a14, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a18, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a1c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a20, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a24, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a28, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a2c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a30, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a34, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a38, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a3c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a40, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a44, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a48, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a4c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a50, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a54, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a58, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a5c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a60, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a64, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a68, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a6c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a70, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a74, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a78, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a7c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a80, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a84, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a88, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a8c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a90, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a94, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a98, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5a9c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5aa0, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5aa4, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5aa8, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5aac, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5ab0, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5ab4, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5ab8, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5abc, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5ac0, 0xffffffff, 0x00000000), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_dac_gain_defs_a); + +static const struct rtw89_reg5_def rtw8852bt_tssi_dac_gain_defs_b[] = { + RTW89_DECL_RFK_WM(0x78b0, 0x00000fff, 0x000), + RTW89_DECL_RFK_WM(0x78b0, 0x00000800, 0x1), + RTW89_DECL_RFK_WM(0x7a00, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a04, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a08, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a0c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a10, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a14, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a18, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a1c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a20, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a24, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a28, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a2c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a30, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a34, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a38, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a3c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a40, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a44, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a48, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a4c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a50, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a54, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a58, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a5c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a60, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a64, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a68, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a6c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a70, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a74, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a78, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a7c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a80, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a84, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a88, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a8c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a90, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a94, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a98, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7a9c, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7aa0, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7aa4, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7aa8, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7aac, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7ab0, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7ab4, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7ab8, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7abc, 0xffffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7ac0, 0xffffffff, 0x00000000), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_dac_gain_defs_b); + +static const struct rtw89_reg5_def rtw8852bt_tssi_slope_a_defs_2g[] = { + RTW89_DECL_RFK_WM(0x5608, 0x07ffffff, 0x0801008), + RTW89_DECL_RFK_WM(0x560c, 0x07ffffff, 0x0201020), + RTW89_DECL_RFK_WM(0x5610, 0x07ffffff, 0x0201008), + RTW89_DECL_RFK_WM(0x5614, 0x07ffffff, 0x0804008), + RTW89_DECL_RFK_WM(0x5618, 0x07ffffff, 0x0201008), + RTW89_DECL_RFK_WM(0x561c, 0x000001ff, 0x008), + RTW89_DECL_RFK_WM(0x561c, 0xffff0000, 0x0808), + RTW89_DECL_RFK_WM(0x5620, 0xffffffff, 0x08081e28), + RTW89_DECL_RFK_WM(0x5624, 0xffffffff, 0x08080808), + RTW89_DECL_RFK_WM(0x5628, 0xffffffff, 0x08081e28), + RTW89_DECL_RFK_WM(0x562c, 0x0000ffff, 0x0808), + RTW89_DECL_RFK_WM(0x581c, 0x00100000, 0x1), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_slope_a_defs_2g); + +static const struct rtw89_reg5_def rtw8852bt_tssi_slope_a_defs_5g[] = { + RTW89_DECL_RFK_WM(0x5608, 0x07ffffff, 0x0201008), + RTW89_DECL_RFK_WM(0x560c, 0x07ffffff, 0x0201019), + RTW89_DECL_RFK_WM(0x5610, 0x07ffffff, 0x0201008), + RTW89_DECL_RFK_WM(0x5614, 0x07ffffff, 0x0201008), + RTW89_DECL_RFK_WM(0x5618, 0x07ffffff, 0x0201008), + RTW89_DECL_RFK_WM(0x561c, 0x000001ff, 0x008), + RTW89_DECL_RFK_WM(0x561c, 0xffff0000, 0x0808), + RTW89_DECL_RFK_WM(0x5620, 0xffffffff, 0x08081808), + RTW89_DECL_RFK_WM(0x5624, 0xffffffff, 0x08080808), + RTW89_DECL_RFK_WM(0x5628, 0xffffffff, 0x08080808), + RTW89_DECL_RFK_WM(0x562c, 0x0000ffff, 0x0808), + RTW89_DECL_RFK_WM(0x581c, 0x00100000, 0x1), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_slope_a_defs_5g); + +static const struct rtw89_reg5_def rtw8852bt_tssi_slope_b_defs_2g[] = { + RTW89_DECL_RFK_WM(0x7608, 0x07ffffff, 0x0801008), + RTW89_DECL_RFK_WM(0x760c, 0x07ffffff, 0x0201020), + RTW89_DECL_RFK_WM(0x7610, 0x07ffffff, 0x0201008), + RTW89_DECL_RFK_WM(0x7614, 0x07ffffff, 0x0804008), + RTW89_DECL_RFK_WM(0x7618, 0x07ffffff, 0x0201008), + RTW89_DECL_RFK_WM(0x761c, 0x000001ff, 0x008), + RTW89_DECL_RFK_WM(0x761c, 0xffff0000, 0x0808), + RTW89_DECL_RFK_WM(0x7620, 0xffffffff, 0x08081e28), + RTW89_DECL_RFK_WM(0x7624, 0xffffffff, 0x08080808), + RTW89_DECL_RFK_WM(0x7628, 0xffffffff, 0x08081e28), + RTW89_DECL_RFK_WM(0x762c, 0x0000ffff, 0x0808), + RTW89_DECL_RFK_WM(0x781c, 0x00100000, 0x1), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_slope_b_defs_2g); + +static const struct rtw89_reg5_def rtw8852bt_tssi_slope_b_defs_5g[] = { + RTW89_DECL_RFK_WM(0x7608, 0x07ffffff, 0x0201008), + RTW89_DECL_RFK_WM(0x760c, 0x07ffffff, 0x0201019), + RTW89_DECL_RFK_WM(0x7610, 0x07ffffff, 0x0201008), + RTW89_DECL_RFK_WM(0x7614, 0x07ffffff, 0x0201008), + RTW89_DECL_RFK_WM(0x7618, 0x07ffffff, 0x0201008), + RTW89_DECL_RFK_WM(0x761c, 0x000001ff, 0x008), + RTW89_DECL_RFK_WM(0x761c, 0xffff0000, 0x0808), + RTW89_DECL_RFK_WM(0x7620, 0xffffffff, 0x08081808), + RTW89_DECL_RFK_WM(0x7624, 0xffffffff, 0x08080808), + RTW89_DECL_RFK_WM(0x7628, 0xffffffff, 0x08080808), + RTW89_DECL_RFK_WM(0x762c, 0x0000ffff, 0x0808), + RTW89_DECL_RFK_WM(0x781c, 0x00100000, 0x1), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_slope_b_defs_5g); + +static const struct rtw89_reg5_def rtw8852bt_tssi_align_a_2g_all_defs[] = { + RTW89_DECL_RFK_WM(0x5604, 0x80000000, 0x1), + RTW89_DECL_RFK_WM(0x5600, 0x3fffffff, 0x3f2d2721), + RTW89_DECL_RFK_WM(0x5604, 0x003fffff, 0x010101), + RTW89_DECL_RFK_WM(0x5630, 0x3fffffff, 0x029f57c0), + RTW89_DECL_RFK_WM(0x5634, 0x3fffffff, 0x00000077), + RTW89_DECL_RFK_WM(0x5638, 0x000fffff, 0x00000), + RTW89_DECL_RFK_WM(0x563c, 0x3fffffff, 0x029f5bc0), + RTW89_DECL_RFK_WM(0x5640, 0x3fffffff, 0x00000076), + RTW89_DECL_RFK_WM(0x5644, 0x000fffff, 0x00000), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_align_a_2g_all_defs); + +static const struct rtw89_reg5_def rtw8852bt_tssi_align_a_5g1_all_defs[] = { + RTW89_DECL_RFK_WM(0x5604, 0x80000000, 0x1), + RTW89_DECL_RFK_WM(0x5600, 0x3fffffff, 0x3f2d2721), + RTW89_DECL_RFK_WM(0x5604, 0x003fffff, 0x010101), + RTW89_DECL_RFK_WM(0x5630, 0x3fffffff, 0x007ff3d7), + RTW89_DECL_RFK_WM(0x5634, 0x3fffffff, 0x00000068), + RTW89_DECL_RFK_WM(0x5638, 0x000fffff, 0x00000), + RTW89_DECL_RFK_WM(0x563c, 0x3fffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5640, 0x3fffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5644, 0x000fffff, 0x00000), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_align_a_5g1_all_defs); + +static const struct rtw89_reg5_def rtw8852bt_tssi_align_a_5g2_all_defs[] = { + RTW89_DECL_RFK_WM(0x5604, 0x80000000, 0x1), + RTW89_DECL_RFK_WM(0x5600, 0x3fffffff, 0x3f2d2721), + RTW89_DECL_RFK_WM(0x5604, 0x003fffff, 0x010101), + RTW89_DECL_RFK_WM(0x5630, 0x3fffffff, 0x00a003db), + RTW89_DECL_RFK_WM(0x5634, 0x3fffffff, 0x00000065), + RTW89_DECL_RFK_WM(0x5638, 0x000fffff, 0x00000), + RTW89_DECL_RFK_WM(0x563c, 0x3fffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5640, 0x3fffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5644, 0x000fffff, 0x00000), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_align_a_5g2_all_defs); + +static const struct rtw89_reg5_def rtw8852bt_tssi_align_a_5g3_all_defs[] = { + RTW89_DECL_RFK_WM(0x5604, 0x80000000, 0x1), + RTW89_DECL_RFK_WM(0x5600, 0x3fffffff, 0x3f2d2721), + RTW89_DECL_RFK_WM(0x5604, 0x003fffff, 0x010101), + RTW89_DECL_RFK_WM(0x5630, 0x3fffffff, 0x01101be2), + RTW89_DECL_RFK_WM(0x5634, 0x3fffffff, 0x00000065), + RTW89_DECL_RFK_WM(0x5638, 0x000fffff, 0x00000), + RTW89_DECL_RFK_WM(0x563c, 0x3fffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5640, 0x3fffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x5644, 0x000fffff, 0x00000), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_align_a_5g3_all_defs); + +static const struct rtw89_reg5_def rtw8852bt_tssi_align_b_2g_all_defs[] = { + RTW89_DECL_RFK_WM(0x7604, 0x80000000, 0x1), + RTW89_DECL_RFK_WM(0x7600, 0x3fffffff, 0x3f2d2721), + RTW89_DECL_RFK_WM(0x7604, 0x003fffff, 0x010101), + RTW89_DECL_RFK_WM(0x7630, 0x3fffffff, 0x023f3fb9), + RTW89_DECL_RFK_WM(0x7634, 0x3fffffff, 0x00000075), + RTW89_DECL_RFK_WM(0x7638, 0x000fffff, 0x00000), + RTW89_DECL_RFK_WM(0x763c, 0x3fffffff, 0x01df3fb8), + RTW89_DECL_RFK_WM(0x7640, 0x3fffffff, 0x00000074), + RTW89_DECL_RFK_WM(0x7644, 0x000fffff, 0x00000), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_align_b_2g_all_defs); + +static const struct rtw89_reg5_def rtw8852bt_tssi_align_b_5g1_all_defs[] = { + RTW89_DECL_RFK_WM(0x7604, 0x80000000, 0x1), + RTW89_DECL_RFK_WM(0x7600, 0x3fffffff, 0x3f2d2721), + RTW89_DECL_RFK_WM(0x7604, 0x003fffff, 0x010101), + RTW89_DECL_RFK_WM(0x7630, 0x3fffffff, 0x010017e0), + RTW89_DECL_RFK_WM(0x7634, 0x3fffffff, 0x00000069), + RTW89_DECL_RFK_WM(0x7638, 0x000fffff, 0x00000), + RTW89_DECL_RFK_WM(0x763c, 0x3fffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7640, 0x3fffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7644, 0x000fffff, 0x00000), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_align_b_5g1_all_defs); + +static const struct rtw89_reg5_def rtw8852bt_tssi_align_b_5g2_all_defs[] = { + RTW89_DECL_RFK_WM(0x7604, 0x80000000, 0x1), + RTW89_DECL_RFK_WM(0x7600, 0x3fffffff, 0x3f2d2721), + RTW89_DECL_RFK_WM(0x7604, 0x003fffff, 0x010101), + RTW89_DECL_RFK_WM(0x7630, 0x3fffffff, 0x01201fe2), + RTW89_DECL_RFK_WM(0x7634, 0x3fffffff, 0x00000066), + RTW89_DECL_RFK_WM(0x7638, 0x000fffff, 0x00000), + RTW89_DECL_RFK_WM(0x763c, 0x3fffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7640, 0x3fffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7644, 0x000fffff, 0x00000), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_align_b_5g2_all_defs); + +static const struct rtw89_reg5_def rtw8852bt_tssi_align_b_5g3_all_defs[] = { + RTW89_DECL_RFK_WM(0x7604, 0x80000000, 0x1), + RTW89_DECL_RFK_WM(0x7600, 0x3fffffff, 0x3f2d2721), + RTW89_DECL_RFK_WM(0x7604, 0x003fffff, 0x010101), + RTW89_DECL_RFK_WM(0x7630, 0x3fffffff, 0x01602fe5), + RTW89_DECL_RFK_WM(0x7634, 0x3fffffff, 0x00000068), + RTW89_DECL_RFK_WM(0x7638, 0x000fffff, 0x00000), + RTW89_DECL_RFK_WM(0x763c, 0x3fffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7640, 0x3fffffff, 0x00000000), + RTW89_DECL_RFK_WM(0x7644, 0x000fffff, 0x00000), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_align_b_5g3_all_defs); + +static const struct rtw89_reg5_def rtw8852bt_tssi_slope_defs_a[] = { + RTW89_DECL_RFK_WM(0x5814, 0x00000800, 0x1), + RTW89_DECL_RFK_WM(0x581c, 0x20000000, 0x1), + RTW89_DECL_RFK_WM(0x5814, 0x20000000, 0x1), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_slope_defs_a); + +static const struct rtw89_reg5_def rtw8852bt_tssi_slope_defs_b[] = { + RTW89_DECL_RFK_WM(0x7814, 0x00000800, 0x1), + RTW89_DECL_RFK_WM(0x781c, 0x20000000, 0x1), + RTW89_DECL_RFK_WM(0x7814, 0x20000000, 0x1), +}; + +RTW89_DECLARE_RFK_TBL(rtw8852bt_tssi_slope_defs_b); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk_table.h b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk_table.h new file mode 100644 index 000000000000..beb246237d17 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk_table.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2024 Realtek Corporation + */ + +#ifndef __RTW89_8852BT_RFK_TABLE_H__ +#define __RTW89_8852BT_RFK_TABLE_H__ + +#include "phy.h" + +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_sys_defs_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_sys_a_defs_2g_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_sys_a_defs_5g_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_sys_b_defs_2g_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_sys_b_defs_5g_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_init_txpwr_defs_a_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_init_txpwr_defs_b_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_init_txpwr_he_tb_defs_a_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_init_txpwr_he_tb_defs_b_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_dck_defs_a_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_dck_defs_b_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_dac_gain_defs_a_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_dac_gain_defs_b_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_slope_a_defs_2g_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_slope_a_defs_5g_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_slope_b_defs_2g_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_slope_b_defs_5g_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_align_a_2g_all_defs_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_align_a_5g1_all_defs_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_align_a_5g2_all_defs_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_align_a_5g3_all_defs_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_align_b_2g_all_defs_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_align_b_5g1_all_defs_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_align_b_5g2_all_defs_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_align_b_5g3_all_defs_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_slope_defs_a_tbl; +extern const struct rtw89_rfk_tbl rtw8852bt_tssi_slope_defs_b_tbl; + +#endif From 5b8c61b82eec9ed267d02331f7ff6b126d9f1253 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 21 Jun 2024 15:34:58 +0800 Subject: [PATCH 048/204] wifi: rtw89: 8852bt: rfk: add DPK DPK is short for digital pre-distortion calibration. It can adjusts digital waveform according to PA linear characteristics dynamically to enhance TX EVM for high power. Do this calibration when we are going to run on AP channel. To prevent power offset out of boundary, it monitors thermal and set proper boundary to register. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240621073458.55187-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 2 + drivers/net/wireless/realtek/rtw89/reg.h | 24 + .../wireless/realtek/rtw89/rtw8852bt_rfk.c | 1333 +++++++++++++++++ .../wireless/realtek/rtw89/rtw8852bt_rfk.h | 3 + 4 files changed, 1362 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index f1de975c5356..e1bcac7e1324 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4764,6 +4764,8 @@ struct rtw89_dpk_info { u8 cur_idx[RTW89_DPK_RF_PATH]; u8 cur_k_set; struct rtw89_dpk_bkup_para bp[RTW89_DPK_RF_PATH][RTW89_DPK_BKUP_NUM]; + u8 max_dpk_txagc[RTW89_DPK_RF_PATH]; + u32 dpk_order[RTW89_DPK_RF_PATH]; }; struct rtw89_fem_info { diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index ed4964312063..177981a108e0 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -7877,6 +7877,7 @@ #define R_RXCCA_BE1 0x0520 #define B_RXCCA_BE1_DIS BIT(0) #define R_UPD_CLK_ADC 0x0700 +#define B_UPD_GEN_ON BIT(27) #define B_UPD_CLK_ADC_VAL GENMASK(26, 25) #define B_UPD_CLK_ADC_ON BIT(24) #define B_ENABLE_CCK BIT(5) @@ -7945,6 +7946,8 @@ #define B_MEASUREMENT_TRIG_MSK BIT(2) #define B_CCX_TRIG_OPT_MSK BIT(1) #define B_CCX_EN_MSK BIT(0) +#define R_FAHM 0x0C1C +#define B_RXTD_CKEN BIT(2) #define R_IFS_COUNTER 0x0C28 #define B_IFS_CLM_PERIOD_MSK GENMASK(31, 16) #define B_IFS_CLM_COUNTER_UNIT_MSK GENMASK(15, 14) @@ -7978,6 +7981,7 @@ #define B_IQK_DPK_RST BIT(0) #define R_TX_COLLISION_T2R_ST 0x0C70 #define B_TX_COLLISION_T2R_ST_M GENMASK(25, 20) +#define B_TXRX_FORCE_VAL GENMASK(9, 0) #define R_TXGATING 0x0C74 #define B_TXGATING_EN BIT(4) #define R_TXRFC 0x0C7C @@ -8038,6 +8042,7 @@ #define B_P0_RFMODE_FTM_RX GENMASK(11, 0) #define R_P0_NRBW 0x12B8 #define B_P0_NRBW_DBG BIT(30) +#define B_P0_NRBW_RSTB BIT(28) #define R_S0_RXDC 0x12D4 #define B_S0_RXDC_I GENMASK(25, 16) #define B_S0_RXDC_Q GENMASK(31, 26) @@ -8119,6 +8124,8 @@ #define R_S0_ADDCK 0x1E00 #define B_S0_ADDCK_I GENMASK(9, 0) #define B_S0_ADDCK_Q GENMASK(19, 10) +#define R_TXCKEN_FORCE 0x2008 +#define B_TXCKEN_FORCE_ALL GENMASK(24, 0) #define R_EDCCA_RPT_SEL 0x20CC #define B_EDCCA_RPT_SEL_MSK GENMASK(2, 0) #define R_ADC_FIFO 0x20fc @@ -8274,6 +8281,7 @@ #define R_DCFO_COMP_S0 0x448C #define B_DCFO_COMP_S0_MSK GENMASK(11, 0) #define R_DCFO_WEIGHT 0x4490 +#define B_DAC_CLK_IDX BIT(31) #define B_DCFO_WEIGHT_MSK GENMASK(27, 24) #define R_DCFO_OPT 0x4494 #define B_DCFO_OPT_EN BIT(29) @@ -8636,6 +8644,8 @@ #define B_P0_TMETER GENMASK(15, 10) #define B_P0_TMETER_DIS BIT(16) #define B_P0_TMETER_TRK BIT(24) +#define R_P0_ADCFF_EN 0x58C8 +#define B_P0_ADCFF_EN BIT(24) #define R_P1_TSSIC 0x7814 #define B_P1_TSSIC_BYPASS BIT(11) #define R_P0_TSSI_TRK 0x5818 @@ -8647,6 +8657,7 @@ #define B_P0_TSSI_EN BIT(31) #define B_P0_TSSI_AVG GENMASK(15, 12) #define R_P0_RFCTM 0x5864 +#define B_P0_CLKG_FORCE GENMASK(31, 30) #define B_P0_RFCTM_EN BIT(29) #define B_P0_RFCTM_VAL GENMASK(25, 20) #define R_P0_RFCTM_RDY BIT(26) @@ -8680,12 +8691,14 @@ #define B_P0_RFM_BT_EN BIT(5) #define B_P0_RFM_OUT GENMASK(4, 0) #define R_P0_PATH_RST 0x58AC +#define B_P0_PATH_RST BIT(27) #define R_P0_TXDPD 0x58D4 #define B_P0_TXDPD GENMASK(31, 28) #define R_P0_TXPW_RSTB 0x58DC #define B_P0_TXPW_RSTB_MANON BIT(30) #define B_P0_TXPW_RSTB_TSSI BIT(31) #define R_P0_TSSI_MV_AVG 0x58E4 +#define B_P0_TXPW_RSTB GENMASK(28, 27) #define B_P0_TSSI_MV_MIX GENMASK(19, 11) #define B_P0_TSSI_MV_AVG GENMASK(13, 11) #define B_P0_TSSI_MV_CLR BIT(14) @@ -8810,6 +8823,10 @@ #define B_P1_TSSI_ALIM2 GENMASK(29, 0) #define R_P1_TSSI_ADC_CLK 0x766c #define B_P1_TSSI_ADC_CLK GENMASK(17, 16) +#define R_P1_TXAGC_TH 0x7800 +#define B_P1_TXAGC_MAXMIN GENMASK(15, 0) +#define R_P1_TXPW_FORCE 0x780C +#define B_P1_TXPW_RDY BIT(15) #define R_P1_TSSIC 0x7814 #define B_P1_TSSIC_BYPASS BIT(11) #define R_P1_TMETER 0x7810 @@ -8825,14 +8842,20 @@ #define B_P1_TSSI_EN BIT(31) #define B_P1_TSSI_AVG GENMASK(15, 12) #define R_P1_RFCTM 0x7864 +#define B_P1_CLKG_FORCE GENMASK(31, 30) +#define B_P1_GOT_TXRX GENMASK(28, 27) #define R_P1_RFCTM_RDY BIT(26) #define B_P1_RFCTM_VAL GENMASK(25, 20) #define B_P1_RFCTM_DEL GENMASK(19, 11) #define R_P1_PATH_RST 0x78AC +#define B_P1_PATH_RST BIT(27) +#define R_P1_ADCFF_EN 0x78C8 +#define B_P1_ADCFF_EN BIT(24) #define R_P1_TXPW_RSTB 0x78DC #define B_P1_TXPW_RSTB_MANON BIT(30) #define B_P1_TXPW_RSTB_TSSI BIT(31) #define R_P1_TSSI_MV_AVG 0x78E4 +#define B_P1_TXPW_RSTB GENMASK(28, 27) #define B_P1_TSSI_MV_MIX GENMASK(19, 11) #define B_P1_TSSI_MV_AVG GENMASK(13, 11) #define B_P1_TSSI_MV_CLR BIT(14) @@ -9051,6 +9074,7 @@ #define B_IQKINF2_FCNT GENMASK(23, 16) #define B_IQKINF2_KCNT GENMASK(15, 8) #define B_IQKINF2_NCTLV GENMASK(7, 0) +#define R_RFK_ST 0xBFF8 #define R_DCOF0 0xC000 #define B_DCOF0_RST BIT(17) #define B_DCOF0_V GENMASK(4, 1) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c index dcc15797f5db..d0a40eabfe2d 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c @@ -13,9 +13,77 @@ #include "rtw8852bt_rfk_table.h" #include "rtw8852b_common.h" +#define RTW8852BT_SS 2 #define RTW8852BT_TSSI_PATH_NR 2 +#define RTW8852BT_DPK_VER 0x06 +#define DPK_RF_PATH_MAX_8852BT 2 #define _TSSI_DE_MASK GENMASK(21, 12) +#define DPK_TXAGC_LOWER 0x2e +#define DPK_TXAGC_UPPER 0x3f +#define DPK_TXAGC_INVAL 0xff +#define RFREG_MASKRXBB 0x003e0 +#define RFREG_MASKMODE 0xf0000 + +enum rf_mode { + RF_SHUT_DOWN = 0x0, + RF_STANDBY = 0x1, + RF_TX = 0x2, + RF_RX = 0x3, + RF_TXIQK = 0x4, + RF_DPK = 0x5, + RF_RXK1 = 0x6, + RF_RXK2 = 0x7, +}; + +enum rtw8852bt_dpk_id { + LBK_RXIQK = 0x06, + SYNC = 0x10, + MDPK_IDL = 0x11, + MDPK_MPA = 0x12, + GAIN_LOSS = 0x13, + GAIN_CAL = 0x14, + DPK_RXAGC = 0x15, + KIP_PRESET = 0x16, + KIP_RESTORE = 0x17, + DPK_TXAGC = 0x19, + D_KIP_PRESET = 0x28, + D_TXAGC = 0x29, + D_RXAGC = 0x2a, + D_SYNC = 0x2b, + D_GAIN_LOSS = 0x2c, + D_MDPK_IDL = 0x2d, + D_GAIN_NORM = 0x2f, + D_KIP_THERMAL = 0x30, + D_KIP_RESTORE = 0x31 +}; + +enum dpk_agc_step { + DPK_AGC_STEP_SYNC_DGAIN, + DPK_AGC_STEP_GAIN_ADJ, + DPK_AGC_STEP_GAIN_LOSS_IDX, + DPK_AGC_STEP_GL_GT_CRITERION, + DPK_AGC_STEP_GL_LT_CRITERION, + DPK_AGC_STEP_SET_TX_GAIN, +}; + +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_trigger[RTW8852BT_TSSI_PATH_NR] = {0x5820, 0x7820}; static const u32 _tssi_cw_rpt_addr[RTW8852BT_TSSI_PATH_NR] = {0x1c18, 0x3c18}; @@ -33,6 +101,116 @@ static const u32 _tssi_de_mcs_80m_80m[RF_PATH_NUM_8852BT] = {0x5850, 0x7850}; static const u32 _tssi_de_mcs_5m[RF_PATH_NUM_8852BT] = {0x5828, 0x7828}; static const u32 _tssi_de_mcs_10m[RF_PATH_NUM_8852BT] = {0x5830, 0x7830}; +static const u32 rtw8852bt_backup_bb_regs[] = {0x2344, 0x5800, 0x7800, 0x0704}; +static const u32 rtw8852bt_backup_rf_regs[] = { + 0xde, 0xdf, 0x8b, 0x90, 0x97, 0x85, 0x5, 0x10005}; +static const u32 rtw8852bt_backup_kip_regs[] = { + 0x813c, 0x8124, 0x8120, 0xc0d4, 0xc0d8, 0xc0c4, 0xc0ec, + 0x823c, 0x8224, 0x8220, 0xc1d4, 0xc1d8, 0xc1c4, 0xc1ec}; + +#define BACKUP_BB_REGS_NR ARRAY_SIZE(rtw8852bt_backup_bb_regs) +#define BACKUP_RF_REGS_NR ARRAY_SIZE(rtw8852bt_backup_rf_regs) +#define BACKUP_KIP_REGS_NR ARRAY_SIZE(rtw8852bt_backup_kip_regs) + +static void _rfk_get_thermal(struct rtw89_dev *rtwdev, u8 kidx, enum rtw89_rf_path path) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + + rtw89_write_rf(rtwdev, path, RR_TM, RR_TM_TRI, 0x1); + rtw89_write_rf(rtwdev, path, RR_TM, RR_TM_TRI, 0x0); + rtw89_write_rf(rtwdev, path, RR_TM, RR_TM_TRI, 0x1); + + udelay(200); + + dpk->bp[path][kidx].ther_dpk = rtw89_read_rf(rtwdev, path, RR_TM, RR_TM_VAL); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] thermal@DPK = 0x%x\n", + dpk->bp[path][kidx].ther_dpk); +} + +static void _rfk_backup_bb_reg(struct rtw89_dev *rtwdev, u32 backup_bb_reg_val[]) +{ + u32 i; + + for (i = 0; i < BACKUP_BB_REGS_NR; i++) { + backup_bb_reg_val[i] = + rtw89_phy_read32_mask(rtwdev, rtw8852bt_backup_bb_regs[i], MASKDWORD); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RFK]backup bb reg : %x, value =%x\n", + rtw8852bt_backup_bb_regs[i], backup_bb_reg_val[i]); + } +} + +static void _rfk_backup_kip_reg(struct rtw89_dev *rtwdev, u32 backup_kip_reg_val[]) +{ + u32 i; + + for (i = 0; i < BACKUP_KIP_REGS_NR; i++) { + backup_kip_reg_val[i] = + rtw89_phy_read32_mask(rtwdev, rtw8852bt_backup_kip_regs[i], + MASKDWORD); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] Backup 0x%x = %x\n", + rtw8852bt_backup_kip_regs[i], backup_kip_reg_val[i]); + } +} + +static +void _rfk_backup_rf_reg(struct rtw89_dev *rtwdev, u32 backup_rf_reg_val[], u8 rf_path) +{ + u32 i; + + for (i = 0; i < BACKUP_RF_REGS_NR; i++) { + backup_rf_reg_val[i] = + rtw89_read_rf(rtwdev, rf_path, rtw8852bt_backup_rf_regs[i], + RFREG_MASK); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] Backup RF S%d 0x%x = %x\n", + rf_path, rtw8852bt_backup_rf_regs[i], backup_rf_reg_val[i]); + } +} + +static void _rfk_reload_bb_reg(struct rtw89_dev *rtwdev, const u32 backup_bb_reg_val[]) +{ + u32 i; + + for (i = 0; i < BACKUP_BB_REGS_NR; i++) { + rtw89_phy_write32_mask(rtwdev, rtw8852bt_backup_bb_regs[i], + MASKDWORD, backup_bb_reg_val[i]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RFK]restore bb reg : %x, value =%x\n", + rtw8852bt_backup_bb_regs[i], backup_bb_reg_val[i]); + } +} + +static void _rfk_reload_kip_reg(struct rtw89_dev *rtwdev, u32 backup_kip_reg_val[]) +{ + u32 i; + + for (i = 0; i < BACKUP_KIP_REGS_NR; i++) { + rtw89_phy_write32_mask(rtwdev, rtw8852bt_backup_kip_regs[i], + MASKDWORD, backup_kip_reg_val[i]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RFK]restore kip reg : %x, value =%x\n", + rtw8852bt_backup_kip_regs[i], backup_kip_reg_val[i]); + } +} + +static void _rfk_reload_rf_reg(struct rtw89_dev *rtwdev, + const u32 backup_rf_reg_val[], u8 rf_path) +{ + u32 i; + + for (i = 0; i < BACKUP_RF_REGS_NR; i++) { + rtw89_write_rf(rtwdev, rf_path, rtw8852bt_backup_rf_regs[i], + RFREG_MASK, backup_rf_reg_val[i]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RFK]restore rf S%d reg: %x, value =%x\n", rf_path, + rtw8852bt_backup_rf_regs[i], backup_rf_reg_val[i]); + } +} + static u8 _kpath(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { u8 val; @@ -51,6 +229,124 @@ static u8 _kpath(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) return val; } +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) +{ + u32 bw = 0; + + 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_480M: + bw = RTW89_CHANNEL_WIDTH_40; + break; + case ADC_960M: + bw = RTW89_CHANNEL_WIDTH_80; + break; + case ADC_1920M: + bw = RTW89_CHANNEL_WIDTH_160; + break; + default: + rtw89_debug(rtwdev, RTW89_DBG_RFK, "%s==>Invalid ck", __func__); + break; + } + + rtw8852bx_adc_cfg(rtwdev, bw, path); +} + +static void _rfk_bb_afe_setting(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, u8 kpath) +{ + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, MASKHWORD, 0x0303); + rtw89_phy_write32_mask(rtwdev, R_P0_ADCFF_EN, B_P0_ADCFF_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P1_ADCFF_EN, B_P1_ADCFF_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_CLKG_FORCE, 0x3); + rtw89_phy_write32_mask(rtwdev, R_P1_RFCTM, B_P1_CLKG_FORCE, 0x3); + rtw89_phy_write32_mask(rtwdev, R_TXCKEN_FORCE, B_TXCKEN_FORCE_ALL, 0x1ffffff); + rtw89_phy_write32_mask(rtwdev, R_FAHM, B_RXTD_CKEN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, B_UPD_GEN_ON, 0x1); + rtw89_phy_write32_mask(rtwdev, R_TX_COLLISION_T2R_ST, B_TXRX_FORCE_VAL, 0x3ff); + rtw89_phy_write32_mask(rtwdev, R_IOQ_IQK_DPK, B_IOQ_IQK_DPK_CLKEN, 0x3); + rtw89_phy_write32_mask(rtwdev, R_IQK_DPK_RST, B_IQK_DPK_RST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P0_PATH_RST, B_P0_PATH_RST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P1_PATH_RST, B_P1_PATH_RST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_PD_CTRL, B_PD_HIT_DIS, 0x1); + rtw89_phy_write32_mask(rtwdev, R_RXCCA, B_RXCCA_DIS, 0x1); + rtw89_phy_write32_mask(rtwdev, R_DCFO_WEIGHT, B_DAC_CLK_IDX, 0x1); + + _txck_force(rtwdev, RF_PATH_A, true, DAC_960M); + _txck_force(rtwdev, RF_PATH_B, true, DAC_960M); + _rxck_force(rtwdev, RF_PATH_A, true, ADC_1920M); + _rxck_force(rtwdev, RF_PATH_B, true, ADC_1920M); + + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, + B_UPD_CLK_ADC_VAL | B_UPD_CLK_ADC_ON, 0x5); + rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P1_DBGMOD, B_P1_DBGMOD_ON, 0x1); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, MASKBYTE3, 0x1f); + udelay(1); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, MASKBYTE3, 0x13); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, MASKHWORD, 0x0001); + udelay(1); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, MASKHWORD, 0x0041); + rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_RSTB, 0x1); + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, MASKHWORD, 0x3333); + + rtw89_phy_write32_mask(rtwdev, R_TXPWRB_H, B_TXPWRB_RDY, 0x1); + rtw89_phy_write32_mask(rtwdev, R_DPD_OFT_EN, MASKLWORD, 0x0000); + rtw89_phy_write32_mask(rtwdev, R_P1_TXPW_FORCE, B_P1_TXPW_RDY, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P1_TXAGC_TH, MASKLWORD, 0x0000); +} + +static void _rfk_bb_afe_restore(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, u8 kpath) +{ + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, MASKHWORD, 0x0303); + rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P1_DBGMOD, B_P1_DBGMOD_ON, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_CLKG_FORCE, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P1_RFCTM, B_P1_CLKG_FORCE, 0x0); + rtw89_phy_write32_mask(rtwdev, R_TXCKEN_FORCE, B_TXCKEN_FORCE_ALL, 0x0); + rtw89_phy_write32_mask(rtwdev, R_FAHM, B_RXTD_CKEN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, B_UPD_GEN_ON, 0x0); + rtw89_phy_write32_mask(rtwdev, R_TX_COLLISION_T2R_ST, B_TXRX_FORCE_VAL, 0x63); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_TXCK_ALL, 0x00); + rtw89_phy_write32_mask(rtwdev, R_P1_RXCK, B_P1_TXCK_ALL, 0x00); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, + B_UPD_CLK_ADC_VAL | B_UPD_CLK_ADC_ON, 0x0); + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, MASKHWORD, 0x0000); + rtw89_phy_write32_mask(rtwdev, R_P0_ADCFF_EN, B_P0_ADCFF_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P1_ADCFF_EN, B_P1_ADCFF_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PD_CTRL, B_PD_HIT_DIS, 0x0); + + rtw89_phy_write32_mask(rtwdev, R_TXPWRB_H, B_TXPWRB_RDY, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_MV_AVG, B_P0_TXPW_RSTB, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_MV_AVG, B_P0_TXPW_RSTB, 0x2); + rtw89_phy_write32_mask(rtwdev, R_P1_TXPW_FORCE, B_P1_TXPW_RDY, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_MV_AVG, B_P1_TXPW_RSTB, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_MV_AVG, B_P1_TXPW_RSTB, 0x2); +} + static void _wait_rx_mode(struct rtw89_dev *rtwdev, u8 kpath) { u32 rf_mode; @@ -78,6 +374,1011 @@ static void _tmac_tx_pause(struct rtw89_dev *rtwdev, enum rtw89_phy_idx band_idx _wait_rx_mode(rtwdev, _kpath(rtwdev, band_idx)); } +static void _dpk_onoff(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, bool off) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + u8 val, kidx = dpk->cur_idx[path]; + bool off_reverse; + + val = dpk->is_dpk_enable && !off && dpk->bp[path][kidx].path_ok; + + if (off) + off_reverse = false; + else + off_reverse = true; + + val = dpk->is_dpk_enable & off_reverse & dpk->bp[path][kidx].path_ok; + + rtw89_phy_write32_mask(rtwdev, R_DPD_CH0A + (path << 8) + (kidx << 2), + BIT(24), val); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d[%d] DPK %s !!!\n", path, + kidx, dpk->is_dpk_enable & off_reverse ? "enable" : "disable"); +} + +static void _dpk_one_shot(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, enum rtw8852bt_dpk_id id) +{ + u16 dpk_cmd; + u32 val; + int ret; + + dpk_cmd = (id << 8) | (0x19 + (path << 4)); + rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, dpk_cmd); + + ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, val, val == 0x55, + 1, 30000, false, + rtwdev, R_RFK_ST, MASKBYTE0); + if (ret) + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] one-shot 1 over 30ms!!!!\n"); + + udelay(1); + rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, MASKDWORD, 0x00030000); + + ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, val, val == 0x8000, + 1, 2000, false, + rtwdev, R_RPT_COM, MASKLWORD); + if (ret) + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] one-shot 2 over 2ms!!!!\n"); + + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, MASKBYTE0, 0x0); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] one-shot for %s = 0x%04x\n", + id == 0x06 ? "LBK_RXIQK" : + id == 0x10 ? "SYNC" : + id == 0x11 ? "MDPK_IDL" : + id == 0x12 ? "MDPK_MPA" : + id == 0x13 ? "GAIN_LOSS" : + id == 0x14 ? "PWR_CAL" : + id == 0x15 ? "DPK_RXAGC" : + id == 0x16 ? "KIP_PRESET" : + id == 0x17 ? "KIP_RESOTRE" : + "DPK_TXAGC", dpk_cmd); +} + +static void _dpk_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + rtw89_write_rf(rtwdev, path, RR_DCK, RR_DCK_LV, 0x0); + rtw89_write_rf(rtwdev, path, RR_DCK, RR_DCK_LV, 0x1); + + udelay(600); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d RXDCK\n", path); +} + +static void _dpk_information(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + + u8 kidx = dpk->cur_idx[path]; + + dpk->bp[path][kidx].band = chan->band_type; + dpk->bp[path][kidx].ch = chan->channel; + dpk->bp[path][kidx].bw = chan->band_width; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] S%d[%d] (PHY%d): TSSI %s/ DBCC %s/ %s/ CH%d/ %s\n", + path, dpk->cur_idx[path], phy, + rtwdev->is_tssi_mode[path] ? "on" : "off", + rtwdev->dbcc_en ? "on" : "off", + dpk->bp[path][kidx].band == 0 ? "2G" : + dpk->bp[path][kidx].band == 1 ? "5G" : "6G", + dpk->bp[path][kidx].ch, + dpk->bp[path][kidx].bw == 0 ? "20M" : + dpk->bp[path][kidx].bw == 1 ? "40M" : "80M"); +} + +static void _dpk_tssi_pause(struct rtw89_dev *rtwdev, + enum rtw89_rf_path path, bool is_pause) +{ + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK + (path << 13), + B_P0_TSSI_TRK_EN, is_pause); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d TSSI %s\n", path, + is_pause ? "pause" : "resume"); +} + +static void _dpk_kip_restore(struct rtw89_dev *rtwdev, + enum rtw89_rf_path path) +{ + rtw89_phy_write32_mask(rtwdev, R_NCTL_RPT, MASKDWORD, 0x00000000); + rtw89_phy_write32_mask(rtwdev, R_KIP_SYSCFG, MASKDWORD, 0x80000000); + + if (rtwdev->hal.cv > CHIP_CAV) + rtw89_phy_write32_mask(rtwdev, R_DPD_COM + (path << 8), + B_DPD_COM_OF, 0x1); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d restore KIP\n", path); +} + +static void _dpk_lbk_rxiqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, u8 cur_rxbb, u32 rf_18) +{ + rtw89_phy_write32_mask(rtwdev, R_MDPK_RX_DCK, B_MDPK_RX_DCK_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_IQK_RES + (path << 8), B_IQK_RES_RXCFIR, 0x0); + + rtw89_write_rf(rtwdev, path, RR_RSV4, RFREG_MASK, rf_18); + rtw89_write_rf(rtwdev, path, RR_MOD, RFREG_MASKMODE, 0xd); + rtw89_write_rf(rtwdev, path, RR_RXK, RR_RXK_PLLEN, 0x1); + + if (cur_rxbb >= 0x11) + rtw89_write_rf(rtwdev, path, RR_TXIQK, RR_TXIQK_ATT1, 0x13); + else if (cur_rxbb <= 0xa) + rtw89_write_rf(rtwdev, path, RR_TXIQK, RR_TXIQK_ATT1, 0x00); + else + rtw89_write_rf(rtwdev, path, RR_TXIQK, RR_TXIQK_ATT1, 0x05); + + rtw89_write_rf(rtwdev, path, RR_XGLNA2, RR_XGLNA2_SW, 0x0); + rtw89_write_rf(rtwdev, path, RR_RXKPLL, RR_RXKPLL_POW, 0x0); + rtw89_write_rf(rtwdev, path, RR_RXKPLL, RFREG_MASK, 0x80014); + + udelay(100); + + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x025); + + _dpk_one_shot(rtwdev, phy, path, LBK_RXIQK); + + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); + + rtw89_write_rf(rtwdev, path, RR_RXK, RR_RXK_PLLEN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_MDPK_RX_DCK, B_MDPK_RX_DCK_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_KPATH_CFG, B_KPATH_CFG_ED, 0x0); + rtw89_phy_write32_mask(rtwdev, R_LOAD_COEF + (path << 8), B_LOAD_COEF_DI, 0x1); + rtw89_write_rf(rtwdev, path, RR_MOD, RFREG_MASKMODE, 0x5); +} + +static void _dpk_rf_setting(struct rtw89_dev *rtwdev, u8 gain, + enum rtw89_rf_path path, u8 kidx) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + + if (dpk->bp[path][kidx].band == RTW89_BAND_2G) { + rtw89_write_rf(rtwdev, path, RR_MOD, RFREG_MASK, 0x50220); + rtw89_write_rf(rtwdev, path, RR_RXBB, RR_RXBB_FATT, 0xf2); + rtw89_write_rf(rtwdev, path, RR_LUTDBG, RR_LUTDBG_TIA, 0x1); + rtw89_write_rf(rtwdev, path, RR_TIA, RR_TIA_N6, 0x1); + } else { + rtw89_write_rf(rtwdev, path, RR_MOD, RFREG_MASK, 0x50220); + rtw89_write_rf(rtwdev, path, RR_RXA2, RR_RAA2_SWATT, 0x5); + rtw89_write_rf(rtwdev, path, RR_LUTDBG, RR_LUTDBG_TIA, 0x1); + rtw89_write_rf(rtwdev, path, RR_TIA, RR_TIA_N6, 0x1); + rtw89_write_rf(rtwdev, path, RR_RXA_LNA, RFREG_MASK, 0x920FC); + rtw89_write_rf(rtwdev, path, RR_XALNA2, RFREG_MASK, 0x002C0); + rtw89_write_rf(rtwdev, path, RR_IQGEN, RFREG_MASK, 0x38800); + } + + rtw89_write_rf(rtwdev, path, RR_RCKD, RR_RCKD_BW, 0x1); + rtw89_write_rf(rtwdev, path, RR_BTC, RR_BTC_TXBB, dpk->bp[path][kidx].bw + 1); + rtw89_write_rf(rtwdev, path, RR_BTC, RR_BTC_RXBB, 0x0); +} + +static void _dpk_bypass_rxcfir(struct rtw89_dev *rtwdev, + enum rtw89_rf_path path, bool is_bypass) +{ + if (is_bypass) { + rtw89_phy_write32_mask(rtwdev, R_RXIQC + (path << 8), + B_RXIQC_BYPASS2, 0x1); + rtw89_phy_write32_mask(rtwdev, R_RXIQC + (path << 8), + B_RXIQC_BYPASS, 0x1); + } else { + rtw89_phy_write32_mask(rtwdev, R_RXIQC + (path << 8), + B_RXIQC_BYPASS2, 0x0); + rtw89_phy_write32_mask(rtwdev, R_RXIQC + (path << 8), + B_RXIQC_BYPASS, 0x0); + } +} + +static +void _dpk_tpg_sel(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, u8 kidx) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + + if (dpk->bp[path][kidx].bw == RTW89_CHANNEL_WIDTH_80) + rtw89_phy_write32_mask(rtwdev, R_TPG_MOD, B_TPG_MOD_F, 0x0); + else if (dpk->bp[path][kidx].bw == RTW89_CHANNEL_WIDTH_40) + rtw89_phy_write32_mask(rtwdev, R_TPG_MOD, B_TPG_MOD_F, 0x2); + else + rtw89_phy_write32_mask(rtwdev, R_TPG_MOD, B_TPG_MOD_F, 0x1); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] TPG_Select for %s\n", + dpk->bp[path][kidx].bw == RTW89_CHANNEL_WIDTH_80 ? "80M" : + dpk->bp[path][kidx].bw == RTW89_CHANNEL_WIDTH_40 ? "40M" : "20M"); +} + +static void _dpk_table_select(struct rtw89_dev *rtwdev, + enum rtw89_rf_path path, u8 kidx, u8 gain) +{ + u8 val; + + val = 0x80 + kidx * 0x20 + gain * 0x10; + rtw89_phy_write32_mask(rtwdev, R_DPD_CH0 + (path << 8), MASKBYTE3, val); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] table select for Kidx[%d], Gain[%d] (0x%x)\n", kidx, + gain, val); +} + +static bool _dpk_sync_check(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, u8 kidx) +{ +#define DPK_SYNC_TH_DC_I 200 +#define DPK_SYNC_TH_DC_Q 200 +#define DPK_SYNC_TH_CORR 170 + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + u8 corr_val, corr_idx; + u16 dc_i, dc_q; + u32 corr, dc; + + rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, B_KIP_RPT1_SEL, 0x0); + + corr = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, MASKDWORD); + corr_idx = u32_get_bits(corr, B_PRT_COM_CORI); + corr_val = u32_get_bits(corr, B_PRT_COM_CORV); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] S%d Corr_idx / Corr_val = %d / %d\n", + path, corr_idx, corr_val); + + dpk->corr_idx[path][kidx] = corr_idx; + dpk->corr_val[path][kidx] = corr_val; + + rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, B_KIP_RPT1_SEL, 0x9); + + dc = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, MASKDWORD); + dc_i = u32_get_bits(dc, B_PRT_COM_DCI); + dc_q = u32_get_bits(dc, B_PRT_COM_DCQ); + + dc_i = abs(sign_extend32(dc_i, 11)); + dc_q = abs(sign_extend32(dc_q, 11)); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d DC I/Q, = %d / %d\n", + path, dc_i, dc_q); + + dpk->dc_i[path][kidx] = dc_i; + dpk->dc_q[path][kidx] = dc_q; + + if (dc_i > DPK_SYNC_TH_DC_I || dc_q > DPK_SYNC_TH_DC_Q || + corr_val < DPK_SYNC_TH_CORR) + return true; + else + return false; +} + +static void _dpk_sync(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, u8 kidx) +{ + _dpk_one_shot(rtwdev, phy, path, SYNC); +} + +static u16 _dpk_dgain_read(struct rtw89_dev *rtwdev) +{ + u16 dgain; + + rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, B_KIP_RPT1_SEL, 0x0); + + dgain = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, B_PRT_COM_DCI); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] DGain = 0x%x\n", dgain); + + return dgain; +} + +static s8 _dpk_dgain_mapping(struct rtw89_dev *rtwdev, u16 dgain) +{ + static const u16 bnd[15] = { + 0xbf1, 0xaa5, 0x97d, 0x875, 0x789, 0x6b7, 0x5fc, 0x556, + 0x4c1, 0x43d, 0x3c7, 0x35e, 0x2ac, 0x262, 0x220 + }; + s8 offset; + + if (dgain >= bnd[0]) + offset = 0x6; + else if (bnd[0] > dgain && dgain >= bnd[1]) + offset = 0x6; + else if (bnd[1] > dgain && dgain >= bnd[2]) + offset = 0x5; + else if (bnd[2] > dgain && dgain >= bnd[3]) + offset = 0x4; + else if (bnd[3] > dgain && dgain >= bnd[4]) + offset = 0x3; + else if (bnd[4] > dgain && dgain >= bnd[5]) + offset = 0x2; + else if (bnd[5] > dgain && dgain >= bnd[6]) + offset = 0x1; + else if (bnd[6] > dgain && dgain >= bnd[7]) + offset = 0x0; + else if (bnd[7] > dgain && dgain >= bnd[8]) + offset = 0xff; + else if (bnd[8] > dgain && dgain >= bnd[9]) + offset = 0xfe; + else if (bnd[9] > dgain && dgain >= bnd[10]) + offset = 0xfd; + else if (bnd[10] > dgain && dgain >= bnd[11]) + offset = 0xfc; + else if (bnd[11] > dgain && dgain >= bnd[12]) + offset = 0xfb; + else if (bnd[12] > dgain && dgain >= bnd[13]) + offset = 0xfa; + else if (bnd[13] > dgain && dgain >= bnd[14]) + offset = 0xf9; + else if (bnd[14] > dgain) + offset = 0xf8; + else + offset = 0x0; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] DGain offset = %d\n", offset); + + return offset; +} + +static u8 _dpk_gainloss_read(struct rtw89_dev *rtwdev) +{ + rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, B_KIP_RPT1_SEL, 0x6); + rtw89_phy_write32_mask(rtwdev, R_DPK_CFG2, B_DPK_CFG2_ST, 0x1); + + return rtw89_phy_read32_mask(rtwdev, R_RPT_COM, B_PRT_COM_GL); +} + +static void _dpk_gainloss(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, u8 kidx) +{ + _dpk_one_shot(rtwdev, phy, path, GAIN_LOSS); + + rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, B_KIP_RPT1_SEL, 0x6); + rtw89_phy_write32_mask(rtwdev, R_DPK_CFG2, B_DPK_CFG2_ST, 0x1); +} + +static void _dpk_kip_preset(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, u8 kidx) +{ + _dpk_tpg_sel(rtwdev, path, kidx); + _dpk_one_shot(rtwdev, phy, path, KIP_PRESET); +} + +static void _dpk_kip_pwr_clk_on(struct rtw89_dev *rtwdev, + enum rtw89_rf_path path) +{ + rtw89_phy_write32_mask(rtwdev, R_NCTL_RPT, MASKDWORD, 0x00000080); + rtw89_phy_write32_mask(rtwdev, R_KIP_SYSCFG, MASKDWORD, 0x807f030a); + rtw89_phy_write32_mask(rtwdev, R_CFIR_SYS + (path << 8), MASKDWORD, 0xce000a08); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] KIP Power/CLK on\n"); +} + +static +u8 _dpk_txagc_check_8852bt(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, u8 txagc) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + + if (txagc >= dpk->max_dpk_txagc[path]) + txagc = dpk->max_dpk_txagc[path]; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] Set TxAGC = 0x%x\n", txagc); + + return txagc; +} + +static void _dpk_kip_set_txagc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, u8 txagc) +{ + u8 val; + + val = _dpk_txagc_check_8852bt(rtwdev, path, txagc); + rtw89_write_rf(rtwdev, path, RR_TXAGC, RFREG_MASK, val); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); + _dpk_one_shot(rtwdev, phy, path, DPK_TXAGC); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] set TXAGC = 0x%x\n", txagc); +} + +static void _dpk_kip_set_rxagc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + rtw89_phy_write32_mask(rtwdev, R_KIP_MOD, B_KIP_MOD, 0x50220); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); + _dpk_one_shot(rtwdev, phy, path, DPK_RXAGC); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); +} + +static u8 _dpk_set_offset(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, u8 txagc, s8 gain_offset) +{ + txagc = rtw89_read_rf(rtwdev, path, RR_TXAGC, RFREG_MASK); + + if ((txagc - gain_offset) < DPK_TXAGC_LOWER) + txagc = DPK_TXAGC_LOWER; + else if ((txagc - gain_offset) > DPK_TXAGC_UPPER) + txagc = DPK_TXAGC_UPPER; + else + txagc = txagc - gain_offset; + + _dpk_kip_set_txagc(rtwdev, phy, path, txagc); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] tmp_txagc (GL=%d) = 0x%x\n", + gain_offset, txagc); + return txagc; +} + +static bool _dpk_pas_read(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, + u8 is_check) +{ + u32 val1_i = 0, val1_q = 0, val2_i = 0, val2_q = 0; + u8 i; + + rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, MASKBYTE2, 0x06); + rtw89_phy_write32_mask(rtwdev, R_DPK_CFG2, B_DPK_CFG2_ST, 0x0); + rtw89_phy_write32_mask(rtwdev, R_DPK_CFG3, MASKBYTE2, 0x08); + + if (is_check) { + rtw89_phy_write32_mask(rtwdev, R_DPK_CFG3, MASKBYTE3, 0x00); + val1_i = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, MASKHWORD); + val1_i = abs(sign_extend32(val1_i, 11)); + val1_q = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, MASKLWORD); + val1_q = abs(sign_extend32(val1_q, 11)); + + rtw89_phy_write32_mask(rtwdev, R_DPK_CFG3, MASKBYTE3, 0x1f); + val2_i = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, MASKHWORD); + val2_i = abs(sign_extend32(val2_i, 11)); + val2_q = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, MASKLWORD); + val2_q = abs(sign_extend32(val2_q, 11)); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] PAS_delta = 0x%x\n", + phy_div(val1_i * val1_i + val1_q * val1_q, + val2_i * val2_i + val2_q * val2_q)); + } else { + for (i = 0; i < 32; i++) { + rtw89_phy_write32_mask(rtwdev, R_DPK_CFG3, MASKBYTE3, i); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] PAS_Read[%02d]= 0x%08x\n", i, + rtw89_phy_read32_mask(rtwdev, R_RPT_COM, MASKDWORD)); + } + } + + if (val1_i * val1_i + val1_q * val1_q >= + (val2_i * val2_i + val2_q * val2_q) * 8 / 5) + return true; + + return false; +} + +static u8 _dpk_agc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, u8 kidx, u8 init_txagc, + bool loss_only) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + u8 goout = 0, agc_cnt = 0, limited_rxbb = 0, gl_cnt = 0; + u8 tmp_txagc, tmp_rxbb, tmp_gl_idx = 0; + u8 step = DPK_AGC_STEP_SYNC_DGAIN; + int limit = 200; + s8 offset = 0; + u16 dgain = 0; + u32 rf_18; + + tmp_txagc = init_txagc; + + tmp_rxbb = rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASKRXBB); + rf_18 = rtw89_read_rf(rtwdev, path, RR_CFGCH, RFREG_MASK); + + do { + switch (step) { + case DPK_AGC_STEP_SYNC_DGAIN: + _dpk_sync(rtwdev, phy, path, kidx); + if (agc_cnt == 0) { + if (chan->band_width < 2) + _dpk_bypass_rxcfir(rtwdev, path, true); + else + _dpk_lbk_rxiqk(rtwdev, phy, path, + tmp_rxbb, rf_18); + } + + if (_dpk_sync_check(rtwdev, path, kidx) == true) { + tmp_txagc = 0xff; + goout = 1; + break; + } + + dgain = _dpk_dgain_read(rtwdev); + offset = _dpk_dgain_mapping(rtwdev, dgain); + + if (loss_only == 1 || limited_rxbb == 1 || offset == 0) + step = DPK_AGC_STEP_GAIN_LOSS_IDX; + else + step = DPK_AGC_STEP_GAIN_ADJ; + break; + case DPK_AGC_STEP_GAIN_ADJ: + tmp_rxbb = rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASKRXBB); + + if (tmp_rxbb + offset > 0x1f) { + tmp_rxbb = 0x1f; + limited_rxbb = 1; + } else if (tmp_rxbb + offset < 0) { + tmp_rxbb = 0; + limited_rxbb = 1; + } else { + tmp_rxbb = tmp_rxbb + offset; + } + + rtw89_write_rf(rtwdev, path, RR_MOD, RFREG_MASKRXBB, tmp_rxbb); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] Adjust RXBB (%d) = 0x%x\n", offset, tmp_rxbb); + + if (chan->band_width == RTW89_CHANNEL_WIDTH_80) + _dpk_lbk_rxiqk(rtwdev, phy, path, tmp_rxbb, rf_18); + if (dgain > 1922 || dgain < 342) + step = DPK_AGC_STEP_SYNC_DGAIN; + else + step = DPK_AGC_STEP_GAIN_LOSS_IDX; + + agc_cnt++; + break; + case DPK_AGC_STEP_GAIN_LOSS_IDX: + _dpk_gainloss(rtwdev, phy, path, kidx); + + tmp_gl_idx = _dpk_gainloss_read(rtwdev); + + if ((tmp_gl_idx == 0 && _dpk_pas_read(rtwdev, path, true)) || + tmp_gl_idx >= 7) + step = DPK_AGC_STEP_GL_GT_CRITERION; + else if (tmp_gl_idx == 0) + step = DPK_AGC_STEP_GL_LT_CRITERION; + else + step = DPK_AGC_STEP_SET_TX_GAIN; + + gl_cnt++; + break; + case DPK_AGC_STEP_GL_GT_CRITERION: + if (tmp_txagc == 0x2e || + tmp_txagc == dpk->max_dpk_txagc[path]) { + goout = 1; + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] Txagc@lower bound!!\n"); + } else { + tmp_txagc = _dpk_set_offset(rtwdev, phy, path, + tmp_txagc, 0x3); + } + step = DPK_AGC_STEP_GAIN_LOSS_IDX; + agc_cnt++; + break; + + case DPK_AGC_STEP_GL_LT_CRITERION: + if (tmp_txagc == 0x3f || tmp_txagc == dpk->max_dpk_txagc[path]) { + goout = 1; + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] Txagc@upper bound!!\n"); + } else { + tmp_txagc = _dpk_set_offset(rtwdev, phy, path, + tmp_txagc, 0xfe); + } + step = DPK_AGC_STEP_GAIN_LOSS_IDX; + agc_cnt++; + break; + + case DPK_AGC_STEP_SET_TX_GAIN: + tmp_txagc = _dpk_set_offset(rtwdev, phy, path, tmp_txagc, + tmp_gl_idx); + goout = 1; + agc_cnt++; + break; + + default: + goout = 1; + break; + } + } while (!goout && agc_cnt < 6 && limit-- > 0); + + if (gl_cnt >= 6) + _dpk_pas_read(rtwdev, path, false); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] Txagc / RXBB for DPK = 0x%x / 0x%x\n", tmp_txagc, tmp_rxbb); + + return tmp_txagc; +} + +static void _dpk_set_mdpd_para(struct rtw89_dev *rtwdev, + enum rtw89_rf_path path, u8 order) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + + switch (order) { + case 0: /* (5,3,1) */ + rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_OP, order); + rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_PN, 0x3); + rtw89_phy_write32_mask(rtwdev, R_MDPK_SYNC, B_MDPK_SYNC_MAN, 0x1); + dpk->dpk_order[path] = 0x3; + break; + case 1: /* (5,3,0) */ + rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_OP, order); + rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_PN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_MDPK_SYNC, B_MDPK_SYNC_MAN, 0x0); + dpk->dpk_order[path] = 0x1; + break; + case 2: /* (5,0,0) */ + rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_OP, order); + rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_PN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_MDPK_SYNC, B_MDPK_SYNC_MAN, 0x0); + dpk->dpk_order[path] = 0x0; + break; + default: + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] Wrong MDPD order!!(0x%x)\n", order); + break; + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] Set %s for IDL\n", + order == 0x0 ? "(5,3,1)" : + order == 0x1 ? "(5,3,0)" : "(5,0,0)"); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] Set MDPD order to 0x%x for IDL\n", order); +} + +static void _dpk_idl_mpa(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, u8 kidx, u8 gain) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + + if (dpk->bp[path][kidx].bw < RTW89_CHANNEL_WIDTH_80 && + dpk->bp[path][kidx].band == RTW89_BAND_5G) + _dpk_set_mdpd_para(rtwdev, path, 0x2); + else + _dpk_set_mdpd_para(rtwdev, path, 0x0); + + _dpk_one_shot(rtwdev, phy, path, MDPK_IDL); +} + +static void _dpk_fill_result(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, u8 kidx, u8 gain, u8 txagc) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + u8 gs = dpk->dpk_gs[phy]; + u16 pwsf = 0x78; + + rtw89_phy_write32_mask(rtwdev, R_COEF_SEL + (path << 8), BIT(8), kidx); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] Fill txagc/ pwsf/ gs = 0x%x/ 0x%x/ 0x%x\n", + txagc, pwsf, gs); + + dpk->bp[path][kidx].txagc_dpk = txagc; + rtw89_phy_write32_mask(rtwdev, R_TXAGC_RFK + (path << 8), + 0x3F << ((gain << 3) + (kidx << 4)), txagc); + + dpk->bp[path][kidx].pwsf = pwsf; + rtw89_phy_write32_mask(rtwdev, R_DPD_BND + (path << 8) + (kidx << 2), + 0x1FF << (gain << 4), pwsf); + + rtw89_phy_write32_mask(rtwdev, R_LOAD_COEF + (path << 8), B_LOAD_COEF_MDPD, 0x1); + rtw89_phy_write32_mask(rtwdev, R_LOAD_COEF + (path << 8), B_LOAD_COEF_MDPD, 0x0); + + dpk->bp[path][kidx].gs = gs; + if (dpk->dpk_gs[phy] == 0x7f) + rtw89_phy_write32_mask(rtwdev, + R_DPD_CH0A + (path << 8) + (kidx << 2), + MASKDWORD, 0x007f7f7f); + else + rtw89_phy_write32_mask(rtwdev, + R_DPD_CH0A + (path << 8) + (kidx << 2), + MASKDWORD, 0x005b5b5b); + + rtw89_phy_write32_mask(rtwdev, R_DPD_CH0A + (path << 8) + (kidx << 2), + B_DPD_ORDER_V1, dpk->dpk_order[path]); + + rtw89_phy_write32_mask(rtwdev, R_DPD_V1 + (path << 8), MASKDWORD, 0x0); + rtw89_phy_write32_mask(rtwdev, R_MDPK_SYNC, B_MDPK_SYNC_SEL, 0x0); +} + +static bool _dpk_reload_check(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + u8 idx, cur_band, cur_ch; + bool is_reload = false; + + cur_band = chan->band_type; + cur_ch = chan->channel; + + for (idx = 0; idx < RTW89_DPK_BKUP_NUM; idx++) { + if (cur_band != dpk->bp[path][idx].band || + cur_ch != dpk->bp[path][idx].ch) + continue; + + rtw89_phy_write32_mask(rtwdev, R_COEF_SEL + (path << 8), + B_COEF_SEL_MDPD, idx); + dpk->cur_idx[path] = idx; + is_reload = true; + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] reload S%d[%d] success\n", path, idx); + } + + return is_reload; +} + +static +void _rf_direct_cntrl(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, bool is_bybb) +{ + if (is_bybb) + rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x1); + else + rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x0); +} + +static +void _drf_direct_cntrl(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, bool is_bybb) +{ + if (is_bybb) + rtw89_write_rf(rtwdev, path, RR_BBDC, RR_BBDC_SEL, 0x1); + else + rtw89_write_rf(rtwdev, path, RR_BBDC, RR_BBDC_SEL, 0x0); +} + +static bool _dpk_main(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, u8 gain) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + u8 txagc = 0x38, kidx = dpk->cur_idx[path]; + bool is_fail = false; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] ========= S%d[%d] DPK Start =========\n", path, kidx); + + _rf_direct_cntrl(rtwdev, path, false); + _drf_direct_cntrl(rtwdev, path, false); + + _dpk_kip_pwr_clk_on(rtwdev, path); + _dpk_kip_set_txagc(rtwdev, phy, path, txagc); + _dpk_rf_setting(rtwdev, gain, path, kidx); + _dpk_rx_dck(rtwdev, phy, path); + _dpk_kip_preset(rtwdev, phy, path, kidx); + _dpk_kip_set_rxagc(rtwdev, phy, path); + _dpk_table_select(rtwdev, path, kidx, gain); + + txagc = _dpk_agc(rtwdev, phy, path, kidx, txagc, false); + + _rfk_get_thermal(rtwdev, kidx, path); + + if (txagc == 0xff) { + is_fail = true; + goto _error; + } + + _dpk_idl_mpa(rtwdev, phy, path, kidx, gain); + + rtw89_write_rf(rtwdev, path, RR_MOD, RFREG_MASKMODE, RF_RX); + _dpk_fill_result(rtwdev, phy, path, kidx, gain, txagc); + +_error: + if (!is_fail) + dpk->bp[path][kidx].path_ok = 1; + else + dpk->bp[path][kidx].path_ok = 0; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d[%d] DPK %s\n", path, kidx, + is_fail ? "Check" : "Success"); + + _dpk_onoff(rtwdev, path, is_fail); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d[%d] DPK %s\n", path, kidx, + is_fail ? "Check" : "Success"); + + return is_fail; +} + +static void _dpk_cal_select(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy, u8 kpath) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + u32 backup_kip_val[BACKUP_KIP_REGS_NR]; + u32 backup_bb_val[BACKUP_BB_REGS_NR]; + u32 backup_rf_val[RTW8852BT_SS][BACKUP_RF_REGS_NR]; + bool reloaded[2] = {false}; + u8 path; + + for (path = 0; path < DPK_RF_PATH_MAX_8852BT; path++) { + reloaded[path] = _dpk_reload_check(rtwdev, phy, path); + if (!reloaded[path] && dpk->bp[path][0].ch != 0) + dpk->cur_idx[path] = !dpk->cur_idx[path]; + else + _dpk_onoff(rtwdev, path, false); + } + + _rfk_backup_bb_reg(rtwdev, backup_bb_val); + _rfk_backup_kip_reg(rtwdev, backup_kip_val); + + for (path = 0; path < DPK_RF_PATH_MAX_8852BT; path++) { + _rfk_backup_rf_reg(rtwdev, backup_rf_val[path], path); + _dpk_information(rtwdev, phy, path); + if (rtwdev->is_tssi_mode[path]) + _dpk_tssi_pause(rtwdev, path, true); + } + + _rfk_bb_afe_setting(rtwdev, phy, path, kpath); + + for (path = 0; path < DPK_RF_PATH_MAX_8852BT; path++) + _dpk_main(rtwdev, phy, path, 1); + + _rfk_bb_afe_restore(rtwdev, phy, path, kpath); + + _dpk_kip_restore(rtwdev, path); + _rfk_reload_bb_reg(rtwdev, backup_bb_val); + _rfk_reload_kip_reg(rtwdev, backup_kip_val); + + for (path = 0; path < DPK_RF_PATH_MAX_8852BT; path++) { + _rfk_reload_rf_reg(rtwdev, backup_rf_val[path], path); + if (rtwdev->is_tssi_mode[path]) + _dpk_tssi_pause(rtwdev, path, false); + } +} + +static bool _dpk_bypass_check(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + struct rtw89_fem_info *fem = &rtwdev->fem; + + if (fem->epa_2g && chan->band_type == RTW89_BAND_2G) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] Skip DPK due to 2G_ext_PA exist!!\n"); + return true; + } else if (fem->epa_5g && chan->band_type == RTW89_BAND_5G) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] Skip DPK due to 5G_ext_PA exist!!\n"); + return true; + } else if (fem->epa_6g && chan->band_type == RTW89_BAND_6G) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] Skip DPK due to 6G_ext_PA exist!!\n"); + return true; + } + + return false; +} + +static void _dpk_force_bypass(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) +{ + u8 path, kpath; + + kpath = _kpath(rtwdev, phy); + + for (path = 0; path < RTW8852BT_SS; path++) { + if (kpath & BIT(path)) + _dpk_onoff(rtwdev, path, true); + } +} + +static void _dpk_track(struct rtw89_dev *rtwdev) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + s8 txagc_bb, txagc_bb_tp, ini_diff = 0, txagc_ofst; + s8 delta_ther[2] = {}; + u8 trk_idx, txagc_rf; + u8 path, kidx; + u16 pwsf[2]; + u8 cur_ther; + u32 tmp; + + for (path = 0; path < RF_PATH_NUM_8852BT; path++) { + kidx = dpk->cur_idx[path]; + + rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, + "[DPK_TRK] ================[S%d[%d] (CH %d)]================\n", + path, kidx, dpk->bp[path][kidx].ch); + + cur_ther = ewma_thermal_read(&rtwdev->phystat.avg_thermal[path]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, + "[DPK_TRK] thermal now = %d\n", cur_ther); + + if (dpk->bp[path][kidx].ch && cur_ther) + delta_ther[path] = dpk->bp[path][kidx].ther_dpk - cur_ther; + + if (dpk->bp[path][kidx].band == RTW89_BAND_2G) + delta_ther[path] = delta_ther[path] * 3 / 2; + else + delta_ther[path] = delta_ther[path] * 5 / 2; + + txagc_rf = rtw89_phy_read32_mask(rtwdev, R_TXAGC_BB + (path << 13), + B_TXAGC_RF); + + if (rtwdev->is_tssi_mode[path]) { + trk_idx = rtw89_read_rf(rtwdev, path, RR_TXA, RR_TXA_TRK); + + rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, + "[DPK_TRK] txagc_RF / track_idx = 0x%x / %d\n", + txagc_rf, trk_idx); + + txagc_bb = + rtw89_phy_read32_mask(rtwdev, R_TXAGC_BB + (path << 13), + MASKBYTE2); + txagc_bb_tp = + rtw89_phy_read32_mask(rtwdev, R_TXAGC_TP + (path << 13), + B_TXAGC_TP); + + rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, + "[DPK_TRK] txagc_bb_tp / txagc_bb = 0x%x / 0x%x\n", + txagc_bb_tp, txagc_bb); + + txagc_ofst = + rtw89_phy_read32_mask(rtwdev, R_TXAGC_BB + (path << 13), + MASKBYTE3); + + rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, + "[DPK_TRK] txagc_offset / delta_ther = %d / %d\n", + txagc_ofst, delta_ther[path]); + tmp = rtw89_phy_read32_mask(rtwdev, R_DPD_COM + (path << 8), + B_DPD_COM_OF); + if (tmp == 0x1) { + txagc_ofst = 0; + rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, + "[DPK_TRK] HW txagc offset mode\n"); + } + + if (txagc_rf && cur_ther) + ini_diff = txagc_ofst + (delta_ther[path]); + + tmp = rtw89_phy_read32_mask(rtwdev, + R_P0_TXDPD + (path << 13), + B_P0_TXDPD); + if (tmp == 0x0) { + pwsf[0] = dpk->bp[path][kidx].pwsf + + txagc_bb_tp - txagc_bb + ini_diff; + pwsf[1] = dpk->bp[path][kidx].pwsf + + txagc_bb_tp - txagc_bb + ini_diff; + } else { + pwsf[0] = dpk->bp[path][kidx].pwsf + ini_diff; + pwsf[1] = dpk->bp[path][kidx].pwsf + ini_diff; + } + } else { + pwsf[0] = (dpk->bp[path][kidx].pwsf + delta_ther[path]) & 0x1ff; + pwsf[1] = (dpk->bp[path][kidx].pwsf + delta_ther[path]) & 0x1ff; + } + + tmp = rtw89_phy_read32_mask(rtwdev, R_DPK_TRK, B_DPK_TRK_DIS); + if (!tmp && txagc_rf) { + rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, + "[DPK_TRK] New pwsf[0] / pwsf[1] = 0x%x / 0x%x\n", + pwsf[0], pwsf[1]); + + rtw89_phy_write32_mask(rtwdev, + R_DPD_BND + (path << 8) + (kidx << 2), + B_DPD_BND_0, pwsf[0]); + rtw89_phy_write32_mask(rtwdev, + R_DPD_BND + (path << 8) + (kidx << 2), + B_DPD_BND_1, pwsf[1]); + } + } +} + +static void _set_dpd_backoff(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + u8 tx_scale, ofdm_bkof, path, kpath; + + kpath = _kpath(rtwdev, phy); + + ofdm_bkof = rtw89_phy_read32_mask(rtwdev, R_DPD_BF + (phy << 13), B_DPD_BF_OFDM); + tx_scale = rtw89_phy_read32_mask(rtwdev, R_DPD_BF + (phy << 13), B_DPD_BF_SCA); + + if (ofdm_bkof + tx_scale >= 44) { + /* move dpd backoff to bb, and set dpd backoff to 0 */ + dpk->dpk_gs[phy] = 0x7f; + for (path = 0; path < RF_PATH_NUM_8852BT; path++) { + if (!(kpath & BIT(path))) + continue; + + rtw89_phy_write32_mask(rtwdev, R_DPD_CH0A + (path << 8), + B_DPD_CFG, 0x7f7f7f); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RFK] Set S%d DPD backoff to 0dB\n", path); + } + } else { + dpk->dpk_gs[phy] = 0x5b; + } +} + static void _tssi_dpk_off(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) { rtw89_phy_write32_mask(rtwdev, R_DPD_CH0A, BIT(24), 0x0); @@ -1077,6 +2378,38 @@ static void _tssi_alimentk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, tssi_info->tssi_alimk_time); } +void rtw8852bt_dpk_init(struct rtw89_dev *rtwdev) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + + u8 path; + + for (path = 0; path < 2; path++) { + dpk->cur_idx[path] = 0; + dpk->max_dpk_txagc[path] = 0x3F; + } + + dpk->is_dpk_enable = true; + dpk->is_dpk_reload_en = false; + _set_dpd_backoff(rtwdev, RTW89_PHY_0); +} + +void rtw8852bt_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] ****** DPK Start (Ver: 0x%x) ******\n", RTW8852BT_DPK_VER); + + if (_dpk_bypass_check(rtwdev, phy_idx)) + _dpk_force_bypass(rtwdev, phy_idx); + else + _dpk_cal_select(rtwdev, phy_idx, RF_AB); +} + +void rtw8852bt_dpk_track(struct rtw89_dev *rtwdev) +{ + _dpk_track(rtwdev); +} + void rtw8852bt_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool hwtx_en) { static const u32 reg[2] = {R_DPD_CH0A, R_DPD_CH0B}; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h index 03fad3abe554..89640b42d4d0 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h @@ -7,6 +7,9 @@ #include "core.h" +void rtw8852bt_dpk_init(struct rtw89_dev *rtwdev); +void rtw8852bt_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy); +void rtw8852bt_dpk_track(struct rtw89_dev *rtwdev); void rtw8852bt_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool hwtx_en); void rtw8852bt_tssi_scan(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy); void rtw8852bt_wifi_scan_notify(struct rtw89_dev *rtwdev, bool scan_start, From 5f7e92c59b8e03ac90130223c2ebb4449373b9cd Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 21 Jun 2024 20:36:16 +0800 Subject: [PATCH 049/204] wifi: rtw89: 8852b: set AMSDU limit to 5000 Enlarge AMSDU limit to improve MAC efficient to get better TX throughput from 851 to 895 Mbps. No change for RX throughput 902 Mbps. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240621123617.6687-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 24f9fd444ca0..1a9c4951060a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -944,7 +944,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .fifo_size = 196608, .small_fifo_size = true, .dle_scc_rsvd_size = 98304, - .max_amsdu_limit = 3500, + .max_amsdu_limit = 5000, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, .hfc_param_ini = rtw8852b_hfc_param_ini_pcie, From 2f35712ab82683554c660bc2456f05785835efbe Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Fri, 21 Jun 2024 20:36:17 +0800 Subject: [PATCH 050/204] wifi: rtw89: 8852b: fix definition of KIP register number An incorrect definition caused DPK to fail to backup and restore a set of KIP registers. Fixing this will improve RX throughput from 902 to 997 Mbps. Fixes: 5b8471ace5b1 ("wifi: rtw89: 8852b: rfk: add DPK") Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240621123617.6687-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c index 7c90e98dc1d9..12354612441c 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c @@ -21,7 +21,7 @@ #define RTW8852B_RF_REL_VERSION 34 #define RTW8852B_DPK_VER 0x0d #define RTW8852B_DPK_RF_PATH 2 -#define RTW8852B_DPK_KIP_REG_NUM 2 +#define RTW8852B_DPK_KIP_REG_NUM 3 #define _TSSI_DE_MASK GENMASK(21, 12) #define ADDC_T_AVG 100 From d0b4b8ef083ca46d5d318e66a30fb80e0abbb90d Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Mon, 24 Jun 2024 16:00:37 +0200 Subject: [PATCH 051/204] wifi: rtl8xxxu: 8188f: Limit TX power index TX power index is read from the efuse on init, the values get written to the TX power registers when the channel gets switched. When the chip has not yet been calibrated, the efuse values are 0xFF, which on some boards leads to USB timeouts for reading/writing registers after the first frames have been sent. The vendor driver (v5.11.5-1) checks for these invalid values and sets default values instead. Implement something similar in rtl8188fu_parse_efuse(). Fixes: c888183b21f3 ("wifi: rtl8xxxu: Support new chip RTL8188FU") Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240624140037.231657-1-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/8188f.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/8188f.c b/drivers/net/wireless/realtek/rtl8xxxu/8188f.c index bd5a0603b4a2..3abf14d7044f 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/8188f.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/8188f.c @@ -697,9 +697,14 @@ static void rtl8188fu_init_statistics(struct rtl8xxxu_priv *priv) rtl8xxxu_write32(priv, REG_OFDM0_FA_RSTC, val32); } +#define TX_POWER_INDEX_MAX 0x3F +#define TX_POWER_INDEX_DEFAULT_CCK 0x22 +#define TX_POWER_INDEX_DEFAULT_HT40 0x27 + static int rtl8188fu_parse_efuse(struct rtl8xxxu_priv *priv) { struct rtl8188fu_efuse *efuse = &priv->efuse_wifi.efuse8188fu; + int i; if (efuse->rtl_id != cpu_to_le16(0x8129)) return -EINVAL; @@ -713,6 +718,16 @@ static int rtl8188fu_parse_efuse(struct rtl8xxxu_priv *priv) efuse->tx_power_index_A.ht40_base, sizeof(efuse->tx_power_index_A.ht40_base)); + for (i = 0; i < ARRAY_SIZE(priv->cck_tx_power_index_A); i++) { + if (priv->cck_tx_power_index_A[i] > TX_POWER_INDEX_MAX) + priv->cck_tx_power_index_A[i] = TX_POWER_INDEX_DEFAULT_CCK; + } + + for (i = 0; i < ARRAY_SIZE(priv->ht40_1s_tx_power_index_A); i++) { + if (priv->ht40_1s_tx_power_index_A[i] > TX_POWER_INDEX_MAX) + priv->ht40_1s_tx_power_index_A[i] = TX_POWER_INDEX_DEFAULT_HT40; + } + priv->ofdm_tx_power_diff[0].a = efuse->tx_power_index_A.ht20_ofdm_1s_diff.a; priv->ht20_tx_power_diff[0].a = efuse->tx_power_index_A.ht20_ofdm_1s_diff.b; From 9783e0407421a4dfc25e3a3001d0e0cff4236806 Mon Sep 17 00:00:00 2001 From: Rameshkumar Sundaram Date: Wed, 26 Jun 2024 08:12:57 +0530 Subject: [PATCH 052/204] wifi: ath12k: fix driver initialization for WoW unsupported devices Commit 4a3c212eee0e ("wifi: ath12k: add basic WoW functionalities") broke driver initialization, now mac registration is allowed only for devices that advertise WMI_TLV_SERVICE_WOW, but QCN9274 doesn't support WoW and hence mac registration is aborted and driver is de-initialized. Allow mac registration to proceed without WoW Support for devices that don't advertise WMI_TLV_SERVICE_WOW. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Fixes: 4a3c212eee0e ("wifi: ath12k: add basic WoW functionalities") Signed-off-by: Rameshkumar Sundaram Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240626024257.709460-1-quic_ramess@quicinc.com --- drivers/net/wireless/ath/ath12k/wow.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wow.c b/drivers/net/wireless/ath/ath12k/wow.c index 685e8e98d845..c5cba825a84a 100644 --- a/drivers/net/wireless/ath/ath12k/wow.c +++ b/drivers/net/wireless/ath/ath12k/wow.c @@ -1001,8 +1001,8 @@ int ath12k_wow_op_resume(struct ieee80211_hw *hw) int ath12k_wow_init(struct ath12k *ar) { - if (WARN_ON(!test_bit(WMI_TLV_SERVICE_WOW, ar->wmi->wmi_ab->svc_map))) - return -EINVAL; + if (!test_bit(WMI_TLV_SERVICE_WOW, ar->wmi->wmi_ab->svc_map)) + return 0; ar->wow.wowlan_support = ath12k_wowlan_support; From a7e5793035792cc46a1a4b0a783655ffa897dfe9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 27 Jun 2024 10:44:11 +0200 Subject: [PATCH 053/204] wifi: nl80211: don't give key data to userspace When a key is requested by userspace, there's really no need to include the key data, the sequence counter is really what userspace needs in this case. The fact that it's included is just a historic quirk. Remove the key data. Reviewed-by: Miriam Rachel Korenblit Link: https://patch.msgid.link/20240627104411.b6a4f097e4ea.I7e6cc976cb9e8a80ef25a3351330f313373b4578@changeid Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 19d81200a2a2..674368d028f3 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4487,10 +4487,7 @@ static void get_key_callback(void *c, struct key_params *params) struct nlattr *key; struct get_key_cookie *cookie = c; - if ((params->key && - nla_put(cookie->msg, NL80211_ATTR_KEY_DATA, - params->key_len, params->key)) || - (params->seq && + if ((params->seq && nla_put(cookie->msg, NL80211_ATTR_KEY_SEQ, params->seq_len, params->seq)) || (params->cipher && @@ -4502,10 +4499,7 @@ static void get_key_callback(void *c, struct key_params *params) if (!key) goto nla_put_failure; - if ((params->key && - nla_put(cookie->msg, NL80211_KEY_DATA, - params->key_len, params->key)) || - (params->seq && + if ((params->seq && nla_put(cookie->msg, NL80211_KEY_SEQ, params->seq_len, params->seq)) || (params->cipher && From 0a3d5991438fcf89c3aebf55c30231faee31567e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 27 Jun 2024 10:44:12 +0200 Subject: [PATCH 054/204] wifi: mac80211: remove key data from get_key callback This is now unused in nl80211, so there's no need to set the pointer/length. Reviewed-by: Miriam Rachel Korenblit Link: https://patch.msgid.link/20240627104411.f8ac49a8cfe0.Ic01f775903f0acd10b9ba77eb39d4ed50e709173@changeid Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 7eb2e5bedb6f..3d49b3ee3a2b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -742,9 +742,6 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, break; } - params.key = key->conf.key; - params.key_len = key->conf.keylen; - callback(cookie, ¶ms); err = 0; From 3f5d7ff7c533af6f06a39becb77a7afbfaa8b782 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Thu, 27 Jun 2024 10:46:00 +0200 Subject: [PATCH 055/204] wifi: mac80211: Use the link BSS configuration for beacon processing The beacon processing should be fully done in the context of the link. This also resolves a bug with CQM handling with MLO as in such a case the RSSI thresholds configuration is maintained in the link context and not in the interface context. Reviewed-by: Miriam Rachel Korenblit Signed-off-by: Ilan Peer Link: https://patch.msgid.link/20240627104600.bb2f0f697881.I675b6a8a186b717f3eef79113c27361fd1a7622c@changeid Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3d207d79d11f..80a10cd49565 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -6696,7 +6696,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, { struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; + struct ieee80211_bss_conf *bss_conf = link->conf; struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg; struct ieee80211_mgmt *mgmt = (void *) hdr; size_t baselen; @@ -6740,7 +6740,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, parse_params.len = len - baselen; rcu_read_lock(); - chanctx_conf = rcu_dereference(link->conf->chanctx_conf); + chanctx_conf = rcu_dereference(bss_conf->chanctx_conf); if (!chanctx_conf) { rcu_read_unlock(); return; @@ -6770,11 +6770,11 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, ifmgd->assoc_data->need_beacon = false; if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY) && !ieee80211_is_s1g_beacon(hdr->frame_control)) { - link->conf->sync_tsf = + bss_conf->sync_tsf = le64_to_cpu(mgmt->u.beacon.timestamp); - link->conf->sync_device_ts = + bss_conf->sync_device_ts = rx_status->device_timestamp; - link->conf->sync_dtim_count = elems->dtim_count; + bss_conf->sync_dtim_count = elems->dtim_count; } if (elems->mbssid_config_ie) @@ -6798,7 +6798,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, } if (!ifmgd->associated || - !ieee80211_rx_our_beacon(bssid, link->conf->bss)) + !ieee80211_rx_our_beacon(bssid, bss_conf->bss)) return; bssid = link->u.mgd.bssid; @@ -6825,7 +6825,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, */ if (!ieee80211_is_s1g_beacon(hdr->frame_control)) ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); - parse_params.bss = link->conf->bss; + parse_params.bss = bss_conf->bss; parse_params.filter = care_about_ies; parse_params.crc = ncrc; elems = ieee802_11_parse_elems_full(&parse_params); @@ -6906,11 +6906,11 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, */ if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY) && !ieee80211_is_s1g_beacon(hdr->frame_control)) { - link->conf->sync_tsf = + bss_conf->sync_tsf = le64_to_cpu(mgmt->u.beacon.timestamp); - link->conf->sync_device_ts = + bss_conf->sync_device_ts = rx_status->device_timestamp; - link->conf->sync_dtim_count = elems->dtim_count; + bss_conf->sync_dtim_count = elems->dtim_count; } if ((ncrc == link->u.mgd.beacon_crc && link->u.mgd.beacon_crc_valid) || @@ -6973,10 +6973,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, goto free; } - if (WARN_ON(!link->conf->chanreq.oper.chan)) + if (WARN_ON(!bss_conf->chanreq.oper.chan)) goto free; - sband = local->hw.wiphy->bands[link->conf->chanreq.oper.chan->band]; + sband = local->hw.wiphy->bands[bss_conf->chanreq.oper.chan->band]; changed |= ieee80211_recalc_twt_req(sdata, sband, link, link_sta, elems); From 4314bb46cb56851f13bda9db356ebc3cf750b7f1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 27 Jun 2024 10:46:22 +0200 Subject: [PATCH 056/204] wifi: mac80211_hwsim: fix kernel-doc Some kernel-doc in the header file was mismatched, fix that. Reviewed-by: Miriam Rachel Korenblit Link: https://patch.msgid.link/20240627104621.3b2dd62adb2c.I8a4c469b674e5eac737378a1ed2358b57d01613f@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/mac80211_hwsim.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.h b/drivers/net/wireless/virtual/mac80211_hwsim.h index 21b1afd83dc1..28c1db482e79 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.h +++ b/drivers/net/wireless/virtual/mac80211_hwsim.h @@ -257,7 +257,7 @@ enum hwsim_tx_rate_flags { }; /** - * struct hwsim_tx_rate - rate selection/status + * struct hwsim_tx_rate_flag - rate selection/status * * @idx: rate index to attempt to send with * @flags: the rate flags according to &enum hwsim_tx_rate_flags @@ -295,7 +295,7 @@ enum hwsim_vqs { }; /** - * enum hwsim_rate_info -- bitrate information. + * enum hwsim_rate_info_attributes - bitrate information. * * Information about a receiving or transmitting bitrate * that can be mapped to struct rate_info From 8c62617295d3c4cd03f1a02c3b9bf9d4e6d6e0c6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 27 Jun 2024 13:25:27 +0200 Subject: [PATCH 057/204] wifi: mac80211: remove DEAUTH_NEED_MGD_TX_PREP This flag is annoying because it puts a lot of logic into mac80211 that could just as well be in the driver (only iwlmvm uses it) and the implementation is also broken for MLO. Remove the flag in favour of calling drv_mgd_prepare_tx() without any conditions even for the deauth-while-assoc case. The drivers that implement it can take the appropriate actions, which for the only user of DEAUTH_NEED_MGD_TX_PREP (iwlmvm) is a bit more tricky than the implementation in mac80211 is anyway, and all others have no need and can just exit if info->was_assoc is set. Reviewed-by: Miriam Rachel Korenblit Link: https://patch.msgid.link/20240627132527.94924bcc9c9e.I328a219e45f2e2724cd52e75bb9feee3bf21a463@changeid Signed-off-by: Johannes Berg --- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 12 ++++----- .../wireless/intel/iwlwifi/mvm/mld-mac80211.c | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 4 +++ .../wireless/intel/iwlwifi/mvm/time-event.c | 2 ++ include/net/mac80211.h | 22 +++++----------- net/mac80211/debugfs.c | 1 - net/mac80211/main.c | 3 --- net/mac80211/mlme.c | 26 +++---------------- 8 files changed, 23 insertions(+), 49 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 90cf0ec69682..60bfe42d5386 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -383,12 +383,6 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) if (!mvm->mld_api_is_used) ieee80211_hw_set(hw, TIMING_BEACON_ONLY); - /* We should probably have this, but mac80211 - * currently doesn't support it for MLO. - */ - if (!(hw->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO)) - ieee80211_hw_set(hw, DEAUTH_NEED_MGD_TX_PREP); - /* * On older devices, enabling TX A-MSDU occasionally leads to * something getting messed up, the command read from the FIFO @@ -2853,6 +2847,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, if (changes & BSS_CHANGED_ASSOC) { if (vif->cfg.assoc) { + mvmvif->session_prot_connection_loss = false; + /* clear statistics to get clean beacon counter */ iwl_mvm_request_statistics(mvm, true); for_each_mvm_vif_valid_link(mvmvif, i) @@ -4268,8 +4264,12 @@ void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_prep_tx_info *info) { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + if (info->was_assoc && !mvmvif->session_prot_connection_loss) + return; + guard(mvm)(mvm); iwl_mvm_protect_assoc(mvm, vif, info->duration, info->link_id); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index ebf313e161f4..3c99396ad369 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -873,6 +873,8 @@ static void iwl_mvm_mld_vif_cfg_changed_station(struct iwl_mvm *mvm, if (changes & BSS_CHANGED_ASSOC) { if (vif->cfg.assoc) { + mvmvif->session_prot_connection_loss = false; + /* clear statistics to get clean beacon counter */ iwl_mvm_request_statistics(mvm, true); iwl_mvm_sf_update(mvm, vif, false); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 362973fdeac0..393ce424c196 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -450,6 +450,9 @@ struct iwl_mvm_esr_exit { * @unblock_esr_tpt_wk: work for unblocking EMLSR when tpt is high enough. * @roc_activity: currently running ROC activity for this vif (or * ROC_NUM_ACTIVITIES if no activity is running). + * @session_prot_connection_loss: the connection was lost due to session + * protection ending without receiving a beacon, so we need to now + * protect the deauth separately */ struct iwl_mvm_vif { struct iwl_mvm *mvm; @@ -463,6 +466,7 @@ struct iwl_mvm_vif { bool pm_enabled; bool monitor_active; bool esr_active; + bool session_prot_connection_loss; u8 low_latency: 6; u8 low_latency_actual: 1; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 2773dfa8baa9..77b0cae8566f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -222,6 +222,8 @@ static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm, iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_ASSOC_FAILED, NULL); + + mvmvif->session_prot_connection_loss = true; } iwl_mvm_connection_loss(mvm, vif, errmsg); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 9c96e8ae9ef7..bd0f8aefa797 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2767,14 +2767,6 @@ struct ieee80211_txq { * @IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA: Hardware supports buffer STA on * TDLS links. * - * @IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP: The driver requires the - * mgd_prepare_tx() callback to be called before transmission of a - * deauthentication frame in case the association was completed but no - * beacon was heard. This is required in multi-channel scenarios, where the - * virtual interface might not be given air time for the transmission of - * the frame, as it is not synced with the AP/P2P GO yet, and thus the - * deauthentication frame might not be transmitted. - * * @IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP: The driver (or firmware) doesn't * support QoS NDP for AP probing - that's most likely a driver bug. * @@ -2874,7 +2866,6 @@ enum ieee80211_hw_flags { IEEE80211_HW_REPORTS_LOW_ACK, IEEE80211_HW_SUPPORTS_TX_FRAG, IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA, - IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP, IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP, IEEE80211_HW_BUFF_MMPDU_TXQ, IEEE80211_HW_SUPPORTS_VHT_EXT_NSS_BW, @@ -3787,13 +3778,15 @@ enum ieee80211_reconfig_type { * @success: whether the frame exchange was successful, only * used with the mgd_complete_tx() method, and then only * valid for auth and (re)assoc. + * @was_assoc: set if this call is due to deauth/disassoc + * while just having been associated * @link_id: the link id on which the frame will be TX'ed. * Only used with the mgd_prepare_tx() method. */ struct ieee80211_prep_tx_info { u16 duration; u16 subtype; - u8 success:1; + u8 success:1, was_assoc:1; int link_id; }; @@ -4242,12 +4235,9 @@ struct ieee80211_prep_tx_info { * yet it need not necessarily be given airtime, in particular since any * transmission to a P2P GO needs to be synchronized against the GO's * powersave state. mac80211 will call this function before transmitting a - * management frame prior to having successfully associated to allow the - * driver to give it channel time for the transmission, to get a response - * and to be able to synchronize with the GO. - * For drivers that set %IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP, mac80211 - * would also call this function before transmitting a deauthentication - * frame in case that no beacon was heard from the AP/P2P GO. + * management frame prior to transmitting that frame to allow the driver + * to give it channel time for the transmission, to get a response and be + * able to synchronize with the GO. * The callback will be called before each transmission and upon return * mac80211 will transmit the frame right away. * Additional information is passed in the &struct ieee80211_prep_tx_info diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 98310188f330..02b5476a4376 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -483,7 +483,6 @@ static const char *hw_flag_names[] = { FLAG(REPORTS_LOW_ACK), FLAG(SUPPORTS_TX_FRAG), FLAG(SUPPORTS_TDLS_BUFFER_STA), - FLAG(DEAUTH_NEED_MGD_TX_PREP), FLAG(DOESNT_SUPPORT_QOS_NDP), FLAG(BUFF_MMPDU_TXQ), FLAG(SUPPORTS_VHT_EXT_NSS_BW), diff --git a/net/mac80211/main.c b/net/mac80211/main.c index a9aefc83d30a..7578ea56c12f 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1161,9 +1161,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (WARN_ON(!ieee80211_hw_check(hw, AP_LINK_PS))) return -EINVAL; - - if (WARN_ON(ieee80211_hw_check(hw, DEAUTH_NEED_MGD_TX_PREP))) - return -EINVAL; } #ifdef CONFIG_PM diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 80a10cd49565..4779a18ab75d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3521,6 +3521,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, u64 changed = 0; struct ieee80211_prep_tx_info info = { .subtype = stype, + .was_assoc = true, + .link_id = ffs(sdata->vif.active_links) - 1, }; lockdep_assert_wiphy(local->hw.wiphy); @@ -3569,29 +3571,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, /* deauthenticate/disassociate now */ if (tx || frame_buf) { - /* - * In multi channel scenarios guarantee that the virtual - * interface is granted immediate airtime to transmit the - * deauthentication frame by calling mgd_prepare_tx, if the - * driver requested so. - */ - if (ieee80211_hw_check(&local->hw, DEAUTH_NEED_MGD_TX_PREP)) { - for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); - link_id++) { - struct ieee80211_link_data *link; - - link = sdata_dereference(sdata->link[link_id], - sdata); - if (!link) - continue; - if (link->u.mgd.have_beacon) - break; - } - if (link_id == IEEE80211_MLD_MAX_NUM_LINKS) { - info.link_id = ffs(sdata->vif.active_links) - 1; - drv_mgd_prepare_tx(sdata->local, sdata, &info); - } - } + drv_mgd_prepare_tx(sdata->local, sdata, &info); ieee80211_send_deauth_disassoc(sdata, sdata->vif.cfg.ap_addr, sdata->vif.cfg.ap_addr, stype, From 3f73c24f28b317f22df7870c25ff82f1d625c6c2 Mon Sep 17 00:00:00 2001 From: Dinesh Karthikeyan Date: Wed, 26 Jun 2024 14:28:51 +0530 Subject: [PATCH 058/204] wifi: ath12k: Add support to enable debugfs_htt_stats Create debugfs_htt_stats file when ath12k debugfs support is enabled. Add basic ath12k_debugfs_htt_stats_register and handle htt_stats_type file operations. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Dinesh Karthikeyan Co-developed-by: Ramya Gnanasekar Signed-off-by: Ramya Gnanasekar Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240626085854.2500681-2-quic_rgnanase@quicinc.com --- drivers/net/wireless/ath/ath12k/Makefile | 2 +- drivers/net/wireless/ath/ath12k/core.h | 7 ++ drivers/net/wireless/ath/ath12k/debugfs.c | 3 + .../wireless/ath/ath12k/debugfs_htt_stats.c | 81 +++++++++++++++++++ .../wireless/ath/ath12k/debugfs_htt_stats.h | 20 +++++ 5 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c create mode 100644 drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h diff --git a/drivers/net/wireless/ath/ath12k/Makefile b/drivers/net/wireless/ath/ath12k/Makefile index f0dcc933aa95..5a1ed20d730e 100644 --- a/drivers/net/wireless/ath/ath12k/Makefile +++ b/drivers/net/wireless/ath/ath12k/Makefile @@ -23,7 +23,7 @@ ath12k-y += core.o \ fw.o \ p2p.o -ath12k-$(CONFIG_ATH12K_DEBUGFS) += debugfs.o +ath12k-$(CONFIG_ATH12K_DEBUGFS) += debugfs.o debugfs_htt_stats.o ath12k-$(CONFIG_ACPI) += acpi.o ath12k-$(CONFIG_ATH12K_TRACING) += trace.o ath12k-$(CONFIG_PM) += wow.o diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 9de3df924a1c..7173c7e174a7 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -29,6 +29,7 @@ #include "fw.h" #include "acpi.h" #include "wow.h" +#include "debugfs_htt_stats.h" #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) @@ -481,9 +482,15 @@ struct ath12k_fw_stats { struct list_head bcn; }; +struct ath12k_dbg_htt_stats { + enum ath12k_dbg_htt_ext_stats_type type; + u32 cfg_param[4]; +}; + struct ath12k_debug { struct dentry *debugfs_pdev; struct dentry *debugfs_pdev_symlink; + struct ath12k_dbg_htt_stats htt_stats; }; struct ath12k_per_peer_tx_stats { diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c index 751a9b04386a..2a977c36af00 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs.c +++ b/drivers/net/wireless/ath/ath12k/debugfs.c @@ -6,6 +6,7 @@ #include "core.h" #include "debugfs.h" +#include "debugfs_htt_stats.h" static ssize_t ath12k_write_simulate_radar(struct file *file, const char __user *user_buf, @@ -89,6 +90,8 @@ void ath12k_debugfs_register(struct ath12k *ar) ar->debug.debugfs_pdev, ar, &fops_simulate_radar); } + + ath12k_debugfs_htt_stats_register(ar); } void ath12k_debugfs_unregister(struct ath12k *ar) diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c new file mode 100644 index 000000000000..d1d469ae6d2b --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include "core.h" +#include "debug.h" +#include "debugfs_htt_stats.h" + +static ssize_t ath12k_read_htt_stats_type(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath12k *ar = file->private_data; + enum ath12k_dbg_htt_ext_stats_type type; + char buf[32]; + size_t len; + + mutex_lock(&ar->conf_mutex); + type = ar->debug.htt_stats.type; + mutex_unlock(&ar->conf_mutex); + + len = scnprintf(buf, sizeof(buf), "%u\n", type); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath12k_write_htt_stats_type(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath12k *ar = file->private_data; + enum ath12k_dbg_htt_ext_stats_type type; + unsigned int cfg_param[4] = {0}; + const int size = 32; + int num_args; + + char *buf __free(kfree) = kzalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + + num_args = sscanf(buf, "%u %u %u %u %u\n", &type, &cfg_param[0], + &cfg_param[1], &cfg_param[2], &cfg_param[3]); + if (!num_args || num_args > 5) + return -EINVAL; + + if (type == ATH12K_DBG_HTT_EXT_STATS_RESET || + type >= ATH12K_DBG_HTT_NUM_EXT_STATS) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + + ar->debug.htt_stats.type = type; + ar->debug.htt_stats.cfg_param[0] = cfg_param[0]; + ar->debug.htt_stats.cfg_param[1] = cfg_param[1]; + ar->debug.htt_stats.cfg_param[2] = cfg_param[2]; + ar->debug.htt_stats.cfg_param[3] = cfg_param[3]; + + mutex_unlock(&ar->conf_mutex); + + return count; +} + +static const struct file_operations fops_htt_stats_type = { + .read = ath12k_read_htt_stats_type, + .write = ath12k_write_htt_stats_type, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void ath12k_debugfs_htt_stats_register(struct ath12k *ar) +{ + debugfs_create_file("htt_stats_type", 0600, ar->debug.debugfs_pdev, + ar, &fops_htt_stats_type); +} diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h new file mode 100644 index 000000000000..8610db89289a --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef DEBUG_HTT_STATS_H +#define DEBUG_HTT_STATS_H + +void ath12k_debugfs_htt_stats_register(struct ath12k *ar); + +/* htt_dbg_ext_stats_type */ +enum ath12k_dbg_htt_ext_stats_type { + ATH12K_DBG_HTT_EXT_STATS_RESET = 0, + + /* keep this last */ + ATH12K_DBG_HTT_NUM_EXT_STATS, +}; + +#endif From ad201b35d3ec48d81da6c873b9a50586afd8defa Mon Sep 17 00:00:00 2001 From: Dinesh Karthikeyan Date: Thu, 27 Jun 2024 19:36:50 +0300 Subject: [PATCH 059/204] wifi: ath12k: Add htt_stats_dump file ops support Add dump_htt_stats file operation to dump the stats value requested for the requested stats_type. Stats sent from firmware will be cumulative. Hence add debugfs to reset the requested stats type. Example with one ath12k device: ath12k `-- pci-0000:06:00.0 |-- mac0 `-- htt_stats |-- htt_stats_type |-- htt_stats_reset Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Dinesh Karthikeyan Co-developed-by: Ramya Gnanasekar Signed-off-by: Ramya Gnanasekar Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240626085854.2500681-3-quic_rgnanase@quicinc.com --- drivers/net/wireless/ath/ath12k/core.h | 2 + .../wireless/ath/ath12k/debugfs_htt_stats.c | 205 ++++++++++++++++++ .../wireless/ath/ath12k/debugfs_htt_stats.h | 30 +++ drivers/net/wireless/ath/ath12k/dp_tx.c | 4 +- 4 files changed, 240 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 7173c7e174a7..cdfd43a7321a 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -485,6 +485,8 @@ struct ath12k_fw_stats { struct ath12k_dbg_htt_stats { enum ath12k_dbg_htt_ext_stats_type type; u32 cfg_param[4]; + u8 reset; + struct debug_htt_stats_req *stats_req; }; struct ath12k_debug { diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c index d1d469ae6d2b..9f44285caa58 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c @@ -8,6 +8,7 @@ #include "core.h" #include "debug.h" #include "debugfs_htt_stats.h" +#include "dp_tx.h" static ssize_t ath12k_read_htt_stats_type(struct file *file, char __user *user_buf, @@ -74,8 +75,212 @@ static const struct file_operations fops_htt_stats_type = { .llseek = default_llseek, }; +static int ath12k_debugfs_htt_stats_req(struct ath12k *ar) +{ + struct debug_htt_stats_req *stats_req = ar->debug.htt_stats.stats_req; + 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 }; + + lockdep_assert_held(&ar->conf_mutex); + + init_completion(&stats_req->htt_stats_rcvd); + + pdev_id = ath12k_mac_get_target_pdev_id(ar); + stats_req->done = false; + stats_req->pdev_id = pdev_id; + + cookie = u64_encode_bits(ATH12K_HTT_STATS_MAGIC_VALUE, + ATH12K_HTT_STATS_COOKIE_MSB); + cookie |= u64_encode_bits(pdev_id, ATH12K_HTT_STATS_COOKIE_LSB); + + if (stats_req->override_cfg_param) { + cfg_params.cfg0 = stats_req->cfg_param[0]; + cfg_params.cfg1 = stats_req->cfg_param[1]; + cfg_params.cfg2 = stats_req->cfg_param[2]; + cfg_params.cfg3 = stats_req->cfg_param[3]; + } + + ret = ath12k_dp_tx_htt_h2t_ext_stats_req(ar, type, &cfg_params, cookie); + if (ret) { + ath12k_warn(ar->ab, "failed to send htt stats request: %d\n", ret); + return ret; + } + if (!wait_for_completion_timeout(&stats_req->htt_stats_rcvd, 3 * HZ)) { + spin_lock_bh(&ar->data_lock); + if (!stats_req->done) { + stats_req->done = true; + spin_unlock_bh(&ar->data_lock); + ath12k_warn(ar->ab, "stats request timed out\n"); + return -ETIMEDOUT; + } + spin_unlock_bh(&ar->data_lock); + } + + return 0; +} + +static int ath12k_open_htt_stats(struct inode *inode, + struct file *file) +{ + struct ath12k *ar = inode->i_private; + struct debug_htt_stats_req *stats_req; + enum ath12k_dbg_htt_ext_stats_type type = ar->debug.htt_stats.type; + struct ath12k_hw *ah = ath12k_ar_to_ah(ar); + int ret; + + if (type == ATH12K_DBG_HTT_EXT_STATS_RESET) + return -EPERM; + + mutex_lock(&ar->conf_mutex); + + if (ah->state != ATH12K_HW_STATE_ON) { + ret = -ENETDOWN; + goto err_unlock; + } + + if (ar->debug.htt_stats.stats_req) { + ret = -EAGAIN; + goto err_unlock; + } + + stats_req = kzalloc(sizeof(*stats_req) + ATH12K_HTT_STATS_BUF_SIZE, GFP_KERNEL); + if (!stats_req) { + ret = -ENOMEM; + goto err_unlock; + } + + ar->debug.htt_stats.stats_req = stats_req; + stats_req->type = type; + stats_req->cfg_param[0] = ar->debug.htt_stats.cfg_param[0]; + stats_req->cfg_param[1] = ar->debug.htt_stats.cfg_param[1]; + stats_req->cfg_param[2] = ar->debug.htt_stats.cfg_param[2]; + stats_req->cfg_param[3] = ar->debug.htt_stats.cfg_param[3]; + stats_req->override_cfg_param = !!stats_req->cfg_param[0] || + !!stats_req->cfg_param[1] || + !!stats_req->cfg_param[2] || + !!stats_req->cfg_param[3]; + + ret = ath12k_debugfs_htt_stats_req(ar); + if (ret < 0) + goto out; + + file->private_data = stats_req; + + mutex_unlock(&ar->conf_mutex); + + return 0; +out: + kfree(stats_req); + ar->debug.htt_stats.stats_req = NULL; +err_unlock: + mutex_unlock(&ar->conf_mutex); + + return ret; +} + +static int ath12k_release_htt_stats(struct inode *inode, + struct file *file) +{ + struct ath12k *ar = inode->i_private; + + mutex_lock(&ar->conf_mutex); + kfree(file->private_data); + ar->debug.htt_stats.stats_req = NULL; + mutex_unlock(&ar->conf_mutex); + + return 0; +} + +static ssize_t ath12k_read_htt_stats(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct debug_htt_stats_req *stats_req = file->private_data; + char *buf; + u32 length; + + buf = stats_req->buf; + length = min_t(u32, stats_req->buf_len, ATH12K_HTT_STATS_BUF_SIZE); + return simple_read_from_buffer(user_buf, count, ppos, buf, length); +} + +static const struct file_operations fops_dump_htt_stats = { + .open = ath12k_open_htt_stats, + .release = ath12k_release_htt_stats, + .read = ath12k_read_htt_stats, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t ath12k_write_htt_stats_reset(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath12k *ar = file->private_data; + enum ath12k_dbg_htt_ext_stats_type type; + struct htt_ext_stats_cfg_params cfg_params = { 0 }; + u8 param_pos; + int ret; + + ret = kstrtou32_from_user(user_buf, count, 0, &type); + if (ret) + return ret; + + if (type >= ATH12K_DBG_HTT_NUM_EXT_STATS || + type == ATH12K_DBG_HTT_EXT_STATS_RESET) + return -E2BIG; + + mutex_lock(&ar->conf_mutex); + cfg_params.cfg0 = HTT_STAT_DEFAULT_RESET_START_OFFSET; + param_pos = (type >> 5) + 1; + + switch (param_pos) { + case ATH12K_HTT_STATS_RESET_PARAM_CFG_32_BYTES: + cfg_params.cfg1 = 1 << (cfg_params.cfg0 + type); + break; + case ATH12K_HTT_STATS_RESET_PARAM_CFG_64_BYTES: + cfg_params.cfg2 = ATH12K_HTT_STATS_RESET_BITMAP32_BIT(cfg_params.cfg0 + + type); + break; + case ATH12K_HTT_STATS_RESET_PARAM_CFG_128_BYTES: + cfg_params.cfg3 = ATH12K_HTT_STATS_RESET_BITMAP64_BIT(cfg_params.cfg0 + + type); + break; + default: + break; + } + + ret = ath12k_dp_tx_htt_h2t_ext_stats_req(ar, + ATH12K_DBG_HTT_EXT_STATS_RESET, + &cfg_params, + 0ULL); + if (ret) { + ath12k_warn(ar->ab, "failed to send htt stats request: %d\n", ret); + mutex_unlock(&ar->conf_mutex); + return ret; + } + + ar->debug.htt_stats.reset = type; + mutex_unlock(&ar->conf_mutex); + + return count; +} + +static const struct file_operations fops_htt_stats_reset = { + .write = ath12k_write_htt_stats_reset, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + void ath12k_debugfs_htt_stats_register(struct ath12k *ar) { debugfs_create_file("htt_stats_type", 0600, ar->debug.debugfs_pdev, ar, &fops_htt_stats_type); + debugfs_create_file("htt_stats", 0400, ar->debug.debugfs_pdev, + ar, &fops_dump_htt_stats); + debugfs_create_file("htt_stats_reset", 0200, ar->debug.debugfs_pdev, + ar, &fops_htt_stats_reset); } diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h index 8610db89289a..252c59f5eac8 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h @@ -7,6 +7,18 @@ #ifndef DEBUG_HTT_STATS_H #define DEBUG_HTT_STATS_H +#define ATH12K_HTT_STATS_BUF_SIZE (1024 * 512) +#define ATH12K_HTT_STATS_COOKIE_LSB GENMASK_ULL(31, 0) +#define ATH12K_HTT_STATS_COOKIE_MSB GENMASK_ULL(63, 32) +#define ATH12K_HTT_STATS_MAGIC_VALUE 0xF0F0F0F0 + +#define ATH12K_HTT_STATS_RESET_BITMAP32_OFFSET(_idx) ((_idx) & 0x1f) +#define ATH12K_HTT_STATS_RESET_BITMAP64_OFFSET(_idx) ((_idx) & 0x3f) +#define ATH12K_HTT_STATS_RESET_BITMAP32_BIT(_idx) (1 << \ + ATH12K_HTT_STATS_RESET_BITMAP32_OFFSET(_idx)) +#define ATH12K_HTT_STATS_RESET_BITMAP64_BIT(_idx) (1 << \ + ATH12K_HTT_STATS_RESET_BITMAP64_OFFSET(_idx)) + void ath12k_debugfs_htt_stats_register(struct ath12k *ar); /* htt_dbg_ext_stats_type */ @@ -17,4 +29,22 @@ enum ath12k_dbg_htt_ext_stats_type { ATH12K_DBG_HTT_NUM_EXT_STATS, }; +enum ath12k_htt_stats_reset_cfg_param_alloc_pos { + ATH12K_HTT_STATS_RESET_PARAM_CFG_32_BYTES = 1, + ATH12K_HTT_STATS_RESET_PARAM_CFG_64_BYTES, + ATH12K_HTT_STATS_RESET_PARAM_CFG_128_BYTES, +}; + +struct debug_htt_stats_req { + bool done; + bool override_cfg_param; + u8 pdev_id; + enum ath12k_dbg_htt_ext_stats_type type; + u32 cfg_param[4]; + u8 peer_addr[ETH_ALEN]; + struct completion htt_stats_rcvd; + u32 buf_len; + u8 buf[]; +}; + #endif diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index c4cfa7cf7cb9..d08c04343e90 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -1086,6 +1086,7 @@ ath12k_dp_tx_htt_h2t_ext_stats_req(struct ath12k *ar, u8 type, struct htt_ext_stats_cfg_cmd *cmd; int len = sizeof(*cmd); int ret; + u32 pdev_id; skb = ath12k_htc_alloc_skb(ab, len); if (!skb) @@ -1097,7 +1098,8 @@ ath12k_dp_tx_htt_h2t_ext_stats_req(struct ath12k *ar, u8 type, memset(cmd, 0, sizeof(*cmd)); cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_EXT_STATS_CFG; - cmd->hdr.pdev_mask = 1 << ar->pdev->pdev_id; + pdev_id = ath12k_mac_get_target_pdev_id(ar); + cmd->hdr.pdev_mask = 1 << pdev_id; cmd->hdr.stats_type = type; cmd->cfg_param0 = cpu_to_le32(cfg_params->cfg0); From adf6df963c0325c6f3848ade1b73d2afc4948351 Mon Sep 17 00:00:00 2001 From: Dinesh Karthikeyan Date: Thu, 27 Jun 2024 19:36:56 +0300 Subject: [PATCH 060/204] wifi: ath12k: Add support to parse requested stats_type Add extended htt stats parser and print the corresponding TLVs associated with the requested htt_stats_type. Add support for TX PDEV related htt stats. Sample output: -------------- echo 1 > /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats_type cat /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats HTT_TX_PDEV_STATS_CMN_TLV: mac_id = 0 comp_delivered = 0 self_triggers = 256 hw_queued = 275 hw_reaped = 275 underrun = 241 hw_paused = 0 hw_flush = 0 hw_filt = 1 tx_abort = 0 ppdu_ok = 246 mpdu_requeued = 0 tx_xretry = 0 data_rc = 3 mpdu_dropped_xretry = 0 illegal_rate_phy_err = 0 cont_xretry = 0 tx_timeout = 0 tx_time_dur_data = 0 pdev_resets = 0 phy_underrun = 0 txop_ovf = 0 seq_posted = 247 seq_failed_queueing = 0 seq_completed = 247 seq_restarted = 0 seq_txop_repost_stop = 0 next_seq_cancel = 0 dl_mu_mimo_seq_posted = 0 dl_mu_ofdma_seq_posted = 0 ul_mu_mimo_seq_posted = 0 ul_mu_ofdma_seq_posted = 0 mu_mimo_peer_blacklisted = 0 seq_qdepth_repost_stop = 0 seq_min_msdu_repost_stop = 0 mu_seq_min_msdu_repost_stop = 0 seq_switch_hw_paused = 0 next_seq_posted_dsr = 0 seq_posted_isr = 0 seq_ctrl_cached = 0 mpdu_count_tqm = 0 msdu_count_tqm = 0 mpdu_removed_tqm = 0 msdu_removed_tqm = 0 remove_mpdus_max_retries = 0 mpdus_sw_flush = 0 mpdus_hw_filter = 0 mpdus_truncated = 0 mpdus_ack_failed = 0 mpdus_expired = 0 mpdus_seq_hw_retry = 0 ack_tlv_proc = 0 coex_abort_mpdu_cnt_valid = 0 coex_abort_mpdu_cnt = 5 num_total_ppdus_tried_ota = 5 num_data_ppdus_tried_ota = 0 local_ctrl_mgmt_enqued = 247 local_ctrl_mgmt_freed = 247 local_data_enqued = 0 local_data_freed = 0 mpdu_tried = 0 isr_wait_seq_posted = 0 tx_active_dur_us_low = 0 tx_active_dur_us_high = 0 fes_offsets_err_cnt = 0 HTT_TX_PDEV_STATS_URRN_TLV: urrn_stats = 0:0, 1:241, 2:0 HTT_TX_PDEV_STATS_SIFS_TLV: sifs_status = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0 HTT_TX_PDEV_STATS_FLUSH_TLV: flush_errs = 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, 101:0, 102:0, 103:0, 104:0, 105:0, 106:0, 107:0, 108:0, 109:0, 110:0, 111:0, 112:0, 113:0, 114:0, 115:0, 116:0, 117:0, 118:0, 119:0, 120:0, 121:0, 122:0, 123:0, 124:0, 125:0, 126:0, 127:0 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Dinesh Karthikeyan Co-developed-by: Ramya Gnanasekar Signed-off-by: Ramya Gnanasekar Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240626085854.2500681-4-quic_rgnanase@quicinc.com --- .../wireless/ath/ath12k/debugfs_htt_stats.c | 328 ++++++++++++++++++ .../wireless/ath/ath12k/debugfs_htt_stats.h | 211 +++++++++++ drivers/net/wireless/ath/ath12k/dp_rx.c | 10 +- drivers/net/wireless/ath/ath12k/dp_rx.h | 4 + 4 files changed, 549 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c index 9f44285caa58..0c1d8644c1f6 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c @@ -9,6 +9,334 @@ #include "debug.h" #include "debugfs_htt_stats.h" #include "dp_tx.h" +#include "dp_rx.h" + +static u32 +print_array_to_buf(u8 *buf, u32 offset, const char *header, + const __le32 *array, u32 array_len, const char *footer) +{ + int index = 0; + u8 i; + + if (header) { + index += scnprintf(buf + offset, + ATH12K_HTT_STATS_BUF_SIZE - offset, + "%s = ", header); + } + for (i = 0; i < array_len; i++) { + index += scnprintf(buf + offset + index, + (ATH12K_HTT_STATS_BUF_SIZE - offset) - index, + " %u:%u,", i, le32_to_cpu(array[i])); + } + /* To overwrite the last trailing comma */ + index--; + *(buf + offset + index) = '\0'; + + if (footer) { + index += scnprintf(buf + offset + index, + (ATH12K_HTT_STATS_BUF_SIZE - offset) - index, + "%s", footer); + } + return index; +} + +static void +htt_print_tx_pdev_stats_cmn_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_pdev_stats_cmn_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + 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_TX_PDEV_STATS_CMN_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, "comp_delivered = %u\n", + le32_to_cpu(htt_stats_buf->comp_delivered)); + len += scnprintf(buf + len, buf_len - len, "self_triggers = %u\n", + le32_to_cpu(htt_stats_buf->self_triggers)); + len += scnprintf(buf + len, buf_len - len, "hw_queued = %u\n", + le32_to_cpu(htt_stats_buf->hw_queued)); + len += scnprintf(buf + len, buf_len - len, "hw_reaped = %u\n", + le32_to_cpu(htt_stats_buf->hw_reaped)); + len += scnprintf(buf + len, buf_len - len, "underrun = %u\n", + le32_to_cpu(htt_stats_buf->underrun)); + len += scnprintf(buf + len, buf_len - len, "hw_paused = %u\n", + le32_to_cpu(htt_stats_buf->hw_paused)); + len += scnprintf(buf + len, buf_len - len, "hw_flush = %u\n", + le32_to_cpu(htt_stats_buf->hw_flush)); + len += scnprintf(buf + len, buf_len - len, "hw_filt = %u\n", + le32_to_cpu(htt_stats_buf->hw_filt)); + len += scnprintf(buf + len, buf_len - len, "tx_abort = %u\n", + le32_to_cpu(htt_stats_buf->tx_abort)); + len += scnprintf(buf + len, buf_len - len, "ppdu_ok = %u\n", + le32_to_cpu(htt_stats_buf->ppdu_ok)); + len += scnprintf(buf + len, buf_len - len, "mpdu_requeued = %u\n", + le32_to_cpu(htt_stats_buf->mpdu_requed)); + len += scnprintf(buf + len, buf_len - len, "tx_xretry = %u\n", + le32_to_cpu(htt_stats_buf->tx_xretry)); + len += scnprintf(buf + len, buf_len - len, "data_rc = %u\n", + le32_to_cpu(htt_stats_buf->data_rc)); + len += scnprintf(buf + len, buf_len - len, "mpdu_dropped_xretry = %u\n", + le32_to_cpu(htt_stats_buf->mpdu_dropped_xretry)); + len += scnprintf(buf + len, buf_len - len, "illegal_rate_phy_err = %u\n", + le32_to_cpu(htt_stats_buf->illgl_rate_phy_err)); + len += scnprintf(buf + len, buf_len - len, "cont_xretry = %u\n", + le32_to_cpu(htt_stats_buf->cont_xretry)); + len += scnprintf(buf + len, buf_len - len, "tx_timeout = %u\n", + le32_to_cpu(htt_stats_buf->tx_timeout)); + len += scnprintf(buf + len, buf_len - len, "tx_time_dur_data = %u\n", + le32_to_cpu(htt_stats_buf->tx_time_dur_data)); + len += scnprintf(buf + len, buf_len - len, "pdev_resets = %u\n", + le32_to_cpu(htt_stats_buf->pdev_resets)); + len += scnprintf(buf + len, buf_len - len, "phy_underrun = %u\n", + le32_to_cpu(htt_stats_buf->phy_underrun)); + len += scnprintf(buf + len, buf_len - len, "txop_ovf = %u\n", + le32_to_cpu(htt_stats_buf->txop_ovf)); + len += scnprintf(buf + len, buf_len - len, "seq_posted = %u\n", + le32_to_cpu(htt_stats_buf->seq_posted)); + len += scnprintf(buf + len, buf_len - len, "seq_failed_queueing = %u\n", + le32_to_cpu(htt_stats_buf->seq_failed_queueing)); + len += scnprintf(buf + len, buf_len - len, "seq_completed = %u\n", + le32_to_cpu(htt_stats_buf->seq_completed)); + len += scnprintf(buf + len, buf_len - len, "seq_restarted = %u\n", + le32_to_cpu(htt_stats_buf->seq_restarted)); + len += scnprintf(buf + len, buf_len - len, "seq_txop_repost_stop = %u\n", + le32_to_cpu(htt_stats_buf->seq_txop_repost_stop)); + len += scnprintf(buf + len, buf_len - len, "next_seq_cancel = %u\n", + le32_to_cpu(htt_stats_buf->next_seq_cancel)); + len += scnprintf(buf + len, buf_len - len, "dl_mu_mimo_seq_posted = %u\n", + le32_to_cpu(htt_stats_buf->mu_seq_posted)); + len += scnprintf(buf + len, buf_len - len, "dl_mu_ofdma_seq_posted = %u\n", + le32_to_cpu(htt_stats_buf->mu_ofdma_seq_posted)); + len += scnprintf(buf + len, buf_len - len, "ul_mu_mimo_seq_posted = %u\n", + le32_to_cpu(htt_stats_buf->ul_mumimo_seq_posted)); + len += scnprintf(buf + len, buf_len - len, "ul_mu_ofdma_seq_posted = %u\n", + le32_to_cpu(htt_stats_buf->ul_ofdma_seq_posted)); + len += scnprintf(buf + len, buf_len - len, "mu_mimo_peer_blacklisted = %u\n", + le32_to_cpu(htt_stats_buf->num_mu_peer_blacklisted)); + len += scnprintf(buf + len, buf_len - len, "seq_qdepth_repost_stop = %u\n", + le32_to_cpu(htt_stats_buf->seq_qdepth_repost_stop)); + len += scnprintf(buf + len, buf_len - len, "seq_min_msdu_repost_stop = %u\n", + le32_to_cpu(htt_stats_buf->seq_min_msdu_repost_stop)); + len += scnprintf(buf + len, buf_len - len, "mu_seq_min_msdu_repost_stop = %u\n", + le32_to_cpu(htt_stats_buf->mu_seq_min_msdu_repost_stop)); + len += scnprintf(buf + len, buf_len - len, "seq_switch_hw_paused = %u\n", + le32_to_cpu(htt_stats_buf->seq_switch_hw_paused)); + len += scnprintf(buf + len, buf_len - len, "next_seq_posted_dsr = %u\n", + le32_to_cpu(htt_stats_buf->next_seq_posted_dsr)); + len += scnprintf(buf + len, buf_len - len, "seq_posted_isr = %u\n", + le32_to_cpu(htt_stats_buf->seq_posted_isr)); + len += scnprintf(buf + len, buf_len - len, "seq_ctrl_cached = %u\n", + le32_to_cpu(htt_stats_buf->seq_ctrl_cached)); + len += scnprintf(buf + len, buf_len - len, "mpdu_count_tqm = %u\n", + le32_to_cpu(htt_stats_buf->mpdu_count_tqm)); + len += scnprintf(buf + len, buf_len - len, "msdu_count_tqm = %u\n", + le32_to_cpu(htt_stats_buf->msdu_count_tqm)); + len += scnprintf(buf + len, buf_len - len, "mpdu_removed_tqm = %u\n", + le32_to_cpu(htt_stats_buf->mpdu_removed_tqm)); + len += scnprintf(buf + len, buf_len - len, "msdu_removed_tqm = %u\n", + le32_to_cpu(htt_stats_buf->msdu_removed_tqm)); + len += scnprintf(buf + len, buf_len - len, "remove_mpdus_max_retries = %u\n", + le32_to_cpu(htt_stats_buf->remove_mpdus_max_retries)); + len += scnprintf(buf + len, buf_len - len, "mpdus_sw_flush = %u\n", + le32_to_cpu(htt_stats_buf->mpdus_sw_flush)); + len += scnprintf(buf + len, buf_len - len, "mpdus_hw_filter = %u\n", + le32_to_cpu(htt_stats_buf->mpdus_hw_filter)); + len += scnprintf(buf + len, buf_len - len, "mpdus_truncated = %u\n", + le32_to_cpu(htt_stats_buf->mpdus_truncated)); + len += scnprintf(buf + len, buf_len - len, "mpdus_ack_failed = %u\n", + le32_to_cpu(htt_stats_buf->mpdus_ack_failed)); + len += scnprintf(buf + len, buf_len - len, "mpdus_expired = %u\n", + le32_to_cpu(htt_stats_buf->mpdus_expired)); + len += scnprintf(buf + len, buf_len - len, "mpdus_seq_hw_retry = %u\n", + le32_to_cpu(htt_stats_buf->mpdus_seq_hw_retry)); + len += scnprintf(buf + len, buf_len - len, "ack_tlv_proc = %u\n", + le32_to_cpu(htt_stats_buf->ack_tlv_proc)); + len += scnprintf(buf + len, buf_len - len, "coex_abort_mpdu_cnt_valid = %u\n", + le32_to_cpu(htt_stats_buf->coex_abort_mpdu_cnt_valid)); + len += scnprintf(buf + len, buf_len - len, "coex_abort_mpdu_cnt = %u\n", + le32_to_cpu(htt_stats_buf->coex_abort_mpdu_cnt)); + len += scnprintf(buf + len, buf_len - len, "num_total_ppdus_tried_ota = %u\n", + le32_to_cpu(htt_stats_buf->num_total_ppdus_tried_ota)); + len += scnprintf(buf + len, buf_len - len, "num_data_ppdus_tried_ota = %u\n", + le32_to_cpu(htt_stats_buf->num_data_ppdus_tried_ota)); + len += scnprintf(buf + len, buf_len - len, "local_ctrl_mgmt_enqued = %u\n", + le32_to_cpu(htt_stats_buf->local_ctrl_mgmt_enqued)); + len += scnprintf(buf + len, buf_len - len, "local_ctrl_mgmt_freed = %u\n", + le32_to_cpu(htt_stats_buf->local_ctrl_mgmt_freed)); + len += scnprintf(buf + len, buf_len - len, "local_data_enqued = %u\n", + le32_to_cpu(htt_stats_buf->local_data_enqued)); + len += scnprintf(buf + len, buf_len - len, "local_data_freed = %u\n", + le32_to_cpu(htt_stats_buf->local_data_freed)); + len += scnprintf(buf + len, buf_len - len, "mpdu_tried = %u\n", + le32_to_cpu(htt_stats_buf->mpdu_tried)); + len += scnprintf(buf + len, buf_len - len, "isr_wait_seq_posted = %u\n", + le32_to_cpu(htt_stats_buf->isr_wait_seq_posted)); + len += scnprintf(buf + len, buf_len - len, "tx_active_dur_us_low = %u\n", + le32_to_cpu(htt_stats_buf->tx_active_dur_us_low)); + len += scnprintf(buf + len, buf_len - len, "tx_active_dur_us_high = %u\n", + le32_to_cpu(htt_stats_buf->tx_active_dur_us_high)); + len += scnprintf(buf + len, buf_len - len, "fes_offsets_err_cnt = %u\n\n", + le32_to_cpu(htt_stats_buf->fes_offsets_err_cnt)); + + stats_req->buf_len = len; +} + +static void +htt_print_tx_pdev_stats_urrn_tlv(const void *tag_buf, + u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_pdev_stats_urrn_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u16 num_elems = min_t(u16, (tag_len >> 2), + HTT_TX_PDEV_MAX_URRN_STATS); + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_STATS_URRN_TLV:\n"); + + len += print_array_to_buf(buf, len, "urrn_stats", htt_stats_buf->urrn_stats, + num_elems, "\n\n"); + + stats_req->buf_len = len; +} + +static void +htt_print_tx_pdev_stats_flush_tlv(const void *tag_buf, + u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_pdev_stats_flush_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u16 num_elems = min_t(u16, (tag_len >> 2), + ATH12K_HTT_TX_PDEV_MAX_FLUSH_REASON_STATS); + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_STATS_FLUSH_TLV:\n"); + + len += print_array_to_buf(buf, len, "flush_errs", htt_stats_buf->flush_errs, + num_elems, "\n\n"); + + stats_req->buf_len = len; +} + +static void +htt_print_tx_pdev_stats_sifs_tlv(const void *tag_buf, + u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_pdev_stats_sifs_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u16 num_elems = min_t(u16, (tag_len >> 2), + ATH12K_HTT_TX_PDEV_MAX_SIFS_BURST_STATS); + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_STATS_SIFS_TLV:\n"); + + len += print_array_to_buf(buf, len, "sifs_status", htt_stats_buf->sifs_status, + num_elems, "\n\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) +{ + struct debug_htt_stats_req *stats_req = user_data; + + switch (tag) { + case HTT_STATS_TX_PDEV_CMN_TAG: + htt_print_tx_pdev_stats_cmn_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_PDEV_UNDERRUN_TAG: + htt_print_tx_pdev_stats_urrn_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_PDEV_SIFS_TAG: + htt_print_tx_pdev_stats_sifs_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_PDEV_FLUSH_TAG: + htt_print_tx_pdev_stats_flush_tlv(tag_buf, len, stats_req); + break; + default: + break; + } + + return 0; +} + +void ath12k_debugfs_htt_ext_stats_handler(struct ath12k_base *ab, + struct sk_buff *skb) +{ + struct ath12k_htt_extd_stats_msg *msg; + struct debug_htt_stats_req *stats_req; + struct ath12k *ar; + u32 len, pdev_id, stats_info; + u64 cookie; + int ret; + bool send_completion = false; + + msg = (struct ath12k_htt_extd_stats_msg *)skb->data; + cookie = le64_to_cpu(msg->cookie); + + if (u64_get_bits(cookie, ATH12K_HTT_STATS_COOKIE_MSB) != + ATH12K_HTT_STATS_MAGIC_VALUE) { + ath12k_warn(ab, "received invalid htt ext stats event\n"); + return; + } + + pdev_id = u64_get_bits(cookie, ATH12K_HTT_STATS_COOKIE_LSB); + rcu_read_lock(); + ar = ath12k_mac_get_ar_by_pdev_id(ab, pdev_id); + if (!ar) { + ath12k_warn(ab, "failed to get ar for pdev_id %d\n", pdev_id); + goto exit; + } + + stats_req = ar->debug.htt_stats.stats_req; + if (!stats_req) + goto exit; + + spin_lock_bh(&ar->data_lock); + + stats_info = le32_to_cpu(msg->info1); + stats_req->done = u32_get_bits(stats_info, ATH12K_HTT_T2H_EXT_STATS_INFO1_DONE); + if (stats_req->done) + send_completion = true; + + spin_unlock_bh(&ar->data_lock); + + len = u32_get_bits(stats_info, ATH12K_HTT_T2H_EXT_STATS_INFO1_LENGTH); + if (len > skb->len) { + ath12k_warn(ab, "invalid length %d for HTT stats", len); + goto exit; + } + + ret = ath12k_dp_htt_tlv_iter(ab, msg->data, len, + ath12k_dbg_htt_ext_stats_parse, + stats_req); + if (ret) + ath12k_warn(ab, "Failed to parse tlv %d\n", ret); + + if (send_completion) + complete(&stats_req->htt_stats_rcvd); +exit: + rcu_read_unlock(); +} static ssize_t ath12k_read_htt_stats_type(struct file *file, char __user *user_buf, diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h index 252c59f5eac8..83060c54d00b 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h @@ -21,14 +21,134 @@ void ath12k_debugfs_htt_stats_register(struct ath12k *ar); +#ifdef CONFIG_ATH12K_DEBUGFS +void ath12k_debugfs_htt_ext_stats_handler(struct ath12k_base *ab, + struct sk_buff *skb); +#else /* CONFIG_ATH12K_DEBUGFS */ +static inline void ath12k_debugfs_htt_ext_stats_handler(struct ath12k_base *ab, + struct sk_buff *skb) +{ +} +#endif + +/** + * DOC: target -> host extended statistics upload + * + * The following field definitions describe the format of the HTT + * target to host stats upload confirmation message. + * The message contains a cookie echoed from the HTT host->target stats + * upload request, which identifies which request the confirmation is + * for, and a single stats can span over multiple HTT stats indication + * due to the HTT message size limitation so every HTT ext stats + * indication will have tag-length-value stats information elements. + * The tag-length header for each HTT stats IND message also includes a + * status field, to indicate whether the request for the stat type in + * question was fully met, partially met, unable to be met, or invalid + * (if the stat type in question is disabled in the target). + * A Done bit 1's indicate the end of the of stats info elements. + * + * + * |31 16|15 12|11|10 8|7 5|4 0| + * |--------------------------------------------------------------| + * | reserved | msg type | + * |--------------------------------------------------------------| + * | cookie LSBs | + * |--------------------------------------------------------------| + * | cookie MSBs | + * |--------------------------------------------------------------| + * | stats entry length | rsvd | D| S | stat type | + * |--------------------------------------------------------------| + * | type-specific stats info | + * | (see debugfs_htt_stats.h) | + * |--------------------------------------------------------------| + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: Identifies this is a extended statistics upload confirmation + * message. + * Value: 0x1c + * - COOKIE_LSBS + * Bits 31:0 + * Purpose: Provide a mechanism to match a target->host stats confirmation + * message with its preceding host->target stats request message. + * Value: MSBs of the opaque cookie specified by the host-side requestor + * - COOKIE_MSBS + * Bits 31:0 + * Purpose: Provide a mechanism to match a target->host stats confirmation + * message with its preceding host->target stats request message. + * Value: MSBs of the opaque cookie specified by the host-side requestor + * + * Stats Information Element tag-length header fields: + * - STAT_TYPE + * Bits 7:0 + * Purpose: identifies the type of statistics info held in the + * following information element + * Value: ath12k_dbg_htt_ext_stats_type + * - STATUS + * Bits 10:8 + * Purpose: indicate whether the requested stats are present + * Value: + * 0 -> The requested stats have been delivered in full + * 1 -> The requested stats have been delivered in part + * 2 -> The requested stats could not be delivered (error case) + * 3 -> The requested stat type is either not recognized (invalid) + * - DONE + * Bits 11 + * Purpose: + * Indicates the completion of the stats entry, this will be the last + * stats conf HTT segment for the requested stats type. + * Value: + * 0 -> the stats retrieval is ongoing + * 1 -> the stats retrieval is complete + * - LENGTH + * Bits 31:16 + * Purpose: indicate the stats information size + * Value: This field specifies the number of bytes of stats information + * that follows the element tag-length header. + * It is expected but not required that this length is a multiple of + * 4 bytes. + */ + +#define ATH12K_HTT_T2H_EXT_STATS_INFO1_DONE BIT(11) +#define ATH12K_HTT_T2H_EXT_STATS_INFO1_LENGTH GENMASK(31, 16) + +struct ath12k_htt_extd_stats_msg { + __le32 info0; + __le64 cookie; + __le32 info1; + u8 data[]; +} __packed; + /* htt_dbg_ext_stats_type */ enum ath12k_dbg_htt_ext_stats_type { ATH12K_DBG_HTT_EXT_STATS_RESET = 0, + ATH12K_DBG_HTT_EXT_STATS_PDEV_TX = 1, /* keep this last */ ATH12K_DBG_HTT_NUM_EXT_STATS, }; +enum ath12k_dbg_htt_tlv_tag { + HTT_STATS_TX_PDEV_CMN_TAG = 0, + HTT_STATS_TX_PDEV_UNDERRUN_TAG = 1, + HTT_STATS_TX_PDEV_SIFS_TAG = 2, + HTT_STATS_TX_PDEV_FLUSH_TAG = 3, + + HTT_STATS_MAX_TAG, +}; + +#define ATH12K_HTT_STATS_MAC_ID GENMASK(7, 0) + +#define ATH12K_HTT_TX_PDEV_MAX_SIFS_BURST_STATS 9 +#define ATH12K_HTT_TX_PDEV_MAX_FLUSH_REASON_STATS 150 + +enum ath12k_htt_tx_pdev_underrun_enum { + HTT_STATS_TX_PDEV_NO_DATA_UNDERRUN = 0, + HTT_STATS_TX_PDEV_DATA_UNDERRUN_BETWEEN_MPDU = 1, + HTT_STATS_TX_PDEV_DATA_UNDERRUN_WITHIN_MPDU = 2, + HTT_TX_PDEV_MAX_URRN_STATS = 3, +}; + enum ath12k_htt_stats_reset_cfg_param_alloc_pos { ATH12K_HTT_STATS_RESET_PARAM_CFG_32_BYTES = 1, ATH12K_HTT_STATS_RESET_PARAM_CFG_64_BYTES, @@ -47,4 +167,95 @@ struct debug_htt_stats_req { u8 buf[]; }; +struct ath12k_htt_tx_pdev_stats_cmn_tlv { + __le32 mac_id__word; + __le32 hw_queued; + __le32 hw_reaped; + __le32 underrun; + __le32 hw_paused; + __le32 hw_flush; + __le32 hw_filt; + __le32 tx_abort; + __le32 mpdu_requed; + __le32 tx_xretry; + __le32 data_rc; + __le32 mpdu_dropped_xretry; + __le32 illgl_rate_phy_err; + __le32 cont_xretry; + __le32 tx_timeout; + __le32 pdev_resets; + __le32 phy_underrun; + __le32 txop_ovf; + __le32 seq_posted; + __le32 seq_failed_queueing; + __le32 seq_completed; + __le32 seq_restarted; + __le32 mu_seq_posted; + __le32 seq_switch_hw_paused; + __le32 next_seq_posted_dsr; + __le32 seq_posted_isr; + __le32 seq_ctrl_cached; + __le32 mpdu_count_tqm; + __le32 msdu_count_tqm; + __le32 mpdu_removed_tqm; + __le32 msdu_removed_tqm; + __le32 mpdus_sw_flush; + __le32 mpdus_hw_filter; + __le32 mpdus_truncated; + __le32 mpdus_ack_failed; + __le32 mpdus_expired; + __le32 mpdus_seq_hw_retry; + __le32 ack_tlv_proc; + __le32 coex_abort_mpdu_cnt_valid; + __le32 coex_abort_mpdu_cnt; + __le32 num_total_ppdus_tried_ota; + __le32 num_data_ppdus_tried_ota; + __le32 local_ctrl_mgmt_enqued; + __le32 local_ctrl_mgmt_freed; + __le32 local_data_enqued; + __le32 local_data_freed; + __le32 mpdu_tried; + __le32 isr_wait_seq_posted; + + __le32 tx_active_dur_us_low; + __le32 tx_active_dur_us_high; + __le32 remove_mpdus_max_retries; + __le32 comp_delivered; + __le32 ppdu_ok; + __le32 self_triggers; + __le32 tx_time_dur_data; + __le32 seq_qdepth_repost_stop; + __le32 mu_seq_min_msdu_repost_stop; + __le32 seq_min_msdu_repost_stop; + __le32 seq_txop_repost_stop; + __le32 next_seq_cancel; + __le32 fes_offsets_err_cnt; + __le32 num_mu_peer_blacklisted; + __le32 mu_ofdma_seq_posted; + __le32 ul_mumimo_seq_posted; + __le32 ul_ofdma_seq_posted; + + __le32 thermal_suspend_cnt; + __le32 dfs_suspend_cnt; + __le32 tx_abort_suspend_cnt; + __le32 tgt_specific_opaque_txq_suspend_info; + __le32 last_suspend_reason; +} __packed; + +struct ath12k_htt_tx_pdev_stats_urrn_tlv { + DECLARE_FLEX_ARRAY(__le32, urrn_stats); +} __packed; + +struct ath12k_htt_tx_pdev_stats_flush_tlv { + DECLARE_FLEX_ARRAY(__le32, flush_errs); +} __packed; + +struct ath12k_htt_tx_pdev_stats_phy_err_tlv { + DECLARE_FLEX_ARRAY(__le32, phy_errs); +} __packed; + +struct ath12k_htt_tx_pdev_stats_sifs_tlv { + DECLARE_FLEX_ARRAY(__le32, sifs_status); +} __packed; + #endif diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index d7bb412ad391..14236d0a0c89 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -17,6 +17,7 @@ #include "dp_tx.h" #include "peer.h" #include "dp_mon.h" +#include "debugfs_htt_stats.h" #define ATH12K_DP_RX_FRAGMENT_TIMEOUT_MS (2 * HZ) @@ -1268,10 +1269,10 @@ static int ath12k_htt_tlv_ppdu_stats_parse(struct ath12k_base *ab, return 0; } -static int ath12k_dp_htt_tlv_iter(struct ath12k_base *ab, const void *ptr, size_t len, - int (*iter)(struct ath12k_base *ar, u16 tag, u16 len, - const void *ptr, void *data), - void *data) +int ath12k_dp_htt_tlv_iter(struct ath12k_base *ab, const void *ptr, size_t len, + int (*iter)(struct ath12k_base *ar, u16 tag, u16 len, + const void *ptr, void *data), + void *data) { const struct htt_tlv *tlv; const void *begin = ptr; @@ -1741,6 +1742,7 @@ void ath12k_dp_htt_htc_t2h_msg_handler(struct ath12k_base *ab, ath12k_htt_pull_ppdu_stats(ab, skb); break; case HTT_T2H_MSG_TYPE_EXT_STATS_CONF: + ath12k_debugfs_htt_ext_stats_handler(ab, skb); break; case HTT_T2H_MSG_TYPE_MLO_TIMESTAMP_OFFSET_IND: ath12k_htt_mlo_offset_event_handler(ab, skb); diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h index 2ff421160181..eb1f92559179 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.h +++ b/drivers/net/wireless/ath/ath12k/dp_rx.h @@ -139,4 +139,8 @@ ath12k_dp_rx_h_find_peer(struct ath12k_base *ab, struct sk_buff *msdu); int ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab); int ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab); +int ath12k_dp_htt_tlv_iter(struct ath12k_base *ab, const void *ptr, size_t len, + int (*iter)(struct ath12k_base *ar, u16 tag, u16 len, + const void *ptr, void *data), + void *data); #endif /* ATH12K_DP_RX_H */ From a9f2976f0e9ebc4a579cdd507b153a191692a72c Mon Sep 17 00:00:00 2001 From: Ramya Gnanasekar Date: Thu, 27 Jun 2024 19:37:02 +0300 Subject: [PATCH 061/204] wifi: ath12k: Dump additional Tx PDEV HTT stats Support to dump additional Tx PDEV stats through HTT stats debugfs. Following stats dump are supported: 1. PDEV control path stat to dump Tx management frame count 2. Tx PDEV SIFS histogram stats 3. Tx MU MIMO PPDU stats for 802.11ac, 802.11ax and 802.11be Sample Output: --------------- echo 1 > /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats_type cat /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats HTT_TX_PDEV_STATS_CMN_TLV: mac_id = 0 comp_delivered = 0 self_triggers = 13 ...... ...... HTT_TX_PDEV_STATS_CTRL_PATH_TX_STATS: fw_tx_mgmt_subtype = 0:1, 1:0, 2:0, 3:0, 4:38, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:1, 12:0, 13:7, 14:0, 15:0 HTT_TX_PDEV_STATS_SIFS_HIST_TLV: sifs_hist_status = 0:237, 1:185, 2:1, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0 HTT_TX_PDEV_AC_MU_PPDU_DISTRIBUTION_STATS: ac_mu_mimo_num_seq_posted_nr4 = 0 ac_mu_mimo_num_ppdu_posted_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0 ac_mu_mimo_num_ppdu_completed_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0 ac_mu_mimo_num_seq_term_status_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0 ac_mu_mimo_num_seq_posted_nr8 = 0 ac_mu_mimo_num_ppdu_posted_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0 ac_mu_mimo_num_ppdu_completed_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0 ac_mu_mimo_num_seq_term_status_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0 HTT_TX_PDEV_AX_MU_PPDU_DISTRIBUTION_STATS: ax_mu_mimo_num_seq_posted_nr4 = 0 ax_mu_mimo_num_ppdu_posted_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0 ax_mu_mimo_num_ppdu_completed_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0 ax_mu_mimo_num_seq_term_status_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0 ax_mu_mimo_num_seq_posted_nr8 = 0 ax_mu_mimo_num_ppdu_posted_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0 ax_mu_mimo_num_ppdu_completed_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0 ax_mu_mimo_num_seq_term_status_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0 HTT_TX_PDEV_BE_MU_PPDU_DISTRIBUTION_STATS: be_mu_mimo_num_seq_posted_nr4 = 0 be_mu_mimo_num_ppdu_posted_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0 be_mu_mimo_num_ppdu_completed_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0 be_mu_mimo_num_seq_term_status_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0 be_mu_mimo_num_seq_posted_nr8 = 0 be_mu_mimo_num_ppdu_posted_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0 be_mu_mimo_num_ppdu_completed_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0 be_mu_mimo_num_seq_term_status_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Ramya Gnanasekar Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240626085854.2500681-5-quic_rgnanase@quicinc.com --- .../wireless/ath/ath12k/debugfs_htt_stats.c | 142 ++++++++++++++++++ .../wireless/ath/ath12k/debugfs_htt_stats.h | 39 +++++ 2 files changed, 181 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c index 0c1d8644c1f6..fd04f057598d 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c @@ -253,6 +253,139 @@ htt_print_tx_pdev_stats_sifs_tlv(const void *tag_buf, stats_req->buf_len = len; } +static void +htt_print_tx_pdev_mu_ppdu_dist_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_pdev_mu_ppdu_dist_stats_tlv *htt_stats_buf = tag_buf; + char *mode; + u8 j, hw_mode, i, str_buf_len; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 stats_value; + u8 max_ppdu = ATH12K_HTT_STATS_MAX_NUM_MU_PPDU_PER_BURST; + u8 max_sched = ATH12K_HTT_STATS_MAX_NUM_SCHED_STATUS; + char str_buf[ATH12K_HTT_MAX_STRING_LEN]; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + hw_mode = le32_to_cpu(htt_stats_buf->hw_mode); + + switch (hw_mode) { + case ATH12K_HTT_STATS_HWMODE_AC: + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_AC_MU_PPDU_DISTRIBUTION_STATS:\n"); + mode = "ac"; + break; + case ATH12K_HTT_STATS_HWMODE_AX: + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_AX_MU_PPDU_DISTRIBUTION_STATS:\n"); + mode = "ax"; + break; + case ATH12K_HTT_STATS_HWMODE_BE: + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_BE_MU_PPDU_DISTRIBUTION_STATS:\n"); + mode = "be"; + break; + default: + return; + } + + for (i = 0; i < ATH12K_HTT_STATS_NUM_NR_BINS ; i++) { + len += scnprintf(buf + len, buf_len - len, + "%s_mu_mimo_num_seq_posted_nr%u = %u\n", mode, + ((i + 1) * 4), htt_stats_buf->num_seq_posted[i]); + str_buf_len = 0; + memset(str_buf, 0x0, sizeof(str_buf)); + for (j = 0; j < ATH12K_HTT_STATS_MAX_NUM_MU_PPDU_PER_BURST ; j++) { + stats_value = le32_to_cpu(htt_stats_buf->num_ppdu_posted_per_burst + [i * max_ppdu + j]); + str_buf_len += scnprintf(&str_buf[str_buf_len], + ATH12K_HTT_MAX_STRING_LEN - str_buf_len, + " %u:%u,", j, stats_value); + } + /* To overwrite the last trailing comma */ + str_buf[str_buf_len - 1] = '\0'; + len += scnprintf(buf + len, buf_len - len, + "%s_mu_mimo_num_ppdu_posted_per_burst_nr%u = %s\n", + mode, ((i + 1) * 4), str_buf); + str_buf_len = 0; + memset(str_buf, 0x0, sizeof(str_buf)); + for (j = 0; j < ATH12K_HTT_STATS_MAX_NUM_MU_PPDU_PER_BURST ; j++) { + stats_value = le32_to_cpu(htt_stats_buf->num_ppdu_cmpl_per_burst + [i * max_ppdu + j]); + str_buf_len += scnprintf(&str_buf[str_buf_len], + ATH12K_HTT_MAX_STRING_LEN - str_buf_len, + " %u:%u,", j, stats_value); + } + /* To overwrite the last trailing comma */ + str_buf[str_buf_len - 1] = '\0'; + len += scnprintf(buf + len, buf_len - len, + "%s_mu_mimo_num_ppdu_completed_per_burst_nr%u = %s\n", + mode, ((i + 1) * 4), str_buf); + str_buf_len = 0; + memset(str_buf, 0x0, sizeof(str_buf)); + for (j = 0; j < ATH12K_HTT_STATS_MAX_NUM_SCHED_STATUS ; j++) { + stats_value = le32_to_cpu(htt_stats_buf->num_seq_term_status + [i * max_sched + j]); + str_buf_len += scnprintf(&str_buf[str_buf_len], + ATH12K_HTT_MAX_STRING_LEN - str_buf_len, + " %u:%u,", j, stats_value); + } + /* To overwrite the last trailing comma */ + str_buf[str_buf_len - 1] = '\0'; + len += scnprintf(buf + len, buf_len - len, + "%s_mu_mimo_num_seq_term_status_nr%u = %s\n\n", + mode, ((i + 1) * 4), str_buf); + } + + stats_req->buf_len = len; +} + +static void +htt_print_tx_pdev_stats_sifs_hist_tlv(const void *tag_buf, + u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_pdev_stats_sifs_hist_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u16 num_elems = min_t(u16, (tag_len >> 2), + ATH12K_HTT_TX_PDEV_MAX_SIFS_BURST_HIST_STATS); + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_STATS_SIFS_HIST_TLV:\n"); + + len += print_array_to_buf(buf, len, "sifs_hist_status", + htt_stats_buf->sifs_hist_status, num_elems, "\n\n"); + + stats_req->buf_len = len; +} + +static void +htt_print_pdev_ctrl_path_tx_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_pdev_ctrl_path_tx_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_STATS_CTRL_PATH_TX_STATS:\n"); + len += print_array_to_buf(buf, len, "fw_tx_mgmt_subtype", + htt_stats_buf->fw_tx_mgmt_subtype, + ATH12K_HTT_STATS_SUBTYPE_MAX, "\n\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) @@ -272,6 +405,15 @@ static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab, case HTT_STATS_TX_PDEV_FLUSH_TAG: htt_print_tx_pdev_stats_flush_tlv(tag_buf, len, stats_req); break; + case HTT_STATS_TX_PDEV_SIFS_HIST_TAG: + htt_print_tx_pdev_stats_sifs_hist_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_PDEV_CTRL_PATH_TX_STATS_TAG: + htt_print_pdev_ctrl_path_tx_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_MU_PPDU_DIST_TAG: + htt_print_tx_pdev_mu_ppdu_dist_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 83060c54d00b..878d9cf6e7cb 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h @@ -11,6 +11,8 @@ #define ATH12K_HTT_STATS_COOKIE_LSB GENMASK_ULL(31, 0) #define ATH12K_HTT_STATS_COOKIE_MSB GENMASK_ULL(63, 32) #define ATH12K_HTT_STATS_MAGIC_VALUE 0xF0F0F0F0 +#define ATH12K_HTT_STATS_SUBTYPE_MAX 16 +#define ATH12K_HTT_MAX_STRING_LEN 256 #define ATH12K_HTT_STATS_RESET_BITMAP32_OFFSET(_idx) ((_idx) & 0x1f) #define ATH12K_HTT_STATS_RESET_BITMAP64_OFFSET(_idx) ((_idx) & 0x3f) @@ -133,6 +135,9 @@ enum ath12k_dbg_htt_tlv_tag { HTT_STATS_TX_PDEV_UNDERRUN_TAG = 1, HTT_STATS_TX_PDEV_SIFS_TAG = 2, HTT_STATS_TX_PDEV_FLUSH_TAG = 3, + HTT_STATS_TX_PDEV_SIFS_HIST_TAG = 67, + HTT_STATS_PDEV_CTRL_PATH_TX_STATS_TAG = 102, + HTT_STATS_MU_PPDU_DIST_TAG = 129, HTT_STATS_MAX_TAG, }; @@ -142,6 +147,18 @@ enum ath12k_dbg_htt_tlv_tag { #define ATH12K_HTT_TX_PDEV_MAX_SIFS_BURST_STATS 9 #define ATH12K_HTT_TX_PDEV_MAX_FLUSH_REASON_STATS 150 +/* MU MIMO distribution stats is a 2-dimensional array + * with dimension one denoting stats for nr4[0] or nr8[1] + */ +#define ATH12K_HTT_STATS_NUM_NR_BINS 2 +#define ATH12K_HTT_STATS_MAX_NUM_MU_PPDU_PER_BURST 10 +#define ATH12K_HTT_TX_PDEV_MAX_SIFS_BURST_HIST_STATS 10 +#define ATH12K_HTT_STATS_MAX_NUM_SCHED_STATUS 9 +#define ATH12K_HTT_STATS_NUM_SCHED_STATUS_WORDS \ + (ATH12K_HTT_STATS_NUM_NR_BINS * ATH12K_HTT_STATS_MAX_NUM_SCHED_STATUS) +#define ATH12K_HTT_STATS_MU_PPDU_PER_BURST_WORDS \ + (ATH12K_HTT_STATS_NUM_NR_BINS * ATH12K_HTT_STATS_MAX_NUM_MU_PPDU_PER_BURST) + enum ath12k_htt_tx_pdev_underrun_enum { HTT_STATS_TX_PDEV_NO_DATA_UNDERRUN = 0, HTT_STATS_TX_PDEV_DATA_UNDERRUN_BETWEEN_MPDU = 1, @@ -258,4 +275,26 @@ struct ath12k_htt_tx_pdev_stats_sifs_tlv { DECLARE_FLEX_ARRAY(__le32, sifs_status); } __packed; +struct ath12k_htt_pdev_ctrl_path_tx_stats_tlv { + __le32 fw_tx_mgmt_subtype[ATH12K_HTT_STATS_SUBTYPE_MAX]; +} __packed; + +struct ath12k_htt_tx_pdev_stats_sifs_hist_tlv { + DECLARE_FLEX_ARRAY(__le32, sifs_hist_status); +} __packed; + +enum ath12k_htt_stats_hw_mode { + ATH12K_HTT_STATS_HWMODE_AC = 0, + ATH12K_HTT_STATS_HWMODE_AX = 1, + ATH12K_HTT_STATS_HWMODE_BE = 2, +}; + +struct ath12k_htt_tx_pdev_mu_ppdu_dist_stats_tlv { + __le32 hw_mode; + __le32 num_seq_term_status[ATH12K_HTT_STATS_NUM_SCHED_STATUS_WORDS]; + __le32 num_ppdu_cmpl_per_burst[ATH12K_HTT_STATS_MU_PPDU_PER_BURST_WORDS]; + __le32 num_seq_posted[ATH12K_HTT_STATS_NUM_NR_BINS]; + __le32 num_ppdu_posted_per_burst[ATH12K_HTT_STATS_MU_PPDU_PER_BURST_WORDS]; +} __packed; + #endif From 4b6dfc758c2f6ce61336637b22bc0db57fa6d649 Mon Sep 17 00:00:00 2001 From: Dinesh Karthikeyan Date: Tue, 25 Jun 2024 09:52:15 +0530 Subject: [PATCH 062/204] wifi: ath12k: Support Transmit Scheduler stats Add support to request transmission scheduler stats from firmware through HTT stats type 4. This stat gives information such as pdev stats scheduled per transmission queue, transmission queue command posted and reaped, scheduler order, scheduler ineligibility and supercycle triggers. Sample output: ------------- echo 4 > /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats_type cat /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats HTT_STATS_TX_SCHED_CMN_TLV: mac_id = 0 current_timestamp = 952546828 HTT_TX_PDEV_STATS_SCHED_PER_TXQ_TLV: mac_id = 0 txq_id = 14 sched_policy = 2 ..... HTT_SCHED_TXQ_CMD_POSTED_TLV: sched_cmd_posted = 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 HTT_SCHED_TXQ_CMD_REAPED_TLV: sched_cmd_reaped = 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 HTT_SCHED_TXQ_SCHED_ORDER_SU_TLV: sched_order_su = 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 HTT_SCHED_TXQ_SCHED_INELIGIBILITY: sched_ineligibility = 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 HTT_SCHED_TXQ_SUPERCYCLE_TRIGGER: supercycle_triggers = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Dinesh Karthikeyan Signed-off-by: Roopni Devanathan Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240625042217.1303332-2-quic_rdevanat@quicinc.com --- .../wireless/ath/ath12k/debugfs_htt_stats.c | 233 ++++++++++++++++++ .../wireless/ath/ath12k/debugfs_htt_stats.h | 81 ++++++ 2 files changed, 314 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c index fd04f057598d..586f002df15e 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c @@ -386,6 +386,216 @@ htt_print_pdev_ctrl_path_tx_stats_tlv(const void *tag_buf, u16 tag_len, stats_req->buf_len = len; } +static void +ath12k_htt_print_stats_tx_sched_cmn_tlv(const void *tag_buf, + u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_stats_tx_sched_cmn_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + 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_STATS_TX_SCHED_CMN_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, "current_timestamp = %u\n\n", + le32_to_cpu(htt_stats_buf->current_timestamp)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_pdev_stats_sched_per_txq_tlv(const void *tag_buf, + u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_pdev_stats_sched_per_txq_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + 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_TX_PDEV_STATS_SCHED_PER_TXQ_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", + u32_get_bits(mac_id_word, + ATH12K_HTT_TX_PDEV_STATS_SCHED_PER_TXQ_MAC_ID)); + len += scnprintf(buf + len, buf_len - len, "txq_id = %u\n", + u32_get_bits(mac_id_word, + ATH12K_HTT_TX_PDEV_STATS_SCHED_PER_TXQ_ID)); + len += scnprintf(buf + len, buf_len - len, "sched_policy = %u\n", + le32_to_cpu(htt_stats_buf->sched_policy)); + len += scnprintf(buf + len, buf_len - len, + "last_sched_cmd_posted_timestamp = %u\n", + le32_to_cpu(htt_stats_buf->last_sched_cmd_posted_timestamp)); + len += scnprintf(buf + len, buf_len - len, + "last_sched_cmd_compl_timestamp = %u\n", + le32_to_cpu(htt_stats_buf->last_sched_cmd_compl_timestamp)); + len += scnprintf(buf + len, buf_len - len, "sched_2_tac_lwm_count = %u\n", + le32_to_cpu(htt_stats_buf->sched_2_tac_lwm_count)); + len += scnprintf(buf + len, buf_len - len, "sched_2_tac_ring_full = %u\n", + le32_to_cpu(htt_stats_buf->sched_2_tac_ring_full)); + len += scnprintf(buf + len, buf_len - len, "sched_cmd_post_failure = %u\n", + le32_to_cpu(htt_stats_buf->sched_cmd_post_failure)); + len += scnprintf(buf + len, buf_len - len, "num_active_tids = %u\n", + le32_to_cpu(htt_stats_buf->num_active_tids)); + len += scnprintf(buf + len, buf_len - len, "num_ps_schedules = %u\n", + le32_to_cpu(htt_stats_buf->num_ps_schedules)); + len += scnprintf(buf + len, buf_len - len, "sched_cmds_pending = %u\n", + le32_to_cpu(htt_stats_buf->sched_cmds_pending)); + len += scnprintf(buf + len, buf_len - len, "num_tid_register = %u\n", + le32_to_cpu(htt_stats_buf->num_tid_register)); + len += scnprintf(buf + len, buf_len - len, "num_tid_unregister = %u\n", + le32_to_cpu(htt_stats_buf->num_tid_unregister)); + len += scnprintf(buf + len, buf_len - len, "num_qstats_queried = %u\n", + le32_to_cpu(htt_stats_buf->num_qstats_queried)); + len += scnprintf(buf + len, buf_len - len, "qstats_update_pending = %u\n", + le32_to_cpu(htt_stats_buf->qstats_update_pending)); + len += scnprintf(buf + len, buf_len - len, "last_qstats_query_timestamp = %u\n", + le32_to_cpu(htt_stats_buf->last_qstats_query_timestamp)); + len += scnprintf(buf + len, buf_len - len, "num_tqm_cmdq_full = %u\n", + le32_to_cpu(htt_stats_buf->num_tqm_cmdq_full)); + len += scnprintf(buf + len, buf_len - len, "num_de_sched_algo_trigger = %u\n", + le32_to_cpu(htt_stats_buf->num_de_sched_algo_trigger)); + len += scnprintf(buf + len, buf_len - len, "num_rt_sched_algo_trigger = %u\n", + le32_to_cpu(htt_stats_buf->num_rt_sched_algo_trigger)); + len += scnprintf(buf + len, buf_len - len, "num_tqm_sched_algo_trigger = %u\n", + le32_to_cpu(htt_stats_buf->num_tqm_sched_algo_trigger)); + len += scnprintf(buf + len, buf_len - len, "notify_sched = %u\n", + le32_to_cpu(htt_stats_buf->notify_sched)); + len += scnprintf(buf + len, buf_len - len, "dur_based_sendn_term = %u\n", + le32_to_cpu(htt_stats_buf->dur_based_sendn_term)); + len += scnprintf(buf + len, buf_len - len, "su_notify2_sched = %u\n", + le32_to_cpu(htt_stats_buf->su_notify2_sched)); + len += scnprintf(buf + len, buf_len - len, "su_optimal_queued_msdus_sched = %u\n", + le32_to_cpu(htt_stats_buf->su_optimal_queued_msdus_sched)); + len += scnprintf(buf + len, buf_len - len, "su_delay_timeout_sched = %u\n", + le32_to_cpu(htt_stats_buf->su_delay_timeout_sched)); + len += scnprintf(buf + len, buf_len - len, "su_min_txtime_sched_delay = %u\n", + le32_to_cpu(htt_stats_buf->su_min_txtime_sched_delay)); + len += scnprintf(buf + len, buf_len - len, "su_no_delay = %u\n", + le32_to_cpu(htt_stats_buf->su_no_delay)); + len += scnprintf(buf + len, buf_len - len, "num_supercycles = %u\n", + le32_to_cpu(htt_stats_buf->num_supercycles)); + len += scnprintf(buf + len, buf_len - len, "num_subcycles_with_sort = %u\n", + le32_to_cpu(htt_stats_buf->num_subcycles_with_sort)); + len += scnprintf(buf + len, buf_len - len, "num_subcycles_no_sort = %u\n\n", + le32_to_cpu(htt_stats_buf->num_subcycles_no_sort)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_sched_txq_cmd_posted_tlv(const void *tag_buf, + u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_sched_txq_cmd_posted_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u16 num_elements = tag_len >> 2; + + len += scnprintf(buf + len, buf_len - len, "HTT_SCHED_TXQ_CMD_POSTED_TLV:\n"); + len += print_array_to_buf(buf, len, "sched_cmd_posted", + htt_stats_buf->sched_cmd_posted, num_elements, "\n\n"); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_sched_txq_cmd_reaped_tlv(const void *tag_buf, + u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_sched_txq_cmd_reaped_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u16 num_elements = tag_len >> 2; + + len += scnprintf(buf + len, buf_len - len, "HTT_SCHED_TXQ_CMD_REAPED_TLV:\n"); + len += print_array_to_buf(buf, len, "sched_cmd_reaped", + htt_stats_buf->sched_cmd_reaped, num_elements, "\n\n"); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_sched_txq_sched_order_su_tlv(const void *tag_buf, + u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_sched_txq_sched_order_su_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 sched_order_su_num_entries = min_t(u32, (tag_len >> 2), + ATH12K_HTT_TX_PDEV_NUM_SCHED_ORDER_LOG); + + len += scnprintf(buf + len, buf_len - len, + "HTT_SCHED_TXQ_SCHED_ORDER_SU_TLV:\n"); + len += print_array_to_buf(buf, len, "sched_order_su", + htt_stats_buf->sched_order_su, + sched_order_su_num_entries, "\n\n"); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_sched_txq_sched_ineligibility_tlv(const void *tag_buf, + u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_sched_txq_sched_ineligibility_tlv *htt_stats_buf = + tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 sched_ineligibility_num_entries = tag_len >> 2; + + len += scnprintf(buf + len, buf_len - len, + "HTT_SCHED_TXQ_SCHED_INELIGIBILITY:\n"); + len += print_array_to_buf(buf, len, "sched_ineligibility", + htt_stats_buf->sched_ineligibility, + sched_ineligibility_num_entries, "\n\n"); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_sched_txq_supercycle_trigger_tlv(const void *tag_buf, + u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_sched_txq_supercycle_triggers_tlv *htt_stats_buf = + tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u16 num_elems = min_t(u16, (tag_len >> 2), + ATH12K_HTT_SCHED_SUPERCYCLE_TRIGGER_MAX); + + len += scnprintf(buf + len, buf_len - len, + "HTT_SCHED_TXQ_SUPERCYCLE_TRIGGER:\n"); + len += print_array_to_buf(buf, len, "supercycle_triggers", + htt_stats_buf->supercycle_triggers, num_elems, "\n\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) @@ -414,6 +624,29 @@ static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab, case HTT_STATS_MU_PPDU_DIST_TAG: htt_print_tx_pdev_mu_ppdu_dist_stats_tlv(tag_buf, len, stats_req); break; + case HTT_STATS_TX_SCHED_CMN_TAG: + ath12k_htt_print_stats_tx_sched_cmn_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_PDEV_SCHEDULER_TXQ_STATS_TAG: + ath12k_htt_print_tx_pdev_stats_sched_per_txq_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_SCHED_TXQ_CMD_POSTED_TAG: + ath12k_htt_print_sched_txq_cmd_posted_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_SCHED_TXQ_CMD_REAPED_TAG: + ath12k_htt_print_sched_txq_cmd_reaped_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_SCHED_TXQ_SCHED_ORDER_SU_TAG: + ath12k_htt_print_sched_txq_sched_order_su_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_SCHED_TXQ_SCHED_INELIGIBILITY_TAG: + ath12k_htt_print_sched_txq_sched_ineligibility_tlv(tag_buf, len, + stats_req); + break; + case HTT_STATS_SCHED_TXQ_SUPERCYCLE_TRIGGER_TAG: + ath12k_htt_print_sched_txq_supercycle_trigger_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 878d9cf6e7cb..ee90d620fc1d 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h @@ -125,6 +125,7 @@ struct ath12k_htt_extd_stats_msg { enum ath12k_dbg_htt_ext_stats_type { ATH12K_DBG_HTT_EXT_STATS_RESET = 0, ATH12K_DBG_HTT_EXT_STATS_PDEV_TX = 1, + ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_SCHED = 4, /* keep this last */ ATH12K_DBG_HTT_NUM_EXT_STATS, @@ -135,7 +136,14 @@ enum ath12k_dbg_htt_tlv_tag { HTT_STATS_TX_PDEV_UNDERRUN_TAG = 1, HTT_STATS_TX_PDEV_SIFS_TAG = 2, HTT_STATS_TX_PDEV_FLUSH_TAG = 3, + HTT_STATS_TX_PDEV_SCHEDULER_TXQ_STATS_TAG = 36, + HTT_STATS_TX_SCHED_CMN_TAG = 37, + HTT_STATS_SCHED_TXQ_CMD_POSTED_TAG = 39, + HTT_STATS_SCHED_TXQ_CMD_REAPED_TAG = 44, HTT_STATS_TX_PDEV_SIFS_HIST_TAG = 67, + HTT_STATS_SCHED_TXQ_SCHED_ORDER_SU_TAG = 86, + HTT_STATS_SCHED_TXQ_SCHED_INELIGIBILITY_TAG = 87, + HTT_STATS_SCHED_TXQ_SUPERCYCLE_TRIGGER_TAG = 100, HTT_STATS_PDEV_CTRL_PATH_TX_STATS_TAG = 102, HTT_STATS_MU_PPDU_DIST_TAG = 129, @@ -297,4 +305,77 @@ struct ath12k_htt_tx_pdev_mu_ppdu_dist_stats_tlv { __le32 num_ppdu_posted_per_burst[ATH12K_HTT_STATS_MU_PPDU_PER_BURST_WORDS]; } __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) + +#define ATH12K_HTT_TX_PDEV_NUM_SCHED_ORDER_LOG 20 + +struct ath12k_htt_stats_tx_sched_cmn_tlv { + __le32 mac_id__word; + __le32 current_timestamp; +} __packed; + +struct ath12k_htt_tx_pdev_stats_sched_per_txq_tlv { + __le32 mac_id__word; + __le32 sched_policy; + __le32 last_sched_cmd_posted_timestamp; + __le32 last_sched_cmd_compl_timestamp; + __le32 sched_2_tac_lwm_count; + __le32 sched_2_tac_ring_full; + __le32 sched_cmd_post_failure; + __le32 num_active_tids; + __le32 num_ps_schedules; + __le32 sched_cmds_pending; + __le32 num_tid_register; + __le32 num_tid_unregister; + __le32 num_qstats_queried; + __le32 qstats_update_pending; + __le32 last_qstats_query_timestamp; + __le32 num_tqm_cmdq_full; + __le32 num_de_sched_algo_trigger; + __le32 num_rt_sched_algo_trigger; + __le32 num_tqm_sched_algo_trigger; + __le32 notify_sched; + __le32 dur_based_sendn_term; + __le32 su_notify2_sched; + __le32 su_optimal_queued_msdus_sched; + __le32 su_delay_timeout_sched; + __le32 su_min_txtime_sched_delay; + __le32 su_no_delay; + __le32 num_supercycles; + __le32 num_subcycles_with_sort; + __le32 num_subcycles_no_sort; +} __packed; + +struct ath12k_htt_sched_txq_cmd_posted_tlv { + DECLARE_FLEX_ARRAY(__le32, sched_cmd_posted); +} __packed; + +struct ath12k_htt_sched_txq_cmd_reaped_tlv { + DECLARE_FLEX_ARRAY(__le32, sched_cmd_reaped); +} __packed; + +struct ath12k_htt_sched_txq_sched_order_su_tlv { + DECLARE_FLEX_ARRAY(__le32, sched_order_su); +} __packed; + +struct ath12k_htt_sched_txq_sched_ineligibility_tlv { + DECLARE_FLEX_ARRAY(__le32, sched_ineligibility); +} __packed; + +enum ath12k_htt_sched_txq_supercycle_triggers_tlv_enum { + ATH12K_HTT_SCHED_SUPERCYCLE_TRIGGER_NONE = 0, + ATH12K_HTT_SCHED_SUPERCYCLE_TRIGGER_FORCED, + ATH12K_HTT_SCHED_SUPERCYCLE_TRIGGER_LESS_NUM_TIDQ_ENTRIES, + ATH12K_HTT_SCHED_SUPERCYCLE_TRIGGER_LESS_NUM_ACTIVE_TIDS, + ATH12K_HTT_SCHED_SUPERCYCLE_TRIGGER_MAX_ITR_REACHED, + ATH12K_HTT_SCHED_SUPERCYCLE_TRIGGER_DUR_THRESHOLD_REACHED, + ATH12K_HTT_SCHED_SUPERCYCLE_TRIGGER_TWT_TRIGGER, + ATH12K_HTT_SCHED_SUPERCYCLE_TRIGGER_MAX, +}; + +struct ath12k_htt_sched_txq_supercycle_triggers_tlv { + DECLARE_FLEX_ARRAY(__le32, supercycle_triggers); +} __packed; + #endif From cf1187b3a683feb718a50ee19178dc6e90a73a64 Mon Sep 17 00:00:00 2001 From: Dinesh Karthikeyan Date: Tue, 25 Jun 2024 09:52:16 +0530 Subject: [PATCH 063/204] wifi: ath12k: Support pdev error stats Add support to request pdev error stats from firmware through HTT stats type 5. This stats type gives information such as list of pdev errors, reasons for reset, logging information about recovery, drain and war stats. etc. Sample output: ------------- echo 5 > /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats_type cat /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats HTT_HW_STATS_PDEV_ERRS_TLV: mac_id = 0 tx_abort = 0 tx_abort_fail_count = 0 rx_abort = 53 ..... PDEV_PHY_WARM_RESET_REASONS: phy_warm_reset_reason_phy_m3 = 0 phy_warm_reset_reason_tx_hw_stuck = 0 phy_warm_reset_reason_num_cca_rx_frame_stuck = 0 ..... WAL_RX_RECOVERY_STATS: wal_rx_recovery_rst_mac_hang_count = 0 wal_rx_recovery_rst_known_sig_count = 0 wal_rx_recovery_rst_no_rx_count = 0 ..... HTT_RX_DEST_DRAIN_STATS: rx_dest_drain_rx_descs_leak_prevention_done = 0 rx_dest_drain_rx_descs_saved_cnt = 0 rx_dest_drain_rxdma2reo_leak_detected = 0 ..... HTT_HW_STATS_INTR_MISC_TLV: hw_intr_name = AMPI mask = 0 count = 2 HTT_HW_STATS_WHAL_TX_TLV: mac_id = 0 last_unpause_ppdu_id = 0 hwsch_unpause_wait_tqm_write = 0 ..... HTT_HW_WAR_STATS_TLV: mac_id = 0 hw_war 0 = 0 hw_war 1 = 0 ..... Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Dinesh Karthikeyan Signed-off-by: Roopni Devanathan Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240625042217.1303332-3-quic_rdevanat@quicinc.com --- .../wireless/ath/ath12k/debugfs_htt_stats.c | 262 ++++++++++++++++++ .../wireless/ath/ath12k/debugfs_htt_stats.h | 84 ++++++ 2 files changed, 346 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c index 586f002df15e..05bb0ea68e15 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c @@ -596,6 +596,256 @@ ath12k_htt_print_sched_txq_supercycle_trigger_tlv(const void *tag_buf, stats_req->buf_len = len; } +static void +ath12k_htt_print_hw_stats_pdev_errs_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_hw_stats_pdev_errs_tlv *htt_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 mac_id_word; + + if (tag_len < sizeof(*htt_buf)) + return; + + mac_id_word = le32_to_cpu(htt_buf->mac_id__word); + + len += scnprintf(buf + len, buf_len - len, "HTT_HW_STATS_PDEV_ERRS_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, "tx_abort = %u\n", + le32_to_cpu(htt_buf->tx_abort)); + len += scnprintf(buf + len, buf_len - len, "tx_abort_fail_count = %u\n", + le32_to_cpu(htt_buf->tx_abort_fail_count)); + len += scnprintf(buf + len, buf_len - len, "rx_abort = %u\n", + le32_to_cpu(htt_buf->rx_abort)); + len += scnprintf(buf + len, buf_len - len, "rx_abort_fail_count = %u\n", + le32_to_cpu(htt_buf->rx_abort_fail_count)); + len += scnprintf(buf + len, buf_len - len, "rx_flush_cnt = %u\n", + le32_to_cpu(htt_buf->rx_flush_cnt)); + len += scnprintf(buf + len, buf_len - len, "warm_reset = %u\n", + le32_to_cpu(htt_buf->warm_reset)); + len += scnprintf(buf + len, buf_len - len, "cold_reset = %u\n", + le32_to_cpu(htt_buf->cold_reset)); + len += scnprintf(buf + len, buf_len - len, "mac_cold_reset_restore_cal = %u\n", + le32_to_cpu(htt_buf->mac_cold_reset_restore_cal)); + len += scnprintf(buf + len, buf_len - len, "mac_cold_reset = %u\n", + le32_to_cpu(htt_buf->mac_cold_reset)); + len += scnprintf(buf + len, buf_len - len, "mac_warm_reset = %u\n", + le32_to_cpu(htt_buf->mac_warm_reset)); + len += scnprintf(buf + len, buf_len - len, "mac_only_reset = %u\n", + le32_to_cpu(htt_buf->mac_only_reset)); + len += scnprintf(buf + len, buf_len - len, "phy_warm_reset = %u\n", + le32_to_cpu(htt_buf->phy_warm_reset)); + len += scnprintf(buf + len, buf_len - len, "phy_warm_reset_ucode_trig = %u\n", + le32_to_cpu(htt_buf->phy_warm_reset_ucode_trig)); + len += scnprintf(buf + len, buf_len - len, "mac_warm_reset_restore_cal = %u\n", + le32_to_cpu(htt_buf->mac_warm_reset_restore_cal)); + len += scnprintf(buf + len, buf_len - len, "mac_sfm_reset = %u\n", + le32_to_cpu(htt_buf->mac_sfm_reset)); + len += scnprintf(buf + len, buf_len - len, "phy_warm_reset_m3_ssr = %u\n", + le32_to_cpu(htt_buf->phy_warm_reset_m3_ssr)); + len += scnprintf(buf + len, buf_len - len, "fw_rx_rings_reset = %u\n", + le32_to_cpu(htt_buf->fw_rx_rings_reset)); + len += scnprintf(buf + len, buf_len - len, "tx_flush = %u\n", + le32_to_cpu(htt_buf->tx_flush)); + len += scnprintf(buf + len, buf_len - len, "tx_glb_reset = %u\n", + le32_to_cpu(htt_buf->tx_glb_reset)); + len += scnprintf(buf + len, buf_len - len, "tx_txq_reset = %u\n", + le32_to_cpu(htt_buf->tx_txq_reset)); + len += scnprintf(buf + len, buf_len - len, "rx_timeout_reset = %u\n\n", + le32_to_cpu(htt_buf->rx_timeout_reset)); + + len += scnprintf(buf + len, buf_len - len, "PDEV_PHY_WARM_RESET_REASONS:\n"); + len += scnprintf(buf + len, buf_len - len, "phy_warm_reset_reason_phy_m3 = %u\n", + le32_to_cpu(htt_buf->phy_warm_reset_reason_phy_m3)); + len += scnprintf(buf + len, buf_len - len, + "phy_warm_reset_reason_tx_hw_stuck = %u\n", + le32_to_cpu(htt_buf->phy_warm_reset_reason_tx_hw_stuck)); + len += scnprintf(buf + len, buf_len - len, + "phy_warm_reset_reason_num_cca_rx_frame_stuck = %u\n", + le32_to_cpu(htt_buf->phy_warm_reset_reason_num_rx_frame_stuck)); + len += scnprintf(buf + len, buf_len - len, + "phy_warm_reset_reason_wal_rx_recovery_rst_rx_busy = %u\n", + le32_to_cpu(htt_buf->phy_warm_reset_reason_wal_rx_rec_rx_busy)); + len += scnprintf(buf + len, buf_len - len, + "phy_warm_reset_reason_wal_rx_recovery_rst_mac_hang = %u\n", + le32_to_cpu(htt_buf->phy_warm_reset_reason_wal_rx_rec_mac_hng)); + len += scnprintf(buf + len, buf_len - len, + "phy_warm_reset_reason_mac_reset_converted_phy_reset = %u\n", + le32_to_cpu(htt_buf->phy_warm_reset_reason_mac_conv_phy_reset)); + len += scnprintf(buf + len, buf_len - len, + "phy_warm_reset_reason_tx_lifetime_expiry_cca_stuck = %u\n", + le32_to_cpu(htt_buf->phy_warm_reset_reason_tx_exp_cca_stuck)); + len += scnprintf(buf + len, buf_len - len, + "phy_warm_reset_reason_tx_consecutive_flush9_war = %u\n", + le32_to_cpu(htt_buf->phy_warm_reset_reason_tx_consec_flsh_war)); + len += scnprintf(buf + len, buf_len - len, + "phy_warm_reset_reason_tx_hwsch_reset_war = %u\n", + le32_to_cpu(htt_buf->phy_warm_reset_reason_tx_hwsch_reset_war)); + len += scnprintf(buf + len, buf_len - len, + "phy_warm_reset_reason_hwsch_wdog_or_cca_wdog_war = %u\n\n", + le32_to_cpu(htt_buf->phy_warm_reset_reason_hwsch_cca_wdog_war)); + + len += scnprintf(buf + len, buf_len - len, "WAL_RX_RECOVERY_STATS:\n"); + len += scnprintf(buf + len, buf_len - len, + "wal_rx_recovery_rst_mac_hang_count = %u\n", + le32_to_cpu(htt_buf->wal_rx_recovery_rst_mac_hang_cnt)); + len += scnprintf(buf + len, buf_len - len, + "wal_rx_recovery_rst_known_sig_count = %u\n", + le32_to_cpu(htt_buf->wal_rx_recovery_rst_known_sig_cnt)); + len += scnprintf(buf + len, buf_len - len, + "wal_rx_recovery_rst_no_rx_count = %u\n", + le32_to_cpu(htt_buf->wal_rx_recovery_rst_no_rx_cnt)); + len += scnprintf(buf + len, buf_len - len, + "wal_rx_recovery_rst_no_rx_consecutive_count = %u\n", + le32_to_cpu(htt_buf->wal_rx_recovery_rst_no_rx_consec_cnt)); + len += scnprintf(buf + len, buf_len - len, + "wal_rx_recovery_rst_rx_busy_count = %u\n", + le32_to_cpu(htt_buf->wal_rx_recovery_rst_rx_busy_cnt)); + len += scnprintf(buf + len, buf_len - len, + "wal_rx_recovery_rst_phy_mac_hang_count = %u\n\n", + le32_to_cpu(htt_buf->wal_rx_recovery_rst_phy_mac_hang_cnt)); + + len += scnprintf(buf + len, buf_len - len, "HTT_RX_DEST_DRAIN_STATS:\n"); + len += scnprintf(buf + len, buf_len - len, + "rx_dest_drain_rx_descs_leak_prevention_done = %u\n", + le32_to_cpu(htt_buf->rx_dest_drain_rx_descs_leak_prevented)); + len += scnprintf(buf + len, buf_len - len, + "rx_dest_drain_rx_descs_saved_cnt = %u\n", + le32_to_cpu(htt_buf->rx_dest_drain_rx_descs_saved_cnt)); + len += scnprintf(buf + len, buf_len - len, + "rx_dest_drain_rxdma2reo_leak_detected = %u\n", + le32_to_cpu(htt_buf->rx_dest_drain_rxdma2reo_leak_detected)); + len += scnprintf(buf + len, buf_len - len, + "rx_dest_drain_rxdma2fw_leak_detected = %u\n", + le32_to_cpu(htt_buf->rx_dest_drain_rxdma2fw_leak_detected)); + len += scnprintf(buf + len, buf_len - len, + "rx_dest_drain_rxdma2wbm_leak_detected = %u\n", + le32_to_cpu(htt_buf->rx_dest_drain_rxdma2wbm_leak_detected)); + len += scnprintf(buf + len, buf_len - len, + "rx_dest_drain_rxdma1_2sw_leak_detected = %u\n", + le32_to_cpu(htt_buf->rx_dest_drain_rxdma1_2sw_leak_detected)); + len += scnprintf(buf + len, buf_len - len, + "rx_dest_drain_rx_drain_ok_mac_idle = %u\n", + le32_to_cpu(htt_buf->rx_dest_drain_rx_drain_ok_mac_idle)); + len += scnprintf(buf + len, buf_len - len, + "rx_dest_drain_ok_mac_not_idle = %u\n", + le32_to_cpu(htt_buf->rx_dest_drain_ok_mac_not_idle)); + len += scnprintf(buf + len, buf_len - len, + "rx_dest_drain_prerequisite_invld = %u\n", + le32_to_cpu(htt_buf->rx_dest_drain_prerequisite_invld)); + len += scnprintf(buf + len, buf_len - len, + "rx_dest_drain_skip_for_non_lmac_reset = %u\n", + le32_to_cpu(htt_buf->rx_dest_drain_skip_non_lmac_reset)); + len += scnprintf(buf + len, buf_len - len, + "rx_dest_drain_hw_fifo_not_empty_post_drain_wait = %u\n\n", + le32_to_cpu(htt_buf->rx_dest_drain_hw_fifo_notempty_post_wait)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_hw_stats_intr_misc_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_hw_stats_intr_misc_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_HW_STATS_INTR_MISC_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "hw_intr_name = %s\n", + htt_stats_buf->hw_intr_name); + len += scnprintf(buf + len, buf_len - len, "mask = %u\n", + le32_to_cpu(htt_stats_buf->mask)); + len += scnprintf(buf + len, buf_len - len, "count = %u\n\n", + le32_to_cpu(htt_stats_buf->count)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_hw_stats_whal_tx_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_hw_stats_whal_tx_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + 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_HW_STATS_WHAL_TX_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, "last_unpause_ppdu_id = %u\n", + le32_to_cpu(htt_stats_buf->last_unpause_ppdu_id)); + len += scnprintf(buf + len, buf_len - len, "hwsch_unpause_wait_tqm_write = %u\n", + le32_to_cpu(htt_stats_buf->hwsch_unpause_wait_tqm_write)); + len += scnprintf(buf + len, buf_len - len, "hwsch_dummy_tlv_skipped = %u\n", + le32_to_cpu(htt_stats_buf->hwsch_dummy_tlv_skipped)); + len += scnprintf(buf + len, buf_len - len, + "hwsch_misaligned_offset_received = %u\n", + le32_to_cpu(htt_stats_buf->hwsch_misaligned_offset_received)); + len += scnprintf(buf + len, buf_len - len, "hwsch_reset_count = %u\n", + le32_to_cpu(htt_stats_buf->hwsch_reset_count)); + len += scnprintf(buf + len, buf_len - len, "hwsch_dev_reset_war = %u\n", + le32_to_cpu(htt_stats_buf->hwsch_dev_reset_war)); + len += scnprintf(buf + len, buf_len - len, "hwsch_delayed_pause = %u\n", + le32_to_cpu(htt_stats_buf->hwsch_delayed_pause)); + len += scnprintf(buf + len, buf_len - len, "hwsch_long_delayed_pause = %u\n", + le32_to_cpu(htt_stats_buf->hwsch_long_delayed_pause)); + len += scnprintf(buf + len, buf_len - len, "sch_rx_ppdu_no_response = %u\n", + le32_to_cpu(htt_stats_buf->sch_rx_ppdu_no_response)); + len += scnprintf(buf + len, buf_len - len, "sch_selfgen_response = %u\n", + le32_to_cpu(htt_stats_buf->sch_selfgen_response)); + len += scnprintf(buf + len, buf_len - len, "sch_rx_sifs_resp_trigger= %u\n\n", + le32_to_cpu(htt_stats_buf->sch_rx_sifs_resp_trigger)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_hw_war_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_hw_war_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u16 fixed_len, array_len; + u8 i, array_words; + u32 mac_id; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + mac_id = __le32_to_cpu(htt_stats_buf->mac_id__word); + fixed_len = sizeof(*htt_stats_buf); + array_len = tag_len - fixed_len; + array_words = array_len >> 2; + + len += scnprintf(buf + len, buf_len - len, "HTT_HW_WAR_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", + u32_get_bits(mac_id, ATH12K_HTT_STATS_MAC_ID)); + + for (i = 0; i < array_words; i++) { + len += scnprintf(buf + len, buf_len - len, "hw_war %u = %u\n\n", + i, le32_to_cpu(htt_stats_buf->hw_wars[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) @@ -647,6 +897,18 @@ static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab, ath12k_htt_print_sched_txq_supercycle_trigger_tlv(tag_buf, len, stats_req); break; + case HTT_STATS_HW_PDEV_ERRS_TAG: + ath12k_htt_print_hw_stats_pdev_errs_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_HW_INTR_MISC_TAG: + ath12k_htt_print_hw_stats_intr_misc_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_WHAL_TX_TAG: + ath12k_htt_print_hw_stats_whal_tx_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_HW_WAR_TAG: + ath12k_htt_print_hw_war_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 ee90d620fc1d..777a2e067a04 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h @@ -126,6 +126,7 @@ enum ath12k_dbg_htt_ext_stats_type { ATH12K_DBG_HTT_EXT_STATS_RESET = 0, ATH12K_DBG_HTT_EXT_STATS_PDEV_TX = 1, ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_SCHED = 4, + ATH12K_DBG_HTT_EXT_STATS_PDEV_ERROR = 5, /* keep this last */ ATH12K_DBG_HTT_NUM_EXT_STATS, @@ -140,9 +141,13 @@ enum ath12k_dbg_htt_tlv_tag { HTT_STATS_TX_SCHED_CMN_TAG = 37, HTT_STATS_SCHED_TXQ_CMD_POSTED_TAG = 39, HTT_STATS_SCHED_TXQ_CMD_REAPED_TAG = 44, + HTT_STATS_HW_INTR_MISC_TAG = 54, + HTT_STATS_HW_PDEV_ERRS_TAG = 56, + HTT_STATS_WHAL_TX_TAG = 66, HTT_STATS_TX_PDEV_SIFS_HIST_TAG = 67, HTT_STATS_SCHED_TXQ_SCHED_ORDER_SU_TAG = 86, HTT_STATS_SCHED_TXQ_SCHED_INELIGIBILITY_TAG = 87, + HTT_STATS_HW_WAR_TAG = 89, HTT_STATS_SCHED_TXQ_SUPERCYCLE_TRIGGER_TAG = 100, HTT_STATS_PDEV_CTRL_PATH_TX_STATS_TAG = 102, HTT_STATS_MU_PPDU_DIST_TAG = 129, @@ -378,4 +383,83 @@ struct ath12k_htt_sched_txq_supercycle_triggers_tlv { DECLARE_FLEX_ARRAY(__le32, supercycle_triggers); } __packed; +struct ath12k_htt_hw_stats_pdev_errs_tlv { + __le32 mac_id__word; + __le32 tx_abort; + __le32 tx_abort_fail_count; + __le32 rx_abort; + __le32 rx_abort_fail_count; + __le32 warm_reset; + __le32 cold_reset; + __le32 tx_flush; + __le32 tx_glb_reset; + __le32 tx_txq_reset; + __le32 rx_timeout_reset; + __le32 mac_cold_reset_restore_cal; + __le32 mac_cold_reset; + __le32 mac_warm_reset; + __le32 mac_only_reset; + __le32 phy_warm_reset; + __le32 phy_warm_reset_ucode_trig; + __le32 mac_warm_reset_restore_cal; + __le32 mac_sfm_reset; + __le32 phy_warm_reset_m3_ssr; + __le32 phy_warm_reset_reason_phy_m3; + __le32 phy_warm_reset_reason_tx_hw_stuck; + __le32 phy_warm_reset_reason_num_rx_frame_stuck; + __le32 phy_warm_reset_reason_wal_rx_rec_rx_busy; + __le32 phy_warm_reset_reason_wal_rx_rec_mac_hng; + __le32 phy_warm_reset_reason_mac_conv_phy_reset; + __le32 wal_rx_recovery_rst_mac_hang_cnt; + __le32 wal_rx_recovery_rst_known_sig_cnt; + __le32 wal_rx_recovery_rst_no_rx_cnt; + __le32 wal_rx_recovery_rst_no_rx_consec_cnt; + __le32 wal_rx_recovery_rst_rx_busy_cnt; + __le32 wal_rx_recovery_rst_phy_mac_hang_cnt; + __le32 rx_flush_cnt; + __le32 phy_warm_reset_reason_tx_exp_cca_stuck; + __le32 phy_warm_reset_reason_tx_consec_flsh_war; + __le32 phy_warm_reset_reason_tx_hwsch_reset_war; + __le32 phy_warm_reset_reason_hwsch_cca_wdog_war; + __le32 fw_rx_rings_reset; + __le32 rx_dest_drain_rx_descs_leak_prevented; + __le32 rx_dest_drain_rx_descs_saved_cnt; + __le32 rx_dest_drain_rxdma2reo_leak_detected; + __le32 rx_dest_drain_rxdma2fw_leak_detected; + __le32 rx_dest_drain_rxdma2wbm_leak_detected; + __le32 rx_dest_drain_rxdma1_2sw_leak_detected; + __le32 rx_dest_drain_rx_drain_ok_mac_idle; + __le32 rx_dest_drain_ok_mac_not_idle; + __le32 rx_dest_drain_prerequisite_invld; + __le32 rx_dest_drain_skip_non_lmac_reset; + __le32 rx_dest_drain_hw_fifo_notempty_post_wait; +} __packed; + +#define ATH12K_HTT_STATS_MAX_HW_INTR_NAME_LEN 8 +struct ath12k_htt_hw_stats_intr_misc_tlv { + u8 hw_intr_name[ATH12K_HTT_STATS_MAX_HW_INTR_NAME_LEN]; + __le32 mask; + __le32 count; +} __packed; + +struct ath12k_htt_hw_stats_whal_tx_tlv { + __le32 mac_id__word; + __le32 last_unpause_ppdu_id; + __le32 hwsch_unpause_wait_tqm_write; + __le32 hwsch_dummy_tlv_skipped; + __le32 hwsch_misaligned_offset_received; + __le32 hwsch_reset_count; + __le32 hwsch_dev_reset_war; + __le32 hwsch_delayed_pause; + __le32 hwsch_long_delayed_pause; + __le32 sch_rx_ppdu_no_response; + __le32 sch_selfgen_response; + __le32 sch_rx_sifs_resp_trigger; +} __packed; + +struct ath12k_htt_hw_war_stats_tlv { + __le32 mac_id__word; + DECLARE_FLEX_ARRAY(__le32, hw_wars); +} __packed; + #endif From 5344fc76f8944249026884157f846f88489edfc0 Mon Sep 17 00:00:00 2001 From: Dinesh Karthikeyan Date: Tue, 25 Jun 2024 09:52:17 +0530 Subject: [PATCH 064/204] wifi: ath12k: Support TQM stats Add support to request pdev TQM stats from firmware through HTT stats type 6. This stat type gives information such as TQM error, MPDU related information and TQM pdev stats. Sample output: ------------- echo 6 > /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats_type cat /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats HTT_TX_TQM_ERROR_STATS_TLV: q_empty_failure = 0 q_not_empty_failure = 0 add_msdu_failure = 0 TQM_ERROR_RESET_STATS: tqm_cache_ctl_err = 0 tqm_soft_reset = 0 tqm_reset_total_num_in_use_link_descs = 0 ..... HTT_TX_TQM_GEN_MPDU_STATS_TLV: gen_mpdu_end_reason = 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 HTT_TX_TQM_LIST_MPDU_STATS_TLV: list_mpdu_end_reason = 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 HTT_TX_TQM_LIST_MPDU_CNT_TLV_V: list_mpdu_cnt_hist = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0 HTT_TX_TQM_PDEV_STATS_TLV_V: msdu_count = 0 mpdu_count = 0 remove_msdu = 0 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Dinesh Karthikeyan Signed-off-by: Roopni Devanathan Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240625042217.1303332-4-quic_rdevanat@quicinc.com --- .../wireless/ath/ath12k/debugfs_htt_stats.c | 289 ++++++++++++++++++ .../wireless/ath/ath12k/debugfs_htt_stats.h | 102 +++++++ 2 files changed, 391 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c index 05bb0ea68e15..ce80e7b5175b 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c @@ -846,6 +846,277 @@ ath12k_htt_print_hw_war_tlv(const void *tag_buf, u16 tag_len, stats_req->buf_len = len; } +static void +ath12k_htt_print_tx_tqm_cmn_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_tqm_cmn_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + 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_TX_TQM_CMN_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, "max_cmdq_id = %u\n", + le32_to_cpu(htt_stats_buf->max_cmdq_id)); + len += scnprintf(buf + len, buf_len - len, "list_mpdu_cnt_hist_intvl = %u\n", + le32_to_cpu(htt_stats_buf->list_mpdu_cnt_hist_intvl)); + len += scnprintf(buf + len, buf_len - len, "add_msdu = %u\n", + le32_to_cpu(htt_stats_buf->add_msdu)); + len += scnprintf(buf + len, buf_len - len, "q_empty = %u\n", + le32_to_cpu(htt_stats_buf->q_empty)); + len += scnprintf(buf + len, buf_len - len, "q_not_empty = %u\n", + le32_to_cpu(htt_stats_buf->q_not_empty)); + len += scnprintf(buf + len, buf_len - len, "drop_notification = %u\n", + le32_to_cpu(htt_stats_buf->drop_notification)); + len += scnprintf(buf + len, buf_len - len, "desc_threshold = %u\n", + le32_to_cpu(htt_stats_buf->desc_threshold)); + len += scnprintf(buf + len, buf_len - len, "hwsch_tqm_invalid_status = %u\n", + le32_to_cpu(htt_stats_buf->hwsch_tqm_invalid_status)); + len += scnprintf(buf + len, buf_len - len, "missed_tqm_gen_mpdus = %u\n", + le32_to_cpu(htt_stats_buf->missed_tqm_gen_mpdus)); + len += scnprintf(buf + len, buf_len - len, + "total_msduq_timestamp_updates = %u\n", + le32_to_cpu(htt_stats_buf->msduq_timestamp_updates)); + len += scnprintf(buf + len, buf_len - len, + "total_msduq_timestamp_updates_by_get_mpdu_head_info_cmd = %u\n", + le32_to_cpu(htt_stats_buf->msduq_updates_mpdu_head_info_cmd)); + len += scnprintf(buf + len, buf_len - len, + "total_msduq_timestamp_updates_by_emp_to_nonemp_status = %u\n", + le32_to_cpu(htt_stats_buf->msduq_updates_emp_to_nonemp_status)); + len += scnprintf(buf + len, buf_len - len, + "total_get_mpdu_head_info_cmds_by_sched_algo_la_query = %u\n", + le32_to_cpu(htt_stats_buf->get_mpdu_head_info_cmds_by_query)); + len += scnprintf(buf + len, buf_len - len, + "total_get_mpdu_head_info_cmds_by_tac = %u\n", + le32_to_cpu(htt_stats_buf->get_mpdu_head_info_cmds_by_tac)); + len += scnprintf(buf + len, buf_len - len, + "total_gen_mpdu_cmds_by_sched_algo_la_query = %u\n", + le32_to_cpu(htt_stats_buf->gen_mpdu_cmds_by_query)); + len += scnprintf(buf + len, buf_len - len, "active_tqm_tids = %u\n", + le32_to_cpu(htt_stats_buf->tqm_active_tids)); + len += scnprintf(buf + len, buf_len - len, "inactive_tqm_tids = %u\n", + le32_to_cpu(htt_stats_buf->tqm_inactive_tids)); + len += scnprintf(buf + len, buf_len - len, "tqm_active_msduq_flows = %u\n", + le32_to_cpu(htt_stats_buf->tqm_active_msduq_flows)); + len += scnprintf(buf + len, buf_len - len, "hi_prio_q_not_empty = %u\n\n", + le32_to_cpu(htt_stats_buf->high_prio_q_not_empty)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_tqm_error_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_tqm_error_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_ERROR_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "q_empty_failure = %u\n", + le32_to_cpu(htt_stats_buf->q_empty_failure)); + len += scnprintf(buf + len, buf_len - len, "q_not_empty_failure = %u\n", + le32_to_cpu(htt_stats_buf->q_not_empty_failure)); + len += scnprintf(buf + len, buf_len - len, "add_msdu_failure = %u\n\n", + le32_to_cpu(htt_stats_buf->add_msdu_failure)); + + len += scnprintf(buf + len, buf_len - len, "TQM_ERROR_RESET_STATS:\n"); + len += scnprintf(buf + len, buf_len - len, "tqm_cache_ctl_err = %u\n", + le32_to_cpu(htt_stats_buf->tqm_cache_ctl_err)); + len += scnprintf(buf + len, buf_len - len, "tqm_soft_reset = %u\n", + le32_to_cpu(htt_stats_buf->tqm_soft_reset)); + len += scnprintf(buf + len, buf_len - len, + "tqm_reset_total_num_in_use_link_descs = %u\n", + le32_to_cpu(htt_stats_buf->tqm_reset_num_in_use_link_descs)); + len += scnprintf(buf + len, buf_len - len, + "tqm_reset_worst_case_num_lost_link_descs = %u\n", + le32_to_cpu(htt_stats_buf->tqm_reset_num_lost_link_descs)); + len += scnprintf(buf + len, buf_len - len, + "tqm_reset_worst_case_num_lost_host_tx_bufs_count = %u\n", + le32_to_cpu(htt_stats_buf->tqm_reset_num_lost_host_tx_buf_cnt)); + len += scnprintf(buf + len, buf_len - len, + "tqm_reset_num_in_use_link_descs_internal_tqm = %u\n", + le32_to_cpu(htt_stats_buf->tqm_reset_num_in_use_internal_tqm)); + len += scnprintf(buf + len, buf_len - len, + "tqm_reset_num_in_use_link_descs_wbm_idle_link_ring = %u\n", + le32_to_cpu(htt_stats_buf->tqm_reset_num_in_use_idle_link_rng)); + len += scnprintf(buf + len, buf_len - len, + "tqm_reset_time_to_tqm_hang_delta_ms = %u\n", + le32_to_cpu(htt_stats_buf->tqm_reset_time_to_tqm_hang_delta_ms)); + len += scnprintf(buf + len, buf_len - len, "tqm_reset_recovery_time_ms = %u\n", + le32_to_cpu(htt_stats_buf->tqm_reset_recovery_time_ms)); + len += scnprintf(buf + len, buf_len - len, "tqm_reset_num_peers_hdl = %u\n", + le32_to_cpu(htt_stats_buf->tqm_reset_num_peers_hdl)); + len += scnprintf(buf + len, buf_len - len, + "tqm_reset_cumm_dirty_hw_mpduq_proc_cnt = %u\n", + le32_to_cpu(htt_stats_buf->tqm_reset_cumm_dirty_hw_mpduq_cnt)); + len += scnprintf(buf + len, buf_len - len, + "tqm_reset_cumm_dirty_hw_msduq_proc = %u\n", + le32_to_cpu(htt_stats_buf->tqm_reset_cumm_dirty_hw_msduq_proc)); + len += scnprintf(buf + len, buf_len - len, + "tqm_reset_flush_cache_cmd_su_cnt = %u\n", + le32_to_cpu(htt_stats_buf->tqm_reset_flush_cache_cmd_su_cnt)); + len += scnprintf(buf + len, buf_len - len, + "tqm_reset_flush_cache_cmd_other_cnt = %u\n", + le32_to_cpu(htt_stats_buf->tqm_reset_flush_cache_cmd_other_cnt)); + len += scnprintf(buf + len, buf_len - len, + "tqm_reset_flush_cache_cmd_trig_type = %u\n", + le32_to_cpu(htt_stats_buf->tqm_reset_flush_cache_cmd_trig_type)); + len += scnprintf(buf + len, buf_len - len, + "tqm_reset_flush_cache_cmd_trig_cfg = %u\n", + le32_to_cpu(htt_stats_buf->tqm_reset_flush_cache_cmd_trig_cfg)); + len += scnprintf(buf + len, buf_len - len, + "tqm_reset_flush_cache_cmd_skip_cmd_status_null = %u\n\n", + le32_to_cpu(htt_stats_buf->tqm_reset_flush_cmd_skp_status_null)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_tqm_gen_mpdu_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_tqm_gen_mpdu_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u16 num_elements = tag_len >> 2; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_GEN_MPDU_STATS_TLV:\n"); + len += print_array_to_buf(buf, len, "gen_mpdu_end_reason", + htt_stats_buf->gen_mpdu_end_reason, num_elements, + "\n\n"); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_tqm_list_mpdu_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_tqm_list_mpdu_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u16 num_elems = min_t(u16, (tag_len >> 2), + ATH12K_HTT_TX_TQM_MAX_LIST_MPDU_END_REASON); + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_LIST_MPDU_STATS_TLV:\n"); + len += print_array_to_buf(buf, len, "list_mpdu_end_reason", + htt_stats_buf->list_mpdu_end_reason, num_elems, "\n\n"); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_tqm_list_mpdu_cnt_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_tqm_list_mpdu_cnt_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u16 num_elems = min_t(u16, (tag_len >> 2), + ATH12K_HTT_TX_TQM_MAX_LIST_MPDU_CNT_HISTOGRAM_BINS); + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_LIST_MPDU_CNT_TLV_V:\n"); + len += print_array_to_buf(buf, len, "list_mpdu_cnt_hist", + htt_stats_buf->list_mpdu_cnt_hist, num_elems, "\n\n"); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_tqm_pdev_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_tqm_pdev_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_PDEV_STATS_TLV_V:\n"); + len += scnprintf(buf + len, buf_len - len, "msdu_count = %u\n", + le32_to_cpu(htt_stats_buf->msdu_count)); + len += scnprintf(buf + len, buf_len - len, "mpdu_count = %u\n", + le32_to_cpu(htt_stats_buf->mpdu_count)); + len += scnprintf(buf + len, buf_len - len, "remove_msdu = %u\n", + le32_to_cpu(htt_stats_buf->remove_msdu)); + len += scnprintf(buf + len, buf_len - len, "remove_mpdu = %u\n", + le32_to_cpu(htt_stats_buf->remove_mpdu)); + len += scnprintf(buf + len, buf_len - len, "remove_msdu_ttl = %u\n", + le32_to_cpu(htt_stats_buf->remove_msdu_ttl)); + len += scnprintf(buf + len, buf_len - len, "send_bar = %u\n", + le32_to_cpu(htt_stats_buf->send_bar)); + len += scnprintf(buf + len, buf_len - len, "bar_sync = %u\n", + le32_to_cpu(htt_stats_buf->bar_sync)); + len += scnprintf(buf + len, buf_len - len, "notify_mpdu = %u\n", + le32_to_cpu(htt_stats_buf->notify_mpdu)); + len += scnprintf(buf + len, buf_len - len, "sync_cmd = %u\n", + le32_to_cpu(htt_stats_buf->sync_cmd)); + len += scnprintf(buf + len, buf_len - len, "write_cmd = %u\n", + le32_to_cpu(htt_stats_buf->write_cmd)); + len += scnprintf(buf + len, buf_len - len, "hwsch_trigger = %u\n", + le32_to_cpu(htt_stats_buf->hwsch_trigger)); + len += scnprintf(buf + len, buf_len - len, "ack_tlv_proc = %u\n", + le32_to_cpu(htt_stats_buf->ack_tlv_proc)); + len += scnprintf(buf + len, buf_len - len, "gen_mpdu_cmd = %u\n", + le32_to_cpu(htt_stats_buf->gen_mpdu_cmd)); + len += scnprintf(buf + len, buf_len - len, "gen_list_cmd = %u\n", + le32_to_cpu(htt_stats_buf->gen_list_cmd)); + len += scnprintf(buf + len, buf_len - len, "remove_mpdu_cmd = %u\n", + le32_to_cpu(htt_stats_buf->remove_mpdu_cmd)); + len += scnprintf(buf + len, buf_len - len, "remove_mpdu_tried_cmd = %u\n", + le32_to_cpu(htt_stats_buf->remove_mpdu_tried_cmd)); + len += scnprintf(buf + len, buf_len - len, "mpdu_queue_stats_cmd = %u\n", + le32_to_cpu(htt_stats_buf->mpdu_queue_stats_cmd)); + len += scnprintf(buf + len, buf_len - len, "mpdu_head_info_cmd = %u\n", + le32_to_cpu(htt_stats_buf->mpdu_head_info_cmd)); + len += scnprintf(buf + len, buf_len - len, "msdu_flow_stats_cmd = %u\n", + le32_to_cpu(htt_stats_buf->msdu_flow_stats_cmd)); + len += scnprintf(buf + len, buf_len - len, "remove_msdu_cmd = %u\n", + le32_to_cpu(htt_stats_buf->remove_msdu_cmd)); + len += scnprintf(buf + len, buf_len - len, "remove_msdu_ttl_cmd = %u\n", + le32_to_cpu(htt_stats_buf->remove_msdu_ttl_cmd)); + len += scnprintf(buf + len, buf_len - len, "flush_cache_cmd = %u\n", + le32_to_cpu(htt_stats_buf->flush_cache_cmd)); + len += scnprintf(buf + len, buf_len - len, "update_mpduq_cmd = %u\n", + le32_to_cpu(htt_stats_buf->update_mpduq_cmd)); + len += scnprintf(buf + len, buf_len - len, "enqueue = %u\n", + le32_to_cpu(htt_stats_buf->enqueue)); + len += scnprintf(buf + len, buf_len - len, "enqueue_notify = %u\n", + le32_to_cpu(htt_stats_buf->enqueue_notify)); + len += scnprintf(buf + len, buf_len - len, "notify_mpdu_at_head = %u\n", + le32_to_cpu(htt_stats_buf->notify_mpdu_at_head)); + len += scnprintf(buf + len, buf_len - len, "notify_mpdu_state_valid = %u\n", + le32_to_cpu(htt_stats_buf->notify_mpdu_state_valid)); + len += scnprintf(buf + len, buf_len - len, "sched_udp_notify1 = %u\n", + le32_to_cpu(htt_stats_buf->sched_udp_notify1)); + len += scnprintf(buf + len, buf_len - len, "sched_udp_notify2 = %u\n", + le32_to_cpu(htt_stats_buf->sched_udp_notify2)); + len += scnprintf(buf + len, buf_len - len, "sched_nonudp_notify1 = %u\n", + le32_to_cpu(htt_stats_buf->sched_nonudp_notify1)); + len += scnprintf(buf + len, buf_len - len, "sched_nonudp_notify2 = %u\n\n", + le32_to_cpu(htt_stats_buf->sched_nonudp_notify2)); + + 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) @@ -909,6 +1180,24 @@ static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab, case HTT_STATS_HW_WAR_TAG: ath12k_htt_print_hw_war_tlv(tag_buf, len, stats_req); break; + case HTT_STATS_TX_TQM_CMN_TAG: + ath12k_htt_print_tx_tqm_cmn_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_TQM_ERROR_STATS_TAG: + ath12k_htt_print_tx_tqm_error_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_TQM_GEN_MPDU_TAG: + ath12k_htt_print_tx_tqm_gen_mpdu_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_TQM_LIST_MPDU_TAG: + ath12k_htt_print_tx_tqm_list_mpdu_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_TQM_LIST_MPDU_CNT_TAG: + ath12k_htt_print_tx_tqm_list_mpdu_cnt_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_TQM_PDEV_TAG: + ath12k_htt_print_tx_tqm_pdev_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 777a2e067a04..6294a082cf8a 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h @@ -127,6 +127,7 @@ enum ath12k_dbg_htt_ext_stats_type { ATH12K_DBG_HTT_EXT_STATS_PDEV_TX = 1, ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_SCHED = 4, ATH12K_DBG_HTT_EXT_STATS_PDEV_ERROR = 5, + ATH12K_DBG_HTT_EXT_STATS_PDEV_TQM = 6, /* keep this last */ ATH12K_DBG_HTT_NUM_EXT_STATS, @@ -137,9 +138,15 @@ enum ath12k_dbg_htt_tlv_tag { HTT_STATS_TX_PDEV_UNDERRUN_TAG = 1, HTT_STATS_TX_PDEV_SIFS_TAG = 2, HTT_STATS_TX_PDEV_FLUSH_TAG = 3, + HTT_STATS_TX_TQM_GEN_MPDU_TAG = 11, + HTT_STATS_TX_TQM_LIST_MPDU_TAG = 12, + HTT_STATS_TX_TQM_LIST_MPDU_CNT_TAG = 13, + HTT_STATS_TX_TQM_CMN_TAG = 14, + HTT_STATS_TX_TQM_PDEV_TAG = 15, HTT_STATS_TX_PDEV_SCHEDULER_TXQ_STATS_TAG = 36, HTT_STATS_TX_SCHED_CMN_TAG = 37, HTT_STATS_SCHED_TXQ_CMD_POSTED_TAG = 39, + HTT_STATS_TX_TQM_ERROR_STATS_TAG = 43, HTT_STATS_SCHED_TXQ_CMD_REAPED_TAG = 44, HTT_STATS_HW_INTR_MISC_TAG = 54, HTT_STATS_HW_PDEV_ERRS_TAG = 56, @@ -462,4 +469,99 @@ struct ath12k_htt_hw_war_stats_tlv { DECLARE_FLEX_ARRAY(__le32, hw_wars); } __packed; +struct ath12k_htt_tx_tqm_cmn_stats_tlv { + __le32 mac_id__word; + __le32 max_cmdq_id; + __le32 list_mpdu_cnt_hist_intvl; + __le32 add_msdu; + __le32 q_empty; + __le32 q_not_empty; + __le32 drop_notification; + __le32 desc_threshold; + __le32 hwsch_tqm_invalid_status; + __le32 missed_tqm_gen_mpdus; + __le32 tqm_active_tids; + __le32 tqm_inactive_tids; + __le32 tqm_active_msduq_flows; + __le32 msduq_timestamp_updates; + __le32 msduq_updates_mpdu_head_info_cmd; + __le32 msduq_updates_emp_to_nonemp_status; + __le32 get_mpdu_head_info_cmds_by_query; + __le32 get_mpdu_head_info_cmds_by_tac; + __le32 gen_mpdu_cmds_by_query; + __le32 high_prio_q_not_empty; +} __packed; + +struct ath12k_htt_tx_tqm_error_stats_tlv { + __le32 q_empty_failure; + __le32 q_not_empty_failure; + __le32 add_msdu_failure; + __le32 tqm_cache_ctl_err; + __le32 tqm_soft_reset; + __le32 tqm_reset_num_in_use_link_descs; + __le32 tqm_reset_num_lost_link_descs; + __le32 tqm_reset_num_lost_host_tx_buf_cnt; + __le32 tqm_reset_num_in_use_internal_tqm; + __le32 tqm_reset_num_in_use_idle_link_rng; + __le32 tqm_reset_time_to_tqm_hang_delta_ms; + __le32 tqm_reset_recovery_time_ms; + __le32 tqm_reset_num_peers_hdl; + __le32 tqm_reset_cumm_dirty_hw_mpduq_cnt; + __le32 tqm_reset_cumm_dirty_hw_msduq_proc; + __le32 tqm_reset_flush_cache_cmd_su_cnt; + __le32 tqm_reset_flush_cache_cmd_other_cnt; + __le32 tqm_reset_flush_cache_cmd_trig_type; + __le32 tqm_reset_flush_cache_cmd_trig_cfg; + __le32 tqm_reset_flush_cmd_skp_status_null; +} __packed; + +struct ath12k_htt_tx_tqm_gen_mpdu_stats_tlv { + DECLARE_FLEX_ARRAY(__le32, gen_mpdu_end_reason); +} __packed; + +#define ATH12K_HTT_TX_TQM_MAX_LIST_MPDU_END_REASON 16 +#define ATH12K_HTT_TX_TQM_MAX_LIST_MPDU_CNT_HISTOGRAM_BINS 16 + +struct ath12k_htt_tx_tqm_list_mpdu_stats_tlv { + DECLARE_FLEX_ARRAY(__le32, list_mpdu_end_reason); +} __packed; + +struct ath12k_htt_tx_tqm_list_mpdu_cnt_tlv { + DECLARE_FLEX_ARRAY(__le32, list_mpdu_cnt_hist); +} __packed; + +struct ath12k_htt_tx_tqm_pdev_stats_tlv { + __le32 msdu_count; + __le32 mpdu_count; + __le32 remove_msdu; + __le32 remove_mpdu; + __le32 remove_msdu_ttl; + __le32 send_bar; + __le32 bar_sync; + __le32 notify_mpdu; + __le32 sync_cmd; + __le32 write_cmd; + __le32 hwsch_trigger; + __le32 ack_tlv_proc; + __le32 gen_mpdu_cmd; + __le32 gen_list_cmd; + __le32 remove_mpdu_cmd; + __le32 remove_mpdu_tried_cmd; + __le32 mpdu_queue_stats_cmd; + __le32 mpdu_head_info_cmd; + __le32 msdu_flow_stats_cmd; + __le32 remove_msdu_cmd; + __le32 remove_msdu_ttl_cmd; + __le32 flush_cache_cmd; + __le32 update_mpduq_cmd; + __le32 enqueue; + __le32 enqueue_notify; + __le32 notify_mpdu_at_head; + __le32 notify_mpdu_state_valid; + __le32 sched_udp_notify1; + __le32 sched_udp_notify2; + __le32 sched_nonudp_notify1; + __le32 sched_nonudp_notify2; +} __packed; + #endif From d2f299a4c9983022907ff8ec4d4ace49a409ce40 Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Wed, 26 Jun 2024 10:31:29 +0800 Subject: [PATCH 065/204] wifi: rtw89: coex: Add coexistence policy for hardware scan Add additional policy option to let Bluetooth audio can play well during Wi-Fi is hardware scanning. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240626023129.7776-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 26 ++++++++++++++++++++++- drivers/net/wireless/realtek/rtw89/core.h | 1 + 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index d8fc93318a51..24929ef534e0 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -91,7 +91,7 @@ static const struct rtw89_btc_fbtc_slot s_def[] = { [CXST_BLK] = __DEF_FBTC_SLOT(500, 0x55555555, SLOT_MIX), [CXST_E2G] = __DEF_FBTC_SLOT(0, 0xea5a5a5a, SLOT_MIX), [CXST_E5G] = __DEF_FBTC_SLOT(0, 0xffffffff, SLOT_ISO), - [CXST_EBT] = __DEF_FBTC_SLOT(0, 0xe5555555, SLOT_MIX), + [CXST_EBT] = __DEF_FBTC_SLOT(5, 0xe5555555, SLOT_MIX), [CXST_ENULL] = __DEF_FBTC_SLOT(0, 0xaaaaaaaa, SLOT_ISO), [CXST_WLK] = __DEF_FBTC_SLOT(250, 0xea5a5a5a, SLOT_MIX), [CXST_W1FDD] = __DEF_FBTC_SLOT(50, 0xffffffff, SLOT_ISO), @@ -3617,6 +3617,7 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) struct rtw89_btc_wl_info *wl = &btc->cx.wl; u8 type, null_role; u32 tbl_w1, tbl_b1, tbl_b4; + u16 dur_2; type = FIELD_GET(BTC_CXP_MASK, policy_type); @@ -3727,7 +3728,21 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) if (hid->exist || hfp->exist) tbl_w1 = cxtbl[16]; + dur_2 = dm->e2g_slot_limit; + switch (policy_type) { + case BTC_CXP_OFFE_2GBWISOB: /* for normal-case */ + _slot_set(btc, CXST_E2G, 0, tbl_w1, SLOT_ISO); + _slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur, + s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype); + _slot_set_dur(btc, CXST_EBT, dur_2); + break; + case BTC_CXP_OFFE_2GISOB: /* for bt no-link */ + _slot_set(btc, CXST_E2G, 0, cxtbl[1], SLOT_ISO); + _slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur, + s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype); + _slot_set_dur(btc, CXST_EBT, dur_2); + break; case BTC_CXP_OFFE_DEF: _slot_set_le(btc, CXST_E2G, s_def[CXST_E2G].dur, s_def[CXST_E2G].cxtbl, s_def[CXST_E2G].cxtype); @@ -3747,6 +3762,15 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) _slot_set_le(btc, CXST_ENULL, s_def[CXST_ENULL].dur, s_def[CXST_ENULL].cxtbl, s_def[CXST_ENULL].cxtype); break; + case BTC_CXP_OFFE_2GBWMIXB: + _slot_set(btc, CXST_E2G, 0, 0x55555555, SLOT_MIX); + _slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur, + cpu_to_le32(0x55555555), s_def[CXST_EBT].cxtype); + break; + case BTC_CXP_OFFE_WL: /* for 4-way */ + _slot_set(btc, CXST_E2G, 0, cxtbl[1], SLOT_MIX); + _slot_set(btc, CXST_EBT, 0, cxtbl[1], SLOT_MIX); + break; default: break; } diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index e1bcac7e1324..b20a0d5c9e66 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -1330,6 +1330,7 @@ struct rtw89_btc_wl_smap { u32 scan: 1; u32 connecting: 1; u32 roaming: 1; + u32 dbccing: 1; u32 transacting: 1; u32 _4way: 1; u32 rf_off: 1; From dcf920ff8c16868ce0f9738fb1dadf455f86bd94 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 26 Jun 2024 10:32:37 +0800 Subject: [PATCH 066/204] wifi: rtw89: constrain TX power according to Transmit Power Envelope Calculate a TX power constraint based on content of ieee80211 Transmit Power Envelope (TPE). Since HW control registers aren't designed as many as all kinds of TPE fields, we strictly intersect all TPE inputs in driver. Then, according to result, constrain TX power via TX power limit/limit_RU. Besides, extend dbgfs txpwr_table to show info about 6 GHz regulatory. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240626023237.7901-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 10 +- drivers/net/wireless/realtek/rtw89/core.h | 14 +- drivers/net/wireless/realtek/rtw89/debug.c | 25 ++- drivers/net/wireless/realtek/rtw89/mac80211.c | 3 + drivers/net/wireless/realtek/rtw89/phy.c | 38 +++- drivers/net/wireless/realtek/rtw89/regd.c | 190 +++++++++++++++++- 6 files changed, 262 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 4acd4301d3c2..7019f7d482a8 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3376,8 +3376,12 @@ int rtw89_core_sta_add(struct rtw89_dev *rtwdev, if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { /* for station mode, assign the mac_id from itself */ rtwsta->mac_id = rtwvif->mac_id; - /* must do rtw89_reg_6ghz_power_recalc() before rfk channel */ - rtw89_reg_6ghz_power_recalc(rtwdev, rtwvif, true); + + /* must do rtw89_reg_6ghz_recalc() before rfk channel */ + ret = rtw89_reg_6ghz_recalc(rtwdev, rtwvif, true); + if (ret) + return ret; + rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta, BTC_ROLE_MSTS_STA_CONN_START); rtw89_chip_rfk_channel(rtwdev); @@ -3565,7 +3569,7 @@ int rtw89_core_sta_remove(struct rtw89_dev *rtwdev, int ret; if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { - rtw89_reg_6ghz_power_recalc(rtwdev, rtwvif, false); + rtw89_reg_6ghz_recalc(rtwdev, rtwvif, false); rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta, BTC_ROLE_MSTS_STA_DIS_CONN); } else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index b20a0d5c9e66..001da3ad149e 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -746,6 +746,14 @@ enum rtw89_reg_6ghz_power { RTW89_REG_6GHZ_POWER_DFLT = RTW89_REG_6GHZ_POWER_VLP, }; +#define RTW89_MIN_VALID_POWER_CONSTRAINT (-10) /* unit: dBm */ + +/* calculate based on ieee80211 Transmit Power Envelope */ +struct rtw89_reg_6ghz_tpe { + bool valid; + s8 constraint; /* unit: dBm */ +}; + enum rtw89_fw_pkt_ofld_type { RTW89_PKT_OFLD_TYPE_PROBE_RSP = 0, RTW89_PKT_OFLD_TYPE_PS_POLL = 1, @@ -3397,6 +3405,7 @@ struct rtw89_vif { bool chanctx_assigned; /* only valid when running with chanctx_ops */ enum rtw89_sub_entity_idx sub_entity_idx; enum rtw89_reg_6ghz_power reg_6ghz_power; + struct rtw89_reg_6ghz_tpe reg_6ghz_tpe; u8 mac_id; u8 port; @@ -4941,6 +4950,7 @@ struct rtw89_regd { struct rtw89_regulatory_info { const struct rtw89_regd *regd; enum rtw89_reg_6ghz_power reg_6ghz_power; + struct rtw89_reg_6ghz_tpe reg_6ghz_tpe; 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); @@ -6535,8 +6545,8 @@ void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, const u8 *mac_addr, bool hw_scan); void rtw89_core_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, bool hw_scan); -void rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool active); +int rtw89_reg_6ghz_recalc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + bool active); void rtw89_core_update_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif); void rtw89_core_ntfy_btc_event(struct rtw89_dev *rtwdev, enum rtw89_btc_hmsg event); diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index 49bbbd049316..9cbf136aa2ac 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -818,6 +818,28 @@ static const struct dbgfs_txpwr_table *dbgfs_txpwr_tables[RTW89_CHIP_GEN_NUM] = [RTW89_CHIP_BE] = &dbgfs_txpwr_table_be, }; +static +void rtw89_debug_priv_txpwr_table_get_regd(struct seq_file *m, + struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan) +{ + const struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + const struct rtw89_reg_6ghz_tpe *tpe6 = ®ulatory->reg_6ghz_tpe; + + seq_printf(m, "[Chanctx] band %u, ch %u, bw %u\n", + chan->band_type, chan->channel, chan->band_width); + + seq_puts(m, "[Regulatory] "); + __print_regd(m, rtwdev, chan); + + if (chan->band_type == RTW89_BAND_6G) { + seq_printf(m, "[reg6_pwr_type] %u\n", regulatory->reg_6ghz_power); + + if (tpe6->valid) + seq_printf(m, "[TPE] %d dBm\n", tpe6->constraint); + } +} + static int rtw89_debug_priv_txpwr_table_get(struct seq_file *m, void *v) { struct rtw89_debugfs_priv *debugfs_priv = m->private; @@ -831,8 +853,7 @@ static int rtw89_debug_priv_txpwr_table_get(struct seq_file *m, void *v) rtw89_leave_ps_mode(rtwdev); chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); - seq_puts(m, "[Regulatory] "); - __print_regd(m, rtwdev, chan); + rtw89_debug_priv_txpwr_table_get_regd(m, rtwdev, chan); seq_puts(m, "[SAR]\n"); rtw89_print_sar(m, rtwdev, chan->freq); diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index 41b286da3d59..c8a0ad0cffc9 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -487,6 +487,9 @@ static void rtw89_ops_link_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_CQM) rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, true); + if (changed & BSS_CHANGED_TPE) + rtw89_reg_6ghz_recalc(rtwdev, rtwvif, true); + mutex_unlock(&rtwdev->mutex); } diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 60f20e596321..e025f0ed9f59 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -1847,6 +1847,36 @@ static s8 rtw89_phy_txpwr_rf_to_mac(struct rtw89_dev *rtwdev, s8 txpwr_rf) return txpwr_rf >> (chip->txpwr_factor_rf - chip->txpwr_factor_mac); } +static s8 rtw89_phy_txpwr_dbm_to_mac(struct rtw89_dev *rtwdev, s8 dbm) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + return clamp_t(s16, dbm << chip->txpwr_factor_mac, -64, 63); +} + +static s8 rtw89_phy_txpwr_dbm_without_tolerance(s8 dbm) +{ + const u8 tssi_deviation_point = 0; + const u8 tssi_max_deviation = 2; + + if (dbm <= tssi_deviation_point) + dbm -= tssi_max_deviation; + + return dbm; +} + +static s8 rtw89_phy_get_tpe_constraint(struct rtw89_dev *rtwdev, u8 band) +{ + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + const struct rtw89_reg_6ghz_tpe *tpe = ®ulatory->reg_6ghz_tpe; + s8 cstr = S8_MAX; + + if (band == RTW89_BAND_6G && tpe->valid) + cstr = rtw89_phy_txpwr_dbm_without_tolerance(tpe->constraint); + + return rtw89_phy_txpwr_dbm_to_mac(rtwdev, cstr); +} + s8 rtw89_phy_read_txpwr_byrate(struct rtw89_dev *rtwdev, u8 band, u8 bw, const struct rtw89_rate_desc *rate_desc) { @@ -1921,6 +1951,7 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band, u8 regd = rtw89_regd_get(rtwdev, band); u8 reg6 = regulatory->reg_6ghz_power; s8 lmt = 0, sar; + s8 cstr; switch (band) { case RTW89_BAND_2G: @@ -1953,8 +1984,9 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band, lmt = rtw89_phy_txpwr_rf_to_mac(rtwdev, lmt); sar = rtw89_query_sar(rtwdev, freq); + cstr = rtw89_phy_get_tpe_constraint(rtwdev, band); - return min(lmt, sar); + return min3(lmt, sar, cstr); } EXPORT_SYMBOL(rtw89_phy_read_txpwr_limit); @@ -2178,6 +2210,7 @@ s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band, u8 regd = rtw89_regd_get(rtwdev, band); u8 reg6 = regulatory->reg_6ghz_power; s8 lmt_ru = 0, sar; + s8 cstr; switch (band) { case RTW89_BAND_2G: @@ -2210,8 +2243,9 @@ s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band, lmt_ru = rtw89_phy_txpwr_rf_to_mac(rtwdev, lmt_ru); sar = rtw89_query_sar(rtwdev, freq); + cstr = rtw89_phy_get_tpe_constraint(rtwdev, band); - return min(lmt_ru, sar); + return min3(lmt_ru, sar, cstr); } static void diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index 1a133914f673..a251b0e3b16e 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -714,7 +714,154 @@ void rtw89_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request mutex_unlock(&rtwdev->mutex); } -static void __rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev) +/* Maximum Transmit Power field (@raw) can be EIRP or PSD. + * Both units are 0.5 dB-based. Return a constraint in dB. + */ +static s8 tpe_get_constraint(s8 raw) +{ + const u8 hw_deviation = 3; /* unit: 0.5 dB */ + const u8 antenna_gain = 10; /* unit: 0.5 dB */ + const u8 array_gain = 6; /* unit: 0.5 dB */ + const u8 offset = hw_deviation + antenna_gain + array_gain; + + return (raw - offset) / 2; +} + +static void tpe_intersect_constraint(struct rtw89_reg_6ghz_tpe *tpe, s8 cstr) +{ + if (tpe->valid) { + tpe->constraint = min(tpe->constraint, cstr); + return; + } + + tpe->constraint = cstr; + tpe->valid = true; +} + +static void tpe_deal_with_eirp(struct rtw89_reg_6ghz_tpe *tpe, + const struct ieee80211_parsed_tpe_eirp *eirp) +{ + unsigned int i; + s8 cstr; + + if (!eirp->valid) + return; + + for (i = 0; i < eirp->count; i++) { + cstr = tpe_get_constraint(eirp->power[i]); + tpe_intersect_constraint(tpe, cstr); + } +} + +static s8 tpe_convert_psd_to_eirp(s8 psd) +{ + static const unsigned int mlog20 = 1301; + + return psd + 10 * mlog20 / 1000; +} + +static void tpe_deal_with_psd(struct rtw89_reg_6ghz_tpe *tpe, + const struct ieee80211_parsed_tpe_psd *psd) +{ + unsigned int i; + s8 cstr_psd; + s8 cstr; + + if (!psd->valid) + return; + + for (i = 0; i < psd->count; i++) { + cstr_psd = tpe_get_constraint(psd->power[i]); + cstr = tpe_convert_psd_to_eirp(cstr_psd); + tpe_intersect_constraint(tpe, cstr); + } +} + +static void rtw89_calculate_tpe(struct rtw89_dev *rtwdev, + struct rtw89_reg_6ghz_tpe *result_tpe, + const struct ieee80211_parsed_tpe *parsed_tpe) +{ + static const u8 category = IEEE80211_TPE_CAT_6GHZ_DEFAULT; + + tpe_deal_with_eirp(result_tpe, &parsed_tpe->max_local[category]); + tpe_deal_with_eirp(result_tpe, &parsed_tpe->max_reg_client[category]); + tpe_deal_with_psd(result_tpe, &parsed_tpe->psd_local[category]); + tpe_deal_with_psd(result_tpe, &parsed_tpe->psd_reg_client[category]); +} + +static bool __rtw89_reg_6ghz_tpe_recalc(struct rtw89_dev *rtwdev) +{ + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + struct rtw89_reg_6ghz_tpe new = {}; + struct rtw89_vif *rtwvif; + bool changed = false; + + rtw89_for_each_rtwvif(rtwdev, rtwvif) { + const struct rtw89_reg_6ghz_tpe *tmp; + const struct rtw89_chan *chan; + + chan = rtw89_chan_get(rtwdev, rtwvif->sub_entity_idx); + if (chan->band_type != RTW89_BAND_6G) + continue; + + tmp = &rtwvif->reg_6ghz_tpe; + if (!tmp->valid) + continue; + + tpe_intersect_constraint(&new, tmp->constraint); + } + + if (memcmp(®ulatory->reg_6ghz_tpe, &new, + sizeof(regulatory->reg_6ghz_tpe)) != 0) + changed = true; + + if (changed) { + if (new.valid) + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "recalc 6 GHz reg TPE to %d dBm\n", + new.constraint); + else + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "recalc 6 GHz reg TPE to none\n"); + + regulatory->reg_6ghz_tpe = new; + } + + return changed; +} + +static int rtw89_reg_6ghz_tpe_recalc(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool active, + unsigned int *changed) +{ + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct rtw89_reg_6ghz_tpe *tpe = &rtwvif->reg_6ghz_tpe; + + memset(tpe, 0, sizeof(*tpe)); + + if (!active || rtwvif->reg_6ghz_power != RTW89_REG_6GHZ_POWER_STD) + goto bottom; + + rtw89_calculate_tpe(rtwdev, tpe, &bss_conf->tpe); + if (!tpe->valid) + goto bottom; + + if (tpe->constraint < RTW89_MIN_VALID_POWER_CONSTRAINT) { + rtw89_err(rtwdev, + "%s: constraint %d dBm is less than min valid val\n", + __func__, tpe->constraint); + + tpe->valid = false; + return -EINVAL; + } + +bottom: + *changed += __rtw89_reg_6ghz_tpe_recalc(rtwdev); + return 0; +} + +static bool __rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev) { struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; const struct rtw89_regd *regd = regulatory->regd; @@ -751,23 +898,21 @@ static void __rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev) } if (regulatory->reg_6ghz_power == sel) - return; + return false; rtw89_debug(rtwdev, RTW89_DBG_REGD, "recalc 6 GHz reg power type to %d\n", sel); regulatory->reg_6ghz_power = sel; - - rtw89_core_set_chip_txpwr(rtwdev); + return true; } -void rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool active) +static int rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool active, + unsigned int *changed) { struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); - lockdep_assert_held(&rtwdev->mutex); - if (active) { switch (vif->bss_conf.power_type) { case IEEE80211_REG_VLP_AP: @@ -787,5 +932,32 @@ void rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev, rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; } - __rtw89_reg_6ghz_power_recalc(rtwdev); + *changed += __rtw89_reg_6ghz_power_recalc(rtwdev); + return 0; +} + +int rtw89_reg_6ghz_recalc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + bool active) +{ + unsigned int changed = 0; + int ret; + + lockdep_assert_held(&rtwdev->mutex); + + /* The result of reg_6ghz_tpe may depend on reg_6ghz_power type, + * so must do reg_6ghz_tpe_recalc() after reg_6ghz_power_recalc(). + */ + + ret = rtw89_reg_6ghz_power_recalc(rtwdev, rtwvif, active, &changed); + if (ret) + return ret; + + ret = rtw89_reg_6ghz_tpe_recalc(rtwdev, rtwvif, active, &changed); + if (ret) + return ret; + + if (changed) + rtw89_core_set_chip_txpwr(rtwdev); + + return 0; } From f77c5179bc9f6f22d6f1b064bda2e87a567ca7d5 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 27 Jun 2024 10:58:46 +0800 Subject: [PATCH 067/204] wifi: rtw89: 8852bt: rfk: add IQK IQ signal calibration is a very important calibration to yield good RF performance. We do this calibration once we are going to an AP. During scanning phase, without this calibration RF performance is still acceptable because it transmits and receives with low data rate at this phase. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240627025849.25198-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 1 + .../wireless/realtek/rtw89/rtw8852bt_rfk.c | 892 ++++++++++++++++++ .../wireless/realtek/rtw89/rtw8852bt_rfk.h | 1 + 3 files changed, 894 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 177981a108e0..24e8d244534e 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -8659,6 +8659,7 @@ #define R_P0_RFCTM 0x5864 #define B_P0_CLKG_FORCE GENMASK(31, 30) #define B_P0_RFCTM_EN BIT(29) +#define B_P0_GOT_TXRX GENMASK(28, 27) #define B_P0_RFCTM_VAL GENMASK(25, 20) #define R_P0_RFCTM_RDY BIT(26) #define R_P0_TRSW 0x5868 diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c index d0a40eabfe2d..4a638e2444db 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c @@ -13,6 +13,7 @@ #include "rtw8852bt_rfk_table.h" #include "rtw8852b_common.h" +#define RTW8852BT_IQK_VER 0x2a #define RTW8852BT_SS 2 #define RTW8852BT_TSSI_PATH_NR 2 #define RTW8852BT_DPK_VER 0x06 @@ -67,6 +68,23 @@ enum dpk_agc_step { DPK_AGC_STEP_SET_TX_GAIN, }; +enum rtw8852bt_iqk_type { + ID_TXAGC = 0x0, + ID_FLOK_COARSE = 0x1, + ID_FLOK_FINE = 0x2, + ID_TXK = 0x3, + ID_RXAGC = 0x4, + ID_RXK = 0x5, + ID_NBTXK = 0x6, + ID_NBRXK = 0x7, + ID_FLOK_VBUFFER = 0x8, + ID_A_FLOK_COARSE = 0x9, + ID_G_FLOK_COARSE = 0xa, + ID_A_FLOK_FINE = 0xb, + ID_G_FLOK_FINE = 0xc, + ID_IQK_RESTORE = 0x10, +}; + enum adc_ck { ADC_NA = 0, ADC_480M = 1, @@ -347,6 +365,813 @@ static void _rfk_bb_afe_restore(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_MV_AVG, B_P1_TXPW_RSTB, 0x2); } +static bool _iqk_check_cal(struct rtw89_dev *rtwdev, u8 path, u8 ktype) +{ + bool notready = false; + u32 val; + int ret; + + ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, val, val == 0x55, + 10, 8200, false, + rtwdev, R_RFK_ST, MASKBYTE0); + if (ret) + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]NCTL1 IQK timeout!!!\n"); + + udelay(10); + + ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, val, val == 0x8000, + 10, 400, false, + rtwdev, R_RPT_COM, B_RPT_COM_RDY); + if (ret) { + notready = true; + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]NCTL2 IQK timeout!!!\n"); + } + + udelay(10); + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, MASKBYTE0, 0x0); + + return notready; +} + +static bool _iqk_one_shot(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, + u8 path, u8 ktype) +{ + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + u32 iqk_cmd; + bool fail; + + switch (ktype) { + case ID_TXAGC: + iqk_cmd = 0x008 | (1 << (4 + path)) | (path << 1); + break; + case ID_FLOK_COARSE: + iqk_cmd = 0x108 | (1 << (4 + path)); + break; + case ID_FLOK_FINE: + iqk_cmd = 0x208 | (1 << (4 + path)); + break; + case ID_FLOK_VBUFFER: + iqk_cmd = 0x308 | (1 << (4 + path)); + break; + case ID_TXK: + iqk_cmd = 0x008 | (1 << (path + 4)) | + (((0x8 + iqk_info->iqk_bw[path]) & 0xf) << 8); + break; + case ID_RXAGC: + iqk_cmd = 0x508 | (1 << (4 + path)) | (path << 1); + break; + case ID_RXK: + iqk_cmd = 0x008 | (1 << (path + 4)) | + (((0xb + iqk_info->iqk_bw[path]) & 0xf) << 8); + break; + case ID_NBTXK: + iqk_cmd = 0x408 | (1 << (4 + path)); + break; + case ID_NBRXK: + iqk_cmd = 0x608 | (1 << (4 + path)); + break; + default: + return false; + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s, iqk_cmd = %x\n", + __func__, iqk_cmd + 1); + + rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, iqk_cmd + 1); + fail = _iqk_check_cal(rtwdev, path, ktype); + + return fail; +} + +static void _iqk_txk_setting(struct rtw89_dev *rtwdev, u8 path) +{ + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + + switch (iqk_info->iqk_band[path]) { + case RTW89_BAND_2G: + rtw89_write_rf(rtwdev, path, RR_TXG1, RR_TXG1_ATT2, 0x0); + rtw89_write_rf(rtwdev, path, RR_TXG1, RR_TXG1_ATT1, 0x0); + rtw89_write_rf(rtwdev, path, RR_TXG2, RR_TXG2_ATT0, 0x1); + rtw89_write_rf(rtwdev, path, RR_TXGA, RR_TXGA_LOK_EXT, 0x0); + rtw89_write_rf(rtwdev, path, RR_LUTWE, RR_LUTWE_LOK, 0x1); + rtw89_write_rf(rtwdev, path, RR_LUTWA, RR_LUTWA_M1, 0x00); + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_IQK, 0x403e); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, 0x0); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, 0x5); + udelay(1); + break; + case RTW89_BAND_5G: + rtw89_write_rf(rtwdev, path, RR_BIASA, RR_BIASA_A, 0x1); + rtw89_write_rf(rtwdev, path, RR_TXGA, RR_TXGA_LOK_EXT, 0x0); + rtw89_write_rf(rtwdev, path, RR_LUTWE, RR_LUTWE_LOK, 0x1); + rtw89_write_rf(rtwdev, path, RR_LUTWA, RR_LUTWA_M1, 0x80); + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_IQK, 0x403e); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, 0x0); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, 0x4); + udelay(1); + break; + default: + break; + } +} + +static bool _iqk_2g_lok(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u8 path) +{ + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), B_KIP_IQP_IQSW, 0x09); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_TXT, 0x021); + rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, 0x00000119 + (path << 4)); + + _iqk_check_cal(rtwdev, path, ID_FLOK_COARSE); + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); + + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, 0x12); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), B_KIP_IQP_IQSW, 0x24); + rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, 0x00000319 + (path << 4)); + + _iqk_check_cal(rtwdev, path, ID_FLOK_VBUFFER); + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); + + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), B_KIP_IQP_IQSW, 0x09); + rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, 0x00000219 + (path << 4)); + + _iqk_check_cal(rtwdev, path, ID_FLOK_COARSE); + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); + + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, 0x12); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), B_KIP_IQP_IQSW, 0x24); + rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, 0x00000319 + (path << 4)); + + _iqk_check_cal(rtwdev, path, ID_FLOK_VBUFFER); + + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); + + return false; +} + +static bool _iqk_5g_lok(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u8 path) +{ + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), B_KIP_IQP_IQSW, 0x09); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_TXT, 0x021); + rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, 0x00000119 + (path << 4)); + + _iqk_check_cal(rtwdev, path, ID_FLOK_COARSE); + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); + + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, 0x12); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), B_KIP_IQP_IQSW, 0x24); + rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, 0x00000319 + (path << 4)); + + _iqk_check_cal(rtwdev, path, ID_FLOK_VBUFFER); + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); + + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), B_KIP_IQP_IQSW, 0x09); + rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, 0x00000219 + (path << 4)); + + _iqk_check_cal(rtwdev, path, ID_FLOK_COARSE); + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); + + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, 0x12); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), B_KIP_IQP_IQSW, 0x24); + rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, 0x00000319 + (path << 4)); + + _iqk_check_cal(rtwdev, path, ID_FLOK_VBUFFER); + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); + + return false; +} + +static bool _iqk_2g_tx(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u8 path) +{ + static const u32 g_power_range[4] = {0x0, 0x0, 0x0, 0x0}; + static const u32 g_track_range[4] = {0x4, 0x4, 0x6, 0x6}; + static const u32 g_gain_bb[4] = {0x08, 0x0e, 0x08, 0x0e}; + static const u32 g_itqt[4] = {0x09, 0x12, 0x1b, 0x24}; + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + bool notready = false; + bool kfail = false; + u8 gp; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + + for (gp = 0x0; gp < 0x4; gp++) { + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, + g_power_range[gp]); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, + g_track_range[gp]); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, + g_gain_bb[gp]); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), + 0x00000100, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), + 0x00000010, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), + 0x00000004, 0x0); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), + 0x00000003, gp); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_TXT, + 0x009); + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), + B_KIP_IQP_IQSW, g_itqt[gp]); + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBTXK); + iqk_info->nb_txcfir[path] = + rtw89_phy_read32_mask(rtwdev, R_TXIQC + (path << 8), MASKDWORD); + + if (iqk_info->is_nbiqk) + break; + + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), + B_KIP_IQP_IQSW, g_itqt[gp]); + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_TXK); + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, gp = 0x%x, 0x8%x38 = 0x%x\n", + path, gp, 1 << path, iqk_info->nb_txcfir[path]); + } + + if (!notready) + kfail = !!rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, B_NCTL_RPT_FLG); + + if (kfail) { + iqk_info->nb_txcfir[path] = 0x40000002; + rtw89_phy_write32_mask(rtwdev, R_IQK_RES + (path << 8), + B_IQK_RES_TXCFIR, 0x0); + } + + return kfail; +} + +static bool _iqk_5g_tx(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u8 path) +{ + static const u32 a_power_range[4] = {0x0, 0x0, 0x0, 0x0}; + static const u32 a_track_range[4] = {0x3, 0x3, 0x6, 0x6}; + static const u32 a_gain_bb[4] = {0x08, 0x10, 0x08, 0x0e}; + static const u32 a_itqt[4] = {0x09, 0x12, 0x1b, 0x24}; + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + bool notready = false; + bool kfail = false; + u8 gp; + + for (gp = 0x0; gp < 0x4; gp++) { + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, a_power_range[gp]); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, a_track_range[gp]); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, a_gain_bb[gp]); + + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), + MASKDWORD, a_itqt[gp]); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), + 0x00000100, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), + 0x00000010, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), + 0x00000004, 0x0); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), + 0x00000003, gp); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_TXT, + 0x009); + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), + B_KIP_IQP_IQSW, a_itqt[gp]); + + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBTXK); + iqk_info->nb_txcfir[path] = + rtw89_phy_read32_mask(rtwdev, R_TXIQC + (path << 8), MASKDWORD); + + if (iqk_info->is_nbiqk) + break; + + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), + B_KIP_IQP_IQSW, a_itqt[gp]); + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_TXK); + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, gp = 0x%x, 0x8%x38 = 0x%x\n", + path, gp, 1 << path, iqk_info->nb_txcfir[path]); + } + + if (!notready) + kfail = !!rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, B_NCTL_RPT_FLG); + + if (kfail) { + iqk_info->nb_txcfir[path] = 0x40000002; + rtw89_phy_write32_mask(rtwdev, R_IQK_RES + (path << 8), + B_IQK_RES_TXCFIR, 0x0); + } + + return kfail; +} + +static void _iqk_adc_fifo_rst(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, u8 path) +{ + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, B_ADC_FIFO_RXK, 0x0303); + udelay(10); + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, B_ADC_FIFO_RXK, 0x3333); +} + +static void _iqk_rxclk_setting(struct rtw89_dev *rtwdev, u8 path) +{ + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, B_ADC_FIFO_RXK, 0x0303); + + if (iqk_info->iqk_bw[path] == RTW89_CHANNEL_WIDTH_80) { + _rxck_force(rtwdev, RF_PATH_A, true, ADC_960M); + _rxck_force(rtwdev, RF_PATH_B, true, ADC_960M); + udelay(1); + + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, + B_UPD_CLK_ADC_ON, 0x1); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, + B_UPD_CLK_ADC_VAL, 0x1); + rtw89_phy_write32_mask(rtwdev, R_PATH0_SAMPL_DLY_T_V1, + B_PATH0_SAMPL_DLY_T_MSK_V1, 0x2); + rtw89_phy_write32_mask(rtwdev, R_PATH1_SAMPL_DLY_T_V1, + B_PATH1_SAMPL_DLY_T_MSK_V1, 0x2); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1, B_P0_CFCH_BW1, 0x8); + rtw89_phy_write32_mask(rtwdev, R_PATH1_BW_SEL_V1, + B_PATH1_BW_SEL_MSK_V1, 0x8); + } else { + _rxck_force(rtwdev, RF_PATH_A, true, ADC_480M); + _rxck_force(rtwdev, RF_PATH_B, true, ADC_480M); + udelay(1); + + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, + B_UPD_CLK_ADC_ON, 0x1); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, + B_UPD_CLK_ADC_VAL, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PATH0_SAMPL_DLY_T_V1, + B_PATH0_SAMPL_DLY_T_MSK_V1, 0x3); + rtw89_phy_write32_mask(rtwdev, R_PATH1_SAMPL_DLY_T_V1, + B_PATH1_SAMPL_DLY_T_MSK_V1, 0x3); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1, B_P0_CFCH_BW1, 0xf); + rtw89_phy_write32_mask(rtwdev, R_PATH1_BW_SEL_V1, + B_PATH1_BW_SEL_MSK_V1, 0xf); + } + + rtw89_phy_write32_mask(rtwdev, R_PATH0_SAMPL_DLY_T_V1, 0x00000780, 0x8); + rtw89_phy_write32_mask(rtwdev, R_PATH1_SAMPL_DLY_T_V1, 0x00000780, 0x8); + rtw89_phy_write32_mask(rtwdev, R_PATH0_SAMPL_DLY_T_V1, 0x00007800, 0x2); + rtw89_phy_write32_mask(rtwdev, R_PATH1_SAMPL_DLY_T_V1, 0x00007800, 0x2); + rtw89_phy_write32_mask(rtwdev, R_DRCK, B_DRCK_MUL, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P1_DBGMOD, B_P1_DBGMOD_ON, 0x1); + udelay(1); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15, 0x0f); + udelay(1); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15, 0x03); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_15, 0xa001); + udelay(1); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_15, 0xa041); + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, B_ADC_FIFO_RXK, 0x3333); +} + +static bool _iqk_2g_rx(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u8 path) +{ + static const u32 g_idxrxgain[2] = {0x212, 0x310}; + static const u32 g_idxattc2[2] = {0x00, 0x20}; + static const u32 g_idxattc1[2] = {0x3, 0x2}; + static const u32 g_idxrxagc[2] = {0x0, 0x2}; + static const u32 g_idx[2] = {0x0, 0x2}; + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + bool notready = false; + bool kfail = false; + u32 rf_18, tmp; + u8 gp; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_MASK, 0xc); + rtw89_write_rf(rtwdev, path, RR_RXK, RR_RXK_SEL2G, 0x1); + rf_18 = rtw89_read_rf(rtwdev, path, RR_CFGCH, RFREG_MASK); + rtw89_write_rf(rtwdev, path, RR_RSV4, RFREG_MASK, rf_18); + + for (gp = 0x0; gp < 0x2; gp++) { + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_RGM, g_idxrxgain[gp]); + rtw89_write_rf(rtwdev, path, RR_RXBB, RR_RXBB_C2G, g_idxattc2[gp]); + rtw89_write_rf(rtwdev, path, RR_RXBB, RR_RXBB_C1G, g_idxattc1[gp]); + + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), + 0x00000100, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), + 0x00000010, 0x0); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), + 0x00000007, g_idx[gp]); + rtw89_write_rf(rtwdev, path, RR_RXKPLL, RFREG_MASK, 0x80013); + udelay(100); + udelay(100); + + tmp = rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASK); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF2, B_IQK_DIF2_RXPI, tmp); + rtw89_phy_write32_mask(rtwdev, R_IQK_RXA, B_IQK_RXAGC, g_idxrxagc[gp]); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x11); + + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_RXAGC); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, rf rxbb = %x\n", path, + rtw89_read_rf(rtwdev, path, RR_MOD, 0x003c0)); + + rtw89_write_rf(rtwdev, path, RR_RXKPLL, RFREG_MASK, 0x80013); + udelay(100); + udelay(100); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x011); + + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBRXK); + iqk_info->nb_rxcfir[path] = + rtw89_phy_read32_mask(rtwdev, R_RXIQC + (path << 8), + MASKDWORD) | 0x2; + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, gp = 0x%x, 0x8%x3c = 0x%x\n", path, + g_idx[gp], 1 << path, iqk_info->nb_rxcfir[path]); + + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); + + if (iqk_info->is_nbiqk) + break; + + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_RXK); + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); + } + + if (!notready) + kfail = !!rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, B_NCTL_RPT_FLG); + + if (kfail) { + iqk_info->nb_txcfir[path] = 0x40000002; + rtw89_phy_write32_mask(rtwdev, R_IQK_RES + (path << 8), + B_IQK_RES_RXCFIR, 0x0); + } + rtw89_write_rf(rtwdev, path, RR_RXK, RR_RXK_SEL2G, 0x0); + + return kfail; +} + +static bool _iqk_5g_rx(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u8 path) +{ + static const u32 a_idxrxgain[2] = {0x110, 0x290}; + static const u32 a_idxattc2[2] = {0x0f, 0x0f}; + static const u32 a_idxattc1[2] = {0x2, 0x2}; + static const u32 a_idxrxagc[2] = {0x4, 0x6}; + static const u32 a_idx[2] = {0x0, 0x2}; + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + bool notready = false; + bool kfail = false; + u32 rf_18, tmp; + u8 gp; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_MASK, 0xc); + rtw89_write_rf(rtwdev, path, RR_RXK, RR_RXK_SEL5G, 0x1); + rf_18 = rtw89_read_rf(rtwdev, path, RR_CFGCH, RFREG_MASK); + rtw89_write_rf(rtwdev, path, RR_RSV4, RFREG_MASK, rf_18); + + for (gp = 0x0; gp < 0x2; gp++) { + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_RGM, a_idxrxgain[gp]); + rtw89_write_rf(rtwdev, path, RR_RXA2, RR_RXA2_HATT, a_idxattc2[gp]); + rtw89_write_rf(rtwdev, path, RR_RXA2, RR_RXA2_CC2, a_idxattc1[gp]); + + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), + 0x00000100, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), + 0x00000010, 0x0); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), + 0x00000007, a_idx[gp]); + rtw89_write_rf(rtwdev, path, RR_RXKPLL, RFREG_MASK, 0x80013); + udelay(100); + udelay(100); + + tmp = rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASK); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF2, B_IQK_DIF2_RXPI, tmp); + rtw89_phy_write32_mask(rtwdev, R_IQK_RXA, B_IQK_RXAGC, a_idxrxagc[gp]); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x11); + + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_RXAGC); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, rf rxbb = %x\n", path, + rtw89_read_rf(rtwdev, path, RR_MOD, 0x003c0)); + + rtw89_write_rf(rtwdev, path, RR_RXKPLL, RFREG_MASK, 0x80013); + udelay(200); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x011); + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBRXK); + iqk_info->nb_rxcfir[path] = + rtw89_phy_read32_mask(rtwdev, R_RXIQC + (path << 8), + MASKDWORD) | 0x2; + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, gp = 0x%x, 0x8%x3c = 0x%x\n", + path, a_idx[gp], 1 << path, iqk_info->nb_rxcfir[path]); + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); + + if (iqk_info->is_nbiqk) + break; + + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_RXK); + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); + } + + if (!notready) + kfail = !!rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, B_NCTL_RPT_FLG); + + if (kfail) { + iqk_info->nb_txcfir[path] = 0x40000002; + rtw89_phy_write32_mask(rtwdev, R_IQK_RES + (path << 8), + B_IQK_RES_RXCFIR, 0x0); + } + rtw89_write_rf(rtwdev, path, RR_RXK, RR_RXK_SEL2G, 0x0); + + return kfail; +} + +static void _iqk_by_path(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u8 path) +{ + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + bool lok_result = false; + bool txk_result = false; + bool rxk_result = false; + u8 i; + + for (i = 0; i < 3; i++) { + _iqk_txk_setting(rtwdev, path); + if (iqk_info->iqk_band[path] == RTW89_BAND_2G) + lok_result = _iqk_2g_lok(rtwdev, phy_idx, path); + else + lok_result = _iqk_5g_lok(rtwdev, phy_idx, path); + + if (!lok_result) + break; + } + + if (lok_result) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]!!!!!!!!!!LOK by Pass !!!!!!!!!!!\n"); + rtw89_write_rf(rtwdev, path, RR_DTXLOK, RFREG_MASK, 0x80200); + rtw89_write_rf(rtwdev, path, RR_RSV2, RFREG_MASK, 0x80200); + rtw89_write_rf(rtwdev, path, RR_LOKVB, RFREG_MASK, 0x80200); + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]RF_0x08[00:19] = 0x%x\n", + rtw89_read_rf(rtwdev, path, RR_DTXLOK, RFREG_MASK)); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]RF_0x09[00:19] = 0x%x\n", + rtw89_read_rf(rtwdev, path, RR_RSV2, RFREG_MASK)); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]RF_0x0a[00:19] = 0x%x\n", + rtw89_read_rf(rtwdev, path, RR_LOKVB, RFREG_MASK)); + + if (iqk_info->iqk_band[path] == RTW89_BAND_2G) + txk_result = _iqk_2g_tx(rtwdev, phy_idx, path); + else + txk_result = _iqk_5g_tx(rtwdev, phy_idx, path); + + _iqk_rxclk_setting(rtwdev, path); + _iqk_adc_fifo_rst(rtwdev, phy_idx, path); + + if (iqk_info->iqk_band[path] == RTW89_BAND_2G) + rxk_result = _iqk_2g_rx(rtwdev, phy_idx, path); + else + rxk_result = _iqk_5g_rx(rtwdev, phy_idx, path); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]result : lok_= %x, txk_= %x, rxk_= %x\n", + lok_result, txk_result, rxk_result); +} + +static void _iqk_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, u8 path) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + u8 get_empty_table = false; + 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); + + iqk_info->iqk_band[path] = chan->band_type; + iqk_info->iqk_bw[path] = chan->band_width; + iqk_info->iqk_ch[path] = chan->channel; + iqk_info->iqk_mcc_ch[idx][path] = chan->channel; + iqk_info->iqk_table_idx[path] = idx; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x18= 0x%x, idx = %x\n", + path, reg_rf18, idx); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x18= 0x%x\n", + path, reg_rf18); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x35c= 0x%x\n", + path, reg_35c); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]times = 0x%x, ch =%x\n", + iqk_info->iqk_times, idx); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]iqk_mcc_ch[%x][%x] = 0x%x\n", + idx, path, iqk_info->iqk_mcc_ch[idx][path]); +} + +static void _iqk_start_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u8 path) +{ + _iqk_by_path(rtwdev, phy_idx, path); +} + +static void _iqk_restore(struct rtw89_dev *rtwdev, u8 path) +{ + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "===> %s\n", __func__); + + if (iqk_info->is_nbiqk) { + rtw89_phy_write32_mask(rtwdev, R_TXIQC + (path << 8), + MASKDWORD, iqk_info->nb_txcfir[path]); + rtw89_phy_write32_mask(rtwdev, R_RXIQC + (path << 8), + MASKDWORD, iqk_info->nb_rxcfir[path]); + } else { + rtw89_phy_write32_mask(rtwdev, R_TXIQC + (path << 8), + MASKDWORD, 0x40000000); + rtw89_phy_write32_mask(rtwdev, R_RXIQC + (path << 8), + MASKDWORD, 0x40000000); + } + rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, + 0x00000e19 + (path << 4)); + + _iqk_check_cal(rtwdev, path, 0x0); + + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_NCTL_RPT, MASKDWORD, 0x00000000); + rtw89_phy_write32_mask(rtwdev, R_KIP_SYSCFG, MASKDWORD, 0x80000000); + + rtw89_phy_write32_mask(rtwdev, R_KIP_CLK, MASKDWORD, 0x0); + rtw89_phy_write32_mask(rtwdev, R_IQRSN, B_IQRSN_K2, 0x0); + rtw89_phy_write32_mask(rtwdev, R_CFIR_SYS + (path << 8), BIT(28), 0x0); + + rtw89_write_rf(rtwdev, path, RR_LUTWE, RR_LUTWE_LOK, 0x0); + rtw89_write_rf(rtwdev, path, RR_LUTWE, RR_LUTWE_LOK, 0x0); + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_MASK, 0x3); + rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x1); + rtw89_write_rf(rtwdev, path, RR_BBDC, RR_BBDC_SEL, 0x1); +} + +static void _iqk_afebb_restore(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, u8 path) +{ + rtw89_debug(rtwdev, RTW89_DBG_RFK, "===> %s\n", __func__); + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, B_ADC_FIFO_RXK, 0x0303); + rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P1_DBGMOD, B_P1_DBGMOD_ON, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_CLKG_FORCE, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P1_RFCTM, B_P1_CLKG_FORCE, 0x0); + rtw89_phy_write32_mask(rtwdev, R_TXCKEN_FORCE, B_TXCKEN_FORCE_ALL, 0x0000000); + rtw89_phy_write32_mask(rtwdev, R_FAHM, B_RXTD_CKEN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, B_UPD_GEN_ON, 0x0); + rtw89_phy_write32_mask(rtwdev, R_TX_COLLISION_T2R_ST, 0x0000001f, 0x03); + rtw89_phy_write32_mask(rtwdev, R_TX_COLLISION_T2R_ST, 0x000003e0, 0x03); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_TXCK_ALL, 0x00); + rtw89_phy_write32_mask(rtwdev, R_P1_RXCK, B_P1_TXCK_ALL, 0x00); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, + B_UPD_CLK_ADC_VAL | B_UPD_CLK_ADC_ON, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PD_CTRL, B_PD_HIT_DIS, 0x0); + rtw89_phy_write32_mask(rtwdev, R_RXCCA, B_RXCCA_DIS, 0x0); + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, B_ADC_FIFO_RXK, 0x0000); + rtw89_phy_write32_mask(rtwdev, R_P0_ADCFF_EN, B_P0_ADCFF_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P1_ADCFF_EN, B_P1_ADCFF_EN, 0x0); +} + +static void _iqk_preset(struct rtw89_dev *rtwdev, u8 path) +{ + u8 idx = 0; + + rtw89_phy_write32_mask(rtwdev, R_COEF_SEL + (path << 8), 0x00000001, idx); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), 0x00000008, idx); + rtw89_phy_write32_mask(rtwdev, R_TXIQC + (path << 8), MASKDWORD, 0x40000000); + rtw89_phy_write32_mask(rtwdev, R_RXIQC + (path << 8), MASKDWORD, 0x40000000); + + rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x0); + rtw89_write_rf(rtwdev, path, RR_BBDC, RR_BBDC_SEL, 0x0); + rtw89_phy_write32_mask(rtwdev, R_NCTL_RPT, MASKDWORD, 0x00000080); + rtw89_phy_write32_mask(rtwdev, R_KIP_SYSCFG, MASKDWORD, 0x81ff010a); +} + +static void _iqk_macbb_setting(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, u8 path) +{ + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, B_ADC_FIFO_RXK, 0x0303); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_GOT_TXRX, 0x3); + rtw89_phy_write32_mask(rtwdev, R_P1_RFCTM, B_P1_GOT_TXRX, 0x3); + rtw89_phy_write32_mask(rtwdev, R_P0_ADCFF_EN, B_P0_ADCFF_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P1_ADCFF_EN, B_P1_ADCFF_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_CLKG_FORCE, 0x3); + rtw89_phy_write32_mask(rtwdev, R_P1_RFCTM, B_P0_CLKG_FORCE, 0x3); + rtw89_phy_write32_mask(rtwdev, R_TXCKEN_FORCE, B_TXCKEN_FORCE_ALL, 0x1ffffff); + rtw89_phy_write32_mask(rtwdev, R_FAHM, B_RXTD_CKEN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, B_UPD_GEN_ON, 0x1); + rtw89_phy_write32_mask(rtwdev, R_TX_COLLISION_T2R_ST, B_TXRX_FORCE_VAL, 0x3ff); + rtw89_phy_write32_mask(rtwdev, R_IOQ_IQK_DPK, B_IOQ_IQK_DPK_CLKEN, 0x3); + rtw89_phy_write32_mask(rtwdev, R_IQK_DPK_RST, B_IQK_DPK_RST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P0_PATH_RST, B_P0_PATH_RST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P1_PATH_RST, B_P1_PATH_RST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_PD_CTRL, B_PD_HIT_DIS, 0x1); + rtw89_phy_write32_mask(rtwdev, R_RXCCA, B_RXCCA_DIS, 0x1); + rtw89_phy_write32_mask(rtwdev, R_DCFO_WEIGHT, B_DAC_CLK_IDX, 0x1); + + _txck_force(rtwdev, RF_PATH_A, true, DAC_960M); + _txck_force(rtwdev, RF_PATH_B, true, DAC_960M); + _rxck_force(rtwdev, RF_PATH_A, true, ADC_1920M); + _rxck_force(rtwdev, RF_PATH_B, true, ADC_1920M); + + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, B_UPD_CLK_ADC_ON, 0x1); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, B_UPD_CLK_ADC_VAL, 0x2); + + rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P1_DBGMOD, B_P1_DBGMOD_ON, 0x1); + udelay(10); + 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); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_15, 0x0001); + udelay(10); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_15, 0x0041); + rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_RSTB, 0x1); + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, B_ADC_FIFO_RXK, 0x3333); +} + +static void _iqk_init(struct rtw89_dev *rtwdev) +{ + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + u8 idx, path; + + rtw89_phy_write32_mask(rtwdev, R_IQKINF, MASKDWORD, 0x0); + + if (iqk_info->is_iqk_init) + return; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + iqk_info->is_iqk_init = true; + iqk_info->is_nbiqk = false; + iqk_info->iqk_fft_en = false; + iqk_info->iqk_sram_en = false; + iqk_info->iqk_cfir_en = false; + iqk_info->iqk_xym_en = false; + iqk_info->iqk_times = 0x0; + + for (idx = 0; idx < RTW89_IQK_CHS_NR; idx++) { + iqk_info->iqk_channel[idx] = 0x0; + for (path = 0; path < RTW8852BT_SS; path++) { + iqk_info->lok_cor_fail[idx][path] = false; + iqk_info->lok_fin_fail[idx][path] = false; + iqk_info->iqk_tx_fail[idx][path] = false; + iqk_info->iqk_rx_fail[idx][path] = false; + iqk_info->iqk_mcc_ch[idx][path] = 0x0; + iqk_info->iqk_table_idx[path] = 0x0; + } + } +} + static void _wait_rx_mode(struct rtw89_dev *rtwdev, u8 kpath) { u32 rf_mode; @@ -374,6 +1199,57 @@ static void _tmac_tx_pause(struct rtw89_dev *rtwdev, enum rtw89_phy_idx band_idx _wait_rx_mode(rtwdev, _kpath(rtwdev, band_idx)); } +static void _doiqk(struct rtw89_dev *rtwdev, bool force, + enum rtw89_phy_idx phy_idx, u8 path) +{ + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + u32 backup_bb_val[BACKUP_BB_REGS_NR]; + u32 backup_rf_val[RTW8852BT_SS][BACKUP_RF_REGS_NR]; + u8 phy_map = rtw89_btc_phymap(rtwdev, phy_idx, RF_AB); + + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_ONESHOT_START); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]==========IQK start!!!!!==========\n"); + iqk_info->iqk_times++; + iqk_info->version = RTW8852BT_IQK_VER; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]Test Ver 0x%x\n", iqk_info->version); + _iqk_get_ch_info(rtwdev, phy_idx, path); + + _rfk_backup_bb_reg(rtwdev, backup_bb_val); + _rfk_backup_rf_reg(rtwdev, backup_rf_val[path], path); + _iqk_macbb_setting(rtwdev, phy_idx, path); + _iqk_preset(rtwdev, path); + _iqk_start_iqk(rtwdev, phy_idx, path); + _iqk_restore(rtwdev, path); + _iqk_afebb_restore(rtwdev, phy_idx, path); + _rfk_reload_bb_reg(rtwdev, backup_bb_val); + _rfk_reload_rf_reg(rtwdev, backup_rf_val[path], path); + + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_ONESHOT_STOP); +} + +static void _iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, bool force) +{ + u8 kpath = _kpath(rtwdev, phy_idx); + + switch (kpath) { + case RF_A: + _doiqk(rtwdev, force, phy_idx, RF_PATH_A); + break; + case RF_B: + _doiqk(rtwdev, force, phy_idx, RF_PATH_B); + break; + case RF_AB: + _doiqk(rtwdev, force, phy_idx, RF_PATH_A); + _doiqk(rtwdev, force, phy_idx, RF_PATH_B); + break; + default: + break; + } +} + static void _dpk_onoff(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, bool off) { struct rtw89_dpk_info *dpk = &rtwdev->dpk; @@ -2394,6 +3270,22 @@ void rtw8852bt_dpk_init(struct rtw89_dev *rtwdev) _set_dpd_backoff(rtwdev, RTW89_PHY_0); } +void rtw8852bt_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + u8 phy_map = rtw89_btc_phymap(rtwdev, phy_idx, 0); + u32 tx_en; + + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_START); + rtw89_chip_stop_sch_tx(rtwdev, phy_idx, &tx_en, RTW89_SCH_TX_SEL_ALL); + _wait_rx_mode(rtwdev, _kpath(rtwdev, phy_idx)); + + _iqk_init(rtwdev); + _iqk(rtwdev, phy_idx, false); + + rtw89_chip_resume_sch_tx(rtwdev, phy_idx, tx_en); + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_STOP); +} + void rtw8852bt_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { rtw89_debug(rtwdev, RTW89_DBG_RFK, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h index 89640b42d4d0..22c0c9c3d173 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h @@ -7,6 +7,7 @@ #include "core.h" +void rtw8852bt_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); void rtw8852bt_dpk_init(struct rtw89_dev *rtwdev); void rtw8852bt_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy); void rtw8852bt_dpk_track(struct rtw89_dev *rtwdev); From c3d9705de5e7442afe8ce121b86f99b4b7de4ac8 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 27 Jun 2024 10:58:47 +0800 Subject: [PATCH 068/204] wifi: rtw89: 8852bt: rfk: add RX DCK RX DCK stands for receiver DC calibration. With this calibration, we have proper DC offset to reflect correct received signal strength indicator. Do this calibration when bringing up interface and going to connect. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240627025849.25198-3-pkshih@realtek.com --- .../wireless/realtek/rtw89/rtw8852bt_rfk.c | 57 +++++++++++++++++++ .../wireless/realtek/rtw89/rtw8852bt_rfk.h | 1 + 2 files changed, 58 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c index 4a638e2444db..52dfbe0b3d6b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c @@ -13,6 +13,7 @@ #include "rtw8852bt_rfk_table.h" #include "rtw8852b_common.h" +#define RTW8852BT_RXDCK_VER 0x1 #define RTW8852BT_IQK_VER 0x2a #define RTW8852BT_SS 2 #define RTW8852BT_TSSI_PATH_NR 2 @@ -365,6 +366,47 @@ static void _rfk_bb_afe_restore(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_MV_AVG, B_P1_TXPW_RSTB, 0x2); } +static void _set_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + rtw89_write_rf(rtwdev, path, RR_DCK1, RR_DCK1_CLR, 0x0); + rtw89_write_rf(rtwdev, path, RR_DCK, RR_DCK_LV, 0x0); + rtw89_write_rf(rtwdev, path, RR_DCK, RR_DCK_LV, 0x1); + mdelay(1); +} + +static void _rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) +{ + u8 path, dck_tune; + u32 rf_reg5; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] ****** RXDCK Start (Ver: 0x%x, CV : 0x%x) ******\n", + RTW8852BT_RXDCK_VER, rtwdev->hal.cv); + + for (path = 0; path < RF_PATH_NUM_8852BT; path++) { + rf_reg5 = rtw89_read_rf(rtwdev, path, RR_RSV1, RFREG_MASK); + dck_tune = rtw89_read_rf(rtwdev, path, RR_DCK, RR_DCK_FINE); + + if (rtwdev->is_tssi_mode[path]) + rtw89_phy_write32_mask(rtwdev, + R_P0_TSSI_TRK + (path << 13), + B_P0_TSSI_TRK_EN, 0x1); + + rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x0); + rtw89_write_rf(rtwdev, path, RR_DCK, RR_DCK_FINE, 0x0); + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_MASK, RR_MOD_V_RX); + _set_rx_dck(rtwdev, phy, path); + rtw89_write_rf(rtwdev, path, RR_DCK, RR_DCK_FINE, dck_tune); + rtw89_write_rf(rtwdev, path, RR_RSV1, RFREG_MASK, rf_reg5); + + if (rtwdev->is_tssi_mode[path]) + rtw89_phy_write32_mask(rtwdev, + R_P0_TSSI_TRK + (path << 13), + B_P0_TSSI_TRK_EN, 0x0); + } +} + static bool _iqk_check_cal(struct rtw89_dev *rtwdev, u8 path, u8 ktype) { bool notready = false; @@ -3286,6 +3328,21 @@ void rtw8852bt_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_STOP); } +void rtw8852bt_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + u8 phy_map = rtw89_btc_phymap(rtwdev, phy_idx, 0); + u32 tx_en; + + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_RXDCK, BTC_WRFK_START); + rtw89_chip_stop_sch_tx(rtwdev, phy_idx, &tx_en, RTW89_SCH_TX_SEL_ALL); + _wait_rx_mode(rtwdev, _kpath(rtwdev, phy_idx)); + + _rx_dck(rtwdev, phy_idx); + + rtw89_chip_resume_sch_tx(rtwdev, phy_idx, tx_en); + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_RXDCK, BTC_WRFK_STOP); +} + void rtw8852bt_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { rtw89_debug(rtwdev, RTW89_DBG_RFK, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h index 22c0c9c3d173..3ac63a2a63f7 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h @@ -8,6 +8,7 @@ #include "core.h" void rtw8852bt_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +void rtw8852bt_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); void rtw8852bt_dpk_init(struct rtw89_dev *rtwdev); void rtw8852bt_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy); void rtw8852bt_dpk_track(struct rtw89_dev *rtwdev); From 39f0123e032192f13c843344a83e3132bff28f3c Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 27 Jun 2024 10:58:48 +0800 Subject: [PATCH 069/204] wifi: rtw89: 8852bt: rfk: add DACK DACK (digital-to-analog converters calibration) is used to calibrate DAC to output signals as expected. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240627025849.25198-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 15 + .../wireless/realtek/rtw89/rtw8852bt_rfk.c | 487 ++++++++++++++++++ .../wireless/realtek/rtw89/rtw8852bt_rfk.h | 1 + 3 files changed, 503 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 24e8d244534e..7df36f3bff0b 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -7836,6 +7836,7 @@ #define B_ANAPAR_PW15_H2 GENMASK(27, 26) #define R_ANAPAR 0x032C #define B_ANAPAR_15 GENMASK(31, 16) +#define B_ANAPAR_EN1 BIT(31) #define B_ANAPAR_ADCCLK BIT(30) #define B_ANAPAR_FLTRST BIT(22) #define B_ANAPAR_CRXBB GENMASK(18, 16) @@ -9080,11 +9081,13 @@ #define B_DCOF0_RST BIT(17) #define B_DCOF0_V GENMASK(4, 1) #define R_DCOF1 0xC004 +#define B_DCOF1_VAL GENMASK(31, 20) #define B_DCOF1_RST BIT(17) #define B_DCOF1_S BIT(0) #define R_DCOF8 0xC020 #define B_DCOF8_V GENMASK(4, 1) #define R_DCOF9 0xC024 +#define B_DCOF9_VAL GENMASK(31, 20) #define B_DCOF9_RST BIT(17) #define R_DACK_S0P0 0xC040 #define B_DACK_S0P0_OK BIT(31) @@ -9158,11 +9161,18 @@ #define B_ADDCKR0_DC GENMASK(15, 4) #define B_ADDCKR0_A1 GENMASK(9, 0) #define R_DACK10 0xC100 +#define B_DACK10_RST BIT(17) #define B_DACK10 GENMASK(4, 1) #define R_DACK1_K 0xc104 +#define B_DACK1_VAL GENMASK(31, 20) +#define B_DACK1_RST BIT(17) #define B_DACK1_EN BIT(0) #define R_DACK11 0xC120 #define B_DACK11 GENMASK(4, 1) +#define R_DACK2_K 0xC124 +#define B_DACK2_VAL GENMASK(31, 20) +#define B_DACK2_RST BIT(17) +#define B_DACK2_EN BIT(0) #define R_DACK_S1P0 0xC140 #define B_DACK_S1P0_OK BIT(31) #define R_DACK_BIAS10 0xC148 @@ -9211,6 +9221,11 @@ #define B_DACKN0_V GENMASK(21, 14) #define R_DACKN1_CTL 0xC224 #define B_DACKN1_V GENMASK(21, 14) +#define B_DACKN1_ON BIT(0) +#define R_DACKN2_CTL 0xC238 +#define B_DACKN2_ON BIT(0) +#define R_DACKN3_CTL 0xC24C +#define B_DACKN3_ON BIT(0) #define R_GAIN_MAP0 0xE44C #define B_GAIN_MAP0_EN BIT(0) #define R_GAIN_MAP1 0xE54C diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c index 52dfbe0b3d6b..6c2fecb58940 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c @@ -407,6 +407,484 @@ static void _rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) } } +static void _drck(struct rtw89_dev *rtwdev) +{ + u32 rck_d; + u32 val; + int ret; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]Ddie RCK start!!!\n"); + rtw89_phy_write32_mask(rtwdev, R_DRCK, B_DRCK_EN, 0x1); + + ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, val, val, + 1, 10000, false, + rtwdev, R_DRCK_RES, B_DRCK_POL); + if (ret) + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]DRCK timeout\n"); + + rtw89_phy_write32_mask(rtwdev, R_DRCK, B_DRCK_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_DRCK_FH, B_DRCK_LAT, 0x1); + udelay(1); + rtw89_phy_write32_mask(rtwdev, R_DRCK_FH, B_DRCK_LAT, 0x0); + + rck_d = rtw89_phy_read32_mask(rtwdev, R_DRCK_RES, 0x7c00); + rtw89_phy_write32_mask(rtwdev, R_DRCK, B_DRCK_IDLE, 0x0); + rtw89_phy_write32_mask(rtwdev, R_DRCK, B_DRCK_VAL, rck_d); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0xc0c4 = 0x%x\n", + rtw89_phy_read32_mask(rtwdev, R_DRCK, MASKDWORD)); +} + +static void _dack_backup_s0(struct rtw89_dev *rtwdev) +{ + struct rtw89_dack_info *dack = &rtwdev->dack; + u8 i; + + rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x1); + + for (i = 0; i < 0x10; i++) { + rtw89_phy_write32_mask(rtwdev, R_DCOF0, B_DCOF0_V, i); + dack->msbk_d[0][0][i] = + rtw89_phy_read32_mask(rtwdev, R_DACK_S0P2, B_DACK_S0M0); + + rtw89_phy_write32_mask(rtwdev, R_DCOF8, B_DCOF8_V, i); + dack->msbk_d[0][1][i] = + rtw89_phy_read32_mask(rtwdev, R_DACK_S0P3, B_DACK_S0M1); + } + + dack->biask_d[0][0] = + rtw89_phy_read32_mask(rtwdev, R_DACK_BIAS00, B_DACK_BIAS00); + dack->biask_d[0][1] = + rtw89_phy_read32_mask(rtwdev, R_DACK_BIAS01, B_DACK_BIAS01); + + dack->dadck_d[0][0] = + rtw89_phy_read32_mask(rtwdev, R_DACK_DADCK00, B_DACK_DADCK00); + dack->dadck_d[0][1] = + rtw89_phy_read32_mask(rtwdev, R_DACK_DADCK01, B_DACK_DADCK01); +} + +static void _dack_backup_s1(struct rtw89_dev *rtwdev) +{ + struct rtw89_dack_info *dack = &rtwdev->dack; + u8 i; + + rtw89_phy_write32_mask(rtwdev, R_P1_DBGMOD, B_P1_DBGMOD_ON, 0x1); + + for (i = 0; i < 0x10; i++) { + rtw89_phy_write32_mask(rtwdev, R_DACK10, B_DACK10, i); + dack->msbk_d[1][0][i] = + rtw89_phy_read32_mask(rtwdev, R_DACK10S, B_DACK10S); + + rtw89_phy_write32_mask(rtwdev, R_DACK11, B_DACK11, i); + dack->msbk_d[1][1][i] = + rtw89_phy_read32_mask(rtwdev, R_DACK11S, B_DACK11S); + } + + dack->biask_d[1][0] = + rtw89_phy_read32_mask(rtwdev, R_DACK_BIAS10, B_DACK_BIAS10); + dack->biask_d[1][1] = + rtw89_phy_read32_mask(rtwdev, R_DACK_BIAS11, B_DACK_BIAS11); + + dack->dadck_d[1][0] = + rtw89_phy_read32_mask(rtwdev, R_DACK_DADCK10, B_DACK_DADCK10); + dack->dadck_d[1][1] = + rtw89_phy_read32_mask(rtwdev, R_DACK_DADCK11, B_DACK_DADCK11); +} + +static +void _dack_reset(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) +{ + if (path == RF_PATH_A) { + rtw89_phy_write32_mask(rtwdev, R_DCOF0, B_DCOF0_RST, 0x0); + rtw89_phy_write32_mask(rtwdev, R_DCOF0, B_DCOF0_RST, 0x1); + } else { + rtw89_phy_write32_mask(rtwdev, R_DACK10, B_DACK10_RST, 0x0); + rtw89_phy_write32_mask(rtwdev, R_DACK10, B_DACK10_RST, 0x1); + } +} + +static +void _dack_reload_by_path(struct rtw89_dev *rtwdev, u8 path, u8 index) +{ + struct rtw89_dack_info *dack = &rtwdev->dack; + u32 tmp, tmp_offset, tmp_reg; + u32 idx_offset, path_offset; + u8 i; + + if (index == 0) + idx_offset = 0; + else + idx_offset = 0x14; + + if (path == RF_PATH_A) + path_offset = 0; + else + path_offset = 0x28; + + tmp_offset = idx_offset + path_offset; + + rtw89_phy_write32_mask(rtwdev, R_DCOF1, B_DCOF1_RST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_DCOF9, B_DCOF9_RST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_DACK1_K, B_DACK1_RST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_DACK2_K, B_DACK2_RST, 0x1); + + /* msbk_d: 15/14/13/12 */ + tmp = 0x0; + for (i = 0; i < 4; i++) + tmp |= dack->msbk_d[path][index][i + 12] << (i * 8); + tmp_reg = 0xc200 + tmp_offset; + rtw89_phy_write32(rtwdev, tmp_reg, tmp); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x=0x%x\n", tmp_reg, + rtw89_phy_read32_mask(rtwdev, tmp_reg, MASKDWORD)); + + /* msbk_d: 11/10/9/8 */ + tmp = 0x0; + for (i = 0; i < 4; i++) + tmp |= dack->msbk_d[path][index][i + 8] << (i * 8); + tmp_reg = 0xc204 + tmp_offset; + rtw89_phy_write32(rtwdev, tmp_reg, tmp); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x=0x%x\n", tmp_reg, + rtw89_phy_read32_mask(rtwdev, tmp_reg, MASKDWORD)); + + /* msbk_d: 7/6/5/4 */ + tmp = 0x0; + for (i = 0; i < 4; i++) + tmp |= dack->msbk_d[path][index][i + 4] << (i * 8); + tmp_reg = 0xc208 + tmp_offset; + rtw89_phy_write32(rtwdev, tmp_reg, tmp); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x=0x%x\n", tmp_reg, + rtw89_phy_read32_mask(rtwdev, tmp_reg, MASKDWORD)); + + /* msbk_d: 3/2/1/0 */ + tmp = 0x0; + for (i = 0; i < 4; i++) + tmp |= dack->msbk_d[path][index][i] << (i * 8); + tmp_reg = 0xc20c + tmp_offset; + rtw89_phy_write32(rtwdev, tmp_reg, tmp); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x=0x%x\n", tmp_reg, + rtw89_phy_read32_mask(rtwdev, tmp_reg, MASKDWORD)); + + /* dadak_d/biask_d */ + tmp = (dack->biask_d[path][index] << 22) | + (dack->dadck_d[path][index] << 14); + tmp_reg = 0xc210 + tmp_offset; + rtw89_phy_write32(rtwdev, tmp_reg, tmp); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x=0x%x\n", tmp_reg, + rtw89_phy_read32_mask(rtwdev, tmp_reg, MASKDWORD)); + + /* enable DACK result from reg */ + rtw89_phy_write32_mask(rtwdev, R_DACKN0_CTL + tmp_offset, B_DACKN0_EN, 0x1); +} + +static +void _dack_reload(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) +{ + u8 i; + + for (i = 0; i < 2; i++) + _dack_reload_by_path(rtwdev, path, i); +} + +static bool _dack_s0_poll(struct rtw89_dev *rtwdev) +{ + if (rtw89_phy_read32_mask(rtwdev, R_DACK_S0P0, B_DACK_S0P0_OK) == 0 || + rtw89_phy_read32_mask(rtwdev, R_DACK_S0P1, B_DACK_S0P1_OK) == 0 || + rtw89_phy_read32_mask(rtwdev, R_DACK_S0P2, B_DACK_S0P2_OK) == 0 || + rtw89_phy_read32_mask(rtwdev, R_DACK_S0P3, B_DACK_S0P3_OK) == 0) + return false; + + return true; +} + +static void _dack_s0(struct rtw89_dev *rtwdev) +{ + struct rtw89_dack_info *dack = &rtwdev->dack; + bool done; + int ret; + + _txck_force(rtwdev, RF_PATH_A, true, DAC_160M); + + rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x1); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, BIT(28), 0x1); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_EN1, 0x0); + udelay(100); + rtw89_phy_write32_mask(rtwdev, R_DCOF1, B_DCOF1_VAL, 0x30); + rtw89_phy_write32_mask(rtwdev, R_DCOF9, B_DCOF9_VAL, 0x30); + + _dack_reset(rtwdev, RF_PATH_A); + + rtw89_phy_write32_mask(rtwdev, R_DCOF1, B_DCOF1_S, 0x1); + udelay(1); + + dack->msbk_timeout[0] = false; + + ret = read_poll_timeout_atomic(_dack_s0_poll, done, done, + 1, 20000, false, rtwdev); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 DACK timeout\n"); + dack->msbk_timeout[0] = true; + } + + rtw89_phy_write32_mask(rtwdev, R_DCOF1, B_DCOF1_S, 0x0); + + _txck_force(rtwdev, RF_PATH_A, false, DAC_960M); + _dack_backup_s0(rtwdev); + _dack_reload(rtwdev, RF_PATH_A); + + rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x0); +} + +static bool _dack_s1_poll(struct rtw89_dev *rtwdev) +{ + if (rtw89_phy_read32_mask(rtwdev, R_DACK_S1P0, B_DACK_S1P0_OK) == 0 || + rtw89_phy_read32_mask(rtwdev, R_DACK_S1P1, B_DACK_S1P1_OK) == 0 || + rtw89_phy_read32_mask(rtwdev, R_DACK_S1P2, B_DACK_S1P2_OK) == 0 || + rtw89_phy_read32_mask(rtwdev, R_DACK_S1P3, B_DACK_S1P3_OK) == 0) + return false; + + return true; +} + +static void _dack_s1(struct rtw89_dev *rtwdev) +{ + struct rtw89_dack_info *dack = &rtwdev->dack; + bool done; + int ret; + + _txck_force(rtwdev, RF_PATH_B, true, DAC_160M); + + rtw89_phy_write32_mask(rtwdev, R_P1_DBGMOD, B_P1_DBGMOD_ON, 0x1); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, BIT(28), 0x1); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_EN1, 0x0); + udelay(100); + rtw89_phy_write32_mask(rtwdev, R_DACK1_K, B_DACK1_VAL, 0x30); + rtw89_phy_write32_mask(rtwdev, R_DACK2_K, B_DACK2_VAL, 0x30); + + _dack_reset(rtwdev, RF_PATH_B); + + rtw89_phy_write32_mask(rtwdev, R_DACK1_K, B_DACK1_EN, 0x1); + udelay(1); + + dack->msbk_timeout[1] = false; + + ret = read_poll_timeout_atomic(_dack_s1_poll, done, done, + 1, 10000, false, rtwdev); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 DACK timeout\n"); + dack->msbk_timeout[1] = true; + } + + rtw89_phy_write32_mask(rtwdev, R_DACK1_K, B_DACK1_EN, 0x0); + + _txck_force(rtwdev, RF_PATH_B, false, DAC_960M); + _dack_backup_s1(rtwdev); + _dack_reload(rtwdev, RF_PATH_B); + + rtw89_phy_write32_mask(rtwdev, R_P1_DBGMOD, B_P1_DBGMOD_ON, 0x0); +} + +static void _dack(struct rtw89_dev *rtwdev) +{ + _dack_s0(rtwdev); + _dack_s1(rtwdev); +} + +static void _dack_dump(struct rtw89_dev *rtwdev) +{ + struct rtw89_dack_info *dack = &rtwdev->dack; + u8 i; + u8 t; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DACK]S0 ADC_DCK ic = 0x%x, qc = 0x%x\n", + dack->addck_d[0][0], dack->addck_d[0][1]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DACK]S1 ADC_DCK ic = 0x%x, qc = 0x%x\n", + dack->addck_d[1][0], dack->addck_d[1][1]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DACK]S0 DAC_DCK ic = 0x%x, qc = 0x%x\n", + dack->dadck_d[0][0], dack->dadck_d[0][1]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DACK]S1 DAC_DCK ic = 0x%x, qc = 0x%x\n", + dack->dadck_d[1][0], dack->dadck_d[1][1]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DACK]S0 biask ic = 0x%x, qc = 0x%x\n", + dack->biask_d[0][0], dack->biask_d[0][1]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DACK]S1 biask ic = 0x%x, qc = 0x%x\n", + dack->biask_d[1][0], dack->biask_d[1][1]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK ic:\n"); + for (i = 0; i < 0x10; i++) { + t = dack->msbk_d[0][0][i]; + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n", t); + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK qc:\n"); + for (i = 0; i < RTW89_DACK_MSBK_NR; i++) { + t = dack->msbk_d[0][1][i]; + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n", t); + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 MSBK ic:\n"); + for (i = 0; i < RTW89_DACK_MSBK_NR; i++) { + t = dack->msbk_d[1][0][i]; + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n", t); + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 MSBK qc:\n"); + for (i = 0; i < RTW89_DACK_MSBK_NR; i++) { + t = dack->msbk_d[1][1][i]; + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n", t); + } +} + +static void _addck_ori(struct rtw89_dev *rtwdev) +{ + struct rtw89_dack_info *dack = &rtwdev->dack; + u32 val; + int ret; + + rtw89_phy_write32_mask(rtwdev, R_ADDCK0, B_ADDCK0_MAN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_ADDCK1, B_ADDCK1_MAN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x1); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_ADCCLK, 0x0); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_FLTRST, 0x0); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_FLTRST, 0x1); + + rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15_H, 0xf); + udelay(100); + + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PATH0_SAMPL_DLY_T_V1, BIT(4), 0x1); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15_H, 0x3); + rtw89_phy_write32_mask(rtwdev, R_ADDCK0, B_ADDCK0_TRG, 0x1); + rtw89_phy_write32_mask(rtwdev, R_ADDCK0, B_ADDCK0_TRG, 0x0); + udelay(1); + + rtw89_phy_write32_mask(rtwdev, R_ADDCK0, B_ADDCK0, 0x1); + dack->addck_timeout[0] = false; + + ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, val, val, + 1, 10000, false, + rtwdev, R_ADDCKR0, BIT(0)); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 ADDCK timeout\n"); + dack->addck_timeout[0] = true; + } + + rtw89_phy_write32_mask(rtwdev, R_PATH0_SAMPL_DLY_T_V1, BIT(4), 0x0); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15_H, 0xc); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_ADCCLK, 0x1); + + rtw89_phy_write32_mask(rtwdev, R_ADDCK0, B_ADDCK0, 0x0); + dack->addck_d[0][0] = + rtw89_phy_read32_mask(rtwdev, R_ADDCKR0, B_ADDCKR0_A0); + dack->addck_d[0][1] = + rtw89_phy_read32_mask(rtwdev, R_ADDCKR0, B_ADDCKR0_A1); + rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x0); + + rtw89_phy_write32_mask(rtwdev, R_P1_DBGMOD, B_P1_DBGMOD_ON, 0x1); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_ADCCLK, 0x0); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_FLTRST, 0x0); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_FLTRST, 0x1); + + rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15_H, 0xf); + udelay(100); + + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PATH1_SAMPL_DLY_T_V1, BIT(4), 0x1); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15_H, 0x3); + rtw89_phy_write32_mask(rtwdev, R_ADDCK1, B_ADDCK1_TRG, 0x1); + rtw89_phy_write32_mask(rtwdev, R_ADDCK1, B_ADDCK1_TRG, 0x0); + udelay(1); + + rtw89_phy_write32_mask(rtwdev, R_ADDCK1, B_ADDCK1, 0x1); + dack->addck_timeout[1] = false; + + ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, val, val, + 1, 10000, false, + rtwdev, R_ADDCKR1, BIT(0)); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 ADDCK timeout\n"); + dack->addck_timeout[1] = true; + } + + rtw89_phy_write32_mask(rtwdev, R_PATH1_SAMPL_DLY_T_V1, BIT(4), 0x0); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15_H, 0xc); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_ADCCLK, 0x1); + + rtw89_phy_write32_mask(rtwdev, R_ADDCK1, B_ADDCK1, 0x0); + dack->addck_d[1][0] = + rtw89_phy_read32_mask(rtwdev, R_ADDCKR1, B_ADDCKR1_A0); + dack->addck_d[1][1] = + rtw89_phy_read32_mask(rtwdev, R_ADDCKR1, B_ADDCKR1_A1); + + rtw89_phy_write32_mask(rtwdev, R_P1_DBGMOD, B_P1_DBGMOD_ON, 0x0); +} + +static void _addck_reload(struct rtw89_dev *rtwdev) +{ + struct rtw89_dack_info *dack = &rtwdev->dack; + + rtw89_phy_write32_mask(rtwdev, R_ADDCK0_RL, B_ADDCK0_RL1, dack->addck_d[0][0]); + rtw89_phy_write32_mask(rtwdev, R_ADDCK0_RL, B_ADDCK0_RL0, dack->addck_d[0][1]); + + rtw89_phy_write32_mask(rtwdev, R_ADDCK0_RL, B_ADDCK0_RLS, 0x3); + + rtw89_phy_write32_mask(rtwdev, R_ADDCK1_RL, B_ADDCK1_RL1, dack->addck_d[1][0]); + rtw89_phy_write32_mask(rtwdev, R_ADDCK1_RL, B_ADDCK1_RL0, dack->addck_d[1][1]); + + rtw89_phy_write32_mask(rtwdev, R_ADDCK1_RL, B_ADDCK1_RLS, 0x3); +} + +static void _dack_manual_off(struct rtw89_dev *rtwdev) +{ + rtw89_phy_write32_mask(rtwdev, R_ADDCK0_RL, B_ADDCK0_RLS, 0x0); + rtw89_phy_write32_mask(rtwdev, R_ADDCK1_RL, B_ADDCK1_RLS, 0x0); + + rtw89_phy_write32_mask(rtwdev, R_DACKN0_CTL, B_DACKN0_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_DACKN1_CTL, B_DACKN1_ON, 0x0); + rtw89_phy_write32_mask(rtwdev, R_DACKN2_CTL, B_DACKN2_ON, 0x0); + rtw89_phy_write32_mask(rtwdev, R_DACKN3_CTL, B_DACKN3_ON, 0x0); +} + +static void _dac_cal(struct rtw89_dev *rtwdev, bool force) +{ + struct rtw89_dack_info *dack = &rtwdev->dack; + + dack->dack_done = false; + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]DACK start!!!\n"); + + _drck(rtwdev); + _dack_manual_off(rtwdev); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, RFREG_MASK, 0x0); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_RSV1, RFREG_MASK, 0x0); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RFREG_MASK, 0x337e1); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_MOD, RFREG_MASK, 0x337e1); + _rxck_force(rtwdev, RF_PATH_A, true, ADC_960M); + _rxck_force(rtwdev, RF_PATH_B, true, ADC_960M); + _addck_ori(rtwdev); + + _rxck_force(rtwdev, RF_PATH_A, false, ADC_960M); + _rxck_force(rtwdev, RF_PATH_B, false, ADC_960M); + _addck_reload(rtwdev); + + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MODOPT, RFREG_MASK, 0x0); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_MODOPT, RFREG_MASK, 0x0); + + _dack(rtwdev); + _dack_dump(rtwdev); + dack->dack_done = true; + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, RFREG_MASK, 0x1); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_RSV1, RFREG_MASK, 0x1); + + dack->dack_cnt++; + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]DACK finish!!!\n"); +} + static bool _iqk_check_cal(struct rtw89_dev *rtwdev, u8 path, u8 ktype) { bool notready = false; @@ -3312,6 +3790,15 @@ void rtw8852bt_dpk_init(struct rtw89_dev *rtwdev) _set_dpd_backoff(rtwdev, RTW89_PHY_0); } +void rtw8852bt_dack(struct rtw89_dev *rtwdev) +{ + u8 phy_map = rtw89_btc_phymap(rtwdev, RTW89_PHY_0, 0); + + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_DACK, BTC_WRFK_START); + _dac_cal(rtwdev, false); + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_DACK, BTC_WRFK_STOP); +} + void rtw8852bt_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { u8 phy_map = rtw89_btc_phymap(rtwdev, phy_idx, 0); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h index 3ac63a2a63f7..772a5b099377 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h @@ -7,6 +7,7 @@ #include "core.h" +void rtw8852bt_dack(struct rtw89_dev *rtwdev); void rtw8852bt_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); void rtw8852bt_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); void rtw8852bt_dpk_init(struct rtw89_dev *rtwdev); From 746f4ae52a38459dbed792adb58cadaed370dcc2 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 27 Jun 2024 10:58:49 +0800 Subject: [PATCH 070/204] wifi: rtw89: 8852bt: rfk: add RCK RCK is synchronize RC calibration. Driver triggers this calibration and writes the result to registers. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240627025849.25198-5-pkshih@realtek.com --- .../wireless/realtek/rtw89/rtw8852bt_rfk.c | 43 +++++++++++++++++++ .../wireless/realtek/rtw89/rtw8852bt_rfk.h | 1 + 2 files changed, 44 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c index 6c2fecb58940..fa0e49d58112 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c @@ -407,6 +407,41 @@ static void _rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) } } +static void _rck(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) +{ + u32 rf_reg5; + u32 rck_val; + u32 val; + int ret; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RCK] ====== S%d RCK ======\n", path); + + rf_reg5 = rtw89_read_rf(rtwdev, path, RR_RSV1, RFREG_MASK); + + rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x0); + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_MASK, RR_MOD_V_RX); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RCK] RF0x00 = 0x%05x\n", + rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASK)); + + /* RCK trigger */ + rtw89_write_rf(rtwdev, path, RR_RCKC, RFREG_MASK, 0x00240); + + ret = read_poll_timeout_atomic(rtw89_read_rf, val, val, 2, 30, + false, rtwdev, path, RR_RCKS, BIT(3)); + + rck_val = rtw89_read_rf(rtwdev, path, RR_RCKC, RR_RCKC_CA); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RCK] rck_val = 0x%x, ret = %d\n", + rck_val, ret); + + rtw89_write_rf(rtwdev, path, RR_RCKC, RFREG_MASK, rck_val); + rtw89_write_rf(rtwdev, path, RR_RSV1, RFREG_MASK, rf_reg5); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RCK] RF 0x1b = 0x%x\n", + rtw89_read_rf(rtwdev, path, RR_RCKC, RFREG_MASK)); +} + static void _drck(struct rtw89_dev *rtwdev) { u32 rck_d; @@ -3790,6 +3825,14 @@ void rtw8852bt_dpk_init(struct rtw89_dev *rtwdev) _set_dpd_backoff(rtwdev, RTW89_PHY_0); } +void rtw8852bt_rck(struct rtw89_dev *rtwdev) +{ + u8 path; + + for (path = 0; path < RF_PATH_NUM_8852BT; path++) + _rck(rtwdev, path); +} + void rtw8852bt_dack(struct rtw89_dev *rtwdev) { u8 phy_map = rtw89_btc_phymap(rtwdev, RTW89_PHY_0, 0); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h index 772a5b099377..09918835c6e8 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h @@ -7,6 +7,7 @@ #include "core.h" +void rtw8852bt_rck(struct rtw89_dev *rtwdev); void rtw8852bt_dack(struct rtw89_dev *rtwdev); void rtw8852bt_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); void rtw8852bt_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); From 4278d88fedcfde1b91a5cfa96acb0e06d7742e12 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 2 Jul 2024 13:00:00 +0200 Subject: [PATCH 071/204] wifi: iwlwifi: mvm: fix interface combinations The NAN code referenced in this commit isn't actually present in the driver (any more), and the commit didn't add the extra NAN entry. Thus, the -1 is incorrect. Reported-by: Alexander Wetzel Closes: https://lore.kernel.org/20240702104128.26394-1-Alexander@wetzel-home.de Fixes: 5c38bedac16a ("wifi: iwlwifi: mvm: unify and fix interface combinations") Link: https://patch.msgid.link/20240702130001.8c871a3f0b5a.I08a6542f52f63c5bd66bf3feb09e1998ce7c60e5@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 60bfe42d5386..e40f993b17fd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -59,13 +59,13 @@ static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = { .num_different_channels = 2, .max_interfaces = 3, .limits = iwl_mvm_limits, - .n_limits = ARRAY_SIZE(iwl_mvm_limits) - 1, + .n_limits = ARRAY_SIZE(iwl_mvm_limits), }, { .num_different_channels = 1, .max_interfaces = 3, .limits = iwl_mvm_limits_ap, - .n_limits = ARRAY_SIZE(iwl_mvm_limits_ap) - 1, + .n_limits = ARRAY_SIZE(iwl_mvm_limits_ap), }, }; From 187accaa328dc4de98064eef176841b8a4716f96 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 3 Jul 2024 06:43:17 +0300 Subject: [PATCH 072/204] wifi: iwlwifi: mvm: don't send an ROC command with max_delay = 0 The firmware can't handle that (it will crash with ASSERT 300A). This happened because we looked at vif->bss_conf which is not the right bss_conf to look at in case of an MLD connection. Fix iwl_mvm_roc_duration_and_delay to iterate on the active links to get the right value for the dtim_interval. Signed-off-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Reviewed-by: Johannes Berg Link: https://patch.msgid.link/20240703064027.e12f8d84c8fd.I3dd9f720c678c06ec7a5bf7ca56e21cf0b614c8c@changeid Signed-off-by: Johannes Berg --- .../net/wireless/intel/iwlwifi/mvm/time-event.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 77b0cae8566f..a8c42ce3b630 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -1057,12 +1057,21 @@ void iwl_mvm_roc_duration_and_delay(struct ieee80211_vif *vif, u32 *duration_tu, u32 *delay) { - u32 dtim_interval = vif->bss_conf.dtim_period * - vif->bss_conf.beacon_int; + struct ieee80211_bss_conf *link_conf; + unsigned int link_id; + u32 dtim_interval = 0; *delay = AUX_ROC_MIN_DELAY; *duration_tu = MSEC_TO_TU(duration_ms); + rcu_read_lock(); + for_each_vif_active_link(vif, link_conf, link_id) { + dtim_interval = + max_t(u32, dtim_interval, + link_conf->dtim_period * link_conf->beacon_int); + } + rcu_read_unlock(); + /* * If we are associated we want the delay time to be at least one * dtim interval so that the FW can wait until after the DTIM and @@ -1071,8 +1080,10 @@ void iwl_mvm_roc_duration_and_delay(struct ieee80211_vif *vif, * Since we want to use almost a whole dtim interval we would also * like the delay to be for 2-3 dtim intervals, in case there are * other time events with higher priority. + * dtim_interval should never be 0, it can be 1 if we don't know it + * (we haven't heard any beacon yet). */ - if (vif->cfg.assoc) { + if (vif->cfg.assoc && !WARN_ON(!dtim_interval)) { *delay = min_t(u32, dtim_interval * 3, AUX_ROC_MAX_DELAY); /* We cannot remain off-channel longer than the DTIM interval */ if (dtim_interval <= *duration_tu) { From eb801f4fabdf877d38c4746333e3454c4e7603cc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 Jul 2024 12:58:49 +0300 Subject: [PATCH 073/204] wifi: iwlwifi: mvm: clean up reorder buffer data We really don't need to maintain the buffer size per queue buffer, it's the same for the whole BA session. Also, we no longer use the mvm pointer inside each queue's data structure. Clean that up. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20240703125541.64ea1ba75379.I2a25af040061efaf82379e96a84a76c5fb65c677@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 6 ++---- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 6 +++--- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 11 +++++------ 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 393ce424c196..227463522b7c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -739,24 +739,20 @@ struct iwl_mvm_tcm { * struct iwl_mvm_reorder_buffer - per ra/tid/queue reorder buffer * @head_sn: reorder window head sn * @num_stored: number of mpdus stored in the buffer - * @buf_size: the reorder buffer size as set by the last addba request * @queue: queue of this reorder buffer * @last_amsdu: track last ASMDU SN for duplication detection * @last_sub_index: track ASMDU sub frame index for duplication detection * @valid: reordering is valid for this queue * @lock: protect reorder buffer internal state - * @mvm: mvm pointer, needed for frame timer context */ struct iwl_mvm_reorder_buffer { u16 head_sn; u16 num_stored; - u16 buf_size; int queue; u16 last_amsdu; u8 last_sub_index; bool valid; spinlock_t lock; - struct iwl_mvm *mvm; } ____cacheline_aligned_in_smp; /** @@ -778,6 +774,7 @@ __aligned(roundup_pow_of_two(sizeof(struct sk_buff_head))) * @tid: tid of the session * @baid: baid of the session * @timeout: the timeout set in the addba request + * @buf_size: the reorder buffer size as set by the last addba request * @entries_per_queue: # of buffers per queue, this actually gets * aligned up to avoid cache line sharing between queues * @last_rx: last rx jiffies, updated only if timeout passed from last update @@ -794,6 +791,7 @@ struct iwl_mvm_baid_data { u8 tid; u8 baid; u16 timeout; + u16 buf_size; u16 entries_per_queue; unsigned long last_rx; struct timer_list session_timer; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 5370580f6210..1a210d0c22b3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -566,7 +566,7 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm, lockdep_assert_held(&reorder_buf->lock); while (ieee80211_sn_less(ssn, nssn)) { - int index = ssn % reorder_buf->buf_size; + int index = ssn % baid_data->buf_size; struct sk_buff_head *skb_list = &entries[index].frames; struct sk_buff *skb; @@ -617,7 +617,7 @@ static void iwl_mvm_del_ba(struct iwl_mvm *mvm, int queue, spin_lock_bh(&reorder_buf->lock); iwl_mvm_release_frames(mvm, sta, NULL, ba_data, reorder_buf, ieee80211_sn_add(reorder_buf->head_sn, - reorder_buf->buf_size)); + ba_data->buf_size)); spin_unlock_bh(&reorder_buf->lock); out: @@ -839,7 +839,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, } /* put in reorder buffer */ - index = sn % buffer->buf_size; + index = sn % baid_data->buf_size; __skb_queue_tail(&entries[index].frames, skb); buffer->num_stored++; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index c57755e5ff5e..15e64d94d6ea 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2743,7 +2743,7 @@ static void iwl_mvm_free_reorder(struct iwl_mvm *mvm, */ WARN_ON(1); - for (j = 0; j < reorder_buf->buf_size; j++) + for (j = 0; j < data->buf_size; j++) __skb_queue_purge(&entries[j].frames); spin_unlock_bh(&reorder_buf->lock); @@ -2752,7 +2752,7 @@ static void iwl_mvm_free_reorder(struct iwl_mvm *mvm, static void iwl_mvm_init_reorder_buffer(struct iwl_mvm *mvm, struct iwl_mvm_baid_data *data, - u16 ssn, u16 buf_size) + u16 ssn) { int i; @@ -2765,12 +2765,10 @@ static void iwl_mvm_init_reorder_buffer(struct iwl_mvm *mvm, reorder_buf->num_stored = 0; reorder_buf->head_sn = ssn; - reorder_buf->buf_size = buf_size; spin_lock_init(&reorder_buf->lock); - reorder_buf->mvm = mvm; reorder_buf->queue = i; reorder_buf->valid = false; - for (j = 0; j < reorder_buf->buf_size; j++) + for (j = 0; j < data->buf_size; j++) __skb_queue_head_init(&entries[j].frames); } } @@ -2979,13 +2977,14 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, baid_data->mvm = mvm; baid_data->tid = tid; baid_data->sta_mask = iwl_mvm_sta_fw_id_mask(mvm, sta, -1); + baid_data->buf_size = buf_size; mvm_sta->tid_to_baid[tid] = baid; if (timeout) mod_timer(&baid_data->session_timer, TU_TO_EXP_TIME(timeout * 2)); - iwl_mvm_init_reorder_buffer(mvm, baid_data, ssn, buf_size); + iwl_mvm_init_reorder_buffer(mvm, baid_data, ssn); /* * protect the BA data with RCU to cover a case where our * internal RX sync mechanism will timeout (not that it's From d81bf4b63006330d1f70a59414eae61e1a60e677 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 Jul 2024 12:58:50 +0300 Subject: [PATCH 074/204] wifi: iwlwifi: mvm: align reorder buffer entries to cacheline The entries[] array needs to be cacheline aligned to avoid false sharing between different queues, each queue has a set of entries in it that it writes to. While it is aligned in practice today given that each array entry before it is aligned, it's still clearer to explicitly require it to be aligned, so add the annotation for that. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20240703125541.3bc7a55ac867.Id3c1df6d40e92c3de9caededcbc32d0e57e4423d@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 227463522b7c..056fdc42e253 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -798,7 +798,7 @@ struct iwl_mvm_baid_data { struct iwl_mvm_baid_data __rcu **rcu_ptr; struct iwl_mvm *mvm; struct iwl_mvm_reorder_buffer reorder_buf[IWL_MAX_RX_HW_QUEUES]; - struct iwl_mvm_reorder_buf_entry entries[]; + struct iwl_mvm_reorder_buf_entry entries[] ____cacheline_aligned_in_smp; }; static inline struct iwl_mvm_baid_data * From f27579ff8b9344226db63a902dc9e9cbddf07b74 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 Jul 2024 12:58:51 +0300 Subject: [PATCH 075/204] wifi: iwlwifi: mvm: simplify EMLSR blocking If EMLSR is already blocked for the same reason that it's blocked for again, there's no need to actually do any work, so exit early from the function. Also, print the state after modifying it, so it's clearer. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20240703125541.6995464f0bac.Iac9fe3546ca0a0d6bc6666c822a667ab257419a9@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/link.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index 73527781f89a..4e702e7a4b82 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -1033,15 +1033,17 @@ void iwl_mvm_block_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (WARN_ON(!(reason & IWL_MVM_BLOCK_ESR_REASONS))) return; - if (!(mvmvif->esr_disable_reason & reason)) { - IWL_DEBUG_INFO(mvm, - "Blocking EMLSR mode. reason = %s (0x%x)\n", - iwl_get_esr_state_string(reason), reason); - iwl_mvm_print_esr_state(mvm, mvmvif->esr_disable_reason); - } + if (mvmvif->esr_disable_reason & reason) + return; + + IWL_DEBUG_INFO(mvm, + "Blocking EMLSR mode. reason = %s (0x%x)\n", + iwl_get_esr_state_string(reason), reason); mvmvif->esr_disable_reason |= reason; + iwl_mvm_print_esr_state(mvm, mvmvif->esr_disable_reason); + iwl_mvm_exit_esr(mvm, vif, reason, link_to_keep); } From d023a228e927c142c5c418dae346f63d1c8ba105 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 3 Jul 2024 12:58:52 +0300 Subject: [PATCH 076/204] wifi: iwlwifi: return a new allocation for hdr page space Instead of returning the pointer to the structure describing the header page, return the pointer to the newly allocated area. This disentangles the user from the allocation within the page as it does not need to advance the position itself. Signed-off-by: Benjamin Berg Signed-off-by: Miri Korenblit Reviewed-by: Johannes Berg Link: https://patch.msgid.link/20240703125541.044f2cb373f1.I52a807ac6f311b89530e18deacc7452638a6f5d8@changeid Signed-off-by: Johannes Berg --- .../wireless/intel/iwlwifi/pcie/internal.h | 4 +- .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 35 ++++++------- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 50 ++++++++++--------- 3 files changed, 44 insertions(+), 45 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index f2bb34270ccf..754928062921 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -623,8 +623,8 @@ void iwl_trans_pcie_tx_reset(struct iwl_trans *trans); int iwl_pcie_txq_alloc(struct iwl_trans *trans, struct iwl_txq *txq, int slots_num, bool cmd_queue); -struct iwl_tso_hdr_page *iwl_pcie_get_page_hdr(struct iwl_trans *trans, - size_t len, struct sk_buff *skb); +void *iwl_pcie_get_page_hdr(struct iwl_trans *trans, size_t len, + struct sk_buff *skb); void iwl_pcie_free_tso_page(struct iwl_trans *trans, struct sk_buff *skb); static inline dma_addr_t diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index b897de1b9226..543efb52b084 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -130,7 +130,6 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans, unsigned int mss = skb_shinfo(skb)->gso_size; u16 length, amsdu_pad; u8 *start_hdr; - struct iwl_tso_hdr_page *hdr_page; struct tso_t tso; trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd), @@ -146,12 +145,10 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans, (3 + snap_ip_tcp_hdrlen + sizeof(struct ethhdr)); /* Our device supports 9 segments at most, it will fit in 1 page */ - hdr_page = iwl_pcie_get_page_hdr(trans, hdr_room, skb); - if (!hdr_page) + start_hdr = iwl_pcie_get_page_hdr(trans, hdr_room, skb); + if (!start_hdr) return -ENOMEM; - start_hdr = hdr_page->pos; - /* * Pull the ieee80211 header to be able to use TSO core, * we will restore it for the tx_status flow. @@ -172,32 +169,32 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans, unsigned int data_left = min_t(unsigned int, mss, total_len); unsigned int tb_len; dma_addr_t tb_phys; - u8 *subf_hdrs_start = hdr_page->pos; + u8 *pos_hdr = start_hdr; total_len -= data_left; - memset(hdr_page->pos, 0, amsdu_pad); - hdr_page->pos += amsdu_pad; + memset(pos_hdr, 0, amsdu_pad); + pos_hdr += amsdu_pad; amsdu_pad = (4 - (sizeof(struct ethhdr) + snap_ip_tcp_hdrlen + data_left)) & 0x3; - ether_addr_copy(hdr_page->pos, ieee80211_get_DA(hdr)); - hdr_page->pos += ETH_ALEN; - ether_addr_copy(hdr_page->pos, ieee80211_get_SA(hdr)); - hdr_page->pos += ETH_ALEN; + ether_addr_copy(pos_hdr, ieee80211_get_DA(hdr)); + pos_hdr += ETH_ALEN; + ether_addr_copy(pos_hdr, ieee80211_get_SA(hdr)); + pos_hdr += ETH_ALEN; length = snap_ip_tcp_hdrlen + data_left; - *((__be16 *)hdr_page->pos) = cpu_to_be16(length); - hdr_page->pos += sizeof(length); + *((__be16 *)pos_hdr) = cpu_to_be16(length); + pos_hdr += sizeof(length); /* * This will copy the SNAP as well which will be considered * as MAC header. */ - tso_build_hdr(skb, hdr_page->pos, &tso, data_left, !total_len); + tso_build_hdr(skb, pos_hdr, &tso, data_left, !total_len); - hdr_page->pos += snap_ip_tcp_hdrlen; + pos_hdr += snap_ip_tcp_hdrlen; - tb_len = hdr_page->pos - start_hdr; + tb_len = pos_hdr - start_hdr; tb_phys = dma_map_single(trans->dev, start_hdr, tb_len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(trans->dev, tb_phys))) @@ -211,10 +208,10 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans, trace_iwlwifi_dev_tx_tb(trans->dev, skb, start_hdr, tb_phys, tb_len); /* add this subframe's headers' length to the tx_cmd */ - le16_add_cpu(&tx_cmd->len, hdr_page->pos - subf_hdrs_start); + le16_add_cpu(&tx_cmd->len, tb_len); /* prepare the start_hdr for the next subframe */ - start_hdr = hdr_page->pos; + start_hdr = pos_hdr; /* put the payload */ while (data_left) { diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index f4452732417d..d67ad40634f9 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1702,12 +1702,13 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, } #ifdef CONFIG_INET -struct iwl_tso_hdr_page *iwl_pcie_get_page_hdr(struct iwl_trans *trans, - size_t len, struct sk_buff *skb) +void *iwl_pcie_get_page_hdr(struct iwl_trans *trans, + size_t len, struct sk_buff *skb) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_tso_hdr_page *p = this_cpu_ptr(trans_pcie->txqs.tso_hdr_page); struct page **page_ptr; + void *ret; page_ptr = (void *)((u8 *)skb->cb + trans_pcie->txqs.page_offs); @@ -1744,7 +1745,10 @@ struct iwl_tso_hdr_page *iwl_pcie_get_page_hdr(struct iwl_trans *trans, out: *page_ptr = p->page; get_page(p->page); - return p; + ret = p->pos; + p->pos += len; + + return ret; } static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, @@ -1759,8 +1763,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room; unsigned int mss = skb_shinfo(skb)->gso_size; u16 length, iv_len, amsdu_pad; - u8 *start_hdr; - struct iwl_tso_hdr_page *hdr_page; + u8 *start_hdr, *pos_hdr; struct tso_t tso; /* if the packet is protected, then it must be CCMP or GCMP */ @@ -1783,13 +1786,12 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, (3 + snap_ip_tcp_hdrlen + sizeof(struct ethhdr)) + iv_len; /* Our device supports 9 segments at most, it will fit in 1 page */ - hdr_page = iwl_pcie_get_page_hdr(trans, hdr_room, skb); - if (!hdr_page) + pos_hdr = start_hdr = iwl_pcie_get_page_hdr(trans, hdr_room, skb); + if (!start_hdr) return -ENOMEM; - start_hdr = hdr_page->pos; - memcpy(hdr_page->pos, skb->data + hdr_len, iv_len); - hdr_page->pos += iv_len; + memcpy(pos_hdr, skb->data + hdr_len, iv_len); + pos_hdr += iv_len; /* * Pull the ieee80211 header + IV to be able to use TSO core, @@ -1812,32 +1814,32 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, min_t(unsigned int, mss, total_len); unsigned int hdr_tb_len; dma_addr_t hdr_tb_phys; - u8 *subf_hdrs_start = hdr_page->pos; + u8 *subf_hdrs_start = pos_hdr; total_len -= data_left; - memset(hdr_page->pos, 0, amsdu_pad); - hdr_page->pos += amsdu_pad; + memset(pos_hdr, 0, amsdu_pad); + pos_hdr += amsdu_pad; amsdu_pad = (4 - (sizeof(struct ethhdr) + snap_ip_tcp_hdrlen + data_left)) & 0x3; - ether_addr_copy(hdr_page->pos, ieee80211_get_DA(hdr)); - hdr_page->pos += ETH_ALEN; - ether_addr_copy(hdr_page->pos, ieee80211_get_SA(hdr)); - hdr_page->pos += ETH_ALEN; + ether_addr_copy(pos_hdr, ieee80211_get_DA(hdr)); + pos_hdr += ETH_ALEN; + ether_addr_copy(pos_hdr, ieee80211_get_SA(hdr)); + pos_hdr += ETH_ALEN; length = snap_ip_tcp_hdrlen + data_left; - *((__be16 *)hdr_page->pos) = cpu_to_be16(length); - hdr_page->pos += sizeof(length); + *((__be16 *)pos_hdr) = cpu_to_be16(length); + pos_hdr += sizeof(length); /* * This will copy the SNAP as well which will be considered * as MAC header. */ - tso_build_hdr(skb, hdr_page->pos, &tso, data_left, !total_len); + tso_build_hdr(skb, pos_hdr, &tso, data_left, !total_len); - hdr_page->pos += snap_ip_tcp_hdrlen; + pos_hdr += snap_ip_tcp_hdrlen; - hdr_tb_len = hdr_page->pos - start_hdr; + hdr_tb_len = pos_hdr - start_hdr; hdr_tb_phys = dma_map_single(trans->dev, start_hdr, hdr_tb_len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(trans->dev, hdr_tb_phys))) @@ -1847,10 +1849,10 @@ 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, hdr_page->pos - subf_hdrs_start); + le16_add_cpu(&tx_cmd->len, pos_hdr - subf_hdrs_start); /* prepare the start_hdr for the next subframe */ - start_hdr = hdr_page->pos; + start_hdr = pos_hdr; /* put the payload */ while (data_left) { From 7f5e3038f02902a1409c9ad0f07e3b11c581c113 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 3 Jul 2024 12:58:53 +0300 Subject: [PATCH 077/204] wifi: iwlwifi: map entire SKB when sending AMSDUs This adds logic to map the entire SKB for AMSDUs. The required scatter gather list is allocated together with the space for TSO headers. Unmapping happens again when free'ing the TSO header page. For now the mapping is unused, this will be changed in a later commit. Signed-off-by: Benjamin Berg Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20240703125541.96c6006f40ff.I55b74bc97c4026761397a7513a559c88a10b6489@changeid Signed-off-by: Johannes Berg --- .../net/wireless/intel/iwlwifi/iwl-trans.h | 5 +- .../wireless/intel/iwlwifi/pcie/internal.h | 10 +- .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 20 +-- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 114 ++++++++++++++++-- 4 files changed, 128 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index ecf94ec2c2b0..015f02122df6 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -120,6 +120,7 @@ enum CMD_MODE { CMD_BLOCK_TXQS = BIT(3), CMD_SEND_IN_D3 = BIT(4), }; +#define CMD_MODE_BITS 5 #define DEF_CMD_PAYLOAD_SIZE 320 @@ -712,7 +713,9 @@ struct iwl_dma_ptr { struct iwl_cmd_meta { /* only for SYNC commands, iff the reply skb is wanted */ struct iwl_host_cmd *source; - u32 flags; + u32 flags: CMD_MODE_BITS; + /* sg_offset is valid if it is non-zero */ + u32 sg_offset: PAGE_SHIFT; u32 tbs; }; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 754928062921..d63c1c284f70 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -623,9 +623,13 @@ void iwl_trans_pcie_tx_reset(struct iwl_trans *trans); int iwl_pcie_txq_alloc(struct iwl_trans *trans, struct iwl_txq *txq, int slots_num, bool cmd_queue); -void *iwl_pcie_get_page_hdr(struct iwl_trans *trans, size_t len, - struct sk_buff *skb); -void iwl_pcie_free_tso_page(struct iwl_trans *trans, struct sk_buff *skb); +dma_addr_t iwl_pcie_get_sgt_tb_phys(struct sg_table *sgt, void *addr); +struct sg_table *iwl_pcie_prep_tso(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_cmd_meta *cmd_meta, + u8 **hdr, unsigned int hdr_room); + +void iwl_pcie_free_tso_page(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_cmd_meta *cmd_meta); static inline dma_addr_t iwl_txq_get_first_tb_dma(struct iwl_txq *txq, int idx) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 543efb52b084..3dcce6a8da50 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -119,7 +119,9 @@ static int iwl_txq_gen2_set_tb_with_wa(struct iwl_trans *trans, static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans, struct sk_buff *skb, - struct iwl_tfh_tfd *tfd, int start_len, + struct iwl_tfh_tfd *tfd, + struct iwl_cmd_meta *out_meta, + int start_len, u8 hdr_len, struct iwl_device_tx_cmd *dev_cmd) { @@ -130,6 +132,7 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans, unsigned int mss = skb_shinfo(skb)->gso_size; u16 length, amsdu_pad; u8 *start_hdr; + struct sg_table *sgt; struct tso_t tso; trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd), @@ -145,8 +148,8 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans, (3 + snap_ip_tcp_hdrlen + sizeof(struct ethhdr)); /* Our device supports 9 segments at most, it will fit in 1 page */ - start_hdr = iwl_pcie_get_page_hdr(trans, hdr_room, skb); - if (!start_hdr) + sgt = iwl_pcie_prep_tso(trans, skb, out_meta, &start_hdr, hdr_room); + if (!sgt) return -ENOMEM; /* @@ -287,8 +290,8 @@ iwl_tfh_tfd *iwl_txq_gen2_build_tx_amsdu(struct iwl_trans *trans, */ iwl_txq_gen2_set_tb(trans, tfd, tb_phys, len); - if (iwl_txq_gen2_build_amsdu(trans, skb, tfd, len + IWL_FIRST_TB_SIZE, - hdr_len, dev_cmd)) + if (iwl_txq_gen2_build_amsdu(trans, skb, tfd, out_meta, + len + IWL_FIRST_TB_SIZE, hdr_len, dev_cmd)) goto out_err; /* building the A-MSDU might have changed this data, memcpy it now */ @@ -719,7 +722,7 @@ int iwl_txq_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, /* Set up first empty entry in queue's array of Tx/cmd buffers */ out_meta = &txq->entries[idx].meta; - out_meta->flags = 0; + memset(out_meta, 0, sizeof(*out_meta)); tfd = iwl_txq_gen2_build_tfd(trans, txq, dev_cmd, skb, out_meta); if (!tfd) { @@ -775,10 +778,11 @@ static void iwl_txq_gen2_unmap(struct iwl_trans *trans, int txq_id) if (txq_id != trans_pcie->txqs.cmd.q_id) { int idx = iwl_txq_get_cmd_index(txq, txq->read_ptr); + struct iwl_cmd_meta *cmd_meta = &txq->entries[idx].meta; struct sk_buff *skb = txq->entries[idx].skb; if (!WARN_ON_ONCE(!skb)) - iwl_pcie_free_tso_page(trans, skb); + iwl_pcie_free_tso_page(trans, skb, cmd_meta); } iwl_txq_gen2_free_tfd(trans, txq); txq->read_ptr = iwl_txq_inc_wrap(trans, txq->read_ptr); @@ -1247,7 +1251,7 @@ int iwl_pcie_gen2_enqueue_hcmd(struct iwl_trans *trans, out_cmd = txq->entries[idx].cmd; out_meta = &txq->entries[idx].meta; - /* re-initialize to NULL */ + /* re-initialize, this also marks the SG list as unused */ memset(out_meta, 0, sizeof(*out_meta)); if (cmd->flags & CMD_WANT_SKB) out_meta->source = cmd; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index d67ad40634f9..ac545a39ad2a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -209,7 +209,8 @@ static void iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans) spin_unlock(&trans_pcie->reg_lock); } -void iwl_pcie_free_tso_page(struct iwl_trans *trans, struct sk_buff *skb) +void iwl_pcie_free_tso_page(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_cmd_meta *cmd_meta) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct page **page_ptr; @@ -224,6 +225,17 @@ void iwl_pcie_free_tso_page(struct iwl_trans *trans, struct sk_buff *skb) next = *(void **)((u8 *)page_address(next) + PAGE_SIZE - sizeof(void *)); + + /* Unmap the scatter gather list that is on the last page */ + if (!next && cmd_meta->sg_offset) { + struct sg_table *sgt; + + sgt = (void *)((u8 *)page_address(tmp) + + cmd_meta->sg_offset); + + dma_unmap_sgtable(trans->dev, sgt, DMA_TO_DEVICE, 0); + } + __free_page(tmp); } } @@ -363,11 +375,13 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id) if (txq_id != trans_pcie->txqs.cmd.q_id) { struct sk_buff *skb = txq->entries[txq->read_ptr].skb; + struct iwl_cmd_meta *cmd_meta = + &txq->entries[txq->read_ptr].meta; if (WARN_ON_ONCE(!skb)) continue; - iwl_pcie_free_tso_page(trans, skb); + iwl_pcie_free_tso_page(trans, skb, cmd_meta); } iwl_txq_free_tfd(trans, txq); txq->read_ptr = iwl_txq_inc_wrap(trans, txq->read_ptr); @@ -1420,7 +1434,8 @@ int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, out_cmd = txq->entries[idx].cmd; out_meta = &txq->entries[idx].meta; - memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */ + /* re-initialize, this also marks the SG list as unused */ + memset(out_meta, 0, sizeof(*out_meta)); if (cmd->flags & CMD_WANT_SKB) out_meta->source = cmd; @@ -1702,8 +1717,8 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, } #ifdef CONFIG_INET -void *iwl_pcie_get_page_hdr(struct iwl_trans *trans, - size_t len, struct sk_buff *skb) +static void *iwl_pcie_get_page_hdr(struct iwl_trans *trans, + size_t len, struct sk_buff *skb) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_tso_hdr_page *p = this_cpu_ptr(trans_pcie->txqs.tso_hdr_page); @@ -1751,6 +1766,84 @@ void *iwl_pcie_get_page_hdr(struct iwl_trans *trans, return ret; } +/** + * iwl_pcie_get_sgt_tb_phys - Find TB address in mapped SG list + * @sgt: scatter gather table + * @addr: Virtual address + * + * Find the entry that includes the address for the given address and return + * correct physical address for the TB entry. + * + * Returns: Address for TB entry + */ +dma_addr_t iwl_pcie_get_sgt_tb_phys(struct sg_table *sgt, void *addr) +{ + struct scatterlist *sg; + int i; + + for_each_sgtable_dma_sg(sgt, sg, i) { + if (addr >= sg_virt(sg) && + (u8 *)addr < (u8 *)sg_virt(sg) + sg_dma_len(sg)) + return sg_dma_address(sg) + + ((unsigned long)addr - (unsigned long)sg_virt(sg)); + } + + WARN_ON_ONCE(1); + + return DMA_MAPPING_ERROR; +} + +/** + * iwl_pcie_prep_tso - Prepare TSO page and SKB for sending + * @trans: transport private data + * @skb: the SKB to map + * @cmd_meta: command meta to store the scatter list information for unmapping + * @hdr: output argument for TSO headers + * @hdr_room: requested length for TSO headers + * + * Allocate space for a scatter gather list and TSO headers and map the SKB + * using the scatter gather list. The SKB is unmapped again when the page is + * free'ed again at the end of the operation. + * + * Returns: newly allocated and mapped scatter gather table with list + */ +struct sg_table *iwl_pcie_prep_tso(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_cmd_meta *cmd_meta, + u8 **hdr, unsigned int hdr_room) +{ + struct sg_table *sgt; + + if (WARN_ON_ONCE(skb_has_frag_list(skb))) + return NULL; + + *hdr = iwl_pcie_get_page_hdr(trans, + hdr_room + __alignof__(struct sg_table) + + sizeof(struct sg_table) + + (skb_shinfo(skb)->nr_frags + 1) * + sizeof(struct scatterlist), + skb); + if (!*hdr) + return NULL; + + sgt = (void *)PTR_ALIGN(*hdr + hdr_room, __alignof__(struct sg_table)); + sgt->sgl = (void *)(sgt + 1); + + sg_init_table(sgt->sgl, skb_shinfo(skb)->nr_frags + 1); + + sgt->orig_nents = skb_to_sgvec(skb, sgt->sgl, 0, skb->len); + if (WARN_ON_ONCE(sgt->orig_nents <= 0)) + return NULL; + + /* And map the entire SKB */ + if (dma_map_sgtable(trans->dev, sgt, DMA_TO_DEVICE, 0) < 0) + return NULL; + + /* Store non-zero (i.e. valid) offset for unmapping */ + cmd_meta->sg_offset = (unsigned long) sgt & ~PAGE_MASK; + + return sgt; +} + static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_txq *txq, u8 hdr_len, struct iwl_cmd_meta *out_meta, @@ -1764,6 +1857,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, unsigned int mss = skb_shinfo(skb)->gso_size; u16 length, iv_len, amsdu_pad; u8 *start_hdr, *pos_hdr; + struct sg_table *sgt; struct tso_t tso; /* if the packet is protected, then it must be CCMP or GCMP */ @@ -1786,10 +1880,11 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, (3 + snap_ip_tcp_hdrlen + sizeof(struct ethhdr)) + iv_len; /* Our device supports 9 segments at most, it will fit in 1 page */ - pos_hdr = start_hdr = iwl_pcie_get_page_hdr(trans, hdr_room, skb); - if (!start_hdr) + sgt = iwl_pcie_prep_tso(trans, skb, out_meta, &start_hdr, hdr_room); + if (!sgt) return -ENOMEM; + pos_hdr = start_hdr; memcpy(pos_hdr, skb->data + hdr_len, iv_len); pos_hdr += iv_len; @@ -2029,7 +2124,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, /* Set up first empty entry in queue's array of Tx/cmd buffers */ out_meta = &txq->entries[txq->write_ptr].meta; - out_meta->flags = 0; + memset(out_meta, 0, sizeof(*out_meta)); /* * The second TB (tb1) points to the remainder of the TX command @@ -2228,13 +2323,14 @@ void iwl_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, read_ptr != tfd_num; txq->read_ptr = iwl_txq_inc_wrap(trans, txq->read_ptr), read_ptr = iwl_txq_get_cmd_index(txq, txq->read_ptr)) { + struct iwl_cmd_meta *cmd_meta = &txq->entries[read_ptr].meta; struct sk_buff *skb = txq->entries[read_ptr].skb; if (WARN_ONCE(!skb, "no SKB at %d (%d) on queue %d\n", read_ptr, txq->read_ptr, txq_id)) continue; - iwl_pcie_free_tso_page(trans, skb); + iwl_pcie_free_tso_page(trans, skb, cmd_meta); __skb_queue_tail(skbs, skb); From adc902ceada26add77ad75426805e973a7c67f01 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 3 Jul 2024 12:58:54 +0300 Subject: [PATCH 078/204] wifi: iwlwifi: keep the TSO and workaround pages mapped Map the pages when allocating them so that we will not need to map each of the used fragments at a later point. For now the mapping is not used, this will be changed in a later commit. Signed-off-by: Benjamin Berg Signed-off-by: Miri Korenblit Reviewed-by: Johannes Berg Link: https://patch.msgid.link/20240703125541.7ced468fe431.Ibb109867dc680c37fe8d891e9ab9ef64ed5c5d2d@changeid Signed-off-by: Johannes Berg --- .../wireless/intel/iwlwifi/pcie/internal.h | 30 +++++++++- .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 22 ++++++- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 60 +++++++++++++++---- 3 files changed, 95 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index d63c1c284f70..b59de4f80b4b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -603,6 +603,22 @@ struct iwl_tso_hdr_page { u8 *pos; }; +/* + * Note that we put this struct *last* in the page. By doing that, we ensure + * that no TB referencing this page can trigger the 32-bit boundary hardware + * bug. + */ +struct iwl_tso_page_info { + dma_addr_t dma_addr; + struct page *next; + refcount_t use_count; +}; + +#define IWL_TSO_PAGE_DATA_SIZE (PAGE_SIZE - sizeof(struct iwl_tso_page_info)) +#define IWL_TSO_PAGE_INFO(addr) \ + ((struct iwl_tso_page_info *)(((unsigned long)addr & PAGE_MASK) + \ + IWL_TSO_PAGE_DATA_SIZE)) + int iwl_pcie_tx_init(struct iwl_trans *trans); void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr); int iwl_pcie_tx_stop(struct iwl_trans *trans); @@ -628,8 +644,18 @@ struct sg_table *iwl_pcie_prep_tso(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_cmd_meta *cmd_meta, u8 **hdr, unsigned int hdr_room); -void iwl_pcie_free_tso_page(struct iwl_trans *trans, struct sk_buff *skb, - struct iwl_cmd_meta *cmd_meta); +void iwl_pcie_free_tso_pages(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_cmd_meta *cmd_meta); + +static inline dma_addr_t iwl_pcie_get_tso_page_phys(void *addr) +{ + dma_addr_t res; + + res = IWL_TSO_PAGE_INFO(addr)->dma_addr; + res += (unsigned long)addr & ~PAGE_MASK; + + return res; +} static inline dma_addr_t iwl_txq_get_first_tb_dma(struct iwl_txq *txq, int idx) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 3dcce6a8da50..10ee2c328458 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -19,8 +19,10 @@ static struct page *get_workaround_page(struct iwl_trans *trans, struct sk_buff *skb) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_tso_page_info *info; struct page **page_ptr; struct page *ret; + dma_addr_t phys; page_ptr = (void *)((u8 *)skb->cb + trans_pcie->txqs.page_offs); @@ -28,8 +30,22 @@ static struct page *get_workaround_page(struct iwl_trans *trans, if (!ret) return NULL; + info = IWL_TSO_PAGE_INFO(page_address(ret)); + + /* Create a DMA mapping for the page */ + phys = dma_map_page_attrs(trans->dev, ret, 0, PAGE_SIZE, + DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); + if (unlikely(dma_mapping_error(trans->dev, phys))) { + __free_page(ret); + return NULL; + } + + /* Store physical address and set use count */ + info->dma_addr = phys; + refcount_set(&info->use_count, 1); + /* set the chaining pointer to the previous page if there */ - *(void **)((u8 *)page_address(ret) + PAGE_SIZE - sizeof(void *)) = *page_ptr; + info->next = *page_ptr; *page_ptr = ret; return ret; @@ -76,7 +92,7 @@ static int iwl_txq_gen2_set_tb_with_wa(struct iwl_trans *trans, * a new mapping for it so the device will not fail. */ - if (WARN_ON(len > PAGE_SIZE - sizeof(void *))) { + if (WARN_ON(len > IWL_TSO_PAGE_DATA_SIZE)) { ret = -ENOBUFS; goto unmap; } @@ -782,7 +798,7 @@ static void iwl_txq_gen2_unmap(struct iwl_trans *trans, int txq_id) struct sk_buff *skb = txq->entries[idx].skb; if (!WARN_ON_ONCE(!skb)) - iwl_pcie_free_tso_page(trans, skb, cmd_meta); + iwl_pcie_free_tso_pages(trans, skb, cmd_meta); } iwl_txq_gen2_free_tfd(trans, txq); txq->read_ptr = iwl_txq_inc_wrap(trans, txq->read_ptr); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index ac545a39ad2a..e00d85866de9 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -209,8 +209,22 @@ static void iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans) spin_unlock(&trans_pcie->reg_lock); } -void iwl_pcie_free_tso_page(struct iwl_trans *trans, struct sk_buff *skb, - struct iwl_cmd_meta *cmd_meta) +static void iwl_pcie_free_and_unmap_tso_page(struct iwl_trans *trans, + struct page *page) +{ + struct iwl_tso_page_info *info = IWL_TSO_PAGE_INFO(page_address(page)); + + /* Decrease internal use count and unmap/free page if needed */ + if (refcount_dec_and_test(&info->use_count)) { + dma_unmap_page(trans->dev, info->dma_addr, PAGE_SIZE, + DMA_TO_DEVICE); + + __free_page(page); + } +} + +void iwl_pcie_free_tso_pages(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_cmd_meta *cmd_meta) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct page **page_ptr; @@ -221,10 +235,11 @@ void iwl_pcie_free_tso_page(struct iwl_trans *trans, struct sk_buff *skb, *page_ptr = NULL; while (next) { + struct iwl_tso_page_info *info; struct page *tmp = next; - next = *(void **)((u8 *)page_address(next) + PAGE_SIZE - - sizeof(void *)); + info = IWL_TSO_PAGE_INFO(page_address(next)); + next = info->next; /* Unmap the scatter gather list that is on the last page */ if (!next && cmd_meta->sg_offset) { @@ -236,7 +251,7 @@ void iwl_pcie_free_tso_page(struct iwl_trans *trans, struct sk_buff *skb, dma_unmap_sgtable(trans->dev, sgt, DMA_TO_DEVICE, 0); } - __free_page(tmp); + iwl_pcie_free_and_unmap_tso_page(trans, tmp); } } @@ -381,7 +396,7 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id) if (WARN_ON_ONCE(!skb)) continue; - iwl_pcie_free_tso_page(trans, skb, cmd_meta); + iwl_pcie_free_tso_pages(trans, skb, cmd_meta); } iwl_txq_free_tfd(trans, txq); txq->read_ptr = iwl_txq_inc_wrap(trans, txq->read_ptr); @@ -1722,7 +1737,9 @@ static void *iwl_pcie_get_page_hdr(struct iwl_trans *trans, { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_tso_hdr_page *p = this_cpu_ptr(trans_pcie->txqs.tso_hdr_page); + struct iwl_tso_page_info *info; struct page **page_ptr; + dma_addr_t phys; void *ret; page_ptr = (void *)((u8 *)skb->cb + trans_pcie->txqs.page_offs); @@ -1743,23 +1760,42 @@ static void *iwl_pcie_get_page_hdr(struct iwl_trans *trans, * * (see also get_workaround_page() in tx-gen2.c) */ - if (p->pos + len < (u8 *)page_address(p->page) + PAGE_SIZE - - sizeof(void *)) + if (((unsigned long)p->pos & ~PAGE_MASK) + len < IWL_TSO_PAGE_DATA_SIZE) { + info = IWL_TSO_PAGE_INFO(page_address(ret)); goto out; + } /* We don't have enough room on this page, get a new one. */ - __free_page(p->page); + iwl_pcie_free_and_unmap_tso_page(trans, p->page); alloc: p->page = alloc_page(GFP_ATOMIC); if (!p->page) return NULL; p->pos = page_address(p->page); + + info = IWL_TSO_PAGE_INFO(page_address(ret)); + /* set the chaining pointer to NULL */ - *(void **)((u8 *)page_address(p->page) + PAGE_SIZE - sizeof(void *)) = NULL; + info->next = NULL; + + /* Create a DMA mapping for the page */ + phys = dma_map_page_attrs(trans->dev, p->page, 0, PAGE_SIZE, + DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); + if (unlikely(dma_mapping_error(trans->dev, phys))) { + __free_page(p->page); + p->page = NULL; + + return NULL; + } + + /* Store physical address and set use count */ + info->dma_addr = phys; + refcount_set(&info->use_count, 1); out: *page_ptr = p->page; - get_page(p->page); + /* Return an internal reference for the caller */ + refcount_inc(&info->use_count); ret = p->pos; p->pos += len; @@ -2330,7 +2366,7 @@ void iwl_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, read_ptr, txq->read_ptr, txq_id)) continue; - iwl_pcie_free_tso_page(trans, skb, cmd_meta); + iwl_pcie_free_tso_pages(trans, skb, cmd_meta); __skb_queue_tail(skbs, skb); From 90db50755228252f94b143bbf2380242688b1104 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 3 Jul 2024 12:58:55 +0300 Subject: [PATCH 079/204] wifi: iwlwifi: use already mapped data when TXing an AMSDU The previous commits added mappings for the SKB and TSO page. This switches the code to use these mappings instead of creating new ones. Signed-off-by: Benjamin Berg Signed-off-by: Miri Korenblit Reviewed-by: Johannes Berg Link: https://patch.msgid.link/20240703125541.35d89c5e4ae8.I4feb8d34e7b30768d21365ec22c944bacc274d0b@changeid Signed-off-by: Johannes Berg --- .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 64 ++++++++++++++----- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 21 ++++-- 2 files changed, 63 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 10ee2c328458..21c3998a76c8 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -61,7 +61,8 @@ static int iwl_txq_gen2_set_tb_with_wa(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_tfh_tfd *tfd, dma_addr_t phys, void *virt, - u16 len, struct iwl_cmd_meta *meta) + u16 len, struct iwl_cmd_meta *meta, + bool unmap) { dma_addr_t oldphys = phys; struct page *page; @@ -105,10 +106,27 @@ static int iwl_txq_gen2_set_tb_with_wa(struct iwl_trans *trans, memcpy(page_address(page), virt, len); - phys = dma_map_single(trans->dev, page_address(page), len, - DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(trans->dev, phys))) - return -ENOMEM; + /* + * This is a bit odd, but performance does not matter here, what + * matters are the expectations of the calling code and TB cleanup + * function. + * + * As such, if unmap is set, then create another mapping for the TB + * entry as it will be unmapped later. On the other hand, if it is not + * set, then the TB entry will not be unmapped and instead we simply + * reference and sync the mapping that get_workaround_page() created. + */ + if (unmap) { + phys = dma_map_single(trans->dev, page_address(page), len, + DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(trans->dev, phys))) + return -ENOMEM; + } else { + phys = iwl_pcie_get_tso_page_phys(page_address(page)); + dma_sync_single_for_device(trans->dev, phys, len, + DMA_TO_DEVICE); + } + ret = iwl_txq_gen2_set_tb(trans, tfd, phys, len); if (ret < 0) { /* unmap the new allocation as single */ @@ -116,6 +134,7 @@ static int iwl_txq_gen2_set_tb_with_wa(struct iwl_trans *trans, meta = NULL; goto unmap; } + IWL_DEBUG_TX(trans, "TB bug workaround: copied %d bytes from 0x%llx to 0x%llx\n", len, (unsigned long long)oldphys, @@ -123,6 +142,9 @@ static int iwl_txq_gen2_set_tb_with_wa(struct iwl_trans *trans, ret = 0; unmap: + if (!unmap) + goto trace; + if (meta) dma_unmap_page(trans->dev, oldphys, len, DMA_TO_DEVICE); else @@ -146,6 +168,7 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans, struct ieee80211_hdr *hdr = (void *)skb->data; unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room; unsigned int mss = skb_shinfo(skb)->gso_size; + dma_addr_t start_hdr_phys; u16 length, amsdu_pad; u8 *start_hdr; struct sg_table *sgt; @@ -168,6 +191,8 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans, if (!sgt) return -ENOMEM; + start_hdr_phys = iwl_pcie_get_tso_page_phys(start_hdr); + /* * Pull the ieee80211 header to be able to use TSO core, * we will restore it for the tx_status flow. @@ -214,10 +239,8 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans, pos_hdr += snap_ip_tcp_hdrlen; tb_len = pos_hdr - start_hdr; - tb_phys = dma_map_single(trans->dev, start_hdr, - tb_len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(trans->dev, tb_phys))) - goto out_err; + tb_phys = iwl_pcie_get_tso_page_phys(start_hdr); + /* * No need for _with_wa, this is from the TSO page and * we leave some space at the end of it so can't hit @@ -237,11 +260,14 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans, int ret; tb_len = min_t(unsigned int, tso.size, data_left); - tb_phys = dma_map_single(trans->dev, tso.data, - tb_len, DMA_TO_DEVICE); + tb_phys = iwl_pcie_get_sgt_tb_phys(sgt, tso.data); + /* Not a real mapping error, use direct comparison */ + if (unlikely(tb_phys == DMA_MAPPING_ERROR)) + goto out_err; + ret = iwl_txq_gen2_set_tb_with_wa(trans, skb, tfd, tb_phys, tso.data, - tb_len, NULL); + tb_len, NULL, false); if (ret) goto out_err; @@ -250,6 +276,9 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans, } } + dma_sync_single_for_device(trans->dev, start_hdr_phys, hdr_room, + DMA_TO_DEVICE); + /* re -add the WiFi header */ skb_push(skb, hdr_len); @@ -339,7 +368,7 @@ static int iwl_txq_gen2_tx_add_frags(struct iwl_trans *trans, fragsz, DMA_TO_DEVICE); ret = iwl_txq_gen2_set_tb_with_wa(trans, skb, tfd, tb_phys, skb_frag_address(frag), - fragsz, out_meta); + fragsz, out_meta, true); if (ret) return ret; } @@ -413,7 +442,7 @@ iwl_tfh_tfd *iwl_txq_gen2_build_tx(struct iwl_trans *trans, tb2_len, DMA_TO_DEVICE); ret = iwl_txq_gen2_set_tb_with_wa(trans, skb, tfd, tb_phys, skb->data + hdr_len, tb2_len, - NULL); + NULL, true); if (ret) goto out_err; } @@ -428,7 +457,8 @@ iwl_tfh_tfd *iwl_txq_gen2_build_tx(struct iwl_trans *trans, skb_headlen(frag), DMA_TO_DEVICE); ret = iwl_txq_gen2_set_tb_with_wa(trans, skb, tfd, tb_phys, frag->data, - skb_headlen(frag), NULL); + skb_headlen(frag), NULL, + true); if (ret) goto out_err; if (iwl_txq_gen2_tx_add_frags(trans, frag, tfd, out_meta)) @@ -623,6 +653,10 @@ void iwl_txq_gen2_tfd_unmap(struct iwl_trans *trans, return; } + /* TB1 is mapped directly, the rest is the TSO page and SG list. */ + if (meta->sg_offset) + num_tbs = 2; + /* first TB is never freed - it's the bidirectional DMA data */ for (i = 1; i < num_tbs; i++) { if (meta->tbs & BIT(i)) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index e00d85866de9..8afb5fc1972e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -303,6 +303,10 @@ static void iwl_txq_gen1_tfd_unmap(struct iwl_trans *trans, return; } + /* TB1 is mapped directly, the rest is the TSO page and SG list. */ + if (meta->sg_offset) + num_tbs = 2; + /* first TB is never freed - it's the bidirectional DMA data */ for (i = 1; i < num_tbs; i++) { @@ -1892,6 +1896,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room; unsigned int mss = skb_shinfo(skb)->gso_size; u16 length, iv_len, amsdu_pad; + dma_addr_t start_hdr_phys; u8 *start_hdr, *pos_hdr; struct sg_table *sgt; struct tso_t tso; @@ -1920,6 +1925,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, if (!sgt) return -ENOMEM; + start_hdr_phys = iwl_pcie_get_tso_page_phys(start_hdr); pos_hdr = start_hdr; memcpy(pos_hdr, skb->data + hdr_len, iv_len); pos_hdr += iv_len; @@ -1971,10 +1977,8 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, pos_hdr += snap_ip_tcp_hdrlen; hdr_tb_len = pos_hdr - start_hdr; - hdr_tb_phys = dma_map_single(trans->dev, start_hdr, - hdr_tb_len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(trans->dev, hdr_tb_phys))) - return -EINVAL; + hdr_tb_phys = iwl_pcie_get_tso_page_phys(start_hdr); + iwl_pcie_txq_build_tfd(trans, txq, hdr_tb_phys, hdr_tb_len, false); trace_iwlwifi_dev_tx_tb(trans->dev, skb, start_hdr, @@ -1991,9 +1995,9 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, data_left); dma_addr_t tb_phys; - tb_phys = dma_map_single(trans->dev, tso.data, - size, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(trans->dev, tb_phys))) + tb_phys = iwl_pcie_get_sgt_tb_phys(sgt, tso.data); + /* Not a real mapping error, use direct comparison */ + if (unlikely(tb_phys == DMA_MAPPING_ERROR)) return -EINVAL; iwl_pcie_txq_build_tfd(trans, txq, tb_phys, @@ -2006,6 +2010,9 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, } } + dma_sync_single_for_device(trans->dev, start_hdr_phys, hdr_room, + DMA_TO_DEVICE); + /* re -add the WiFi header and IV */ skb_push(skb, hdr_len + iv_len); From 1a3364e963989dbcd1465dd8e94d9c5babd3474a Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 3 Jul 2024 12:58:56 +0300 Subject: [PATCH 080/204] wifi: iwlwifi: keep BHs disabled when TXing from reclaim During reclaim, we may release the txq->lock spinlock in order to call iwl_trans_tx to queue new frames. The iwl_trans_tx function expects to be called with BHs disabled and iwl_pcie_reclaim is most of the times called with BHs disabled already. However, reclaim can also happen after flushing a STA and in that case BHs will not be disabled. Solve this corner case by only releasing the spinlock but keeping BHs disabled. Signed-off-by: Benjamin Berg Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20240703125541.5d12e0e54e9f.Ic53a7ff75f1163eb38bdcf5d66b503e91e6ce5ca@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 8afb5fc1972e..1f6db6b90f6f 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -2412,7 +2412,7 @@ void iwl_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, * have tx as well. Bottom line, we can unlock and re-lock * later. */ - spin_unlock_bh(&txq->lock); + spin_unlock(&txq->lock); while ((skb = __skb_dequeue(&overflow_skbs))) { struct iwl_device_tx_cmd *dev_cmd_ptr; @@ -2431,7 +2431,7 @@ void iwl_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, if (iwl_txq_space(trans, txq) > txq->low_mark) iwl_trans_pcie_wake_queue(trans, txq); - spin_lock_bh(&txq->lock); + spin_lock(&txq->lock); txq->overflow_tx = false; } From a2ed933dfefac8976ac915e1b1b60028b9c344b3 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 3 Jul 2024 12:58:57 +0300 Subject: [PATCH 081/204] wifi: iwlwifi: release TXQ lock during reclaim Much of the work during reclaim can be done without holding the TXQ lock and releasing the lock means that command submission can happen at the same time. Add a new reclaim_lock to prevent parallel cleanup. Release the lock while working with an internal copy of the txq->read_ptr and only take the lock again when updating the read pointer after the cleanup is done. Signed-off-by: Benjamin Berg Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20240703125541.2a81021d49ac.I53698ae92fb75a0461d41176db115462cf8be1cd@changeid Signed-off-by: Johannes Berg --- .../net/wireless/intel/iwlwifi/iwl-trans.h | 3 + .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 6 +- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 78 +++++++++++-------- 3 files changed, 54 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 015f02122df6..6148acbac6af 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -752,6 +752,7 @@ struct iwl_pcie_first_tb_buf { * @first_tb_dma: DMA address for the first_tb_bufs start * @entries: transmit entries (driver state) * @lock: queue lock + * @reclaim_lock: reclaim lock * @stuck_timer: timer that fires if queue gets stuck * @trans: pointer back to transport (for timer) * @need_update: indicates need to update read/write index @@ -794,6 +795,8 @@ struct iwl_txq { struct iwl_pcie_txq_entry *entries; /* lock for syncing changes on the queue */ spinlock_t lock; + /* lock to prevent concurrent reclaim */ + spinlock_t reclaim_lock; unsigned long frozen_expiry_remainder; struct timer_list stuck_timer; struct iwl_trans *trans; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 21c3998a76c8..2e780fb2da42 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -821,7 +821,8 @@ static void iwl_txq_gen2_unmap(struct iwl_trans *trans, int txq_id) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_txq *txq = trans_pcie->txqs.txq[txq_id]; - spin_lock_bh(&txq->lock); + spin_lock_bh(&txq->reclaim_lock); + spin_lock(&txq->lock); while (txq->write_ptr != txq->read_ptr) { IWL_DEBUG_TX_REPLY(trans, "Q %d Free %d\n", txq_id, txq->read_ptr); @@ -844,7 +845,8 @@ static void iwl_txq_gen2_unmap(struct iwl_trans *trans, int txq_id) iwl_op_mode_free_skb(trans->op_mode, skb); } - spin_unlock_bh(&txq->lock); + spin_unlock(&txq->lock); + spin_unlock_bh(&txq->reclaim_lock); /* just in case - this queue may have been stopped */ iwl_trans_pcie_wake_queue(trans, txq); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 1f6db6b90f6f..748772fa6b3e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -333,20 +333,21 @@ static void iwl_txq_gen1_tfd_unmap(struct iwl_trans *trans, * iwl_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr] * @trans: transport private data * @txq: tx queue + * @read_ptr: the TXQ read_ptr to free * * Does NOT advance any TFD circular buffer read/write indexes * Does NOT free the TFD itself (which is within circular buffer) */ -static void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq) +static void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq, + int read_ptr) { /* rd_ptr is bounded by TFD_QUEUE_SIZE_MAX and * idx is bounded by n_window */ - int rd_ptr = txq->read_ptr; - int idx = iwl_txq_get_cmd_index(txq, rd_ptr); + int idx = iwl_txq_get_cmd_index(txq, read_ptr); struct sk_buff *skb; - lockdep_assert_held(&txq->lock); + lockdep_assert_held(&txq->reclaim_lock); if (!txq->entries) return; @@ -356,10 +357,10 @@ static void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq) */ if (trans->trans_cfg->gen2) iwl_txq_gen2_tfd_unmap(trans, &txq->entries[idx].meta, - iwl_txq_get_tfd(trans, txq, rd_ptr)); + iwl_txq_get_tfd(trans, txq, read_ptr)); else iwl_txq_gen1_tfd_unmap(trans, &txq->entries[idx].meta, - txq, rd_ptr); + txq, read_ptr); /* free SKB */ skb = txq->entries[idx].skb; @@ -387,7 +388,8 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id) return; } - spin_lock_bh(&txq->lock); + spin_lock_bh(&txq->reclaim_lock); + spin_lock(&txq->lock); while (txq->write_ptr != txq->read_ptr) { IWL_DEBUG_TX_REPLY(trans, "Q %d Free %d\n", txq_id, txq->read_ptr); @@ -402,7 +404,7 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id) iwl_pcie_free_tso_pages(trans, skb, cmd_meta); } - iwl_txq_free_tfd(trans, txq); + iwl_txq_free_tfd(trans, txq, txq->read_ptr); txq->read_ptr = iwl_txq_inc_wrap(trans, txq->read_ptr); if (txq->read_ptr == txq->write_ptr && @@ -416,7 +418,8 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id) iwl_op_mode_free_skb(trans->op_mode, skb); } - spin_unlock_bh(&txq->lock); + spin_unlock(&txq->lock); + spin_unlock_bh(&txq->reclaim_lock); /* just in case - this queue may have been stopped */ iwl_trans_pcie_wake_queue(trans, txq); @@ -921,6 +924,7 @@ int iwl_txq_init(struct iwl_trans *trans, struct iwl_txq *txq, return ret; spin_lock_init(&txq->lock); + spin_lock_init(&txq->reclaim_lock); if (cmd_queue) { static struct lock_class_key iwl_txq_cmd_queue_lock_class; @@ -1055,11 +1059,12 @@ static void iwl_txq_progress(struct iwl_txq *txq) mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout); } -static inline bool iwl_txq_used(const struct iwl_txq *q, int i) +static inline bool iwl_txq_used(const struct iwl_txq *q, int i, + int read_ptr, int write_ptr) { int index = iwl_txq_get_cmd_index(q, i); - int r = iwl_txq_get_cmd_index(q, q->read_ptr); - int w = iwl_txq_get_cmd_index(q, q->write_ptr); + int r = iwl_txq_get_cmd_index(q, read_ptr); + int w = iwl_txq_get_cmd_index(q, write_ptr); return w >= r ? (index >= r && index < w) : @@ -1086,7 +1091,7 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx) r = iwl_txq_get_cmd_index(txq, txq->read_ptr); if (idx >= trans->trans_cfg->base_params->max_tfd_queue_size || - (!iwl_txq_used(txq, idx))) { + (!iwl_txq_used(txq, idx, txq->read_ptr, txq->write_ptr))) { WARN_ONCE(test_bit(txq_id, trans_pcie->txqs.queue_used), "%s: Read index for DMA queue txq id (%d), index %d is out of range [0-%d] %d %d.\n", __func__, txq_id, idx, @@ -2284,12 +2289,12 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, } static void iwl_txq_gen1_inval_byte_cnt_tbl(struct iwl_trans *trans, - struct iwl_txq *txq) + struct iwl_txq *txq, + int read_ptr) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwlagn_scd_bc_tbl *scd_bc_tbl = trans_pcie->txqs.scd_bc_tbls.addr; int txq_id = txq->id; - int read_ptr = txq->read_ptr; u8 sta_id = 0; __le16 bc_ent; struct iwl_device_tx_cmd *dev_cmd = txq->entries[read_ptr].cmd; @@ -2316,6 +2321,7 @@ void iwl_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_txq *txq = trans_pcie->txqs.txq[txq_id]; int tfd_num, read_ptr, last_to_free; + int txq_read_ptr, txq_write_ptr; /* This function is not meant to release cmd queue*/ if (WARN_ON(txq_id == trans_pcie->txqs.cmd.q_id)) @@ -2326,8 +2332,14 @@ void iwl_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, tfd_num = iwl_txq_get_cmd_index(txq, ssn); - spin_lock_bh(&txq->lock); - read_ptr = iwl_txq_get_cmd_index(txq, txq->read_ptr); + spin_lock_bh(&txq->reclaim_lock); + + spin_lock(&txq->lock); + txq_read_ptr = txq->read_ptr; + txq_write_ptr = txq->write_ptr; + spin_unlock(&txq->lock); + + read_ptr = iwl_txq_get_cmd_index(txq, txq_read_ptr); if (!test_bit(txq_id, trans_pcie->txqs.queue_used)) { IWL_DEBUG_TX_QUEUES(trans, "Q %d inactive - ignoring idx %d\n", @@ -2339,19 +2351,19 @@ void iwl_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, goto out; IWL_DEBUG_TX_REPLY(trans, "[Q %d] %d (%d) -> %d (%d)\n", - txq_id, read_ptr, txq->read_ptr, tfd_num, ssn); + txq_id, read_ptr, txq_read_ptr, tfd_num, ssn); /* Since we free until index _not_ inclusive, the one before index is * the last we will free. This one must be used */ last_to_free = iwl_txq_dec_wrap(trans, tfd_num); - if (!iwl_txq_used(txq, last_to_free)) { + if (!iwl_txq_used(txq, last_to_free, txq_read_ptr, txq_write_ptr)) { IWL_ERR(trans, "%s: Read index for txq id (%d), last_to_free %d is out of range [0-%d] %d %d.\n", __func__, txq_id, last_to_free, trans->trans_cfg->base_params->max_tfd_queue_size, - txq->write_ptr, txq->read_ptr); + txq_write_ptr, txq_read_ptr); iwl_op_mode_time_point(trans->op_mode, IWL_FW_INI_TIME_POINT_FAKE_TX, @@ -2364,13 +2376,13 @@ void iwl_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, for (; read_ptr != tfd_num; - txq->read_ptr = iwl_txq_inc_wrap(trans, txq->read_ptr), - read_ptr = iwl_txq_get_cmd_index(txq, txq->read_ptr)) { + txq_read_ptr = iwl_txq_inc_wrap(trans, txq_read_ptr), + read_ptr = iwl_txq_get_cmd_index(txq, txq_read_ptr)) { struct iwl_cmd_meta *cmd_meta = &txq->entries[read_ptr].meta; struct sk_buff *skb = txq->entries[read_ptr].skb; if (WARN_ONCE(!skb, "no SKB at %d (%d) on queue %d\n", - read_ptr, txq->read_ptr, txq_id)) + read_ptr, txq_read_ptr, txq_id)) continue; iwl_pcie_free_tso_pages(trans, skb, cmd_meta); @@ -2380,11 +2392,15 @@ void iwl_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, txq->entries[read_ptr].skb = NULL; if (!trans->trans_cfg->gen2) - iwl_txq_gen1_inval_byte_cnt_tbl(trans, txq); + iwl_txq_gen1_inval_byte_cnt_tbl(trans, txq, + txq_read_ptr); - iwl_txq_free_tfd(trans, txq); + iwl_txq_free_tfd(trans, txq, txq_read_ptr); } + spin_lock(&txq->lock); + txq->read_ptr = txq_read_ptr; + iwl_txq_progress(txq); if (iwl_txq_space(trans, txq) > txq->low_mark && @@ -2406,11 +2422,10 @@ void iwl_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, txq->overflow_tx = true; /* - * This is tricky: we are in reclaim path which is non - * re-entrant, so noone will try to take the access the - * txq data from that path. We stopped tx, so we can't - * have tx as well. Bottom line, we can unlock and re-lock - * later. + * This is tricky: we are in reclaim path and are holding + * reclaim_lock, so noone will try to access the txq data + * from that path. We stopped tx, so we can't have tx as well. + * Bottom line, we can unlock and re-lock later. */ spin_unlock(&txq->lock); @@ -2435,8 +2450,9 @@ void iwl_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, txq->overflow_tx = false; } + spin_unlock(&txq->lock); out: - spin_unlock_bh(&txq->lock); + spin_unlock_bh(&txq->reclaim_lock); } /* Set wr_ptr of specific device and txq */ From 5fdbde79eafe45888f41f6947132f63e8d39f485 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 Jul 2024 12:58:58 +0300 Subject: [PATCH 082/204] wifi: iwlwifi: mvm: add missing string for ROC EMLSR block This should be labeled for the debug output, add the missing string. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20240703125541.03d428f4ff4d.I858f17a5173fe8337cea4e7665fec00dbb15e514@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/link.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index 4e702e7a4b82..a9929aa49913 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -11,6 +11,7 @@ HOW(BLOCKED_TPT) \ HOW(BLOCKED_FW) \ HOW(BLOCKED_NON_BSS) \ + HOW(BLOCKED_ROC) \ HOW(EXIT_MISSED_BEACON) \ HOW(EXIT_LOW_RSSI) \ HOW(EXIT_COEX) \ From 3a84161cd3fb0756f640d842cb1278713808f887 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 Jul 2024 12:58:59 +0300 Subject: [PATCH 083/204] wifi: iwlwifi: fw: api: fix memory region kernel-doc Add the missing special_mem union member and use constant formatting (%) for the type constants. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20240703125541.9344b2b94d45.Id770b4f1893308ba43fc039a8851c526312ad2b5@changeid Signed-off-by: Johannes Berg --- .../wireless/intel/iwlwifi/fw/api/dbg-tlv.h | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h index e71b3bc20253..855cd13a181e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -147,32 +147,34 @@ struct iwl_fw_ini_region_internal_buffer { * Configures parameters for region data collection * * @hdr: debug header - * @id: region id. Max id is &IWL_FW_INI_MAX_REGION_ID + * @id: region id. Max id is %IWL_FW_INI_MAX_REGION_ID * @type: region type. One of &enum iwl_fw_ini_region_type * @sub_type: region sub type * @sub_type_ver: region sub type version * @reserved: not in use * @name: region name * @dev_addr: device address configuration. Used by - * &IWL_FW_INI_REGION_DEVICE_MEMORY, &IWL_FW_INI_REGION_PERIPHERY_MAC, - * &IWL_FW_INI_REGION_PERIPHERY_PHY, &IWL_FW_INI_REGION_PERIPHERY_AUX, - * &IWL_FW_INI_REGION_PAGING, &IWL_FW_INI_REGION_CSR, - * &IWL_FW_INI_REGION_DRAM_IMR and &IWL_FW_INI_REGION_PCI_IOSF_CONFIG - * &IWL_FW_INI_REGION_DBGI_SRAM, &FW_TLV_DEBUG_REGION_TYPE_DBGI_SRAM, - * &IWL_FW_INI_REGION_PERIPHERY_SNPS_DPHYIP, + * %IWL_FW_INI_REGION_DEVICE_MEMORY, %IWL_FW_INI_REGION_PERIPHERY_MAC, + * %IWL_FW_INI_REGION_PERIPHERY_PHY, %IWL_FW_INI_REGION_PERIPHERY_AUX, + * %IWL_FW_INI_REGION_PAGING, %IWL_FW_INI_REGION_CSR, + * %IWL_FW_INI_REGION_DRAM_IMR and %IWL_FW_INI_REGION_PCI_IOSF_CONFIG + * %IWL_FW_INI_REGION_DBGI_SRAM, %FW_TLV_DEBUG_REGION_TYPE_DBGI_SRAM, + * %IWL_FW_INI_REGION_PERIPHERY_SNPS_DPHYIP, * @dev_addr_range: device address range configuration. Used by - * &IWL_FW_INI_REGION_PERIPHERY_MAC_RANGE and - * &IWL_FW_INI_REGION_PERIPHERY_PHY_RANGE - * @fifos: fifos configuration. Used by &IWL_FW_INI_REGION_TXF and - * &IWL_FW_INI_REGION_RXF + * %IWL_FW_INI_REGION_PERIPHERY_MAC_RANGE and + * %IWL_FW_INI_REGION_PERIPHERY_PHY_RANGE + * @fifos: fifos configuration. Used by %IWL_FW_INI_REGION_TXF and + * %IWL_FW_INI_REGION_RXF * @err_table: error table configuration. Used by - * IWL_FW_INI_REGION_LMAC_ERROR_TABLE and - * IWL_FW_INI_REGION_UMAC_ERROR_TABLE + * %IWL_FW_INI_REGION_LMAC_ERROR_TABLE and + * %IWL_FW_INI_REGION_UMAC_ERROR_TABLE * @internal_buffer: internal monitor buffer configuration. Used by - * &IWL_FW_INI_REGION_INTERNAL_BUFFER + * %IWL_FW_INI_REGION_INTERNAL_BUFFER + * @special_mem: special device memory region, used by + * %IWL_FW_INI_REGION_SPECIAL_DEVICE_MEMORY * @dram_alloc_id: dram allocation id. One of &enum iwl_fw_ini_allocation_id. - * Used by &IWL_FW_INI_REGION_DRAM_BUFFER - * @tlv_mask: tlv collection mask. Used by &IWL_FW_INI_REGION_TLV + * Used by %IWL_FW_INI_REGION_DRAM_BUFFER + * @tlv_mask: tlv collection mask. Used by %IWL_FW_INI_REGION_TLV * @addrs: array of addresses attached to the end of the region tlv */ struct iwl_fw_ini_region_tlv { From 6009de8014a85e952e09d6c1944bfe8409114d94 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 Jul 2024 12:59:00 +0300 Subject: [PATCH 084/204] wifi: iwlwifi: fw: api: mac: fix kernel-doc Fix kernel-doc for MAC context APIs. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20240703125541.a7179f1b0e7e.Idd7ce381960707978ff0b16035101a2a725a4fd9@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/mac.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h index 545826973a80..bcbbf8c4a297 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h @@ -310,6 +310,13 @@ struct iwl_ac_qos { * @filter_flags: combination of &enum iwl_mac_filter_flags * @qos_flags: from &enum iwl_mac_qos_flags * @ac: one iwl_mac_qos configuration for each AC + * @ap: AP specific config data, see &struct iwl_mac_data_ap + * @go: GO specific config data, see &struct iwl_mac_data_go + * @sta: BSS client specific config data, see &struct iwl_mac_data_sta + * @p2p_sta: P2P client specific config data, see &struct iwl_mac_data_p2p_sta + * @p2p_dev: P2P-device specific config data, see &struct iwl_mac_data_p2p_dev + * @pibss: Pseudo-IBSS specific data, unused; see struct iwl_mac_data_pibss + * @ibss: IBSS specific config data, see &struct iwl_mac_data_ibss */ struct iwl_mac_ctx_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ From 94c97e1178d5714d2c02f73da426655adbc24937 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 Jul 2024 12:59:01 +0300 Subject: [PATCH 085/204] wifi: iwlwifi: fw: api: add puncturing to PHY context docs Document the puncture_mask field in the PHY context. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20240703125541.8ba6536ea36b.I181d8da205a14f4fcbf1d8cc6011dcf194a1638a@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h index f192e02e4ba8..4d8a12799c4d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h @@ -144,6 +144,7 @@ struct iwl_phy_context_cmd_v1 { * @rxchain_info: ??? * @sbb_bandwidth: 0 disabled, 1 - 40Mhz ... 4 - 320MHz * @sbb_ctrl_channel_loc: location of the control channel + * @puncture_mask: bitmap of punctured subchannels * @dsp_cfg_flags: set to 0 * @reserved: reserved to align to 64 bit */ From 137579d65db426dbc2e026c1e42cc34ff5ceed85 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 Jul 2024 12:59:02 +0300 Subject: [PATCH 086/204] wifi: iwlwifi: document PPAG table command union correctly This is not documented correctly, fix it. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20240703125541.2ff5ee61e9ec.I3a1299061e472490c38a9fff4bea319ba20f313a@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/power.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h index 19eb6008fe4b..6e6a92d173cc 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h @@ -569,9 +569,12 @@ enum iwl_ppag_flags { * @v2: version 2 * version 3, 4, 5 and 6 are the same structure as v2, * but has a different format of the flags bitmap - * @flags: values from &enum iwl_ppag_flags - * @gain: table of antenna gain values per chain and sub-band - * @reserved: reserved + * @v1.flags: values from &enum iwl_ppag_flags + * @v1.gain: table of antenna gain values per chain and sub-band + * @v1.reserved: reserved + * @v2.flags: values from &enum iwl_ppag_flags + * @v2.gain: table of antenna gain values per chain and sub-band + * @v2.reserved: reserved */ union iwl_ppag_table_cmd { struct { From 6188855fbb76a3b9b7c2e5f9744988b3e8b3e641 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 Jul 2024 12:59:03 +0300 Subject: [PATCH 087/204] wifi: iwlwifi: fw: api: fix missing RX descriptor kernel-doc The v1/v3 remaining bits are not annotated in kernel-doc, fix that. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20240703125541.d7adf8b235fe.I91f75e292d1648f61e5e341e1fe58096f858853d@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/rx.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index 8bd85ef90052..691c879cb90d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -710,7 +710,15 @@ struct iwl_rx_mpdu_desc { __le32 reorder_data; union { + /** + * @v1: version 1 of the remaining RX descriptor, + * see &struct iwl_rx_mpdu_desc_v1 + */ struct iwl_rx_mpdu_desc_v1 v1; + /** + * @v3: version 3 of the remaining RX descriptor, + * see &struct iwl_rx_mpdu_desc_v3 + */ struct iwl_rx_mpdu_desc_v3 v3; }; } __packed; /* RX_MPDU_RES_START_API_S_VER_3, From 8d4f5969f7c7d3a8f0e93d37a1a2fc23048dd12f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 Jul 2024 12:59:04 +0300 Subject: [PATCH 088/204] wifi: iwlwifi: mvm: document remaining mvm data Many iwl_mvm_vif members are not documented, add that. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20240703125541.371664e5e8cd.I593ebee1ab984554b6d269dc2dddc67fbf3bb537@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 29 ++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 056fdc42e253..22f48b66d79c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -453,6 +453,35 @@ struct iwl_mvm_esr_exit { * @session_prot_connection_loss: the connection was lost due to session * protection ending without receiving a beacon, so we need to now * protect the deauth separately + * @ap_early_keys: The firmware cannot install keys before stations etc., + * but higher layers work differently, so we store the keys here for + * later installation. + * @ap_sta: pointer to the AP STA data structure + * @csa_count: CSA counter (old CSA implementation w/o firmware) + * @csa_misbehave: CSA AP misbehaviour flag (old implementation) + * @csa_target_freq: CSA target channel frequency (old implementation) + * @csa_work: CSA work (old implementation) + * @dbgfs_bf: beamforming debugfs data + * @dbgfs_dir: debugfs directory for this vif + * @dbgfs_pm: power management debugfs data + * @dbgfs_quota_min: debugfs value for minimal quota + * @dbgfs_slink: debugfs symlink for this interface + * @ftm_unprotected: unprotected FTM debugfs override + * @hs_time_event_data: hotspot/AUX ROC time event data + * @mac_pwr_cmd: debugfs override for MAC power command + * @target_ipv6_addrs: IPv6 addresses on this interface for offload + * @num_target_ipv6_addrs: number of @target_ipv6_addrs + * @tentative_addrs: bitmap of tentative IPv6 addresses in @target_ipv6_addrs + * @rekey_data: rekeying data for WoWLAN GTK rekey offload + * @seqno: storage for seqno for older firmware D0/D3 transition + * @seqno_valid: indicates @seqno is valid + * @time_event_data: session protection time event data + * @tsf_id: the TSF resource ID assigned in firmware (for firmware needing that) + * @tx_key_idx: WEP transmit key index for D3 + * @uapsd_misbehaving_ap_addr: MLD address/BSSID of U-APSD misbehaving AP, to + * not use U-APSD on reconnection + * @uapsd_nonagg_detected_wk: worker for handling detection of no aggregation + * in U-APSD */ struct iwl_mvm_vif { struct iwl_mvm *mvm; From 1895712afd1cab549b143717d6f1b6534383a9e0 Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Wed, 3 Jul 2024 12:59:05 +0300 Subject: [PATCH 089/204] wifi: iwlwifi: Remove debug message Debug logs related to reset_fw are logged with all notification/response and polluting the trace. Remove the debug message related to reset_fw setting when dump is collected. Signed-off-by: Mukesh Sisodiya Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20240703125541.8fc59cb17526.Ibb5d68b2fe5f7df709db3570de55a566d5af3f24@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 9810a7f4a591..08d990ba8a79 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -1240,12 +1240,6 @@ iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, bool sync, } fwrt->trans->dbg.restart_required = false; - IWL_DEBUG_FW(fwrt, "WRT: tp %d, reset_fw %d\n", - tp, dump_data.trig->reset_fw); - IWL_DEBUG_FW(fwrt, - "WRT: restart_required %d, last_tp_resetfw %d\n", - fwrt->trans->dbg.restart_required, - fwrt->trans->dbg.last_tp_resetfw); if (fwrt->trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_9000) { @@ -1255,22 +1249,17 @@ iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, bool sync, IWL_FW_INI_RESET_FW_MODE_STOP_FW_ONLY) { fwrt->trans->dbg.restart_required = false; fwrt->trans->dbg.last_tp_resetfw = 0xFF; - IWL_DEBUG_FW(fwrt, "WRT: FW_ASSERT due to reset_fw_mode-no restart\n"); } else if (le32_to_cpu(dump_data.trig->reset_fw) == IWL_FW_INI_RESET_FW_MODE_STOP_AND_RELOAD_FW) { - IWL_DEBUG_FW(fwrt, "WRT: stop and reload firmware\n"); fwrt->trans->dbg.restart_required = true; } else if (le32_to_cpu(dump_data.trig->reset_fw) == IWL_FW_INI_RESET_FW_MODE_STOP_FW_ONLY) { - IWL_DEBUG_FW(fwrt, - "WRT: stop only and no reload firmware\n"); fwrt->trans->dbg.restart_required = false; fwrt->trans->dbg.last_tp_resetfw = le32_to_cpu(dump_data.trig->reset_fw); } else if (le32_to_cpu(dump_data.trig->reset_fw) == IWL_FW_INI_RESET_FW_MODE_NOTHING) { - IWL_DEBUG_FW(fwrt, - "WRT: nothing need to be done after debug collection\n"); + /* nothing */ } else { IWL_ERR(fwrt, "WRT: wrong resetfw %d\n", le32_to_cpu(dump_data.trig->reset_fw)); From ef7ddf4e2f949633bd7b2b01c2e0f023aefb6987 Mon Sep 17 00:00:00 2001 From: Anjaneyulu Date: Wed, 3 Jul 2024 12:59:06 +0300 Subject: [PATCH 090/204] wifi: iwlwifi: Add support for LARI_CONFIG_CHANGE_CMD v12 Add support for activate/deactivate unii4 in USA, Canada and WW by reading DSM function 8 from UEFI or ACPI and sending it to the FW. Signed-off-by: Anjaneyulu Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20240703125541.674604cbb6d1.Ibb946ae8ce7a760940a3c9d101e7f4f1808c43e4@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h | 6 +++++- drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index 9ff5d7e538fd..d424d0126367 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -704,6 +704,8 @@ struct iwl_lari_config_change_cmd_v10 { * Each bit represents a country or region, and a band to activate * according to the BIOS definitions. * For LARI cmd version 11 - bits 0:4 are supported. + * For LARI cmd version 12 - bits 0:6 are supported and bits 7:31 are + * reserved. No need to mask out the reserved bits. * @force_disable_channels_bitmap: Bitmap of disabled bands/channels. * Each bit represents a set of channels in a specific band that should be * disabled @@ -731,9 +733,11 @@ struct iwl_lari_config_change_cmd { __le32 oem_11be_allow_bitmap; } __packed; /* LARI_CHANGE_CONF_CMD_S_VER_11 */ +/* LARI_CHANGE_CONF_CMD_S_VER_12 */ /* Activate UNII-1 (5.2GHz) for World Wide */ -#define ACTIVATE_5G2_IN_WW_MASK BIT(4) +#define ACTIVATE_5G2_IN_WW_MASK BIT(4) +#define CHAN_STATE_ACTIVE_BITMAP_CMD_V11 0x1F /** * struct iwl_pnvm_init_complete_ntfy - PNVM initialization complete diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index 5228b837a9ef..560a91998cc4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -497,6 +497,7 @@ static size_t iwl_get_lari_config_cmd_size(u8 cmd_ver) size_t cmd_size; switch (cmd_ver) { + case 12: case 11: cmd_size = sizeof(struct iwl_lari_config_change_cmd); break; @@ -563,6 +564,9 @@ int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt, if (!ret) { if (cmd_ver < 8) value &= ~ACTIVATE_5G2_IN_WW_MASK; + if (cmd_ver < 12) + value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V11; + cmd->chan_state_active_bitmap = cpu_to_le32(value); } From 1b431ba4ef9a760e7643d6fbc53bf522d59650f3 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 3 Jul 2024 13:27:37 +0300 Subject: [PATCH 091/204] wifi: iwlwifi: mvm: re-enable MLO MLO was temporarily disabled by commit 5f404005055 ("wifi: iwlwifi: mvm: disable MLO for the time being"), until it will stabilize. Now, that all the bugs were fixed and the minimum FW version was bumped to a stable one, we can re-enable MLO back. Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20240703132713.8f77a71c3902.Ib302054cbd8fba82db97eb5298b2aaf8bbe106df@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index e40f993b17fd..41aba087c1a6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -372,7 +372,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) if (mvm->mld_api_is_used && mvm->nvm_data->sku_cap_11be_enable && !iwlwifi_mod_params.disable_11ax && !iwlwifi_mod_params.disable_11be) { - hw->wiphy->flags |= WIPHY_FLAG_DISABLE_WEXT; + hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_MLO; /* we handle this already earlier, but need it for MLO */ ieee80211_hw_set(hw, HANDLES_QUIET_CSA); } From adc539784c98a7cc602cbf557debfc2e7b9be8b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20=C5=9Alusarz?= Date: Tue, 28 May 2024 13:02:46 +0200 Subject: [PATCH 092/204] wifi: rtw88: usb: schedule rx work after everything is set up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Right now it's possible to hit NULL pointer dereference in rtw_rx_fill_rx_status on hw object and/or its fields because initialization routine can start getting USB replies before rtw_dev is fully setup. The stack trace looks like this: rtw_rx_fill_rx_status rtw8821c_query_rx_desc rtw_usb_rx_handler ... queue_work rtw_usb_read_port_complete ... usb_submit_urb rtw_usb_rx_resubmit rtw_usb_init_rx rtw_usb_probe So while we do the async stuff rtw_usb_probe continues and calls rtw_register_hw, which does all kinds of initialization (e.g. via ieee80211_register_hw) that rtw_rx_fill_rx_status relies on. Fix this by moving the first usb_submit_urb after everything is set up. For me, this bug manifested as: [ 8.893177] rtw_8821cu 1-1:1.2: band wrong, packet dropped [ 8.910904] rtw_8821cu 1-1:1.2: hw->conf.chandef.chan NULL in rtw_rx_fill_rx_status because I'm using Larry's backport of rtw88 driver with the NULL checks in rtw_rx_fill_rx_status. Link: https://lore.kernel.org/linux-wireless/CA+shoWQ7P49jhQasofDcTdQhiuarPTjYEDa--NiVVx494WcuQw@mail.gmail.com/ Signed-off-by: Marcin Åšlusarz Cc: Tim K Cc: Ping-Ke Shih Cc: Larry Finger Cc: Kalle Valo Cc: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240528110246.477321-1-marcin.slusarz@gmail.com --- drivers/net/wireless/realtek/rtw88/usb.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c index 057c0ffbe944..a55ca5a24227 100644 --- a/drivers/net/wireless/realtek/rtw88/usb.c +++ b/drivers/net/wireless/realtek/rtw88/usb.c @@ -742,7 +742,6 @@ static struct rtw_hci_ops rtw_usb_ops = { static int rtw_usb_init_rx(struct rtw_dev *rtwdev) { struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); - int i; rtwusb->rxwq = create_singlethread_workqueue("rtw88_usb: rx wq"); if (!rtwusb->rxwq) { @@ -754,13 +753,19 @@ static int rtw_usb_init_rx(struct rtw_dev *rtwdev) INIT_WORK(&rtwusb->rx_work, rtw_usb_rx_handler); + return 0; +} + +static void rtw_usb_setup_rx(struct rtw_dev *rtwdev) +{ + struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); + int i; + for (i = 0; i < RTW_USB_RXCB_NUM; i++) { struct rx_usb_ctrl_block *rxcb = &rtwusb->rx_cb[i]; rtw_usb_rx_resubmit(rtwusb, rxcb); } - - return 0; } static void rtw_usb_deinit_rx(struct rtw_dev *rtwdev) @@ -897,6 +902,8 @@ int rtw_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) goto err_destroy_rxwq; } + rtw_usb_setup_rx(rtwdev); + return 0; err_destroy_rxwq: From 0e557c5c1a61ff4d896a21b00e4e7397e3c123b5 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 1 Jul 2024 09:46:18 +0800 Subject: [PATCH 093/204] wifi: rtw89: 8852bx: move BTC common code from 8852b to 8852b_common The BT coexistence part of 8852B and 8852BT are similar, so move shared code into common module. Don't change logic for existing RTL8852BE. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240701014619.7300-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 173 +----------------- .../wireless/realtek/rtw89/rtw8852b_common.c | 168 +++++++++++++++++ .../wireless/realtek/rtw89/rtw8852b_common.h | 42 +++++ 3 files changed, 216 insertions(+), 167 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 1a9c4951060a..a22847a311ad 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -633,86 +633,6 @@ static void rtw8852b_btc_set_rfe(struct rtw89_dev *rtwdev) } } -static -void rtw8852b_set_trx_mask(struct rtw89_dev *rtwdev, u8 path, u8 group, u32 val) -{ - rtw89_write_rf(rtwdev, path, RR_LUTWE, RFREG_MASK, 0x20000); - rtw89_write_rf(rtwdev, path, RR_LUTWA, RFREG_MASK, group); - rtw89_write_rf(rtwdev, path, RR_LUTWD0, RFREG_MASK, val); - rtw89_write_rf(rtwdev, path, RR_LUTWE, RFREG_MASK, 0x0); -} - -static void rtw8852b_btc_init_cfg(struct rtw89_dev *rtwdev) -{ - struct rtw89_btc *btc = &rtwdev->btc; - const struct rtw89_chip_info *chip = rtwdev->chip; - const struct rtw89_mac_ax_coex coex_params = { - .pta_mode = RTW89_MAC_AX_COEX_RTK_MODE, - .direction = RTW89_MAC_AX_COEX_INNER, - }; - - /* PTA init */ - rtw89_mac_coex_init(rtwdev, &coex_params); - - /* set WL Tx response = Hi-Pri */ - chip->ops->btc_set_wl_pri(rtwdev, BTC_PRI_MASK_TX_RESP, true); - chip->ops->btc_set_wl_pri(rtwdev, BTC_PRI_MASK_BEACON, true); - - /* set rf gnt debug off */ - rtw89_write_rf(rtwdev, RF_PATH_A, RR_WLSEL, RFREG_MASK, 0x0); - rtw89_write_rf(rtwdev, RF_PATH_B, RR_WLSEL, RFREG_MASK, 0x0); - - /* set WL Tx thru in TRX mask table if GNT_WL = 0 && BT_S1 = ss group */ - if (btc->ant_type == BTC_ANT_SHARED) { - rtw8852b_set_trx_mask(rtwdev, RF_PATH_A, BTC_BT_SS_GROUP, 0x5ff); - rtw8852b_set_trx_mask(rtwdev, RF_PATH_B, BTC_BT_SS_GROUP, 0x5ff); - /* set path-A(S0) Tx/Rx no-mask if GNT_WL=0 && BT_S1=tx group */ - rtw8852b_set_trx_mask(rtwdev, RF_PATH_A, BTC_BT_TX_GROUP, 0x5ff); - rtw8852b_set_trx_mask(rtwdev, RF_PATH_B, BTC_BT_TX_GROUP, 0x55f); - } else { /* set WL Tx stb if GNT_WL = 0 && BT_S1 = ss group for 3-ant */ - rtw8852b_set_trx_mask(rtwdev, RF_PATH_A, BTC_BT_SS_GROUP, 0x5df); - rtw8852b_set_trx_mask(rtwdev, RF_PATH_B, BTC_BT_SS_GROUP, 0x5df); - rtw8852b_set_trx_mask(rtwdev, RF_PATH_A, BTC_BT_TX_GROUP, 0x5ff); - rtw8852b_set_trx_mask(rtwdev, RF_PATH_B, BTC_BT_TX_GROUP, 0x5ff); - } - - /* set PTA break table */ - rtw89_write32(rtwdev, R_BTC_BREAK_TABLE, BTC_BREAK_PARAM); - - /* enable BT counter 0xda40[16,2] = 2b'11 */ - rtw89_write32_set(rtwdev, R_AX_CSR_MODE, B_AX_BT_CNT_RST | B_AX_STATIS_BT_EN); - btc->cx.wl.status.map.init_ok = true; -} - -static -void rtw8852b_btc_set_wl_pri(struct rtw89_dev *rtwdev, u8 map, bool state) -{ - u32 bitmap; - u32 reg; - - switch (map) { - case BTC_PRI_MASK_TX_RESP: - reg = R_BTC_BT_COEX_MSK_TABLE; - bitmap = B_BTC_PRI_MASK_TX_RESP_V1; - break; - case BTC_PRI_MASK_BEACON: - reg = R_AX_WL_PRI_MSK; - bitmap = B_AX_PTA_WL_PRI_MASK_BCNQ; - break; - case BTC_PRI_MASK_RX_CCK: - reg = R_BTC_BT_COEX_MSK_TABLE; - bitmap = B_BTC_PRI_MASK_RXCCK_V1; - break; - default: - return; - } - - if (state) - rtw89_write32_set(rtwdev, reg, bitmap); - else - rtw89_write32_clr(rtwdev, reg, bitmap); -} - union rtw8852b_btc_wl_txpwr_ctrl { u32 txpwr_val; struct { @@ -780,87 +700,6 @@ do { \ #undef __write_ctrl } -static -s8 rtw8852b_btc_get_bt_rssi(struct rtw89_dev *rtwdev, s8 val) -{ - /* +6 for compensate offset */ - return clamp_t(s8, val + 6, -100, 0) + 100; -} - -static -void rtw8852b_btc_update_bt_cnt(struct rtw89_dev *rtwdev) -{ - /* Feature move to firmware */ -} - -static void rtw8852b_btc_wl_s1_standby(struct rtw89_dev *rtwdev, bool state) -{ - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWE, RFREG_MASK, 0x80000); - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWA, RFREG_MASK, 0x1); - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD1, RFREG_MASK, 0x31); - - /* set WL standby = Rx for GNT_BT_Tx = 1->0 settle issue */ - if (state) - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x179); - else - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x20); - - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWE, RFREG_MASK, 0x0); -} - -static void rtw8852b_btc_set_wl_lna2(struct rtw89_dev *rtwdev, u8 level) -{ - switch (level) { - case 0: /* default */ - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWE, RFREG_MASK, 0x1000); - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWA, RFREG_MASK, 0x0); - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x15); - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWA, RFREG_MASK, 0x1); - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x17); - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWA, RFREG_MASK, 0x2); - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x15); - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWA, RFREG_MASK, 0x3); - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x17); - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWE, RFREG_MASK, 0x0); - break; - case 1: /* Fix LNA2=5 */ - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWE, RFREG_MASK, 0x1000); - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWA, RFREG_MASK, 0x0); - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x15); - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWA, RFREG_MASK, 0x1); - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x5); - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWA, RFREG_MASK, 0x2); - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x15); - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWA, RFREG_MASK, 0x3); - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x5); - rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWE, RFREG_MASK, 0x0); - break; - } -} - -static void rtw8852b_btc_set_wl_rx_gain(struct rtw89_dev *rtwdev, u32 level) -{ - struct rtw89_btc *btc = &rtwdev->btc; - - switch (level) { - case 0: /* original */ - default: - rtw8852bx_ctrl_nbtg_bt_tx(rtwdev, false, RTW89_PHY_0); - btc->dm.wl_lna2 = 0; - break; - case 1: /* for FDD free-run */ - rtw8852bx_ctrl_nbtg_bt_tx(rtwdev, true, RTW89_PHY_0); - btc->dm.wl_lna2 = 0; - break; - case 2: /* for BTG Co-Rx*/ - rtw8852bx_ctrl_nbtg_bt_tx(rtwdev, false, RTW89_PHY_0); - btc->dm.wl_lna2 = 1; - break; - } - - rtw8852b_btc_set_wl_lna2(rtwdev, btc->dm.wl_lna2); -} - static const struct rtw89_chip_ops rtw8852b_chip_ops = { .enable_bb_rf = rtw8852bx_mac_enable_bb_rf, .disable_bb_rf = rtw8852bx_mac_disable_bb_rf, @@ -911,13 +750,13 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .h2c_ba_cam = rtw89_fw_h2c_ba_cam, .btc_set_rfe = rtw8852b_btc_set_rfe, - .btc_init_cfg = rtw8852b_btc_init_cfg, - .btc_set_wl_pri = rtw8852b_btc_set_wl_pri, + .btc_init_cfg = rtw8852bx_btc_init_cfg, + .btc_set_wl_pri = rtw8852bx_btc_set_wl_pri, .btc_set_wl_txpwr_ctrl = rtw8852b_btc_set_wl_txpwr_ctrl, - .btc_get_bt_rssi = rtw8852b_btc_get_bt_rssi, - .btc_update_bt_cnt = rtw8852b_btc_update_bt_cnt, - .btc_wl_s1_standby = rtw8852b_btc_wl_s1_standby, - .btc_set_wl_rx_gain = rtw8852b_btc_set_wl_rx_gain, + .btc_get_bt_rssi = rtw8852bx_btc_get_bt_rssi, + .btc_update_bt_cnt = rtw8852bx_btc_update_bt_cnt, + .btc_wl_s1_standby = rtw8852bx_btc_wl_s1_standby, + .btc_set_wl_rx_gain = rtw8852bx_btc_set_wl_rx_gain, .btc_set_policy = rtw89_btc_set_policy_v1, }; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c index 60e9bd5b1376..f183dce16398 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c @@ -2,6 +2,7 @@ /* Copyright(c) 2024 Realtek Corporation */ +#include "coex.h" #include "debug.h" #include "mac.h" #include "phy.h" @@ -1749,6 +1750,167 @@ static u8 __rtw8852bx_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path r return rtw89_read_rf(rtwdev, rf_path, RR_TM, RR_TM_VAL); } +static +void rtw8852bx_set_trx_mask(struct rtw89_dev *rtwdev, u8 path, u8 group, u32 val) +{ + rtw89_write_rf(rtwdev, path, RR_LUTWE, RFREG_MASK, 0x20000); + rtw89_write_rf(rtwdev, path, RR_LUTWA, RFREG_MASK, group); + rtw89_write_rf(rtwdev, path, RR_LUTWD0, RFREG_MASK, val); + rtw89_write_rf(rtwdev, path, RR_LUTWE, RFREG_MASK, 0x0); +} + +static void __rtw8852bx_btc_init_cfg(struct rtw89_dev *rtwdev) +{ + struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_chip_info *chip = rtwdev->chip; + const struct rtw89_mac_ax_coex coex_params = { + .pta_mode = RTW89_MAC_AX_COEX_RTK_MODE, + .direction = RTW89_MAC_AX_COEX_INNER, + }; + + /* PTA init */ + rtw89_mac_coex_init(rtwdev, &coex_params); + + /* set WL Tx response = Hi-Pri */ + chip->ops->btc_set_wl_pri(rtwdev, BTC_PRI_MASK_TX_RESP, true); + chip->ops->btc_set_wl_pri(rtwdev, BTC_PRI_MASK_BEACON, true); + + /* set rf gnt debug off */ + rtw89_write_rf(rtwdev, RF_PATH_A, RR_WLSEL, RFREG_MASK, 0x0); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_WLSEL, RFREG_MASK, 0x0); + + /* set WL Tx thru in TRX mask table if GNT_WL = 0 && BT_S1 = ss group */ + if (btc->ant_type == BTC_ANT_SHARED) { + rtw8852bx_set_trx_mask(rtwdev, RF_PATH_A, BTC_BT_SS_GROUP, 0x5ff); + rtw8852bx_set_trx_mask(rtwdev, RF_PATH_B, BTC_BT_SS_GROUP, 0x5ff); + /* set path-A(S0) Tx/Rx no-mask if GNT_WL=0 && BT_S1=tx group */ + rtw8852bx_set_trx_mask(rtwdev, RF_PATH_A, BTC_BT_TX_GROUP, 0x5ff); + rtw8852bx_set_trx_mask(rtwdev, RF_PATH_B, BTC_BT_TX_GROUP, 0x55f); + } else { /* set WL Tx stb if GNT_WL = 0 && BT_S1 = ss group for 3-ant */ + rtw8852bx_set_trx_mask(rtwdev, RF_PATH_A, BTC_BT_SS_GROUP, 0x5df); + rtw8852bx_set_trx_mask(rtwdev, RF_PATH_B, BTC_BT_SS_GROUP, 0x5df); + rtw8852bx_set_trx_mask(rtwdev, RF_PATH_A, BTC_BT_TX_GROUP, 0x5ff); + rtw8852bx_set_trx_mask(rtwdev, RF_PATH_B, BTC_BT_TX_GROUP, 0x5ff); + } + + /* set PTA break table */ + rtw89_write32(rtwdev, R_BTC_BREAK_TABLE, BTC_BREAK_PARAM); + + /* enable BT counter 0xda40[16,2] = 2b'11 */ + rtw89_write32_set(rtwdev, R_AX_CSR_MODE, B_AX_BT_CNT_RST | B_AX_STATIS_BT_EN); + btc->cx.wl.status.map.init_ok = true; +} + +static +void __rtw8852bx_btc_set_wl_pri(struct rtw89_dev *rtwdev, u8 map, bool state) +{ + u32 bitmap; + u32 reg; + + switch (map) { + case BTC_PRI_MASK_TX_RESP: + reg = R_BTC_BT_COEX_MSK_TABLE; + bitmap = B_BTC_PRI_MASK_TX_RESP_V1; + break; + case BTC_PRI_MASK_BEACON: + reg = R_AX_WL_PRI_MSK; + bitmap = B_AX_PTA_WL_PRI_MASK_BCNQ; + break; + case BTC_PRI_MASK_RX_CCK: + reg = R_BTC_BT_COEX_MSK_TABLE; + bitmap = B_BTC_PRI_MASK_RXCCK_V1; + break; + default: + return; + } + + if (state) + rtw89_write32_set(rtwdev, reg, bitmap); + else + rtw89_write32_clr(rtwdev, reg, bitmap); +} + +static +s8 __rtw8852bx_btc_get_bt_rssi(struct rtw89_dev *rtwdev, s8 val) +{ + /* +6 for compensate offset */ + return clamp_t(s8, val + 6, -100, 0) + 100; +} + +static +void __rtw8852bx_btc_update_bt_cnt(struct rtw89_dev *rtwdev) +{ + /* Feature move to firmware */ +} + +static void __rtw8852bx_btc_wl_s1_standby(struct rtw89_dev *rtwdev, bool state) +{ + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWE, RFREG_MASK, 0x80000); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWA, RFREG_MASK, 0x1); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD1, RFREG_MASK, 0x31); + + /* set WL standby = Rx for GNT_BT_Tx = 1->0 settle issue */ + if (state) + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x179); + else + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x20); + + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWE, RFREG_MASK, 0x0); +} + +static void rtw8852bx_btc_set_wl_lna2(struct rtw89_dev *rtwdev, u8 level) +{ + switch (level) { + case 0: /* default */ + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWE, RFREG_MASK, 0x1000); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWA, RFREG_MASK, 0x0); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x15); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWA, RFREG_MASK, 0x1); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x17); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWA, RFREG_MASK, 0x2); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x15); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWA, RFREG_MASK, 0x3); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x17); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWE, RFREG_MASK, 0x0); + break; + case 1: /* Fix LNA2=5 */ + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWE, RFREG_MASK, 0x1000); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWA, RFREG_MASK, 0x0); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x15); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWA, RFREG_MASK, 0x1); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x5); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWA, RFREG_MASK, 0x2); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x15); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWA, RFREG_MASK, 0x3); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x5); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWE, RFREG_MASK, 0x0); + break; + } +} + +static void __rtw8852bx_btc_set_wl_rx_gain(struct rtw89_dev *rtwdev, u32 level) +{ + struct rtw89_btc *btc = &rtwdev->btc; + + switch (level) { + case 0: /* original */ + default: + rtw8852bx_ctrl_nbtg_bt_tx(rtwdev, false, RTW89_PHY_0); + btc->dm.wl_lna2 = 0; + break; + case 1: /* for FDD free-run */ + rtw8852bx_ctrl_nbtg_bt_tx(rtwdev, true, RTW89_PHY_0); + btc->dm.wl_lna2 = 0; + break; + case 2: /* for BTG Co-Rx*/ + rtw8852bx_ctrl_nbtg_bt_tx(rtwdev, false, RTW89_PHY_0); + btc->dm.wl_lna2 = 1; + break; + } + + rtw8852bx_btc_set_wl_lna2(rtwdev, btc->dm.wl_lna2); +} + static void rtw8852bx_fill_freq_with_ppdu(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu, struct ieee80211_rx_status *status) @@ -1872,6 +2034,12 @@ const struct rtw8852bx_info rtw8852bx_info = { .set_txpwr_ul_tb_offset = __rtw8852bx_set_txpwr_ul_tb_offset, .get_thermal = __rtw8852bx_get_thermal, .adc_cfg = rtw8852bt_adc_cfg, + .btc_init_cfg = __rtw8852bx_btc_init_cfg, + .btc_set_wl_pri = __rtw8852bx_btc_set_wl_pri, + .btc_get_bt_rssi = __rtw8852bx_btc_get_bt_rssi, + .btc_update_bt_cnt = __rtw8852bx_btc_update_bt_cnt, + .btc_wl_s1_standby = __rtw8852bx_btc_wl_s1_standby, + .btc_set_wl_rx_gain = __rtw8852bx_btc_set_wl_rx_gain, }; EXPORT_SYMBOL(rtw8852bx_info); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.h b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.h index b8e3f20ba189..801e7ab9f4fa 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.h @@ -159,6 +159,12 @@ struct rtw8852bx_info { s8 pw_ofst, enum rtw89_mac_idx mac_idx); u8 (*get_thermal)(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path); void (*adc_cfg)(struct rtw89_dev *rtwdev, u8 bw, u8 path); + void (*btc_init_cfg)(struct rtw89_dev *rtwdev); + void (*btc_set_wl_pri)(struct rtw89_dev *rtwdev, u8 map, bool state); + s8 (*btc_get_bt_rssi)(struct rtw89_dev *rtwdev, s8 val); + void (*btc_update_bt_cnt)(struct rtw89_dev *rtwdev); + void (*btc_wl_s1_standby)(struct rtw89_dev *rtwdev, bool state); + void (*btc_set_wl_rx_gain)(struct rtw89_dev *rtwdev, u32 level); }; extern const struct rtw8852bx_info rtw8852bx_info; @@ -343,4 +349,40 @@ void rtw8852bx_adc_cfg(struct rtw89_dev *rtwdev, u8 bw, u8 path) rtw8852bx_info.adc_cfg(rtwdev, bw, path); } +static inline +void rtw8852bx_btc_init_cfg(struct rtw89_dev *rtwdev) +{ + rtw8852bx_info.btc_init_cfg(rtwdev); +} + +static inline +void rtw8852bx_btc_set_wl_pri(struct rtw89_dev *rtwdev, u8 map, bool state) +{ + rtw8852bx_info.btc_set_wl_pri(rtwdev, map, state); +} + +static inline +s8 rtw8852bx_btc_get_bt_rssi(struct rtw89_dev *rtwdev, s8 val) +{ + return rtw8852bx_info.btc_get_bt_rssi(rtwdev, val); +} + +static inline +void rtw8852bx_btc_update_bt_cnt(struct rtw89_dev *rtwdev) +{ + rtw8852bx_info.btc_update_bt_cnt(rtwdev); +} + +static inline +void rtw8852bx_btc_wl_s1_standby(struct rtw89_dev *rtwdev, bool state) +{ + rtw8852bx_info.btc_wl_s1_standby(rtwdev, state); +} + +static inline +void rtw8852bx_btc_set_wl_rx_gain(struct rtw89_dev *rtwdev, u32 level) +{ + rtw8852bx_info.btc_set_wl_rx_gain(rtwdev, level); +} + #endif From 52bc83ad2ed5b115c33e3acc19cbf636dd2f37c9 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 1 Jul 2024 09:46:19 +0800 Subject: [PATCH 094/204] wifi: rtw89: 8852bx: add extra handles of BTC for 8852BT in 8852b_common For 8852BT, the initial settings of BT-coexistence is a little bit different, so add the extra handles. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240701014619.7300-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8852b_common.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c index f183dce16398..1745c2882acf 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c @@ -1793,6 +1793,11 @@ static void __rtw8852bx_btc_init_cfg(struct rtw89_dev *rtwdev) rtw8852bx_set_trx_mask(rtwdev, RF_PATH_B, BTC_BT_TX_GROUP, 0x5ff); } + if (rtwdev->chip->chip_id == RTL8852BT) { + rtw8852bx_set_trx_mask(rtwdev, RF_PATH_A, BTC_BT_RX_GROUP, 0x5df); + rtw8852bx_set_trx_mask(rtwdev, RF_PATH_B, BTC_BT_RX_GROUP, 0x5df); + } + /* set PTA break table */ rtw89_write32(rtwdev, R_BTC_BREAK_TABLE, BTC_BREAK_PARAM); From 1e71be6a344628d3a6041dfcf26220ad5d66e699 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 2 Jul 2024 20:44:51 +0800 Subject: [PATCH 095/204] wifi: rtw89: mac: parse MRC C2H failure report MRC (multi-role concurrency) has a C2H event for status report. Newer FW will report some kinds of failures. We parse them now and show by debug log. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240702124452.18747-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 40 ++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/mac.h | 10 ++++++ 2 files changed, 50 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 73462f3343e3..e2399796aeb1 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -5202,6 +5202,46 @@ rtw89_mac_c2h_mrc_status_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 case RTW89_MAC_MRC_DEL_SCH_OK: func = H2C_FUNC_DEL_MRC; break; + case RTW89_MAC_MRC_EMPTY_SCH_FAIL: + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MRC C2H STS RPT: empty sch fail\n"); + return; + case RTW89_MAC_MRC_ROLE_NOT_EXIST_FAIL: + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MRC C2H STS RPT: role not exist fail\n"); + return; + case RTW89_MAC_MRC_DATA_NOT_FOUND_FAIL: + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MRC C2H STS RPT: data not found fail\n"); + return; + case RTW89_MAC_MRC_GET_NEXT_SLOT_FAIL: + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MRC C2H STS RPT: get next slot fail\n"); + return; + case RTW89_MAC_MRC_ALT_ROLE_FAIL: + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MRC C2H STS RPT: alt role fail\n"); + return; + case RTW89_MAC_MRC_ADD_PSTIMER_FAIL: + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MRC C2H STS RPT: add ps timer fail\n"); + return; + case RTW89_MAC_MRC_MALLOC_FAIL: + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MRC C2H STS RPT: malloc fail\n"); + return; + case RTW89_MAC_MRC_SWITCH_CH_FAIL: + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MRC C2H STS RPT: switch ch fail\n"); + return; + case RTW89_MAC_MRC_TXNULL0_FAIL: + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MRC C2H STS RPT: tx null-0 fail\n"); + return; + case RTW89_MAC_MRC_PORT_FUNC_EN_FAIL: + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MRC C2H STS RPT: port func en fail\n"); + return; default: rtw89_debug(rtwdev, RTW89_DBG_CHAN, "invalid MRC C2H STS RPT: status %d\n", status); diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index cc9f914d440c..d5895516b3ed 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -466,6 +466,16 @@ enum rtw89_mac_mrc_status { RTW89_MAC_MRC_START_SCH_OK = 0, RTW89_MAC_MRC_STOP_SCH_OK = 1, RTW89_MAC_MRC_DEL_SCH_OK = 2, + RTW89_MAC_MRC_EMPTY_SCH_FAIL = 16, + RTW89_MAC_MRC_ROLE_NOT_EXIST_FAIL = 17, + RTW89_MAC_MRC_DATA_NOT_FOUND_FAIL = 18, + RTW89_MAC_MRC_GET_NEXT_SLOT_FAIL = 19, + RTW89_MAC_MRC_ALT_ROLE_FAIL = 20, + RTW89_MAC_MRC_ADD_PSTIMER_FAIL = 21, + RTW89_MAC_MRC_MALLOC_FAIL = 22, + RTW89_MAC_MRC_SWITCH_CH_FAIL = 23, + RTW89_MAC_MRC_TXNULL0_FAIL = 24, + RTW89_MAC_MRC_PORT_FUNC_EN_FAIL = 25, }; struct rtw89_mac_ax_coex { From 8095364696d38092f34bbd3989b1a73b180a3aaf Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 2 Jul 2024 20:44:52 +0800 Subject: [PATCH 096/204] wifi: rtw89: unify the selection logic of RFK table when MCC Driver will notify FW the target index of RFK table to use at some moments. When MCC (multi-channel concurrent), the correctness of the notification is especially important. We now unify the selection logic of RFK table as below among chips. 1. check each table if it matches target channel 2. check all tables if any is idle by iterating active channels 3. replace the first table if all are busy unexpectedly Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240702124452.18747-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 22 ++++++ drivers/net/wireless/realtek/rtw89/chan.h | 4 ++ drivers/net/wireless/realtek/rtw89/core.h | 7 +- drivers/net/wireless/realtek/rtw89/phy.c | 69 +++++++++++++++++++ drivers/net/wireless/realtek/rtw89/phy.h | 16 +++++ .../net/wireless/realtek/rtw89/rtw8852c_rfk.c | 32 +++------ .../net/wireless/realtek/rtw89/rtw8922a_rfk.c | 17 ++++- 7 files changed, 141 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 3b1997223cc5..7f90d93dcdc0 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -141,6 +141,28 @@ bool rtw89_assign_entity_chan(struct rtw89_dev *rtwdev, return band_changed; } +int rtw89_iterate_entity_chan(struct rtw89_dev *rtwdev, + int (*iterator)(const struct rtw89_chan *chan, + void *data), + void *data) +{ + struct rtw89_hal *hal = &rtwdev->hal; + const struct rtw89_chan *chan; + int ret; + u8 idx; + + lockdep_assert_held(&rtwdev->mutex); + + for_each_set_bit(idx, hal->entity_map, NUM_OF_RTW89_SUB_ENTITY) { + chan = rtw89_chan_get(rtwdev, idx); + ret = iterator(chan, data); + if (ret) + return ret; + } + + return 0; +} + static void __rtw89_config_entity_chandef(struct rtw89_dev *rtwdev, enum rtw89_sub_entity_idx idx, const struct cfg80211_chan_def *chandef, diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h index ffa412f281f3..5278ff8c513b 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.h +++ b/drivers/net/wireless/realtek/rtw89/chan.h @@ -78,6 +78,10 @@ void rtw89_chan_create(struct rtw89_chan *chan, u8 center_chan, u8 primary_chan, bool rtw89_assign_entity_chan(struct rtw89_dev *rtwdev, enum rtw89_sub_entity_idx idx, const struct rtw89_chan *new); +int rtw89_iterate_entity_chan(struct rtw89_dev *rtwdev, + int (*iterator)(const struct rtw89_chan *chan, + void *data), + void *data); void rtw89_config_entity_chandef(struct rtw89_dev *rtwdev, enum rtw89_sub_entity_idx idx, const struct cfg80211_chan_def *chandef); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 001da3ad149e..11fa003a9788 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4695,7 +4695,12 @@ struct rtw89_dack_info { bool msbk_timeout[RTW89_DACK_PATH_NR]; }; -#define RTW89_RFK_CHS_NR 3 +enum rtw89_rfk_chs_nrs { + __RTW89_RFK_CHS_NR_V0 = 2, + __RTW89_RFK_CHS_NR_V1 = 3, + + RTW89_RFK_CHS_NR = __RTW89_RFK_CHS_NR_V1, +}; struct rtw89_rfk_mcc_info { u8 ch[RTW89_RFK_CHS_NR]; diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index e025f0ed9f59..ad11d1414874 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -2,6 +2,7 @@ /* Copyright(c) 2019-2020 Realtek Corporation */ +#include "chan.h" #include "coex.h" #include "debug.h" #include "fw.h" @@ -6003,6 +6004,74 @@ void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif vif->cfg.aid, phy_idx); } +static bool rfk_chan_validate_desc(const struct rtw89_rfk_chan_desc *desc) +{ + return desc->ch != 0; +} + +static bool rfk_chan_is_equivalent(const struct rtw89_rfk_chan_desc *desc, + const struct rtw89_chan *chan) +{ + if (!rfk_chan_validate_desc(desc)) + return false; + + if (desc->ch != chan->channel) + return false; + + if (desc->has_band && desc->band != chan->band_type) + return false; + + if (desc->has_bw && desc->bw != chan->band_width) + return false; + + return true; +} + +struct rfk_chan_iter_data { + const struct rtw89_rfk_chan_desc desc; + unsigned int found; +}; + +static int rfk_chan_iter_search(const struct rtw89_chan *chan, void *data) +{ + struct rfk_chan_iter_data *iter_data = data; + + if (rfk_chan_is_equivalent(&iter_data->desc, chan)) + iter_data->found++; + + return 0; +} + +u8 rtw89_rfk_chan_lookup(struct rtw89_dev *rtwdev, + const struct rtw89_rfk_chan_desc *desc, u8 desc_nr, + const struct rtw89_chan *target_chan) +{ + int sel = -1; + u8 i; + + for (i = 0; i < desc_nr; i++) { + struct rfk_chan_iter_data iter_data = { + .desc = desc[i], + }; + + if (rfk_chan_is_equivalent(&desc[i], target_chan)) + return i; + + rtw89_iterate_entity_chan(rtwdev, rfk_chan_iter_search, &iter_data); + if (!iter_data.found && sel == -1) + sel = i; + } + + if (sel == -1) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "no idle rfk entry; force replace the first\n"); + sel = 0; + } + + return sel; +} +EXPORT_SYMBOL(rtw89_rfk_chan_lookup); + static void _rfk_write_rf(struct rtw89_dev *rtwdev, const struct rtw89_reg5_def *def) { diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 6e53ac9140fb..d8df553b9cb0 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -715,6 +715,19 @@ enum rtw89_phy_gain_band_be rtw89_subband_to_gain_band_be(enum rtw89_subband sub } } +struct rtw89_rfk_chan_desc { + /* desc is valid iff ch is non-zero */ + u8 ch; + + /* To avoid us from extending old chip code every time, each new + * field must be defined along with a bool flag in positivte way. + */ + bool has_band; + u8 band; + bool has_bw; + u8 bw; +}; + enum rtw89_rfk_flag { RTW89_RFK_F_WRF = 0, RTW89_RFK_F_WM = 1, @@ -950,5 +963,8 @@ enum rtw89_rf_path_bit rtw89_phy_get_kpath(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); enum rtw89_rf_path rtw89_phy_get_syn_sel(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +u8 rtw89_rfk_chan_lookup(struct rtw89_dev *rtwdev, + const struct rtw89_rfk_chan_desc *desc, u8 desc_nr, + const struct rtw89_chan *target_chan); #endif diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c index 654e3e5507cb..743f7014bf3e 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c @@ -4070,12 +4070,11 @@ void rtw8852c_set_channel_rf(struct rtw89_dev *rtwdev, void rtw8852c_mcc_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; - DECLARE_BITMAP(map, RTW89_IQK_CHS_NR) = {}; + struct rtw89_rfk_chan_desc desc[__RTW89_RFK_CHS_NR_V0] = {}; const struct rtw89_chan *chan; enum rtw89_entity_mode mode; u8 chan_idx; u8 idx; - u8 i; mode = rtw89_get_entity_mode(rtwdev); switch (mode) { @@ -4087,34 +4086,21 @@ void rtw8852c_mcc_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_i break; } - for (i = 0; i <= chan_idx; i++) { - chan = rtw89_chan_get(rtwdev, i); + chan = rtw89_chan_get(rtwdev, chan_idx); - for (idx = 0; idx < RTW89_IQK_CHS_NR; idx++) { - if (rfk_mcc->ch[idx] == chan->channel && - rfk_mcc->band[idx] == chan->band_type) { - if (i != chan_idx) { - set_bit(idx, map); - break; - } + for (idx = 0; idx < ARRAY_SIZE(desc); idx++) { + struct rtw89_rfk_chan_desc *p = &desc[idx]; - goto bottom; - } - } + p->ch = rfk_mcc->ch[idx]; + + p->has_band = true; + p->band = rfk_mcc->band[idx]; } - idx = find_first_zero_bit(map, RTW89_IQK_CHS_NR); - if (idx == RTW89_IQK_CHS_NR) { - rtw89_debug(rtwdev, RTW89_DBG_RFK, - "%s: no empty rfk table; force replace the first\n", - __func__); - idx = 0; - } + idx = rtw89_rfk_chan_lookup(rtwdev, desc, ARRAY_SIZE(desc), chan); rfk_mcc->ch[idx] = chan->channel; rfk_mcc->band[idx] = chan->band_type; - -bottom: rfk_mcc->table_idx = idx; } diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c index 2a371829268c..0ebcb06ae848 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c @@ -255,6 +255,7 @@ static void rtw8922a_chlk_ktbl_sel(struct rtw89_dev *rtwdev, u8 kpath, u8 idx) static void rtw8922a_chlk_reload(struct rtw89_dev *rtwdev) { struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + struct rtw89_rfk_chan_desc desc[__RTW89_RFK_CHS_NR_V1] = {}; enum rtw89_sub_entity_idx sub_entity_idx; const struct rtw89_chan *chan; enum rtw89_entity_mode mode; @@ -265,16 +266,28 @@ static void rtw8922a_chlk_reload(struct rtw89_dev *rtwdev) switch (mode) { case RTW89_ENTITY_MODE_MCC_PREPARE: sub_entity_idx = RTW89_SUB_ENTITY_1; - tbl_sel = 1; break; default: sub_entity_idx = RTW89_SUB_ENTITY_0; - tbl_sel = 0; break; } chan = rtw89_chan_get(rtwdev, sub_entity_idx); + for (tbl_sel = 0; tbl_sel < ARRAY_SIZE(desc); tbl_sel++) { + struct rtw89_rfk_chan_desc *p = &desc[tbl_sel]; + + p->ch = rfk_mcc->ch[tbl_sel]; + + p->has_band = true; + p->band = rfk_mcc->band[tbl_sel]; + + p->has_bw = true; + p->bw = rfk_mcc->bw[tbl_sel]; + } + + tbl_sel = rtw89_rfk_chan_lookup(rtwdev, desc, ARRAY_SIZE(desc), chan); + rfk_mcc->ch[tbl_sel] = chan->channel; rfk_mcc->band[tbl_sel] = chan->band_type; rfk_mcc->bw[tbl_sel] = chan->band_width; From a1e7eafd12c415a6ac2a65d8ddf32569acd1ecf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20L=C3=B6nnegren?= Date: Wed, 3 Jul 2024 09:06:23 +0200 Subject: [PATCH 097/204] wifi: rtlwifi: fix default typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change 'defult' to 'default' in comments in several rtlwifi drivers. Signed-off-by: Fredrik Lönnegren Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240703070627.135328-1-fredrik@frelon.se --- drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c index 37bb59fa8bfa..35875cda30fc 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c @@ -27,7 +27,7 @@ static void rtl88e_init_aspm_vars(struct ieee80211_hw *hw) * 2 - Enable ASPM with Clock Req, * 3 - Alwyas Enable ASPM with Clock Req, * 4 - Always Enable ASPM without Clock Req. - * set defult to RTL8192CE:3 RTL8192E:2 + * set default to RTL8192CE:3 RTL8192E:2 */ rtlpci->const_pci_aspm = 3; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c index e20f2bec45c4..ce7c28d9c874 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c @@ -31,7 +31,7 @@ static void rtl92c_init_aspm_vars(struct ieee80211_hw *hw) * 2 - Enable ASPM with Clock Req, * 3 - Alwyas Enable ASPM with Clock Req, * 4 - Always Enable ASPM without Clock Req. - * set defult to RTL8192CE:3 RTL8192E:2 + * set default to RTL8192CE:3 RTL8192E:2 * */ rtlpci->const_pci_aspm = 3; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c index f5ce4889523e..e36e4aeb9a95 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c @@ -32,7 +32,7 @@ static void rtl92d_init_aspm_vars(struct ieee80211_hw *hw) * 2 - Enable ASPM with Clock Req, * 3 - Alwyas Enable ASPM with Clock Req, * 4 - Always Enable ASPM without Clock Req. - * set defult to RTL8192CE:3 RTL8192E:2 + * set default to RTL8192CE:3 RTL8192E:2 * */ rtlpci->const_pci_aspm = 3; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c index 7bde20fdbeab..162e734d5b08 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c @@ -31,7 +31,7 @@ static void rtl92ee_init_aspm_vars(struct ieee80211_hw *hw) * 2 - Enable ASPM with Clock Req, * 3 - Alwyas Enable ASPM with Clock Req, * 4 - Always Enable ASPM without Clock Req. - * set defult to RTL8192CE:3 RTL8192E:2 + * set default to RTL8192CE:3 RTL8192E:2 */ rtlpci->const_pci_aspm = 3; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c index 675bdd32feb1..bbf8ff63dced 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c @@ -27,7 +27,7 @@ static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw) * 2 - Enable ASPM with Clock Req, * 3 - Alwyas Enable ASPM with Clock Req, * 4 - Always Enable ASPM without Clock Req. - * set defult to RTL8192CE:3 RTL8192E:2 + * set default to RTL8192CE:3 RTL8192E:2 * */ rtlpci->const_pci_aspm = 2; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c index dd7505e2f22c..1b144fbd4d26 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c @@ -33,7 +33,7 @@ static void rtl8723e_init_aspm_vars(struct ieee80211_hw *hw) * 2 - Enable ASPM with Clock Req, * 3 - Alwyas Enable ASPM with Clock Req, * 4 - Always Enable ASPM without Clock Req. - * set defult to RTL8192CE:3 RTL8192E:2 + * set default to RTL8192CE:3 RTL8192E:2 */ rtlpci->const_pci_aspm = 3; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c index 162c34f0e9b7..0a92d0325098 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c @@ -32,7 +32,7 @@ static void rtl8723be_init_aspm_vars(struct ieee80211_hw *hw) * 2 - Enable ASPM with Clock Req, * 3 - Alwyas Enable ASPM with Clock Req, * 4 - Always Enable ASPM without Clock Req. - * set defult to RTL8192CE:3 RTL8192E:2 + * set default to RTL8192CE:3 RTL8192E:2 */ rtlpci->const_pci_aspm = 3; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c index 7b911695db33..a65503c5ae5a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c @@ -30,7 +30,7 @@ static void rtl8821ae_init_aspm_vars(struct ieee80211_hw *hw) * 2 - Enable ASPM with Clock Req, * 3 - Alwyas Enable ASPM with Clock Req, * 4 - Always Enable ASPM without Clock Req. - * set defult to RTL8192CE:3 RTL8192E:2 + * set default to RTL8192CE:3 RTL8192E:2 */ rtlpci->const_pci_aspm = 3; From 85099c7ce4f9e64c66aa397cd9a37473637ab891 Mon Sep 17 00:00:00 2001 From: Aleksandr Mishin Date: Thu, 4 Jul 2024 00:05:10 +0300 Subject: [PATCH 098/204] wifi: rtw89: Fix array index mistake in rtw89_sta_info_get_iter() In rtw89_sta_info_get_iter() 'status->he_gi' is compared to array size. But then 'rate->he_gi' is used as array index instead of 'status->he_gi'. This can lead to go beyond array boundaries in case of 'rate->he_gi' is not equal to 'status->he_gi' and is bigger than array size. Looks like "copy-paste" mistake. Fix this mistake by replacing 'rate->he_gi' with 'status->he_gi'. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: e3ec7017f6a2 ("rtw89: add Realtek 802.11ax driver") Signed-off-by: Aleksandr Mishin Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20240703210510.11089-1-amishin@t-argos.ru --- drivers/net/wireless/realtek/rtw89/debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index 9cbf136aa2ac..9e1353cce9cc 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -3552,7 +3552,7 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta) case RX_ENC_HE: seq_printf(m, "HE %dSS MCS-%d GI:%s", status->nss, status->rate_idx, status->he_gi <= NL80211_RATE_INFO_HE_GI_3_2 ? - he_gi_str[rate->he_gi] : "N/A"); + he_gi_str[status->he_gi] : "N/A"); break; case RX_ENC_EHT: seq_printf(m, "EHT %dSS MCS-%d GI:%s", status->nss, status->rate_idx, From 34ce9c8b8ada0c03ea8f2a99fcc7a1b297ccaa95 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 2 Jul 2024 13:35:56 +0200 Subject: [PATCH 099/204] wifi: nl80211: split helper function from nl80211_put_iface_combinations Create a helper function that puts the data from struct ieee80211_iface_combination to a nl80211 message. This will be used for adding per-radio interface combination data. Signed-off-by: Felix Fietkau Link: https://patch.msgid.link/22a0eee19dbcf98627239328bc66decd3395122c.1719919832.git-series.nbd@nbd.name Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 113 ++++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 53 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 674368d028f3..deacd5f3f256 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1631,72 +1631,79 @@ static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes) return -ENOBUFS; } +static int nl80211_put_ifcomb_data(struct sk_buff *msg, bool large, int idx, + const struct ieee80211_iface_combination *c) +{ + struct nlattr *nl_combi, *nl_limits; + int i; + + nl_combi = nla_nest_start_noflag(msg, idx); + if (!nl_combi) + goto nla_put_failure; + + nl_limits = nla_nest_start_noflag(msg, NL80211_IFACE_COMB_LIMITS); + if (!nl_limits) + goto nla_put_failure; + + for (i = 0; i < c->n_limits; i++) { + struct nlattr *nl_limit; + + nl_limit = nla_nest_start_noflag(msg, i + 1); + if (!nl_limit) + goto nla_put_failure; + if (nla_put_u32(msg, NL80211_IFACE_LIMIT_MAX, c->limits[i].max)) + goto nla_put_failure; + if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES, + c->limits[i].types)) + goto nla_put_failure; + nla_nest_end(msg, nl_limit); + } + + nla_nest_end(msg, nl_limits); + + if (c->beacon_int_infra_match && + nla_put_flag(msg, NL80211_IFACE_COMB_STA_AP_BI_MATCH)) + goto nla_put_failure; + if (nla_put_u32(msg, NL80211_IFACE_COMB_NUM_CHANNELS, + c->num_different_channels) || + nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM, + c->max_interfaces)) + goto nla_put_failure; + if (large && + (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS, + c->radar_detect_widths) || + nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS, + c->radar_detect_regions))) + goto nla_put_failure; + if (c->beacon_int_min_gcd && + nla_put_u32(msg, NL80211_IFACE_COMB_BI_MIN_GCD, + c->beacon_int_min_gcd)) + goto nla_put_failure; + + nla_nest_end(msg, nl_combi); + + return 0; +nla_put_failure: + return -ENOBUFS; +} + static int nl80211_put_iface_combinations(struct wiphy *wiphy, struct sk_buff *msg, bool large) { struct nlattr *nl_combis; - int i, j; + int i; nl_combis = nla_nest_start_noflag(msg, NL80211_ATTR_INTERFACE_COMBINATIONS); if (!nl_combis) goto nla_put_failure; - for (i = 0; i < wiphy->n_iface_combinations; i++) { - const struct ieee80211_iface_combination *c; - struct nlattr *nl_combi, *nl_limits; - - c = &wiphy->iface_combinations[i]; - - nl_combi = nla_nest_start_noflag(msg, i + 1); - if (!nl_combi) + for (i = 0; i < wiphy->n_iface_combinations; i++) + if (nl80211_put_ifcomb_data(msg, large, i + 1, + &wiphy->iface_combinations[i])) goto nla_put_failure; - nl_limits = nla_nest_start_noflag(msg, - NL80211_IFACE_COMB_LIMITS); - if (!nl_limits) - goto nla_put_failure; - - for (j = 0; j < c->n_limits; j++) { - struct nlattr *nl_limit; - - nl_limit = nla_nest_start_noflag(msg, j + 1); - if (!nl_limit) - goto nla_put_failure; - if (nla_put_u32(msg, NL80211_IFACE_LIMIT_MAX, - c->limits[j].max)) - goto nla_put_failure; - if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES, - c->limits[j].types)) - goto nla_put_failure; - nla_nest_end(msg, nl_limit); - } - - nla_nest_end(msg, nl_limits); - - if (c->beacon_int_infra_match && - nla_put_flag(msg, NL80211_IFACE_COMB_STA_AP_BI_MATCH)) - goto nla_put_failure; - if (nla_put_u32(msg, NL80211_IFACE_COMB_NUM_CHANNELS, - c->num_different_channels) || - nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM, - c->max_interfaces)) - goto nla_put_failure; - if (large && - (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS, - c->radar_detect_widths) || - nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS, - c->radar_detect_regions))) - goto nla_put_failure; - if (c->beacon_int_min_gcd && - nla_put_u32(msg, NL80211_IFACE_COMB_BI_MIN_GCD, - c->beacon_int_min_gcd)) - goto nla_put_failure; - - nla_nest_end(msg, nl_combi); - } - nla_nest_end(msg, nl_combis); return 0; From 574e609c4e6a0843a9ed53de79e00da8fb3e7437 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 4 Jul 2024 15:09:47 +0200 Subject: [PATCH 100/204] wifi: mac80211: clear vif drv_priv after remove_interface when stopping Avoid reusing stale driver data when an interface is brought down and up again. In order to avoid having to duplicate the memset in every single driver, do it here. Signed-off-by: Felix Fietkau Link: https://patch.msgid.link/20240704130947.48609-1-nbd@nbd.name Signed-off-by: Johannes Berg --- net/mac80211/iface.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 6d969d9f1ac9..97aee0a1a39a 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -689,8 +689,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do fallthrough; default: - if (going_down) - drv_remove_interface(local, sdata); + if (!going_down) + break; + drv_remove_interface(local, sdata); + + /* Clear private driver data to prevent reuse */ + memset(sdata->vif.drv_priv, 0, local->hw.vif_data_size); } ieee80211_recalc_ps(local); From b5d14b0c6716fad7f0c94ac6e1d6f60a49f985c7 Mon Sep 17 00:00:00 2001 From: En-Wei Wu Date: Fri, 5 Jul 2024 10:37:56 +0800 Subject: [PATCH 101/204] wifi: virt_wifi: avoid reporting connection success with wrong SSID When user issues a connection with a different SSID than the one virt_wifi has advertised, the __cfg80211_connect_result() will trigger the warning: WARN_ON(bss_not_found). The issue is because the connection code in virt_wifi does not check the SSID from user space (it only checks the BSSID), and virt_wifi will call cfg80211_connect_result() with WLAN_STATUS_SUCCESS even if the SSID is different from the one virt_wifi has advertised. Eventually cfg80211 won't be able to find the cfg80211_bss and generate the warning. Fixed it by checking the SSID (from user space) in the connection code. Fixes: c7cdba31ed8b ("mac80211-next: rtnetlink wifi simulation device") Reported-by: syzbot+d6eb9cee2885ec06f5e3@syzkaller.appspotmail.com Signed-off-by: En-Wei Wu Link: https://patch.msgid.link/20240705023756.10954-1-en-wei.wu@canonical.com Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/virt_wifi.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/virtual/virt_wifi.c b/drivers/net/wireless/virtual/virt_wifi.c index 6a84ec58d618..d2271a7644a0 100644 --- a/drivers/net/wireless/virtual/virt_wifi.c +++ b/drivers/net/wireless/virtual/virt_wifi.c @@ -136,6 +136,8 @@ static struct ieee80211_supported_band band_5ghz = { /* Assigned at module init. Guaranteed locally-administered and unicast. */ static u8 fake_router_bssid[ETH_ALEN] __ro_after_init = {}; +#define VIRT_WIFI_SSID "VirtWifi" + static void virt_wifi_inform_bss(struct wiphy *wiphy) { u64 tsf = div_u64(ktime_get_boottime_ns(), 1000); @@ -146,8 +148,8 @@ static void virt_wifi_inform_bss(struct wiphy *wiphy) u8 ssid[8]; } __packed ssid = { .tag = WLAN_EID_SSID, - .len = 8, - .ssid = "VirtWifi", + .len = strlen(VIRT_WIFI_SSID), + .ssid = VIRT_WIFI_SSID, }; informed_bss = cfg80211_inform_bss(wiphy, &channel_5ghz, @@ -213,6 +215,8 @@ struct virt_wifi_netdev_priv { struct net_device *upperdev; u32 tx_packets; u32 tx_failed; + u32 connect_requested_ssid_len; + u8 connect_requested_ssid[IEEE80211_MAX_SSID_LEN]; u8 connect_requested_bss[ETH_ALEN]; bool is_up; bool is_connected; @@ -229,6 +233,12 @@ static int virt_wifi_connect(struct wiphy *wiphy, struct net_device *netdev, if (priv->being_deleted || !priv->is_up) return -EBUSY; + if (!sme->ssid) + return -EINVAL; + + priv->connect_requested_ssid_len = sme->ssid_len; + memcpy(priv->connect_requested_ssid, sme->ssid, sme->ssid_len); + could_schedule = schedule_delayed_work(&priv->connect, HZ * 2); if (!could_schedule) return -EBUSY; @@ -252,12 +262,15 @@ static void virt_wifi_connect_complete(struct work_struct *work) container_of(work, struct virt_wifi_netdev_priv, connect.work); u8 *requested_bss = priv->connect_requested_bss; bool right_addr = ether_addr_equal(requested_bss, fake_router_bssid); + bool right_ssid = priv->connect_requested_ssid_len == strlen(VIRT_WIFI_SSID) && + !memcmp(priv->connect_requested_ssid, VIRT_WIFI_SSID, + priv->connect_requested_ssid_len); u16 status = WLAN_STATUS_SUCCESS; if (is_zero_ether_addr(requested_bss)) requested_bss = NULL; - if (!priv->is_up || (requested_bss && !right_addr)) + if (!priv->is_up || (requested_bss && !right_addr) || !right_ssid) status = WLAN_STATUS_UNSPECIFIED_FAILURE; else priv->is_connected = true; From 7cd445635562a38c1e3534e3e691c25d2737be54 Mon Sep 17 00:00:00 2001 From: Michael-CY Lee Date: Fri, 5 Jul 2024 15:43:26 +0800 Subject: [PATCH 102/204] wifi: mac80211: cancel color change finalize work when link is stopped The color change finalize work might be called after the link is stopped, which might lead to a kernel crash. Signed-off-by: Michael-CY Lee Link: https://patch.msgid.link/20240705074326.11172-1-michael-cy.lee@mediatek.com Signed-off-by: Johannes Berg --- net/mac80211/link.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/mac80211/link.c b/net/mac80211/link.c index 2e6e92defbca..1a211b8d4057 100644 --- a/net/mac80211/link.c +++ b/net/mac80211/link.c @@ -71,6 +71,8 @@ void ieee80211_link_stop(struct ieee80211_link_data *link) ieee80211_mgd_stop_link(link); cancel_delayed_work_sync(&link->color_collision_detect_work); + wiphy_work_cancel(link->sdata->local->hw.wiphy, + &link->color_change_finalize_work); wiphy_work_cancel(link->sdata->local->hw.wiphy, &link->csa.finalize_work); ieee80211_link_release_channel(link); From 4044b23781104801f70c4a4ec3ca090730a161c5 Mon Sep 17 00:00:00 2001 From: Michael-CY Lee Date: Fri, 5 Jul 2024 15:43:46 +0800 Subject: [PATCH 103/204] wifi: mac80211: do not check BSS color collision in certain cases Do not check BSS color collision in following cases 1. already under a color change 2. color change is disabled Signed-off-by: Michael-CY Lee Link: https://patch.msgid.link/20240705074346.11228-1-michael-cy.lee@mediatek.com Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 0ff9062a130c..59ad24a71141 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3358,6 +3358,7 @@ static void ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx) { struct ieee80211_mgmt *mgmt = (void *)rx->skb->data; + struct ieee80211_bss_conf *bss_conf; const struct element *ie; size_t baselen; @@ -3368,7 +3369,9 @@ ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx) if (ieee80211_hw_check(&rx->local->hw, DETECTS_COLOR_COLLISION)) return; - if (rx->link->conf->csa_active) + bss_conf = rx->link->conf; + if (bss_conf->csa_active || bss_conf->color_change_active || + !bss_conf->he_bss_color.enabled) return; baselen = mgmt->u.beacon.variable - rx->skb->data; @@ -3380,7 +3383,6 @@ ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx) rx->skb->len - baselen); if (ie && ie->datalen >= sizeof(struct ieee80211_he_operation) && ie->datalen >= ieee80211_he_oper_size(ie->data + 1)) { - struct ieee80211_bss_conf *bss_conf = rx->link->conf; const struct ieee80211_he_operation *he_oper; u8 color; From b3603133d3b727b0b07a7094ab74cf27c8aee3bd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 5 Jul 2024 13:39:21 +0200 Subject: [PATCH 104/204] wifi: mac80211_hwsim: fix warning WARN_ON("string") will unconditionally trigger a warning, but not really do what it may look like. Use WARN(1, ...) instead and add the mode number as well. Signed-off-by: Johannes Berg Link: https://patch.msgid.link/20240705133921.a50aa5b15ece.I9a25b7448b0498c0c2e503986978dae165c8bdf8@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/mac80211_hwsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 8491eb32f760..d60c780d4e8a 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -3261,7 +3261,7 @@ static int mac80211_hwsim_switch_vif_chanctx(struct ieee80211_hw *hw, hwsim_clear_chanctx_magic(vifs[i].old_ctx); break; default: - WARN_ON("Invalid mode"); + WARN(1, "Invalid mode %d\n", mode); } } return 0; From 6e909f489191b365364e9d636dec33b5dfd4e5eb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 9 Jul 2024 08:34:09 +0200 Subject: [PATCH 105/204] wifi: virt_wifi: don't use strlen() in const context Looks like not all compilers allow strlen(constant) as a constant, so don't do that. Instead, revert back to defining the length as the first submission had it. Fixes: b5d14b0c6716 ("wifi: virt_wifi: avoid reporting connection success with wrong SSID") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202407090934.NnR1TUbW-lkp@intel.com/ Closes: https://lore.kernel.org/oe-kbuild-all/202407090944.mpwLHGt9-lkp@intel.com/ Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/virt_wifi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/virtual/virt_wifi.c b/drivers/net/wireless/virtual/virt_wifi.c index d2271a7644a0..4ee374080466 100644 --- a/drivers/net/wireless/virtual/virt_wifi.c +++ b/drivers/net/wireless/virtual/virt_wifi.c @@ -137,6 +137,7 @@ static struct ieee80211_supported_band band_5ghz = { static u8 fake_router_bssid[ETH_ALEN] __ro_after_init = {}; #define VIRT_WIFI_SSID "VirtWifi" +#define VIRT_WIFI_SSID_LEN 8 static void virt_wifi_inform_bss(struct wiphy *wiphy) { @@ -148,7 +149,7 @@ static void virt_wifi_inform_bss(struct wiphy *wiphy) u8 ssid[8]; } __packed ssid = { .tag = WLAN_EID_SSID, - .len = strlen(VIRT_WIFI_SSID), + .len = VIRT_WIFI_SSID_LEN, .ssid = VIRT_WIFI_SSID, }; @@ -262,7 +263,7 @@ static void virt_wifi_connect_complete(struct work_struct *work) container_of(work, struct virt_wifi_netdev_priv, connect.work); u8 *requested_bss = priv->connect_requested_bss; bool right_addr = ether_addr_equal(requested_bss, fake_router_bssid); - bool right_ssid = priv->connect_requested_ssid_len == strlen(VIRT_WIFI_SSID) && + bool right_ssid = priv->connect_requested_ssid_len == VIRT_WIFI_SSID_LEN && !memcmp(priv->connect_requested_ssid, VIRT_WIFI_SSID, priv->connect_requested_ssid_len); u16 status = WLAN_STATUS_SUCCESS; From 19b815ed71aadee9a2d31b7a700ef61ae8048010 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 9 Jul 2024 15:35:31 +0800 Subject: [PATCH 106/204] wifi: mac80211: chanctx emulation set CHANGE_CHANNEL when in_reconfig Chanctx emulation didn't info IEEE80211_CONF_CHANGE_CHANNEL to drivers during ieee80211_restart_hw (ieee80211_emulate_add_chanctx). It caused non-chanctx drivers to not stand on the correct channel after recovery. RX then behaved abnormally. Finally, disconnection/reconnection occurred. So, set IEEE80211_CONF_CHANGE_CHANNEL when in_reconfig. Signed-off-by: Zong-Zhe Yang Link: https://patch.msgid.link/20240709073531.30565-1-kevin_yang@realtek.com Cc: stable@vger.kernel.org Fixes: 0a44dfc07074 ("wifi: mac80211: simplify non-chanctx drivers") Signed-off-by: Johannes Berg --- net/mac80211/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 7578ea56c12f..85a267bdb3e3 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -148,7 +148,7 @@ static u32 ieee80211_calc_hw_conf_chan(struct ieee80211_local *local, offchannel_flag ^= local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; /* force it also for scanning, since drivers might config differently */ - if (offchannel_flag || local->scanning || + if (offchannel_flag || local->scanning || local->in_reconfig || !cfg80211_chandef_identical(&local->hw.conf.chandef, &chandef)) { local->hw.conf.chandef = chandef; changed |= IEEE80211_CONF_CHANGE_CHANNEL; From e6c06ca8f21d1cdb444c708e385d86a54bc5fc60 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 9 Jul 2024 10:38:30 +0200 Subject: [PATCH 107/204] wifi: cfg80211: add support for advertising multiple radios belonging to a wiphy The prerequisite for MLO support in cfg80211/mac80211 is that all the links participating in MLO must be from the same wiphy/ieee80211_hw. To meet this expectation, some drivers may need to group multiple discrete hardware each acting as a link in MLO under single wiphy. With this change, supported frequencies and interface combinations of each individual radio are reported to user space. This allows user space to figure out the limitations of what combination of channels can be used concurrently. Even for non-MLO devices, this improves support for devices capable of running on multiple channels at the same time. Signed-off-by: Felix Fietkau Link: https://patch.msgid.link/18a88f9ce82b1c9f7c12f1672430eaf2bb0be295.1720514221.git-series.nbd@nbd.name Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 42 ++++++++++++- include/uapi/linux/nl80211.h | 65 ++++++++++++++++++++ net/wireless/nl80211.c | 113 +++++++++++++++++++++++++++++++---- 3 files changed, 208 insertions(+), 12 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 6f992aff74ae..a00cf80e61dc 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5046,7 +5046,9 @@ struct ieee80211_iface_limit { * struct ieee80211_iface_combination - possible interface combination * * With this structure the driver can describe which interface - * combinations it supports concurrently. + * combinations it supports concurrently. When set in a struct wiphy_radio, + * the combinations refer to combinations of interfaces currently active on + * that radio. * * Examples: * @@ -5406,6 +5408,38 @@ struct wiphy_iftype_akm_suites { int n_akm_suites; }; +/** + * struct wiphy_radio_freq_range - wiphy frequency range + * @start_freq: start range edge frequency (kHz) + * @end_freq: end range edge frequency (kHz) + */ +struct wiphy_radio_freq_range { + u32 start_freq; + u32 end_freq; +}; + + +/** + * struct wiphy_radio - physical radio of a wiphy + * This structure describes a physical radio belonging to a wiphy. + * It is used to describe concurrent-channel capabilities. Only one channel + * can be active on the radio described by struct wiphy_radio. + * + * @freq_range: frequency range that the radio can operate on. + * @n_freq_range: number of elements in @freq_range + * + * @iface_combinations: Valid interface combinations array, should not + * list single interface types. + * @n_iface_combinations: number of entries in @iface_combinations array. + */ +struct wiphy_radio { + const struct wiphy_radio_freq_range *freq_range; + int n_freq_range; + + const struct ieee80211_iface_combination *iface_combinations; + int n_iface_combinations; +}; + #define CFG80211_HW_TIMESTAMP_ALL_PEERS 0xffff /** @@ -5624,6 +5658,9 @@ struct wiphy_iftype_akm_suites { * A value of %CFG80211_HW_TIMESTAMP_ALL_PEERS indicates the driver * supports enabling HW timestamping for all peers (i.e. no need to * specify a mac address). + * + * @radio: radios belonging to this wiphy + * @n_radio: number of radios */ struct wiphy { struct mutex mtx; @@ -5774,6 +5811,9 @@ struct wiphy { u16 hw_timestamp_max_peers; + int n_radio; + const struct wiphy_radio *radio; + char priv[] __aligned(NETDEV_ALIGN); }; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 6ae3997061b6..f97f5adc8d51 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2052,6 +2052,10 @@ enum nl80211_commands { * @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported * interface combinations. In each nested item, it contains attributes * defined in &enum nl80211_if_combination_attrs. + * If the wiphy uses multiple radios (@NL80211_ATTR_WIPHY_RADIOS is set), + * this attribute contains the interface combinations of the first radio. + * See @NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS for the global wiphy + * combinations for the sum of all radios. * @NL80211_ATTR_SOFTWARE_IFTYPES: Nested attribute (just like * %NL80211_ATTR_SUPPORTED_IFTYPES) containing the interface types that * are managed in software: interfaces of these types aren't subject to @@ -2856,6 +2860,14 @@ enum nl80211_commands { * %NL80211_CMD_ASSOCIATE indicating the SPP A-MSDUs * are used on this connection * + * @NL80211_ATTR_WIPHY_RADIOS: Nested attribute describing physical radios + * belonging to this wiphy. See &enum nl80211_wiphy_radio_attrs. + * + * @NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS: Nested attribute listing the + * supported interface combinations for all radios combined. In each + * nested item, it contains attributes defined in + * &enum nl80211_if_combination_attrs. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -3401,6 +3413,9 @@ enum nl80211_attrs { NL80211_ATTR_ASSOC_SPP_AMSDU, + NL80211_ATTR_WIPHY_RADIOS, + NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -8005,4 +8020,54 @@ enum nl80211_ap_settings_flags { NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT = 1 << 1, }; +/** + * enum nl80211_wiphy_radio_attrs - wiphy radio attributes + * + * @__NL80211_WIPHY_RADIO_ATTR_INVALID: Invalid + * + * @NL80211_WIPHY_RADIO_ATTR_INDEX: Index of this radio (u32) + * @NL80211_WIPHY_RADIO_ATTR_FREQ_RANGE: Frequency range supported by this + * radio. Attribute may be present multiple times. + * @NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION: Supported interface + * combination for this radio. Attribute may be present multiple times + * and contains attributes defined in &enum nl80211_if_combination_attrs. + * + * @__NL80211_WIPHY_RADIO_ATTR_LAST: Internal + * @NL80211_WIPHY_RADIO_ATTR_MAX: Highest attribute + */ +enum nl80211_wiphy_radio_attrs { + __NL80211_WIPHY_RADIO_ATTR_INVALID, + + NL80211_WIPHY_RADIO_ATTR_INDEX, + NL80211_WIPHY_RADIO_ATTR_FREQ_RANGE, + NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION, + + /* keep last */ + __NL80211_WIPHY_RADIO_ATTR_LAST, + NL80211_WIPHY_RADIO_ATTR_MAX = __NL80211_WIPHY_RADIO_ATTR_LAST - 1, +}; + +/** + * enum nl80211_wiphy_radio_freq_range - wiphy radio frequency range + * + * @__NL80211_WIPHY_RADIO_FREQ_ATTR_INVALID: Invalid + * + * @NL80211_WIPHY_RADIO_FREQ_ATTR_START: Frequency range start (u32). + * The unit is kHz. + * @NL80211_WIPHY_RADIO_FREQ_ATTR_END: Frequency range end (u32). + * The unit is kHz. + * + * @__NL80211_WIPHY_RADIO_FREQ_ATTR_LAST: Internal + * @NL80211_WIPHY_RADIO_FREQ_ATTR_MAX: Highest attribute + */ +enum nl80211_wiphy_radio_freq_range { + __NL80211_WIPHY_RADIO_FREQ_ATTR_INVALID, + + NL80211_WIPHY_RADIO_FREQ_ATTR_START, + NL80211_WIPHY_RADIO_FREQ_ATTR_END, + + __NL80211_WIPHY_RADIO_FREQ_ATTR_LAST, + NL80211_WIPHY_RADIO_FREQ_ATTR_MAX = __NL80211_WIPHY_RADIO_FREQ_ATTR_LAST - 1, +}; + #endif /* __LINUX_NL80211_H */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index deacd5f3f256..7397a372c78e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1632,16 +1632,18 @@ static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes) } static int nl80211_put_ifcomb_data(struct sk_buff *msg, bool large, int idx, - const struct ieee80211_iface_combination *c) + const struct ieee80211_iface_combination *c, + u16 nested) { struct nlattr *nl_combi, *nl_limits; int i; - nl_combi = nla_nest_start_noflag(msg, idx); + nl_combi = nla_nest_start_noflag(msg, idx | nested); if (!nl_combi) goto nla_put_failure; - nl_limits = nla_nest_start_noflag(msg, NL80211_IFACE_COMB_LIMITS); + nl_limits = nla_nest_start_noflag(msg, NL80211_IFACE_COMB_LIMITS | + nested); if (!nl_limits) goto nla_put_failure; @@ -1689,19 +1691,26 @@ static int nl80211_put_ifcomb_data(struct sk_buff *msg, bool large, int idx, static int nl80211_put_iface_combinations(struct wiphy *wiphy, struct sk_buff *msg, - bool large) + int attr, int radio, + bool large, u16 nested) { + const struct ieee80211_iface_combination *c; struct nlattr *nl_combis; - int i; + int i, n; - nl_combis = nla_nest_start_noflag(msg, - NL80211_ATTR_INTERFACE_COMBINATIONS); + nl_combis = nla_nest_start_noflag(msg, attr | nested); if (!nl_combis) goto nla_put_failure; - for (i = 0; i < wiphy->n_iface_combinations; i++) - if (nl80211_put_ifcomb_data(msg, large, i + 1, - &wiphy->iface_combinations[i])) + if (radio >= 0) { + c = wiphy->radio[0].iface_combinations; + n = wiphy->radio[0].n_iface_combinations; + } else { + c = wiphy->iface_combinations; + n = wiphy->n_iface_combinations; + } + for (i = 0; i < n; i++) + if (nl80211_put_ifcomb_data(msg, large, i + 1, &c[i], nested)) goto nla_put_failure; nla_nest_end(msg, nl_combis); @@ -2408,6 +2417,80 @@ static int nl80211_put_mbssid_support(struct wiphy *wiphy, struct sk_buff *msg) return -ENOBUFS; } +static int nl80211_put_radio(struct wiphy *wiphy, struct sk_buff *msg, int idx) +{ + const struct wiphy_radio *r = &wiphy->radio[idx]; + struct nlattr *radio, *freq; + int i; + + radio = nla_nest_start(msg, idx); + if (!radio) + return -ENOBUFS; + + if (nla_put_u32(msg, NL80211_WIPHY_RADIO_ATTR_INDEX, idx)) + goto nla_put_failure; + + for (i = 0; i < r->n_freq_range; i++) { + const struct wiphy_radio_freq_range *range = &r->freq_range[i]; + + freq = nla_nest_start(msg, NL80211_WIPHY_RADIO_ATTR_FREQ_RANGE); + if (!freq) + goto nla_put_failure; + + if (nla_put_u32(msg, NL80211_WIPHY_RADIO_FREQ_ATTR_START, + range->start_freq) || + nla_put_u32(msg, NL80211_WIPHY_RADIO_FREQ_ATTR_END, + range->end_freq)) + goto nla_put_failure; + + nla_nest_end(msg, freq); + } + + for (i = 0; i < r->n_iface_combinations; i++) + if (nl80211_put_ifcomb_data(msg, true, + NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION, + &r->iface_combinations[i], + NLA_F_NESTED)) + goto nla_put_failure; + + nla_nest_end(msg, radio); + + return 0; + +nla_put_failure: + return -ENOBUFS; +} + +static int nl80211_put_radios(struct wiphy *wiphy, struct sk_buff *msg) +{ + struct nlattr *radios; + int i; + + if (!wiphy->n_radio) + return 0; + + radios = nla_nest_start(msg, NL80211_ATTR_WIPHY_RADIOS); + if (!radios) + return -ENOBUFS; + + for (i = 0; i < wiphy->n_radio; i++) + if (nl80211_put_radio(wiphy, msg, i)) + goto fail; + + nla_nest_end(msg, radios); + + if (nl80211_put_iface_combinations(wiphy, msg, + NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS, + -1, true, NLA_F_NESTED)) + return -ENOBUFS; + + return 0; + +fail: + nla_nest_cancel(msg, radios); + return -ENOBUFS; +} + struct nl80211_dump_wiphy_state { s64 filter_wiphy; long start; @@ -2703,7 +2786,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, goto nla_put_failure; if (nl80211_put_iface_combinations(&rdev->wiphy, msg, - state->split)) + NL80211_ATTR_INTERFACE_COMBINATIONS, + rdev->wiphy.n_radio ? 0 : -1, + state->split, 0)) goto nla_put_failure; state->split_start++; @@ -3017,6 +3102,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, rdev->wiphy.hw_timestamp_max_peers)) goto nla_put_failure; + state->split_start++; + break; + case 17: + if (nl80211_put_radios(&rdev->wiphy, msg)) + goto nla_put_failure; + /* done */ state->split_start = 0; break; From abb4cfe3661aa05426916b21164f88ca5a405a3a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 9 Jul 2024 10:38:31 +0200 Subject: [PATCH 108/204] wifi: cfg80211: extend interface combination check for multi-radio Add a field in struct iface_combination_params to check per-radio interface combinations instead of per-wiphy ones. Signed-off-by: Felix Fietkau Link: https://patch.msgid.link/32b28da89c2d759b0324deeefe2be4cee91de18e.1720514221.git-series.nbd@nbd.name Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 5 +++++ net/mac80211/util.c | 5 ++++- net/wireless/rdev-ops.h | 12 ++++++++++++ net/wireless/util.c | 33 ++++++++++++++++++++++++++------- 4 files changed, 47 insertions(+), 8 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a00cf80e61dc..4767e2c76b01 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1598,6 +1598,7 @@ struct cfg80211_color_change_settings { * * Used to pass interface combination parameters * + * @radio_idx: wiphy radio index or -1 for global * @num_different_channels: the number of different channels we want * to use for verification * @radar_detect: a bitmap where each bit corresponds to a channel @@ -1611,6 +1612,7 @@ struct cfg80211_color_change_settings { * the verification */ struct iface_combination_params { + int radio_idx; int num_different_channels; u8 radar_detect; int iftype_num[NUM_NL80211_IFTYPES]; @@ -4580,6 +4582,8 @@ struct mgmt_frame_regs { * * @set_hw_timestamp: Enable/disable HW timestamping of TM/FTM frames. * @set_ttlm: set the TID to link mapping. + * @get_radio_mask: get bitmask of radios in use. + * (invoked with the wiphy mutex held) */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); @@ -4941,6 +4945,7 @@ struct cfg80211_ops { struct cfg80211_set_hw_timestamp *hwts); int (*set_ttlm)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ttlm_params *params); + u32 (*get_radio_mask)(struct wiphy *wiphy, struct net_device *dev); }; /* diff --git a/net/mac80211/util.c b/net/mac80211/util.c index c6d5f73119d8..27f0db2e9796 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -3944,6 +3944,7 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, int total = 1; struct iface_combination_params params = { .radar_detect = radar_detect, + .radio_idx = -1, }; lockdep_assert_wiphy(local->hw.wiphy); @@ -4034,7 +4035,9 @@ int ieee80211_max_num_channels(struct ieee80211_local *local) struct ieee80211_chanctx *ctx; u32 max_num_different_channels = 1; int err; - struct iface_combination_params params = {0}; + struct iface_combination_params params = { + .radio_idx = -1, + }; lockdep_assert_wiphy(local->hw.wiphy); diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 8f15658002ee..ec3f4aa1c807 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -1532,4 +1532,16 @@ rdev_set_ttlm(struct cfg80211_registered_device *rdev, return ret; } + +static inline u32 +rdev_get_radio_mask(struct cfg80211_registered_device *rdev, + struct net_device *dev) +{ + struct wiphy *wiphy = &rdev->wiphy; + + if (!rdev->ops->get_radio_mask) + return 0; + + return rdev->ops->get_radio_mask(wiphy, dev); +} #endif /* __CFG80211_RDEV_OPS */ diff --git a/net/wireless/util.c b/net/wireless/util.c index af6ec719567f..2492f259621f 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -2307,13 +2307,16 @@ static int cfg80211_wdev_bi(struct wireless_dev *wdev) static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int, u32 *beacon_int_gcd, - bool *beacon_int_different) + bool *beacon_int_different, + int radio_idx) { + struct cfg80211_registered_device *rdev; struct wireless_dev *wdev; *beacon_int_gcd = 0; *beacon_int_different = false; + rdev = wiphy_to_rdev(wiphy); list_for_each_entry(wdev, &wiphy->wdev_list, list) { int wdev_bi; @@ -2321,6 +2324,11 @@ static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int, if (wdev->valid_links) continue; + /* skip wdevs not active on the given wiphy radio */ + if (radio_idx >= 0 && + !(rdev_get_radio_mask(rdev, wdev->netdev) & BIT(radio_idx))) + continue; + wdev_bi = cfg80211_wdev_bi(wdev); if (!wdev_bi) @@ -2368,14 +2376,19 @@ int cfg80211_iter_combinations(struct wiphy *wiphy, void *data), void *data) { + const struct wiphy_radio *radio = NULL; + const struct ieee80211_iface_combination *c, *cs; const struct ieee80211_regdomain *regdom; enum nl80211_dfs_regions region = 0; - int i, j, iftype; + int i, j, n, iftype; int num_interfaces = 0; u32 used_iftypes = 0; u32 beacon_int_gcd; bool beacon_int_different; + if (params->radio_idx >= 0) + radio = &wiphy->radio[params->radio_idx]; + /* * This is a bit strange, since the iteration used to rely only on * the data given by the driver, but here it now relies on context, @@ -2387,7 +2400,8 @@ int cfg80211_iter_combinations(struct wiphy *wiphy, * interfaces (while being brought up) and channel/radar data. */ cfg80211_calculate_bi_data(wiphy, params->new_beacon_int, - &beacon_int_gcd, &beacon_int_different); + &beacon_int_gcd, &beacon_int_different, + params->radio_idx); if (params->radar_detect) { rcu_read_lock(); @@ -2404,13 +2418,18 @@ int cfg80211_iter_combinations(struct wiphy *wiphy, used_iftypes |= BIT(iftype); } - for (i = 0; i < wiphy->n_iface_combinations; i++) { - const struct ieee80211_iface_combination *c; + if (radio) { + cs = radio->iface_combinations; + n = radio->n_iface_combinations; + } else { + cs = wiphy->iface_combinations; + n = wiphy->n_iface_combinations; + } + for (i = 0; i < n; i++) { struct ieee80211_iface_limit *limits; u32 all_iftypes = 0; - c = &wiphy->iface_combinations[i]; - + c = &cs[i]; if (num_interfaces > c->max_interfaces) continue; if (params->num_different_channels > c->num_different_channels) From 510dba80ed669d6123901ccf0476706122b008b1 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 9 Jul 2024 10:38:32 +0200 Subject: [PATCH 109/204] wifi: cfg80211: add helper for checking if a chandef is valid on a radio Check if the full channel width is in the radio's frequency range. Signed-off-by: Felix Fietkau Link: https://patch.msgid.link/7c8ea146feb6f37cee62e5ba6be5370403695797.1720514221.git-series.nbd@nbd.name [add missing Return: documentation] Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 11 +++++++++++ net/wireless/util.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 4767e2c76b01..192d72c8b465 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -6508,6 +6508,17 @@ static inline bool cfg80211_channel_is_psc(struct ieee80211_channel *chan) return ieee80211_frequency_to_channel(chan->center_freq) % 16 == 5; } +/** + * cfg80211_radio_chandef_valid - Check if the radio supports the chandef + * + * @radio: wiphy radio + * @chandef: chandef for current channel + * + * Return: whether or not the given chandef is valid for the given radio + */ +bool cfg80211_radio_chandef_valid(const struct wiphy_radio *radio, + const struct cfg80211_chan_def *chandef); + /** * ieee80211_get_response_rate - get basic rate for a given rate * diff --git a/net/wireless/util.c b/net/wireless/util.c index 2492f259621f..9a7c3adc8a3b 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -2886,3 +2886,38 @@ cfg80211_get_iftype_ext_capa(struct wiphy *wiphy, enum nl80211_iftype type) return NULL; } EXPORT_SYMBOL(cfg80211_get_iftype_ext_capa); + +static bool +ieee80211_radio_freq_range_valid(const struct wiphy_radio *radio, + u32 freq, u32 width) +{ + const struct wiphy_radio_freq_range *r; + int i; + + for (i = 0; i < radio->n_freq_range; i++) { + r = &radio->freq_range[i]; + if (freq - width / 2 >= r->start_freq && + freq + width / 2 <= r->end_freq) + return true; + } + + return false; +} + +bool cfg80211_radio_chandef_valid(const struct wiphy_radio *radio, + const struct cfg80211_chan_def *chandef) +{ + u32 freq, width; + + freq = ieee80211_chandef_to_khz(chandef); + width = nl80211_chan_width_to_mhz(chandef->width); + if (!ieee80211_radio_freq_range_valid(radio, freq, width)) + return false; + + freq = MHZ_TO_KHZ(chandef->center_freq2); + if (freq && !ieee80211_radio_freq_range_valid(radio, freq, width)) + return false; + + return true; +} +EXPORT_SYMBOL(cfg80211_radio_chandef_valid); From a01b1e9f9955679fa04adead06c100022e313e55 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 9 Jul 2024 10:38:33 +0200 Subject: [PATCH 110/204] wifi: mac80211: add support for DFS with multiple radios DFS can be supported with multi-channel combinations, as long as each DFS capable radio only supports one channel. Signed-off-by: Felix Fietkau Link: https://patch.msgid.link/4d27a4adca99fa832af1f7cda4f2e71016bd9fda.1720514221.git-series.nbd@nbd.name Signed-off-by: Johannes Berg --- net/mac80211/main.c | 50 ++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 85a267bdb3e3..a3104b6ea6f0 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1091,6 +1091,27 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) return 0; } +static bool +ieee80211_ifcomb_check(const struct ieee80211_iface_combination *c, int n_comb) +{ + int i, j; + + for (i = 0; i < n_comb; i++, c++) { + /* DFS is not supported with multi-channel combinations yet */ + if (c->radar_detect_widths && + c->num_different_channels > 1) + return false; + + /* mac80211 doesn't support more than one IBSS interface */ + for (j = 0; j < c->n_limits; j++) + if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) && + c->limits[j].max > 1) + return false; + } + + return true; +} + int ieee80211_register_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); @@ -1177,17 +1198,20 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (comb->num_different_channels > 1) return -EINVAL; } - } else { - /* DFS is not supported with multi-channel combinations yet */ - for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { - const struct ieee80211_iface_combination *comb; + } - comb = &local->hw.wiphy->iface_combinations[i]; + if (hw->wiphy->n_radio) { + for (i = 0; i < hw->wiphy->n_radio; i++) { + const struct wiphy_radio *radio = &hw->wiphy->radio[i]; - if (comb->radar_detect_widths && - comb->num_different_channels > 1) + if (!ieee80211_ifcomb_check(radio->iface_combinations, + radio->n_iface_combinations)) return -EINVAL; } + } else { + if (!ieee80211_ifcomb_check(hw->wiphy->iface_combinations, + hw->wiphy->n_iface_combinations)) + return -EINVAL; } /* Only HW csum features are currently compatible with mac80211 */ @@ -1317,18 +1341,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR); - /* mac80211 doesn't support more than one IBSS interface right now */ - for (i = 0; i < hw->wiphy->n_iface_combinations; i++) { - const struct ieee80211_iface_combination *c; - int j; - - c = &hw->wiphy->iface_combinations[i]; - - for (j = 0; j < c->n_limits; j++) - if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) && - c->limits[j].max > 1) - return -EINVAL; - } local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + sizeof(void *) * channels, GFP_KERNEL); From 2920bc8d916d30b5273ec16e6878f13b24e3851f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 9 Jul 2024 10:38:34 +0200 Subject: [PATCH 111/204] wifi: mac80211: add radio index to ieee80211_chanctx_conf Will be used to explicitly assign a channel context to a wiphy radio. Signed-off-by: Felix Fietkau Link: https://patch.msgid.link/59f76f57d935f155099276be22badfa671d5bfd9.1720514221.git-series.nbd@nbd.name Signed-off-by: Johannes Berg --- include/net/mac80211.h | 2 ++ net/mac80211/chan.c | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index bd0f8aefa797..e78ccbe38d6d 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -250,6 +250,7 @@ struct ieee80211_chan_req { * @min_def: the minimum channel definition currently required. * @ap: the channel definition the AP actually is operating as, * for use with (wider bandwidth) OFDMA + * @radio_idx: index of the wiphy radio used used for this channel * @rx_chains_static: The number of RX chains that must always be * active on the channel to receive MIMO transmissions * @rx_chains_dynamic: The number of RX chains that must be enabled @@ -264,6 +265,7 @@ struct ieee80211_chanctx_conf { struct cfg80211_chan_def min_def; struct cfg80211_chan_def ap; + int radio_idx; u8 rx_chains_static, rx_chains_dynamic; bool radar_enabled; diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 06a65dc6f6c6..6c4d02cb07bb 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -656,7 +656,8 @@ ieee80211_chanctx_radar_required(struct ieee80211_local *local, static struct ieee80211_chanctx * ieee80211_alloc_chanctx(struct ieee80211_local *local, const struct ieee80211_chan_req *chanreq, - enum ieee80211_chanctx_mode mode) + enum ieee80211_chanctx_mode mode, + int radio_idx) { struct ieee80211_chanctx *ctx; @@ -674,6 +675,7 @@ ieee80211_alloc_chanctx(struct ieee80211_local *local, ctx->conf.rx_chains_dynamic = 1; ctx->mode = mode; ctx->conf.radar_enabled = false; + ctx->conf.radio_idx = radio_idx; _ieee80211_recalc_chanctx_min_def(local, ctx, NULL, false); return ctx; @@ -714,7 +716,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local, lockdep_assert_wiphy(local->hw.wiphy); - ctx = ieee80211_alloc_chanctx(local, chanreq, mode); + ctx = ieee80211_alloc_chanctx(local, chanreq, mode, -1); if (!ctx) return ERR_PTR(-ENOMEM); @@ -1155,7 +1157,7 @@ int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link, !list_empty(&curr_ctx->reserved_links)) return -EBUSY; - new_ctx = ieee80211_alloc_chanctx(local, chanreq, mode); + new_ctx = ieee80211_alloc_chanctx(local, chanreq, mode, -1); if (!new_ctx) return -ENOMEM; From 0874bcd0e1c97db0bada32df0934d5cf2507bedd Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 9 Jul 2024 10:38:35 +0200 Subject: [PATCH 112/204] wifi: mac80211: extend ifcomb check functions for multi-radio Add support for counting global and per-radio max/current number of channels, as well as checking radio-specific interface combinations. Signed-off-by: Felix Fietkau Link: https://patch.msgid.link/e76307f8ce562a91a74faab274ae01f6a5ba0a2e.1720514221.git-series.nbd@nbd.name Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 7 +- net/mac80211/chan.c | 17 +++-- net/mac80211/ibss.c | 2 +- net/mac80211/ieee80211_i.h | 5 +- net/mac80211/iface.c | 2 +- net/mac80211/util.c | 146 ++++++++++++++++++++++++------------- 6 files changed, 114 insertions(+), 65 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 3d49b3ee3a2b..85cb71de370f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -263,7 +263,7 @@ static int ieee80211_start_p2p_device(struct wiphy *wiphy, lockdep_assert_wiphy(sdata->local->hw.wiphy); - ret = ieee80211_check_combinations(sdata, NULL, 0, 0); + ret = ieee80211_check_combinations(sdata, NULL, 0, 0, -1); if (ret < 0) return ret; @@ -285,7 +285,7 @@ static int ieee80211_start_nan(struct wiphy *wiphy, lockdep_assert_wiphy(sdata->local->hw.wiphy); - ret = ieee80211_check_combinations(sdata, NULL, 0, 0); + ret = ieee80211_check_combinations(sdata, NULL, 0, 0, -1); if (ret < 0) return ret; @@ -4008,7 +4008,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, goto out; /* if reservation is invalid then this will fail */ - err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0); + err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0, -1); if (err) { ieee80211_link_unreserve_chanctx(link_data); goto out; @@ -5203,4 +5203,5 @@ const struct cfg80211_ops mac80211_config_ops = { .del_link_station = ieee80211_del_link_station, .set_hw_timestamp = ieee80211_set_hw_timestamp, .set_ttlm = ieee80211_set_ttlm, + .get_radio_mask = ieee80211_get_radio_mask, }; diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 6c4d02cb07bb..12bad02da561 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -47,24 +47,29 @@ int ieee80211_chanctx_refcount(struct ieee80211_local *local, ieee80211_chanctx_num_reserved(local, ctx); } -static int ieee80211_num_chanctx(struct ieee80211_local *local) +static int ieee80211_num_chanctx(struct ieee80211_local *local, int radio_idx) { struct ieee80211_chanctx *ctx; int num = 0; lockdep_assert_wiphy(local->hw.wiphy); - list_for_each_entry(ctx, &local->chanctx_list, list) + list_for_each_entry(ctx, &local->chanctx_list, list) { + if (radio_idx >= 0 && ctx->conf.radio_idx != radio_idx) + continue; num++; + } return num; } -static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local) +static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local, + int radio_idx) { lockdep_assert_wiphy(local->hw.wiphy); - return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local); + return ieee80211_num_chanctx(local, radio_idx) < + ieee80211_max_num_channels(local, radio_idx); } static struct ieee80211_chanctx * @@ -1101,7 +1106,7 @@ int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link, new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode); if (!new_ctx) { - if (ieee80211_can_create_new_chanctx(local)) { + if (ieee80211_can_create_new_chanctx(local, -1)) { new_ctx = ieee80211_new_chanctx(local, chanreq, mode, false); if (IS_ERR(new_ctx)) @@ -1822,7 +1827,7 @@ int _ieee80211_link_use_channel(struct ieee80211_link_data *link, link->radar_required = ret; ret = ieee80211_check_combinations(sdata, &chanreq->oper, mode, - radar_detect_width); + radar_detect_width, -1); if (ret < 0) goto out; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 7db4c3ee7e6d..3f74bbceeca5 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -1746,7 +1746,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, IEEE80211_CHANCTX_SHARED : IEEE80211_CHANCTX_EXCLUSIVE; ret = ieee80211_check_combinations(sdata, ¶ms->chandef, chanmode, - radar_detect_width); + radar_detect_width, -1); if (ret < 0) return ret; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6349552e62a8..a3485e4c6132 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2640,8 +2640,9 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local, int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, const struct cfg80211_chan_def *chandef, enum ieee80211_chanctx_mode chanmode, - u8 radar_detect); -int ieee80211_max_num_channels(struct ieee80211_local *local); + u8 radar_detect, int radio_idx); +int ieee80211_max_num_channels(struct ieee80211_local *local, int radio_idx); +u32 ieee80211_get_radio_mask(struct wiphy *wiphy, struct net_device *dev); void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, struct ieee80211_chanctx *ctx); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 97aee0a1a39a..b4ad66af3af3 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -397,7 +397,7 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, } } - return ieee80211_check_combinations(sdata, NULL, 0, 0); + return ieee80211_check_combinations(sdata, NULL, 0, 0, -1); } static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 27f0db2e9796..ced19ce7c51a 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -3932,20 +3932,103 @@ static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local, return radar_detect; } +static u32 +__ieee80211_get_radio_mask(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_bss_conf *link_conf; + struct ieee80211_chanctx_conf *conf; + unsigned int link_id; + u32 mask = 0; + + for_each_vif_active_link(&sdata->vif, link_conf, link_id) { + conf = sdata_dereference(link_conf->chanctx_conf, sdata); + if (!conf || conf->radio_idx < 0) + continue; + + mask |= BIT(conf->radio_idx); + } + + return mask; +} + +u32 ieee80211_get_radio_mask(struct wiphy *wiphy, struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + return __ieee80211_get_radio_mask(sdata); +} + +static bool +ieee80211_sdata_uses_radio(struct ieee80211_sub_if_data *sdata, int radio_idx) +{ + if (radio_idx < 0) + return true; + + return __ieee80211_get_radio_mask(sdata) & BIT(radio_idx); +} + +static int +ieee80211_fill_ifcomb_params(struct ieee80211_local *local, + struct iface_combination_params *params, + const struct cfg80211_chan_def *chandef, + struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_sub_if_data *sdata_iter; + struct ieee80211_chanctx *ctx; + int total = !!sdata; + + list_for_each_entry(ctx, &local->chanctx_list, list) { + if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) + continue; + + if (params->radio_idx >= 0 && + ctx->conf.radio_idx != params->radio_idx) + continue; + + params->radar_detect |= + ieee80211_chanctx_radar_detect(local, ctx); + + if (chandef && ctx->mode != IEEE80211_CHANCTX_EXCLUSIVE && + cfg80211_chandef_compatible(chandef, &ctx->conf.def)) + continue; + + params->num_different_channels++; + } + + list_for_each_entry(sdata_iter, &local->interfaces, list) { + struct wireless_dev *wdev_iter; + + wdev_iter = &sdata_iter->wdev; + + if (sdata_iter == sdata || + !ieee80211_sdata_running(sdata_iter) || + cfg80211_iftype_allowed(local->hw.wiphy, + wdev_iter->iftype, 0, 1)) + continue; + + if (!ieee80211_sdata_uses_radio(sdata_iter, params->radio_idx)) + continue; + + params->iftype_num[wdev_iter->iftype]++; + total++; + } + + return total; +} + int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, const struct cfg80211_chan_def *chandef, enum ieee80211_chanctx_mode chanmode, - u8 radar_detect) + u8 radar_detect, int radio_idx) { + bool shared = chanmode == IEEE80211_CHANCTX_SHARED; struct ieee80211_local *local = sdata->local; - struct ieee80211_sub_if_data *sdata_iter; enum nl80211_iftype iftype = sdata->wdev.iftype; - struct ieee80211_chanctx *ctx; - int total = 1; struct iface_combination_params params = { .radar_detect = radar_detect, - .radio_idx = -1, + .radio_idx = radio_idx, }; + int total; lockdep_assert_wiphy(local->hw.wiphy); @@ -3982,37 +4065,9 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, if (iftype != NL80211_IFTYPE_UNSPECIFIED) params.iftype_num[iftype] = 1; - list_for_each_entry(ctx, &local->chanctx_list, list) { - if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) - continue; - params.radar_detect |= - ieee80211_chanctx_radar_detect(local, ctx); - if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) { - params.num_different_channels++; - continue; - } - if (chandef && chanmode == IEEE80211_CHANCTX_SHARED && - cfg80211_chandef_compatible(chandef, - &ctx->conf.def)) - continue; - params.num_different_channels++; - } - - list_for_each_entry_rcu(sdata_iter, &local->interfaces, list) { - struct wireless_dev *wdev_iter; - - wdev_iter = &sdata_iter->wdev; - - if (sdata_iter == sdata || - !ieee80211_sdata_running(sdata_iter) || - cfg80211_iftype_allowed(local->hw.wiphy, - wdev_iter->iftype, 0, 1)) - continue; - - params.iftype_num[wdev_iter->iftype]++; - total++; - } - + total = ieee80211_fill_ifcomb_params(local, ¶ms, + shared ? chandef : NULL, + sdata); if (total == 1 && !params.radar_detect) return 0; @@ -4029,30 +4084,17 @@ ieee80211_iter_max_chans(const struct ieee80211_iface_combination *c, c->num_different_channels); } -int ieee80211_max_num_channels(struct ieee80211_local *local) +int ieee80211_max_num_channels(struct ieee80211_local *local, int radio_idx) { - struct ieee80211_sub_if_data *sdata; - struct ieee80211_chanctx *ctx; u32 max_num_different_channels = 1; int err; struct iface_combination_params params = { - .radio_idx = -1, + .radio_idx = radio_idx, }; lockdep_assert_wiphy(local->hw.wiphy); - list_for_each_entry(ctx, &local->chanctx_list, list) { - if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) - continue; - - params.num_different_channels++; - - params.radar_detect |= - ieee80211_chanctx_radar_detect(local, ctx); - } - - list_for_each_entry_rcu(sdata, &local->interfaces, list) - params.iftype_num[sdata->wdev.iftype]++; + ieee80211_fill_ifcomb_params(local, ¶ms, NULL, NULL); err = cfg80211_iter_combinations(local->hw.wiphy, ¶ms, ieee80211_iter_max_chans, From 6265c67f2668047c97834c5c434f6abcf86e3406 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 9 Jul 2024 10:38:36 +0200 Subject: [PATCH 113/204] wifi: mac80211: move code in ieee80211_link_reserve_chanctx to a helper Reduces indentation in preparation for further changes Signed-off-by: Felix Fietkau Link: https://patch.msgid.link/cce95007092336254d51570f4a27e05a6f150a53.1720514221.git-series.nbd@nbd.name Signed-off-by: Johannes Berg --- net/mac80211/chan.c | 141 ++++++++++++++++++++++---------------------- 1 file changed, 72 insertions(+), 69 deletions(-) diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 12bad02da561..9aa3b9e25228 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -1089,6 +1089,71 @@ int ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link) return 0; } +static struct ieee80211_chanctx * +ieee80211_replace_chanctx(struct ieee80211_local *local, + const struct ieee80211_chan_req *chanreq, + enum ieee80211_chanctx_mode mode, + struct ieee80211_chanctx *curr_ctx) +{ + struct ieee80211_chanctx *new_ctx, *ctx; + + if (!curr_ctx || (curr_ctx->replace_state == + IEEE80211_CHANCTX_WILL_BE_REPLACED) || + !list_empty(&curr_ctx->reserved_links)) { + /* + * Another link already requested this context for a + * reservation. Find another one hoping all links assigned + * to it will also switch soon enough. + * + * TODO: This needs a little more work as some cases + * (more than 2 chanctx capable devices) may fail which could + * otherwise succeed provided some channel context juggling was + * performed. + * + * Consider ctx1..3, link1..6, each ctx has 2 links. link1 and + * link2 from ctx1 request new different chandefs starting 2 + * in-place reserations with ctx4 and ctx5 replacing ctx1 and + * ctx2 respectively. Next link5 and link6 from ctx3 reserve + * ctx4. If link3 and link4 remain on ctx2 as they are then this + * fails unless `replace_ctx` from ctx5 is replaced with ctx3. + */ + list_for_each_entry(ctx, &local->chanctx_list, list) { + if (ctx->replace_state != + IEEE80211_CHANCTX_REPLACE_NONE) + continue; + + if (!list_empty(&ctx->reserved_links)) + continue; + + curr_ctx = ctx; + break; + } + } + + /* + * If that's true then all available contexts already have reservations + * and cannot be used. + */ + if (!curr_ctx || (curr_ctx->replace_state == + IEEE80211_CHANCTX_WILL_BE_REPLACED) || + !list_empty(&curr_ctx->reserved_links)) + return ERR_PTR(-EBUSY); + + new_ctx = ieee80211_alloc_chanctx(local, chanreq, mode, -1); + if (!new_ctx) + return ERR_PTR(-ENOMEM); + + new_ctx->replace_ctx = curr_ctx; + new_ctx->replace_state = IEEE80211_CHANCTX_REPLACES_OTHER; + + curr_ctx->replace_ctx = new_ctx; + curr_ctx->replace_state = IEEE80211_CHANCTX_WILL_BE_REPLACED; + + list_add_rcu(&new_ctx->list, &local->chanctx_list); + + return new_ctx; +} + int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link, const struct ieee80211_chan_req *chanreq, enum ieee80211_chanctx_mode mode, @@ -1096,7 +1161,7 @@ int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link, { struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_local *local = sdata->local; - struct ieee80211_chanctx *new_ctx, *curr_ctx, *ctx; + struct ieee80211_chanctx *new_ctx, *curr_ctx; lockdep_assert_wiphy(local->hw.wiphy); @@ -1106,76 +1171,14 @@ int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link, new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode); if (!new_ctx) { - if (ieee80211_can_create_new_chanctx(local, -1)) { + if (ieee80211_can_create_new_chanctx(local, -1)) new_ctx = ieee80211_new_chanctx(local, chanreq, mode, false); - if (IS_ERR(new_ctx)) - return PTR_ERR(new_ctx); - } else { - if (!curr_ctx || - (curr_ctx->replace_state == - IEEE80211_CHANCTX_WILL_BE_REPLACED) || - !list_empty(&curr_ctx->reserved_links)) { - /* - * Another link already requested this context - * for a reservation. Find another one hoping - * all links assigned to it will also switch - * soon enough. - * - * TODO: This needs a little more work as some - * cases (more than 2 chanctx capable devices) - * may fail which could otherwise succeed - * provided some channel context juggling was - * performed. - * - * Consider ctx1..3, link1..6, each ctx has 2 - * links. link1 and link2 from ctx1 request new - * different chandefs starting 2 in-place - * reserations with ctx4 and ctx5 replacing - * ctx1 and ctx2 respectively. Next link5 and - * link6 from ctx3 reserve ctx4. If link3 and - * link4 remain on ctx2 as they are then this - * fails unless `replace_ctx` from ctx5 is - * replaced with ctx3. - */ - list_for_each_entry(ctx, &local->chanctx_list, - list) { - if (ctx->replace_state != - IEEE80211_CHANCTX_REPLACE_NONE) - continue; - - if (!list_empty(&ctx->reserved_links)) - continue; - - curr_ctx = ctx; - break; - } - } - - /* - * If that's true then all available contexts already - * have reservations and cannot be used. - */ - if (!curr_ctx || - (curr_ctx->replace_state == - IEEE80211_CHANCTX_WILL_BE_REPLACED) || - !list_empty(&curr_ctx->reserved_links)) - return -EBUSY; - - new_ctx = ieee80211_alloc_chanctx(local, chanreq, mode, -1); - if (!new_ctx) - return -ENOMEM; - - new_ctx->replace_ctx = curr_ctx; - new_ctx->replace_state = - IEEE80211_CHANCTX_REPLACES_OTHER; - - curr_ctx->replace_ctx = new_ctx; - curr_ctx->replace_state = - IEEE80211_CHANCTX_WILL_BE_REPLACED; - - list_add_rcu(&new_ctx->list, &local->chanctx_list); - } + else + new_ctx = ieee80211_replace_chanctx(local, chanreq, + mode, curr_ctx); + if (IS_ERR(new_ctx)) + return PTR_ERR(new_ctx); } list_add(&link->reserved_chanctx_list, &new_ctx->reserved_links); From 27d4c03441eb951142c79fff0a25dd8ba3263875 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 9 Jul 2024 10:38:37 +0200 Subject: [PATCH 114/204] wifi: mac80211: add wiphy radio assignment and validation Validate number of channels and interface combinations per radio. Assign each channel context to a radio. Signed-off-by: Felix Fietkau Link: https://patch.msgid.link/1d3e9ba70a30ce18aaff337f0a76d7aeb311bafb.1720514221.git-series.nbd@nbd.name Signed-off-by: Johannes Berg --- net/mac80211/chan.c | 52 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 9aa3b9e25228..e8567723e94d 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -714,14 +714,15 @@ static struct ieee80211_chanctx * ieee80211_new_chanctx(struct ieee80211_local *local, const struct ieee80211_chan_req *chanreq, enum ieee80211_chanctx_mode mode, - bool assign_on_failure) + bool assign_on_failure, + int radio_idx) { struct ieee80211_chanctx *ctx; int err; lockdep_assert_wiphy(local->hw.wiphy); - ctx = ieee80211_alloc_chanctx(local, chanreq, mode, -1); + ctx = ieee80211_alloc_chanctx(local, chanreq, mode, radio_idx); if (!ctx) return ERR_PTR(-ENOMEM); @@ -1096,6 +1097,8 @@ ieee80211_replace_chanctx(struct ieee80211_local *local, struct ieee80211_chanctx *curr_ctx) { struct ieee80211_chanctx *new_ctx, *ctx; + struct wiphy *wiphy = local->hw.wiphy; + const struct wiphy_radio *radio; if (!curr_ctx || (curr_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) || @@ -1125,6 +1128,12 @@ ieee80211_replace_chanctx(struct ieee80211_local *local, if (!list_empty(&ctx->reserved_links)) continue; + if (ctx->conf.radio_idx >= 0) { + radio = &wiphy->radio[ctx->conf.radio_idx]; + if (!cfg80211_radio_chandef_valid(radio, &chanreq->oper)) + continue; + } + curr_ctx = ctx; break; } @@ -1154,6 +1163,34 @@ ieee80211_replace_chanctx(struct ieee80211_local *local, return new_ctx; } +static bool +ieee80211_find_available_radio(struct ieee80211_local *local, + const struct ieee80211_chan_req *chanreq, + int *radio_idx) +{ + struct wiphy *wiphy = local->hw.wiphy; + const struct wiphy_radio *radio; + int i; + + *radio_idx = -1; + if (!wiphy->n_radio) + return true; + + for (i = 0; i < wiphy->n_radio; i++) { + radio = &wiphy->radio[i]; + if (!cfg80211_radio_chandef_valid(radio, &chanreq->oper)) + continue; + + if (!ieee80211_can_create_new_chanctx(local, i)) + continue; + + *radio_idx = i; + return true; + } + + return false; +} + int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link, const struct ieee80211_chan_req *chanreq, enum ieee80211_chanctx_mode mode, @@ -1162,6 +1199,7 @@ int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link, struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx *new_ctx, *curr_ctx; + int radio_idx; lockdep_assert_wiphy(local->hw.wiphy); @@ -1171,9 +1209,10 @@ int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link, new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode); if (!new_ctx) { - if (ieee80211_can_create_new_chanctx(local, -1)) + if (ieee80211_can_create_new_chanctx(local, -1) && + ieee80211_find_available_radio(local, chanreq, &radio_idx)) new_ctx = ieee80211_new_chanctx(local, chanreq, mode, - false); + false, radio_idx); else new_ctx = ieee80211_replace_chanctx(local, chanreq, mode, curr_ctx); @@ -1810,6 +1849,7 @@ int _ieee80211_link_use_channel(struct ieee80211_link_data *link, struct ieee80211_chanctx *ctx; u8 radar_detect_width = 0; bool reserved = false; + int radio_idx; int ret; lockdep_assert_wiphy(local->hw.wiphy); @@ -1840,9 +1880,11 @@ int _ieee80211_link_use_channel(struct ieee80211_link_data *link, /* Note: context is now reserved */ if (ctx) reserved = true; + else if (!ieee80211_find_available_radio(local, chanreq, &radio_idx)) + ctx = ERR_PTR(-EBUSY); else ctx = ieee80211_new_chanctx(local, chanreq, mode, - assign_on_failure); + assign_on_failure, radio_idx); if (IS_ERR(ctx)) { ret = PTR_ERR(ctx); goto out; From d2601e34a1024cb2466e6bd13bd943e19fd54fa6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 9 Jul 2024 10:38:38 +0200 Subject: [PATCH 115/204] wifi: mac80211_hwsim: add support for multi-radio wiphy This registers one wiphy radio per supported band. Number of different channels is set per radio. Signed-off-by: Felix Fietkau Link: https://patch.msgid.link/3a16838bb7a7d1a072bd7c9d586d17f70fcd8a60.1720514221.git-series.nbd@nbd.name Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/mac80211_hwsim.c | 74 ++++++++++++++++--- drivers/net/wireless/virtual/mac80211_hwsim.h | 4 + 2 files changed, 67 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index d60c780d4e8a..714e1f04b0cb 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -69,6 +69,10 @@ static bool mlo; module_param(mlo, bool, 0444); MODULE_PARM_DESC(mlo, "Support MLO"); +static bool multi_radio; +module_param(multi_radio, bool, 0444); +MODULE_PARM_DESC(mlo, "Support Multiple Radios per wiphy"); + /** * enum hwsim_regtest - the type of regulatory tests we offer * @@ -669,6 +673,10 @@ struct mac80211_hwsim_data { struct ieee80211_iface_limit if_limits[3]; int n_if_limits; + struct ieee80211_iface_combination if_combination_radio; + struct wiphy_radio_freq_range radio_range[NUM_NL80211_BANDS]; + struct wiphy_radio radio[NUM_NL80211_BANDS]; + u32 ciphers[ARRAY_SIZE(hwsim_ciphers)]; struct mac_address addresses[2]; @@ -917,6 +925,7 @@ static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { [HWSIM_ATTR_MLO_SUPPORT] = { .type = NLA_FLAG }, [HWSIM_ATTR_PMSR_SUPPORT] = NLA_POLICY_NESTED(hwsim_pmsr_capa_policy), [HWSIM_ATTR_PMSR_RESULT] = NLA_POLICY_NESTED(hwsim_pmsr_peers_result_policy), + [HWSIM_ATTR_MULTI_RADIO] = { .type = NLA_FLAG }, }; #if IS_REACHABLE(CONFIG_VIRTIO) @@ -4018,6 +4027,7 @@ struct hwsim_new_radio_params { bool reg_strict; bool p2p_device; bool use_chanctx; + bool multi_radio; bool destroy_on_close; const char *hwname; bool no_vif; @@ -4094,6 +4104,12 @@ static int append_radio_msg(struct sk_buff *skb, int id, return ret; } + if (param->multi_radio) { + ret = nla_put_flag(skb, HWSIM_ATTR_MULTI_RADIO); + if (ret < 0) + return ret; + } + if (param->hwname) { ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, strlen(param->hwname), param->hwname); @@ -5114,6 +5130,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, struct net *net; int idx, i; int n_limits = 0; + int n_bands = 0; if (WARN_ON(param->channels > 1 && !param->use_chanctx)) return -EINVAL; @@ -5217,22 +5234,22 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, n_limits++; } + data->if_combination.radar_detect_widths = + BIT(NL80211_CHAN_WIDTH_5) | + BIT(NL80211_CHAN_WIDTH_10) | + 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); + if (data->use_chanctx) { hw->wiphy->max_scan_ssids = 255; hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; hw->wiphy->max_remain_on_channel_duration = 1000; - data->if_combination.radar_detect_widths = 0; data->if_combination.num_different_channels = data->channels; } else { data->if_combination.num_different_channels = 1; - data->if_combination.radar_detect_widths = - BIT(NL80211_CHAN_WIDTH_5) | - BIT(NL80211_CHAN_WIDTH_10) | - 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); } if (!n_limits) { @@ -5350,6 +5367,9 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) { struct ieee80211_supported_band *sband = &data->bands[band]; + struct wiphy_radio_freq_range *radio_range; + const struct ieee80211_channel *c; + struct wiphy_radio *radio; sband->band = band; @@ -5423,8 +5443,36 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, mac80211_hwsim_sband_capab(sband); hw->wiphy->bands[band] = sband; + + if (!param->multi_radio) + continue; + + c = sband->channels; + radio_range = &data->radio_range[n_bands]; + radio_range->start_freq = ieee80211_channel_to_khz(c) - 10000; + + c += sband->n_channels - 1; + radio_range->end_freq = ieee80211_channel_to_khz(c) + 10000; + + radio = &data->radio[n_bands++]; + radio->freq_range = radio_range; + radio->n_freq_range = 1; + radio->iface_combinations = &data->if_combination_radio; + radio->n_iface_combinations = 1; } + if (param->multi_radio) { + hw->wiphy->radio = data->radio; + hw->wiphy->n_radio = n_bands; + + memcpy(&data->if_combination_radio, &data->if_combination, + sizeof(data->if_combination)); + data->if_combination.num_different_channels *= n_bands; + } + + if (data->use_chanctx) + data->if_combination.radar_detect_widths = 0; + /* By default all radios belong to the first group */ data->group = 1; mutex_init(&data->mutex); @@ -6042,6 +6090,9 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info) else param.use_chanctx = (param.channels > 1); + if (info->attrs[HWSIM_ATTR_MULTI_RADIO]) + param.multi_radio = true; + if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]) param.reg_alpha2 = nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]); @@ -6122,7 +6173,7 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info) param.mlo = info->attrs[HWSIM_ATTR_MLO_SUPPORT]; - if (param.mlo) + if (param.mlo || param.multi_radio) param.use_chanctx = true; if (info->attrs[HWSIM_ATTR_RADIO_NAME]) { @@ -6815,7 +6866,8 @@ static int __init init_mac80211_hwsim(void) param.p2p_device = support_p2p_device; param.mlo = mlo; - param.use_chanctx = channels > 1 || mlo; + param.multi_radio = multi_radio; + param.use_chanctx = channels > 1 || mlo || multi_radio; param.iftypes = HWSIM_IFTYPE_SUPPORT_MASK; if (param.p2p_device) param.iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE); diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.h b/drivers/net/wireless/virtual/mac80211_hwsim.h index 28c1db482e79..f32fc3a492b0 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.h +++ b/drivers/net/wireless/virtual/mac80211_hwsim.h @@ -157,6 +157,9 @@ enum hwsim_commands { * to provide details about peer measurement request (nl80211_peer_measurement_attrs) * @HWSIM_ATTR_PMSR_RESULT: nested attributed used with %HWSIM_CMD_REPORT_PMSR * to provide peer measurement result (nl80211_peer_measurement_attrs) + * @HWSIM_ATTR_MULTI_RADIO: Register multiple wiphy radios (flag). + * Adds one radio for each band. Number of supported channels will be set for + * each radio instead of for the wiphy. * @__HWSIM_ATTR_MAX: enum limit */ enum hwsim_attrs { @@ -189,6 +192,7 @@ enum hwsim_attrs { HWSIM_ATTR_PMSR_SUPPORT, HWSIM_ATTR_PMSR_REQUEST, HWSIM_ATTR_PMSR_RESULT, + HWSIM_ATTR_MULTI_RADIO, __HWSIM_ATTR_MAX, }; #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1) From c145eea2f75ff7949392aebecf7ef0a81c1f6c14 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 3 Jul 2024 09:24:09 +0200 Subject: [PATCH 116/204] wifi: mwifiex: Do not return unused priv in mwifiex_get_priv_by_id() mwifiex_get_priv_by_id() returns the priv pointer corresponding to the bss_num and bss_type, but without checking if the priv is actually currently in use. Unused priv pointers do not have a wiphy attached to them which can lead to NULL pointer dereferences further down the callstack. Fix this by returning only used priv pointers which have priv->bss_mode set to something else than NL80211_IFTYPE_UNSPECIFIED. Said NULL pointer dereference happened when an Accesspoint was started with wpa_supplicant -i mlan0 with this config: network={ ssid="somessid" mode=2 frequency=2412 key_mgmt=WPA-PSK WPA-PSK-SHA256 proto=RSN group=CCMP pairwise=CCMP psk="12345678" } When waiting for the AP to be established, interrupting wpa_supplicant with and starting it again this happens: | Unable to handle kernel NULL pointer dereference at virtual address 0000000000000140 | Mem abort info: | ESR = 0x0000000096000004 | EC = 0x25: DABT (current EL), IL = 32 bits | SET = 0, FnV = 0 | EA = 0, S1PTW = 0 | FSC = 0x04: level 0 translation fault | Data abort info: | ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000 | CM = 0, WnR = 0, TnD = 0, TagAccess = 0 | GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 | user pgtable: 4k pages, 48-bit VAs, pgdp=0000000046d96000 | [0000000000000140] pgd=0000000000000000, p4d=0000000000000000 | Internal error: Oops: 0000000096000004 [#1] PREEMPT SMP | Modules linked in: caam_jr caamhash_desc spidev caamalg_desc crypto_engine authenc libdes mwifiex_sdio +mwifiex crct10dif_ce cdc_acm onboard_usb_hub fsl_imx8_ddr_perf imx8m_ddrc rtc_ds1307 lm75 rtc_snvs +imx_sdma caam imx8mm_thermal spi_imx error imx_cpufreq_dt fuse ip_tables x_tables ipv6 | CPU: 0 PID: 8 Comm: kworker/0:1 Not tainted 6.9.0-00007-g937242013fce-dirty #18 | Hardware name: somemachine (DT) | Workqueue: events sdio_irq_work | pstate: 00000005 (nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) | pc : mwifiex_get_cfp+0xd8/0x15c [mwifiex] | lr : mwifiex_get_cfp+0x34/0x15c [mwifiex] | sp : ffff8000818b3a70 | x29: ffff8000818b3a70 x28: ffff000006bfd8a5 x27: 0000000000000004 | x26: 000000000000002c x25: 0000000000001511 x24: 0000000002e86bc9 | x23: ffff000006bfd996 x22: 0000000000000004 x21: ffff000007bec000 | x20: 000000000000002c x19: 0000000000000000 x18: 0000000000000000 | x17: 000000040044ffff x16: 00500072b5503510 x15: ccc283740681e517 | x14: 0201000101006d15 x13: 0000000002e8ff43 x12: 002c01000000ffb1 | x11: 0100000000000000 x10: 02e8ff43002c0100 x9 : 0000ffb100100157 | x8 : ffff000003d20000 x7 : 00000000000002f1 x6 : 00000000ffffe124 | x5 : 0000000000000001 x4 : 0000000000000003 x3 : 0000000000000000 | x2 : 0000000000000000 x1 : 0001000000011001 x0 : 0000000000000000 | Call trace: | mwifiex_get_cfp+0xd8/0x15c [mwifiex] | mwifiex_parse_single_response_buf+0x1d0/0x504 [mwifiex] | mwifiex_handle_event_ext_scan_report+0x19c/0x2f8 [mwifiex] | mwifiex_process_sta_event+0x298/0xf0c [mwifiex] | mwifiex_process_event+0x110/0x238 [mwifiex] | mwifiex_main_process+0x428/0xa44 [mwifiex] | mwifiex_sdio_interrupt+0x64/0x12c [mwifiex_sdio] | process_sdio_pending_irqs+0x64/0x1b8 | sdio_irq_work+0x4c/0x7c | process_one_work+0x148/0x2a0 | worker_thread+0x2fc/0x40c | kthread+0x110/0x114 | ret_from_fork+0x10/0x20 | Code: a94153f3 a8c37bfd d50323bf d65f03c0 (f940a000) | ---[ end trace 0000000000000000 ]--- Signed-off-by: Sascha Hauer Acked-by: Brian Norris Reviewed-by: Francesco Dolcini Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240703072409.556618-1-s.hauer@pengutronix.de --- drivers/net/wireless/marvell/mwifiex/main.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 175882485a19..c5164ae41b54 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -1287,6 +1287,9 @@ mwifiex_get_priv_by_id(struct mwifiex_adapter *adapter, for (i = 0; i < adapter->priv_num; i++) { if (adapter->priv[i]) { + if (adapter->priv[i]->bss_mode == NL80211_IFTYPE_UNSPECIFIED) + continue; + if ((adapter->priv[i]->bss_num == bss_num) && (adapter->priv[i]->bss_type == bss_type)) break; From 3588e6438a1c2e353616959ce16bce06aef0e424 Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Thu, 4 Jul 2024 17:06:22 +0800 Subject: [PATCH 117/204] wifi: ipw2x00: Use kzalloc() instead of kmalloc()/memset() Replace kmalloc() + memset() to kzalloc() for better code readability and simplicity. Signed-off-by: Chen Ni Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240704090622.2260102-1-nichen@iscas.ac.cn --- drivers/net/wireless/intel/ipw2x00/libipw_tx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c index 4aec1fce1ae2..e22a6732a4c3 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c @@ -180,11 +180,10 @@ static struct libipw_txb *libipw_alloc_txb(int nr_frags, int txb_size, struct libipw_txb *txb; int i; - txb = kmalloc(struct_size(txb, fragments, nr_frags), gfp_mask); + txb = kzalloc(struct_size(txb, fragments, nr_frags), gfp_mask); if (!txb) return NULL; - memset(txb, 0, sizeof(struct libipw_txb)); txb->nr_frags = nr_frags; txb->frag_size = txb_size; From 30e89baeb01fc765824ed931b33b0faf4d8d1461 Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Wed, 12 Jun 2024 20:01:55 -0700 Subject: [PATCH 118/204] wifi: mt76: mt792x: add struct mt792x_bss_conf We are introducing a new structure, mt792x_bss_conf, to manage per-link configurations in preparation for future STA support of Multi-Link Operation (MLO). The patch does not include any logic changes, only structural changes. We have moved relevant parameters from the mt7921x_vif structure such as to mt76 of mt76_vif structure, rssi and Tx queue parameters to mt7921x_bss_conf structure. We can access those members to configure the BSS for this interface, whether it is our own BSS or the one we are associated with. However, we have not yet created the per-link BSS configuration indexed by link ID for Multi-Link Device (MLD) support. This step needs to be extended before adding MLD support for AP mode. Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Deren Wu Link: https://patch.msgid.link/20240613030241.5771-2-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7921/main.c | 42 +++++++------- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 42 +++++++------- .../net/wireless/mediatek/mt76/mt7925/main.c | 56 +++++++++---------- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 56 +++++++++---------- drivers/net/wireless/mediatek/mt76/mt792x.h | 12 ++-- .../net/wireless/mediatek/mt76/mt792x_core.c | 18 +++--- .../net/wireless/mediatek/mt76/mt792x_mac.c | 2 +- 7 files changed, 115 insertions(+), 113 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 4f30426afbb7..77999d778a38 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -295,30 +295,30 @@ mt7921_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) mt792x_mutex_acquire(dev); - mvif->mt76.idx = __ffs64(~dev->mt76.vif_mask); - if (mvif->mt76.idx >= MT792x_MAX_INTERFACES) { + mvif->bss_conf.mt76.idx = __ffs64(~dev->mt76.vif_mask); + if (mvif->bss_conf.mt76.idx >= MT792x_MAX_INTERFACES) { ret = -ENOSPC; goto out; } - mvif->mt76.omac_idx = mvif->mt76.idx; + mvif->bss_conf.mt76.omac_idx = mvif->bss_conf.mt76.idx; mvif->phy = phy; - mvif->mt76.band_idx = 0; - mvif->mt76.wmm_idx = mvif->mt76.idx % MT76_CONNAC_MAX_WMM_SETS; + mvif->bss_conf.mt76.band_idx = 0; + mvif->bss_conf.mt76.wmm_idx = mvif->bss_conf.mt76.idx % MT76_CONNAC_MAX_WMM_SETS; ret = mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.wcid, true); if (ret) goto out; - dev->mt76.vif_mask |= BIT_ULL(mvif->mt76.idx); - phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx); + dev->mt76.vif_mask |= BIT_ULL(mvif->bss_conf.mt76.idx); + phy->omac_mask |= BIT_ULL(mvif->bss_conf.mt76.omac_idx); - idx = MT792x_WTBL_RESERVED - mvif->mt76.idx; + idx = MT792x_WTBL_RESERVED - mvif->bss_conf.mt76.idx; INIT_LIST_HEAD(&mvif->sta.wcid.poll_list); mvif->sta.wcid.idx = idx; - mvif->sta.wcid.phy_idx = mvif->mt76.band_idx; + mvif->sta.wcid.phy_idx = mvif->bss_conf.mt76.band_idx; mvif->sta.wcid.hw_key_idx = -1; mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; mt76_wcid_init(&mvif->sta.wcid); @@ -326,7 +326,7 @@ mt7921_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) mt7921_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - ewma_rssi_init(&mvif->rssi); + ewma_rssi_init(&mvif->bss_conf.rssi); rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); if (vif->txq) { @@ -718,7 +718,7 @@ static void mt7921_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ARP_FILTER) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - mt76_connac_mcu_update_arp_filter(&dev->mt76, &mvif->mt76, + mt76_connac_mcu_update_arp_filter(&dev->mt76, &mvif->bss_conf.mt76, info); } @@ -803,7 +803,7 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, msta->vif = mvif; msta->wcid.sta = 1; msta->wcid.idx = idx; - msta->wcid.phy_idx = mvif->mt76.band_idx; + msta->wcid.phy_idx = mvif->bss_conf.mt76.band_idx; msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; msta->last_txs = jiffies; @@ -841,7 +841,7 @@ void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, &mvif->sta.wcid, - true, mvif->mt76.ctx); + true, mvif->bss_conf.mt76.ctx); ewma_avg_signal_init(&msta->avg_ack_signal); @@ -872,11 +872,11 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; mvif->wep_sta = NULL; - ewma_rssi_init(&mvif->rssi); + ewma_rssi_init(&mvif->bss_conf.rssi); if (!sta->tdls) mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, &mvif->sta.wcid, false, - mvif->mt76.ctx); + mvif->bss_conf.mt76.ctx); } spin_lock_bh(&dev->mt76.sta_poll_lock); @@ -1196,7 +1196,7 @@ static void mt7921_ipv6_addr_change(struct ieee80211_hw *hw, struct mt76_connac_arpns_tlv arpns; } req_hdr = { .hdr = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, }, .arpns = { .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ND), @@ -1295,7 +1295,7 @@ mt7921_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt792x_mutex_acquire(dev); err = mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid, - true, mvif->mt76.ctx); + true, mvif->bss_conf.mt76.ctx); if (err) goto out; @@ -1327,7 +1327,7 @@ mt7921_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, goto out; mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid, false, - mvif->mt76.ctx); + mvif->bss_conf.mt76.ctx); out: mt792x_mutex_release(dev); @@ -1352,13 +1352,13 @@ static void mt7921_ctx_iter(void *priv, u8 *mac, struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct ieee80211_chanctx_conf *ctx = priv; - if (ctx != mvif->mt76.ctx) + if (ctx != mvif->bss_conf.mt76.ctx) return; if (vif->type == NL80211_IFTYPE_MONITOR) mt7921_mcu_config_sniffer(mvif, ctx); else - mt76_connac_mcu_uni_set_chctx(mvif->phy->mt76, &mvif->mt76, ctx); + mt76_connac_mcu_uni_set_chctx(mvif->phy->mt76, &mvif->bss_conf.mt76, ctx); } static void @@ -1385,7 +1385,7 @@ static void mt7921_mgd_prepare_tx(struct ieee80211_hw *hw, jiffies_to_msecs(HZ); mt792x_mutex_acquire(dev); - mt7921_set_roc(mvif->phy, mvif, mvif->mt76.ctx->def.chan, duration, + mt7921_set_roc(mvif->phy, mvif, mvif->bss_conf.mt76.ctx->def.chan, duration, MT7921_ROC_REQ_JOIN); mt792x_mutex_release(dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index bdd8b5f19b24..0453af012016 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -105,7 +105,7 @@ mt7921_mcu_set_ipv6_ns_filter(struct mt76_dev *dev, struct mt76_connac_arpns_tlv arpns; } req = { .hdr = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, }, .arpns = { .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ND), @@ -260,7 +260,7 @@ mt7921_mcu_rssi_monitor_iter(void *priv, u8 *mac, struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt76_connac_rssi_notify_event *event = priv; enum nl80211_cqm_rssi_threshold_event nl_event; - s32 rssi = le32_to_cpu(event->rssi[mvif->mt76.idx]); + s32 rssi = le32_to_cpu(event->rssi[mvif->bss_conf.mt76.idx]); if (!rssi) return; @@ -388,7 +388,7 @@ int mt7921_mcu_uni_tx_ba(struct mt792x_dev *dev, if (enable && !params->amsdu) msta->wcid.amsdu = false; - return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->mt76, params, + return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->bss_conf.mt76, params, MCU_UNI_CMD(STA_REC_UPDATE), enable, true); } @@ -399,7 +399,7 @@ int mt7921_mcu_uni_rx_ba(struct mt792x_dev *dev, { struct mt792x_sta *msta = (struct mt792x_sta *)params->sta->drv_priv; - return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->mt76, params, + return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->bss_conf.mt76, params, MCU_UNI_CMD(STA_REC_UPDATE), enable, false); } @@ -678,9 +678,9 @@ int mt7921_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_vif *vif) u8 wmm_idx; u8 pad; } __packed req = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, .qos = vif->bss_conf.qos, - .wmm_idx = mvif->mt76.wmm_idx, + .wmm_idx = mvif->bss_conf.mt76.wmm_idx, }; struct mu_edca { u8 cw_min; @@ -701,15 +701,15 @@ int mt7921_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_vif *vif) struct mu_edca edca[IEEE80211_NUM_ACS]; u8 pad3[32]; } __packed req_mu = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, .qos = vif->bss_conf.qos, - .wmm_idx = mvif->mt76.wmm_idx, + .wmm_idx = mvif->bss_conf.mt76.wmm_idx, }; static const int to_aci[] = { 1, 0, 2, 3 }; int ac, ret; for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac]; + struct ieee80211_tx_queue_params *q = &mvif->bss_conf.queue_params[ac]; struct edca *e = &req.edca[to_aci[ac]]; e->aifs = cpu_to_le16(q->aifs); @@ -738,10 +738,10 @@ int mt7921_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_vif *vif) struct ieee80211_he_mu_edca_param_ac_rec *q; struct mu_edca *e; - if (!mvif->queue_params[ac].mu_edca) + if (!mvif->bss_conf.queue_params[ac].mu_edca) break; - q = &mvif->queue_params[ac].mu_edca_param_rec; + q = &mvif->bss_conf.queue_params[ac].mu_edca_param_rec; e = &(req_mu.edca[to_aci[ac]]); e->cw_min = q->ecw_min_max & 0xf; @@ -790,7 +790,7 @@ int mt7921_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_vif *vif, .tokenid = token_id, .reqtype = type, .maxinterval = cpu_to_le32(duration), - .bss_idx = vif->mt76.idx, + .bss_idx = vif->bss_conf.mt76.idx, .control_channel = chan->hw_value, .bw = CMD_CBW_20MHZ, .bw_from_ap = CMD_CBW_20MHZ, @@ -842,7 +842,7 @@ int mt7921_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_vif *vif, .tag = cpu_to_le16(UNI_ROC_ABORT), .len = cpu_to_le16(sizeof(struct roc_abort_tlv)), .tokenid = token_id, - .bss_idx = vif->mt76.idx, + .bss_idx = vif->bss_conf.mt76.idx, .dbdcband = 0xff, /* auto*/ }, }; @@ -947,7 +947,7 @@ int mt7921_mcu_uni_bss_ps(struct mt792x_dev *dev, struct ieee80211_vif *vif) } __packed ps; } __packed ps_req = { .hdr = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, }, .ps = { .tag = cpu_to_le16(UNI_BSS_INFO_PS), @@ -982,7 +982,7 @@ mt7921_mcu_uni_bss_bcnft(struct mt792x_dev *dev, struct ieee80211_vif *vif, } __packed bcnft; } __packed bcnft_req = { .hdr = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, }, .bcnft = { .tag = cpu_to_le16(UNI_BSS_INFO_BCNFT), @@ -1015,7 +1015,7 @@ mt7921_mcu_set_bss_pm(struct mt792x_dev *dev, struct ieee80211_vif *vif, u8 bmc_triggered_ac; u8 pad; } req = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, .aid = cpu_to_le16(vif->cfg.aid), .dtim_period = vif->bss_conf.dtim_period, .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), @@ -1024,7 +1024,7 @@ mt7921_mcu_set_bss_pm(struct mt792x_dev *dev, struct ieee80211_vif *vif, u8 bss_idx; u8 pad[3]; } req_hdr = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, }; int err; @@ -1042,7 +1042,7 @@ int mt7921_mcu_sta_update(struct mt792x_dev *dev, struct ieee80211_sta *sta, enum mt76_sta_info_state state) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - int rssi = -ewma_rssi_read(&mvif->rssi); + int rssi = -ewma_rssi_read(&mvif->bss_conf.rssi); struct mt76_sta_cmd_info info = { .sta = sta, .vif = vif, @@ -1190,7 +1190,7 @@ int mt7921_mcu_config_sniffer(struct mt792x_vif *vif, } __packed tlv; } __packed req = { .hdr = { - .band_idx = vif->mt76.band_idx, + .band_idx = vif->bss_conf.mt76.band_idx, }, .tlv = { .tag = cpu_to_le16(1), @@ -1251,7 +1251,7 @@ mt7921_mcu_uni_add_beacon_offload(struct mt792x_dev *dev, } __packed beacon_tlv; } req = { .hdr = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, }, .beacon_tlv = { .tag = cpu_to_le16(UNI_BSS_INFO_BCN_CONTENT), @@ -1460,7 +1460,7 @@ int mt7921_mcu_set_rssimonitor(struct mt792x_dev *dev, struct ieee80211_vif *vif .enable = vif->cfg.assoc, .cqm_rssi_high = vif->bss_conf.cqm_rssi_thold + vif->bss_conf.cqm_rssi_hyst, .cqm_rssi_low = vif->bss_conf.cqm_rssi_thold - vif->bss_conf.cqm_rssi_hyst, - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, }; return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(RSSI_MONITOR), diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 6179798a8845..dfc606cc9bdd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -328,35 +328,35 @@ mt7925_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) mt792x_mutex_acquire(dev); - mvif->mt76.idx = __ffs64(~dev->mt76.vif_mask); - if (mvif->mt76.idx >= MT792x_MAX_INTERFACES) { + mvif->bss_conf.mt76.idx = __ffs64(~dev->mt76.vif_mask); + if (mvif->bss_conf.mt76.idx >= MT792x_MAX_INTERFACES) { ret = -ENOSPC; goto out; } - mvif->mt76.omac_idx = mvif->mt76.idx; + mvif->bss_conf.mt76.omac_idx = mvif->bss_conf.mt76.idx; mvif->phy = phy; - mvif->mt76.band_idx = 0; - mvif->mt76.wmm_idx = mvif->mt76.idx % MT76_CONNAC_MAX_WMM_SETS; + mvif->bss_conf.mt76.band_idx = 0; + mvif->bss_conf.mt76.wmm_idx = mvif->bss_conf.mt76.idx % MT76_CONNAC_MAX_WMM_SETS; if (phy->mt76->chandef.chan->band != NL80211_BAND_2GHZ) - mvif->mt76.basic_rates_idx = MT792x_BASIC_RATES_TBL + 4; + mvif->bss_conf.mt76.basic_rates_idx = MT792x_BASIC_RATES_TBL + 4; else - mvif->mt76.basic_rates_idx = MT792x_BASIC_RATES_TBL; + mvif->bss_conf.mt76.basic_rates_idx = MT792x_BASIC_RATES_TBL; ret = mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.wcid, true); if (ret) goto out; - dev->mt76.vif_mask |= BIT_ULL(mvif->mt76.idx); - phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx); + dev->mt76.vif_mask |= BIT_ULL(mvif->bss_conf.mt76.idx); + phy->omac_mask |= BIT_ULL(mvif->bss_conf.mt76.omac_idx); - idx = MT792x_WTBL_RESERVED - mvif->mt76.idx; + idx = MT792x_WTBL_RESERVED - mvif->bss_conf.mt76.idx; INIT_LIST_HEAD(&mvif->sta.wcid.poll_list); mvif->sta.wcid.idx = idx; - mvif->sta.wcid.phy_idx = mvif->mt76.band_idx; + mvif->sta.wcid.phy_idx = mvif->bss_conf.mt76.band_idx; mvif->sta.wcid.hw_key_idx = -1; mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; mvif->sta.vif = mvif; @@ -365,7 +365,7 @@ mt7925_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) mt7925_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - ewma_rssi_init(&mvif->rssi); + ewma_rssi_init(&mvif->bss_conf.rssi); rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); if (vif->txq) { @@ -524,11 +524,11 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mt792x_mutex_acquire(dev); - if (cmd == SET_KEY && !mvif->mt76.cipher) { + if (cmd == SET_KEY && !mvif->bss_conf.mt76.cipher) { struct mt792x_phy *phy = mt792x_hw_phy(hw); - mvif->mt76.cipher = mt7925_mcu_get_cipher(key->cipher); - mt7925_mcu_add_bss_info(phy, mvif->mt76.ctx, vif, sta, true); + mvif->bss_conf.mt76.cipher = mt7925_mcu_get_cipher(key->cipher); + mt7925_mcu_add_bss_info(phy, mvif->bss_conf.mt76.ctx, vif, sta, true); } if (cmd == SET_KEY) @@ -748,7 +748,7 @@ static void mt7925_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ARP_FILTER) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - mt7925_mcu_update_arp_filter(&dev->mt76, &mvif->mt76, info); + mt7925_mcu_update_arp_filter(&dev->mt76, &mvif->bss_conf.mt76, info); } mt792x_mutex_release(dev); @@ -770,7 +770,7 @@ int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, msta->vif = mvif; msta->wcid.sta = 1; msta->wcid.idx = idx; - msta->wcid.phy_idx = mvif->mt76.band_idx; + msta->wcid.phy_idx = mvif->bss_conf.mt76.band_idx; msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; msta->last_txs = jiffies; @@ -786,7 +786,7 @@ int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, /* should update bss info before STA add */ if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) - mt7925_mcu_add_bss_info(&dev->phy, mvif->mt76.ctx, vif, sta, + mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, vif, sta, false); ret = mt7925_mcu_sta_update(dev, sta, vif, true, @@ -810,7 +810,7 @@ void mt7925_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, mt792x_mutex_acquire(dev); if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) - mt7925_mcu_add_bss_info(&dev->phy, mvif->mt76.ctx, vif, sta, + mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, vif, sta, true); ewma_avg_signal_init(&msta->avg_ack_signal); @@ -842,9 +842,9 @@ void mt7925_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; mvif->wep_sta = NULL; - ewma_rssi_init(&mvif->rssi); + ewma_rssi_init(&mvif->bss_conf.rssi); if (!sta->tdls) - mt7925_mcu_add_bss_info(&dev->phy, mvif->mt76.ctx, vif, sta, + mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, vif, sta, false); } @@ -1190,7 +1190,7 @@ static void mt7925_ipv6_addr_change(struct ieee80211_hw *hw, struct in6_addr ns_addrs[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; } req_hdr = { .hdr = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, }, .arpns = { .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ND), @@ -1288,7 +1288,7 @@ mt7925_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, }; /* firmware uses access class index */ - mvif->queue_params[mq_to_aci[queue]] = *params; + mvif->bss_conf.queue_params[mq_to_aci[queue]] = *params; return 0; } @@ -1303,7 +1303,7 @@ mt7925_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt792x_mutex_acquire(dev); - err = mt7925_mcu_add_bss_info(&dev->phy, mvif->mt76.ctx, vif, NULL, + err = mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, vif, NULL, true); if (err) goto out; @@ -1334,7 +1334,7 @@ mt7925_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (err) goto out; - mt7925_mcu_add_bss_info(&dev->phy, mvif->mt76.ctx, vif, NULL, + mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, vif, NULL, false); out: @@ -1360,14 +1360,14 @@ static void mt7925_ctx_iter(void *priv, u8 *mac, struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct ieee80211_chanctx_conf *ctx = priv; - if (ctx != mvif->mt76.ctx) + if (ctx != mvif->bss_conf.mt76.ctx) return; if (vif->type == NL80211_IFTYPE_MONITOR) { mt7925_mcu_set_sniffer(mvif->phy->dev, vif, true); mt7925_mcu_config_sniffer(mvif, ctx); } else { - mt7925_mcu_set_chctx(mvif->phy->mt76, &mvif->mt76, ctx); + mt7925_mcu_set_chctx(mvif->phy->mt76, &mvif->bss_conf.mt76, ctx); } } @@ -1395,7 +1395,7 @@ static void mt7925_mgd_prepare_tx(struct ieee80211_hw *hw, jiffies_to_msecs(HZ); mt792x_mutex_acquire(dev); - mt7925_set_roc(mvif->phy, mvif, mvif->mt76.ctx->def.chan, duration, + mt7925_set_roc(mvif->phy, mvif, mvif->bss_conf.mt76.ctx->def.chan, duration, MT7925_ROC_REQ_JOIN); mt792x_mutex_release(dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 652a9accc43c..c259aedb96e0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -546,7 +546,7 @@ int mt7925_mcu_uni_tx_ba(struct mt792x_dev *dev, if (enable && !params->amsdu) msta->wcid.amsdu = false; - return mt7925_mcu_sta_ba(&dev->mt76, &mvif->mt76, params, + return mt7925_mcu_sta_ba(&dev->mt76, &mvif->bss_conf.mt76, params, enable, true); } @@ -557,7 +557,7 @@ int mt7925_mcu_uni_rx_ba(struct mt792x_dev *dev, struct mt792x_sta *msta = (struct mt792x_sta *)params->sta->drv_priv; struct mt792x_vif *mvif = msta->vif; - return mt7925_mcu_sta_ba(&dev->mt76, &mvif->mt76, params, + return mt7925_mcu_sta_ba(&dev->mt76, &mvif->bss_conf.mt76, params, enable, false); } @@ -889,7 +889,7 @@ int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev, msta = sta ? (struct mt792x_sta *)sta->drv_priv : &mvif->sta; - skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, + skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->bss_conf.mt76, &msta->wcid, MT7925_STA_UPDATE_MAX_SIZE); if (IS_ERR(skb)) @@ -915,7 +915,7 @@ int mt7925_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_vif *vif) u8 bss_idx; u8 __rsv[3]; } __packed hdr = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, }; struct sk_buff *skb; int len = sizeof(hdr) + IEEE80211_NUM_ACS * sizeof(struct edca); @@ -928,7 +928,7 @@ int mt7925_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_vif *vif) skb_put_data(skb, &hdr, sizeof(hdr)); for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac]; + struct ieee80211_tx_queue_params *q = &mvif->bss_conf.queue_params[ac]; struct edca *e; struct tlv *tlv; @@ -976,7 +976,7 @@ mt7925_mcu_sta_key_tlv(struct mt76_wcid *wcid, tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V3, sizeof(*sec)); sec = (struct sta_rec_sec_uni *)tlv; - sec->bss_idx = mvif->mt76.idx; + sec->bss_idx = mvif->bss_conf.mt76.idx; sec->is_authenticator = 0; sec->mgmt_prot = 0; sec->wlan_idx = (u8)wcid->idx; @@ -1085,7 +1085,7 @@ int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_vif *vif, .tokenid = token_id, .reqtype = type, .maxinterval = cpu_to_le32(duration), - .bss_idx = vif->mt76.idx, + .bss_idx = vif->bss_conf.mt76.idx, .control_channel = chan->hw_value, .bw = CMD_CBW_20MHZ, .bw_from_ap = CMD_CBW_20MHZ, @@ -1137,7 +1137,7 @@ int mt7925_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_vif *vif, .tag = cpu_to_le16(UNI_ROC_ABORT), .len = cpu_to_le16(sizeof(struct roc_abort_tlv)), .tokenid = token_id, - .bss_idx = vif->mt76.idx, + .bss_idx = vif->bss_conf.mt76.idx, .dbdcband = 0xff, /* auto*/ }, }; @@ -1263,7 +1263,7 @@ int mt7925_mcu_uni_bss_ps(struct mt792x_dev *dev, struct ieee80211_vif *vif) } __packed ps; } __packed ps_req = { .hdr = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, }, .ps = { .tag = cpu_to_le16(UNI_BSS_INFO_PS), @@ -1300,7 +1300,7 @@ mt7925_mcu_uni_bss_bcnft(struct mt792x_dev *dev, struct ieee80211_vif *vif, } __packed bcnft; } __packed bcnft_req = { .hdr = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, }, .bcnft = { .tag = cpu_to_le16(UNI_BSS_INFO_BCNFT), @@ -1338,7 +1338,7 @@ mt7925_mcu_set_bss_pm(struct mt792x_dev *dev, struct ieee80211_vif *vif, } __packed enable; } req = { .hdr = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, }, .enable = { .tag = cpu_to_le16(UNI_BSS_INFO_BCNFT), @@ -1358,7 +1358,7 @@ mt7925_mcu_set_bss_pm(struct mt792x_dev *dev, struct ieee80211_vif *vif, } __packed disable; } req1 = { .hdr = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, }, .disable = { .tag = cpu_to_le16(UNI_BSS_INFO_PM_DISABLE), @@ -1502,7 +1502,7 @@ mt7925_mcu_sta_phy_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - struct cfg80211_chan_def *chandef = &mvif->mt76.ctx->def; + struct cfg80211_chan_def *chandef = &mvif->bss_conf.mt76.ctx->def; struct sta_rec_phy *phy; struct tlv *tlv; u8 af = 0, mm = 0; @@ -1569,7 +1569,7 @@ mt7925_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - struct cfg80211_chan_def *chandef = &mvif->mt76.ctx->def; + struct cfg80211_chan_def *chandef = &mvif->bss_conf.mt76.ctx->def; enum nl80211_band band = chandef->chan->band; struct sta_rec_ra_info *ra_info; struct tlv *tlv; @@ -1655,7 +1655,7 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev, struct ieee80211_sta *sta, enum mt76_sta_info_state state) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - int rssi = -ewma_rssi_read(&mvif->rssi); + int rssi = -ewma_rssi_read(&mvif->bss_conf.rssi); struct mt76_sta_cmd_info info = { .sta = sta, .vif = vif, @@ -1746,7 +1746,7 @@ int mt7925_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif, } __packed enable; } __packed req = { .hdr = { - .band_idx = mvif->mt76.band_idx, + .band_idx = mvif->bss_conf.mt76.band_idx, }, .enable = { .tag = cpu_to_le16(UNI_SNIFFER_ENABLE), @@ -1805,7 +1805,7 @@ int mt7925_mcu_config_sniffer(struct mt792x_vif *vif, } __packed tlv; } __packed req = { .hdr = { - .band_idx = vif->mt76.band_idx, + .band_idx = vif->bss_conf.mt76.band_idx, }, .tlv = { .tag = cpu_to_le16(UNI_SNIFFER_CONFIG), @@ -1866,7 +1866,7 @@ mt7925_mcu_uni_add_beacon_offload(struct mt792x_dev *dev, } __packed beacon_tlv; } req = { .hdr = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, }, .beacon_tlv = { .tag = cpu_to_le16(UNI_BSS_INFO_BCN_CONTENT), @@ -2080,8 +2080,8 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_BASIC, sizeof(*basic_req)); basic_req = (struct mt76_connac_bss_basic_tlv *)tlv; - idx = mvif->mt76.omac_idx > EXT_BSSID_START ? HW_BSSID_0 : - mvif->mt76.omac_idx; + idx = mvif->bss_conf.mt76.omac_idx > EXT_BSSID_START ? HW_BSSID_0 : + mvif->bss_conf.mt76.omac_idx; basic_req->hw_bss_idx = idx; basic_req->phymode_ext = mt7925_get_phy_mode_ext(phy, vif, band, sta); @@ -2097,9 +2097,9 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, basic_req->dtim_period = vif->bss_conf.dtim_period; basic_req->bmc_tx_wlan_idx = cpu_to_le16(wlan_idx); basic_req->sta_idx = cpu_to_le16(msta->wcid.idx); - basic_req->omac_idx = mvif->mt76.omac_idx; - basic_req->band_idx = mvif->mt76.band_idx; - basic_req->wmm_idx = mvif->mt76.wmm_idx; + basic_req->omac_idx = mvif->bss_conf.mt76.omac_idx; + basic_req->band_idx = mvif->bss_conf.mt76.band_idx; + basic_req->wmm_idx = mvif->bss_conf.mt76.wmm_idx; basic_req->conn_state = !enable; switch (vif->type) { @@ -2217,8 +2217,8 @@ mt7925_mcu_bss_mld_tlv(struct sk_buff *skb, mld = (struct bss_mld_tlv *)tlv; mld->link_id = sta ? (is_mld ? vif->bss_conf.link_id : 0) : 0xff; - mld->group_mld_id = is_mld ? mvif->mt76.idx : 0xff; - mld->own_mld_id = mvif->mt76.idx + 32; + mld->group_mld_id = is_mld ? mvif->bss_conf.mt76.idx : 0xff; + mld->own_mld_id = mvif->bss_conf.mt76.idx + 32; mld->remap_idx = 0xff; if (sta) @@ -2301,7 +2301,7 @@ int mt7925_mcu_set_timing(struct mt792x_phy *phy, struct mt792x_dev *dev = phy->dev; struct sk_buff *skb; - skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76, + skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mvif->bss_conf.mt76, MT7925_BSS_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -2323,7 +2323,7 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, struct sk_buff *skb; int err; - skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76, + skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mvif->bss_conf.mt76, MT7925_BSS_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -2348,7 +2348,7 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, if (err < 0) return err; - return mt7925_mcu_set_chctx(phy->mt76, &mvif->mt76, ctx); + return mt7925_mcu_set_chctx(phy->mt76, &mvif->bss_conf.mt76, ctx); } int mt7925_mcu_set_dbdc(struct mt76_phy *phy) diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index cf14a38c5e72..27bfda04d0f2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -98,17 +98,19 @@ struct mt792x_sta { DECLARE_EWMA(rssi, 10, 8); -struct mt792x_vif { +struct mt792x_bss_conf { struct mt76_vif mt76; /* must be first */ + struct ewma_rssi rssi; + struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; +}; + +struct mt792x_vif { + struct mt792x_bss_conf bss_conf; /* must be first */ struct mt792x_sta sta; struct mt792x_sta *wep_sta; struct mt792x_phy *phy; - - struct ewma_rssi rssi; - - struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; }; struct mt792x_phy { diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c index 4adca99eb9b8..9eeaf3344217 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c @@ -128,8 +128,8 @@ void mt792x_remove_interface(struct ieee80211_hw *hw, rcu_assign_pointer(dev->mt76.wcid[idx], NULL); - dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx); - phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx); + dev->mt76.vif_mask &= ~BIT_ULL(mvif->bss_conf.mt76.idx); + phy->omac_mask &= ~BIT_ULL(mvif->bss_conf.mt76.omac_idx); mt792x_mutex_release(dev); spin_lock_bh(&dev->mt76.sta_poll_lock); @@ -149,7 +149,7 @@ int mt792x_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, /* no need to update right away, we'll get BSS_CHANGED_QOS */ queue = mt76_connac_lmac_mapping(queue); - mvif->queue_params[queue] = *params; + mvif->bss_conf.queue_params[queue] = *params; return 0; } @@ -178,7 +178,7 @@ u64 mt792x_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_dev *dev = mt792x_hw_dev(hw); - u8 omac_idx = mvif->mt76.omac_idx; + u8 omac_idx = mvif->bss_conf.mt76.omac_idx; union { u64 t64; u32 t32[2]; @@ -204,7 +204,7 @@ void mt792x_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_dev *dev = mt792x_hw_dev(hw); - u8 omac_idx = mvif->mt76.omac_idx; + u8 omac_idx = mvif->bss_conf.mt76.omac_idx; union { u64 t64; u32 t32[2]; @@ -265,7 +265,7 @@ int mt792x_assign_vif_chanctx(struct ieee80211_hw *hw, struct mt792x_dev *dev = mt792x_hw_dev(hw); mutex_lock(&dev->mt76.mutex); - mvif->mt76.ctx = ctx; + mvif->bss_conf.mt76.ctx = ctx; mutex_unlock(&dev->mt76.mutex); return 0; @@ -281,7 +281,7 @@ void mt792x_unassign_vif_chanctx(struct ieee80211_hw *hw, struct mt792x_dev *dev = mt792x_hw_dev(hw); mutex_lock(&dev->mt76.mutex); - mvif->mt76.ctx = NULL; + mvif->bss_conf.mt76.ctx = NULL; mutex_unlock(&dev->mt76.mutex); } EXPORT_SYMBOL_GPL(mt792x_unassign_vif_chanctx); @@ -405,7 +405,7 @@ mt792x_ethtool_worker(void *wi_data, struct ieee80211_sta *sta) struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; struct mt76_ethtool_worker_info *wi = wi_data; - if (msta->vif->mt76.idx != wi->idx) + if (msta->vif->bss_conf.mt76.idx != wi->idx) return; mt76_ethtool_worker(wi, &msta->wcid.stats, true); @@ -421,7 +421,7 @@ void mt792x_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct mt76_mib_stats *mib = &phy->mib; struct mt76_ethtool_worker_info wi = { .data = data, - .idx = mvif->mt76.idx, + .idx = mvif->bss_conf.mt76.idx, }; int i, ei = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c index eb29434abee1..45dd94ff386d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c @@ -173,7 +173,7 @@ mt792x_mac_rssi_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) if (!ether_addr_equal(vif->addr, hdr->addr1)) return; - ewma_rssi_add(&mvif->rssi, -status->signal); + ewma_rssi_add(&mvif->bss_conf.rssi, -status->signal); } void mt792x_mac_assoc_rssi(struct mt792x_dev *dev, struct sk_buff *skb) From 4c28c0976ed83c3e8240e80ea918c4d1a3f9c5bc Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Wed, 12 Jun 2024 20:01:56 -0700 Subject: [PATCH 119/204] wifi: mt76: mt792x: add struct mt792x_link_sta We are introducing a new structure, mt792x_link_sta, to manage per-link configurations in preparation for future station (STA) support of Multi-Link Operation (MLO). This patch only includes structural changes and does not involve any logic changes. We have moved relevant parameters, such as the wcid from the mt76_wcid structure, from the mt7921x_sta structure to the mt792x_link_sta structure. For current drivers that do not support MLO, there is only one link STA, and link information is accessed via the deflink member. However, we have not yet created the per-link BSS configuration indexed by link ID for Multi-Link Device (MLD) support in mt7921x_sta. This step needs to be completed before adding MLD support for STA mode. Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Deren Wu Link: https://patch.msgid.link/20240613030241.5771-3-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7921/mac.c | 65 ++++++++-------- .../net/wireless/mediatek/mt76/mt7921/main.c | 76 +++++++++---------- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 4 +- .../wireless/mediatek/mt76/mt7921/pci_mac.c | 4 +- .../net/wireless/mediatek/mt76/mt7925/mac.c | 66 ++++++++-------- .../net/wireless/mediatek/mt76/mt7925/main.c | 66 ++++++++-------- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 17 +++-- .../wireless/mediatek/mt76/mt7925/pci_mac.c | 4 +- drivers/net/wireless/mediatek/mt76/mt792x.h | 10 ++- .../net/wireless/mediatek/mt76/mt792x_core.c | 28 +++---- .../net/wireless/mediatek/mt76/mt792x_mac.c | 6 +- 11 files changed, 180 insertions(+), 166 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 73e42ef42983..9ae9590999f4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -39,6 +39,7 @@ static void mt7921_mac_sta_poll(struct mt792x_dev *dev) }; struct ieee80211_sta *sta; struct mt792x_sta *msta; + struct mt792x_link_sta *mlink; u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS]; LIST_HEAD(sta_poll_list); struct rate_info *rate; @@ -60,23 +61,25 @@ static void mt7921_mac_sta_poll(struct mt792x_dev *dev) spin_unlock_bh(&dev->mt76.sta_poll_lock); break; } - msta = list_first_entry(&sta_poll_list, - struct mt792x_sta, wcid.poll_list); - list_del_init(&msta->wcid.poll_list); + mlink = list_first_entry(&sta_poll_list, + struct mt792x_link_sta, + wcid.poll_list); + msta = container_of(mlink, struct mt792x_sta, deflink); + list_del_init(&mlink->wcid.poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); - idx = msta->wcid.idx; + idx = mlink->wcid.idx; addr = mt7921_mac_wtbl_lmac_addr(idx, MT_WTBL_AC0_CTT_OFFSET); for (i = 0; i < IEEE80211_NUM_ACS; i++) { - u32 tx_last = msta->airtime_ac[i]; - u32 rx_last = msta->airtime_ac[i + 4]; + u32 tx_last = mlink->airtime_ac[i]; + u32 rx_last = mlink->airtime_ac[i + 4]; - msta->airtime_ac[i] = mt76_rr(dev, addr); - msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4); + mlink->airtime_ac[i] = mt76_rr(dev, addr); + mlink->airtime_ac[i + 4] = mt76_rr(dev, addr + 4); - tx_time[i] = msta->airtime_ac[i] - tx_last; - rx_time[i] = msta->airtime_ac[i + 4] - rx_last; + tx_time[i] = mlink->airtime_ac[i] - tx_last; + rx_time[i] = mlink->airtime_ac[i + 4] - rx_last; if ((tx_last | rx_last) & BIT(30)) clear = true; @@ -87,10 +90,10 @@ static void mt7921_mac_sta_poll(struct mt792x_dev *dev) if (clear) { mt7921_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac)); + memset(mlink->airtime_ac, 0, sizeof(mlink->airtime_ac)); } - if (!msta->wcid.sta) + if (!mlink->wcid.sta) continue; sta = container_of((void *)msta, struct ieee80211_sta, @@ -113,7 +116,7 @@ static void mt7921_mac_sta_poll(struct mt792x_dev *dev) * we need to make sure that flags match so polling GI * from per-sta counters directly. */ - rate = &msta->wcid.rate; + rate = &mlink->wcid.rate; addr = mt7921_mac_wtbl_lmac_addr(idx, MT_WTBL_TXRX_CAP_RATE_OFFSET); val = mt76_rr(dev, addr); @@ -154,10 +157,10 @@ static void mt7921_mac_sta_poll(struct mt792x_dev *dev) rssi[2] = to_rssi(GENMASK(23, 16), val); rssi[3] = to_rssi(GENMASK(31, 14), val); - msta->ack_signal = + mlink->ack_signal = mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi); - ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal); + ewma_avg_signal_add(&mlink->avg_ack_signal, -mlink->ack_signal); } } @@ -180,6 +183,7 @@ mt7921_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb) u32 rxd3 = le32_to_cpu(rxd[3]); u32 rxd4 = le32_to_cpu(rxd[4]); struct mt792x_sta *msta = NULL; + struct mt792x_link_sta *mlink; u16 seq_ctrl = 0; __le16 fc = 0; u8 mode = 0; @@ -210,10 +214,11 @@ mt7921_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb) status->wcid = mt792x_rx_get_wcid(dev, idx, unicast); if (status->wcid) { - msta = container_of(status->wcid, struct mt792x_sta, wcid); + mlink = container_of(status->wcid, struct mt792x_link_sta, wcid); + msta = container_of(mlink, struct mt792x_sta, deflink); spin_lock_bh(&dev->mt76.sta_poll_lock); - if (list_empty(&msta->wcid.poll_list)) - list_add_tail(&msta->wcid.poll_list, + if (list_empty(&mlink->wcid.poll_list)) + list_add_tail(&mlink->wcid.poll_list, &dev->mt76.sta_poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); } @@ -444,7 +449,7 @@ mt7921_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb) void mt7921_mac_add_txs(struct mt792x_dev *dev, void *data) { - struct mt792x_sta *msta = NULL; + struct mt792x_link_sta *mlink; struct mt76_wcid *wcid; __le32 *txs_data = data; u16 wcidx; @@ -468,15 +473,15 @@ void mt7921_mac_add_txs(struct mt792x_dev *dev, void *data) if (!wcid) goto out; - msta = container_of(wcid, struct mt792x_sta, wcid); + mlink = container_of(wcid, struct mt792x_link_sta, wcid); mt76_connac2_mac_add_txs_skb(&dev->mt76, wcid, pid, txs_data); if (!wcid->sta) goto out; spin_lock_bh(&dev->mt76.sta_poll_lock); - if (list_empty(&msta->wcid.poll_list)) - list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list); + if (list_empty(&mlink->wcid.poll_list)) + list_add_tail(&mlink->wcid.poll_list, &dev->mt76.sta_poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); out: @@ -513,7 +518,7 @@ static void mt7921_mac_tx_free(struct mt792x_dev *dev, void *data, int len) * 1'b0: msdu_id with the same 'wcid pair' as above. */ if (info & MT_TX_FREE_PAIR) { - struct mt792x_sta *msta; + struct mt792x_link_sta *mlink; u16 idx; count++; @@ -523,10 +528,10 @@ static void mt7921_mac_tx_free(struct mt792x_dev *dev, void *data, int len) if (!sta) continue; - msta = container_of(wcid, struct mt792x_sta, wcid); + mlink = container_of(wcid, struct mt792x_link_sta, wcid); spin_lock_bh(&mdev->sta_poll_lock); - if (list_empty(&msta->wcid.poll_list)) - list_add_tail(&msta->wcid.poll_list, + if (list_empty(&mlink->wcid.poll_list)) + list_add_tail(&mlink->wcid.poll_list, &mdev->sta_poll_list); spin_unlock_bh(&mdev->sta_poll_lock); continue; @@ -641,11 +646,11 @@ mt7921_vif_connect_iter(void *priv, u8 *mac, if (vif->type == NL80211_IFTYPE_STATION) ieee80211_disconnect(vif, true); - mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.wcid, true); + mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.deflink.wcid, true); mt7921_mcu_set_tx(dev, vif); if (vif->type == NL80211_IFTYPE_AP) { - mt76_connac_mcu_uni_add_bss(dev->phy.mt76, vif, &mvif->sta.wcid, + mt76_connac_mcu_uni_add_bss(dev->phy.mt76, vif, &mvif->sta.deflink.wcid, true, NULL); mt7921_mcu_sta_update(dev, NULL, vif, true, MT76_STA_INFO_STATE_NONE); @@ -786,9 +791,9 @@ int mt7921_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (sta) { struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; - if (time_after(jiffies, msta->last_txs + HZ / 4)) { + if (time_after(jiffies, msta->deflink.last_txs + HZ / 4)) { info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; - msta->last_txs = jiffies; + msta->deflink.last_txs = jiffies; } } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 77999d778a38..f83cb45957d2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -306,7 +306,7 @@ mt7921_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) mvif->bss_conf.mt76.band_idx = 0; mvif->bss_conf.mt76.wmm_idx = mvif->bss_conf.mt76.idx % MT76_CONNAC_MAX_WMM_SETS; - ret = mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.wcid, + ret = mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.deflink.wcid, true); if (ret) goto out; @@ -316,19 +316,19 @@ mt7921_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) idx = MT792x_WTBL_RESERVED - mvif->bss_conf.mt76.idx; - INIT_LIST_HEAD(&mvif->sta.wcid.poll_list); - mvif->sta.wcid.idx = idx; - mvif->sta.wcid.phy_idx = mvif->bss_conf.mt76.band_idx; - mvif->sta.wcid.hw_key_idx = -1; - mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; - mt76_wcid_init(&mvif->sta.wcid); + INIT_LIST_HEAD(&mvif->sta.deflink.wcid.poll_list); + mvif->sta.deflink.wcid.idx = idx; + mvif->sta.deflink.wcid.phy_idx = mvif->bss_conf.mt76.band_idx; + mvif->sta.deflink.wcid.hw_key_idx = -1; + mvif->sta.deflink.wcid.tx_info |= MT_WCID_TX_INFO_SET; + mt76_wcid_init(&mvif->sta.deflink.wcid); mt7921_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); ewma_rssi_init(&mvif->bss_conf.rssi); - rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); + rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.deflink.wcid); if (vif->txq) { mtxq = (struct mt76_txq *)vif->txq->drv_priv; mtxq->wcid = idx; @@ -494,7 +494,7 @@ static int mt7921_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_sta *msta = sta ? (struct mt792x_sta *)sta->drv_priv : &mvif->sta; - struct mt76_wcid *wcid = &msta->wcid; + struct mt76_wcid *wcid = &msta->deflink.wcid; u8 *wcid_keyidx = &wcid->hw_key_idx; int idx = key->keyidx, err = 0; @@ -541,18 +541,18 @@ static int mt7921_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } mt76_wcid_key_setup(&dev->mt76, wcid, key); - err = mt76_connac_mcu_add_key(&dev->mt76, vif, &msta->bip, + err = mt76_connac_mcu_add_key(&dev->mt76, vif, &msta->deflink.bip, key, MCU_UNI_CMD(STA_REC_UPDATE), - &msta->wcid, cmd); + &msta->deflink.wcid, cmd); if (err) goto out; if (key->cipher == WLAN_CIPHER_SUITE_WEP104 || key->cipher == WLAN_CIPHER_SUITE_WEP40) err = mt76_connac_mcu_add_key(&dev->mt76, vif, - &mvif->wep_sta->bip, + &mvif->wep_sta->deflink.bip, key, MCU_UNI_CMD(STA_REC_UPDATE), - &mvif->wep_sta->wcid, cmd); + &mvif->wep_sta->deflink.wcid, cmd); out: mt792x_mutex_release(dev); @@ -799,13 +799,13 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (idx < 0) return -ENOSPC; - INIT_LIST_HEAD(&msta->wcid.poll_list); + INIT_LIST_HEAD(&msta->deflink.wcid.poll_list); msta->vif = mvif; - msta->wcid.sta = 1; - msta->wcid.idx = idx; - msta->wcid.phy_idx = mvif->bss_conf.mt76.band_idx; - msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; - msta->last_txs = jiffies; + msta->deflink.wcid.sta = 1; + msta->deflink.wcid.idx = idx; + msta->deflink.wcid.phy_idx = mvif->bss_conf.mt76.band_idx; + msta->deflink.wcid.tx_info |= MT_WCID_TX_INFO_SET; + msta->deflink.last_txs = jiffies; ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm); if (ret) @@ -840,14 +840,14 @@ void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, mt792x_mutex_acquire(dev); if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) - mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, &mvif->sta.wcid, + mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, &mvif->sta.deflink.wcid, true, mvif->bss_conf.mt76.ctx); - ewma_avg_signal_init(&msta->avg_ack_signal); + ewma_avg_signal_init(&msta->deflink.avg_ack_signal); - mt7921_mac_wtbl_update(dev, msta->wcid.idx, + mt7921_mac_wtbl_update(dev, msta->deflink.wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac)); + memset(msta->deflink.airtime_ac, 0, sizeof(msta->deflink.airtime_ac)); mt7921_mcu_sta_update(dev, sta, vif, true, MT76_STA_INFO_STATE_ASSOC); @@ -861,11 +861,11 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; - mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->wcid); + mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->deflink.wcid); mt76_connac_pm_wake(&dev->mphy, &dev->pm); mt7921_mcu_sta_update(dev, sta, vif, false, MT76_STA_INFO_STATE_NONE); - mt7921_mac_wtbl_update(dev, msta->wcid.idx, + mt7921_mac_wtbl_update(dev, msta->deflink.wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); if (vif->type == NL80211_IFTYPE_STATION) { @@ -875,13 +875,13 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, ewma_rssi_init(&mvif->bss_conf.rssi); if (!sta->tdls) mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, - &mvif->sta.wcid, false, + &mvif->sta.deflink.wcid, false, mvif->bss_conf.mt76.ctx); } spin_lock_bh(&dev->mt76.sta_poll_lock); - if (!list_empty(&msta->wcid.poll_list)) - list_del_init(&msta->wcid.poll_list); + if (!list_empty(&msta->deflink.wcid.poll_list)) + list_del_init(&msta->deflink.wcid.poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); mt7921_regd_set_6ghz_power_type(vif, false); @@ -923,12 +923,12 @@ mt7921_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt792x_mutex_acquire(dev); switch (action) { case IEEE80211_AMPDU_RX_START: - mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, + mt76_rx_aggr_start(&dev->mt76, &msta->deflink.wcid, tid, ssn, params->buf_size); mt7921_mcu_uni_rx_ba(dev, params, true); break; case IEEE80211_AMPDU_RX_STOP: - mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); + mt76_rx_aggr_stop(&dev->mt76, &msta->deflink.wcid, tid); mt7921_mcu_uni_rx_ba(dev, params, false); break; case IEEE80211_AMPDU_TX_OPERATIONAL: @@ -939,16 +939,16 @@ mt7921_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: mtxq->aggr = false; - clear_bit(tid, &msta->wcid.ampdu_state); + clear_bit(tid, &msta->deflink.wcid.ampdu_state); mt7921_mcu_uni_tx_ba(dev, params, false); break; case IEEE80211_AMPDU_TX_START: - set_bit(tid, &msta->wcid.ampdu_state); + set_bit(tid, &msta->deflink.wcid.ampdu_state); ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; case IEEE80211_AMPDU_TX_STOP_CONT: mtxq->aggr = false; - clear_bit(tid, &msta->wcid.ampdu_state); + clear_bit(tid, &msta->deflink.wcid.ampdu_state); mt7921_mcu_uni_tx_ba(dev, params, false); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; @@ -1166,11 +1166,11 @@ static void mt7921_sta_set_decap_offload(struct ieee80211_hw *hw, mt792x_mutex_acquire(dev); if (enabled) - set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); + set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->deflink.wcid.flags); else - clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); + clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->deflink.wcid.flags); - mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76, vif, &msta->wcid, + mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76, vif, &msta->deflink.wcid, MCU_UNI_CMD(STA_REC_UPDATE)); mt792x_mutex_release(dev); @@ -1294,7 +1294,7 @@ mt7921_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt792x_mutex_acquire(dev); - err = mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid, + err = mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.deflink.wcid, true, mvif->bss_conf.mt76.ctx); if (err) goto out; @@ -1326,7 +1326,7 @@ mt7921_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (err) goto out; - mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid, false, + mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.deflink.wcid, false, mvif->bss_conf.mt76.ctx); out: diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 0453af012016..394fcd799345 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -386,7 +386,7 @@ int mt7921_mcu_uni_tx_ba(struct mt792x_dev *dev, struct mt792x_sta *msta = (struct mt792x_sta *)params->sta->drv_priv; if (enable && !params->amsdu) - msta->wcid.amsdu = false; + msta->deflink.wcid.amsdu = false; return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->bss_conf.mt76, params, MCU_UNI_CMD(STA_REC_UPDATE), @@ -1055,7 +1055,7 @@ int mt7921_mcu_sta_update(struct mt792x_dev *dev, struct ieee80211_sta *sta, struct mt792x_sta *msta; msta = sta ? (struct mt792x_sta *)sta->drv_priv : NULL; - info.wcid = msta ? &msta->wcid : &mvif->sta.wcid; + info.wcid = msta ? &msta->deflink.wcid : &mvif->sta.deflink.wcid; info.newly = msta ? state != MT76_STA_INFO_STATE_ASSOC : true; return mt76_connac_mcu_sta_cmd(&dev->mphy, &info); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c index 031ba9aaa4e2..2452b1a2d118 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c @@ -34,9 +34,9 @@ int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (sta) { struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; - if (time_after(jiffies, msta->last_txs + HZ / 4)) { + if (time_after(jiffies, msta->deflink.last_txs + HZ / 4)) { info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; - msta->last_txs = jiffies; + msta->deflink.last_txs = jiffies; } } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c index c2460ef4993d..88e7b2ff4593 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c @@ -28,6 +28,7 @@ static void mt7925_mac_sta_poll(struct mt792x_dev *dev) }; struct ieee80211_sta *sta; struct mt792x_sta *msta; + struct mt792x_link_sta *mlink; u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS]; LIST_HEAD(sta_poll_list); struct rate_info *rate; @@ -46,24 +47,25 @@ static void mt7925_mac_sta_poll(struct mt792x_dev *dev) if (list_empty(&sta_poll_list)) break; - msta = list_first_entry(&sta_poll_list, - struct mt792x_sta, wcid.poll_list); + mlink = list_first_entry(&sta_poll_list, + struct mt792x_link_sta, wcid.poll_list); + msta = container_of(mlink, struct mt792x_sta, deflink); spin_lock_bh(&dev->mt76.sta_poll_lock); - list_del_init(&msta->wcid.poll_list); + list_del_init(&mlink->wcid.poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); - idx = msta->wcid.idx; + idx = mlink->wcid.idx; addr = mt7925_mac_wtbl_lmac_addr(dev, idx, MT_WTBL_AC0_CTT_OFFSET); for (i = 0; i < IEEE80211_NUM_ACS; i++) { - u32 tx_last = msta->airtime_ac[i]; - u32 rx_last = msta->airtime_ac[i + 4]; + u32 tx_last = mlink->airtime_ac[i]; + u32 rx_last = mlink->airtime_ac[i + 4]; - msta->airtime_ac[i] = mt76_rr(dev, addr); - msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4); + mlink->airtime_ac[i] = mt76_rr(dev, addr); + mlink->airtime_ac[i + 4] = mt76_rr(dev, addr + 4); - tx_time[i] = msta->airtime_ac[i] - tx_last; - rx_time[i] = msta->airtime_ac[i + 4] - rx_last; + tx_time[i] = mlink->airtime_ac[i] - tx_last; + rx_time[i] = mlink->airtime_ac[i + 4] - rx_last; if ((tx_last | rx_last) & BIT(30)) clear = true; @@ -74,10 +76,10 @@ static void mt7925_mac_sta_poll(struct mt792x_dev *dev) if (clear) { mt7925_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac)); + memset(mlink->airtime_ac, 0, sizeof(mlink->airtime_ac)); } - if (!msta->wcid.sta) + if (!mlink->wcid.sta) continue; sta = container_of((void *)msta, struct ieee80211_sta, @@ -100,7 +102,7 @@ static void mt7925_mac_sta_poll(struct mt792x_dev *dev) * we need to make sure that flags match so polling GI * from per-sta counters directly. */ - rate = &msta->wcid.rate; + rate = &mlink->wcid.rate; switch (rate->bw) { case RATE_INFO_BW_160: @@ -144,10 +146,10 @@ static void mt7925_mac_sta_poll(struct mt792x_dev *dev) rssi[2] = to_rssi(GENMASK(23, 16), val); rssi[3] = to_rssi(GENMASK(31, 14), val); - msta->ack_signal = + mlink->ack_signal = mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi); - ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal); + ewma_avg_signal_add(&mlink->avg_ack_signal, -mlink->ack_signal); } } @@ -365,7 +367,7 @@ mt7925_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb) u32 rxd2 = le32_to_cpu(rxd[2]); u32 rxd3 = le32_to_cpu(rxd[3]); u32 rxd4 = le32_to_cpu(rxd[4]); - struct mt792x_sta *msta = NULL; + struct mt792x_link_sta *mlink; u8 mode = 0; /* , band_idx; */ u16 seq_ctrl = 0; __le16 fc = 0; @@ -393,10 +395,10 @@ mt7925_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb) status->wcid = mt792x_rx_get_wcid(dev, idx, unicast); if (status->wcid) { - msta = container_of(status->wcid, struct mt792x_sta, wcid); + mlink = container_of(status->wcid, struct mt792x_link_sta, wcid); spin_lock_bh(&dev->mt76.sta_poll_lock); - if (list_empty(&msta->wcid.poll_list)) - list_add_tail(&msta->wcid.poll_list, + if (list_empty(&mlink->wcid.poll_list)) + list_add_tail(&mlink->wcid.poll_list, &dev->mt76.sta_poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); } @@ -851,7 +853,7 @@ static void mt7925_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) return; msta = (struct mt792x_sta *)sta->drv_priv; - if (!test_and_set_bit(tid, &msta->wcid.ampdu_state)) + if (!test_and_set_bit(tid, &msta->deflink.wcid.ampdu_state)) ieee80211_start_tx_ba_session(sta, tid, 0); } @@ -991,7 +993,7 @@ mt7925_mac_add_txs_skb(struct mt792x_dev *dev, struct mt76_wcid *wcid, void mt7925_mac_add_txs(struct mt792x_dev *dev, void *data) { - struct mt792x_sta *msta = NULL; + struct mt792x_link_sta *mlink = NULL; struct mt76_wcid *wcid; __le32 *txs_data = data; u16 wcidx; @@ -1015,15 +1017,15 @@ void mt7925_mac_add_txs(struct mt792x_dev *dev, void *data) if (!wcid) goto out; - msta = container_of(wcid, struct mt792x_sta, wcid); + mlink = container_of(wcid, struct mt792x_link_sta, wcid); mt7925_mac_add_txs_skb(dev, wcid, pid, txs_data); if (!wcid->sta) goto out; spin_lock_bh(&dev->mt76.sta_poll_lock); - if (list_empty(&msta->wcid.poll_list)) - list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list); + if (list_empty(&mlink->wcid.poll_list)) + list_add_tail(&mlink->wcid.poll_list, &dev->mt76.sta_poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); out: @@ -1094,7 +1096,7 @@ mt7925_mac_tx_free(struct mt792x_dev *dev, void *data, int len) */ info = le32_to_cpu(*cur_info); if (info & MT_TXFREE_INFO_PAIR) { - struct mt792x_sta *msta; + struct mt792x_link_sta *mlink; u16 idx; idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info); @@ -1103,10 +1105,10 @@ mt7925_mac_tx_free(struct mt792x_dev *dev, void *data, int len) if (!sta) continue; - msta = container_of(wcid, struct mt792x_sta, wcid); + mlink = container_of(wcid, struct mt792x_link_sta, wcid); spin_lock_bh(&mdev->sta_poll_lock); - if (list_empty(&msta->wcid.poll_list)) - list_add_tail(&msta->wcid.poll_list, + if (list_empty(&mlink->wcid.poll_list)) + list_add_tail(&mlink->wcid.poll_list, &mdev->sta_poll_list); spin_unlock_bh(&mdev->sta_poll_lock); continue; @@ -1241,11 +1243,11 @@ mt7925_vif_connect_iter(void *priv, u8 *mac, if (vif->type == NL80211_IFTYPE_STATION) ieee80211_disconnect(vif, true); - mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.wcid, true); + mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.deflink.wcid, true); mt7925_mcu_set_tx(dev, vif); if (vif->type == NL80211_IFTYPE_AP) { - mt76_connac_mcu_uni_add_bss(dev->phy.mt76, vif, &mvif->sta.wcid, + mt76_connac_mcu_uni_add_bss(dev->phy.mt76, vif, &mvif->sta.deflink.wcid, true, NULL); mt7925_mcu_sta_update(dev, NULL, vif, true, MT76_STA_INFO_STATE_NONE); @@ -1380,9 +1382,9 @@ int mt7925_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (sta) { struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; - if (time_after(jiffies, msta->last_txs + HZ / 4)) { + if (time_after(jiffies, msta->deflink.last_txs + HZ / 4)) { info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; - msta->last_txs = jiffies; + msta->deflink.last_txs = jiffies; } } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index dfc606cc9bdd..504c2ecc3845 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -344,7 +344,7 @@ mt7925_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) else mvif->bss_conf.mt76.basic_rates_idx = MT792x_BASIC_RATES_TBL; - ret = mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.wcid, + ret = mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.deflink.wcid, true); if (ret) goto out; @@ -354,20 +354,20 @@ mt7925_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) idx = MT792x_WTBL_RESERVED - mvif->bss_conf.mt76.idx; - INIT_LIST_HEAD(&mvif->sta.wcid.poll_list); - mvif->sta.wcid.idx = idx; - mvif->sta.wcid.phy_idx = mvif->bss_conf.mt76.band_idx; - mvif->sta.wcid.hw_key_idx = -1; - mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; + INIT_LIST_HEAD(&mvif->sta.deflink.wcid.poll_list); + mvif->sta.deflink.wcid.idx = idx; + mvif->sta.deflink.wcid.phy_idx = mvif->bss_conf.mt76.band_idx; + mvif->sta.deflink.wcid.hw_key_idx = -1; + mvif->sta.deflink.wcid.tx_info |= MT_WCID_TX_INFO_SET; mvif->sta.vif = mvif; - mt76_wcid_init(&mvif->sta.wcid); + mt76_wcid_init(&mvif->sta.deflink.wcid); mt7925_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); ewma_rssi_init(&mvif->bss_conf.rssi); - rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); + rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.deflink.wcid); if (vif->txq) { mtxq = (struct mt76_txq *)vif->txq->drv_priv; mtxq->wcid = idx; @@ -486,7 +486,7 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_sta *msta = sta ? (struct mt792x_sta *)sta->drv_priv : &mvif->sta; - struct mt76_wcid *wcid = &msta->wcid; + struct mt76_wcid *wcid = &msta->deflink.wcid; u8 *wcid_keyidx = &wcid->hw_key_idx; int idx = key->keyidx, err = 0; @@ -541,18 +541,18 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mt76_wcid_key_setup(&dev->mt76, wcid, cmd == SET_KEY ? key : NULL); - err = mt7925_mcu_add_key(&dev->mt76, vif, &msta->bip, + err = mt7925_mcu_add_key(&dev->mt76, vif, &msta->deflink.bip, key, MCU_UNI_CMD(STA_REC_UPDATE), - &msta->wcid, cmd); + &msta->deflink.wcid, cmd); if (err) goto out; if (key->cipher == WLAN_CIPHER_SUITE_WEP104 || key->cipher == WLAN_CIPHER_SUITE_WEP40) - err = mt7925_mcu_add_key(&dev->mt76, vif, &mvif->wep_sta->bip, + err = mt7925_mcu_add_key(&dev->mt76, vif, &mvif->wep_sta->deflink.bip, key, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), - &mvif->wep_sta->wcid, cmd); + &mvif->wep_sta->deflink.wcid, cmd); out: mt792x_mutex_release(dev); @@ -766,13 +766,13 @@ int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (idx < 0) return -ENOSPC; - INIT_LIST_HEAD(&msta->wcid.poll_list); + INIT_LIST_HEAD(&msta->deflink.wcid.poll_list); msta->vif = mvif; - msta->wcid.sta = 1; - msta->wcid.idx = idx; - msta->wcid.phy_idx = mvif->bss_conf.mt76.band_idx; - msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; - msta->last_txs = jiffies; + msta->deflink.wcid.sta = 1; + msta->deflink.wcid.idx = idx; + msta->deflink.wcid.phy_idx = mvif->bss_conf.mt76.band_idx; + msta->deflink.wcid.tx_info |= MT_WCID_TX_INFO_SET; + msta->deflink.last_txs = jiffies; ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm); if (ret) @@ -813,11 +813,11 @@ void mt7925_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, vif, sta, true); - ewma_avg_signal_init(&msta->avg_ack_signal); + ewma_avg_signal_init(&msta->deflink.avg_ack_signal); - mt7925_mac_wtbl_update(dev, msta->wcid.idx, + mt7925_mac_wtbl_update(dev, msta->deflink.wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac)); + memset(msta->deflink.airtime_ac, 0, sizeof(msta->deflink.airtime_ac)); mt7925_mcu_sta_update(dev, sta, vif, true, MT76_STA_INFO_STATE_ASSOC); @@ -831,11 +831,11 @@ void mt7925_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; - mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->wcid); + mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->deflink.wcid); mt76_connac_pm_wake(&dev->mphy, &dev->pm); mt7925_mcu_sta_update(dev, sta, vif, false, MT76_STA_INFO_STATE_NONE); - mt7925_mac_wtbl_update(dev, msta->wcid.idx, + mt7925_mac_wtbl_update(dev, msta->deflink.wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); if (vif->type == NL80211_IFTYPE_STATION) { @@ -849,8 +849,8 @@ void mt7925_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, } spin_lock_bh(&mdev->sta_poll_lock); - if (!list_empty(&msta->wcid.poll_list)) - list_del_init(&msta->wcid.poll_list); + if (!list_empty(&msta->deflink.wcid.poll_list)) + list_del_init(&msta->deflink.wcid.poll_list); spin_unlock_bh(&mdev->sta_poll_lock); mt76_connac_power_save_sched(&dev->mphy, &dev->pm); @@ -890,12 +890,12 @@ mt7925_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt792x_mutex_acquire(dev); switch (action) { case IEEE80211_AMPDU_RX_START: - mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, + mt76_rx_aggr_start(&dev->mt76, &msta->deflink.wcid, tid, ssn, params->buf_size); mt7925_mcu_uni_rx_ba(dev, params, true); break; case IEEE80211_AMPDU_RX_STOP: - mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); + mt76_rx_aggr_stop(&dev->mt76, &msta->deflink.wcid, tid); mt7925_mcu_uni_rx_ba(dev, params, false); break; case IEEE80211_AMPDU_TX_OPERATIONAL: @@ -906,16 +906,16 @@ mt7925_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: mtxq->aggr = false; - clear_bit(tid, &msta->wcid.ampdu_state); + clear_bit(tid, &msta->deflink.wcid.ampdu_state); mt7925_mcu_uni_tx_ba(dev, params, false); break; case IEEE80211_AMPDU_TX_START: - set_bit(tid, &msta->wcid.ampdu_state); + set_bit(tid, &msta->deflink.wcid.ampdu_state); ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; case IEEE80211_AMPDU_TX_STOP_CONT: mtxq->aggr = false; - clear_bit(tid, &msta->wcid.ampdu_state); + clear_bit(tid, &msta->deflink.wcid.ampdu_state); mt7925_mcu_uni_tx_ba(dev, params, false); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; @@ -1161,9 +1161,9 @@ static void mt7925_sta_set_decap_offload(struct ieee80211_hw *hw, mt792x_mutex_acquire(dev); if (enabled) - set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); + set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->deflink.wcid.flags); else - clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); + clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->deflink.wcid.flags); mt7925_mcu_wtbl_update_hdr_trans(dev, vif, sta); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index c259aedb96e0..67c05f785190 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -544,7 +544,7 @@ int mt7925_mcu_uni_tx_ba(struct mt792x_dev *dev, struct mt792x_vif *mvif = msta->vif; if (enable && !params->amsdu) - msta->wcid.amsdu = false; + msta->deflink.wcid.amsdu = false; return mt7925_mcu_sta_ba(&dev->mt76, &mvif->bss_conf.mt76, params, enable, true); @@ -867,7 +867,7 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb, if (sta) wcid = (struct mt76_wcid *)sta->drv_priv; else - wcid = &mvif->sta.wcid; + wcid = &mvif->sta.deflink.wcid; if (!wcid) return; @@ -890,7 +890,7 @@ int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev, msta = sta ? (struct mt792x_sta *)sta->drv_priv : &mvif->sta; skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->bss_conf.mt76, - &msta->wcid, + &msta->deflink.wcid, MT7925_STA_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -962,7 +962,8 @@ mt7925_mcu_sta_key_tlv(struct mt76_wcid *wcid, struct ieee80211_key_conf *key, enum set_key_cmd cmd) { - struct mt792x_sta *msta = container_of(wcid, struct mt792x_sta, wcid); + struct mt792x_link_sta *mlink = container_of(wcid, struct mt792x_link_sta, wcid); + struct mt792x_sta *msta = container_of(mlink, struct mt792x_sta, deflink); struct sta_rec_sec_uni *sec; struct mt792x_vif *mvif = msta->vif; struct ieee80211_sta *sta; @@ -1480,7 +1481,7 @@ mt7925_mcu_sta_amsdu_tlv(struct sk_buff *skb, amsdu = (struct sta_rec_amsdu *)tlv; amsdu->max_amsdu_num = 8; amsdu->amsdu_en = true; - msta->wcid.amsdu = true; + msta->deflink.wcid.amsdu = true; switch (sta->deflink.agg.max_amsdu_len) { case IEEE80211_MAX_MPDU_LEN_VHT_11454: @@ -1668,7 +1669,7 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev, struct ieee80211_sta *sta, struct mt792x_sta *msta; msta = sta ? (struct mt792x_sta *)sta->drv_priv : NULL; - info.wcid = msta ? &msta->wcid : &mvif->sta.wcid; + info.wcid = msta ? &msta->deflink.wcid : &mvif->sta.deflink.wcid; info.newly = msta ? state != MT76_STA_INFO_STATE_ASSOC : true; return mt7925_mcu_sta_cmd(&dev->mphy, &info); @@ -2096,7 +2097,7 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, basic_req->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); basic_req->dtim_period = vif->bss_conf.dtim_period; basic_req->bmc_tx_wlan_idx = cpu_to_le16(wlan_idx); - basic_req->sta_idx = cpu_to_le16(msta->wcid.idx); + basic_req->sta_idx = cpu_to_le16(msta->deflink.wcid.idx); basic_req->omac_idx = mvif->bss_conf.mt76.omac_idx; basic_req->band_idx = mvif->bss_conf.mt76.band_idx; basic_req->wmm_idx = mvif->bss_conf.mt76.wmm_idx; @@ -2330,7 +2331,7 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, /* bss_basic must be first */ mt7925_mcu_bss_basic_tlv(skb, vif, sta, ctx, phy->mt76, - mvif->sta.wcid.idx, enable); + mvif->sta.deflink.wcid.idx, enable); mt7925_mcu_bss_sec_tlv(skb, vif); mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, vif, sta); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c index 9fca887977d2..ef631a68005d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c @@ -34,9 +34,9 @@ int mt7925e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (sta) { struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; - if (time_after(jiffies, msta->last_txs + HZ / 4)) { + if (time_after(jiffies, msta->deflink.last_txs + HZ / 4)) { info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; - msta->last_txs = jiffies; + msta->deflink.last_txs = jiffies; } } diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index 27bfda04d0f2..97865404444d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -81,11 +81,9 @@ enum mt792x_reg_power_type { DECLARE_EWMA(avg_signal, 10, 8) -struct mt792x_sta { +struct mt792x_link_sta { struct mt76_wcid wcid; /* must be first */ - struct mt792x_vif *vif; - u32 airtime_ac[8]; int ack_signal; @@ -96,6 +94,12 @@ struct mt792x_sta { struct mt76_connac_sta_key_conf bip; }; +struct mt792x_sta { + struct mt792x_link_sta deflink; /* must be first */ + + struct mt792x_vif *vif; +}; + DECLARE_EWMA(rssi, 10, 8); struct mt792x_bss_conf { diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c index 9eeaf3344217..dbe98d4dbf94 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c @@ -65,14 +65,14 @@ void mt792x_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct mt792x_sta *sta; sta = (struct mt792x_sta *)control->sta->drv_priv; - wcid = &sta->wcid; + wcid = &sta->deflink.wcid; } if (vif && !control->sta) { struct mt792x_vif *mvif; mvif = (struct mt792x_vif *)vif->drv_priv; - wcid = &mvif->sta.wcid; + wcid = &mvif->sta.deflink.wcid; } if (mt76_connac_pm_ref(mphy, &dev->pm)) { @@ -120,11 +120,11 @@ void mt792x_remove_interface(struct ieee80211_hw *hw, struct mt792x_sta *msta = &mvif->sta; struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt792x_phy *phy = mt792x_hw_phy(hw); - int idx = msta->wcid.idx; + int idx = msta->deflink.wcid.idx; mt792x_mutex_acquire(dev); - mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->wcid); - mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.wcid, false); + mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->deflink.wcid); + mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.deflink.wcid, false); rcu_assign_pointer(dev->mt76.wcid[idx], NULL); @@ -133,11 +133,11 @@ void mt792x_remove_interface(struct ieee80211_hw *hw, mt792x_mutex_release(dev); spin_lock_bh(&dev->mt76.sta_poll_lock); - if (!list_empty(&msta->wcid.poll_list)) - list_del_init(&msta->wcid.poll_list); + if (!list_empty(&msta->deflink.wcid.poll_list)) + list_del_init(&msta->deflink.wcid.poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); - mt76_wcid_cleanup(&dev->mt76, &msta->wcid); + mt76_wcid_cleanup(&dev->mt76, &msta->deflink.wcid); } EXPORT_SYMBOL_GPL(mt792x_remove_interface); @@ -408,7 +408,7 @@ mt792x_ethtool_worker(void *wi_data, struct ieee80211_sta *sta) if (msta->vif->bss_conf.mt76.idx != wi->idx) return; - mt76_ethtool_worker(wi, &msta->wcid.stats, true); + mt76_ethtool_worker(wi, &msta->deflink.wcid.stats, true); } void mt792x_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -487,7 +487,7 @@ void mt792x_sta_statistics(struct ieee80211_hw *hw, struct station_info *sinfo) { struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; - struct rate_info *txrate = &msta->wcid.rate; + struct rate_info *txrate = &msta->deflink.wcid.rate; if (!txrate->legacy && !txrate->flags) return; @@ -502,19 +502,19 @@ void mt792x_sta_statistics(struct ieee80211_hw *hw, sinfo->txrate.he_dcm = txrate->he_dcm; sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc; } - sinfo->tx_failed = msta->wcid.stats.tx_failed; + sinfo->tx_failed = msta->deflink.wcid.stats.tx_failed; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); - sinfo->tx_retries = msta->wcid.stats.tx_retries; + sinfo->tx_retries = msta->deflink.wcid.stats.tx_retries; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); sinfo->txrate.flags = txrate->flags; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); - sinfo->ack_signal = (s8)msta->ack_signal; + sinfo->ack_signal = (s8)msta->deflink.ack_signal; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL); - sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read(&msta->avg_ack_signal); + sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read(&msta->deflink.avg_ack_signal); sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG); } EXPORT_SYMBOL_GPL(mt792x_sta_statistics); diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c index 45dd94ff386d..106273935b26 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c @@ -138,6 +138,7 @@ EXPORT_SYMBOL_GPL(mt792x_mac_update_mib_stats); struct mt76_wcid *mt792x_rx_get_wcid(struct mt792x_dev *dev, u16 idx, bool unicast) { + struct mt792x_link_sta *link; struct mt792x_sta *sta; struct mt76_wcid *wcid; @@ -151,11 +152,12 @@ struct mt76_wcid *mt792x_rx_get_wcid(struct mt792x_dev *dev, u16 idx, if (!wcid->sta) return NULL; - sta = container_of(wcid, struct mt792x_sta, wcid); + link = container_of(wcid, struct mt792x_link_sta, wcid); + sta = container_of(link, struct mt792x_sta, deflink); if (!sta->vif) return NULL; - return &sta->vif->sta.wcid; + return &sta->vif->sta.deflink.wcid; } EXPORT_SYMBOL_GPL(mt792x_rx_get_wcid); From f3898da2e86e43b83165347acf9194914a9146e0 Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Wed, 12 Jun 2024 20:01:57 -0700 Subject: [PATCH 120/204] wifi: mt76: mt792x: add struct mt792x_chanctx We are introducing a new structure, mt792x_chanctx, to quickly identify the linked BSS it is working on. This eliminates the need to search in mt7921_ctx_iter() or mt7925_ctx_iter() when the channel context changes. Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Deren Wu Link: https://patch.msgid.link/20240613030241.5771-4-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7921/main.c | 31 ++++++++----------- .../net/wireless/mediatek/mt76/mt7925/main.c | 31 ++++++++----------- drivers/net/wireless/mediatek/mt76/mt792x.h | 4 +++ .../net/wireless/mediatek/mt76/mt792x_core.c | 5 +++ 4 files changed, 35 insertions(+), 36 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index f83cb45957d2..5dd9a7507f0b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -1346,32 +1346,27 @@ mt7921_remove_chanctx(struct ieee80211_hw *hw, { } -static void mt7921_ctx_iter(void *priv, u8 *mac, - struct ieee80211_vif *vif) -{ - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - struct ieee80211_chanctx_conf *ctx = priv; - - if (ctx != mvif->bss_conf.mt76.ctx) - return; - - if (vif->type == NL80211_IFTYPE_MONITOR) - mt7921_mcu_config_sniffer(mvif, ctx); - else - mt76_connac_mcu_uni_set_chctx(mvif->phy->mt76, &mvif->bss_conf.mt76, ctx); -} - static void mt7921_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx, u32 changed) { + struct mt792x_chanctx *mctx = (struct mt792x_chanctx *)ctx->drv_priv; struct mt792x_phy *phy = mt792x_hw_phy(hw); + struct ieee80211_vif *vif; + struct mt792x_vif *mvif; + + if (!mctx->bss_conf) + return; + + mvif = container_of(mctx->bss_conf, struct mt792x_vif, bss_conf); + vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv); mt792x_mutex_acquire(phy->dev); - ieee80211_iterate_active_interfaces(phy->mt76->hw, - IEEE80211_IFACE_ITER_ACTIVE, - mt7921_ctx_iter, ctx); + if (vif->type == NL80211_IFTYPE_MONITOR) + mt7921_mcu_config_sniffer(mvif, ctx); + else + mt76_connac_mcu_uni_set_chctx(mvif->phy->mt76, &mvif->bss_conf.mt76, ctx); mt792x_mutex_release(phy->dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 504c2ecc3845..91edbe076c22 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -1354,34 +1354,29 @@ mt7925_remove_chanctx(struct ieee80211_hw *hw, { } -static void mt7925_ctx_iter(void *priv, u8 *mac, - struct ieee80211_vif *vif) +static void +mt7925_change_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx, + u32 changed) { - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - struct ieee80211_chanctx_conf *ctx = priv; + struct mt792x_chanctx *mctx = (struct mt792x_chanctx *)ctx->drv_priv; + struct mt792x_phy *phy = mt792x_hw_phy(hw); + struct ieee80211_vif *vif; + struct mt792x_vif *mvif; - if (ctx != mvif->bss_conf.mt76.ctx) + if (!mctx->bss_conf) return; + mvif = container_of(mctx->bss_conf, struct mt792x_vif, bss_conf); + vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv); + + mt792x_mutex_acquire(phy->dev); if (vif->type == NL80211_IFTYPE_MONITOR) { mt7925_mcu_set_sniffer(mvif->phy->dev, vif, true); mt7925_mcu_config_sniffer(mvif, ctx); } else { mt7925_mcu_set_chctx(mvif->phy->mt76, &mvif->bss_conf.mt76, ctx); } -} - -static void -mt7925_change_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *ctx, - u32 changed) -{ - struct mt792x_phy *phy = mt792x_hw_phy(hw); - - mt792x_mutex_acquire(phy->dev); - ieee80211_iterate_active_interfaces(phy->mt76->hw, - IEEE80211_IFACE_ITER_ACTIVE, - mt7925_ctx_iter, ctx); mt792x_mutex_release(phy->dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index 97865404444d..eee872aa0108 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -102,6 +102,10 @@ struct mt792x_sta { DECLARE_EWMA(rssi, 10, 8); +struct mt792x_chanctx { + struct mt792x_bss_conf *bss_conf; +}; + struct mt792x_bss_conf { struct mt76_vif mt76; /* must be first */ struct ewma_rssi rssi; diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c index dbe98d4dbf94..4d0e2def1c1d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c @@ -261,11 +261,13 @@ int mt792x_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { + struct mt792x_chanctx *mctx = (struct mt792x_chanctx *)ctx->drv_priv; struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_dev *dev = mt792x_hw_dev(hw); mutex_lock(&dev->mt76.mutex); mvif->bss_conf.mt76.ctx = ctx; + mctx->bss_conf = &mvif->bss_conf; mutex_unlock(&dev->mt76.mutex); return 0; @@ -277,10 +279,12 @@ void mt792x_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { + struct mt792x_chanctx *mctx = (struct mt792x_chanctx *)ctx->drv_priv; struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_dev *dev = mt792x_hw_dev(hw); mutex_lock(&dev->mt76.mutex); + mctx->bss_conf = NULL; mvif->bss_conf.mt76.ctx = NULL; mutex_unlock(&dev->mt76.mutex); } @@ -556,6 +560,7 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw) hw->sta_data_size = sizeof(struct mt792x_sta); hw->vif_data_size = sizeof(struct mt792x_vif); + hw->chanctx_data_size = sizeof(struct mt792x_chanctx); if (dev->fw_features & MT792x_FW_CAP_CNM) { wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; From 43626f0e0c991593ff196a886ccb9455701e4e2e Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Wed, 12 Jun 2024 20:01:58 -0700 Subject: [PATCH 121/204] wifi: mt76: mt7925: support for split bss_info_changed method The .bss_info_changed method is being split into .vif_cfg_changed and .link_info_changed to support MLD devices, but it will still support non-MLD devices. Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Deren Wu Link: https://patch.msgid.link/20240613030241.5771-5-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/main.c | 132 ++++++++++-------- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 7 +- .../net/wireless/mediatek/mt76/mt7925/mcu.h | 3 +- 3 files changed, 76 insertions(+), 66 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 91edbe076c22..397776ddf01a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -695,65 +695,6 @@ mt7925_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return mvif->basic_rates_idx; } -static void mt7925_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, - u64 changed) -{ - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; - struct mt792x_phy *phy = mt792x_hw_phy(hw); - struct mt792x_dev *dev = mt792x_hw_dev(hw); - - mt792x_mutex_acquire(dev); - - if (changed & BSS_CHANGED_ERP_SLOT) { - int slottime = info->use_short_slot ? 9 : 20; - - if (slottime != phy->slottime) { - phy->slottime = slottime; - mt7925_mcu_set_timing(phy, vif); - } - } - - if (changed & BSS_CHANGED_MCAST_RATE) - mvif->mcast_rates_idx = - mt7925_get_rates_table(hw, vif, false, true); - - if (changed & BSS_CHANGED_BASIC_RATES) - mvif->basic_rates_idx = - mt7925_get_rates_table(hw, vif, false, false); - - if (changed & (BSS_CHANGED_BEACON | - BSS_CHANGED_BEACON_ENABLED)) { - mvif->beacon_rates_idx = - mt7925_get_rates_table(hw, vif, true, false); - - mt7925_mcu_uni_add_beacon_offload(dev, hw, vif, - info->enable_beacon); - } - - /* ensure that enable txcmd_mode after bss_info */ - if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED)) - mt7925_mcu_set_tx(dev, vif); - - if (changed & BSS_CHANGED_PS) - mt7925_mcu_uni_bss_ps(dev, vif); - - if (changed & BSS_CHANGED_ASSOC) { - mt7925_mcu_sta_update(dev, NULL, vif, true, - MT76_STA_INFO_STATE_ASSOC); - mt7925_mcu_set_beacon_filter(dev, vif, vif->cfg.assoc); - } - - if (changed & BSS_CHANGED_ARP_FILTER) { - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - - mt7925_mcu_update_arp_filter(&dev->mt76, &mvif->bss_conf.mt76, info); - } - - mt792x_mutex_release(dev); -} - int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { @@ -1404,6 +1345,76 @@ static void mt7925_mgd_complete_tx(struct ieee80211_hw *hw, mt7925_abort_roc(mvif->phy, mvif); } +static void mt7925_vif_cfg_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u64 changed) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + + mt792x_mutex_acquire(dev); + + if (changed & BSS_CHANGED_ASSOC) { + mt7925_mcu_sta_update(dev, NULL, vif, true, + MT76_STA_INFO_STATE_ASSOC); + mt7925_mcu_set_beacon_filter(dev, vif, vif->cfg.assoc); + } + + if (changed & BSS_CHANGED_ARP_FILTER) { + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + + mt7925_mcu_update_arp_filter(&dev->mt76, &mvif->bss_conf.mt76); + } + + if (changed & BSS_CHANGED_PS) + mt7925_mcu_uni_bss_ps(dev, vif); + + mt792x_mutex_release(dev); +} + +static void mt7925_link_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u64 changed) +{ + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt792x_phy *phy = mt792x_hw_phy(hw); + struct mt792x_dev *dev = mt792x_hw_dev(hw); + + mt792x_mutex_acquire(dev); + + if (changed & BSS_CHANGED_ERP_SLOT) { + int slottime = info->use_short_slot ? 9 : 20; + + if (slottime != phy->slottime) { + phy->slottime = slottime; + mt7925_mcu_set_timing(phy, vif); + } + } + + if (changed & BSS_CHANGED_MCAST_RATE) + mvif->mcast_rates_idx = + mt7925_get_rates_table(hw, vif, false, true); + + if (changed & BSS_CHANGED_BASIC_RATES) + mvif->basic_rates_idx = + mt7925_get_rates_table(hw, vif, false, false); + + if (changed & (BSS_CHANGED_BEACON | + BSS_CHANGED_BEACON_ENABLED)) { + mvif->beacon_rates_idx = + mt7925_get_rates_table(hw, vif, true, false); + + mt7925_mcu_uni_add_beacon_offload(dev, hw, vif, + info->enable_beacon); + } + + /* ensure that enable txcmd_mode after bss_info */ + if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED)) + mt7925_mcu_set_tx(dev, vif); + + mt792x_mutex_release(dev); +} + const struct ieee80211_ops mt7925_ops = { .tx = mt792x_tx, .start = mt7925_start, @@ -1413,7 +1424,6 @@ const struct ieee80211_ops mt7925_ops = { .config = mt7925_config, .conf_tx = mt7925_conf_tx, .configure_filter = mt7925_configure_filter, - .bss_info_changed = mt7925_bss_info_changed, .start_ap = mt7925_start_ap, .stop_ap = mt7925_stop_ap, .sta_state = mt76_sta_state, @@ -1461,6 +1471,8 @@ const struct ieee80211_ops mt7925_ops = { .unassign_vif_chanctx = mt792x_unassign_vif_chanctx, .mgd_prepare_tx = mt7925_mgd_prepare_tx, .mgd_complete_tx = mt7925_mgd_complete_tx, + .vif_cfg_changed = mt7925_vif_cfg_changed, + .link_info_changed = mt7925_link_info_changed, }; EXPORT_SYMBOL_GPL(mt7925_ops); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 67c05f785190..5e72f7278e8b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -121,11 +121,10 @@ int mt7925_mcu_regval(struct mt792x_dev *dev, u32 regidx, u32 *val, bool set) EXPORT_SYMBOL_GPL(mt7925_mcu_regval); int mt7925_mcu_update_arp_filter(struct mt76_dev *dev, - struct mt76_vif *vif, - struct ieee80211_bss_conf *info) + struct mt76_vif *vif) { - struct ieee80211_vif *mvif = container_of(info, struct ieee80211_vif, - bss_conf); + struct ieee80211_vif *mvif = container_of((void *)vif, struct ieee80211_vif, + drv_priv); struct sk_buff *skb; int i, len = min_t(int, mvif->cfg.arp_addr_cnt, IEEE80211_BSS_ARP_ADDR_LIST_LEN); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h index b8315a89f4a9..b499b1d0531a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -590,6 +590,5 @@ int mt7925_mcu_set_chctx(struct mt76_phy *phy, struct mt76_vif *mvif, struct ieee80211_chanctx_conf *ctx); int mt7925_mcu_set_rate_txpower(struct mt76_phy *phy); int mt7925_mcu_update_arp_filter(struct mt76_dev *dev, - struct mt76_vif *vif, - struct ieee80211_bss_conf *info); + struct mt76_vif *vif); #endif From 7cebb6a66ac6a08b5fc80c1e6cfb337473f4f4d2 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:01:59 -0700 Subject: [PATCH 122/204] wifi: mt76: mt792x: extend mt76_connac_mcu_uni_add_dev for per-link BSS Extend mt76_connac_mcu_uni_add_dev with per-link BSS configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. We also extend link_idx field in mt76_connac_bss_basic_tlv for the firmware to able to identify the link index in the MLO mode that is not harmful for the current non-MLO mode. Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-6-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 12 +++++++----- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt7925/main.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt792x_core.c | 2 +- 8 files changed, 20 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index c807bd8d928d..792ae41f7c69 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1109,8 +1109,8 @@ mt7615_mcu_uni_add_dev(struct mt7615_phy *phy, struct ieee80211_vif *vif, { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - return mt76_connac_mcu_uni_add_dev(phy->mt76, vif, &mvif->sta.wcid, - enable); + return mt76_connac_mcu_uni_add_dev(phy->mt76, &vif->bss_conf, + &mvif->sta.wcid, enable); } static int diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 162c57fb7954..a059532f383a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1132,11 +1132,11 @@ void mt76_connac_mcu_wtbl_ba_tlv(struct mt76_dev *dev, struct sk_buff *skb, EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_ba_tlv); int mt76_connac_mcu_uni_add_dev(struct mt76_phy *phy, - struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, struct mt76_wcid *wcid, bool enable) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif *mvif = (struct mt76_vif *)bss_conf->vif->drv_priv; struct mt76_dev *dev = phy->dev; struct { struct { @@ -1148,7 +1148,7 @@ int mt76_connac_mcu_uni_add_dev(struct mt76_phy *phy, __le16 tag; __le16 len; u8 active; - u8 pad; + u8 link_idx; /* not link_id */ u8 omac_addr[ETH_ALEN]; } __packed tlv; } dev_req = { @@ -1160,6 +1160,7 @@ int mt76_connac_mcu_uni_add_dev(struct mt76_phy *phy, .tag = cpu_to_le16(DEV_INFO_ACTIVE), .len = cpu_to_le16(sizeof(struct req_tlv)), .active = enable, + .link_idx = mvif->idx, }, }; struct { @@ -1182,12 +1183,13 @@ int mt76_connac_mcu_uni_add_dev(struct mt76_phy *phy, .bmc_tx_wlan_idx = cpu_to_le16(wcid->idx), .sta_idx = cpu_to_le16(wcid->idx), .conn_state = 1, + .link_idx = mvif->idx, }, }; int err, idx, cmd, len; void *data; - switch (vif->type) { + switch (bss_conf->vif->type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_AP: @@ -1207,7 +1209,7 @@ int mt76_connac_mcu_uni_add_dev(struct mt76_phy *phy, idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; basic_req.basic.hw_bss_idx = idx; - memcpy(dev_req.tlv.omac_addr, vif->addr, ETH_ALEN); + memcpy(dev_req.tlv.omac_addr, bss_conf->vif->addr, ETH_ALEN); cmd = enable ? MCU_UNI_CMD(DEV_INFO_UPDATE) : MCU_UNI_CMD(BSS_INFO_UPDATE); data = enable ? (void *)&dev_req : (void *)&basic_req; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 6873ce14d299..5c7c42c95de1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1443,7 +1443,7 @@ struct mt76_connac_bss_basic_tlv { __le16 sta_idx; __le16 nonht_basic_phy; u8 phymode_ext; /* bit(0) AX_6G */ - u8 pad[1]; + u8 link_idx; } __packed; struct mt76_connac_bss_qos_tlv { @@ -1917,7 +1917,7 @@ void mt76_connac_mcu_sta_ba_tlv(struct sk_buff *skb, struct ieee80211_ampdu_params *params, bool enable, bool tx); int mt76_connac_mcu_uni_add_dev(struct mt76_phy *phy, - struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, struct mt76_wcid *wcid, bool enable); int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 9ae9590999f4..047106b65d2b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -646,7 +646,8 @@ mt7921_vif_connect_iter(void *priv, u8 *mac, if (vif->type == NL80211_IFTYPE_STATION) ieee80211_disconnect(vif, true); - mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.deflink.wcid, true); + mt76_connac_mcu_uni_add_dev(&dev->mphy, &vif->bss_conf, + &mvif->sta.deflink.wcid, true); mt7921_mcu_set_tx(dev, vif); if (vif->type == NL80211_IFTYPE_AP) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 5dd9a7507f0b..2e6268cb06c0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -306,8 +306,8 @@ mt7921_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) mvif->bss_conf.mt76.band_idx = 0; mvif->bss_conf.mt76.wmm_idx = mvif->bss_conf.mt76.idx % MT76_CONNAC_MAX_WMM_SETS; - ret = mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.deflink.wcid, - true); + ret = mt76_connac_mcu_uni_add_dev(&dev->mphy, &vif->bss_conf, + &mvif->sta.deflink.wcid, true); if (ret) goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c index 88e7b2ff4593..48425fc4e7fe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c @@ -1243,7 +1243,8 @@ mt7925_vif_connect_iter(void *priv, u8 *mac, if (vif->type == NL80211_IFTYPE_STATION) ieee80211_disconnect(vif, true); - mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.deflink.wcid, true); + mt76_connac_mcu_uni_add_dev(&dev->mphy, &vif->bss_conf, + &mvif->sta.deflink.wcid, true); mt7925_mcu_set_tx(dev, vif); if (vif->type == NL80211_IFTYPE_AP) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 397776ddf01a..b0c8b090d2ce 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -344,8 +344,8 @@ mt7925_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) else mvif->bss_conf.mt76.basic_rates_idx = MT792x_BASIC_RATES_TBL; - ret = mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.deflink.wcid, - true); + ret = mt76_connac_mcu_uni_add_dev(&dev->mphy, &vif->bss_conf, + &mvif->sta.deflink.wcid, true); if (ret) goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c index 4d0e2def1c1d..b1c51e3f39d0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c @@ -124,7 +124,7 @@ void mt792x_remove_interface(struct ieee80211_hw *hw, mt792x_mutex_acquire(dev); mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->deflink.wcid); - mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.deflink.wcid, false); + mt76_connac_mcu_uni_add_dev(&dev->mphy, &vif->bss_conf, &mvif->sta.deflink.wcid, false); rcu_assign_pointer(dev->mt76.wcid[idx], NULL); From acdfc3e79899871ef8146efd9be74a9b78858b67 Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Wed, 12 Jun 2024 20:02:00 -0700 Subject: [PATCH 123/204] wifi: mt76: mt7925: extend mt7925_mcu_set_tx with for per-link BSS Extend mt7925_mcu_set_tx with per-link BSS configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Deren Wu Link: https://patch.msgid.link/20240613030241.5771-7-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/mac.c | 2 +- .../net/wireless/mediatek/mt76/mt7925/main.c | 2 +- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 9 ++++--- .../wireless/mediatek/mt76/mt7925/mt7925.h | 2 +- drivers/net/wireless/mediatek/mt76/mt792x.h | 25 +++++++++++++++++++ 5 files changed, 33 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c index 48425fc4e7fe..2be2ab914411 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c @@ -1245,7 +1245,7 @@ mt7925_vif_connect_iter(void *priv, u8 *mac, mt76_connac_mcu_uni_add_dev(&dev->mphy, &vif->bss_conf, &mvif->sta.deflink.wcid, true); - mt7925_mcu_set_tx(dev, vif); + mt7925_mcu_set_tx(dev, &vif->bss_conf); if (vif->type == NL80211_IFTYPE_AP) { mt76_connac_mcu_uni_add_bss(dev->phy.mt76, vif, &mvif->sta.deflink.wcid, diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index b0c8b090d2ce..d11919688bae 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -1410,7 +1410,7 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw, /* ensure that enable txcmd_mode after bss_info */ if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED)) - mt7925_mcu_set_tx(dev, vif); + mt7925_mcu_set_tx(dev, info); mt792x_mutex_release(dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 5e72f7278e8b..1c262a024dc8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -900,7 +900,8 @@ int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); } -int mt7925_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_vif *vif) +int mt7925_mcu_set_tx(struct mt792x_dev *dev, + struct ieee80211_bss_conf *bss_conf) { #define MCU_EDCA_AC_PARAM 0 #define WMM_AIFS_SET BIT(0) @@ -909,12 +910,12 @@ int mt7925_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_vif *vif) #define WMM_TXOP_SET BIT(3) #define WMM_PARAM_SET (WMM_AIFS_SET | WMM_CW_MIN_SET | \ WMM_CW_MAX_SET | WMM_TXOP_SET) - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(bss_conf); struct { u8 bss_idx; u8 __rsv[3]; } __packed hdr = { - .bss_idx = mvif->bss_conf.mt76.idx, + .bss_idx = mconf->mt76.idx, }; struct sk_buff *skb; int len = sizeof(hdr) + IEEE80211_NUM_ACS * sizeof(struct edca); @@ -927,7 +928,7 @@ int mt7925_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_vif *vif) skb_put_data(skb, &hdr, sizeof(hdr)); for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - struct ieee80211_tx_queue_params *q = &mvif->bss_conf.queue_params[ac]; + struct ieee80211_tx_queue_params *q = &mconf->queue_params[ac]; struct edca *e; struct tlv *tlv; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h index 8a4a71f6bcb6..f689f7a359ea 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h @@ -198,7 +198,7 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev, struct ieee80211_sta *sta, struct ieee80211_vif *vif, bool enable, enum mt76_sta_info_state state); int mt7925_mcu_set_chan_info(struct mt792x_phy *phy, u16 tag); -int mt7925_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_vif *vif); +int mt7925_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_bss_conf *bss_conf); int mt7925_mcu_set_eeprom(struct mt792x_dev *dev); int mt7925_mcu_get_rx_rate(struct mt792x_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct rate_info *rate); diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index eee872aa0108..9630514ae25f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -114,6 +114,7 @@ struct mt792x_bss_conf { struct mt792x_vif { struct mt792x_bss_conf bss_conf; /* must be first */ + struct mt792x_bss_conf __rcu *link_conf[IEEE80211_MLD_MAX_NUM_LINKS]; struct mt792x_sta sta; struct mt792x_sta *wep_sta; @@ -221,6 +222,30 @@ struct mt792x_dev { u32 backup_l2; }; +static inline struct mt792x_bss_conf * +mt792x_vif_to_link(struct mt792x_vif *mvif, u8 link_id) +{ + struct ieee80211_vif *vif; + + vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv); + + if (!ieee80211_vif_is_mld(vif) || + link_id >= IEEE80211_LINK_UNSPECIFIED) + return &mvif->bss_conf; + + return rcu_dereference_protected(mvif->link_conf[link_id], + lockdep_is_held(&mvif->phy->dev->mt76.mutex)); +} + +static inline struct mt792x_bss_conf * +mt792x_link_conf_to_mconf(struct ieee80211_bss_conf *link_conf) +{ + struct ieee80211_vif *vif = link_conf->vif; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + + return mt792x_vif_to_link(mvif, link_conf->link_id); +} + static inline struct mt792x_dev * mt792x_hw_dev(struct ieee80211_hw *hw) { From fa5f44463f51944a2f33caf92c47e2d02217e3f1 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:01 -0700 Subject: [PATCH 124/204] wifi: mt76: mt7925: extend mt7925_mcu_add_bss_info for per-link BSS Extend mt7925_mcu_add_bss_info with per-link BSS configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-8-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/main.c | 35 +++++++++++++------ .../net/wireless/mediatek/mt76/mt7925/mcu.c | 22 ++++++------ .../net/wireless/mediatek/mt76/mt7925/mcu.h | 2 +- drivers/net/wireless/mediatek/mt76/mt792x.h | 10 ++++++ 4 files changed, 46 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index d11919688bae..7b9deb586b34 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -487,9 +487,12 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct mt792x_sta *msta = sta ? (struct mt792x_sta *)sta->drv_priv : &mvif->sta; struct mt76_wcid *wcid = &msta->deflink.wcid; + struct ieee80211_bss_conf *link_conf; u8 *wcid_keyidx = &wcid->hw_key_idx; int idx = key->keyidx, err = 0; + link_conf = mt792x_vif_to_bss_conf(vif, vif->bss_conf.link_id); + /* The hardware does not support per-STA RX GTK, fallback * to software mode for these. */ @@ -528,7 +531,8 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct mt792x_phy *phy = mt792x_hw_phy(hw); mvif->bss_conf.mt76.cipher = mt7925_mcu_get_cipher(key->cipher); - mt7925_mcu_add_bss_info(phy, mvif->bss_conf.mt76.ctx, vif, sta, true); + mt7925_mcu_add_bss_info(phy, mvif->bss_conf.mt76.ctx, link_conf, + sta, true); } if (cmd == SET_KEY) @@ -701,6 +705,7 @@ int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct ieee80211_bss_conf *link_conf; int ret, idx; idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); @@ -725,10 +730,12 @@ int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, mt7925_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + link_conf = mt792x_vif_to_bss_conf(vif, vif->bss_conf.link_id); + /* should update bss info before STA add */ if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) - mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, vif, sta, - false); + mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, + link_conf, sta, false); ret = mt7925_mcu_sta_update(dev, sta, vif, true, MT76_STA_INFO_STATE_NONE); @@ -747,12 +754,15 @@ void mt7925_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct ieee80211_bss_conf *link_conf; mt792x_mutex_acquire(dev); + link_conf = mt792x_vif_to_bss_conf(vif, vif->bss_conf.link_id); + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) - mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, vif, sta, - true); + mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, + link_conf, sta, true); ewma_avg_signal_init(&msta->deflink.avg_ack_signal); @@ -771,6 +781,7 @@ void mt7925_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + struct ieee80211_bss_conf *link_conf; mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->deflink.wcid); mt76_connac_pm_wake(&dev->mphy, &dev->pm); @@ -779,14 +790,16 @@ void mt7925_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, mt7925_mac_wtbl_update(dev, msta->deflink.wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + link_conf = mt792x_vif_to_bss_conf(vif, vif->bss_conf.link_id); + if (vif->type == NL80211_IFTYPE_STATION) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; mvif->wep_sta = NULL; ewma_rssi_init(&mvif->bss_conf.rssi); if (!sta->tdls) - mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, vif, sta, - false); + mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, + link_conf, sta, false); } spin_lock_bh(&mdev->sta_poll_lock); @@ -1244,8 +1257,8 @@ mt7925_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt792x_mutex_acquire(dev); - err = mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, vif, NULL, - true); + err = mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, + link_conf, NULL, true); if (err) goto out; @@ -1275,8 +1288,8 @@ mt7925_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (err) goto out; - mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, vif, NULL, - false); + mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, link_conf, + NULL, false); out: mt792x_mutex_release(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 1c262a024dc8..fb261ee525be 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2315,11 +2315,11 @@ int mt7925_mcu_set_timing(struct mt792x_phy *phy, int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, struct ieee80211_chanctx_conf *ctx, - struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, struct ieee80211_sta *sta, int enable) { - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv; struct mt792x_dev *dev = phy->dev; struct sk_buff *skb; int err; @@ -2330,18 +2330,18 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, return PTR_ERR(skb); /* bss_basic must be first */ - mt7925_mcu_bss_basic_tlv(skb, vif, sta, ctx, phy->mt76, + mt7925_mcu_bss_basic_tlv(skb, link_conf->vif, sta, ctx, phy->mt76, mvif->sta.deflink.wcid.idx, enable); - mt7925_mcu_bss_sec_tlv(skb, vif); + mt7925_mcu_bss_sec_tlv(skb, link_conf->vif); - mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, vif, sta); - mt7925_mcu_bss_qos_tlv(skb, vif); - mt7925_mcu_bss_mld_tlv(skb, vif, sta); - mt7925_mcu_bss_ifs_tlv(skb, vif); + mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, link_conf->vif, sta); + mt7925_mcu_bss_qos_tlv(skb, link_conf->vif); + mt7925_mcu_bss_mld_tlv(skb, link_conf->vif, sta); + mt7925_mcu_bss_ifs_tlv(skb, link_conf->vif); - if (vif->bss_conf.he_support) { - mt7925_mcu_bss_he_tlv(skb, vif, phy); - mt7925_mcu_bss_color_tlv(skb, vif, enable); + if (link_conf->he_support) { + mt7925_mcu_bss_he_tlv(skb, link_conf->vif, phy); + mt7925_mcu_bss_color_tlv(skb, link_conf->vif, enable); } err = mt76_mcu_skb_send_msg(&dev->mt76, skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h index b499b1d0531a..c692996e057c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -578,7 +578,7 @@ int mt7925_mcu_sched_scan_enable(struct mt76_phy *phy, bool enable); int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, struct ieee80211_chanctx_conf *ctx, - struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, struct ieee80211_sta *sta, int enable); int mt7925_mcu_set_timing(struct mt792x_phy *phy, diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index 9630514ae25f..718c6b185d99 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -246,6 +246,16 @@ mt792x_link_conf_to_mconf(struct ieee80211_bss_conf *link_conf) return mt792x_vif_to_link(mvif, link_conf->link_id); } +static inline struct ieee80211_bss_conf * +mt792x_vif_to_bss_conf(struct ieee80211_vif *vif, unsigned int link_id) +{ + if (!ieee80211_vif_is_mld(vif) || + link_id >= IEEE80211_LINK_UNSPECIFIED) + return &vif->bss_conf; + + return link_conf_dereference_protected(vif, link_id); +} + static inline struct mt792x_dev * mt792x_hw_dev(struct ieee80211_hw *hw) { From b8b04b6616bacca2ddd3eeefeb54b1bcdb2d7f4b Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:02 -0700 Subject: [PATCH 125/204] wifi: mt76: mt7925: extend mt7925_mcu_set_timing for per-link BSS Extend mt7925_mcu_set_timing with per-link BSS configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-9-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt7925/mcu.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 7b9deb586b34..6a1afff92399 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -1400,7 +1400,7 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw, if (slottime != phy->slottime) { phy->slottime = slottime; - mt7925_mcu_set_timing(phy, vif); + mt7925_mcu_set_timing(phy, info); } } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index fb261ee525be..b82cc1bd09b6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2296,9 +2296,9 @@ mt7925_mcu_bss_ifs_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) } int mt7925_mcu_set_timing(struct mt792x_phy *phy, - struct ieee80211_vif *vif) + struct ieee80211_bss_conf *link_conf) { - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv; struct mt792x_dev *dev = phy->dev; struct sk_buff *skb; @@ -2307,7 +2307,7 @@ int mt7925_mcu_set_timing(struct mt792x_phy *phy, if (IS_ERR(skb)) return PTR_ERR(skb); - mt7925_mcu_bss_ifs_tlv(skb, vif); + mt7925_mcu_bss_ifs_tlv(skb, link_conf->vif); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_UNI_CMD(BSS_INFO_UPDATE), true); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h index c692996e057c..d3584743c266 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -582,7 +582,7 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, struct ieee80211_sta *sta, int enable); int mt7925_mcu_set_timing(struct mt792x_phy *phy, - struct ieee80211_vif *vif); + struct ieee80211_bss_conf *link_conf); int mt7925_mcu_set_deep_sleep(struct mt792x_dev *dev, bool enable); int mt7925_mcu_set_channel_domain(struct mt76_phy *phy); int mt7925_mcu_set_radio_en(struct mt792x_phy *phy, bool enable); From d62f77e3477819ddda50e62974ee160eb4c7734f Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:03 -0700 Subject: [PATCH 126/204] wifi: mt76: mt7925: extend mt7925_mcu_bss_ifs_tlv for per-link BSS Extend mt7925_mcu_bss_ifs_tlv with per-link BSS configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-10-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index b82cc1bd09b6..7cde18e273d8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2282,9 +2282,10 @@ mt7925_mcu_bss_color_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, } static void -mt7925_mcu_bss_ifs_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) +mt7925_mcu_bss_ifs_tlv(struct sk_buff *skb, + struct ieee80211_bss_conf *link_conf) { - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv; struct mt792x_phy *phy = mvif->phy; struct bss_ifs_time_tlv *ifs_time; struct tlv *tlv; @@ -2307,7 +2308,7 @@ int mt7925_mcu_set_timing(struct mt792x_phy *phy, if (IS_ERR(skb)) return PTR_ERR(skb); - mt7925_mcu_bss_ifs_tlv(skb, link_conf->vif); + mt7925_mcu_bss_ifs_tlv(skb, link_conf); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_UNI_CMD(BSS_INFO_UPDATE), true); @@ -2337,7 +2338,7 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, link_conf->vif, sta); mt7925_mcu_bss_qos_tlv(skb, link_conf->vif); mt7925_mcu_bss_mld_tlv(skb, link_conf->vif, sta); - mt7925_mcu_bss_ifs_tlv(skb, link_conf->vif); + mt7925_mcu_bss_ifs_tlv(skb, link_conf); if (link_conf->he_support) { mt7925_mcu_bss_he_tlv(skb, link_conf->vif, phy); From b698264e1ec20b22dad6f58323f3d53d7680cc2d Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:04 -0700 Subject: [PATCH 127/204] wifi: mt76: mt7925: extend mt7925_mcu_bss_color_tlv for per-link BSS Extend mt7925_mcu_bss_color_tlv with per-link BSS configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-11-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 7cde18e273d8..10e38637eb83 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2266,7 +2266,7 @@ mt7925_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, } static void -mt7925_mcu_bss_color_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, +mt7925_mcu_bss_color_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf, bool enable) { struct bss_info_uni_bss_color *color; @@ -2276,9 +2276,9 @@ mt7925_mcu_bss_color_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, color = (struct bss_info_uni_bss_color *)tlv; color->enable = enable ? - vif->bss_conf.he_bss_color.enabled : 0; + link_conf->he_bss_color.enabled : 0; color->bss_color = enable ? - vif->bss_conf.he_bss_color.color : 0; + link_conf->he_bss_color.color : 0; } static void @@ -2342,7 +2342,7 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, if (link_conf->he_support) { mt7925_mcu_bss_he_tlv(skb, link_conf->vif, phy); - mt7925_mcu_bss_color_tlv(skb, link_conf->vif, enable); + mt7925_mcu_bss_color_tlv(skb, link_conf, enable); } err = mt76_mcu_skb_send_msg(&dev->mt76, skb, From a5c372f77aa7969db9cde1b71c3193bdb126259b Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:05 -0700 Subject: [PATCH 128/204] wifi: mt76: mt7925: extend mt7925_mcu_bss_he_tlv for per-link BSS Extend mt7925_mcu_bss_he_tlv with per-link BSS configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-12-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 10e38637eb83..533214403008 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2238,7 +2238,7 @@ mt7925_mcu_bss_qos_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) } static void -mt7925_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, +mt7925_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf, struct mt792x_phy *phy) { #define DEFAULT_HE_PE_DURATION 4 @@ -2247,16 +2247,16 @@ mt7925_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct bss_info_uni_he *he; struct tlv *tlv; - cap = mt76_connac_get_he_phy_cap(phy->mt76, vif); + cap = mt76_connac_get_he_phy_cap(phy->mt76, link_conf->vif); tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_HE_BASIC, sizeof(*he)); he = (struct bss_info_uni_he *)tlv; - he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext; + he->he_pe_duration = link_conf->htc_trig_based_pkt_ext; if (!he->he_pe_duration) he->he_pe_duration = DEFAULT_HE_PE_DURATION; - he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th); + he->he_rts_thres = cpu_to_le16(link_conf->frame_time_rts_th); if (!he->he_rts_thres) he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES); @@ -2341,7 +2341,7 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, mt7925_mcu_bss_ifs_tlv(skb, link_conf); if (link_conf->he_support) { - mt7925_mcu_bss_he_tlv(skb, link_conf->vif, phy); + mt7925_mcu_bss_he_tlv(skb, link_conf, phy); mt7925_mcu_bss_color_tlv(skb, link_conf, enable); } From eff53d6ee11bb45d7dbcd348fbf4a1734f97d753 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:06 -0700 Subject: [PATCH 129/204] wifi: mt76: mt7925: extend mt7925_mcu_bss_qos_tlv for per-link BSS Extend mt7925_mcu_bss_qos_tlv with per-link BSS configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-13-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 533214403008..d6a590061e36 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2227,14 +2227,14 @@ mt7925_mcu_bss_mld_tlv(struct sk_buff *skb, } static void -mt7925_mcu_bss_qos_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) +mt7925_mcu_bss_qos_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf) { struct mt76_connac_bss_qos_tlv *qos; struct tlv *tlv; tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_QBSS, sizeof(*qos)); qos = (struct mt76_connac_bss_qos_tlv *)tlv; - qos->qos = vif->bss_conf.qos; + qos->qos = link_conf->qos; } static void @@ -2336,7 +2336,7 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, mt7925_mcu_bss_sec_tlv(skb, link_conf->vif); mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, link_conf->vif, sta); - mt7925_mcu_bss_qos_tlv(skb, link_conf->vif); + mt7925_mcu_bss_qos_tlv(skb, link_conf); mt7925_mcu_bss_mld_tlv(skb, link_conf->vif, sta); mt7925_mcu_bss_ifs_tlv(skb, link_conf); From 220865160cf624c8630de76b5a6013562399eb2e Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:07 -0700 Subject: [PATCH 130/204] wifi: mt76: mt7925: extend mt7925_mcu_bss_mld_tlv for per-link BSS Extend mt7925_mcu_bss_mld_tlv with per-link BSS configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-14-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index d6a590061e36..93ce018a0801 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2206,20 +2206,20 @@ mt7925_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt792x_phy *phy, static void mt7925_mcu_bss_mld_tlv(struct sk_buff *skb, - struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, struct ieee80211_sta *sta) { - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - bool is_mld = ieee80211_vif_is_mld(vif); + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); + bool is_mld = ieee80211_vif_is_mld(link_conf->vif); struct bss_mld_tlv *mld; struct tlv *tlv; tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_MLD, sizeof(*mld)); mld = (struct bss_mld_tlv *)tlv; - mld->link_id = sta ? (is_mld ? vif->bss_conf.link_id : 0) : 0xff; - mld->group_mld_id = is_mld ? mvif->bss_conf.mt76.idx : 0xff; - mld->own_mld_id = mvif->bss_conf.mt76.idx + 32; + mld->link_id = sta ? (is_mld ? link_conf->link_id : 0) : 0xff; + mld->group_mld_id = is_mld ? mconf->mt76.idx : 0xff; + mld->own_mld_id = mconf->mt76.idx + 32; mld->remap_idx = 0xff; if (sta) @@ -2337,7 +2337,7 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, link_conf->vif, sta); mt7925_mcu_bss_qos_tlv(skb, link_conf); - mt7925_mcu_bss_mld_tlv(skb, link_conf->vif, sta); + mt7925_mcu_bss_mld_tlv(skb, link_conf, sta); mt7925_mcu_bss_ifs_tlv(skb, link_conf); if (link_conf->he_support) { From 1d1f12689919588050afe89d5577a009774f4439 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:08 -0700 Subject: [PATCH 131/204] wifi: mt76: mt7925: extend mt7925_mcu_bss_bmc_tlv for per-link BSS Extend mt7925_mcu_bss_bmc_tlv with per-link BSS configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-15-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 93ce018a0801..48b157f42db9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2179,12 +2179,13 @@ mt7925_mcu_bss_sec_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) static void mt7925_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt792x_phy *phy, struct ieee80211_chanctx_conf *ctx, - struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, struct ieee80211_sta *sta) { struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &phy->mt76->chandef; - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); enum nl80211_band band = chandef->chan->band; + struct mt76_vif *mvif = &mconf->mt76; struct bss_rate_tlv *bmc; struct tlv *tlv; u8 idx = mvif->mcast_rates_idx ? @@ -2335,7 +2336,7 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, mvif->sta.deflink.wcid.idx, enable); mt7925_mcu_bss_sec_tlv(skb, link_conf->vif); - mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, link_conf->vif, sta); + mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, link_conf, sta); mt7925_mcu_bss_qos_tlv(skb, link_conf); mt7925_mcu_bss_mld_tlv(skb, link_conf, sta); mt7925_mcu_bss_ifs_tlv(skb, link_conf); From 0637256a79ecf22d483876263881329b35ad788c Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:09 -0700 Subject: [PATCH 132/204] wifi: mt76: mt7925: remove unused parameters in mt7925_mcu_bss_bmc_tlv remove unused parameters in mt7925_mcu_bss_bmc_tlv Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-16-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 48b157f42db9..797d4c936fec 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2179,8 +2179,7 @@ mt7925_mcu_bss_sec_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) static void mt7925_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt792x_phy *phy, struct ieee80211_chanctx_conf *ctx, - struct ieee80211_bss_conf *link_conf, - struct ieee80211_sta *sta) + struct ieee80211_bss_conf *link_conf) { struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &phy->mt76->chandef; struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); @@ -2336,7 +2335,7 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, mvif->sta.deflink.wcid.idx, enable); mt7925_mcu_bss_sec_tlv(skb, link_conf->vif); - mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, link_conf, sta); + mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, link_conf); mt7925_mcu_bss_qos_tlv(skb, link_conf); mt7925_mcu_bss_mld_tlv(skb, link_conf, sta); mt7925_mcu_bss_ifs_tlv(skb, link_conf); From ff5efcd4f8cb264ba86236785f5d32ba604625ef Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:10 -0700 Subject: [PATCH 133/204] wifi: mt76: mt7925: extend mt7925_mcu_bss_sec_tlv for per-link BSS Extend mt7925_mcu_bss_sec_tlv with per-link BSS configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-17-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 797d4c936fec..028c94d8c21f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2132,9 +2132,11 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, } static void -mt7925_mcu_bss_sec_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) +mt7925_mcu_bss_sec_tlv(struct sk_buff *skb, + struct ieee80211_bss_conf *link_conf) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); + struct mt76_vif *mvif = &mconf->mt76; struct bss_sec_tlv { __le16 tag; __le16 len; @@ -2333,7 +2335,7 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, /* bss_basic must be first */ mt7925_mcu_bss_basic_tlv(skb, link_conf->vif, sta, ctx, phy->mt76, mvif->sta.deflink.wcid.idx, enable); - mt7925_mcu_bss_sec_tlv(skb, link_conf->vif); + mt7925_mcu_bss_sec_tlv(skb, link_conf); mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, link_conf); mt7925_mcu_bss_qos_tlv(skb, link_conf); From 21760dcd2ab61333533e9d72c1e585f6bf25bb7b Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:11 -0700 Subject: [PATCH 134/204] wifi: mt76: mt7925: extend mt7925_mcu_bss_basic_tlv for per-link BSS Extend mt7925_mcu_bss_basic_tlv with per-link BSS configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-18-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/main.c | 1 + .../net/wireless/mediatek/mt76/mt7925/mcu.c | 25 ++++++++++--------- drivers/net/wireless/mediatek/mt76/mt792x.h | 1 + 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 6a1afff92399..457e1fa2fde1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -338,6 +338,7 @@ mt7925_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) mvif->phy = phy; mvif->bss_conf.mt76.band_idx = 0; mvif->bss_conf.mt76.wmm_idx = mvif->bss_conf.mt76.idx % MT76_CONNAC_MAX_WMM_SETS; + mvif->bss_conf.vif = mvif; if (phy->mt76->chandef.chan->band != NL80211_BAND_2GHZ) mvif->bss_conf.mt76.basic_rates_idx = MT792x_BASIC_RATES_TBL + 4; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 028c94d8c21f..18e19ffdbb7e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2062,15 +2062,16 @@ mt7925_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif, static void mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, - struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, struct ieee80211_sta *sta, struct ieee80211_chanctx_conf *ctx, struct mt76_phy *phy, u16 wlan_idx, bool enable) { - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct ieee80211_vif *vif = link_conf->vif; + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); struct mt792x_sta *msta = sta ? (struct mt792x_sta *)sta->drv_priv : - &mvif->sta; + &mconf->vif->sta; struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &phy->chandef; enum nl80211_band band = chandef->chan->band; struct mt76_connac_bss_basic_tlv *basic_req; @@ -2081,8 +2082,8 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_BASIC, sizeof(*basic_req)); basic_req = (struct mt76_connac_bss_basic_tlv *)tlv; - idx = mvif->bss_conf.mt76.omac_idx > EXT_BSSID_START ? HW_BSSID_0 : - mvif->bss_conf.mt76.omac_idx; + idx = mconf->mt76.omac_idx > EXT_BSSID_START ? HW_BSSID_0 : + mconf->mt76.omac_idx; basic_req->hw_bss_idx = idx; basic_req->phymode_ext = mt7925_get_phy_mode_ext(phy, vif, band, sta); @@ -2092,15 +2093,15 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, else basic_req->nonht_basic_phy = cpu_to_le16(PHY_TYPE_OFDM_INDEX); - memcpy(basic_req->bssid, vif->bss_conf.bssid, ETH_ALEN); + memcpy(basic_req->bssid, link_conf->bssid, ETH_ALEN); basic_req->phymode = mt76_connac_get_phy_mode(phy, vif, band, sta); - basic_req->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); - basic_req->dtim_period = vif->bss_conf.dtim_period; + basic_req->bcn_interval = cpu_to_le16(link_conf->beacon_int); + basic_req->dtim_period = link_conf->dtim_period; basic_req->bmc_tx_wlan_idx = cpu_to_le16(wlan_idx); basic_req->sta_idx = cpu_to_le16(msta->deflink.wcid.idx); - basic_req->omac_idx = mvif->bss_conf.mt76.omac_idx; - basic_req->band_idx = mvif->bss_conf.mt76.band_idx; - basic_req->wmm_idx = mvif->bss_conf.mt76.wmm_idx; + basic_req->omac_idx = mconf->mt76.omac_idx; + basic_req->band_idx = mconf->mt76.band_idx; + basic_req->wmm_idx = mconf->mt76.wmm_idx; basic_req->conn_state = !enable; switch (vif->type) { @@ -2333,7 +2334,7 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, return PTR_ERR(skb); /* bss_basic must be first */ - mt7925_mcu_bss_basic_tlv(skb, link_conf->vif, sta, ctx, phy->mt76, + mt7925_mcu_bss_basic_tlv(skb, link_conf, sta, ctx, phy->mt76, mvif->sta.deflink.wcid.idx, enable); mt7925_mcu_bss_sec_tlv(skb, link_conf); diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index 718c6b185d99..f36e4aeb79b2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -108,6 +108,7 @@ struct mt792x_chanctx { struct mt792x_bss_conf { struct mt76_vif mt76; /* must be first */ + struct mt792x_vif *vif; struct ewma_rssi rssi; struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; }; From b6749ee8b466d5f0fe0a8b80991bc44866ce0be5 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:12 -0700 Subject: [PATCH 135/204] wifi: mt76: mt7925: extend mt7925_mcu_set_bss_pm for per-link BSS Extend mt7925_mcu_set_bss_pm with per-link BSS configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-19-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/main.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 15 ++++++++------- .../net/wireless/mediatek/mt76/mt7925/mt7925.h | 3 ++- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 457e1fa2fde1..aeed2c777a20 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -1263,7 +1263,7 @@ mt7925_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (err) goto out; - err = mt7925_mcu_set_bss_pm(dev, vif, true); + err = mt7925_mcu_set_bss_pm(dev, link_conf, true); if (err) goto out; @@ -1285,7 +1285,7 @@ mt7925_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt792x_mutex_acquire(dev); - err = mt7925_mcu_set_bss_pm(dev, vif, false); + err = mt7925_mcu_set_bss_pm(dev, link_conf, false); if (err) goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 18e19ffdbb7e..0350f0e34690 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1319,10 +1319,11 @@ mt7925_mcu_uni_bss_bcnft(struct mt792x_dev *dev, struct ieee80211_vif *vif, } int -mt7925_mcu_set_bss_pm(struct mt792x_dev *dev, struct ieee80211_vif *vif, +mt7925_mcu_set_bss_pm(struct mt792x_dev *dev, + struct ieee80211_bss_conf *link_conf, bool enable) { - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); struct { struct { u8 bss_idx; @@ -1339,13 +1340,13 @@ mt7925_mcu_set_bss_pm(struct mt792x_dev *dev, struct ieee80211_vif *vif, } __packed enable; } req = { .hdr = { - .bss_idx = mvif->bss_conf.mt76.idx, + .bss_idx = mconf->mt76.idx, }, .enable = { .tag = cpu_to_le16(UNI_BSS_INFO_BCNFT), .len = cpu_to_le16(sizeof(struct bcnft_tlv)), - .dtim_period = vif->bss_conf.dtim_period, - .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), + .dtim_period = link_conf->dtim_period, + .bcn_interval = cpu_to_le16(link_conf->beacon_int), }, }; struct { @@ -1359,7 +1360,7 @@ mt7925_mcu_set_bss_pm(struct mt792x_dev *dev, struct ieee80211_vif *vif, } __packed disable; } req1 = { .hdr = { - .bss_idx = mvif->bss_conf.mt76.idx, + .bss_idx = mconf->mt76.idx, }, .disable = { .tag = cpu_to_le16(UNI_BSS_INFO_PM_DISABLE), @@ -1693,7 +1694,7 @@ int mt7925_mcu_set_beacon_filter(struct mt792x_dev *dev, MT_WF_RFCR_DROP_OTHER_BEACON); } - err = mt7925_mcu_set_bss_pm(dev, vif, false); + err = mt7925_mcu_set_bss_pm(dev, &vif->bss_conf, false); if (err) return err; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h index f689f7a359ea..07ea03195e4e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h @@ -192,7 +192,8 @@ int __mt7925_start(struct mt792x_phy *phy); int mt7925_register_device(struct mt792x_dev *dev); void mt7925_unregister_device(struct mt792x_dev *dev); int mt7925_run_firmware(struct mt792x_dev *dev); -int mt7925_mcu_set_bss_pm(struct mt792x_dev *dev, struct ieee80211_vif *vif, +int mt7925_mcu_set_bss_pm(struct mt792x_dev *dev, + struct ieee80211_bss_conf *link_conf, bool enable); int mt7925_mcu_sta_update(struct mt792x_dev *dev, struct ieee80211_sta *sta, struct ieee80211_vif *vif, bool enable, From 0aa5e96c6df77aa8c0e5b3f77afa0a4fc84ffe4c Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:13 -0700 Subject: [PATCH 136/204] wifi: mt76: mt7925: extend mt7925_mcu_[abort, set]_roc for per-link BSS The channel context has to be bound with the per-link BSS, thus, we extend mt7925_mcu_[abort, set]_roc to work with the per-link BSS configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-20-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/main.c | 23 +++++++++++-------- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 8 +++---- .../wireless/mediatek/mt76/mt7925/mt7925.h | 4 ++-- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index aeed2c777a20..bba17e51a023 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -387,7 +387,7 @@ static void mt7925_roc_iter(void *priv, u8 *mac, struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_phy *phy = priv; - mt7925_mcu_abort_roc(phy, mvif, phy->roc_token_id); + mt7925_mcu_abort_roc(phy, &mvif->bss_conf, phy->roc_token_id); } void mt7925_roc_work(struct work_struct *work) @@ -408,7 +408,8 @@ void mt7925_roc_work(struct work_struct *work) ieee80211_remain_on_channel_expired(phy->mt76->hw); } -static int mt7925_abort_roc(struct mt792x_phy *phy, struct mt792x_vif *vif) +static int mt7925_abort_roc(struct mt792x_phy *phy, + struct mt792x_bss_conf *mconf) { int err = 0; @@ -417,14 +418,14 @@ static int mt7925_abort_roc(struct mt792x_phy *phy, struct mt792x_vif *vif) mt792x_mutex_acquire(phy->dev); if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) - err = mt7925_mcu_abort_roc(phy, vif, phy->roc_token_id); + err = mt7925_mcu_abort_roc(phy, mconf, phy->roc_token_id); mt792x_mutex_release(phy->dev); return err; } static int mt7925_set_roc(struct mt792x_phy *phy, - struct mt792x_vif *vif, + struct mt792x_bss_conf *mconf, struct ieee80211_channel *chan, int duration, enum mt7925_roc_req type) @@ -436,7 +437,7 @@ static int mt7925_set_roc(struct mt792x_phy *phy, phy->roc_grant = false; - err = mt7925_mcu_set_roc(phy, vif, chan, duration, type, + err = mt7925_mcu_set_roc(phy, mconf, chan, duration, type, ++phy->roc_token_id); if (err < 0) { clear_bit(MT76_STATE_ROC, &phy->mt76->state); @@ -444,7 +445,7 @@ static int mt7925_set_roc(struct mt792x_phy *phy, } if (!wait_event_timeout(phy->roc_wait, phy->roc_grant, 4 * HZ)) { - mt7925_mcu_abort_roc(phy, vif, phy->roc_token_id); + mt7925_mcu_abort_roc(phy, mconf, phy->roc_token_id); clear_bit(MT76_STATE_ROC, &phy->mt76->state); err = -ETIMEDOUT; } @@ -464,7 +465,8 @@ static int mt7925_remain_on_channel(struct ieee80211_hw *hw, int err; mt792x_mutex_acquire(phy->dev); - err = mt7925_set_roc(phy, mvif, chan, duration, MT7925_ROC_REQ_ROC); + err = mt7925_set_roc(phy, &mvif->bss_conf, + chan, duration, MT7925_ROC_REQ_ROC); mt792x_mutex_release(phy->dev); return err; @@ -476,7 +478,7 @@ static int mt7925_cancel_remain_on_channel(struct ieee80211_hw *hw, struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_phy *phy = mt792x_hw_phy(hw); - return mt7925_abort_roc(phy, mvif); + return mt7925_abort_roc(phy, &mvif->bss_conf); } static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, @@ -1345,7 +1347,8 @@ static void mt7925_mgd_prepare_tx(struct ieee80211_hw *hw, jiffies_to_msecs(HZ); mt792x_mutex_acquire(dev); - mt7925_set_roc(mvif->phy, mvif, mvif->bss_conf.mt76.ctx->def.chan, duration, + mt7925_set_roc(mvif->phy, &mvif->bss_conf, + mvif->bss_conf.mt76.ctx->def.chan, duration, MT7925_ROC_REQ_JOIN); mt792x_mutex_release(dev); } @@ -1356,7 +1359,7 @@ static void mt7925_mgd_complete_tx(struct ieee80211_hw *hw, { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - mt7925_abort_roc(mvif->phy, mvif); + mt7925_abort_roc(mvif->phy, &mvif->bss_conf); } static void mt7925_vif_cfg_changed(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 0350f0e34690..a40ad1578212 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1050,7 +1050,7 @@ int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true); } -int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_vif *vif, +int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, struct ieee80211_channel *chan, int duration, enum mt7925_roc_req type, u8 token_id) { @@ -1086,7 +1086,7 @@ int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_vif *vif, .tokenid = token_id, .reqtype = type, .maxinterval = cpu_to_le32(duration), - .bss_idx = vif->bss_conf.mt76.idx, + .bss_idx = mconf->mt76.idx, .control_channel = chan->hw_value, .bw = CMD_CBW_20MHZ, .bw_from_ap = CMD_CBW_20MHZ, @@ -1117,7 +1117,7 @@ int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_vif *vif, &req, sizeof(req), false); } -int mt7925_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_vif *vif, +int mt7925_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, u8 token_id) { struct mt792x_dev *dev = phy->dev; @@ -1138,7 +1138,7 @@ int mt7925_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_vif *vif, .tag = cpu_to_le16(UNI_ROC_ABORT), .len = cpu_to_le16(sizeof(struct roc_abort_tlv)), .tokenid = token_id, - .bss_idx = vif->bss_conf.mt76.idx, + .bss_idx = mconf->mt76.idx, .dbdcband = 0xff, /* auto*/ }, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h index 07ea03195e4e..8ab2bb01ba73 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h @@ -292,10 +292,10 @@ int mt7925_set_tx_sar_pwr(struct ieee80211_hw *hw, int mt7925_mcu_regval(struct mt792x_dev *dev, u32 regidx, u32 *val, bool set); int mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, enum environment_cap env_cap); -int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_vif *vif, +int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, struct ieee80211_channel *chan, int duration, enum mt7925_roc_req type, u8 token_id); -int mt7925_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_vif *vif, +int mt7925_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, u8 token_id); int mt7925_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, int cmd, int *wait_seq); From d1c5f3719faa782efe7b0dd26b8f263345e1d314 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:14 -0700 Subject: [PATCH 137/204] wifi: mt76: mt7925: extend mt7925_mcu_uni_bss_bcnft for per-link BSS Extend mt7925_mcu_uni_bss_bcnft with per-link BSS configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-21-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index a40ad1578212..8950df09a025 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1281,10 +1281,10 @@ int mt7925_mcu_uni_bss_ps(struct mt792x_dev *dev, struct ieee80211_vif *vif) } static int -mt7925_mcu_uni_bss_bcnft(struct mt792x_dev *dev, struct ieee80211_vif *vif, - bool enable) +mt7925_mcu_uni_bss_bcnft(struct mt792x_dev *dev, + struct ieee80211_bss_conf *link_conf, bool enable) { - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); struct { struct { u8 bss_idx; @@ -1301,17 +1301,17 @@ mt7925_mcu_uni_bss_bcnft(struct mt792x_dev *dev, struct ieee80211_vif *vif, } __packed bcnft; } __packed bcnft_req = { .hdr = { - .bss_idx = mvif->bss_conf.mt76.idx, + .bss_idx = mconf->mt76.idx, }, .bcnft = { .tag = cpu_to_le16(UNI_BSS_INFO_BCNFT), .len = cpu_to_le16(sizeof(struct bcnft_tlv)), - .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), - .dtim_period = vif->bss_conf.dtim_period, + .bcn_interval = cpu_to_le16(link_conf->beacon_int), + .dtim_period = link_conf->dtim_period, }, }; - if (vif->type != NL80211_IFTYPE_STATION) + if (link_conf->vif->type != NL80211_IFTYPE_STATION) return 0; return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE), @@ -1685,7 +1685,7 @@ int mt7925_mcu_set_beacon_filter(struct mt792x_dev *dev, int err = 0; if (enable) { - err = mt7925_mcu_uni_bss_bcnft(dev, vif, true); + err = mt7925_mcu_uni_bss_bcnft(dev, &vif->bss_conf, true); if (err) return err; From 3a0c8d2908297b63f0e5a3364721ffd32e5a0c0c Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:15 -0700 Subject: [PATCH 138/204] wifi: mt76: mt7925: extend mt7925_mcu_uni_bss_ps for per-link BSS Extend mt7925_mcu_uni_bss_ps with per-link BSS configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-22-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 11 ++++++----- drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h | 3 ++- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index bba17e51a023..cd20b85109b9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -1383,7 +1383,7 @@ static void mt7925_vif_cfg_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_PS) - mt7925_mcu_uni_bss_ps(dev, vif); + mt7925_mcu_uni_bss_ps(dev, &vif->bss_conf); mt792x_mutex_release(dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 8950df09a025..7624ec23e064 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1243,9 +1243,10 @@ int mt7925_mcu_set_eeprom(struct mt792x_dev *dev) } EXPORT_SYMBOL_GPL(mt7925_mcu_set_eeprom); -int mt7925_mcu_uni_bss_ps(struct mt792x_dev *dev, struct ieee80211_vif *vif) +int mt7925_mcu_uni_bss_ps(struct mt792x_dev *dev, + struct ieee80211_bss_conf *link_conf) { - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); struct { struct { u8 bss_idx; @@ -1264,16 +1265,16 @@ int mt7925_mcu_uni_bss_ps(struct mt792x_dev *dev, struct ieee80211_vif *vif) } __packed ps; } __packed ps_req = { .hdr = { - .bss_idx = mvif->bss_conf.mt76.idx, + .bss_idx = mconf->mt76.idx, }, .ps = { .tag = cpu_to_le16(UNI_BSS_INFO_PS), .len = cpu_to_le16(sizeof(struct ps_tlv)), - .ps_state = vif->cfg.ps ? 2 : 0, + .ps_state = link_conf->vif->cfg.ps ? 2 : 0, }, }; - if (vif->type != NL80211_IFTYPE_STATION) + if (link_conf->vif->type != NL80211_IFTYPE_STATION) return -EOPNOTSUPP; return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE), diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h index 8ab2bb01ba73..ef37951f69d5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h @@ -242,7 +242,8 @@ int mt7925_mcu_uni_rx_ba(struct mt792x_dev *dev, bool enable); void mt7925_scan_work(struct work_struct *work); void mt7925_roc_work(struct work_struct *work); -int mt7925_mcu_uni_bss_ps(struct mt792x_dev *dev, struct ieee80211_vif *vif); +int mt7925_mcu_uni_bss_ps(struct mt792x_dev *dev, + struct ieee80211_bss_conf *link_conf); void mt7925_coredump_work(struct work_struct *work); int mt7925_get_txpwr_info(struct mt792x_dev *dev, u8 band_idx, struct mt7925_txpwr *txpwr); From ca64503a8f06ec712c372a7436ffb2b371e4d93c Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:16 -0700 Subject: [PATCH 139/204] wifi: mt76: mt7925: add mt7925_mcu_bss_rlm_tlv to constitue the RLM TLV add mt7925_mcu_bss_rlm_tlv to maintain consistency with the other TLVs that constitute the command for creating the per-link BSS. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-23-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 64 +++++++++++++++++-- .../net/wireless/mediatek/mt76/mt7925/mcu.h | 16 +++++ 2 files changed, 74 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 7624ec23e064..96b7a9df17d8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1921,6 +1921,59 @@ mt7925_mcu_uni_add_beacon_offload(struct mt792x_dev *dev, &req, sizeof(req), true); } +static +void mt7925_mcu_bss_rlm_tlv(struct sk_buff *skb, struct mt76_phy *phy, + struct ieee80211_chanctx_conf *ctx) +{ + struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &phy->chandef; + int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2; + enum nl80211_band band = chandef->chan->band; + struct bss_rlm_tlv *req; + struct tlv *tlv; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_RLM, sizeof(*req)); + req = (struct bss_rlm_tlv *)tlv; + req->control_channel = chandef->chan->hw_value, + req->center_chan = ieee80211_frequency_to_channel(freq1), + req->center_chan2 = ieee80211_frequency_to_channel(freq2), + req->tx_streams = hweight8(phy->antenna_mask), + req->ht_op_info = 4, /* set HT 40M allowed */ + req->rx_streams = hweight8(phy->antenna_mask), + req->band = band; + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_40: + req->bw = CMD_CBW_40MHZ; + break; + case NL80211_CHAN_WIDTH_80: + req->bw = CMD_CBW_80MHZ; + break; + case NL80211_CHAN_WIDTH_80P80: + req->bw = CMD_CBW_8080MHZ; + break; + case NL80211_CHAN_WIDTH_160: + req->bw = CMD_CBW_160MHZ; + break; + case NL80211_CHAN_WIDTH_5: + req->bw = CMD_CBW_5MHZ; + break; + case NL80211_CHAN_WIDTH_10: + req->bw = CMD_CBW_10MHZ; + break; + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + default: + req->bw = CMD_CBW_20MHZ; + req->ht_op_info = 0; + break; + } + + if (req->control_channel < req->center_chan) + req->sco = 1; /* SCA */ + else if (req->control_channel > req->center_chan) + req->sco = 3; /* SCB */ +} + int mt7925_mcu_set_chctx(struct mt76_phy *phy, struct mt76_vif *mvif, struct ieee80211_chanctx_conf *ctx) { @@ -2326,9 +2379,10 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, int enable) { struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv; + struct mt792x_bss_conf *mconf = mt792x_vif_to_link(mvif, + link_conf->link_id); struct mt792x_dev *dev = phy->dev; struct sk_buff *skb; - int err; skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mvif->bss_conf.mt76, MT7925_BSS_UPDATE_MAX_SIZE); @@ -2350,12 +2404,10 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, mt7925_mcu_bss_color_tlv(skb, link_conf, enable); } - err = mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_UNI_CMD(BSS_INFO_UPDATE), true); - if (err < 0) - return err; + mt7925_mcu_bss_rlm_tlv(skb, phy->mt76, mconf->mt76.ctx); - return mt7925_mcu_set_chctx(phy->mt76, &mvif->bss_conf.mt76, ctx); + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_UNI_CMD(BSS_INFO_UPDATE), true); } int mt7925_mcu_set_dbdc(struct mt76_phy *phy) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h index d3584743c266..c5197577cdc8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -456,6 +456,21 @@ struct bss_ifs_time_tlv { __le16 eifs_cck_time; } __packed; +struct bss_rlm_tlv { + __le16 tag; + __le16 len; + u8 control_channel; + u8 center_chan; + u8 center_chan2; + u8 bw; + u8 tx_streams; + u8 rx_streams; + u8 ht_op_info; + u8 sco; + u8 band; + u8 pad[3]; +} __packed; + #define MT7925_STA_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \ sizeof(struct sta_rec_basic) + \ sizeof(struct sta_rec_bf) + \ @@ -484,6 +499,7 @@ struct bss_ifs_time_tlv { sizeof(struct bss_info_uni_he) + \ sizeof(struct bss_info_uni_bss_color) + \ sizeof(struct bss_ifs_time_tlv) + \ + sizeof(struct bss_rlm_tlv) + \ sizeof(struct tlv)) #define MT_CONNAC3_SKU_POWER_LIMIT 449 From 22d66ef6653bb62c7b3eb6974b86435ff55af3a7 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:17 -0700 Subject: [PATCH 140/204] wifi: mt76: mt7925: mt7925_mcu_set_chctx rely on mt7925_mcu_bss_rlm_tlv make mt7925_mcu_set_chctx rely on mt7925_mcu_bss_rlm_tlv to get rid of the redundant code. Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-24-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 95 ++++--------------- 1 file changed, 16 insertions(+), 79 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 96b7a9df17d8..9d56013b2f55 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1974,85 +1974,6 @@ void mt7925_mcu_bss_rlm_tlv(struct sk_buff *skb, struct mt76_phy *phy, req->sco = 3; /* SCB */ } -int mt7925_mcu_set_chctx(struct mt76_phy *phy, struct mt76_vif *mvif, - struct ieee80211_chanctx_conf *ctx) -{ - struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &phy->chandef; - int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2; - enum nl80211_band band = chandef->chan->band; - struct mt76_dev *mdev = phy->dev; - struct { - struct { - u8 bss_idx; - u8 pad[3]; - } __packed hdr; - struct rlm_tlv { - __le16 tag; - __le16 len; - u8 control_channel; - u8 center_chan; - u8 center_chan2; - u8 bw; - u8 tx_streams; - u8 rx_streams; - u8 ht_op_info; - u8 sco; - u8 band; - u8 pad[3]; - } __packed rlm; - } __packed rlm_req = { - .hdr = { - .bss_idx = mvif->idx, - }, - .rlm = { - .tag = cpu_to_le16(UNI_BSS_INFO_RLM), - .len = cpu_to_le16(sizeof(struct rlm_tlv)), - .control_channel = chandef->chan->hw_value, - .center_chan = ieee80211_frequency_to_channel(freq1), - .center_chan2 = ieee80211_frequency_to_channel(freq2), - .tx_streams = hweight8(phy->antenna_mask), - .ht_op_info = 4, /* set HT 40M allowed */ - .rx_streams = hweight8(phy->antenna_mask), - .band = band, - }, - }; - - switch (chandef->width) { - case NL80211_CHAN_WIDTH_40: - rlm_req.rlm.bw = CMD_CBW_40MHZ; - break; - case NL80211_CHAN_WIDTH_80: - rlm_req.rlm.bw = CMD_CBW_80MHZ; - break; - case NL80211_CHAN_WIDTH_80P80: - rlm_req.rlm.bw = CMD_CBW_8080MHZ; - break; - case NL80211_CHAN_WIDTH_160: - rlm_req.rlm.bw = CMD_CBW_160MHZ; - break; - case NL80211_CHAN_WIDTH_5: - rlm_req.rlm.bw = CMD_CBW_5MHZ; - break; - case NL80211_CHAN_WIDTH_10: - rlm_req.rlm.bw = CMD_CBW_10MHZ; - break; - case NL80211_CHAN_WIDTH_20_NOHT: - case NL80211_CHAN_WIDTH_20: - default: - rlm_req.rlm.bw = CMD_CBW_20MHZ; - rlm_req.rlm.ht_op_info = 0; - break; - } - - if (rlm_req.rlm.control_channel < rlm_req.rlm.center_chan) - rlm_req.rlm.sco = 1; /* SCA */ - else if (rlm_req.rlm.control_channel > rlm_req.rlm.center_chan) - rlm_req.rlm.sco = 3; /* SCB */ - - return mt76_mcu_send_msg(mdev, MCU_UNI_CMD(BSS_INFO_UPDATE), &rlm_req, - sizeof(rlm_req), true); -} - static struct sk_buff * __mt7925_mcu_alloc_bss_req(struct mt76_dev *dev, struct mt76_vif *mvif, int len) { @@ -2070,6 +1991,22 @@ __mt7925_mcu_alloc_bss_req(struct mt76_dev *dev, struct mt76_vif *mvif, int len) return skb; } +int mt7925_mcu_set_chctx(struct mt76_phy *phy, struct mt76_vif *mvif, + struct ieee80211_chanctx_conf *ctx) +{ + struct sk_buff *skb; + + skb = __mt7925_mcu_alloc_bss_req(phy->dev, mvif, + MT7925_BSS_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mt7925_mcu_bss_rlm_tlv(skb, phy, ctx); + + return mt76_mcu_skb_send_msg(phy->dev, skb, + MCU_UNI_CMD(BSS_INFO_UPDATE), true); +} + static u8 mt7925_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif, enum nl80211_band band, struct ieee80211_sta *sta) From f7cc8944039c0066f1e7b78a7f8c02bf558d098f Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:18 -0700 Subject: [PATCH 141/204] wifi: mt76: mt7925: extend mt7925_mcu_sta_update for per-link STA Extend mt7925_mcu_sta_update with the per-link STA configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-25-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 5 +- .../net/wireless/mediatek/mt76/mt7925/main.c | 6 +-- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 53 +++++++++++-------- .../wireless/mediatek/mt76/mt7925/mt7925.h | 3 +- drivers/net/wireless/mediatek/mt76/mt792x.h | 16 ++++++ 5 files changed, 57 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 5c7c42c95de1..994136285815 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1733,7 +1733,10 @@ enum mt76_sta_info_state { }; struct mt76_sta_cmd_info { - struct ieee80211_sta *sta; + union { + struct ieee80211_sta *sta; + struct ieee80211_link_sta *link_sta; + }; struct mt76_wcid *wcid; struct ieee80211_vif *vif; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index cd20b85109b9..f3a32fe9a754 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -740,7 +740,7 @@ int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, link_conf, sta, false); - ret = mt7925_mcu_sta_update(dev, sta, vif, true, + ret = mt7925_mcu_sta_update(dev, &sta->deflink, vif, true, MT76_STA_INFO_STATE_NONE); if (ret) return ret; @@ -773,7 +773,7 @@ void mt7925_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); memset(msta->deflink.airtime_ac, 0, sizeof(msta->deflink.airtime_ac)); - mt7925_mcu_sta_update(dev, sta, vif, true, MT76_STA_INFO_STATE_ASSOC); + mt7925_mcu_sta_update(dev, &sta->deflink, vif, true, MT76_STA_INFO_STATE_ASSOC); mt792x_mutex_release(dev); } @@ -789,7 +789,7 @@ void mt7925_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->deflink.wcid); mt76_connac_pm_wake(&dev->mphy, &dev->pm); - mt7925_mcu_sta_update(dev, sta, vif, false, MT76_STA_INFO_STATE_NONE); + mt7925_mcu_sta_update(dev, &sta->deflink, vif, false, MT76_STA_INFO_STATE_NONE); mt7925_mac_wtbl_update(dev, msta->deflink.wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 9d56013b2f55..9b69b4b178de 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1628,39 +1628,46 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, if (IS_ERR(skb)) return PTR_ERR(skb); - if (info->sta || !info->offload_fw) - mt76_connac_mcu_sta_basic_tlv(dev, skb, info->vif, info->sta, + if (info->link_sta || !info->offload_fw) + mt76_connac_mcu_sta_basic_tlv(dev, skb, info->vif, + info->link_sta->sta, info->enable, info->newly); - if (info->sta && info->enable) { - mt7925_mcu_sta_phy_tlv(skb, info->vif, info->sta); - mt7925_mcu_sta_ht_tlv(skb, info->sta); - mt7925_mcu_sta_vht_tlv(skb, info->sta); - mt76_connac_mcu_sta_uapsd(skb, info->vif, info->sta); - mt7925_mcu_sta_amsdu_tlv(skb, info->vif, info->sta); - mt7925_mcu_sta_he_tlv(skb, info->sta); - mt7925_mcu_sta_he_6g_tlv(skb, info->sta); - mt7925_mcu_sta_eht_tlv(skb, info->sta); - mt7925_mcu_sta_rate_ctrl_tlv(skb, info->vif, info->sta); - mt7925_mcu_sta_state_v2_tlv(phy, skb, info->sta, + if (info->link_sta && info->enable) { + mt7925_mcu_sta_phy_tlv(skb, info->vif, info->link_sta->sta); + mt7925_mcu_sta_ht_tlv(skb, info->link_sta->sta); + mt7925_mcu_sta_vht_tlv(skb, info->link_sta->sta); + mt76_connac_mcu_sta_uapsd(skb, info->vif, info->link_sta->sta); + mt7925_mcu_sta_amsdu_tlv(skb, info->vif, info->link_sta->sta); + mt7925_mcu_sta_he_tlv(skb, info->link_sta->sta); + mt7925_mcu_sta_he_6g_tlv(skb, info->link_sta->sta); + mt7925_mcu_sta_eht_tlv(skb, info->link_sta->sta); + mt7925_mcu_sta_rate_ctrl_tlv(skb, info->vif, + info->link_sta->sta); + mt7925_mcu_sta_state_v2_tlv(phy, skb, info->link_sta->sta, info->vif, info->rcpi, info->state); - mt7925_mcu_sta_mld_tlv(skb, info->vif, info->sta); + mt7925_mcu_sta_mld_tlv(skb, info->vif, info->link_sta->sta); } - if (info->enable) - mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, info->sta); + if (info->enable) { + struct ieee80211_sta *sta = info->link_sta ? + info->link_sta->sta : NULL; + + mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, sta); + } return mt76_mcu_skb_send_msg(dev, skb, info->cmd, true); } -int mt7925_mcu_sta_update(struct mt792x_dev *dev, struct ieee80211_sta *sta, +int mt7925_mcu_sta_update(struct mt792x_dev *dev, + struct ieee80211_link_sta *link_sta, struct ieee80211_vif *vif, bool enable, enum mt76_sta_info_state state) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; int rssi = -ewma_rssi_read(&mvif->bss_conf.rssi); struct mt76_sta_cmd_info info = { - .sta = sta, + .link_sta = link_sta, .vif = vif, .enable = enable, .cmd = MCU_UNI_CMD(STA_REC_UPDATE), @@ -1669,10 +1676,14 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev, struct ieee80211_sta *sta, .rcpi = to_rcpi(rssi), }; struct mt792x_sta *msta; + struct mt792x_link_sta *mlink; - msta = sta ? (struct mt792x_sta *)sta->drv_priv : NULL; - info.wcid = msta ? &msta->deflink.wcid : &mvif->sta.deflink.wcid; - info.newly = msta ? state != MT76_STA_INFO_STATE_ASSOC : true; + if (link_sta) { + msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + mlink = mt792x_sta_to_link(msta, link_sta->link_id); + } + info.wcid = link_sta ? &mlink->wcid : &mvif->sta.deflink.wcid; + info.newly = link_sta ? state != MT76_STA_INFO_STATE_ASSOC : true; return mt7925_mcu_sta_cmd(&dev->mphy, &info); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h index ef37951f69d5..8ec5a3a20202 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h @@ -195,7 +195,8 @@ int mt7925_run_firmware(struct mt792x_dev *dev); int mt7925_mcu_set_bss_pm(struct mt792x_dev *dev, struct ieee80211_bss_conf *link_conf, bool enable); -int mt7925_mcu_sta_update(struct mt792x_dev *dev, struct ieee80211_sta *sta, +int mt7925_mcu_sta_update(struct mt792x_dev *dev, + struct ieee80211_link_sta *link_sta, struct ieee80211_vif *vif, bool enable, enum mt76_sta_info_state state); int mt7925_mcu_set_chan_info(struct mt792x_phy *phy, u16 tag); diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index f36e4aeb79b2..69eb8dac0b70 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -96,6 +96,7 @@ struct mt792x_link_sta { struct mt792x_sta { struct mt792x_link_sta deflink; /* must be first */ + struct mt792x_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; struct mt792x_vif *vif; }; @@ -238,6 +239,21 @@ mt792x_vif_to_link(struct mt792x_vif *mvif, u8 link_id) lockdep_is_held(&mvif->phy->dev->mt76.mutex)); } +static inline struct mt792x_link_sta * +mt792x_sta_to_link(struct mt792x_sta *msta, u8 link_id) +{ + struct ieee80211_vif *vif; + + vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); + + if (!ieee80211_vif_is_mld(vif) || + link_id >= IEEE80211_LINK_UNSPECIFIED) + return &msta->deflink; + + return rcu_dereference_protected(msta->link[link_id], + lockdep_is_held(&msta->vif->phy->dev->mt76.mutex)); +} + static inline struct mt792x_bss_conf * mt792x_link_conf_to_mconf(struct ieee80211_bss_conf *link_conf) { From ec8a86b2f09ca14d8492a625f637c9fbf7264f40 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:19 -0700 Subject: [PATCH 142/204] wifi: mt76: mt7925: extend mt7925_mcu_sta_state_v2_tlv for per-link STA Extend mt7925_mcu_sta_state_v2_tlv with the per-link STA configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-26-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 9b69b4b178de..45437603763e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1540,7 +1540,7 @@ mt7925_mcu_sta_phy_tlv(struct sk_buff *skb, static void mt7925_mcu_sta_state_v2_tlv(struct mt76_phy *mphy, struct sk_buff *skb, - struct ieee80211_sta *sta, + struct ieee80211_link_sta *link_sta, struct ieee80211_vif *vif, u8 rcpi, u8 sta_state) { @@ -1560,9 +1560,9 @@ mt7925_mcu_sta_state_v2_tlv(struct mt76_phy *mphy, struct sk_buff *skb, state = (struct sta_rec_state_v2 *)tlv; state->state = sta_state; - if (sta->deflink.vht_cap.vht_supported) { - state->vht_opmode = sta->deflink.bandwidth; - state->vht_opmode |= sta->deflink.rx_nss << + if (link_sta->vht_cap.vht_supported) { + state->vht_opmode = link_sta->bandwidth; + state->vht_opmode |= link_sta->rx_nss << IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; } } @@ -1643,7 +1643,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, mt7925_mcu_sta_eht_tlv(skb, info->link_sta->sta); mt7925_mcu_sta_rate_ctrl_tlv(skb, info->vif, info->link_sta->sta); - mt7925_mcu_sta_state_v2_tlv(phy, skb, info->link_sta->sta, + mt7925_mcu_sta_state_v2_tlv(phy, skb, info->link_sta, info->vif, info->rcpi, info->state); mt7925_mcu_sta_mld_tlv(skb, info->vif, info->link_sta->sta); From 22e177d2a72e8e8cbdb62722795e36769964b6eb Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:20 -0700 Subject: [PATCH 143/204] wifi: mt76: mt7925: extend mt7925_mcu_sta_rate_ctrl_tlv with per-link STA Extend mt7925_mcu_sta_rate_ctrl_tlv with the per-link STA configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-27-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 45437603763e..266010c0e00a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1569,7 +1569,8 @@ mt7925_mcu_sta_state_v2_tlv(struct mt76_phy *mphy, struct sk_buff *skb, static void mt7925_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, - struct ieee80211_vif *vif, struct ieee80211_sta *sta) + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct cfg80211_chan_def *chandef = &mvif->bss_conf.mt76.ctx->def; @@ -1581,7 +1582,7 @@ mt7925_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra_info)); ra_info = (struct sta_rec_ra_info *)tlv; - supp_rates = sta->deflink.supp_rates[band]; + supp_rates = link_sta->supp_rates[band]; if (band == NL80211_BAND_2GHZ) supp_rates = FIELD_PREP(RA_LEGACY_OFDM, supp_rates >> 4) | FIELD_PREP(RA_LEGACY_CCK, supp_rates & 0xf); @@ -1590,9 +1591,9 @@ mt7925_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, ra_info->legacy = cpu_to_le16(supp_rates); - if (sta->deflink.ht_cap.ht_supported) + if (link_sta->ht_cap.ht_supported) memcpy(ra_info->rx_mcs_bitmask, - sta->deflink.ht_cap.mcs.rx_mask, + link_sta->ht_cap.mcs.rx_mask, HT_MCS_MASK_NUM); } @@ -1642,7 +1643,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, mt7925_mcu_sta_he_6g_tlv(skb, info->link_sta->sta); mt7925_mcu_sta_eht_tlv(skb, info->link_sta->sta); mt7925_mcu_sta_rate_ctrl_tlv(skb, info->vif, - info->link_sta->sta); + info->link_sta); mt7925_mcu_sta_state_v2_tlv(phy, skb, info->link_sta, info->vif, info->rcpi, info->state); From b2f597730619202a9d11f65d1b642a771d6c2658 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:21 -0700 Subject: [PATCH 144/204] wifi: mt76: mt7925: extend mt7925_mcu_sta_eht_tlv for per-link STA Extend mt7925_mcu_sta_eht_tlv with the per-link STA configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-28-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 266010c0e00a..0c9cebd3ee71 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1404,18 +1404,18 @@ mt7925_mcu_sta_he_6g_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) } static void -mt7925_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) +mt7925_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta) { struct ieee80211_eht_mcs_nss_supp *mcs_map; struct ieee80211_eht_cap_elem_fixed *elem; struct sta_rec_eht *eht; struct tlv *tlv; - if (!sta->deflink.eht_cap.has_eht) + if (!link_sta->eht_cap.has_eht) return; - mcs_map = &sta->deflink.eht_cap.eht_mcs_nss_supp; - elem = &sta->deflink.eht_cap.eht_cap_elem; + mcs_map = &link_sta->eht_cap.eht_mcs_nss_supp; + elem = &link_sta->eht_cap.eht_cap_elem; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EHT, sizeof(*eht)); @@ -1425,7 +1425,7 @@ mt7925_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) eht->phy_cap = cpu_to_le64(*(u64 *)elem->phy_cap_info); eht->phy_cap_ext = cpu_to_le64(elem->phy_cap_info[8]); - if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_20) + if (link_sta->bandwidth == IEEE80211_STA_RX_BW_20) memcpy(eht->mcs_map_bw20, &mcs_map->only_20mhz, sizeof(eht->mcs_map_bw20)); memcpy(eht->mcs_map_bw80, &mcs_map->bw._80, sizeof(eht->mcs_map_bw80)); memcpy(eht->mcs_map_bw160, &mcs_map->bw._160, sizeof(eht->mcs_map_bw160)); @@ -1641,7 +1641,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, mt7925_mcu_sta_amsdu_tlv(skb, info->vif, info->link_sta->sta); mt7925_mcu_sta_he_tlv(skb, info->link_sta->sta); mt7925_mcu_sta_he_6g_tlv(skb, info->link_sta->sta); - mt7925_mcu_sta_eht_tlv(skb, info->link_sta->sta); + mt7925_mcu_sta_eht_tlv(skb, info->link_sta); mt7925_mcu_sta_rate_ctrl_tlv(skb, info->vif, info->link_sta); mt7925_mcu_sta_state_v2_tlv(phy, skb, info->link_sta, From 6805b190d2e13f6ddbdfe3bfd434ae2a1aba1d89 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:22 -0700 Subject: [PATCH 145/204] wifi: mt76: mt7925: extend mt7925_mcu_sta_he_6g_tlv for per-link STA Extend mt7925_mcu_sta_he_6g_tlv with the per-link STA configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-29-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 0c9cebd3ee71..e1dc8452468c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1389,18 +1389,19 @@ mt7925_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) } static void -mt7925_mcu_sta_he_6g_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) +mt7925_mcu_sta_he_6g_tlv(struct sk_buff *skb, + struct ieee80211_link_sta *link_sta) { struct sta_rec_he_6g_capa *he_6g; struct tlv *tlv; - if (!sta->deflink.he_6ghz_capa.capa) + if (!link_sta->he_6ghz_capa.capa) return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE_6G, sizeof(*he_6g)); he_6g = (struct sta_rec_he_6g_capa *)tlv; - he_6g->capa = sta->deflink.he_6ghz_capa.capa; + he_6g->capa = link_sta->he_6ghz_capa.capa; } static void @@ -1640,7 +1641,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, mt76_connac_mcu_sta_uapsd(skb, info->vif, info->link_sta->sta); mt7925_mcu_sta_amsdu_tlv(skb, info->vif, info->link_sta->sta); mt7925_mcu_sta_he_tlv(skb, info->link_sta->sta); - mt7925_mcu_sta_he_6g_tlv(skb, info->link_sta->sta); + mt7925_mcu_sta_he_6g_tlv(skb, info->link_sta); mt7925_mcu_sta_eht_tlv(skb, info->link_sta); mt7925_mcu_sta_rate_ctrl_tlv(skb, info->vif, info->link_sta); From e2f10f5bdd687c0ebfdb5dc9f452c05121a45f86 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:23 -0700 Subject: [PATCH 146/204] wifi: mt76: mt7925: extend mt7925_mcu_sta_he_tlv for per-link STA Extend mt7925_mcu_sta_he_tlv with the per-link STA configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-30-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index e1dc8452468c..a57620aed63b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1380,12 +1380,12 @@ mt7925_mcu_set_bss_pm(struct mt792x_dev *dev, } static void -mt7925_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) +mt7925_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta) { - if (!sta->deflink.he_cap.has_he) + if (!link_sta->he_cap.has_he) return; - mt76_connac_mcu_sta_he_tlv_v2(skb, sta); + mt76_connac_mcu_sta_he_tlv_v2(skb, link_sta->sta); } static void @@ -1640,7 +1640,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, mt7925_mcu_sta_vht_tlv(skb, info->link_sta->sta); mt76_connac_mcu_sta_uapsd(skb, info->vif, info->link_sta->sta); mt7925_mcu_sta_amsdu_tlv(skb, info->vif, info->link_sta->sta); - mt7925_mcu_sta_he_tlv(skb, info->link_sta->sta); + mt7925_mcu_sta_he_tlv(skb, info->link_sta); mt7925_mcu_sta_he_6g_tlv(skb, info->link_sta); mt7925_mcu_sta_eht_tlv(skb, info->link_sta); mt7925_mcu_sta_rate_ctrl_tlv(skb, info->vif, From 8ebb1a61b41e3c803c99b2828953c21eca181fcd Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:24 -0700 Subject: [PATCH 147/204] wifi: mt76: mt7925: extend mt7925_mcu_sta_amsdu_tlv for per-link STA Extend mt7925_mcu_sta_amsdu_tlv with the per-link STA configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-31-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index a57620aed63b..57b89eca4e21 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1467,9 +1467,11 @@ mt7925_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) static void mt7925_mcu_sta_amsdu_tlv(struct sk_buff *skb, - struct ieee80211_vif *vif, struct ieee80211_sta *sta) + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta) { - struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + struct mt792x_sta *msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + struct mt792x_link_sta *mlink; struct sta_rec_amsdu *amsdu; struct tlv *tlv; @@ -1477,16 +1479,18 @@ mt7925_mcu_sta_amsdu_tlv(struct sk_buff *skb, vif->type != NL80211_IFTYPE_AP) return; - if (!sta->deflink.agg.max_amsdu_len) + if (!link_sta->agg.max_amsdu_len) return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu)); amsdu = (struct sta_rec_amsdu *)tlv; amsdu->max_amsdu_num = 8; amsdu->amsdu_en = true; - msta->deflink.wcid.amsdu = true; - switch (sta->deflink.agg.max_amsdu_len) { + mlink = mt792x_sta_to_link(msta, link_sta->link_id); + mlink->wcid.amsdu = true; + + switch (link_sta->agg.max_amsdu_len) { case IEEE80211_MAX_MPDU_LEN_VHT_11454: amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; @@ -1639,7 +1643,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, mt7925_mcu_sta_ht_tlv(skb, info->link_sta->sta); mt7925_mcu_sta_vht_tlv(skb, info->link_sta->sta); mt76_connac_mcu_sta_uapsd(skb, info->vif, info->link_sta->sta); - mt7925_mcu_sta_amsdu_tlv(skb, info->vif, info->link_sta->sta); + mt7925_mcu_sta_amsdu_tlv(skb, info->vif, info->link_sta); mt7925_mcu_sta_he_tlv(skb, info->link_sta); mt7925_mcu_sta_he_6g_tlv(skb, info->link_sta); mt7925_mcu_sta_eht_tlv(skb, info->link_sta); From f75b6ee03aecfe5b74885a1042a5f80189b47144 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:25 -0700 Subject: [PATCH 148/204] wifi: mt76: mt7925: extend mt7925_mcu_sta_vht_tlv for per-link STA Extend mt7925_mcu_sta_vht_tlv with the per-link STA configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-32-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 57b89eca4e21..1b66dd26bd1e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1448,21 +1448,21 @@ mt7925_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) } static void -mt7925_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) +mt7925_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta) { struct sta_rec_vht *vht; struct tlv *tlv; /* For 6G band, this tlv is necessary to let hw work normally */ - if (!sta->deflink.he_6ghz_capa.capa && !sta->deflink.vht_cap.vht_supported) + if (!link_sta->he_6ghz_capa.capa && !link_sta->vht_cap.vht_supported) return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht)); vht = (struct sta_rec_vht *)tlv; - vht->vht_cap = cpu_to_le32(sta->deflink.vht_cap.cap); - vht->vht_rx_mcs_map = sta->deflink.vht_cap.vht_mcs.rx_mcs_map; - vht->vht_tx_mcs_map = sta->deflink.vht_cap.vht_mcs.tx_mcs_map; + vht->vht_cap = cpu_to_le32(link_sta->vht_cap.cap); + vht->vht_rx_mcs_map = link_sta->vht_cap.vht_mcs.rx_mcs_map; + vht->vht_tx_mcs_map = link_sta->vht_cap.vht_mcs.tx_mcs_map; } static void @@ -1641,7 +1641,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, if (info->link_sta && info->enable) { mt7925_mcu_sta_phy_tlv(skb, info->vif, info->link_sta->sta); mt7925_mcu_sta_ht_tlv(skb, info->link_sta->sta); - mt7925_mcu_sta_vht_tlv(skb, info->link_sta->sta); + mt7925_mcu_sta_vht_tlv(skb, info->link_sta); mt76_connac_mcu_sta_uapsd(skb, info->vif, info->link_sta->sta); mt7925_mcu_sta_amsdu_tlv(skb, info->vif, info->link_sta); mt7925_mcu_sta_he_tlv(skb, info->link_sta); From 872b5a03369c97f8e8c51d018618c25c04442d77 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:26 -0700 Subject: [PATCH 149/204] wifi: mt76: mt7925: extend mt7925_mcu_sta_ht_tlv for per-link STA Extend mt7925_mcu_sta_ht_tlv with the per-link STA configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-33-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 1b66dd26bd1e..66d45d676739 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1433,18 +1433,18 @@ mt7925_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta) } static void -mt7925_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) +mt7925_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta) { struct sta_rec_ht *ht; struct tlv *tlv; - if (!sta->deflink.ht_cap.ht_supported) + if (!link_sta->ht_cap.ht_supported) return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht)); ht = (struct sta_rec_ht *)tlv; - ht->ht_cap = cpu_to_le16(sta->deflink.ht_cap.cap); + ht->ht_cap = cpu_to_le16(link_sta->ht_cap.cap); } static void @@ -1640,7 +1640,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, info->enable, info->newly); if (info->link_sta && info->enable) { mt7925_mcu_sta_phy_tlv(skb, info->vif, info->link_sta->sta); - mt7925_mcu_sta_ht_tlv(skb, info->link_sta->sta); + mt7925_mcu_sta_ht_tlv(skb, info->link_sta); mt7925_mcu_sta_vht_tlv(skb, info->link_sta); mt76_connac_mcu_sta_uapsd(skb, info->vif, info->link_sta->sta); mt7925_mcu_sta_amsdu_tlv(skb, info->vif, info->link_sta); From e7a9853e6b8ae7f3da4134364e010894cbb9a754 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:27 -0700 Subject: [PATCH 150/204] wifi: mt76: mt7925: extend mt7925_mcu_sta_phy_tlv for per-link STA Extend mt7925_mcu_sta_phy_tlv with per-link STA configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-34-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 66d45d676739..a0fd02dd9551 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1507,34 +1507,43 @@ mt7925_mcu_sta_amsdu_tlv(struct sk_buff *skb, static void mt7925_mcu_sta_phy_tlv(struct sk_buff *skb, - struct ieee80211_vif *vif, struct ieee80211_sta *sta) + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - struct cfg80211_chan_def *chandef = &mvif->bss_conf.mt76.ctx->def; + struct ieee80211_bss_conf *link_conf; + struct cfg80211_chan_def *chandef; + struct mt792x_bss_conf *mconf; struct sta_rec_phy *phy; struct tlv *tlv; u8 af = 0, mm = 0; + link_conf = mt792x_vif_to_bss_conf(vif, link_sta->link_id); + mconf = mt792x_vif_to_link(mvif, link_sta->link_id); + chandef = &mconf->mt76.ctx->def; + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy)); phy = (struct sta_rec_phy *)tlv; - phy->phy_type = mt76_connac_get_phy_mode_v2(mvif->phy->mt76, vif, chandef->chan->band, sta); - phy->basic_rate = cpu_to_le16((u16)vif->bss_conf.basic_rates); - if (sta->deflink.ht_cap.ht_supported) { - af = sta->deflink.ht_cap.ampdu_factor; - mm = sta->deflink.ht_cap.ampdu_density; + phy->phy_type = mt76_connac_get_phy_mode_v2(mvif->phy->mt76, vif, + chandef->chan->band, + link_sta->sta); + phy->basic_rate = cpu_to_le16((u16)link_conf->basic_rates); + if (link_sta->ht_cap.ht_supported) { + af = link_sta->ht_cap.ampdu_factor; + mm = link_sta->ht_cap.ampdu_density; } - if (sta->deflink.vht_cap.vht_supported) { + if (link_sta->vht_cap.vht_supported) { u8 vht_af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, - sta->deflink.vht_cap.cap); + link_sta->vht_cap.cap); af = max_t(u8, af, vht_af); } - if (sta->deflink.he_6ghz_capa.capa) { - af = le16_get_bits(sta->deflink.he_6ghz_capa.capa, + if (link_sta->he_6ghz_capa.capa) { + af = le16_get_bits(link_sta->he_6ghz_capa.capa, IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP); - mm = le16_get_bits(sta->deflink.he_6ghz_capa.capa, + mm = le16_get_bits(link_sta->he_6ghz_capa.capa, IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START); } @@ -1639,7 +1648,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, info->link_sta->sta, info->enable, info->newly); if (info->link_sta && info->enable) { - mt7925_mcu_sta_phy_tlv(skb, info->vif, info->link_sta->sta); + mt7925_mcu_sta_phy_tlv(skb, info->vif, info->link_sta); mt7925_mcu_sta_ht_tlv(skb, info->link_sta); mt7925_mcu_sta_vht_tlv(skb, info->link_sta); mt76_connac_mcu_sta_uapsd(skb, info->vif, info->link_sta->sta); From 15ced2a624a534df601d7e74e512177dca3901d5 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:28 -0700 Subject: [PATCH 151/204] wifi: mt76: mt7925: extend mt7925_get_phy_mode_ext for per-link STA Extend mt7925_get_phy_mode_ext with the per-link STA configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-35-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index a0fd02dd9551..c6902009fd28 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2035,16 +2035,17 @@ int mt7925_mcu_set_chctx(struct mt76_phy *phy, struct mt76_vif *mvif, static u8 mt7925_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif, - enum nl80211_band band, struct ieee80211_sta *sta) + enum nl80211_band band, + struct ieee80211_link_sta *link_sta) { struct ieee80211_he_6ghz_capa *he_6ghz_capa; const struct ieee80211_sta_eht_cap *eht_cap; __le16 capa = 0; u8 mode = 0; - if (sta) { - he_6ghz_capa = &sta->deflink.he_6ghz_capa; - eht_cap = &sta->deflink.eht_cap; + if (link_sta) { + he_6ghz_capa = &link_sta->he_6ghz_capa; + eht_cap = &link_sta->eht_cap; } else { struct ieee80211_supported_band *sband; @@ -2090,6 +2091,7 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); struct mt792x_sta *msta = sta ? (struct mt792x_sta *)sta->drv_priv : &mconf->vif->sta; + struct ieee80211_link_sta *link_sta = sta ? &sta->deflink : NULL; struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &phy->chandef; enum nl80211_band band = chandef->chan->band; struct mt76_connac_bss_basic_tlv *basic_req; @@ -2104,7 +2106,8 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, mconf->mt76.omac_idx; basic_req->hw_bss_idx = idx; - basic_req->phymode_ext = mt7925_get_phy_mode_ext(phy, vif, band, sta); + basic_req->phymode_ext = mt7925_get_phy_mode_ext(phy, vif, band, + link_sta); if (band == NL80211_BAND_2GHZ) basic_req->nonht_basic_phy = cpu_to_le16(PHY_TYPE_ERP_INDEX); From 9d345e15ef58f7ac6e3ad0f1b99169f6b0bcd521 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:29 -0700 Subject: [PATCH 152/204] wifi: mt76: mt7925: extend mt7925_get_phy_mode for per-link STA Extend mt7925_get_phy_mode with the per-link STA configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-36-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 11 ++++++----- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h | 3 ++- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index a059532f383a..a1a07bbca7b3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1307,7 +1307,8 @@ int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif, EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_ba); u8 mt76_connac_get_phy_mode(struct mt76_phy *phy, struct ieee80211_vif *vif, - enum nl80211_band band, struct ieee80211_sta *sta) + enum nl80211_band band, + struct ieee80211_link_sta *link_sta) { struct mt76_dev *dev = phy->dev; const struct ieee80211_sta_he_cap *he_cap; @@ -1318,10 +1319,10 @@ u8 mt76_connac_get_phy_mode(struct mt76_phy *phy, struct ieee80211_vif *vif, if (is_connac_v1(dev)) return 0x38; - if (sta) { - ht_cap = &sta->deflink.ht_cap; - vht_cap = &sta->deflink.vht_cap; - he_cap = &sta->deflink.he_cap; + if (link_sta) { + ht_cap = &link_sta->ht_cap; + vht_cap = &link_sta->vht_cap; + he_cap = &link_sta->he_cap; } else { struct ieee80211_supported_band *sband; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 994136285815..b56896cdd4d8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1995,7 +1995,8 @@ mt76_connac_get_he_phy_cap(struct mt76_phy *phy, struct ieee80211_vif *vif); const struct ieee80211_sta_eht_cap * mt76_connac_get_eht_phy_cap(struct mt76_phy *phy, struct ieee80211_vif *vif); u8 mt76_connac_get_phy_mode(struct mt76_phy *phy, struct ieee80211_vif *vif, - enum nl80211_band band, struct ieee80211_sta *sta); + enum nl80211_band band, + struct ieee80211_link_sta *sta); u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif, enum nl80211_band band); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 9599adf104b1..590ee510eb7c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1503,7 +1503,7 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, ra->valid = true; ra->auto_rate = true; - ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, sta); + ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, &sta->deflink); ra->channel = chandef->chan->hw_value; ra->bw = sta->deflink.bandwidth; ra->phy.bw = sta->deflink.bandwidth; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index c6902009fd28..c19c6a0be597 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2115,7 +2115,7 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, basic_req->nonht_basic_phy = cpu_to_le16(PHY_TYPE_OFDM_INDEX); memcpy(basic_req->bssid, link_conf->bssid, ETH_ALEN); - basic_req->phymode = mt76_connac_get_phy_mode(phy, vif, band, sta); + basic_req->phymode = mt76_connac_get_phy_mode(phy, vif, band, link_sta); basic_req->bcn_interval = cpu_to_le16(link_conf->beacon_int); basic_req->dtim_period = link_conf->dtim_period; basic_req->bmc_tx_wlan_idx = cpu_to_le16(wlan_idx); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 2c8578677800..15905c0bfa8a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -2002,7 +2002,7 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev, ra->valid = true; ra->auto_rate = true; - ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, sta); + ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, &sta->deflink); ra->channel = chandef->chan->hw_value; ra->bw = (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_320) ? CMD_CBW_320MHZ : sta->deflink.bandwidth; From 45020d10d276f4e9678572207962fcf6d32f625b Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:30 -0700 Subject: [PATCH 153/204] wifi: mt76: mt792x: extend mt76_connac_get_phy_mode_v2 for per-link STA Extend mt76_connac_get_phy_mode_v2 with the per-link STA configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-37-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 16 +++++++++------- .../net/wireless/mediatek/mt76/mt76_connac_mcu.h | 3 ++- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index a1a07bbca7b3..8e9078342429 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -793,7 +793,8 @@ EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_he_tlv_v2); u8 mt76_connac_get_phy_mode_v2(struct mt76_phy *mphy, struct ieee80211_vif *vif, - enum nl80211_band band, struct ieee80211_sta *sta) + enum nl80211_band band, + struct ieee80211_link_sta *link_sta) { struct ieee80211_sta_ht_cap *ht_cap; struct ieee80211_sta_vht_cap *vht_cap; @@ -801,11 +802,11 @@ mt76_connac_get_phy_mode_v2(struct mt76_phy *mphy, struct ieee80211_vif *vif, const struct ieee80211_sta_eht_cap *eht_cap; u8 mode = 0; - if (sta) { - ht_cap = &sta->deflink.ht_cap; - vht_cap = &sta->deflink.vht_cap; - he_cap = &sta->deflink.he_cap; - eht_cap = &sta->deflink.eht_cap; + if (link_sta) { + ht_cap = &link_sta->ht_cap; + vht_cap = &link_sta->vht_cap; + he_cap = &link_sta->he_cap; + eht_cap = &link_sta->eht_cap; } else { struct ieee80211_supported_band *sband; @@ -911,7 +912,8 @@ void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb, tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy)); phy = (struct sta_rec_phy *)tlv; - phy->phy_type = mt76_connac_get_phy_mode_v2(mphy, vif, band, sta); + phy->phy_type = mt76_connac_get_phy_mode_v2(mphy, vif, band, + &sta->deflink); phy->basic_rate = cpu_to_le16((u16)vif->bss_conf.basic_rates); phy->rcpi = rcpi; phy->ampdu = FIELD_PREP(IEEE80211_HT_AMPDU_PARM_FACTOR, diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index b56896cdd4d8..d4488b9cca46 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1901,7 +1901,8 @@ int mt76_connac_mcu_sta_update_hdr_trans(struct mt76_dev *dev, struct mt76_wcid *wcid, int cmd); void mt76_connac_mcu_sta_he_tlv_v2(struct sk_buff *skb, struct ieee80211_sta *sta); u8 mt76_connac_get_phy_mode_v2(struct mt76_phy *mphy, struct ieee80211_vif *vif, - enum nl80211_band band, struct ieee80211_sta *sta); + enum nl80211_band band, + struct ieee80211_link_sta *link_sta); int mt76_connac_mcu_wtbl_update_hdr_trans(struct mt76_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index c19c6a0be597..80b735cfbdc7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1526,7 +1526,7 @@ mt7925_mcu_sta_phy_tlv(struct sk_buff *skb, phy = (struct sta_rec_phy *)tlv; phy->phy_type = mt76_connac_get_phy_mode_v2(mvif->phy->mt76, vif, chandef->chan->band, - link_sta->sta); + link_sta); phy->basic_rate = cpu_to_le16((u16)link_conf->basic_rates); if (link_sta->ht_cap.ht_supported) { af = link_sta->ht_cap.ampdu_factor; From 6e226666efc06dadc0fc92c63c8fe9fa17898b8b Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:31 -0700 Subject: [PATCH 154/204] wifi: mt76: mt762x: extend mt76_connac_mcu_sta_basic_tlv for per-link STA Extend mt76_connac_mcu_sta_basic_tlv with the per-link STA configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-38-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7615/mcu.c | 6 ++++-- .../wireless/mediatek/mt76/mt76_connac_mcu.c | 19 +++++++++++-------- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 4 ++-- .../net/wireless/mediatek/mt76/mt7915/mcu.c | 4 +++- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 2 +- .../net/wireless/mediatek/mt76/mt7996/mcu.c | 5 ++++- 6 files changed, 25 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 792ae41f7c69..d50d967828be 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -842,6 +842,7 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif, { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct sk_buff *skb, *sskb, *wskb = NULL; + struct ieee80211_link_sta *link_sta; struct mt7615_dev *dev = phy->dev; struct wtbl_req_hdr *wtbl_hdr; struct mt7615_sta *msta; @@ -849,6 +850,7 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif, int cmd, err; msta = sta ? (struct mt7615_sta *)sta->drv_priv : &mvif->sta; + link_sta = sta ? &sta->deflink : NULL; sskb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, &msta->wcid); @@ -861,8 +863,8 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif, else mvif->sta_added = true; } - mt76_connac_mcu_sta_basic_tlv(&dev->mt76, sskb, vif, sta, enable, - new_entry); + mt76_connac_mcu_sta_basic_tlv(&dev->mt76, sskb, vif, link_sta, + enable, new_entry); if (enable && sta) mt76_connac_mcu_sta_tlv(phy->mt76, sskb, sta, vif, 0, MT76_STA_INFO_STATE_ASSOC); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 8e9078342429..4e3c8af98fe7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -370,7 +370,7 @@ EXPORT_SYMBOL_GPL(mt76_connac_mcu_bss_omac_tlv); void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ieee80211_link_sta *link_sta, bool enable, bool newly) { struct sta_rec_basic *basic; @@ -390,7 +390,7 @@ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb, basic->conn_state = CONN_STATE_DISCONNECT; } - if (!sta) { + if (!link_sta) { basic->conn_type = cpu_to_le32(CONNECTION_INFRA_BC); if (vif->type == NL80211_IFTYPE_STATION && @@ -411,7 +411,7 @@ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb, else conn_type = CONNECTION_INFRA_STA; basic->conn_type = cpu_to_le32(conn_type); - basic->aid = cpu_to_le16(sta->aid); + basic->aid = cpu_to_le16(link_sta->sta->aid); break; case NL80211_IFTYPE_STATION: if (vif->p2p && !is_mt7921(dev)) @@ -423,15 +423,15 @@ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb, break; case NL80211_IFTYPE_ADHOC: basic->conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); - basic->aid = cpu_to_le16(sta->aid); + basic->aid = cpu_to_le16(link_sta->sta->aid); break; default: WARN_ON(1); break; } - memcpy(basic->peer_addr, sta->addr, ETH_ALEN); - basic->qos = sta->wme; + memcpy(basic->peer_addr, link_sta->addr, ETH_ALEN); + basic->qos = link_sta->sta->wme; } EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_basic_tlv); @@ -1046,6 +1046,7 @@ int mt76_connac_mcu_sta_cmd(struct mt76_phy *phy, struct mt76_sta_cmd_info *info) { struct mt76_vif *mvif = (struct mt76_vif *)info->vif->drv_priv; + struct ieee80211_link_sta *link_sta; struct mt76_dev *dev = phy->dev; struct wtbl_req_hdr *wtbl_hdr; struct tlv *sta_wtbl; @@ -1055,9 +1056,11 @@ int mt76_connac_mcu_sta_cmd(struct mt76_phy *phy, if (IS_ERR(skb)) return PTR_ERR(skb); + link_sta = info->sta ? &info->sta->deflink : NULL; if (info->sta || !info->offload_fw) - mt76_connac_mcu_sta_basic_tlv(dev, skb, info->vif, info->sta, - info->enable, info->newly); + mt76_connac_mcu_sta_basic_tlv(dev, skb, info->vif, + link_sta, info->enable, + info->newly); if (info->sta && info->enable) mt76_connac_mcu_sta_tlv(phy, skb, info->sta, info->vif, info->rcpi, diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index d4488b9cca46..e636b033b87e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1886,8 +1886,8 @@ int mt76_connac_mcu_set_channel_domain(struct mt76_phy *phy); int mt76_connac_mcu_set_vif_ps(struct mt76_dev *dev, struct ieee80211_vif *vif); void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool enable, - bool newly); + struct ieee80211_link_sta *link_sta, + bool enable, bool newly); void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta, void *sta_wtbl, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 590ee510eb7c..2185cd24e2e1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1656,11 +1656,13 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct ieee80211_link_sta *link_sta; struct mt7915_sta *msta; struct sk_buff *skb; int ret; msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta; + link_sta = sta ? &sta->deflink : NULL; skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, &msta->wcid); @@ -1668,7 +1670,7 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, return PTR_ERR(skb); /* starec basic */ - mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, vif, sta, enable, + mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, vif, link_sta, enable, !rcu_access_pointer(dev->mt76.wcid[msta->wcid.idx])); if (!enable) goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 80b735cfbdc7..bf2afaf4c0dc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1645,7 +1645,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, if (info->link_sta || !info->offload_fw) mt76_connac_mcu_sta_basic_tlv(dev, skb, info->vif, - info->link_sta->sta, + info->link_sta, info->enable, info->newly); if (info->link_sta && info->enable) { mt7925_mcu_sta_phy_tlv(skb, info->vif, info->link_sta); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 15905c0bfa8a..2e4fa9f48dfb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -2157,11 +2157,13 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable, bool newly) { struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct ieee80211_link_sta *link_sta; struct mt7996_sta *msta; struct sk_buff *skb; int ret; msta = sta ? (struct mt7996_sta *)sta->drv_priv : &mvif->sta; + link_sta = sta ? &sta->deflink : NULL; skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, &msta->wcid, @@ -2170,7 +2172,8 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif, return PTR_ERR(skb); /* starec basic */ - mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, vif, sta, enable, newly); + mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, vif, link_sta, + enable, newly); if (!enable) goto out; From 612004dd7480b0a039909f3959a73cbc59523f65 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:32 -0700 Subject: [PATCH 155/204] wifi: mt76: mt7925: extend mt7925_mcu_sta_hdr_trans_tlv for per-link STA Extend mt7925_mcu_sta_hdr_trans_tlv with per-link STA configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-39-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index bf2afaf4c0dc..901a5d1f4f04 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -847,7 +847,7 @@ EXPORT_SYMBOL_GPL(mt7925_run_firmware); static void mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct ieee80211_link_sta *link_sta) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct sta_rec_hdr_trans *hdr_trans; @@ -863,8 +863,8 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb, else hdr_trans->from_ds = true; - if (sta) - wcid = (struct mt76_wcid *)sta->drv_priv; + if (link_sta) + wcid = (struct mt76_wcid *)link_sta->sta->drv_priv; else wcid = &mvif->sta.deflink.wcid; @@ -883,6 +883,7 @@ int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev, struct ieee80211_sta *sta) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct ieee80211_link_sta *link_sta = sta ? &sta->deflink : NULL; struct mt792x_sta *msta; struct sk_buff *skb; @@ -895,7 +896,7 @@ int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev, return PTR_ERR(skb); /* starec hdr trans */ - mt7925_mcu_sta_hdr_trans_tlv(skb, vif, sta); + mt7925_mcu_sta_hdr_trans_tlv(skb, vif, link_sta); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); } @@ -1664,12 +1665,8 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, mt7925_mcu_sta_mld_tlv(skb, info->vif, info->link_sta->sta); } - if (info->enable) { - struct ieee80211_sta *sta = info->link_sta ? - info->link_sta->sta : NULL; - - mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, sta); - } + if (info->enable) + mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, info->link_sta); return mt76_mcu_skb_send_msg(dev, skb, info->cmd, true); } From 064a5955aa2732844ca1e30b93d66c9ce179e811 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:33 -0700 Subject: [PATCH 156/204] wifi: mt76: mt7925: extend mt7925_mcu_add_bss_info for per-link STA Extend mt7925_mcu_add_bss_info with the per-link STA configuration. The patch we created is a prerequisite to enable the MLO function in the driver. It is purely a refactoring patch so the functionality should remain unchanged. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-40-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/main.c | 9 +++++---- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt7925/mcu.h | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index f3a32fe9a754..e701d40569fb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -489,6 +489,7 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_sta *msta = sta ? (struct mt792x_sta *)sta->drv_priv : &mvif->sta; + struct ieee80211_link_sta *link_sta = sta ? &sta->deflink : NULL; struct mt76_wcid *wcid = &msta->deflink.wcid; struct ieee80211_bss_conf *link_conf; u8 *wcid_keyidx = &wcid->hw_key_idx; @@ -535,7 +536,7 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mvif->bss_conf.mt76.cipher = mt7925_mcu_get_cipher(key->cipher); mt7925_mcu_add_bss_info(phy, mvif->bss_conf.mt76.ctx, link_conf, - sta, true); + link_sta, true); } if (cmd == SET_KEY) @@ -738,7 +739,7 @@ int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, /* should update bss info before STA add */ if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, - link_conf, sta, false); + link_conf, &sta->deflink, false); ret = mt7925_mcu_sta_update(dev, &sta->deflink, vif, true, MT76_STA_INFO_STATE_NONE); @@ -765,7 +766,7 @@ void mt7925_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, - link_conf, sta, true); + link_conf, &sta->deflink, true); ewma_avg_signal_init(&msta->deflink.avg_ack_signal); @@ -802,7 +803,7 @@ void mt7925_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, ewma_rssi_init(&mvif->bss_conf.rssi); if (!sta->tdls) mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, - link_conf, sta, false); + link_conf, &sta->deflink, false); } spin_lock_bh(&mdev->sta_poll_lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 901a5d1f4f04..03cce9fca0c3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2338,7 +2338,7 @@ int mt7925_mcu_set_timing(struct mt792x_phy *phy, int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, struct ieee80211_chanctx_conf *ctx, struct ieee80211_bss_conf *link_conf, - struct ieee80211_sta *sta, + struct ieee80211_link_sta *link_sta, int enable) { struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv; @@ -2353,13 +2353,13 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, return PTR_ERR(skb); /* bss_basic must be first */ - mt7925_mcu_bss_basic_tlv(skb, link_conf, sta, ctx, phy->mt76, + mt7925_mcu_bss_basic_tlv(skb, link_conf, link_sta->sta, ctx, phy->mt76, mvif->sta.deflink.wcid.idx, enable); mt7925_mcu_bss_sec_tlv(skb, link_conf); mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, link_conf); mt7925_mcu_bss_qos_tlv(skb, link_conf); - mt7925_mcu_bss_mld_tlv(skb, link_conf, sta); + mt7925_mcu_bss_mld_tlv(skb, link_conf, link_sta->sta); mt7925_mcu_bss_ifs_tlv(skb, link_conf); if (link_conf->he_support) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h index c5197577cdc8..da4e84f468d2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -595,7 +595,7 @@ int mt7925_mcu_sched_scan_enable(struct mt76_phy *phy, int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, struct ieee80211_chanctx_conf *ctx, struct ieee80211_bss_conf *link_conf, - struct ieee80211_sta *sta, + struct ieee80211_link_sta *link_sta, int enable); int mt7925_mcu_set_timing(struct mt792x_phy *phy, struct ieee80211_bss_conf *link_conf); From 523f5d9c256079fe21087b3dfc4c3c0c1fffab53 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:34 -0700 Subject: [PATCH 157/204] wifi: mt76: mt7925: extend mt7925_mcu_bss_mld_tlv for per-link STA Extend mt7925_mcu_bss_mld_tlv with the per-link STA configuration. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-41-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 03cce9fca0c3..2a96ff89ef67 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2228,7 +2228,7 @@ mt7925_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt792x_phy *phy, static void mt7925_mcu_bss_mld_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf, - struct ieee80211_sta *sta) + struct ieee80211_link_sta *link_sta) { struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); bool is_mld = ieee80211_vif_is_mld(link_conf->vif); @@ -2238,13 +2238,13 @@ mt7925_mcu_bss_mld_tlv(struct sk_buff *skb, tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_MLD, sizeof(*mld)); mld = (struct bss_mld_tlv *)tlv; - mld->link_id = sta ? (is_mld ? link_conf->link_id : 0) : 0xff; + mld->link_id = link_sta ? (is_mld ? link_conf->link_id : 0) : 0xff; mld->group_mld_id = is_mld ? mconf->mt76.idx : 0xff; mld->own_mld_id = mconf->mt76.idx + 32; mld->remap_idx = 0xff; - if (sta) - memcpy(mld->mac_addr, sta->addr, ETH_ALEN); + if (link_sta) + memcpy(mld->mac_addr, link_sta->addr, ETH_ALEN); } static void @@ -2359,7 +2359,7 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, link_conf); mt7925_mcu_bss_qos_tlv(skb, link_conf); - mt7925_mcu_bss_mld_tlv(skb, link_conf, link_sta->sta); + mt7925_mcu_bss_mld_tlv(skb, link_conf, link_sta); mt7925_mcu_bss_ifs_tlv(skb, link_conf); if (link_conf->he_support) { From c1c98696de70e378a70b5b34ecf6193a8ccad4e5 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:35 -0700 Subject: [PATCH 158/204] wifi: mt76: mt7925: extend mt7925_mcu_bss_basic_tlv for per-link STA Extend mt7925_mcu_bss_basic_tlv with the per-link STA configuration. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-42-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 2a96ff89ef67..09ffa7abe8aa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2079,19 +2079,17 @@ mt7925_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif, static void mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf, - struct ieee80211_sta *sta, + struct ieee80211_link_sta *link_sta, struct ieee80211_chanctx_conf *ctx, struct mt76_phy *phy, u16 wlan_idx, bool enable) { struct ieee80211_vif *vif = link_conf->vif; struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); - struct mt792x_sta *msta = sta ? (struct mt792x_sta *)sta->drv_priv : - &mconf->vif->sta; - struct ieee80211_link_sta *link_sta = sta ? &sta->deflink : NULL; struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &phy->chandef; enum nl80211_band band = chandef->chan->band; struct mt76_connac_bss_basic_tlv *basic_req; + struct mt792x_link_sta *mlink; struct tlv *tlv; int conn_type; u8 idx; @@ -2116,7 +2114,18 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, basic_req->bcn_interval = cpu_to_le16(link_conf->beacon_int); basic_req->dtim_period = link_conf->dtim_period; basic_req->bmc_tx_wlan_idx = cpu_to_le16(wlan_idx); - basic_req->sta_idx = cpu_to_le16(msta->deflink.wcid.idx); + + if (link_sta) { + struct mt792x_sta *msta; + + msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + mlink = mt792x_sta_to_link(msta, link_sta->link_id); + + } else { + mlink = &mconf->vif->sta.deflink; + } + + basic_req->sta_idx = cpu_to_le16(mlink->wcid.idx); basic_req->omac_idx = mconf->mt76.omac_idx; basic_req->band_idx = mconf->mt76.band_idx; basic_req->wmm_idx = mconf->mt76.wmm_idx; @@ -2353,7 +2362,7 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, return PTR_ERR(skb); /* bss_basic must be first */ - mt7925_mcu_bss_basic_tlv(skb, link_conf, link_sta->sta, ctx, phy->mt76, + mt7925_mcu_bss_basic_tlv(skb, link_conf, link_sta, ctx, phy->mt76, mvif->sta.deflink.wcid.idx, enable); mt7925_mcu_bss_sec_tlv(skb, link_conf); From 5029871583c3cf42f3320b7709820ad44a1313fc Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:36 -0700 Subject: [PATCH 159/204] wifi: mt76: mt7925: add mt7925_mac_link_sta_add to create per-link STA The mt7925_mac_link_sta_add function currently adds the per-link STA. We will extend this function when we implement the MLO functionality. This patch only includes structural changes and does not involve any logic changes. Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-43-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/main.c | 47 ++++++++++++------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index e701d40569fb..3872b5debdd8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -703,45 +703,46 @@ mt7925_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return mvif->basic_rates_idx; } -int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +static int mt7925_mac_link_sta_add(struct mt76_dev *mdev, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta) { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); - struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct ieee80211_bss_conf *link_conf; + struct mt792x_link_sta *mlink; + struct mt792x_sta *msta; int ret, idx; + msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + mlink = mt792x_sta_to_link(msta, link_sta->link_id); + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); if (idx < 0) return -ENOSPC; - INIT_LIST_HEAD(&msta->deflink.wcid.poll_list); - msta->vif = mvif; - msta->deflink.wcid.sta = 1; - msta->deflink.wcid.idx = idx; - msta->deflink.wcid.phy_idx = mvif->bss_conf.mt76.band_idx; - msta->deflink.wcid.tx_info |= MT_WCID_TX_INFO_SET; - msta->deflink.last_txs = jiffies; + INIT_LIST_HEAD(&mlink->wcid.poll_list); + mlink->wcid.sta = 1; + mlink->wcid.idx = idx; + mlink->wcid.phy_idx = mvif->bss_conf.mt76.band_idx; + mlink->wcid.tx_info |= MT_WCID_TX_INFO_SET; + mlink->last_txs = jiffies; ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm); if (ret) return ret; - if (vif->type == NL80211_IFTYPE_STATION) - mvif->wep_sta = msta; - mt7925_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); link_conf = mt792x_vif_to_bss_conf(vif, vif->bss_conf.link_id); /* should update bss info before STA add */ - if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) + if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, - link_conf, &sta->deflink, false); + link_conf, link_sta, false); - ret = mt7925_mcu_sta_update(dev, &sta->deflink, vif, true, + ret = mt7925_mcu_sta_update(dev, link_sta, vif, true, MT76_STA_INFO_STATE_NONE); if (ret) return ret; @@ -750,6 +751,20 @@ int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, return 0; } + +int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + + msta->vif = mvif; + + if (vif->type == NL80211_IFTYPE_STATION) + mvif->wep_sta = msta; + + return mt7925_mac_link_sta_add(mdev, vif, &sta->deflink); +} EXPORT_SYMBOL_GPL(mt7925_mac_sta_add); void mt7925_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, From 89397bccc882a446373874cd8c4164e1612d8494 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:37 -0700 Subject: [PATCH 160/204] wifi: mt76: mt7925: add mt7925_mac_link_sta_assoc to associate per-link STA The mt7925_mac_link_sta_add function currently associates the per-link STA. We will extend this function when we implement the MLO functionality. This patch only includes structural changes and does not involve any logic changes. Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-44-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/main.c | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 3872b5debdd8..202bd84716ab 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -767,32 +767,43 @@ int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(mt7925_mac_sta_add); -void mt7925_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta) { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); - struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct ieee80211_bss_conf *link_conf; + struct mt792x_link_sta *mlink; + struct mt792x_sta *msta; + + msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + mlink = mt792x_sta_to_link(msta, link_sta->link_id); mt792x_mutex_acquire(dev); link_conf = mt792x_vif_to_bss_conf(vif, vif->bss_conf.link_id); - if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) + if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, - link_conf, &sta->deflink, true); + link_conf, link_sta, true); - ewma_avg_signal_init(&msta->deflink.avg_ack_signal); + ewma_avg_signal_init(&mlink->avg_ack_signal); - mt7925_mac_wtbl_update(dev, msta->deflink.wcid.idx, + mt7925_mac_wtbl_update(dev, mlink->wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - memset(msta->deflink.airtime_ac, 0, sizeof(msta->deflink.airtime_ac)); + memset(mlink->airtime_ac, 0, sizeof(mlink->airtime_ac)); - mt7925_mcu_sta_update(dev, &sta->deflink, vif, true, MT76_STA_INFO_STATE_ASSOC); + mt7925_mcu_sta_update(dev, link_sta, vif, true, MT76_STA_INFO_STATE_ASSOC); mt792x_mutex_release(dev); } + +void mt7925_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + mt7925_mac_link_sta_assoc(mdev, vif, &sta->deflink); +} EXPORT_SYMBOL_GPL(mt7925_mac_sta_assoc); void mt7925_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, From 5f5b6a745c697c1a80cfd9eacf1f91613d29b050 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:38 -0700 Subject: [PATCH 161/204] wifi: mt76: mt7925: add mt7925_mac_link_sta_remove to remove per-link STA The mt7925_mac_link_sta_remove function currently removes the per-link STA. We will extend this function when we implement the MLO functionality. This patch only includes structural changes and does not involve any logic changes. Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-45-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/main.c | 48 ++++++++++++------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 202bd84716ab..21a2d1bd8d18 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -806,38 +806,54 @@ void mt7925_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(mt7925_mac_sta_assoc); -void mt7925_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta) { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); - struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; struct ieee80211_bss_conf *link_conf; + struct mt792x_link_sta *mlink; + struct mt792x_sta *msta; - mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->deflink.wcid); + msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + mlink = mt792x_sta_to_link(msta, link_sta->link_id); + + mt76_connac_free_pending_tx_skbs(&dev->pm, &mlink->wcid); mt76_connac_pm_wake(&dev->mphy, &dev->pm); - mt7925_mcu_sta_update(dev, &sta->deflink, vif, false, MT76_STA_INFO_STATE_NONE); - mt7925_mac_wtbl_update(dev, msta->deflink.wcid.idx, + mt7925_mcu_sta_update(dev, link_sta, vif, false, + MT76_STA_INFO_STATE_NONE); + mt7925_mac_wtbl_update(dev, mlink->wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); link_conf = mt792x_vif_to_bss_conf(vif, vif->bss_conf.link_id); + if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + mt7925_mcu_add_bss_info(&dev->phy, + mvif->bss_conf.mt76.ctx, link_conf, + link_sta, false); + } + + spin_lock_bh(&mdev->sta_poll_lock); + if (!list_empty(&mlink->wcid.poll_list)) + list_del_init(&mlink->wcid.poll_list); + spin_unlock_bh(&mdev->sta_poll_lock); + + mt76_connac_power_save_sched(&dev->mphy, &dev->pm); +} + +void mt7925_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + mt7925_mac_link_sta_remove(mdev, vif, &sta->deflink); + if (vif->type == NL80211_IFTYPE_STATION) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; mvif->wep_sta = NULL; ewma_rssi_init(&mvif->bss_conf.rssi); - if (!sta->tdls) - mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, - link_conf, &sta->deflink, false); } - - spin_lock_bh(&mdev->sta_poll_lock); - if (!list_empty(&msta->deflink.wcid.poll_list)) - list_del_init(&msta->deflink.wcid.poll_list); - spin_unlock_bh(&mdev->sta_poll_lock); - - mt76_connac_power_save_sched(&dev->mphy, &dev->pm); } EXPORT_SYMBOL_GPL(mt7925_mac_sta_remove); From 95977b1d10cfeb12b67a76dc2eefa86300c396d1 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:39 -0700 Subject: [PATCH 162/204] wifi: mt76: mt7925: add mt7925_mac_link_bss_add to create per-link BSS The mt7925_mac_link_bss_add function currently creates the per-link BSS. We will extend this function when we implement the MLO functionality. This patch only includes structural changes and does not involve any logic changes. Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-46-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/main.c | 104 ++++++++++-------- 1 file changed, 61 insertions(+), 43 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 21a2d1bd8d18..8b10b63bc98d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -317,62 +317,80 @@ static int mt7925_start(struct ieee80211_hw *hw) return err; } +static int mt7925_mac_link_bss_add(struct mt792x_dev *dev, + struct ieee80211_bss_conf *link_conf, + struct mt792x_link_sta *mlink) +{ + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); + struct ieee80211_vif *vif = link_conf->vif; + struct mt792x_vif *mvif = mconf->vif; + struct mt76_txq *mtxq; + int idx, ret = 0; + + mconf->mt76.idx = __ffs64(~dev->mt76.vif_mask); + if (mconf->mt76.idx >= MT792x_MAX_INTERFACES) { + ret = -ENOSPC; + goto out; + } + + mconf->mt76.omac_idx = mconf->mt76.idx; + mconf->mt76.band_idx = 0; + mconf->mt76.wmm_idx = mconf->mt76.idx % MT76_CONNAC_MAX_WMM_SETS; + + if (mvif->phy->mt76->chandef.chan->band != NL80211_BAND_2GHZ) + mconf->mt76.basic_rates_idx = MT792x_BASIC_RATES_TBL + 4; + else + mconf->mt76.basic_rates_idx = MT792x_BASIC_RATES_TBL; + + ret = mt76_connac_mcu_uni_add_dev(&dev->mphy, link_conf, + &mlink->wcid, true); + if (ret) + goto out; + + dev->mt76.vif_mask |= BIT_ULL(mconf->mt76.idx); + mvif->phy->omac_mask |= BIT_ULL(mconf->mt76.omac_idx); + + idx = MT792x_WTBL_RESERVED - mconf->mt76.idx; + + INIT_LIST_HEAD(&mlink->wcid.poll_list); + mlink->wcid.idx = idx; + mlink->wcid.phy_idx = mconf->mt76.band_idx; + mlink->wcid.hw_key_idx = -1; + mlink->wcid.tx_info |= MT_WCID_TX_INFO_SET; + mt76_wcid_init(&mlink->wcid); + + mt7925_mac_wtbl_update(dev, idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + + ewma_rssi_init(&mconf->rssi); + + rcu_assign_pointer(dev->mt76.wcid[idx], &mlink->wcid); + if (vif->txq) { + mtxq = (struct mt76_txq *)vif->txq->drv_priv; + mtxq->wcid = idx; + } + +out: + return ret; +} + static int mt7925_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt792x_phy *phy = mt792x_hw_phy(hw); - struct mt76_txq *mtxq; - int idx, ret = 0; + int ret = 0; mt792x_mutex_acquire(dev); - mvif->bss_conf.mt76.idx = __ffs64(~dev->mt76.vif_mask); - if (mvif->bss_conf.mt76.idx >= MT792x_MAX_INTERFACES) { - ret = -ENOSPC; - goto out; - } - - mvif->bss_conf.mt76.omac_idx = mvif->bss_conf.mt76.idx; mvif->phy = phy; - mvif->bss_conf.mt76.band_idx = 0; - mvif->bss_conf.mt76.wmm_idx = mvif->bss_conf.mt76.idx % MT76_CONNAC_MAX_WMM_SETS; mvif->bss_conf.vif = mvif; - - if (phy->mt76->chandef.chan->band != NL80211_BAND_2GHZ) - mvif->bss_conf.mt76.basic_rates_idx = MT792x_BASIC_RATES_TBL + 4; - else - mvif->bss_conf.mt76.basic_rates_idx = MT792x_BASIC_RATES_TBL; - - ret = mt76_connac_mcu_uni_add_dev(&dev->mphy, &vif->bss_conf, - &mvif->sta.deflink.wcid, true); - if (ret) - goto out; - - dev->mt76.vif_mask |= BIT_ULL(mvif->bss_conf.mt76.idx); - phy->omac_mask |= BIT_ULL(mvif->bss_conf.mt76.omac_idx); - - idx = MT792x_WTBL_RESERVED - mvif->bss_conf.mt76.idx; - - INIT_LIST_HEAD(&mvif->sta.deflink.wcid.poll_list); - mvif->sta.deflink.wcid.idx = idx; - mvif->sta.deflink.wcid.phy_idx = mvif->bss_conf.mt76.band_idx; - mvif->sta.deflink.wcid.hw_key_idx = -1; - mvif->sta.deflink.wcid.tx_info |= MT_WCID_TX_INFO_SET; mvif->sta.vif = mvif; - mt76_wcid_init(&mvif->sta.deflink.wcid); - mt7925_mac_wtbl_update(dev, idx, - MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - - ewma_rssi_init(&mvif->bss_conf.rssi); - - rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.deflink.wcid); - if (vif->txq) { - mtxq = (struct mt76_txq *)vif->txq->drv_priv; - mtxq->wcid = idx; - } + ret = mt7925_mac_link_bss_add(dev, &vif->bss_conf, &mvif->sta.deflink); + if (ret < 0) + goto out; vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; out: From 1541d63c5fe2cebce85b2af84a2850a302ffda9c Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:40 -0700 Subject: [PATCH 163/204] wifi: mt76: mt7925: add mt7925_mac_link_bss_remove to remove per-link BSS The mt7925_mac_link_bss_remove function currently removes the per-link BSS. We will extend this function when we implement the MLO functionality. This patch only includes structural changes and does not involve any logic changes. Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-47-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt792x_core.c | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c index b1c51e3f39d0..813296fad0ed 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c @@ -113,31 +113,38 @@ void mt792x_stop(struct ieee80211_hw *hw, bool suspend) } EXPORT_SYMBOL_GPL(mt792x_stop); +static void mt792x_mac_link_bss_remove(struct mt792x_dev *dev, + struct ieee80211_bss_conf *link_conf, + struct mt792x_link_sta *mlink) +{ + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); + int idx = mlink->wcid.idx; + + mt792x_mutex_acquire(dev); + mt76_connac_free_pending_tx_skbs(&dev->pm, &mlink->wcid); + mt76_connac_mcu_uni_add_dev(&dev->mphy, link_conf, &mlink->wcid, false); + + rcu_assign_pointer(dev->mt76.wcid[idx], NULL); + + dev->mt76.vif_mask &= ~BIT_ULL(mconf->mt76.idx); + mconf->vif->phy->omac_mask &= ~BIT_ULL(mconf->mt76.omac_idx); + mt792x_mutex_release(dev); + + spin_lock_bh(&dev->mt76.sta_poll_lock); + if (!list_empty(&mlink->wcid.poll_list)) + list_del_init(&mlink->wcid.poll_list); + spin_unlock_bh(&dev->mt76.sta_poll_lock); + + mt76_wcid_cleanup(&dev->mt76, &mlink->wcid); +} + void mt792x_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - struct mt792x_sta *msta = &mvif->sta; struct mt792x_dev *dev = mt792x_hw_dev(hw); - struct mt792x_phy *phy = mt792x_hw_phy(hw); - int idx = msta->deflink.wcid.idx; - mt792x_mutex_acquire(dev); - mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->deflink.wcid); - mt76_connac_mcu_uni_add_dev(&dev->mphy, &vif->bss_conf, &mvif->sta.deflink.wcid, false); - - rcu_assign_pointer(dev->mt76.wcid[idx], NULL); - - dev->mt76.vif_mask &= ~BIT_ULL(mvif->bss_conf.mt76.idx); - phy->omac_mask &= ~BIT_ULL(mvif->bss_conf.mt76.omac_idx); - mt792x_mutex_release(dev); - - spin_lock_bh(&dev->mt76.sta_poll_lock); - if (!list_empty(&msta->deflink.wcid.poll_list)) - list_del_init(&msta->deflink.wcid.poll_list); - spin_unlock_bh(&dev->mt76.sta_poll_lock); - - mt76_wcid_cleanup(&dev->mt76, &msta->deflink.wcid); + mt792x_mac_link_bss_remove(dev, &vif->bss_conf, &mvif->sta.deflink); } EXPORT_SYMBOL_GPL(mt792x_remove_interface); From 8b7eb93b7a75f453d2b35c5b904895b628949593 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jun 2024 20:02:41 -0700 Subject: [PATCH 164/204] wifi: mt76: mt7925: simpify mt7925_mcu_sta_cmd logic by removing fw_offload The mt7925 only supports offload firmware making the fw_offload check redundant. This update simplifies the logic in "mt7925_mcu_sta_cmd" by removing the unnecessary check for fw_offoad. Signed-off-by: Sean Wang Link: https://patch.msgid.link/20240613030241.5771-48-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 09ffa7abe8aa..a67d8dd6075f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1644,7 +1644,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, if (IS_ERR(skb)) return PTR_ERR(skb); - if (info->link_sta || !info->offload_fw) + if (info->link_sta) mt76_connac_mcu_sta_basic_tlv(dev, skb, info->vif, info->link_sta, info->enable, info->newly); From 2938b50917a5431efa8c00c9c8b2ee89c406cf05 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 3 Jul 2024 14:42:06 -0700 Subject: [PATCH 165/204] wifi: mt76: mt7925: update mt76_connac_mcu_uni_add_dev for MLO Set OMAC address with the per-link BSS. The change remains compatible with the non-MLO mode and the older firmware. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/6b2502d0c3a53093f83ae33329e9d782ba2465b3.1720042294.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 4e3c8af98fe7..4dce03ddbfa4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1214,7 +1214,7 @@ int mt76_connac_mcu_uni_add_dev(struct mt76_phy *phy, idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; basic_req.basic.hw_bss_idx = idx; - memcpy(dev_req.tlv.omac_addr, bss_conf->vif->addr, ETH_ALEN); + memcpy(dev_req.tlv.omac_addr, bss_conf->addr, ETH_ALEN); cmd = enable ? MCU_UNI_CMD(DEV_INFO_UPDATE) : MCU_UNI_CMD(BSS_INFO_UPDATE); data = enable ? (void *)&dev_req : (void *)&basic_req; From 3878b4333602498a6af3df75e78d5fe255fa5b17 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:27:42 -0700 Subject: [PATCH 166/204] wifi: mt76: mt7925: update mt7925_mac_link_sta_[add, assoc, remove] for MLO [add, assoc, remove] the per-link STA from the corresponding to per-link BSS with the same link id. The change remains compatible with the non-MLO mode. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/2410cc73eec3849c2185b5cfa613b7e903e68abb.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/main.c | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 8b10b63bc98d..a043d93f3e1d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -728,21 +728,24 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev, struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct ieee80211_bss_conf *link_conf; + struct mt792x_bss_conf *mconf; + u8 link_id = link_sta->link_id; struct mt792x_link_sta *mlink; struct mt792x_sta *msta; int ret, idx; msta = (struct mt792x_sta *)link_sta->sta->drv_priv; - mlink = mt792x_sta_to_link(msta, link_sta->link_id); + mlink = mt792x_sta_to_link(msta, link_id); idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); if (idx < 0) return -ENOSPC; + mconf = mt792x_vif_to_link(mvif, link_id); INIT_LIST_HEAD(&mlink->wcid.poll_list); mlink->wcid.sta = 1; mlink->wcid.idx = idx; - mlink->wcid.phy_idx = mvif->bss_conf.mt76.band_idx; + mlink->wcid.phy_idx = mconf->mt76.band_idx; mlink->wcid.tx_info |= MT_WCID_TX_INFO_SET; mlink->last_txs = jiffies; @@ -753,11 +756,11 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev, mt7925_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - link_conf = mt792x_vif_to_bss_conf(vif, vif->bss_conf.link_id); + link_conf = mt792x_vif_to_bss_conf(vif, link_id); /* should update bss info before STA add */ if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) - mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, + mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, link_conf, link_sta, false); ret = mt7925_mcu_sta_update(dev, link_sta, vif, true, @@ -790,7 +793,6 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev, struct ieee80211_link_sta *link_sta) { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct ieee80211_bss_conf *link_conf; struct mt792x_link_sta *mlink; struct mt792x_sta *msta; @@ -802,9 +804,13 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev, link_conf = mt792x_vif_to_bss_conf(vif, vif->bss_conf.link_id); - if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) - mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, + if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { + struct mt792x_bss_conf *mconf; + + mconf = mt792x_link_conf_to_mconf(link_conf); + mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, link_conf, link_sta, true); + } ewma_avg_signal_init(&mlink->avg_ack_signal); @@ -830,11 +836,12 @@ static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev, { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct ieee80211_bss_conf *link_conf; + u8 link_id = link_sta->link_id; struct mt792x_link_sta *mlink; struct mt792x_sta *msta; msta = (struct mt792x_sta *)link_sta->sta->drv_priv; - mlink = mt792x_sta_to_link(msta, link_sta->link_id); + mlink = mt792x_sta_to_link(msta, link_id); mt76_connac_free_pending_tx_skbs(&dev->pm, &mlink->wcid); mt76_connac_pm_wake(&dev->mphy, &dev->pm); @@ -844,12 +851,13 @@ static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev, mt7925_mac_wtbl_update(dev, mlink->wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - link_conf = mt792x_vif_to_bss_conf(vif, vif->bss_conf.link_id); + link_conf = mt792x_vif_to_bss_conf(vif, link_id); if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - mt7925_mcu_add_bss_info(&dev->phy, - mvif->bss_conf.mt76.ctx, link_conf, + struct mt792x_bss_conf *mconf; + + mconf = mt792x_link_conf_to_mconf(link_conf); + mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, link_conf, link_sta, false); } From 882b97c16ab861d7e267262df48b32d6db4121f1 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:27:43 -0700 Subject: [PATCH 167/204] wifi: mt76: mt7925: set Tx queue parameters according to link id Configure TX queue parameters according to link id. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/84a401891b8942f66d1ffbd0a3f10866c94d1bc0.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index a043d93f3e1d..da70c203d618 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -1306,6 +1306,7 @@ mt7925_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const struct ieee80211_tx_queue_params *params) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_bss_conf *mconf = mt792x_vif_to_link(mvif, link_id); static const u8 mq_to_aci[] = { [IEEE80211_AC_VO] = 3, [IEEE80211_AC_VI] = 2, @@ -1314,7 +1315,7 @@ mt7925_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, }; /* firmware uses access class index */ - mvif->bss_conf.queue_params[mq_to_aci[queue]] = *params; + mconf->queue_params[mq_to_aci[queue]] = *params; return 0; } From 00e1ca0cad2e072df173ac6e8290109288352307 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:27:44 -0700 Subject: [PATCH 168/204] wifi: mt76: mt7925: set mt7925_mcu_sta_key_tlv according to link id configure mt7925_mcu_sta_key_tlv according to link id We created a link id field in the common structure mt76_wcid so that mt7925_mcu_sta_key_tlv can access per-link STA/BSS. Additionally, .link_id will be required when reporting the link information of Rx status to mac80211. We will submit the changes for reporting the Rx status in a separate patch. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/16d65aae010113f9be3c4e6e759b4226d396a1be.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt7925/main.c | 1 + drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 15 +++++++++++---- drivers/net/wireless/mediatek/mt76/mt792x.h | 11 +++++++++++ 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 15f83b5adac7..daf1e43e304e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -349,6 +349,7 @@ struct mt76_wcid { u8 sta:1; u8 amsdu:1; u8 phy_idx:2; + u8 link_id:4; u8 rx_check_pn; u8 rx_key_pn[IEEE80211_NUM_TIDS + 1][6]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index da70c203d618..59b1e920bb4a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -748,6 +748,7 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev, mlink->wcid.phy_idx = mconf->mt76.band_idx; mlink->wcid.tx_info |= MT_WCID_TX_INFO_SET; mlink->last_txs = jiffies; + mlink->wcid.link_id = link_sta->link_id; ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm); if (ret) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index a67d8dd6075f..ba91c8e37dff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -967,6 +967,7 @@ mt7925_mcu_sta_key_tlv(struct mt76_wcid *wcid, struct mt792x_sta *msta = container_of(mlink, struct mt792x_sta, deflink); struct sta_rec_sec_uni *sec; struct mt792x_vif *mvif = msta->vif; + struct mt792x_bss_conf *mconf = mt792x_vif_to_link(mvif, wcid->link_id); struct ieee80211_sta *sta; struct ieee80211_vif *vif; struct tlv *tlv; @@ -978,17 +979,23 @@ mt7925_mcu_sta_key_tlv(struct mt76_wcid *wcid, tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V3, sizeof(*sec)); sec = (struct sta_rec_sec_uni *)tlv; - sec->bss_idx = mvif->bss_conf.mt76.idx; + sec->bss_idx = mconf->mt76.idx; sec->is_authenticator = 0; - sec->mgmt_prot = 0; + sec->mgmt_prot = 1; /* only used in MLO mode */ sec->wlan_idx = (u8)wcid->idx; if (sta) { + struct ieee80211_link_sta *link_sta; + sec->tx_key = 1; sec->key_type = 1; - memcpy(sec->peer_addr, sta->addr, ETH_ALEN); + link_sta = mt792x_sta_to_link_sta(vif, sta, wcid->link_id); + memcpy(sec->peer_addr, link_sta->addr, ETH_ALEN); } else { - memcpy(sec->peer_addr, vif->bss_conf.bssid, ETH_ALEN); + struct ieee80211_bss_conf *link_conf; + + link_conf = mt792x_vif_to_bss_conf(vif, wcid->link_id); + memcpy(sec->peer_addr, link_conf->bssid, ETH_ALEN); } if (cmd == SET_KEY) { diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index 69eb8dac0b70..fe5a6c932705 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -273,6 +273,17 @@ mt792x_vif_to_bss_conf(struct ieee80211_vif *vif, unsigned int link_id) return link_conf_dereference_protected(vif, link_id); } +static inline struct ieee80211_link_sta * +mt792x_sta_to_link_sta(struct ieee80211_vif *vif, struct ieee80211_sta *sta, + unsigned int link_id) +{ + if (!ieee80211_vif_is_mld(vif) || + link_id >= IEEE80211_LINK_UNSPECIFIED) + return &sta->deflink; + + return link_sta_dereference_protected(sta, link_id); +} + static inline struct mt792x_dev * mt792x_hw_dev(struct ieee80211_hw *hw) { From 7cf7785a922b920a048fe8edbe9f30d4ea5b9ffe Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:27:45 -0700 Subject: [PATCH 169/204] wifi: mt76: mt7925: add mt7925_set_link_key add mt7925_set_link_key to set up the key according to the link id Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/e8cd7d37484be238a4eb9e500ef2b8aa46e43667.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/main.c | 70 ++++++++++++------- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 25 ++++--- .../wireless/mediatek/mt76/mt7925/mt7925.h | 3 +- 3 files changed, 61 insertions(+), 37 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 59b1e920bb4a..7c7452729710 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -499,31 +499,28 @@ static int mt7925_cancel_remain_on_channel(struct ieee80211_hw *hw, return mt7925_abort_roc(phy, &mvif->bss_conf); } -static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) +static int mt7925_set_link_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, int link_id) { struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_sta *msta = sta ? (struct mt792x_sta *)sta->drv_priv : &mvif->sta; - struct ieee80211_link_sta *link_sta = sta ? &sta->deflink : NULL; - struct mt76_wcid *wcid = &msta->deflink.wcid; struct ieee80211_bss_conf *link_conf; - u8 *wcid_keyidx = &wcid->hw_key_idx; + struct ieee80211_link_sta *link_sta; int idx = key->keyidx, err = 0; + struct mt792x_link_sta *mlink; + struct mt792x_bss_conf *mconf; + struct mt76_wcid *wcid; + u8 *wcid_keyidx; - link_conf = mt792x_vif_to_bss_conf(vif, vif->bss_conf.link_id); - - /* The hardware does not support per-STA RX GTK, fallback - * to software mode for these. - */ - if ((vif->type == NL80211_IFTYPE_ADHOC || - vif->type == NL80211_IFTYPE_MESH_POINT) && - (key->cipher == WLAN_CIPHER_SUITE_TKIP || - key->cipher == WLAN_CIPHER_SUITE_CCMP) && - !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) - return -EOPNOTSUPP; + link_conf = mt792x_vif_to_bss_conf(vif, link_id); + link_sta = sta ? mt792x_sta_to_link_sta(vif, sta, link_id) : NULL; + mconf = mt792x_vif_to_link(mvif, link_id); + mlink = mt792x_sta_to_link(msta, link_id); + wcid = &mlink->wcid; + wcid_keyidx = &wcid->hw_key_idx; /* fall back to sw encryption for unsupported ciphers */ switch (key->cipher) { @@ -547,13 +544,11 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return -EOPNOTSUPP; } - mt792x_mutex_acquire(dev); - - if (cmd == SET_KEY && !mvif->bss_conf.mt76.cipher) { + if (cmd == SET_KEY && !mconf->mt76.cipher) { struct mt792x_phy *phy = mt792x_hw_phy(hw); - mvif->bss_conf.mt76.cipher = mt7925_mcu_get_cipher(key->cipher); - mt7925_mcu_add_bss_info(phy, mvif->bss_conf.mt76.ctx, link_conf, + mconf->mt76.cipher = mt7925_mcu_get_cipher(key->cipher); + mt7925_mcu_add_bss_info(phy, mconf->mt76.ctx, link_conf, link_sta, true); } @@ -567,9 +562,9 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mt76_wcid_key_setup(&dev->mt76, wcid, cmd == SET_KEY ? key : NULL); - err = mt7925_mcu_add_key(&dev->mt76, vif, &msta->deflink.bip, + err = mt7925_mcu_add_key(&dev->mt76, vif, &mlink->bip, key, MCU_UNI_CMD(STA_REC_UPDATE), - &msta->deflink.wcid, cmd); + &mlink->wcid, cmd, msta); if (err) goto out; @@ -578,9 +573,32 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, key->cipher == WLAN_CIPHER_SUITE_WEP40) err = mt7925_mcu_add_key(&dev->mt76, vif, &mvif->wep_sta->deflink.bip, key, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), - &mvif->wep_sta->deflink.wcid, cmd); - + &mvif->wep_sta->deflink.wcid, cmd, msta); out: + return err; +} + +static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + int err; + + /* The hardware does not support per-STA RX GTK, fallback + * to software mode for these. + */ + if ((vif->type == NL80211_IFTYPE_ADHOC || + vif->type == NL80211_IFTYPE_MESH_POINT) && + (key->cipher == WLAN_CIPHER_SUITE_TKIP || + key->cipher == WLAN_CIPHER_SUITE_CCMP) && + !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + return -EOPNOTSUPP; + + mt792x_mutex_acquire(dev); + + err = mt7925_set_link_key(hw, cmd, vif, sta, key, vif->bss_conf.link_id); + mt792x_mutex_release(dev); return err; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index ba91c8e37dff..1db81cf4d71d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -961,13 +961,12 @@ mt7925_mcu_sta_key_tlv(struct mt76_wcid *wcid, struct mt76_connac_sta_key_conf *sta_key_conf, struct sk_buff *skb, struct ieee80211_key_conf *key, - enum set_key_cmd cmd) + enum set_key_cmd cmd, + struct mt792x_sta *msta) { - struct mt792x_link_sta *mlink = container_of(wcid, struct mt792x_link_sta, wcid); - struct mt792x_sta *msta = container_of(mlink, struct mt792x_sta, deflink); - struct sta_rec_sec_uni *sec; struct mt792x_vif *mvif = msta->vif; struct mt792x_bss_conf *mconf = mt792x_vif_to_link(mvif, wcid->link_id); + struct sta_rec_sec_uni *sec; struct ieee80211_sta *sta; struct ieee80211_vif *vif; struct tlv *tlv; @@ -990,12 +989,16 @@ mt7925_mcu_sta_key_tlv(struct mt76_wcid *wcid, sec->tx_key = 1; sec->key_type = 1; link_sta = mt792x_sta_to_link_sta(vif, sta, wcid->link_id); - memcpy(sec->peer_addr, link_sta->addr, ETH_ALEN); + + if (link_sta) + memcpy(sec->peer_addr, link_sta->addr, ETH_ALEN); } else { struct ieee80211_bss_conf *link_conf; link_conf = mt792x_vif_to_bss_conf(vif, wcid->link_id); - memcpy(sec->peer_addr, link_conf->bssid, ETH_ALEN); + + if (link_conf) + memcpy(sec->peer_addr, link_conf->bssid, ETH_ALEN); } if (cmd == SET_KEY) { @@ -1040,18 +1043,20 @@ mt7925_mcu_sta_key_tlv(struct mt76_wcid *wcid, int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, struct mt76_connac_sta_key_conf *sta_key_conf, struct ieee80211_key_conf *key, int mcu_cmd, - struct mt76_wcid *wcid, enum set_key_cmd cmd) + struct mt76_wcid *wcid, enum set_key_cmd cmd, + struct mt792x_sta *msta) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_bss_conf *mconf = mt792x_vif_to_link(mvif, wcid->link_id); struct sk_buff *skb; int ret; - skb = __mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid, + skb = __mt76_connac_mcu_alloc_sta_req(dev, &mconf->mt76, wcid, MT7925_STA_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); - ret = mt7925_mcu_sta_key_tlv(wcid, sta_key_conf, skb, key, cmd); + ret = mt7925_mcu_sta_key_tlv(wcid, sta_key_conf, skb, key, cmd, msta); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h index 8ec5a3a20202..7750049c42f2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h @@ -304,7 +304,8 @@ int mt7925_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, struct mt76_connac_sta_key_conf *sta_key_conf, struct ieee80211_key_conf *key, int mcu_cmd, - struct mt76_wcid *wcid, enum set_key_cmd cmd); + struct mt76_wcid *wcid, enum set_key_cmd cmd, + struct mt792x_sta *msta); int mt7925_mcu_set_rts_thresh(struct mt792x_phy *phy, u32 val); int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev, struct ieee80211_vif *vif, From 49681949b99a3a4bb1eae08e139752b2ffa05df2 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:27:46 -0700 Subject: [PATCH 170/204] wifi: mt76: mt7925: extend mt7925_mcu_uni_roc_event We extended the function to be able multiple pieces of information in a single event, supporting the future MLO-enabled firmware. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/4be7b34904034d521dab147883b898b5402fd29f.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 31 ++++++++++++++++--- .../wireless/mediatek/mt76/mt7925/mt7925.h | 1 + 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 1db81cf4d71d..cf4b46ebfc92 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -313,16 +313,14 @@ mt7925_mcu_roc_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) mvif->band_idx = grant->dbdcband; } -static void -mt7925_mcu_uni_roc_event(struct mt792x_dev *dev, struct sk_buff *skb) +static void mt7925_mcu_roc_handle_grant(struct mt792x_dev *dev, + struct tlv *tlv) { struct ieee80211_hw *hw = dev->mt76.hw; struct mt7925_roc_grant_tlv *grant; - struct mt7925_mcu_rxd *rxd; int duration; - rxd = (struct mt7925_mcu_rxd *)skb->data; - grant = (struct mt7925_roc_grant_tlv *)(rxd->tlv + 4); + grant = (struct mt7925_roc_grant_tlv *)tlv; /* should never happen */ WARN_ON_ONCE((le16_to_cpu(grant->tag) != UNI_EVENT_ROC_GRANT)); @@ -340,6 +338,29 @@ mt7925_mcu_uni_roc_event(struct mt792x_dev *dev, struct sk_buff *skb) jiffies + msecs_to_jiffies(duration)); } +static void +mt7925_mcu_uni_roc_event(struct mt792x_dev *dev, struct sk_buff *skb) +{ + struct tlv *tlv; + int i = 0; + + skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 4); + + while (i < skb->len) { + tlv = (struct tlv *)(skb->data + i); + + switch (le16_to_cpu(tlv->tag)) { + case UNI_EVENT_ROC_GRANT: + mt7925_mcu_roc_handle_grant(dev, tlv); + break; + case UNI_EVENT_ROC_GRANT_SUB_LINK: + break; + } + + i += le16_to_cpu(tlv->len); + } +} + static void mt7925_mcu_scan_event(struct mt792x_dev *dev, struct sk_buff *skb) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h index 7750049c42f2..b7f8802b9cd6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h @@ -41,6 +41,7 @@ enum mt7925_roc_req { enum { UNI_EVENT_ROC_GRANT = 0, + UNI_EVENT_ROC_GRANT_SUB_LINK = 4, UNI_EVENT_ROC_TAG_NUM }; From 69acd6d910b0c83842bd45c36224d4f8fe59d1d4 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:27:47 -0700 Subject: [PATCH 171/204] wifi: mt76: mt7925: add mt7925_change_vif_links Add mt7925_change_vif_links to change the valid links on an interface, supporting the MLO-enabled firmware. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/31c9de30c3a18592c8e100f909845383b66f8677.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/main.c | 130 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7925/mcu.c | 117 +++++++++++++--- .../net/wireless/mediatek/mt76/mt7925/mcu.h | 20 +++ .../wireless/mediatek/mt76/mt7925/mt7925.h | 6 + drivers/net/wireless/mediatek/mt76/mt792x.h | 5 + .../net/wireless/mediatek/mt76/mt792x_core.c | 23 +++- 6 files changed, 275 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 7c7452729710..fcf7bd1a06bc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -472,6 +472,33 @@ static int mt7925_set_roc(struct mt792x_phy *phy, return err; } +static int mt7925_set_mlo_roc(struct mt792x_phy *phy, + struct mt792x_bss_conf *mconf, + u16 sel_links) +{ + int err; + + if (WARN_ON_ONCE(test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state))) + return -EBUSY; + + phy->roc_grant = false; + + err = mt7925_mcu_set_mlo_roc(mconf, sel_links, 5, ++phy->roc_token_id); + if (err < 0) { + clear_bit(MT76_STATE_ROC, &phy->mt76->state); + goto out; + } + + if (!wait_event_timeout(phy->roc_wait, phy->roc_grant, 4 * HZ)) { + mt7925_mcu_abort_roc(phy, mconf, phy->roc_token_id); + clear_bit(MT76_STATE_ROC, &phy->mt76->state); + err = -ETIMEDOUT; + } + +out: + return err; +} + static int mt7925_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel *chan, @@ -1521,6 +1548,108 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw, mt792x_mutex_release(dev); } +static int +mt7925_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u16 old_links, u16 new_links, + struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]) +{ + struct mt792x_bss_conf *mconfs[IEEE80211_MLD_MAX_NUM_LINKS] = {}, *mconf; + struct mt792x_link_sta *mlinks[IEEE80211_MLD_MAX_NUM_LINKS] = {}, *mlink; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + unsigned long add = new_links & ~old_links; + unsigned long rem = old_links & ~new_links; + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_phy *phy = mt792x_hw_phy(hw); + struct ieee80211_bss_conf *link_conf; + unsigned int link_id; + int err; + + if (old_links == new_links) + return 0; + + mt792x_mutex_acquire(dev); + + for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) { + mconf = mt792x_vif_to_link(mvif, link_id); + mlink = mt792x_sta_to_link(&mvif->sta, link_id); + + if (!mconf || !mlink) + continue; + + if (mconf != &mvif->bss_conf) { + mt792x_mac_link_bss_remove(dev, mconf, mlink); + devm_kfree(dev->mt76.dev, mconf); + devm_kfree(dev->mt76.dev, mlink); + } + + rcu_assign_pointer(mvif->link_conf[link_id], NULL); + rcu_assign_pointer(mvif->sta.link[link_id], NULL); + } + + for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { + if (!old_links) { + mconf = &mvif->bss_conf; + mlink = &mvif->sta.deflink; + } else { + mconf = devm_kzalloc(dev->mt76.dev, sizeof(*mconf), + GFP_KERNEL); + mlink = devm_kzalloc(dev->mt76.dev, sizeof(*mlink), + GFP_KERNEL); + } + + mconfs[link_id] = mconf; + mlinks[link_id] = mlink; + mconf->link_id = link_id; + mconf->vif = mvif; + mlink->wcid.link_id = link_id; + } + + if (hweight16(mvif->valid_links) == 0) + mt792x_mac_link_bss_remove(dev, &mvif->bss_conf, + &mvif->sta.deflink); + + for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { + mconf = mconfs[link_id]; + mlink = mlinks[link_id]; + link_conf = mt792x_vif_to_bss_conf(vif, link_id); + + rcu_assign_pointer(mvif->link_conf[link_id], mconf); + rcu_assign_pointer(mvif->sta.link[link_id], mlink); + + err = mt7925_mac_link_bss_add(dev, link_conf, mlink); + if (err < 0) + goto free; + + if (mconf != &mvif->bss_conf) { + err = mt7925_set_mlo_roc(phy, &mvif->bss_conf, + vif->active_links); + if (err < 0) + goto free; + } + } + + mvif->valid_links = new_links; + + mt792x_mutex_release(dev); + + return 0; + +free: + for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { + rcu_assign_pointer(mvif->link_conf[link_id], NULL); + rcu_assign_pointer(mvif->sta.link[link_id], NULL); + + if (mconf != &mvif->bss_conf) + devm_kfree(dev->mt76.dev, mconfs[link_id]); + if (mlink != &mvif->sta.deflink) + devm_kfree(dev->mt76.dev, mlinks[link_id]); + } + + mt792x_mutex_release(dev); + + return err; +} + const struct ieee80211_ops mt7925_ops = { .tx = mt792x_tx, .start = mt7925_start, @@ -1579,6 +1708,7 @@ const struct ieee80211_ops mt7925_ops = { .mgd_complete_tx = mt7925_mgd_complete_tx, .vif_cfg_changed = mt7925_vif_cfg_changed, .link_info_changed = mt7925_link_info_changed, + .change_vif_links = mt7925_change_vif_links, }; EXPORT_SYMBOL_GPL(mt7925_ops); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index cf4b46ebfc92..d87c23911119 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -307,6 +307,9 @@ mt7925_mcu_roc_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; struct mt7925_roc_grant_tlv *grant = priv; + if (ieee80211_vif_is_mld(vif) && vif->type == NL80211_IFTYPE_STATION) + return; + if (mvif->idx != grant->bss_idx) return; @@ -1084,6 +1087,100 @@ int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true); } +int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, + int duration, u8 token_id) +{ + struct mt792x_vif *mvif = mconf->vif; + struct ieee80211_vif *vif = container_of((void *)mvif, + struct ieee80211_vif, drv_priv); + struct ieee80211_bss_conf *link_conf; + struct ieee80211_channel *chan; + const u8 ch_band[] = { + [NL80211_BAND_2GHZ] = 1, + [NL80211_BAND_5GHZ] = 2, + [NL80211_BAND_6GHZ] = 3, + }; + enum mt7925_roc_req type; + int center_ch, i = 0; + bool is_AG_band = false; + struct { + u8 id; + u8 bss_idx; + u16 tag; + struct mt792x_bss_conf *mconf; + struct ieee80211_channel *chan; + } links[2]; + + struct { + struct { + u8 rsv[4]; + } __packed hdr; + struct roc_acquire_tlv roc[2]; + } __packed req; + + if (!mconf || hweight16(vif->valid_links) < 2 || + hweight16(sel_links) != 2) + return -EPERM; + + for (i = 0; i < ARRAY_SIZE(links); i++) { + links[i].id = i ? __ffs(~BIT(mconf->link_id) & sel_links) : + mconf->link_id; + link_conf = mt792x_vif_to_bss_conf(vif, links[i].id); + if (WARN_ON_ONCE(!link_conf)) + return -EPERM; + + links[i].chan = link_conf->chanreq.oper.chan; + if (WARN_ON_ONCE(!links[i].chan)) + return -EPERM; + + links[i].mconf = mt792x_vif_to_link(mvif, links[i].id); + links[i].tag = links[i].id == mconf->link_id ? + UNI_ROC_ACQUIRE : UNI_ROC_SUB_LINK; + + is_AG_band |= links[i].chan->band == NL80211_BAND_2GHZ; + } + + if (vif->cfg.eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP) + type = is_AG_band ? MT7925_ROC_REQ_MLSR_AG : + MT7925_ROC_REQ_MLSR_AA; + else + type = MT7925_ROC_REQ_JOIN; + + for (i = 0; i < ARRAY_SIZE(links) && i < hweight16(vif->active_links); i++) { + if (WARN_ON_ONCE(!links[i].mconf || !links[i].chan)) + continue; + + chan = links[i].chan; + center_ch = ieee80211_frequency_to_channel(chan->center_freq); + req.roc[i].len = cpu_to_le16(sizeof(struct roc_acquire_tlv)); + req.roc[i].tag = cpu_to_le16(links[i].tag); + req.roc[i].tokenid = token_id; + req.roc[i].reqtype = type; + req.roc[i].maxinterval = cpu_to_le32(duration); + req.roc[i].bss_idx = links[i].mconf->mt76.idx; + req.roc[i].control_channel = chan->hw_value; + req.roc[i].bw = CMD_CBW_20MHZ; + req.roc[i].bw_from_ap = CMD_CBW_20MHZ; + req.roc[i].center_chan = center_ch; + req.roc[i].center_chan_from_ap = center_ch; + + /* STR : 0xfe indicates BAND_ALL with enabling DBDC + * EMLSR : 0xff indicates (BAND_AUTO) without DBDC + */ + req.roc[i].dbdcband = type == MT7925_ROC_REQ_JOIN ? 0xfe : 0xff; + + if (chan->hw_value < center_ch) + req.roc[i].sco = 1; /* SCA */ + else if (chan->hw_value > center_ch) + req.roc[i].sco = 3; /* SCB */ + + req.roc[i].band = ch_band[chan->band]; + } + + return mt76_mcu_send_msg(&mvif->phy->dev->mt76, MCU_UNI_CMD(ROC), + &req, sizeof(req), false); +} + int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, struct ieee80211_channel *chan, int duration, enum mt7925_roc_req type, u8 token_id) @@ -1094,25 +1191,7 @@ int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, struct { u8 rsv[4]; } __packed hdr; - struct roc_acquire_tlv { - __le16 tag; - __le16 len; - u8 bss_idx; - u8 tokenid; - u8 control_channel; - u8 sco; - u8 band; - u8 bw; - u8 center_chan; - u8 center_chan2; - u8 bw_from_ap; - u8 center_chan_from_ap; - u8 center_chan2_from_ap; - u8 reqtype; - __le32 maxinterval; - u8 dbdcband; - u8 rsv[3]; - } __packed roc; + struct roc_acquire_tlv roc; } __packed req = { .roc = { .tag = cpu_to_le16(UNI_ROC_ACQUIRE), diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h index da4e84f468d2..fefb6ab384bb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -554,6 +554,26 @@ struct mt7925_wow_pattern_tlv { u8 rsv[7]; } __packed; +struct roc_acquire_tlv { + __le16 tag; + __le16 len; + u8 bss_idx; + u8 tokenid; + u8 control_channel; + u8 sco; + u8 band; + u8 bw; + u8 center_chan; + u8 center_chan2; + u8 bw_from_ap; + u8 center_chan_from_ap; + u8 center_chan2_from_ap; + u8 reqtype; + __le32 maxinterval; + u8 dbdcband; + u8 rsv[3]; +} __packed; + static inline enum connac3_mcu_cipher_type mt7925_mcu_get_cipher(int cipher) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h index b7f8802b9cd6..dbc9e3d426e9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h @@ -30,12 +30,16 @@ enum { UNI_ROC_ACQUIRE, UNI_ROC_ABORT, + UNI_ROC_SUB_LINK = 3, UNI_ROC_NUM }; enum mt7925_roc_req { MT7925_ROC_REQ_JOIN, MT7925_ROC_REQ_ROC, + MT7925_ROC_REQ_SUB_LINK, + MT7925_ROC_REQ_MLSR_AG = 10, + MT7925_ROC_REQ_MLSR_AA, MT7925_ROC_REQ_NUM }; @@ -295,6 +299,8 @@ int mt7925_set_tx_sar_pwr(struct ieee80211_hw *hw, int mt7925_mcu_regval(struct mt792x_dev *dev, u32 regidx, u32 *val, bool set); int mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, enum environment_cap env_cap); +int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, + int duration, u8 token_id); int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, struct ieee80211_channel *chan, int duration, enum mt7925_roc_req type, u8 token_id); diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index fe5a6c932705..9a7443a8a951 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -112,6 +112,7 @@ struct mt792x_bss_conf { struct mt792x_vif *vif; struct ewma_rssi rssi; struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; + unsigned int link_id; }; struct mt792x_vif { @@ -122,6 +123,7 @@ struct mt792x_vif { struct mt792x_sta *wep_sta; struct mt792x_phy *phy; + u16 valid_links; }; struct mt792x_phy { @@ -398,6 +400,9 @@ mt792x_get_mac80211_ops(struct device *dev, int mt792x_init_wcid(struct mt792x_dev *dev); int mt792x_mcu_drv_pmctrl(struct mt792x_dev *dev); int mt792x_mcu_fw_pmctrl(struct mt792x_dev *dev); +void mt792x_mac_link_bss_remove(struct mt792x_dev *dev, + struct mt792x_bss_conf *mconf, + struct mt792x_link_sta *mlink); static inline char *mt792x_ram_name(struct mt792x_dev *dev) { diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c index 813296fad0ed..62f471b5498f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c @@ -113,14 +113,17 @@ void mt792x_stop(struct ieee80211_hw *hw, bool suspend) } EXPORT_SYMBOL_GPL(mt792x_stop); -static void mt792x_mac_link_bss_remove(struct mt792x_dev *dev, - struct ieee80211_bss_conf *link_conf, - struct mt792x_link_sta *mlink) +void mt792x_mac_link_bss_remove(struct mt792x_dev *dev, + struct mt792x_bss_conf *mconf, + struct mt792x_link_sta *mlink) { - struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); + struct ieee80211_vif *vif = container_of((void *)mconf->vif, + struct ieee80211_vif, drv_priv); + struct ieee80211_bss_conf *link_conf; int idx = mlink->wcid.idx; - mt792x_mutex_acquire(dev); + link_conf = mt792x_vif_to_bss_conf(vif, mconf->link_id); + mt76_connac_free_pending_tx_skbs(&dev->pm, &mlink->wcid); mt76_connac_mcu_uni_add_dev(&dev->mphy, link_conf, &mlink->wcid, false); @@ -128,7 +131,6 @@ static void mt792x_mac_link_bss_remove(struct mt792x_dev *dev, dev->mt76.vif_mask &= ~BIT_ULL(mconf->mt76.idx); mconf->vif->phy->omac_mask &= ~BIT_ULL(mconf->mt76.omac_idx); - mt792x_mutex_release(dev); spin_lock_bh(&dev->mt76.sta_poll_lock); if (!list_empty(&mlink->wcid.poll_list)) @@ -137,14 +139,21 @@ static void mt792x_mac_link_bss_remove(struct mt792x_dev *dev, mt76_wcid_cleanup(&dev->mt76, &mlink->wcid); } +EXPORT_SYMBOL_GPL(mt792x_mac_link_bss_remove); void mt792x_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_bss_conf *mconf; - mt792x_mac_link_bss_remove(dev, &vif->bss_conf, &mvif->sta.deflink); + mt792x_mutex_acquire(dev); + + mconf = mt792x_link_conf_to_mconf(&vif->bss_conf); + mt792x_mac_link_bss_remove(dev, mconf, &mvif->sta.deflink); + + mt792x_mutex_release(dev); } EXPORT_SYMBOL_GPL(mt792x_remove_interface); From 43aa4033eb18f46332860db061b135bd9e51be2c Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:27:48 -0700 Subject: [PATCH 172/204] wifi: mt76: mt7925: add mt7925_change_sta_links add mt7925_change_sta_links to change the valid links of a station, supporting the MLO-enabled firmware. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/eeedec88f0576315791a8b1b453464173a4addbe.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/main.c | 142 +++++++++++++++++- drivers/net/wireless/mediatek/mt76/mt792x.h | 7 + 2 files changed, 145 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index fcf7bd1a06bc..afb58a9206b0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -809,16 +809,79 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev, mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, link_conf, link_sta, false); - ret = mt7925_mcu_sta_update(dev, link_sta, vif, true, - MT76_STA_INFO_STATE_NONE); - if (ret) - return ret; + if (ieee80211_vif_is_mld(vif) && + link_sta == mlink->pri_link) { + ret = mt7925_mcu_sta_update(dev, link_sta, vif, true, + MT76_STA_INFO_STATE_NONE); + if (ret) + return ret; + } else if (ieee80211_vif_is_mld(vif) && + link_sta != mlink->pri_link) { + ret = mt7925_mcu_sta_update(dev, mlink->pri_link, vif, + true, MT76_STA_INFO_STATE_ASSOC); + if (ret) + return ret; + + ret = mt7925_mcu_sta_update(dev, link_sta, vif, true, + MT76_STA_INFO_STATE_ASSOC); + if (ret) + return ret; + } else { + ret = mt7925_mcu_sta_update(dev, link_sta, vif, true, + MT76_STA_INFO_STATE_NONE); + if (ret) + return ret; + } mt76_connac_power_save_sched(&dev->mphy, &dev->pm); return 0; } +static int +mt7925_mac_sta_add_links(struct mt792x_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, unsigned long new_links) +{ + struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + struct mt76_wcid *wcid; + unsigned int link_id; + int err = 0; + + for_each_set_bit(link_id, &new_links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct ieee80211_link_sta *link_sta; + struct mt792x_link_sta *mlink; + + if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) { + mlink = &msta->deflink; + msta->deflink_id = link_id; + } else { + mlink = devm_kzalloc(dev->mt76.dev, sizeof(*mlink), GFP_KERNEL); + if (!mlink) { + err = -ENOMEM; + break; + } + + wcid = &mlink->wcid; + ewma_signal_init(&wcid->rssi); + rcu_assign_pointer(dev->mt76.wcid[wcid->idx], wcid); + mt76_wcid_init(wcid); + ewma_avg_signal_init(&mlink->avg_ack_signal); + memset(mlink->airtime_ac, 0, + sizeof(msta->deflink.airtime_ac)); + } + + msta->valid_links |= BIT(link_id); + rcu_assign_pointer(msta->link[link_id], mlink); + mlink->sta = msta; + mlink->pri_link = &sta->deflink; + + link_sta = mt792x_sta_to_link_sta(vif, sta, link_id); + mt7925_mac_link_sta_add(&dev->mt76, vif, link_sta); + } + + return err; +} + int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { @@ -915,6 +978,48 @@ static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev, mt76_connac_power_save_sched(&dev->mphy, &dev->pm); } +static int +mt7925_mac_sta_remove_links(struct mt792x_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, unsigned long old_links) +{ + struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + struct mt76_dev *mdev = &dev->mt76; + struct mt76_wcid *wcid; + unsigned int link_id; + + for_each_set_bit(link_id, &old_links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct ieee80211_link_sta *link_sta; + struct mt792x_link_sta *mlink; + + link_sta = mt792x_sta_to_link_sta(vif, sta, link_id); + if (!link_sta) + continue; + + mlink = mt792x_sta_to_link(msta, link_id); + if (!mlink) + continue; + + mt7925_mac_link_sta_remove(&dev->mt76, vif, link_sta); + + wcid = &mlink->wcid; + rcu_assign_pointer(msta->link[link_id], NULL); + msta->valid_links &= ~BIT(link_id); + mlink->sta = NULL; + mlink->pri_link = NULL; + + if (link_sta != mlink->pri_link) { + mt76_wcid_cleanup(mdev, wcid); + mt76_wcid_mask_clear(mdev->wcid_mask, wcid->idx); + mt76_wcid_mask_clear(mdev->wcid_phy_mask, wcid->idx); + } + + if (msta->deflink_id == link_id) + msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; + } + + return 0; +} + void mt7925_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { @@ -1650,6 +1755,34 @@ mt7925_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return err; } +static int +mt7925_change_sta_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, u16 old_links, u16 new_links) +{ + unsigned long add = new_links & ~old_links; + unsigned long rem = old_links & ~new_links; + struct mt792x_dev *dev = mt792x_hw_dev(hw); + int err = 0; + + if (old_links == new_links) + return 0; + + mt792x_mutex_acquire(dev); + + err = mt7925_mac_sta_remove_links(dev, vif, sta, rem); + if (err < 0) + goto out; + + err = mt7925_mac_sta_add_links(dev, vif, sta, add); + if (err < 0) + goto out; + +out: + mt792x_mutex_release(dev); + + return err; +} + const struct ieee80211_ops mt7925_ops = { .tx = mt792x_tx, .start = mt7925_start, @@ -1709,6 +1842,7 @@ const struct ieee80211_ops mt7925_ops = { .vif_cfg_changed = mt7925_vif_cfg_changed, .link_info_changed = mt7925_link_info_changed, .change_vif_links = mt7925_change_vif_links, + .change_sta_links = mt7925_change_sta_links, }; EXPORT_SYMBOL_GPL(mt7925_ops); diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index 9a7443a8a951..af9a103dc7f4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -92,6 +92,10 @@ struct mt792x_link_sta { unsigned long last_txs; struct mt76_connac_sta_key_conf bip; + + struct mt792x_sta *sta; + + struct ieee80211_link_sta *pri_link; }; struct mt792x_sta { @@ -99,6 +103,9 @@ struct mt792x_sta { struct mt792x_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; struct mt792x_vif *vif; + + u16 valid_links; + u8 deflink_id; }; DECLARE_EWMA(rssi, 10, 8); From 61c92cc3adcfd84d76dfe3f5889206ab968055e2 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:27:49 -0700 Subject: [PATCH 173/204] wifi: mt76: mt7925: add link handling in mt7925_mac_sta_add Added link handling to mt7925_mac_sta_add to support MLD devices. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/632faefe8c82cd5609c2af00aabee15ccc9616ed.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/main.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index afb58a9206b0..042c9fe5a2d9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -885,15 +885,25 @@ mt7925_mac_sta_add_links(struct mt792x_dev *dev, struct ieee80211_vif *vif, int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + int err; msta->vif = mvif; if (vif->type == NL80211_IFTYPE_STATION) mvif->wep_sta = msta; - return mt7925_mac_link_sta_add(mdev, vif, &sta->deflink); + if (ieee80211_vif_is_mld(vif)) { + msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; + + err = mt7925_mac_sta_add_links(dev, vif, sta, sta->valid_links); + } else { + err = mt7925_mac_link_sta_add(mdev, vif, &sta->deflink); + } + + return err; } EXPORT_SYMBOL_GPL(mt7925_mac_sta_add); From 39d80be9951434755566272b401c1619eab37d4d Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:27:50 -0700 Subject: [PATCH 174/204] wifi: mt76: mt7925: add link handling in mt7925_mac_sta_remove Added link handling to mt7925_mac_sta_remove, supporting the MLO-enabled firmware. The change remains comptabile with the non-MLO mode. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/20d53511fe1f64984d893f4d3ec87cb9f87d3070.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 042c9fe5a2d9..79b43101237c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -1033,7 +1033,13 @@ mt7925_mac_sta_remove_links(struct mt792x_dev *dev, struct ieee80211_vif *vif, void mt7925_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - mt7925_mac_link_sta_remove(mdev, vif, &sta->deflink); + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + unsigned long rem; + + rem = ieee80211_vif_is_mld(vif) ? msta->valid_links : BIT(0); + + mt7925_mac_sta_remove_links(dev, vif, sta, rem); if (vif->type == NL80211_IFTYPE_STATION) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; From ebb1406813c6ea60d2d95efc69ce6d53bbe43b31 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:27:51 -0700 Subject: [PATCH 175/204] wifi: mt76: mt7925: add link handling to txwi add link handling to mt792x_tx and writing txwi. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/c0a7c0b33ea2640bcb4f13a5f79a8976b73fa8f2.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/mac.c | 12 ++++++--- .../net/wireless/mediatek/mt76/mt792x_core.c | 26 +++++++++++++++++-- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c index 2be2ab914411..6f5f2130420e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c @@ -740,8 +740,12 @@ mt7925_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, BSS_CHANGED_BEACON_ENABLED)); bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP | BSS_CHANGED_FILS_DISCOVERY)); + struct mt792x_bss_conf *mconf; + + mconf = vif ? mt792x_vif_to_link((struct mt792x_vif *)vif->drv_priv, + wcid->link_id) : NULL; + mvif = mconf ? (struct mt76_vif *)&mconf->mt76 : NULL; - mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL; if (mvif) { omac_idx = mvif->omac_idx; wmm_idx = mvif->wmm_idx; @@ -802,8 +806,10 @@ mt7925_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, txwi[5] = cpu_to_le32(val); - val = MT_TXD6_DIS_MAT | MT_TXD6_DAS | - FIELD_PREP(MT_TXD6_MSDU_CNT, 1); + val = MT_TXD6_DAS | FIELD_PREP(MT_TXD6_MSDU_CNT, 1); + if (!ieee80211_vif_is_mld(vif) || + (q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0)) + val |= MT_TXD6_DIS_MAT; txwi[6] = cpu_to_le32(val); txwi[7] = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c index 62f471b5498f..ae2ac146a7f7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c @@ -59,13 +59,17 @@ void mt792x_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; struct mt76_wcid *wcid = &dev->mt76.global_wcid; + u8 link_id; int qid; if (control->sta) { + struct mt792x_link_sta *mlink; struct mt792x_sta *sta; - + link_id = u32_get_bits(info->control.flags, + IEEE80211_TX_CTRL_MLO_LINK); sta = (struct mt792x_sta *)control->sta->drv_priv; - wcid = &sta->deflink.wcid; + mlink = mt792x_sta_to_link(sta, link_id); + wcid = &mlink->wcid; } if (vif && !control->sta) { @@ -75,6 +79,24 @@ void mt792x_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, wcid = &mvif->sta.deflink.wcid; } + if (vif && control->sta && ieee80211_vif_is_mld(vif)) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_link_sta *link_sta; + struct ieee80211_bss_conf *conf; + + link_id = wcid->link_id; + rcu_read_lock(); + conf = rcu_dereference(vif->link_conf[link_id]); + memcpy(hdr->addr2, conf->addr, ETH_ALEN); + + link_sta = rcu_dereference(control->sta->link[link_id]); + memcpy(hdr->addr1, link_sta->addr, ETH_ALEN); + + if (vif->type == NL80211_IFTYPE_STATION) + memcpy(hdr->addr3, conf->bssid, ETH_ALEN); + rcu_read_unlock(); + } + if (mt76_connac_pm_ref(mphy, &dev->pm)) { mt76_tx(mphy, control->sta, wcid, skb); mt76_connac_pm_unref(mphy, &dev->pm); From 3e758e9f777cde8e9d0106e7b36c6eca389e5856 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:27:52 -0700 Subject: [PATCH 176/204] wifi: mt76: mt7925: add link handling in mt7925_set_key add link handling in mt7925_set_key to support MLO-enabled firmware. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/164608d96ce10a40e673bc6f252189c94bc48da7.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/main.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 79b43101237c..a2cf05fdfc3a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -610,6 +610,9 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_key_conf *key) { struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_sta *msta = sta ? (struct mt792x_sta *)sta->drv_priv : + &mvif->sta; int err; /* The hardware does not support per-STA RX GTK, fallback @@ -624,7 +627,20 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mt792x_mutex_acquire(dev); - err = mt7925_set_link_key(hw, cmd, vif, sta, key, vif->bss_conf.link_id); + if (ieee80211_vif_is_mld(vif)) { + unsigned int link_id; + unsigned long add; + + add = key->link_id != -1 ? BIT(key->link_id) : msta->valid_links; + + for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { + err = mt7925_set_link_key(hw, cmd, vif, sta, key, link_id); + if (err < 0) + break; + } + } else { + err = mt7925_set_link_key(hw, cmd, vif, sta, key, vif->bss_conf.link_id); + } mt792x_mutex_release(dev); From b880cb3caa3e19610701322451b8bdb6f1f6813b Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:27:53 -0700 Subject: [PATCH 177/204] wifi: mt76: mt7925: add link handling to mt7925_change_chanctx add link handling to mt7925_change_chanctx Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/49f2a2f8230979a4e123bc1dab70a8496875cc6c.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/main.c | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index a2cf05fdfc3a..957e6bcaf9c1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -1571,13 +1571,15 @@ mt7925_change_chanctx(struct ieee80211_hw *hw, { struct mt792x_chanctx *mctx = (struct mt792x_chanctx *)ctx->drv_priv; struct mt792x_phy *phy = mt792x_hw_phy(hw); + struct mt792x_bss_conf *mconf; struct ieee80211_vif *vif; struct mt792x_vif *mvif; if (!mctx->bss_conf) return; - mvif = container_of(mctx->bss_conf, struct mt792x_vif, bss_conf); + mconf = mctx->bss_conf; + mvif = mconf->vif; vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv); mt792x_mutex_acquire(phy->dev); @@ -1585,8 +1587,24 @@ mt7925_change_chanctx(struct ieee80211_hw *hw, mt7925_mcu_set_sniffer(mvif->phy->dev, vif, true); mt7925_mcu_config_sniffer(mvif, ctx); } else { - mt7925_mcu_set_chctx(mvif->phy->mt76, &mvif->bss_conf.mt76, ctx); + if (ieee80211_vif_is_mld(vif)) { + unsigned long valid = mvif->valid_links; + u8 i; + + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + mconf = mt792x_vif_to_link(mvif, i); + if (mconf && mconf->mt76.ctx == ctx) + break; + } + + } else { + mconf = &mvif->bss_conf; + } + + if (mconf) + mt7925_mcu_set_chctx(mvif->phy->mt76, &mconf->mt76, ctx); } + mt792x_mutex_release(phy->dev); } From a03abb5045c4f47d4b70bf8b8bb1328bffbb2a74 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:27:54 -0700 Subject: [PATCH 178/204] wifi: mt76: mt7925: add link handling in the BSS_CHANGED_PS handler Added link handling in the BSS_CHANGED_PS handler. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/542ca29261af0cac007d2cb821ed36284d51c679.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/main.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 957e6bcaf9c1..938909ab8d1c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -1637,6 +1637,7 @@ static void mt7925_vif_cfg_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 changed) { + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_dev *dev = mt792x_hw_dev(hw); mt792x_mutex_acquire(dev); @@ -1653,8 +1654,17 @@ static void mt7925_vif_cfg_changed(struct ieee80211_hw *hw, mt7925_mcu_update_arp_filter(&dev->mt76, &mvif->bss_conf.mt76); } - if (changed & BSS_CHANGED_PS) - mt7925_mcu_uni_bss_ps(dev, &vif->bss_conf); + if (changed & BSS_CHANGED_PS) { + unsigned long valid = ieee80211_vif_is_mld(vif) ? + mvif->valid_links : BIT(0); + struct ieee80211_bss_conf *bss_conf; + int i; + + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + bss_conf = mt792x_vif_to_bss_conf(vif, i); + mt7925_mcu_uni_bss_ps(dev, bss_conf); + } + } mt792x_mutex_release(dev); } From acc7a4a6257fb88734125ab89fd6ca5857d77682 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:27:55 -0700 Subject: [PATCH 179/204] wifi: mt76: mt7925: add link handling in mt7925_mcu_set_beacon_filter add link handling in mt7925_mcu_set_beacon_filter Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/b814718a40ad5df6100e63d15c87ba95a318bc22.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index d87c23911119..76ead51fdef2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1818,21 +1818,32 @@ int mt7925_mcu_set_beacon_filter(struct mt792x_dev *dev, { #define MT7925_FIF_BIT_CLR BIT(1) #define MT7925_FIF_BIT_SET BIT(0) + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + unsigned long valid = ieee80211_vif_is_mld(vif) ? + mvif->valid_links : BIT(0); + struct ieee80211_bss_conf *bss_conf; int err = 0; + int i; if (enable) { - err = mt7925_mcu_uni_bss_bcnft(dev, &vif->bss_conf, true); - if (err) - return err; + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + bss_conf = mt792x_vif_to_bss_conf(vif, i); + err = mt7925_mcu_uni_bss_bcnft(dev, bss_conf, true); + if (err < 0) + return err; + } return mt7925_mcu_set_rxfilter(dev, 0, MT7925_FIF_BIT_SET, MT_WF_RFCR_DROP_OTHER_BEACON); } - err = mt7925_mcu_set_bss_pm(dev, &vif->bss_conf, false); - if (err) - return err; + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + bss_conf = mt792x_vif_to_bss_conf(vif, i); + err = mt7925_mcu_set_bss_pm(dev, bss_conf, false); + if (err) + return err; + } return mt7925_mcu_set_rxfilter(dev, 0, MT7925_FIF_BIT_CLR, From 44eb173bdd4f1775e13fce483d9e44ea8929717f Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:27:56 -0700 Subject: [PATCH 180/204] wifi: mt76: mt7925: add link handling in mt7925_txwi_free add link handling in mt7925_txwi_free. MT7996 should have the similar the logic, we try to copy from there to ensure consistency between both. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/f8084e19d388c6b0807618ac6d1bb8ac633dc8cd.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/mac.c | 54 +++++++++++++------ .../wireless/mediatek/mt76/mt7925/mt7925.h | 2 +- .../wireless/mediatek/mt76/mt7925/pci_mac.c | 2 +- 3 files changed, 41 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c index 6f5f2130420e..0cb9031e9fdd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c @@ -839,27 +839,53 @@ mt7925_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, } EXPORT_SYMBOL_GPL(mt7925_mac_write_txwi); -static void mt7925_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) +static void mt7925_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb, + struct mt76_wcid *wcid) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_link_sta *link_sta; + struct mt792x_link_sta *mlink; struct mt792x_sta *msta; + bool is_8023; u16 fc, tid; - u32 val; - if (!sta || !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he)) + link_sta = rcu_dereference(sta->link[wcid->link_id]); + if (!link_sta) return; - tid = le32_get_bits(txwi[1], MT_TXD1_TID); - if (tid >= 6) /* skip VO queue */ + if (!sta || !(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he)) return; - val = le32_to_cpu(txwi[2]); - fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 | - FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4; + tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; + is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; + + if (is_8023) { + fc = IEEE80211_FTYPE_DATA | + (sta->wme ? IEEE80211_STYPE_QOS_DATA : + IEEE80211_STYPE_DATA); + } else { + /* No need to get precise TID for Action/Management Frame, + * since it will not meet the following Frame Control + * condition anyway. + */ + + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + fc = le16_to_cpu(hdr->frame_control) & + (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE); + } + if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA))) return; msta = (struct mt792x_sta *)sta->drv_priv; - if (!test_and_set_bit(tid, &msta->deflink.wcid.ampdu_state)) + + if (sta->mlo && msta->deflink_id != IEEE80211_LINK_UNSPECIFIED) + mlink = rcu_dereference(msta->link[msta->deflink_id]); + else + mlink = &msta->deflink; + + if (!test_and_set_bit(tid, &mlink->wcid.ampdu_state)) ieee80211_start_tx_ba_session(sta, tid, 0); } @@ -1039,7 +1065,7 @@ void mt7925_mac_add_txs(struct mt792x_dev *dev, void *data) } void mt7925_txwi_free(struct mt792x_dev *dev, struct mt76_txwi_cache *t, - struct ieee80211_sta *sta, bool clear_status, + struct ieee80211_sta *sta, struct mt76_wcid *wcid, struct list_head *free_list) { struct mt76_dev *mdev = &dev->mt76; @@ -1052,10 +1078,8 @@ void mt7925_txwi_free(struct mt792x_dev *dev, struct mt76_txwi_cache *t, txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t); if (sta) { - struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; - if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE))) - mt7925_tx_check_aggr(sta, txwi); + mt7925_tx_check_aggr(sta, t->skb, wcid); wcid_idx = wcid->idx; } else { @@ -1140,7 +1164,7 @@ mt7925_mac_tx_free(struct mt792x_dev *dev, void *data, int len) if (!txwi) continue; - mt7925_txwi_free(dev, txwi, sta, 0, &free_list); + mt7925_txwi_free(dev, txwi, sta, wcid, &free_list); } } @@ -1426,7 +1450,7 @@ void mt7925_usb_sdio_tx_complete_skb(struct mt76_dev *mdev, sta = wcid_to_sta(wcid); if (sta && likely(e->skb->protocol != cpu_to_be16(ETH_P_PAE))) - mt7925_tx_check_aggr(sta, txwi); + mt76_connac2_tx_check_aggr(sta, txwi); skb_pull(e->skb, headroom); mt76_tx_complete_skb(mdev, e->wcid, e->skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h index dbc9e3d426e9..bcf8541fa31d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h @@ -260,7 +260,7 @@ void mt7925_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, struct ieee80211_key_conf *key, int pid, enum mt76_txq_id qid, u32 changed); void mt7925_txwi_free(struct mt792x_dev *dev, struct mt76_txwi_cache *t, - struct ieee80211_sta *sta, bool clear_status, + struct ieee80211_sta *sta, struct mt76_wcid *wcid, struct list_head *free_list); int mt7925_mcu_parse_response(struct mt76_dev *mdev, int cmd, struct sk_buff *skb, int seq); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c index ef631a68005d..faedbf766d1a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c @@ -60,7 +60,7 @@ void mt7925_tx_token_put(struct mt792x_dev *dev) spin_lock_bh(&dev->mt76.token_lock); idr_for_each_entry(&dev->mt76.token, txwi, id) { - mt7925_txwi_free(dev, txwi, NULL, false, NULL); + mt7925_txwi_free(dev, txwi, NULL, NULL, NULL); dev->mt76.token_count--; } spin_unlock_bh(&dev->mt76.token_lock); From 9f89f05bef1a57352e908910e0065b15d542038c Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:27:57 -0700 Subject: [PATCH 181/204] wifi: mt76: mt7925: add link handling in mt7925_mac_sta_assoc add links handling in mt7925_mac_sta_assoc Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/0ddf1834783b111d626b05d298478f520d7c0caa.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/main.c | 104 +++++++++++++++++- drivers/net/wireless/mediatek/mt76/mt792x.h | 1 + 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 938909ab8d1c..68a615bbec76 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -387,6 +387,7 @@ mt7925_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) mvif->phy = phy; mvif->bss_conf.vif = mvif; mvif->sta.vif = mvif; + mvif->deflink_id = IEEE80211_LINK_UNSPECIFIED; ret = mt7925_mac_link_bss_add(dev, &vif->bss_conf, &mvif->sta.deflink); if (ret < 0) @@ -923,6 +924,89 @@ int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(mt7925_mac_sta_add); +static u16 +mt7925_mac_select_links(struct mt76_dev *mdev, struct ieee80211_vif *vif) +{ + unsigned long usable_links = ieee80211_vif_usable_links(vif); + struct { + u8 link_id; + enum nl80211_band band; + } data[IEEE80211_MLD_MAX_NUM_LINKS]; + u8 link_id, i, j, n_data = 0; + u16 sel_links = 0; + + if (!ieee80211_vif_is_mld(vif)) + return 0; + + if (vif->active_links == usable_links) + return vif->active_links; + + rcu_read_lock(); + for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct ieee80211_bss_conf *link_conf = + rcu_dereference(vif->link_conf[link_id]); + + if (WARN_ON_ONCE(!link_conf)) + continue; + + data[n_data].link_id = link_id; + data[n_data].band = link_conf->chanreq.oper.chan->band; + n_data++; + } + rcu_read_unlock(); + + for (i = 0; i < n_data; i++) { + if (!(BIT(data[i].link_id) & vif->active_links)) + continue; + + sel_links = BIT(data[i].link_id); + + for (j = 0; j < n_data; j++) { + if (data[i].band != data[j].band) { + sel_links |= BIT(data[j].link_id); + break; + } + } + + break; + } + + return sel_links; +} + +static void +mt7925_mac_set_links(struct mt76_dev *mdev, struct ieee80211_vif *vif) +{ + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct ieee80211_bss_conf *link_conf = + mt792x_vif_to_bss_conf(vif, mvif->deflink_id); + struct cfg80211_chan_def *chandef = &link_conf->chanreq.oper; + enum nl80211_band band = chandef->chan->band, secondary_band; + + u16 sel_links = mt7925_mac_select_links(mdev, vif); + u8 secondary_link_id = __ffs(~BIT(mvif->deflink_id) & sel_links); + + if (!ieee80211_vif_is_mld(vif) || hweight16(sel_links) < 2) + return; + + link_conf = mt792x_vif_to_bss_conf(vif, secondary_link_id); + secondary_band = link_conf->chanreq.oper.chan->band; + + if (band == NL80211_BAND_2GHZ || + (band == NL80211_BAND_5GHZ && secondary_band == NL80211_BAND_6GHZ)) { + mt7925_abort_roc(mvif->phy, &mvif->bss_conf); + + mt792x_mutex_acquire(dev); + + mt7925_set_mlo_roc(mvif->phy, &mvif->bss_conf, sel_links); + + mt792x_mutex_release(dev); + } + + ieee80211_set_active_links_async(vif, sel_links); +} + static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_link_sta *link_sta) @@ -937,7 +1021,11 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev, mt792x_mutex_acquire(dev); - link_conf = mt792x_vif_to_bss_conf(vif, vif->bss_conf.link_id); + if (ieee80211_vif_is_mld(vif)) { + link_conf = mt792x_vif_to_bss_conf(vif, msta->deflink_id); + } else { + link_conf = mt792x_vif_to_bss_conf(vif, vif->bss_conf.link_id); + } if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { struct mt792x_bss_conf *mconf; @@ -961,7 +1049,18 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev, void mt7925_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - mt7925_mac_link_sta_assoc(mdev, vif, &sta->deflink); + if (ieee80211_vif_is_mld(vif)) { + struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + struct ieee80211_link_sta *link_sta; + + link_sta = mt792x_sta_to_link_sta(vif, sta, msta->deflink_id); + + mt7925_mac_set_links(mdev, vif); + + mt7925_mac_link_sta_assoc(mdev, vif, link_sta); + } else { + mt7925_mac_link_sta_assoc(mdev, vif, &sta->deflink); + } } EXPORT_SYMBOL_GPL(mt7925_mac_sta_assoc); @@ -1753,6 +1852,7 @@ mt7925_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { if (!old_links) { + mvif->deflink_id = link_id; mconf = &mvif->bss_conf; mlink = &mvif->sta.deflink; } else { diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index af9a103dc7f4..5ede24116748 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -131,6 +131,7 @@ struct mt792x_vif { struct mt792x_phy *phy; u16 valid_links; + u8 deflink_id; }; struct mt792x_phy { From b859ad65309a5f1654e8b284de582831fc88e2d8 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:27:58 -0700 Subject: [PATCH 182/204] wifi: mt76: mt7925: add link handling in mt7925_sta_set_decap_offload add link handling in mt7925_sta_set_decap_offload Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/df2524e3a63a93699bde441e4ab70a70bbac53ef.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/main.c | 21 ++++++++++++---- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 24 ++++++++++++++----- .../wireless/mediatek/mt76/mt7925/mt7925.h | 3 ++- 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 68a615bbec76..0b61695c9b65 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -1464,16 +1464,27 @@ static void mt7925_sta_set_decap_offload(struct ieee80211_hw *hw, bool enabled) { struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_dev *dev = mt792x_hw_dev(hw); + unsigned long valid = mvif->valid_links; + u8 i; mt792x_mutex_acquire(dev); - if (enabled) - set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->deflink.wcid.flags); - else - clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->deflink.wcid.flags); + valid = ieee80211_vif_is_mld(vif) ? mvif->valid_links : BIT(0); - mt7925_mcu_wtbl_update_hdr_trans(dev, vif, sta); + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + struct mt792x_link_sta *mlink; + + mlink = mt792x_sta_to_link(msta, i); + + if (enabled) + set_bit(MT_WCID_FLAG_HDR_TRANS, &mlink->wcid.flags); + else + clear_bit(MT_WCID_FLAG_HDR_TRANS, &mlink->wcid.flags); + + mt7925_mcu_wtbl_update_hdr_trans(dev, vif, sta, i); + } mt792x_mutex_release(dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 76ead51fdef2..20b118cd450c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -887,10 +887,15 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb, else hdr_trans->from_ds = true; - if (link_sta) - wcid = (struct mt76_wcid *)link_sta->sta->drv_priv; - else + if (link_sta) { + struct mt792x_sta *msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + struct mt792x_link_sta *mlink; + + mlink = mt792x_sta_to_link(msta, link_sta->link_id); + wcid = &mlink->wcid; + } else { wcid = &mvif->sta.deflink.wcid; + } if (!wcid) return; @@ -904,17 +909,24 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb, int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct ieee80211_sta *sta, + int link_id) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct ieee80211_link_sta *link_sta = sta ? &sta->deflink : NULL; + struct mt792x_link_sta *mlink; + struct mt792x_bss_conf *mconf; struct mt792x_sta *msta; struct sk_buff *skb; msta = sta ? (struct mt792x_sta *)sta->drv_priv : &mvif->sta; - skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->bss_conf.mt76, - &msta->deflink.wcid, + mlink = mt792x_sta_to_link(msta, link_id); + link_sta = mt792x_sta_to_link_sta(vif, sta, link_id); + mconf = mt792x_vif_to_link(mvif, link_id); + + skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76, + &mlink->wcid, MT7925_STA_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h index bcf8541fa31d..1ae66629e39f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h @@ -316,6 +316,7 @@ int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, int mt7925_mcu_set_rts_thresh(struct mt792x_phy *phy, u32 val); int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); + struct ieee80211_sta *sta, + int link_id); #endif From 14061994184df6bb89cba31657ee1db24480e92a Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:27:59 -0700 Subject: [PATCH 183/204] wifi: mt76: mt7925: add link handling in mt7925_vif_connect_iter add link handling in mt7925_vif_connect_iter Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/c8d66043a4d31801249d53dd23f695c28a97a933.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c index 0cb9031e9fdd..cf36750cf709 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c @@ -1267,15 +1267,23 @@ mt7925_vif_connect_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + unsigned long valid = ieee80211_vif_is_mld(vif) ? + mvif->valid_links : BIT(0); struct mt792x_dev *dev = mvif->phy->dev; struct ieee80211_hw *hw = mt76_hw(dev); + struct ieee80211_bss_conf *bss_conf; + int i; if (vif->type == NL80211_IFTYPE_STATION) ieee80211_disconnect(vif, true); - mt76_connac_mcu_uni_add_dev(&dev->mphy, &vif->bss_conf, - &mvif->sta.deflink.wcid, true); - mt7925_mcu_set_tx(dev, &vif->bss_conf); + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + bss_conf = mt792x_vif_to_bss_conf(vif, i); + + mt76_connac_mcu_uni_add_dev(&dev->mphy, bss_conf, + &mvif->sta.deflink.wcid, true); + mt7925_mcu_set_tx(dev, bss_conf); + } if (vif->type == NL80211_IFTYPE_AP) { mt76_connac_mcu_uni_add_bss(dev->phy.mt76, vif, &mvif->sta.deflink.wcid, From 147324292979fdd0e612199f898db7162ae083c6 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:28:00 -0700 Subject: [PATCH 184/204] wifi: mt76: mt7925: add link handling in the BSS_CHANGED_ARP_FILTER handler add link handling in the BSS_CHANGED_ARP_FILTER handler. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/6e26e2ce253630ab29702693a7822f9961de6a18.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/main.c | 16 ++++++++-------- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 8 +++++--- drivers/net/wireless/mediatek/mt76/mt7925/mcu.h | 2 +- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 0b61695c9b65..2329e1a19781 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -1749,6 +1749,10 @@ static void mt7925_vif_cfg_changed(struct ieee80211_hw *hw, { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_dev *dev = mt792x_hw_dev(hw); + unsigned long valid = ieee80211_vif_is_mld(vif) ? + mvif->valid_links : BIT(0); + struct ieee80211_bss_conf *bss_conf; + int i; mt792x_mutex_acquire(dev); @@ -1759,17 +1763,13 @@ static void mt7925_vif_cfg_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ARP_FILTER) { - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - - mt7925_mcu_update_arp_filter(&dev->mt76, &mvif->bss_conf.mt76); + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + bss_conf = mt792x_vif_to_bss_conf(vif, i); + mt7925_mcu_update_arp_filter(&dev->mt76, bss_conf); + } } if (changed & BSS_CHANGED_PS) { - unsigned long valid = ieee80211_vif_is_mld(vif) ? - mvif->valid_links : BIT(0); - struct ieee80211_bss_conf *bss_conf; - int i; - for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { bss_conf = mt792x_vif_to_bss_conf(vif, i); mt7925_mcu_uni_bss_ps(dev, bss_conf); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 20b118cd450c..2dbe9362efcf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -121,10 +121,12 @@ int mt7925_mcu_regval(struct mt792x_dev *dev, u32 regidx, u32 *val, bool set) EXPORT_SYMBOL_GPL(mt7925_mcu_regval); int mt7925_mcu_update_arp_filter(struct mt76_dev *dev, - struct mt76_vif *vif) + struct ieee80211_bss_conf *link_conf) { - struct ieee80211_vif *mvif = container_of((void *)vif, struct ieee80211_vif, + struct ieee80211_vif *mvif = container_of((void *)link_conf->vif, + struct ieee80211_vif, drv_priv); + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); struct sk_buff *skb; int i, len = min_t(int, mvif->cfg.arp_addr_cnt, IEEE80211_BSS_ARP_ADDR_LIST_LEN); @@ -136,7 +138,7 @@ int mt7925_mcu_update_arp_filter(struct mt76_dev *dev, struct mt7925_arpns_tlv arp; } req = { .hdr = { - .bss_idx = vif->idx, + .bss_idx = mconf->mt76.idx, }, .arp = { .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP), diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h index fefb6ab384bb..7fb46cad9157 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -626,5 +626,5 @@ int mt7925_mcu_set_chctx(struct mt76_phy *phy, struct mt76_vif *mvif, struct ieee80211_chanctx_conf *ctx); int mt7925_mcu_set_rate_txpower(struct mt76_phy *phy); int mt7925_mcu_update_arp_filter(struct mt76_dev *dev, - struct mt76_vif *vif); + struct ieee80211_bss_conf *link_conf); #endif From 9f8f587cab696e68804e2c4460f4ac1f1a686c8b Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:28:01 -0700 Subject: [PATCH 185/204] wifi: mt76: mt7925: add link handling in the mt7925_ipv6_addr_change add link handling in the mt7925_ipv6_addr_change Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/ed429b1896cc10c8db25dc2ade3e59bec78d7131.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/main.c | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 2329e1a19781..bb8a89e08d7d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -1490,12 +1490,12 @@ static void mt7925_sta_set_decap_offload(struct ieee80211_hw *hw, } #if IS_ENABLED(CONFIG_IPV6) -static void mt7925_ipv6_addr_change(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct inet6_dev *idev) +static void __mt7925_ipv6_addr_change(struct ieee80211_hw *hw, + struct ieee80211_bss_conf *link_conf, + struct inet6_dev *idev) { - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - struct mt792x_dev *dev = mvif->phy->dev; + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); + struct mt792x_dev *dev = mt792x_hw_dev(hw); struct inet6_ifaddr *ifa; struct sk_buff *skb; u8 idx = 0; @@ -1509,7 +1509,7 @@ static void mt7925_ipv6_addr_change(struct ieee80211_hw *hw, struct in6_addr ns_addrs[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; } req_hdr = { .hdr = { - .bss_idx = mvif->bss_conf.mt76.idx, + .bss_idx = mconf->mt76.idx, }, .arpns = { .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ND), @@ -1544,6 +1544,23 @@ static void mt7925_ipv6_addr_change(struct ieee80211_hw *hw, ieee80211_queue_work(dev->mt76.hw, &dev->ipv6_ns_work); } + +static void mt7925_ipv6_addr_change(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct inet6_dev *idev) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + unsigned long valid = ieee80211_vif_is_mld(vif) ? + mvif->valid_links : BIT(0); + struct ieee80211_bss_conf *bss_conf; + int i; + + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + bss_conf = mt792x_vif_to_bss_conf(vif, i); + __mt7925_ipv6_addr_change(hw, bss_conf, idev); + } +} + #endif int mt7925_set_tx_sar_pwr(struct ieee80211_hw *hw, From 3fa01f055c41d20ec11485cd12fa0f82ee5557c1 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:28:02 -0700 Subject: [PATCH 186/204] wifi: mt76: mt7925: update rate index according to link id Update rate index according to link id. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/e0bbc0932edbd9225fe7b7736693c137cf433a52.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/main.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index bb8a89e08d7d..3d23a87e9a74 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -1801,9 +1801,12 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *info, u64 changed) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_phy *phy = mt792x_hw_phy(hw); struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_bss_conf *mconf; + + mconf = mt792x_vif_to_link(mvif, info->link_id); mt792x_mutex_acquire(dev); @@ -1817,16 +1820,16 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_MCAST_RATE) - mvif->mcast_rates_idx = + mconf->mt76.mcast_rates_idx = mt7925_get_rates_table(hw, vif, false, true); if (changed & BSS_CHANGED_BASIC_RATES) - mvif->basic_rates_idx = + mconf->mt76.basic_rates_idx = mt7925_get_rates_table(hw, vif, false, false); if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) { - mvif->beacon_rates_idx = + mconf->mt76.beacon_rates_idx = mt7925_get_rates_table(hw, vif, true, false); mt7925_mcu_uni_add_beacon_offload(dev, hw, vif, From 4f0f33d2747f207ba552dd065042c2d7f3063402 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:28:03 -0700 Subject: [PATCH 187/204] wifi: mt76: mt7925: report link information in rx status report link information in rx status Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/c7cdc17d94375a76802a5c4a825ea3e51cdb53af.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 5 +++++ drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt7925/main.c | 2 ++ 3 files changed, 8 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index e8ba2e4e8484..bb291fe314fb 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1125,6 +1125,11 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, memcpy(status->chain_signal, mstat.chain_signal, sizeof(mstat.chain_signal)); + if (mstat.wcid) { + status->link_valid = mstat.wcid->link_valid; + status->link_id = mstat.wcid->link_id; + } + *sta = wcid_to_sta(mstat.wcid); *hw = mt76_phy_hw(dev, mstat.phy_idx); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index daf1e43e304e..e1d30326f5af 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -350,6 +350,7 @@ struct mt76_wcid { u8 amsdu:1; u8 phy_idx:2; u8 link_id:4; + bool link_valid; u8 rx_check_pn; u8 rx_key_pn[IEEE80211_NUM_TIDS + 1][6]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 3d23a87e9a74..be0a336f601e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -811,6 +811,7 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev, mlink->wcid.tx_info |= MT_WCID_TX_INFO_SET; mlink->last_txs = jiffies; mlink->wcid.link_id = link_sta->link_id; + mlink->wcid.link_valid = !!link_sta->sta->valid_links; ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm); if (ret) @@ -1898,6 +1899,7 @@ mt7925_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mconf->link_id = link_id; mconf->vif = mvif; mlink->wcid.link_id = link_id; + mlink->wcid.link_valid = !!vif->valid_links; } if (hweight16(mvif->valid_links) == 0) From b1d21403c0cfe712ce7ad4020f40c5ca6a013ec5 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:28:04 -0700 Subject: [PATCH 188/204] wifi: mt76: add def_wcid to struct mt76_wcid add def_wcid to struct mt76_wcid to allow per-link wcid to retrieve the struct ieee80211_sta structure. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/d5188ca633666eaad7e90a8061d1a0585487e128.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 5 +++++ drivers/net/wireless/mediatek/mt76/mt7925/main.c | 2 ++ 2 files changed, 7 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index e1d30326f5af..5f8773364d51 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -368,6 +368,8 @@ struct mt76_wcid { struct mt76_sta_stats stats; struct list_head poll_list; + + struct mt76_wcid *def_wcid; }; struct mt76_txq { @@ -1258,6 +1260,9 @@ wcid_to_sta(struct mt76_wcid *wcid) if (!wcid || !wcid->sta) return NULL; + if (wcid->def_wcid) + ptr = wcid->def_wcid; + return container_of(ptr, struct ieee80211_sta, drv_priv); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index be0a336f601e..c25822e3a943 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -892,6 +892,7 @@ mt7925_mac_sta_add_links(struct mt792x_dev *dev, struct ieee80211_vif *vif, rcu_assign_pointer(msta->link[link_id], mlink); mlink->sta = msta; mlink->pri_link = &sta->deflink; + mlink->wcid.def_wcid = &msta->deflink.wcid; link_sta = mt792x_sta_to_link_sta(vif, sta, link_id); mt7925_mac_link_sta_add(&dev->mt76, vif, link_sta); @@ -1900,6 +1901,7 @@ mt7925_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mconf->vif = mvif; mlink->wcid.link_id = link_id; mlink->wcid.link_valid = !!vif->valid_links; + mlink->wcid.def_wcid = &mvif->sta.deflink.wcid; } if (hweight16(mvif->valid_links) == 0) From 621e9e22b8d031da5c026b913de903f2e2180d79 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:28:05 -0700 Subject: [PATCH 189/204] wifi: mt76: mt7925: add mt7925_[assign,unassign]_vif_chanctx add mt7925_[assign,unassign]_vif_chanctx to assign and unassign chanctx to the specific link configuration. If the chctx is not pass in the parameter, we will look up the channel information from link_conf->chanreq.oper. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/15261879a16cb12674d6dea7703410baa6883799.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/main.c | 75 ++++++++++++++++++- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 17 +++-- .../net/wireless/mediatek/mt76/mt7925/mcu.h | 1 + 3 files changed, 82 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index c25822e3a943..0627ef208641 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -1730,8 +1730,13 @@ mt7925_change_chanctx(struct ieee80211_hw *hw, mconf = &mvif->bss_conf; } - if (mconf) - mt7925_mcu_set_chctx(mvif->phy->mt76, &mconf->mt76, ctx); + if (mconf) { + struct ieee80211_bss_conf *link_conf; + + link_conf = mt792x_vif_to_bss_conf(vif, mconf->link_id); + mt7925_mcu_set_chctx(mvif->phy->mt76, &mconf->mt76, + link_conf, ctx); + } } mt792x_mutex_release(phy->dev); @@ -1978,6 +1983,68 @@ mt7925_change_sta_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return err; } +static int mt7925_assign_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_chanctx_conf *ctx) +{ + struct mt792x_chanctx *mctx = (struct mt792x_chanctx *)ctx->drv_priv; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct ieee80211_bss_conf *pri_link_conf; + struct mt792x_bss_conf *mconf; + + mutex_lock(&dev->mt76.mutex); + + if (ieee80211_vif_is_mld(vif)) { + mconf = mt792x_vif_to_link(mvif, link_conf->link_id); + pri_link_conf = mt792x_vif_to_bss_conf(vif, mvif->deflink_id); + + if (vif->type == NL80211_IFTYPE_STATION && + mconf == &mvif->bss_conf) + mt7925_mcu_add_bss_info(&dev->phy, NULL, pri_link_conf, + NULL, true); + } else { + mconf = &mvif->bss_conf; + } + + mconf->mt76.ctx = ctx; + mctx->bss_conf = mconf; + mutex_unlock(&dev->mt76.mutex); + + return 0; +} + +static void mt7925_unassign_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_chanctx_conf *ctx) +{ + struct mt792x_chanctx *mctx = (struct mt792x_chanctx *)ctx->drv_priv; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct ieee80211_bss_conf *pri_link_conf; + struct mt792x_bss_conf *mconf; + + mutex_lock(&dev->mt76.mutex); + + if (ieee80211_vif_is_mld(vif)) { + mconf = mt792x_vif_to_link(mvif, link_conf->link_id); + pri_link_conf = mt792x_vif_to_bss_conf(vif, mvif->deflink_id); + + if (vif->type == NL80211_IFTYPE_STATION && + mconf == &mvif->bss_conf) + mt7925_mcu_add_bss_info(&dev->phy, NULL, pri_link_conf, + NULL, false); + } else { + mconf = &mvif->bss_conf; + } + + mctx->bss_conf = NULL; + mconf->mt76.ctx = NULL; + mutex_unlock(&dev->mt76.mutex); +} + const struct ieee80211_ops mt7925_ops = { .tx = mt792x_tx, .start = mt7925_start, @@ -2030,8 +2097,8 @@ const struct ieee80211_ops mt7925_ops = { .add_chanctx = mt7925_add_chanctx, .remove_chanctx = mt7925_remove_chanctx, .change_chanctx = mt7925_change_chanctx, - .assign_vif_chanctx = mt792x_assign_vif_chanctx, - .unassign_vif_chanctx = mt792x_unassign_vif_chanctx, + .assign_vif_chanctx = mt7925_assign_vif_chanctx, + .unassign_vif_chanctx = mt7925_unassign_vif_chanctx, .mgd_prepare_tx = mt7925_mgd_prepare_tx, .mgd_complete_tx = mt7925_mgd_complete_tx, .vif_cfg_changed = mt7925_vif_cfg_changed, diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 2dbe9362efcf..da3192bd82cd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2083,9 +2083,11 @@ mt7925_mcu_uni_add_beacon_offload(struct mt792x_dev *dev, static void mt7925_mcu_bss_rlm_tlv(struct sk_buff *skb, struct mt76_phy *phy, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { - struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &phy->chandef; + struct cfg80211_chan_def *chandef = ctx ? &ctx->def : + &link_conf->chanreq.oper; int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2; enum nl80211_band band = chandef->chan->band; struct bss_rlm_tlv *req; @@ -2152,6 +2154,7 @@ __mt7925_mcu_alloc_bss_req(struct mt76_dev *dev, struct mt76_vif *mvif, int len) } int mt7925_mcu_set_chctx(struct mt76_phy *phy, struct mt76_vif *mvif, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { struct sk_buff *skb; @@ -2161,7 +2164,7 @@ int mt7925_mcu_set_chctx(struct mt76_phy *phy, struct mt76_vif *mvif, if (IS_ERR(skb)) return PTR_ERR(skb); - mt7925_mcu_bss_rlm_tlv(skb, phy, ctx); + mt7925_mcu_bss_rlm_tlv(skb, phy, link_conf, ctx); return mt76_mcu_skb_send_msg(phy->dev, skb, MCU_UNI_CMD(BSS_INFO_UPDATE), true); @@ -2223,7 +2226,8 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, { struct ieee80211_vif *vif = link_conf->vif; struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); - struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &phy->chandef; + struct cfg80211_chan_def *chandef = ctx ? &ctx->def : + &link_conf->chanreq.oper; enum nl80211_band band = chandef->chan->band; struct mt76_connac_bss_basic_tlv *basic_req; struct mt792x_link_sta *mlink; @@ -2348,7 +2352,8 @@ mt7925_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt792x_phy *phy, struct ieee80211_chanctx_conf *ctx, struct ieee80211_bss_conf *link_conf) { - struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &phy->mt76->chandef; + struct cfg80211_chan_def *chandef = ctx ? &ctx->def : + &link_conf->chanreq.oper; struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); enum nl80211_band band = chandef->chan->band; struct mt76_vif *mvif = &mconf->mt76; @@ -2488,8 +2493,6 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, int enable) { struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv; - struct mt792x_bss_conf *mconf = mt792x_vif_to_link(mvif, - link_conf->link_id); struct mt792x_dev *dev = phy->dev; struct sk_buff *skb; @@ -2513,7 +2516,7 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, mt7925_mcu_bss_color_tlv(skb, link_conf, enable); } - mt7925_mcu_bss_rlm_tlv(skb, phy->mt76, mconf->mt76.ctx); + mt7925_mcu_bss_rlm_tlv(skb, phy->mt76, link_conf, ctx); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_UNI_CMD(BSS_INFO_UPDATE), true); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h index 7fb46cad9157..6ae5286385d9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -623,6 +623,7 @@ int mt7925_mcu_set_deep_sleep(struct mt792x_dev *dev, bool enable); int mt7925_mcu_set_channel_domain(struct mt76_phy *phy); int mt7925_mcu_set_radio_en(struct mt792x_phy *phy, bool enable); int mt7925_mcu_set_chctx(struct mt76_phy *phy, struct mt76_vif *mvif, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx); int mt7925_mcu_set_rate_txpower(struct mt76_phy *phy); int mt7925_mcu_update_arp_filter(struct mt76_dev *dev, From 254f777a9e842e2325f2ee8ba3d0cf45625c71b7 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:28:06 -0700 Subject: [PATCH 190/204] wifi: mt76: mt7925: update mt7925_mcu_sta_mld_tlv for MLO Update mt7925_mcu_sta_mld_tlv for the MLO-enabled firmware. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/25ea3ffd3875083577ab440ec63f3dcd9dc233f4.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index da3192bd82cd..59ae1fbc238b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1742,19 +1742,34 @@ static void mt7925_mcu_sta_mld_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + unsigned long valid = mvif->valid_links; + struct mt792x_bss_conf *mconf; + struct mt792x_link_sta *mlink; struct sta_rec_mld *mld; struct tlv *tlv; + int i, cnt = 0; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MLD, sizeof(*mld)); mld = (struct sta_rec_mld *)tlv; - memcpy(mld->mac_addr, vif->addr, ETH_ALEN); - mld->primary_id = cpu_to_le16(wcid->idx); - mld->wlan_id = cpu_to_le16(wcid->idx); + memcpy(mld->mac_addr, sta->addr, ETH_ALEN); + mld->primary_id = cpu_to_le16(msta->deflink.wcid.idx); + mld->wlan_id = cpu_to_le16(msta->deflink.wcid.idx); + mld->link_num = min_t(u8, hweight16(mvif->valid_links), 2); - /* TODO: 0 means deflink only, add secondary link(1) later */ - mld->link_num = !!(hweight8(vif->active_links) > 1); - WARN_ON_ONCE(mld->link_num); + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + if (cnt == mld->link_num) + break; + + mconf = mt792x_vif_to_link(mvif, i); + mlink = mt792x_sta_to_link(msta, i); + mld->link[cnt].wlan_id = cpu_to_le16(mlink->wcid.idx); + mld->link[cnt++].bss_idx = mconf->mt76.idx; + + if (mlink != &msta->deflink) + mld->secondary_id = cpu_to_le16(mlink->wcid.idx); + } } static int From f8a80a4eed42499f5b923c60d6a51d00e3b6b7d4 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:28:07 -0700 Subject: [PATCH 191/204] wifi: mt76: mt7925: update mt7925_mcu_bss_mld_tlv for MLO update mt7925_mcu_bss_mld_tlv for the MLO-enabled firmware, the change remains compatible with the non-MLO mode and the older firmware. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/2d89b93bcfd92e7c6987aaa0a3c4637e605ac154.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 22 +++++++++++-------- .../net/wireless/mediatek/mt76/mt7925/mcu.h | 5 ++++- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 59ae1fbc238b..7a0225127135 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2393,24 +2393,29 @@ mt7925_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt792x_phy *phy, static void mt7925_mcu_bss_mld_tlv(struct sk_buff *skb, - struct ieee80211_bss_conf *link_conf, - struct ieee80211_link_sta *link_sta) + struct ieee80211_bss_conf *link_conf) { struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); - bool is_mld = ieee80211_vif_is_mld(link_conf->vif); + struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv; struct bss_mld_tlv *mld; struct tlv *tlv; + bool is_mld; + + is_mld = ieee80211_vif_is_mld(link_conf->vif) || + (hweight16(mvif->valid_links) > 1); tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_MLD, sizeof(*mld)); mld = (struct bss_mld_tlv *)tlv; - mld->link_id = link_sta ? (is_mld ? link_conf->link_id : 0) : 0xff; - mld->group_mld_id = is_mld ? mconf->mt76.idx : 0xff; + mld->link_id = is_mld ? link_conf->link_id : 0xff; + /* apply the index of the primary link */ + mld->group_mld_id = is_mld ? mvif->bss_conf.mt76.idx : 0xff; mld->own_mld_id = mconf->mt76.idx + 32; mld->remap_idx = 0xff; + mld->eml_enable = !!(link_conf->vif->cfg.eml_cap & + IEEE80211_EML_CAP_EMLSR_SUPP); - if (link_sta) - memcpy(mld->mac_addr, link_sta->addr, ETH_ALEN); + memcpy(mld->mac_addr, link_conf->addr, ETH_ALEN); } static void @@ -2520,10 +2525,9 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, mt7925_mcu_bss_basic_tlv(skb, link_conf, link_sta, ctx, phy->mt76, mvif->sta.deflink.wcid.idx, enable); mt7925_mcu_bss_sec_tlv(skb, link_conf); - mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, link_conf); mt7925_mcu_bss_qos_tlv(skb, link_conf); - mt7925_mcu_bss_mld_tlv(skb, link_conf, link_sta); + mt7925_mcu_bss_mld_tlv(skb, link_conf); mt7925_mcu_bss_ifs_tlv(skb, link_conf); if (link_conf->he_support) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h index 6ae5286385d9..7b0c6937f918 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -366,7 +366,10 @@ struct bss_mld_tlv { u8 mac_addr[ETH_ALEN]; u8 remap_idx; u8 link_id; - u8 __rsv[2]; + u8 eml_enable; + u8 max_link_num; + u8 hybrid_mode; + u8 __rsv[3]; } __packed; struct sta_rec_ba_uni { From 790e3e1ec8aa232abdbfaa26401167580e789366 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:28:08 -0700 Subject: [PATCH 192/204] wifi: mt76: mt7925: update mt7925_mcu_add_bss_info for MLO Update mt7925_mcu_bss_mld_tlv for the MLO-enabled firmware The change remains compatible with the non-MLO mode and the older firmware. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/a3d03b0a1ca916b2b8b2e7c0afcdcd7e258d97c3.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 7a0225127135..094fa4dde5fe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2513,17 +2513,21 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, int enable) { struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv; + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); struct mt792x_dev *dev = phy->dev; + struct mt792x_link_sta *mlink_bc; struct sk_buff *skb; - skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mvif->bss_conf.mt76, + skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76, MT7925_BSS_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); + mlink_bc = mt792x_sta_to_link(&mvif->sta, mconf->link_id); + /* bss_basic must be first */ mt7925_mcu_bss_basic_tlv(skb, link_conf, link_sta, ctx, phy->mt76, - mvif->sta.deflink.wcid.idx, enable); + mlink_bc->wcid.idx, enable); mt7925_mcu_bss_sec_tlv(skb, link_conf); mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, link_conf); mt7925_mcu_bss_qos_tlv(skb, link_conf); @@ -2535,7 +2539,8 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, mt7925_mcu_bss_color_tlv(skb, link_conf, enable); } - mt7925_mcu_bss_rlm_tlv(skb, phy->mt76, link_conf, ctx); + if (enable) + mt7925_mcu_bss_rlm_tlv(skb, phy->mt76, link_conf, ctx); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_UNI_CMD(BSS_INFO_UPDATE), true); From a5942a3979d6553c09790553c9f0a6daa986ad58 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:28:09 -0700 Subject: [PATCH 193/204] wifi: mt76: mt7925: update mt7925_mcu_sta_update for MLO update mt7925_mcu_sta_update for the MLO-enabled firmware. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/2e25bfc2d8aa503ecd1ba8099c6e54dce0c27b99.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 9 +++ .../net/wireless/mediatek/mt76/mt7925/mcu.c | 68 ++++++++++++++++++- .../net/wireless/mediatek/mt76/mt7925/mcu.h | 3 +- 3 files changed, 78 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index e636b033b87e..9329c959674f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -545,6 +545,13 @@ struct sta_rec_muru { } mimo_ul; } __packed; +struct sta_rec_remove { + __le16 tag; + __le16 len; + u8 action; + u8 pad[3]; +} __packed; + struct sta_phy { u8 type; u8 flag; @@ -814,6 +821,8 @@ enum { STA_REC_HE_V2 = 0x19, STA_REC_MLD = 0x20, STA_REC_EHT = 0x22, + STA_REC_MLD_OFF = 0x23, + STA_REC_REMOVE = 0x25, STA_REC_PN_INFO = 0x26, STA_REC_KEY_V3 = 0x27, STA_REC_HDRT = 0x28, diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 094fa4dde5fe..159d253ba5b8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1812,6 +1812,66 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, return mt76_mcu_skb_send_msg(dev, skb, info->cmd, true); } +static void +mt7925_mcu_sta_remove_tlv(struct sk_buff *skb) +{ + struct sta_rec_remove *rem; + struct tlv *tlv; + + tlv = mt76_connac_mcu_add_tlv(skb, 0x25, sizeof(*rem)); + rem = (struct sta_rec_remove *)tlv; + rem->action = 0; +} + +static int +mt7925_mcu_mlo_sta_cmd(struct mt76_phy *phy, + struct mt76_sta_cmd_info *info) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)info->vif->drv_priv; + struct mt76_dev *dev = phy->dev; + struct mt792x_bss_conf *mconf; + struct sk_buff *skb; + + mconf = mt792x_vif_to_link(mvif, info->wcid->link_id); + + skb = __mt76_connac_mcu_alloc_sta_req(dev, &mconf->mt76, info->wcid, + MT7925_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + if (info->enable) + mt76_connac_mcu_sta_basic_tlv(dev, skb, info->vif, + info->link_sta, + info->enable, info->newly); + + if (info->enable && info->link_sta) { + mt7925_mcu_sta_phy_tlv(skb, info->vif, info->link_sta); + mt7925_mcu_sta_ht_tlv(skb, info->link_sta); + mt7925_mcu_sta_vht_tlv(skb, info->link_sta); + mt76_connac_mcu_sta_uapsd(skb, info->vif, info->link_sta->sta); + mt7925_mcu_sta_amsdu_tlv(skb, info->vif, info->link_sta); + mt7925_mcu_sta_he_tlv(skb, info->link_sta); + mt7925_mcu_sta_he_6g_tlv(skb, info->link_sta); + mt7925_mcu_sta_eht_tlv(skb, info->link_sta); + mt7925_mcu_sta_rate_ctrl_tlv(skb, info->vif, + info->link_sta); + mt7925_mcu_sta_state_v2_tlv(phy, skb, info->link_sta, + info->vif, info->rcpi, + info->state); + if (info->state != MT76_STA_INFO_STATE_NONE) + mt7925_mcu_sta_mld_tlv(skb, info->vif, info->link_sta->sta); + mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, info->link_sta); + } + + if (!info->enable) { + mt7925_mcu_sta_remove_tlv(skb); + mt76_connac_mcu_add_tlv(skb, STA_REC_MLD_OFF, + sizeof(struct tlv)); + } + + return mt76_mcu_skb_send_msg(dev, skb, info->cmd, true); +} + int mt7925_mcu_sta_update(struct mt792x_dev *dev, struct ieee80211_link_sta *link_sta, struct ieee80211_vif *vif, bool enable, @@ -1830,6 +1890,7 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev, }; struct mt792x_sta *msta; struct mt792x_link_sta *mlink; + int err; if (link_sta) { msta = (struct mt792x_sta *)link_sta->sta->drv_priv; @@ -1838,7 +1899,12 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev, info.wcid = link_sta ? &mlink->wcid : &mvif->sta.deflink.wcid; info.newly = link_sta ? state != MT76_STA_INFO_STATE_ASSOC : true; - return mt7925_mcu_sta_cmd(&dev->mphy, &info); + if (ieee80211_vif_is_mld(vif)) + err = mt7925_mcu_mlo_sta_cmd(&dev->mphy, &info); + else + err = mt7925_mcu_sta_cmd(&dev->mphy, &info); + + return err; } int mt7925_mcu_set_beacon_filter(struct mt792x_dev *dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h index 7b0c6937f918..a97e5b539ab9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -492,7 +492,8 @@ struct bss_rlm_tlv { sizeof(struct sta_rec_eht) + \ sizeof(struct sta_rec_hdr_trans) + \ sizeof(struct sta_rec_mld) + \ - sizeof(struct tlv)) + sizeof(struct tlv) * 2 + \ + sizeof(struct sta_rec_remove)) #define MT7925_BSS_UPDATE_MAX_SIZE (sizeof(struct bss_req_hdr) + \ sizeof(struct mt76_connac_bss_basic_tlv) + \ From 6db8639bc813a7670b365b8ed2b77e93ef96cf67 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:28:10 -0700 Subject: [PATCH 194/204] wifi: mt76: mt7925: add mt7925_mcu_sta_eht_mld_tlv for MLO add mt7925_mcu_sta_eht_mld_tlv for the MLO-enabled firmware. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/a1001592eeef4e4ee2c3e15dc94cca0815d64e59.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 1 + .../net/wireless/mediatek/mt76/mt7925/mcu.c | 42 ++++++++++++++++++- .../net/wireless/mediatek/mt76/mt7925/mcu.h | 11 +++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 9329c959674f..d6882c9fd6bc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -820,6 +820,7 @@ enum { STA_REC_HE_6G = 0x17, STA_REC_HE_V2 = 0x19, STA_REC_MLD = 0x20, + STA_REC_EHT_MLD = 0x21, STA_REC_EHT = 0x22, STA_REC_MLD_OFF = 0x23, STA_REC_REMOVE = 0x25, diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 159d253ba5b8..199070bff0f0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1738,6 +1738,42 @@ mt7925_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, HT_MCS_MASK_NUM); } +static void +mt7925_mcu_sta_eht_mld_tlv(struct sk_buff *skb, + struct ieee80211_vif *vif, struct ieee80211_sta *sta) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct wiphy *wiphy = mvif->phy->mt76->hw->wiphy; + const struct wiphy_iftype_ext_capab *ext_capa; + struct sta_rec_eht_mld *eht_mld; + struct tlv *tlv; + u16 eml_cap; + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EHT_MLD, sizeof(*eht_mld)); + eht_mld = (struct sta_rec_eht_mld *)tlv; + eht_mld->mld_type = 0xff; + + if (!ieee80211_vif_is_mld(vif)) + return; + + ext_capa = cfg80211_get_iftype_ext_capa(wiphy, + ieee80211_vif_type_p2p(vif)); + if (!ext_capa) + return; + + eml_cap = (vif->cfg.eml_cap & (IEEE80211_EML_CAP_EMLSR_SUPP | + IEEE80211_EML_CAP_TRANSITION_TIMEOUT)) | + (ext_capa->eml_capabilities & (IEEE80211_EML_CAP_EMLSR_PADDING_DELAY | + IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY)); + + if (eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP) { + eht_mld->eml_cap[0] = u16_get_bits(eml_cap, GENMASK(7, 0)); + eht_mld->eml_cap[1] = u16_get_bits(eml_cap, GENMASK(15, 8)); + } else { + eht_mld->str_cap[0] = BIT(1); + } +} + static void mt7925_mcu_sta_mld_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -1858,8 +1894,12 @@ mt7925_mcu_mlo_sta_cmd(struct mt76_phy *phy, mt7925_mcu_sta_state_v2_tlv(phy, skb, info->link_sta, info->vif, info->rcpi, info->state); - if (info->state != MT76_STA_INFO_STATE_NONE) + + if (info->state != MT76_STA_INFO_STATE_NONE) { mt7925_mcu_sta_mld_tlv(skb, info->vif, info->link_sta->sta); + mt7925_mcu_sta_eht_mld_tlv(skb, info->vif, info->link_sta->sta); + } + mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, info->link_sta); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h index a97e5b539ab9..ac53bdc99332 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -443,6 +443,17 @@ struct sta_rec_mld { } __packed link[2]; } __packed; +struct sta_rec_eht_mld { + __le16 tag; + __le16 len; + u8 nsep; + u8 mld_type; + u8 __rsv1[1]; + u8 str_cap[3]; + u8 eml_cap[3]; + u8 __rsv2[3]; +} __packed; + struct bss_ifs_time_tlv { __le16 tag; __le16 len; From 677f19e161afb1096f30d993ae28140aa61a9847 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:28:11 -0700 Subject: [PATCH 195/204] wifi: mt76: mt7925: update mt7925_mcu_sta_rate_ctrl_tlv for MLO Get band information from the per-link BSS. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/4f6ca2d082627bb93f79d5a4df80dc08998ee5d2.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 199070bff0f0..fbf43dda0cd6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1714,12 +1714,20 @@ mt7925_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - struct cfg80211_chan_def *chandef = &mvif->bss_conf.mt76.ctx->def; - enum nl80211_band band = chandef->chan->band; + struct ieee80211_bss_conf *link_conf; + struct cfg80211_chan_def *chandef; struct sta_rec_ra_info *ra_info; + struct mt792x_bss_conf *mconf; + enum nl80211_band band; struct tlv *tlv; u16 supp_rates; + link_conf = mt792x_vif_to_bss_conf(vif, link_sta->link_id); + mconf = mt792x_vif_to_link(mvif, link_sta->link_id); + chandef = mconf->mt76.ctx ? &mconf->mt76.ctx->def : + &link_conf->chanreq.oper; + band = chandef->chan->band; + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra_info)); ra_info = (struct sta_rec_ra_info *)tlv; From beef8d1643663d501ccbd9637fc314ea79ee09ac Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:28:12 -0700 Subject: [PATCH 196/204] wifi: mt76: mt7925: update mt7925_mcu_sta_phy_tlv for MLO when we serve MLO during the multiple-linked connection, the chanctx may be not available in the internal driver, we should get the proper the band information from link_conf for the MLO-enabled firmware. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/6620e00fbeef686fb2041556deba346411eab0f1.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index fbf43dda0cd6..caf2ac238b4d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1647,7 +1647,8 @@ mt7925_mcu_sta_phy_tlv(struct sk_buff *skb, link_conf = mt792x_vif_to_bss_conf(vif, link_sta->link_id); mconf = mt792x_vif_to_link(mvif, link_sta->link_id); - chandef = &mconf->mt76.ctx->def; + chandef = mconf->mt76.ctx ? &mconf->mt76.ctx->def : + &link_conf->chanreq.oper; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy)); phy = (struct sta_rec_phy *)tlv; From cfbe7f78346e00d33a6461f3f8d94f72c6256acb Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:28:13 -0700 Subject: [PATCH 197/204] wifi: mt76: mt7925: update mt7925_mcu_set_timing for MLO Set the BSS index from the per-linked BSS for the firmware to identify which link the command is operating on. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/dde970c748586d03fbecbccb10cb9903284719aa.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index caf2ac238b4d..bc6d6d957765 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2606,11 +2606,11 @@ mt7925_mcu_bss_ifs_tlv(struct sk_buff *skb, int mt7925_mcu_set_timing(struct mt792x_phy *phy, struct ieee80211_bss_conf *link_conf) { - struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv; + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); struct mt792x_dev *dev = phy->dev; struct sk_buff *skb; - skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mvif->bss_conf.mt76, + skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76, MT7925_BSS_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); From 696d9f3baf03f59584c7c46b62ae28dfd1a731ae Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:28:14 -0700 Subject: [PATCH 198/204] wifi: mt76: mt7925: update mt7925_mcu_bss_basic_tlv for MLO update mt7925_mcu_bss_basic_tlv for the MLO-enabled firmware. The change remains compatible with the non-MLO mode and the older firmware. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/583a3ac10583cfef0028f9a0b5a4802fc4070b99.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index bc6d6d957765..7bfb9c51388c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2385,6 +2385,7 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, basic_req->bcn_interval = cpu_to_le16(link_conf->beacon_int); basic_req->dtim_period = link_conf->dtim_period; basic_req->bmc_tx_wlan_idx = cpu_to_le16(wlan_idx); + basic_req->link_idx = mconf->mt76.idx; if (link_sta) { struct mt792x_sta *msta; From 0cb349d742d17707b5b42f0db1df7f3963fc3a8a Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:28:15 -0700 Subject: [PATCH 199/204] wifi: mt76: mt7925: update mt7925_mac_link_bss_add for MLO Update band_idx in per-link BSS to be auto for the MLO-enabled firmware and the MLO-enabled firmware only supports omac index in 0. The change remains compatible with the non-MLO mode and the older firmware. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/37fcf3ea7b4883840d61f97231277b297e1b15a3.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 0627ef208641..1385ef1f1c79 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -333,8 +333,9 @@ static int mt7925_mac_link_bss_add(struct mt792x_dev *dev, goto out; } - mconf->mt76.omac_idx = mconf->mt76.idx; - mconf->mt76.band_idx = 0; + mconf->mt76.omac_idx = ieee80211_vif_is_mld(vif) ? + 0 : mconf->mt76.idx; + mconf->mt76.band_idx = 0xff; mconf->mt76.wmm_idx = mconf->mt76.idx % MT76_CONNAC_MAX_WMM_SETS; if (mvif->phy->mt76->chandef.chan->band != NL80211_BAND_2GHZ) From 67e9847b0208ae02efbe42dbcda4c1a9a1a853cd Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:28:16 -0700 Subject: [PATCH 200/204] wifi: mt76: mt7925: remove the unused mt7925_mcu_set_chan_info remove the unused function mt7925_mcu_set_chan_info Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/0aa0abe7fc661380ae812c6bc879a7705de401b2.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 74 ------------------- 1 file changed, 74 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 7bfb9c51388c..26f78c0a491e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1274,80 +1274,6 @@ int mt7925_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, &req, sizeof(req), false); } -int mt7925_mcu_set_chan_info(struct mt792x_phy *phy, u16 tag) -{ - static const u8 ch_band[] = { - [NL80211_BAND_2GHZ] = 0, - [NL80211_BAND_5GHZ] = 1, - [NL80211_BAND_6GHZ] = 2, - }; - struct mt792x_dev *dev = phy->dev; - struct cfg80211_chan_def *chandef = &phy->mt76->chandef; - int freq1 = chandef->center_freq1; - u8 band_idx = chandef->chan->band != NL80211_BAND_2GHZ; - struct { - /* fixed field */ - u8 __rsv[4]; - - __le16 tag; - __le16 len; - u8 control_ch; - u8 center_ch; - u8 bw; - u8 tx_path_num; - u8 rx_path; /* mask or num */ - u8 switch_reason; - u8 band_idx; - u8 center_ch2; /* for 80+80 only */ - __le16 cac_case; - u8 channel_band; - u8 rsv0; - __le32 outband_freq; - u8 txpower_drop; - u8 ap_bw; - u8 ap_center_ch; - u8 rsv1[53]; - } __packed req = { - .tag = cpu_to_le16(tag), - .len = cpu_to_le16(sizeof(req) - 4), - .control_ch = chandef->chan->hw_value, - .center_ch = ieee80211_frequency_to_channel(freq1), - .bw = mt76_connac_chan_bw(chandef), - .tx_path_num = hweight8(phy->mt76->antenna_mask), - .rx_path = phy->mt76->antenna_mask, - .band_idx = band_idx, - .channel_band = ch_band[chandef->chan->band], - }; - - if (chandef->chan->band == NL80211_BAND_6GHZ) - req.channel_band = 2; - else - req.channel_band = chandef->chan->band; - - if (tag == UNI_CHANNEL_RX_PATH || - dev->mt76.hw->conf.flags & IEEE80211_CONF_MONITOR) - req.switch_reason = CH_SWITCH_NORMAL; - else if (phy->mt76->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) - req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; - else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef, - NL80211_IFTYPE_AP)) - req.switch_reason = CH_SWITCH_DFS; - else - req.switch_reason = CH_SWITCH_NORMAL; - - if (tag == UNI_CHANNEL_SWITCH) - req.rx_path = hweight8(req.rx_path); - - if (chandef->width == NL80211_CHAN_WIDTH_80P80) { - int freq2 = chandef->center_freq2; - - req.center_ch2 = ieee80211_frequency_to_channel(freq2); - } - - return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(CHANNEL_SWITCH), - &req, sizeof(req), true); -} - int mt7925_mcu_set_eeprom(struct mt792x_dev *dev) { struct { From 86c051f2c418abd7eefd8c545a01bdffd220cb95 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 6 Jul 2024 01:28:17 -0700 Subject: [PATCH 201/204] wifi: mt76: mt7925: enabling MLO when the firmware supports it Register MLD capability for the firmware supporting MLO. Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Link: https://patch.msgid.link/49c796b101e792c84bc2c0d74753022b75fd3355.1720248331.git.sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 1 + .../net/wireless/mediatek/mt76/mt7925/init.c | 6 ++++ .../net/wireless/mediatek/mt76/mt7925/main.c | 29 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7925/mcu.c | 20 +++++++++++++ .../wireless/mediatek/mt76/mt7925/mt7925.h | 1 + drivers/net/wireless/mediatek/mt76/mt792x.h | 2 ++ 6 files changed, 59 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index d6882c9fd6bc..4242d436de26 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1402,6 +1402,7 @@ enum { MT_NIC_CAP_WFDMA_REALLOC, MT_NIC_CAP_6G, MT_NIC_CAP_CHIP_CAP = 0x20, + MT_NIC_CAP_EML_CAP = 0x22, }; #define UNI_WOW_DETECT_TYPE_MAGIC BIT(0) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/init.c b/drivers/net/wireless/mediatek/mt76/mt7925/init.c index c4cbc8976046..039949b344b9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/init.c @@ -179,6 +179,12 @@ static void mt7925_init_work(struct work_struct *work) mt76_set_stream_caps(&dev->mphy, true); mt7925_set_stream_he_eht_caps(&dev->phy); + ret = mt7925_init_mlo_caps(&dev->phy); + if (ret) { + dev_err(dev->mt76.dev, "MLO init failed\n"); + return; + } + ret = mt76_register_device(&dev->mt76, true, mt76_rates, ARRAY_SIZE(mt76_rates)); if (ret) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 1385ef1f1c79..8c0768bf9343 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -236,6 +236,35 @@ mt7925_init_eht_caps(struct mt792x_phy *phy, enum nl80211_band band, eht_nss->bw._160.rx_tx_mcs13_max_nss = val; } +int mt7925_init_mlo_caps(struct mt792x_phy *phy) +{ + struct wiphy *wiphy = phy->mt76->hw->wiphy; + static const u8 ext_capa_sta[] = { + [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, + }; + static struct wiphy_iftype_ext_capab ext_capab[] = { + { + .iftype = NL80211_IFTYPE_STATION, + .extended_capabilities = ext_capa_sta, + .extended_capabilities_mask = ext_capa_sta, + .extended_capabilities_len = sizeof(ext_capa_sta), + }, + }; + + if (!(phy->chip_cap & MT792x_CHIP_CAP_MLO_EVT_EN)) + return 0; + + ext_capab[0].eml_capabilities = phy->eml_cap; + ext_capab[0].mld_capa_and_ops = + u16_encode_bits(1, IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS); + + wiphy->flags |= WIPHY_FLAG_SUPPORTS_MLO; + wiphy->iftype_ext_capab = ext_capab; + wiphy->num_iftype_ext_capab = ARRAY_SIZE(ext_capab); + + return 0; +} + static void __mt7925_set_stream_he_eht_caps(struct mt792x_phy *phy, struct ieee80211_supported_band *sband, diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 26f78c0a491e..9dc22fbe25d3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -751,6 +751,20 @@ mt7925_mcu_parse_phy_cap(struct mt792x_dev *dev, char *data) dev->has_eht = cap->eht; } +static void +mt7925_mcu_parse_eml_cap(struct mt792x_dev *dev, char *data) +{ + struct mt7925_mcu_eml_cap { + u8 rsv[4]; + __le16 eml_cap; + u8 rsv2[6]; + } __packed * cap; + + cap = (struct mt7925_mcu_eml_cap *)data; + + dev->phy.eml_cap = le16_to_cpu(cap->eml_cap); +} + static int mt7925_mcu_get_nic_capability(struct mt792x_dev *dev) { @@ -805,6 +819,12 @@ mt7925_mcu_get_nic_capability(struct mt792x_dev *dev) case MT_NIC_CAP_PHY: mt7925_mcu_parse_phy_cap(dev, tlv->data); break; + case MT_NIC_CAP_CHIP_CAP: + memcpy(&dev->phy.chip_cap, (void *)skb->data, sizeof(u64)); + break; + case MT_NIC_CAP_EML_CAP: + mt7925_mcu_parse_eml_cap(dev, tlv->data); + break; default: break; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h index 1ae66629e39f..669f3a079d04 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h @@ -235,6 +235,7 @@ void mt7925_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb, u32 *info); void mt7925_stats_work(struct work_struct *work); void mt7925_set_stream_he_eht_caps(struct mt792x_phy *phy); +int mt7925_init_mlo_caps(struct mt792x_phy *phy); int mt7925_init_debugfs(struct mt792x_dev *dev); int mt7925_mcu_set_beacon_filter(struct mt792x_dev *dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index 5ede24116748..30635aeba363 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -27,6 +27,7 @@ #define MT792x_CHIP_CAP_CLC_EVT_EN BIT(0) #define MT792x_CHIP_CAP_RSSI_NOTIFY_EVT_EN BIT(1) +#define MT792x_CHIP_CAP_MLO_EVT_EN BIT(2) /* NOTE: used to map mt76_rates. idx may change if firmware expands table */ #define MT792x_BASIC_RATES_TBL 11 @@ -163,6 +164,7 @@ struct mt792x_phy { #endif void *clc[MT792x_CLC_MAX_NUM]; u64 chip_cap; + u16 eml_cap; struct work_struct roc_work; struct timer_list roc_timer; From d53ab629cff57e450fe69fc90eb1ddc372e8da2d Mon Sep 17 00:00:00 2001 From: Michael Lo Date: Thu, 23 May 2024 19:21:31 +0800 Subject: [PATCH 202/204] wifi: mt76: mt792x: fix scheduler interference in drv own process Add some time to wait for LP engine to complete its operation before polling pmctrl register. Signed-off-by: Michael Lo Signed-off-by: Ming Yen Hsieh Tested-by: David Ruth Acked-by: Sean Wang Link: https://patch.msgid.link/20240523112131.31437-1-mingyen.hsieh@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + .../net/wireless/mediatek/mt76/mt7921/pci.c | 3 +++ .../net/wireless/mediatek/mt76/mt7925/pci.c | 3 +++ drivers/net/wireless/mediatek/mt76/mt792x.h | 1 + .../net/wireless/mediatek/mt76/mt792x_core.c | 4 ++++ drivers/net/wireless/mediatek/mt76/pci.c | 23 +++++++++++++++++++ 6 files changed, 35 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 5f8773364d51..4a58a78d5ed2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1085,6 +1085,7 @@ bool ____mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs); void mt76_pci_disable_aspm(struct pci_dev *pdev); +bool mt76_pci_aspm_supported(struct pci_dev *pdev); static inline u16 mt76_chip(struct mt76_dev *dev) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index e75e7b6d3aaf..a7430216a80d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -339,6 +339,9 @@ static int mt7921_pci_probe(struct pci_dev *pdev, bus_ops->rmw = mt7921_rmw; dev->mt76.bus = bus_ops; + if (!mt7921_disable_aspm && mt76_pci_aspm_supported(pdev)) + dev->aspm_supported = true; + ret = mt792xe_mcu_fw_pmctrl(dev); if (ret) goto err_free_dev; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c index 577574fb7a1e..6e4f4e78c350 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c @@ -373,6 +373,9 @@ static int mt7925_pci_probe(struct pci_dev *pdev, bus_ops->rmw = mt7925_rmw; dev->mt76.bus = bus_ops; + if (!mt7925_disable_aspm && mt76_pci_aspm_supported(pdev)) + dev->aspm_supported = true; + ret = __mt792x_mcu_fw_pmctrl(dev); if (ret) goto err_free_dev; diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index 30635aeba363..7fa74d59cc48 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -215,6 +215,7 @@ struct mt792x_dev { bool fw_assert:1; bool has_eht:1; bool regd_in_progress:1; + bool aspm_supported:1; wait_queue_head_t wait; struct work_struct init_work; diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c index ae2ac146a7f7..78fe37c2e07b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c @@ -809,6 +809,10 @@ int __mt792xe_mcu_drv_pmctrl(struct mt792x_dev *dev) for (i = 0; i < MT792x_DRV_OWN_RETRY_COUNT; i++) { mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_CLR_OWN); + + if (dev->aspm_supported) + usleep_range(2000, 3000); + if (mt76_poll_msec_tick(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_OWN_SYNC, 0, 50, 1)) break; diff --git a/drivers/net/wireless/mediatek/mt76/pci.c b/drivers/net/wireless/mediatek/mt76/pci.c index 4c1c159fbb62..b5031ca7f73f 100644 --- a/drivers/net/wireless/mediatek/mt76/pci.c +++ b/drivers/net/wireless/mediatek/mt76/pci.c @@ -45,3 +45,26 @@ void mt76_pci_disable_aspm(struct pci_dev *pdev) aspm_conf); } EXPORT_SYMBOL_GPL(mt76_pci_disable_aspm); + +bool mt76_pci_aspm_supported(struct pci_dev *pdev) +{ + struct pci_dev *parent = pdev->bus->self; + u16 aspm_conf, parent_aspm_conf = 0; + bool result = true; + + pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &aspm_conf); + aspm_conf &= PCI_EXP_LNKCTL_ASPMC; + if (parent) { + pcie_capability_read_word(parent, PCI_EXP_LNKCTL, + &parent_aspm_conf); + parent_aspm_conf &= PCI_EXP_LNKCTL_ASPMC; + } + + if (!aspm_conf && (!parent || !parent_aspm_conf)) { + /* aspm already disabled */ + result = false; + } + + return result; +} +EXPORT_SYMBOL_GPL(mt76_pci_aspm_supported); From 003eae5a28c6c9d50290a4ac9b955be912f24c9f Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 9 Jul 2024 14:31:49 +0200 Subject: [PATCH 203/204] wifi: iwlwifi: correctly reference TSO page information The code got copied from get_workaround_page, but here p->page is the correct way to reference the page. Signed-off-by: Benjamin Berg Fixes: adc902ceada2 ("wifi: iwlwifi: keep the TSO and workaround pages mapped") Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202407062135.NNjnmMdR-lkp@intel.com/ Link: https://patch.msgid.link/20240709123149.1848315-1-benjamin@sipsolutions.net Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 748772fa6b3e..22d482ae53d9 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1770,7 +1770,7 @@ static void *iwl_pcie_get_page_hdr(struct iwl_trans *trans, * (see also get_workaround_page() in tx-gen2.c) */ if (((unsigned long)p->pos & ~PAGE_MASK) + len < IWL_TSO_PAGE_DATA_SIZE) { - info = IWL_TSO_PAGE_INFO(page_address(ret)); + info = IWL_TSO_PAGE_INFO(page_address(p->page)); goto out; } @@ -1783,7 +1783,7 @@ static void *iwl_pcie_get_page_hdr(struct iwl_trans *trans, return NULL; p->pos = page_address(p->page); - info = IWL_TSO_PAGE_INFO(page_address(ret)); + info = IWL_TSO_PAGE_INFO(page_address(p->page)); /* set the chaining pointer to NULL */ info->next = NULL; From 408ac28c62f0b869d5477be12dd9eddc0c37242e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 9 Jul 2024 16:08:50 +0200 Subject: [PATCH 204/204] wifi: mac80211: fix AP chandef capturing in CSA When the CSA is announced with only HT elements, the AP chandef isn't captured correctly, leading to crashes in the later code that checks for TPE changes during CSA. Capture the AP chandef correctly in both cases to fix this. Reported-by: Jouni Malinen Fixes: 4540568136fe ("wifi: mac80211: handle TPE element during CSA") Link: https://patch.msgid.link/20240709160851.47805f24624d.I024091f701447f7921e93bb23b46e01c2f46347d@changeid Signed-off-by: Johannes Berg --- net/mac80211/spectmgmt.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index e91ca4ccdd37..073ff9e0f397 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c @@ -343,6 +343,9 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, break; } + /* capture the AP configuration */ + csa_ie->chanreq.ap = csa_ie->chanreq.oper; + /* parse one of the Elements to build a new chandef */ memset(&new_chandef, 0, sizeof(new_chandef)); new_chandef.chan = new_chan; @@ -369,11 +372,11 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, validate_chandef_by_ht_vht_oper(sdata, conn, vht_cap_info, &new_chandef); - /* capture the AP chandef before (potential) downgrading */ - csa_ie->chanreq.ap = new_chandef; - /* if data is there validate the bandwidth & use it */ if (new_chandef.chan) { + /* capture the AP chandef before (potential) downgrading */ + csa_ie->chanreq.ap = new_chandef; + if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_320 && new_chandef.width == NL80211_CHAN_WIDTH_320) ieee80211_chandef_downgrade(&new_chandef, NULL);