From 90f2ba4896e289ba7973a5349cbad4463c97e321 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Mon, 24 Jul 2023 13:11:07 +0300 Subject: [PATCH 01/32] wifi: ath9k: avoid using uninitialized array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In 'ath_tx_count_frames()', 'ba' array may be used uninitialized, so add 'memset()' call similar to one used in 'ath_tx_complete_aggr()'. Signed-off-by: Dmitry Antipov Acked-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230620080855.396851-1-dmantipov@yandex.ru --- drivers/net/wireless/ath/ath9k/xmit.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index f6f2ab7a63ffc..8babaaacacf59 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -466,6 +466,8 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf, *nframes = 0; isaggr = bf_isaggr(bf); + memset(ba, 0, WME_BA_BMP_SIZE >> 3); + if (isaggr) { seq_st = ts->ts_seqnum; memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3); From 810e41cebb6c6e394f2068f839e1a3fc745a5dcc Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Mon, 24 Jul 2023 13:11:07 +0300 Subject: [PATCH 02/32] wifi: ath9k: fix fortify warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When compiling with gcc 13.1 and CONFIG_FORTIFY_SOURCE=y, I've noticed the following: In function ‘fortify_memcpy_chk’, inlined from ‘ath_tx_complete_aggr’ at drivers/net/wireless/ath/ath9k/xmit.c:556:4, inlined from ‘ath_tx_process_buffer’ at drivers/net/wireless/ath/ath9k/xmit.c:773:3: ./include/linux/fortify-string.h:529:25: warning: call to ‘__read_overflow2_field’ declared with attribute warning: detected read beyond size of field (2nd parameter); maybe use struct_group()? [-Wattribute-warning] 529 | __read_overflow2_field(q_size_field, size); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In function ‘fortify_memcpy_chk’, inlined from ‘ath_tx_count_frames’ at drivers/net/wireless/ath/ath9k/xmit.c:473:3, inlined from ‘ath_tx_complete_aggr’ at drivers/net/wireless/ath/ath9k/xmit.c:572:2, inlined from ‘ath_tx_process_buffer’ at drivers/net/wireless/ath/ath9k/xmit.c:773:3: ./include/linux/fortify-string.h:529:25: warning: call to ‘__read_overflow2_field’ declared with attribute warning: detected read beyond size of field (2nd parameter); maybe use struct_group()? [-Wattribute-warning] 529 | __read_overflow2_field(q_size_field, size); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In both cases, the compiler complains on: memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3); which is the legal way to copy both 'ba_low' and following 'ba_high' members of 'struct ath_tx_status' at once (that is, issue one 8-byte 'memcpy()' for two 4-byte fields). Since the fortification logic seems interprets this trick as an attempt to overread 4-byte 'ba_low', silence relevant warnings by using the convenient 'struct_group()' quirk. Suggested-by: Johannes Berg Signed-off-by: Dmitry Antipov Acked-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230620080855.396851-2-dmantipov@yandex.ru --- drivers/net/wireless/ath/ath9k/mac.h | 6 ++++-- drivers/net/wireless/ath/ath9k/xmit.c | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index af44b33814ddc..f03d792732da7 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -115,8 +115,10 @@ struct ath_tx_status { u8 qid; u16 desc_id; u8 tid; - u32 ba_low; - u32 ba_high; + struct_group(ba, + u32 ba_low; + u32 ba_high; + ); u32 evm0; u32 evm1; u32 evm2; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 8babaaacacf59..4e939dcac1c9d 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -470,7 +470,7 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf, if (isaggr) { seq_st = ts->ts_seqnum; - memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3); + memcpy(ba, &ts->ba, WME_BA_BMP_SIZE >> 3); } while (bf) { @@ -553,7 +553,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, if (isaggr && txok) { if (ts->ts_flags & ATH9K_TX_BA) { seq_st = ts->ts_seqnum; - memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3); + memcpy(ba, &ts->ba, WME_BA_BMP_SIZE >> 3); } else { /* * AR5416 can become deaf/mute when BA From f7eb8315b22a8f58365b8916446a11326e5a719b Mon Sep 17 00:00:00 2001 From: Minjie Du Date: Mon, 24 Jul 2023 13:11:07 +0300 Subject: [PATCH 03/32] wifi: ath5k: remove phydir check from ath5k_debug_init_device() 'phydir' returned from debugfs_create_dir() is checked against NULL. As the debugfs API returns an error pointer, the returned value can never be NULL. Therefore, as the documentation suggests that the check is unnecessary and other debugfs calls have no operation in error cases, it is advisable to completely eliminate the check. Signed-off-by: Minjie Du Reviewed-by: Jiri Slaby Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230714081619.2032-1-duminjie@vivo.com --- drivers/net/wireless/ath/ath5k/debug.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index 4b41160e5d389..ec130510aeb2a 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -982,8 +982,6 @@ ath5k_debug_init_device(struct ath5k_hw *ah) ah->debug.level = ath5k_debug; phydir = debugfs_create_dir("ath5k", ah->hw->wiphy->debugfsdir); - if (!phydir) - return; debugfs_create_file("debug", 0600, phydir, ah, &fops_debug); debugfs_create_file("registers", 0400, phydir, ah, ®isters_fops); From 1301783c8def21fb5e1658676f36d75fff15c571 Mon Sep 17 00:00:00 2001 From: Wang Ming Date: Mon, 24 Jul 2023 13:11:08 +0300 Subject: [PATCH 04/32] wifi: ath6kl: Remove error checking for debugfs_create_dir() It is expected that most callers should _ignore_ the errors return by debugfs_create_dir() in ath6kl_debug_init_fs(). Signed-off-by: Wang Ming Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230714014358.514-1-machel@vivo.com --- drivers/net/wireless/ath/ath6kl/debug.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index 433a047f3747b..b837d31416dfe 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -1793,8 +1793,6 @@ int ath6kl_debug_init_fs(struct ath6kl *ar) { ar->debugfs_phy = debugfs_create_dir("ath6kl", ar->wiphy->debugfsdir); - if (!ar->debugfs_phy) - return -ENOMEM; debugfs_create_file("tgt_stats", 0400, ar->debugfs_phy, ar, &fops_tgt_stats); From 061115fbfb2ce5870c9a004d68dc63138c07c782 Mon Sep 17 00:00:00 2001 From: Dongliang Mu Date: Sun, 23 Jul 2023 12:04:02 +0800 Subject: [PATCH 05/32] wifi: ath9k: fix printk specifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Smatch reports: ath_pci_probe() warn: argument 4 to %lx specifier is cast from pointer ath_ahb_probe() warn: argument 4 to %lx specifier is cast from pointer Fix it by modifying %lx to %p in the printk format string. Note that with this change, the pointer address will be printed as a hashed value by default. This is appropriate because the kernel should not leak kernel pointers to user space in an informational message. If someone wants to see the real address for debugging purposes, this can be achieved with the no_hash_pointers kernel option. Signed-off-by: Dongliang Mu Acked-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230723040403.296723-1-dzm91@hust.edu.cn --- drivers/net/wireless/ath/ath9k/ahb.c | 4 ++-- drivers/net/wireless/ath/ath9k/pci.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 9cd12b20b18d8..9bfaadfa6c009 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -132,8 +132,8 @@ static int ath_ahb_probe(struct platform_device *pdev) ah = sc->sc_ah; ath9k_hw_name(ah, hw_name, sizeof(hw_name)); - wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n", - hw_name, (unsigned long)mem, irq); + wiphy_info(hw->wiphy, "%s mem=0x%p, irq=%d\n", + hw_name, mem, irq); return 0; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index a09f9d223f3de..0633589b85c23 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -988,8 +988,8 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) sc->sc_ah->msi_reg = 0; ath9k_hw_name(sc->sc_ah, hw_name, sizeof(hw_name)); - wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n", - hw_name, (unsigned long)sc->mem, pdev->irq); + wiphy_info(hw->wiphy, "%s mem=0x%p, irq=%d\n", + hw_name, sc->mem, pdev->irq); return 0; From 1ad8237e971630c66a1a6194491e0837b64d00e0 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Wed, 21 Jun 2023 12:36:55 +0300 Subject: [PATCH 06/32] wifi: wil6210: fix fortify warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When compiling with gcc 13.1 and CONFIG_FORTIFY_SOURCE=y, I've noticed the following: In function ‘fortify_memcpy_chk’, inlined from ‘wil_rx_crypto_check_edma’ at drivers/net/wireless/ath/wil6210/txrx_edma.c:566:2: ./include/linux/fortify-string.h:529:25: warning: call to ‘__read_overflow2_field’ declared with attribute warning: detected read beyond size of field (2nd parameter); maybe use struct_group()? [-Wattribute-warning] 529 | __read_overflow2_field(q_size_field, size); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ where the compiler complains on: const u8 *pn; ... pn = (u8 *)&st->ext.pn_15_0; ... memcpy(cc->pn, pn, IEEE80211_GCMP_PN_LEN); and: In function ‘fortify_memcpy_chk’, inlined from ‘wil_rx_crypto_check’ at drivers/net/wireless/ath/wil6210/txrx.c:684:2: ./include/linux/fortify-string.h:529:25: warning: call to ‘__read_overflow2_field’ declared with attribute warning: detected read beyond size of field (2nd parameter); maybe use struct_group()? [-Wattribute-warning] 529 | __read_overflow2_field(q_size_field, size); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ where the compiler complains on: const u8 *pn = (u8 *)&d->mac.pn_15_0; ... memcpy(cc->pn, pn, IEEE80211_GCMP_PN_LEN); In both cases, the fortification logic interprets 'memcpy()' as 6-byte overread of 2-byte field 'pn_15_0' of 'struct wil_rx_status_extension' and 'pn_15_0' of 'struct vring_rx_mac', respectively. To silence these warnings, last two fields of the aforementioned structures are grouped using 'struct_group_attr(pn, __packed' quirk. Signed-off-by: Dmitry Antipov Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230621093711.80118-1-dmantipov@yandex.ru --- drivers/net/wireless/ath/wil6210/txrx.c | 2 +- drivers/net/wireless/ath/wil6210/txrx.h | 6 ++++-- drivers/net/wireless/ath/wil6210/txrx_edma.c | 2 +- drivers/net/wireless/ath/wil6210/txrx_edma.h | 6 ++++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 237cbd5c5060b..f29ac6de71399 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -666,7 +666,7 @@ static int wil_rx_crypto_check(struct wil6210_priv *wil, struct sk_buff *skb) struct wil_tid_crypto_rx *c = mc ? &s->group_crypto_rx : &s->tid_crypto_rx[tid]; struct wil_tid_crypto_rx_single *cc = &c->key_id[key_id]; - const u8 *pn = (u8 *)&d->mac.pn_15_0; + const u8 *pn = (u8 *)&d->mac.pn; if (!cc->key_set) { wil_err_ratelimited(wil, diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index 1ae1bec1b97f1..689f68d89a440 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -343,8 +343,10 @@ struct vring_rx_mac { u32 d0; u32 d1; u16 w4; - u16 pn_15_0; - u32 pn_47_16; + struct_group_attr(pn, __packed, + u16 pn_15_0; + u32 pn_47_16; + ); } __packed; /* Rx descriptor - DMA part diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c index 201c8c35e0c9e..1ba1f21ebea26 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.c +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c @@ -548,7 +548,7 @@ static int wil_rx_crypto_check_edma(struct wil6210_priv *wil, s = &wil->sta[cid]; c = mc ? &s->group_crypto_rx : &s->tid_crypto_rx[tid]; cc = &c->key_id[key_id]; - pn = (u8 *)&st->ext.pn_15_0; + pn = (u8 *)&st->ext.pn; if (!cc->key_set) { wil_err_ratelimited(wil, diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.h b/drivers/net/wireless/ath/wil6210/txrx_edma.h index c736f7413a35f..ee90e225bb050 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.h +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.h @@ -330,8 +330,10 @@ struct wil_rx_status_extension { u32 d0; u32 d1; __le16 seq_num; /* only lower 12 bits */ - u16 pn_15_0; - u32 pn_47_16; + struct_group_attr(pn, __packed, + u16 pn_15_0; + u32 pn_47_16; + ); } __packed; struct wil_rx_status_extended { From 72c8caf904aed2caed5d6e75233294b6159ddb5d Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Wed, 26 Jul 2023 10:16:24 +0530 Subject: [PATCH 07/32] wifi: ath11k: fix band selection for ppdu received in channel 177 of 5 GHz 5 GHz band channel 177 support was added with the commit e5e94d10c856 ("wifi: ath11k: add channel 177 into 5 GHz channel list"). However, during processing for the received ppdu in ath11k_dp_rx_h_ppdu(), channel number is checked only till 173. This leads to driver code checking for channel and then fetching the band from it which is extra effort since firmware has already given the channel number in the metadata. Fix this issue by checking the channel number till 177 since we support it now. Found via code review. Compile tested only. Fixes: e5e94d10c856 ("wifi: ath11k: add channel 177 into 5 GHz channel list") Signed-off-by: Aditya Kumar Singh Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230726044624.20507-1-quic_adisi@quicinc.com --- drivers/net/wireless/ath/ath11k/dp_rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 5c76664ba0dd9..1e488eed282b5 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -2408,7 +2408,7 @@ static void ath11k_dp_rx_h_ppdu(struct ath11k *ar, struct hal_rx_desc *rx_desc, rx_status->freq = center_freq; } else if (channel_num >= 1 && channel_num <= 14) { rx_status->band = NL80211_BAND_2GHZ; - } else if (channel_num >= 36 && channel_num <= 173) { + } else if (channel_num >= 36 && channel_num <= 177) { rx_status->band = NL80211_BAND_5GHZ; } else { spin_lock_bh(&ar->data_lock); From 6f092c98dcfa1e4cf37d45f9b8e4d4a3cbeb79d4 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Wed, 26 Jul 2023 12:21:02 +0300 Subject: [PATCH 08/32] wifi: ath11k: simplify ath11k_mac_validate_vht_he_fixed_rate_settings() In ath11k_mac_validate_vht_he_fixed_rate_settings() ar->ab->peers list is not altered so list_for_each_entry() should be safe. Compile tested only. Signed-off-by: Dmitry Antipov Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230726092113.78794-1-dmantipov@yandex.ru --- drivers/net/wireless/ath/ath11k/mac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 8c77ade49437f..2aadf2c387b62 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -8255,7 +8255,7 @@ ath11k_mac_validate_vht_he_fixed_rate_settings(struct ath11k *ar, enum nl80211_b const struct cfg80211_bitrate_mask *mask) { bool he_fixed_rate = false, vht_fixed_rate = false; - struct ath11k_peer *peer, *tmp; + struct ath11k_peer *peer; const u16 *vht_mcs_mask, *he_mcs_mask; struct ieee80211_link_sta *deflink; u8 vht_nss, he_nss; @@ -8278,7 +8278,7 @@ ath11k_mac_validate_vht_he_fixed_rate_settings(struct ath11k *ar, enum nl80211_b rcu_read_lock(); spin_lock_bh(&ar->ab->base_lock); - list_for_each_entry_safe(peer, tmp, &ar->ab->peers, list) { + list_for_each_entry(peer, &ar->ab->peers, list) { if (peer->sta) { deflink = &peer->sta->deflink; From 011e5a3052a22d3758d17442bf0c04c68bf79bea Mon Sep 17 00:00:00 2001 From: Seevalamuthu Mariappan Date: Wed, 26 Jul 2023 19:40:30 +0530 Subject: [PATCH 09/32] wifi: ath11k: Split coldboot calibration hw_param QCN9074 enables coldboot calibration only in Factory Test Mode (FTM). Hence, split cold_boot_calib to two hw_params for mission and FTM mode. Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Seevalamuthu Mariappan Signed-off-by: Raj Kumar Bhagat Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230726141032.3061-2-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath11k/ahb.c | 3 +-- drivers/net/wireless/ath/ath11k/core.c | 36 ++++++++++++++++++++------ drivers/net/wireless/ath/ath11k/core.h | 1 + drivers/net/wireless/ath/ath11k/hw.h | 3 ++- drivers/net/wireless/ath/ath11k/qmi.c | 6 ++--- 5 files changed, 35 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 1cebba7889d78..56aea2bc97871 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -423,8 +423,7 @@ static int ath11k_ahb_fwreset_from_cold_boot(struct ath11k_base *ab) { int timeout; - if (ath11k_cold_boot_cal == 0 || ab->qmi.cal_done || - ab->hw_params.cold_boot_calib == 0 || + if (!ath11k_core_coldboot_cal_support(ab) || ab->qmi.cal_done || ab->hw_params.cbcal_restart_fw == 0) return 0; diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index bebfd342e28b2..d5bf2896d8c59 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -86,7 +86,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_shadow_regs = false, .idle_ps = false, .supports_sta_ps = false, - .cold_boot_calib = true, + .coldboot_cal_mm = true, + .coldboot_cal_ftm = true, .cbcal_restart_fw = true, .fw_mem_mode = 0, .num_vdevs = 16 + 1, @@ -167,7 +168,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_shadow_regs = false, .idle_ps = false, .supports_sta_ps = false, - .cold_boot_calib = true, + .coldboot_cal_mm = true, + .coldboot_cal_ftm = true, .cbcal_restart_fw = true, .fw_mem_mode = 0, .num_vdevs = 16 + 1, @@ -248,7 +250,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_shadow_regs = true, .idle_ps = true, .supports_sta_ps = true, - .cold_boot_calib = false, + .coldboot_cal_mm = false, + .coldboot_cal_ftm = false, .cbcal_restart_fw = false, .fw_mem_mode = 0, .num_vdevs = 16 + 1, @@ -332,7 +335,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_shadow_regs = false, .idle_ps = false, .supports_sta_ps = false, - .cold_boot_calib = false, + .coldboot_cal_mm = false, + .coldboot_cal_ftm = false, .cbcal_restart_fw = false, .fw_mem_mode = 2, .num_vdevs = 8, @@ -413,7 +417,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_shadow_regs = true, .idle_ps = true, .supports_sta_ps = true, - .cold_boot_calib = false, + .coldboot_cal_mm = false, + .coldboot_cal_ftm = false, .cbcal_restart_fw = false, .fw_mem_mode = 0, .num_vdevs = 16 + 1, @@ -495,7 +500,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_shadow_regs = true, .idle_ps = true, .supports_sta_ps = true, - .cold_boot_calib = false, + .coldboot_cal_mm = false, + .coldboot_cal_ftm = false, .cbcal_restart_fw = false, .fw_mem_mode = 0, .num_vdevs = 16 + 1, @@ -578,7 +584,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_shadow_regs = true, .idle_ps = true, .supports_sta_ps = true, - .cold_boot_calib = true, + .coldboot_cal_mm = true, + .coldboot_cal_ftm = true, .cbcal_restart_fw = false, .fw_mem_mode = 0, .num_vdevs = 16 + 1, @@ -667,7 +674,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_suspend = false, .hal_params = &ath11k_hw_hal_params_ipq8074, .single_pdev_only = false, - .cold_boot_calib = true, + .coldboot_cal_mm = true, + .coldboot_cal_ftm = true, .cbcal_restart_fw = true, .fix_l1ss = true, .supports_dynamic_smps_6ghz = false, @@ -749,6 +757,18 @@ void ath11k_fw_stats_free(struct ath11k_fw_stats *stats) ath11k_fw_stats_bcn_free(&stats->bcn); } +bool ath11k_core_coldboot_cal_support(struct ath11k_base *ab) +{ + if (!ath11k_cold_boot_cal) + return false; + + if (ath11k_ftm_mode) + return ab->hw_params.coldboot_cal_ftm; + + else + return ab->hw_params.coldboot_cal_mm; +} + int ath11k_core_suspend(struct ath11k_base *ab) { int ret; diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 9d15b4390b9c8..b044477624837 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -1186,6 +1186,7 @@ void ath11k_core_halt(struct ath11k *ar); int ath11k_core_resume(struct ath11k_base *ab); int ath11k_core_suspend(struct ath11k_base *ab); void ath11k_core_pre_reconfigure_recovery(struct ath11k_base *ab); +bool ath11k_core_coldboot_cal_support(struct ath11k_base *ab); const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab, const char *filename); diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index f5533630a7f9d..d51a99669dd6e 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -187,7 +187,8 @@ struct ath11k_hw_params { bool supports_shadow_regs; bool idle_ps; bool supports_sta_ps; - bool cold_boot_calib; + bool coldboot_cal_mm; + bool coldboot_cal_ftm; bool cbcal_restart_fw; int fw_mem_mode; u32 num_vdevs; diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index d4eaf7d2ba841..91a214caa8b50 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -2079,7 +2079,7 @@ static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab) return -EINVAL; } - if (ath11k_cold_boot_cal && ab->hw_params.cold_boot_calib) { + if (ath11k_core_coldboot_cal_support(ab)) { if (hremote_node) { ab->qmi.target_mem[idx].paddr = res.start + host_ddr_sz; @@ -3209,8 +3209,8 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work) break; } - if (ath11k_cold_boot_cal && ab->qmi.cal_done == 0 && - ab->hw_params.cold_boot_calib) { + if (ab->qmi.cal_done == 0 && + ath11k_core_coldboot_cal_support(ab)) { ath11k_qmi_process_coldboot_calibration(ab); } else { clear_bit(ATH11K_FLAG_CRASH_FLUSH, From bdfc967bf5fcd762473a01d39edb81f1165ba290 Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Wed, 26 Jul 2023 19:40:31 +0530 Subject: [PATCH 10/32] wifi: ath11k: Add coldboot calibration support for QCN9074 QCN9074 supports 6 GHz, which has increased number of channels compared to 5 GHz/2 GHz. So, to support coldboot calibration in QCN9074 ATH11K_COLD_BOOT_FW_RESET_DELAY extended to 60 seconds. To avoid code redundancy, fwreset_from_cold_boot moved to QMI and made common for both ahb and pci. Coldboot calibration is enabled only in FTM mode for QCN9074. QCN9074 requires firmware restart after coldboot, hence enable cbcal_restart_fw in hw_params. This support can be enabled/disabled using hw params for different hardware. Currently it is not enabled for QCA6390. Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Anilkumar Kolli Signed-off-by: Seevalamuthu Mariappan Signed-off-by: Raj Kumar Bhagat Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230726141032.3061-3-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath11k/ahb.c | 28 ++------------------------ drivers/net/wireless/ath/ath11k/core.c | 4 ++-- drivers/net/wireless/ath/ath11k/pci.c | 2 ++ drivers/net/wireless/ath/ath11k/qmi.c | 28 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/qmi.h | 3 ++- 5 files changed, 36 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 56aea2bc97871..b0a40970bada7 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -14,6 +14,7 @@ #include "ahb.h" #include "debug.h" #include "hif.h" +#include "qmi.h" #include #include "pcic.h" #include @@ -419,31 +420,6 @@ static void ath11k_ahb_power_down(struct ath11k_base *ab) rproc_shutdown(ab_ahb->tgt_rproc); } -static int ath11k_ahb_fwreset_from_cold_boot(struct ath11k_base *ab) -{ - int timeout; - - if (!ath11k_core_coldboot_cal_support(ab) || ab->qmi.cal_done || - ab->hw_params.cbcal_restart_fw == 0) - return 0; - - ath11k_dbg(ab, ATH11K_DBG_AHB, "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); - if (timeout <= 0) { - ath11k_cold_boot_cal = 0; - ath11k_warn(ab, "Coldboot Calibration failed timed out\n"); - } - - /* reset the firmware */ - ath11k_ahb_power_down(ab); - ath11k_ahb_power_up(ab); - - ath11k_dbg(ab, ATH11K_DBG_AHB, "exited from cold boot mode\n"); - return 0; -} - static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base *ab) { struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; @@ -1226,7 +1202,7 @@ static int ath11k_ahb_probe(struct platform_device *pdev) goto err_ce_free; } - ath11k_ahb_fwreset_from_cold_boot(ab); + ath11k_qmi_fwreset_from_cold_boot(ab); return 0; diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index d5bf2896d8c59..fc7c4564a715c 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -336,8 +336,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .idle_ps = false, .supports_sta_ps = false, .coldboot_cal_mm = false, - .coldboot_cal_ftm = false, - .cbcal_restart_fw = false, + .coldboot_cal_ftm = true, + .cbcal_restart_fw = true, .fw_mem_mode = 2, .num_vdevs = 8, .num_peers = 128, diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 79e2cbe826384..5fd08ffc2a9f6 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -15,6 +15,7 @@ #include "mhi.h" #include "debug.h" #include "pcic.h" +#include "qmi.h" #define ATH11K_PCI_BAR_NUM 0 #define ATH11K_PCI_DMA_MASK 32 @@ -897,6 +898,7 @@ static int ath11k_pci_probe(struct pci_dev *pdev, ath11k_err(ab, "failed to init core: %d\n", ret); goto err_irq_affinity_cleanup; } + ath11k_qmi_fwreset_from_cold_boot(ab); return 0; err_irq_affinity_cleanup: diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index 91a214caa8b50..c4eab5d7f5c56 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -9,6 +9,7 @@ #include "qmi.h" #include "core.h" #include "debug.h" +#include "hif.h" #include #include #include @@ -2839,6 +2840,33 @@ int ath11k_qmi_firmware_start(struct ath11k_base *ab, return 0; } +int ath11k_qmi_fwreset_from_cold_boot(struct ath11k_base *ab) +{ + int timeout; + + if (!ath11k_core_coldboot_cal_support(ab) || ab->qmi.cal_done || + ab->hw_params.cbcal_restart_fw == 0) + return 0; + + 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); + + if (timeout <= 0) { + ath11k_warn(ab, "Coldboot Calibration timed out\n"); + return -ETIMEDOUT; + } + + /* reset the firmware */ + ath11k_hif_power_down(ab); + ath11k_hif_power_up(ab); + ath11k_dbg(ab, ATH11K_DBG_QMI, "exit wait for cold boot done\n"); + return 0; +} +EXPORT_SYMBOL(ath11k_qmi_fwreset_from_cold_boot); + static int ath11k_qmi_process_coldboot_calibration(struct ath11k_base *ab) { int timeout; diff --git a/drivers/net/wireless/ath/ath11k/qmi.h b/drivers/net/wireless/ath/ath11k/qmi.h index 0909d53cefebc..b0407abf90cd9 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.h +++ b/drivers/net/wireless/ath/ath11k/qmi.h @@ -37,7 +37,7 @@ #define QMI_WLANFW_MAX_DATA_SIZE_V01 6144 #define ATH11K_FIRMWARE_MODE_OFF 4 -#define ATH11K_COLD_BOOT_FW_RESET_DELAY (40 * HZ) +#define ATH11K_COLD_BOOT_FW_RESET_DELAY (60 * HZ) #define ATH11K_QMI_DEVICE_BAR_SIZE 0x200000 @@ -519,5 +519,6 @@ void ath11k_qmi_msg_recv_work(struct work_struct *work); void ath11k_qmi_deinit_service(struct ath11k_base *ab); int ath11k_qmi_init_service(struct ath11k_base *ab); void ath11k_qmi_free_resource(struct ath11k_base *ab); +int ath11k_qmi_fwreset_from_cold_boot(struct ath11k_base *ab); #endif From 13329d0cb7212b058bd8451a99d215a8f97645ea Mon Sep 17 00:00:00 2001 From: Seevalamuthu Mariappan Date: Wed, 26 Jul 2023 19:40:32 +0530 Subject: [PATCH 11/32] wifi: ath11k: Remove cal_done check during probe In some race conditions, calibration done QMI message is received even before host wait starts for calibration to be done. Due to this, resetting firmware was not performed after calibration. Hence, remove cal_done check in ath11k_qmi_fwreset_from_cold_boot() as this is called only from probe. Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Seevalamuthu Mariappan Signed-off-by: Raj Kumar Bhagat Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230726141032.3061-4-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath11k/qmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index c4eab5d7f5c56..617abb441882b 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -2844,7 +2844,7 @@ int ath11k_qmi_fwreset_from_cold_boot(struct ath11k_base *ab) { int timeout; - if (!ath11k_core_coldboot_cal_support(ab) || ab->qmi.cal_done || + if (!ath11k_core_coldboot_cal_support(ab) || ab->hw_params.cbcal_restart_fw == 0) return 0; From 8ad314da54c6dd223a6b6cc85019160aa842f659 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Wed, 26 Jul 2023 05:26:25 -0400 Subject: [PATCH 12/32] wifi: ath12k: Fix a NULL pointer dereference in ath12k_mac_op_hw_scan() In ath12k_mac_op_hw_scan(), the return value of kzalloc() is directly used in memcpy(), which may lead to a NULL pointer dereference on failure of kzalloc(). Fix this bug by adding a check of arg.extraie.ptr. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Wen Gong Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230726092625.3350-1-quic_wgong@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 1bb9802ef5696..af46b63bb15bc 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -2755,9 +2755,12 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, arg.scan_id = ATH12K_SCAN_ID; if (req->ie_len) { + arg.extraie.ptr = kmemdup(req->ie, req->ie_len, GFP_KERNEL); + if (!arg.extraie.ptr) { + ret = -ENOMEM; + goto exit; + } arg.extraie.len = req->ie_len; - arg.extraie.ptr = kzalloc(req->ie_len, GFP_KERNEL); - memcpy(arg.extraie.ptr, req->ie, req->ie_len); } if (req->n_ssids) { From 15c8441dc1eddb9a19c75a0742edc9f002625931 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Wed, 26 Jul 2023 05:38:57 -0400 Subject: [PATCH 13/32] wifi: ath12k: correct the data_type from QMI_OPT_FLAG to QMI_UNSIGNED_1_BYTE for mlo_capable Currently, the encoding rule for field mlo_capable in struct qmi_wlanfw_host_cap_req_msg_v01 defined in array qmi_wlanfw_host_cap_req_msg_v01_ei uses type QMI_OPT_FLAG. Unfortunately, all ath12k firmware actually expects this field to be of type NON QMI_OPT_FLAG such as QMI_UNSIGNED_1_BYTE/QMI_UNSIGNED_8_BYTE... And as a result, firmware is unable to correctly decode the mlo_capable field. Change the ath12k definition as QMI_UNSIGNED_1_BYTE to match the firmware definition so that firmware can correctly parse the mlo_capable info from message QMI_WLANFW_HOST_CAP_REQ_V01 at wlan load time. This is just an accidental typo and that both WCN7850 and QCN9274 firmwares use QMI_UNSIGNED_1_BYTE. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Wen Gong Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230726093857.3610-1-quic_wgong@quicinc.com --- drivers/net/wireless/ath/ath12k/qmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index b510c2de1bd43..b2db0436bdde6 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -387,7 +387,7 @@ static struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = { mlo_capable_valid), }, { - .data_type = QMI_OPT_FLAG, + .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), .array_type = NO_ARRAY, From 603cf6c2fcdcbc38f1daa316794e7268852677a7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 3 Jul 2023 14:37:29 +0200 Subject: [PATCH 14/32] wifi: ath12k: fix memcpy array overflow in ath12k_peer_assoc_h_he() Two memory copies in this function copy from a short array into a longer one, using the wrong size, which leads to an out-of-bounds access: include/linux/fortify-string.h:592:4: error: call to '__read_overflow2_field' declared with 'warning' attribute: detected read beyond size of field (2nd parameter); maybe use struct_group()? [-Werror,-Wattribute-warning] __read_overflow2_field(q_size_field, size); ^ include/linux/fortify-string.h:592:4: error: call to '__read_overflow2_field' declared with 'warning' attribute: detected read beyond size of field (2nd parameter); maybe use struct_group()? [-Werror,-Wattribute-warning] 2 errors generated. Fixes: d889913205cf7 ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230703123737.3420464-1-arnd@kernel.org --- 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 af46b63bb15bc..d165b24094ad5 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -1637,9 +1637,9 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar, arg->peer_nss = min(sta->deflink.rx_nss, max_nss); memcpy(&arg->peer_he_cap_macinfo, he_cap->he_cap_elem.mac_cap_info, - sizeof(arg->peer_he_cap_macinfo)); + sizeof(he_cap->he_cap_elem.mac_cap_info)); memcpy(&arg->peer_he_cap_phyinfo, he_cap->he_cap_elem.phy_cap_info, - sizeof(arg->peer_he_cap_phyinfo)); + sizeof(he_cap->he_cap_elem.phy_cap_info)); arg->peer_he_ops = vif->bss_conf.he_oper.params; /* the top most byte is used to indicate BSS color info */ From 1e9b1363e2de1552ee4e3d74ac8bb43a194f1cb4 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Fri, 14 Jul 2023 03:24:05 -0400 Subject: [PATCH 15/32] wifi: ath12k: avoid array overflow of hw mode for preferred_hw_mode Currently ath12k define WMI_HOST_HW_MODE_DBS_OR_SBS=5 as max hw mode for enum wmi_host_hw_mode_config_type, it is also same for the array ath12k_hw_mode_pri_map. When tested with new version firmware/board data which support new hw mode eMLSR mode with hw mode value 8, it leads overflow usage for array ath12k_hw_mode_pri_map in function ath12k_wmi_hw_mode_caps(), and then lead preferred_hw_mode changed to 8, and finally function ath12k_pull_mac_phy_cap_svc_ready_ext() select the capability of hw mode 8, but the capability of eMLSR mode report from firmware does not support 2.4 GHz band for WCN7850, so finally 2.4 GHz band is disabled. Skip the hw mode which exceeds WMI_HOST_HW_MODE_MAX in function ath12k_wmi_hw_mode_caps() helps to avoid array overflow, then the 2.4 GHz band will not be disabled. This is to keep compatibility with newer version firmware/board data files, this change is still needed after ath12k add eMLSR hw mode 8 in array ath12k_hw_mode_pri_map and enum wmi_host_hw_mode_config_type, because more hw mode maybe added in next firmware/board data version e.g hw mode 9, then it will also lead new array overflow without this change. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Wen Gong Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230714072405.28705-1-quic_wgong@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 6512267ae4ca5..e6033ab158255 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -3705,6 +3705,10 @@ static int ath12k_wmi_hw_mode_caps(struct ath12k_base *soc, for (i = 0 ; i < svc_rdy_ext->n_hw_mode_caps; i++) { hw_mode_caps = &svc_rdy_ext->hw_mode_caps[i]; mode = le32_to_cpu(hw_mode_caps->hw_mode_id); + + if (mode >= WMI_HOST_HW_MODE_MAX) + continue; + pref = soc->wmi_ab.preferred_hw_mode; if (ath12k_hw_mode_pri_map[mode] < ath12k_hw_mode_pri_map[pref]) { From 7ee027abd4533d53438ccafdd3ba7a68a16aae8d Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Fri, 14 Jul 2023 16:06:58 +0800 Subject: [PATCH 16/32] wifi: ath12k: Use pdev_id rather than mac_id to get pdev We are seeing kernel crash in below test scenario: 1. make DUT connect to an WPA3 encrypted 11ax AP in Ch44 HE80 2. use "wpa_cli -i disconnect" to disconnect 3. wait for DUT to automatically reconnect Kernel crashes while waiting, below shows the crash stack: [ 755.120868] BUG: kernel NULL pointer dereference, address: 0000000000000000 [ 755.120871] #PF: supervisor read access in kernel mode [ 755.120872] #PF: error_code(0x0000) - not-present page [ 755.120873] PGD 0 P4D 0 [ 755.120875] Oops: 0000 [#1] PREEMPT SMP NOPTI [ 755.120876] CPU: 7 PID: 0 Comm: swapper/7 Kdump: loaded Not tainted 5.19.0-rc1+ #3 [ 755.120878] Hardware name: Intel(R) Client Systems NUC11PHi7/NUC11PHBi7, BIOS PHTGL579.0063.2021.0707.1057 07/07/2021 [ 755.120879] RIP: 0010:ath12k_dp_process_rx_err+0x2b6/0x14a0 [ath12k] [ 755.120890] Code: 01 c0 48 c1 e0 05 48 8b 9c 07 b8 b2 00 00 48 c7 c0 61 ff 0e c1 48 85 db 53 48 0f 44 c6 48 c7 c6 80 9d 0f c1 50 e8 1a 25 00 00 <4c> 8b 3b 4d 8b 76 14 41 59 41 5a 41 8b 87 78 43 01 00 4d 85 f6 89 [ 755.120891] RSP: 0018:ffff9a93402c8d10 EFLAGS: 00010282 [ 755.120892] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000303 [ 755.120893] RDX: 0000000000000000 RSI: ffffffff93b7cbe9 RDI: 00000000ffffffff [ 755.120894] RBP: ffff9a93402c8e50 R08: ffffffff93e65360 R09: ffffffff942e044d [ 755.120894] R10: 0000000000000000 R11: 0000000000000063 R12: ffff8dbec5420000 [ 755.120895] R13: ffff8dbec5420000 R14: ffff8dbdefe9a0a0 R15: ffff8dbec5420000 [ 755.120896] FS: 0000000000000000(0000) GS:ffff8dc2705c0000(0000) knlGS:0000000000000000 [ 755.120897] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 755.120898] CR2: 0000000000000000 CR3: 0000000107be4005 CR4: 0000000000770ee0 [ 755.120898] PKRU: 55555554 [ 755.120899] Call Trace: [ 755.120900] [ 755.120903] ? ath12k_pci_write32+0x2e/0x80 [ath12k] [ 755.120910] ath12k_dp_service_srng+0x214/0x2e0 [ath12k] [ 755.120917] ath12k_pci_ext_grp_napi_poll+0x26/0x80 [ath12k] [ 755.120923] __napi_poll+0x2b/0x1c0 [ 755.120925] net_rx_action+0x2a1/0x2f0 [ 755.120927] __do_softirq+0xfa/0x2e9 [ 755.120929] irq_exit_rcu+0xb9/0xd0 [ 755.120932] common_interrupt+0xc1/0xe0 [ 755.120934] [ 755.120934] [ 755.120935] asm_common_interrupt+0x2c/0x40 [ 755.120936] RIP: 0010:cpuidle_enter_state+0xdd/0x3a0 [ 755.120938] Code: 00 31 ff e8 45 e2 74 ff 80 7d d7 00 74 16 9c 58 0f 1f 40 00 f6 c4 02 0f 85 a0 02 00 00 31 ff e8 69 79 7b ff fb 0f 1f 44 00 00 <45> 85 ff 0f 88 6d 01 00 00 49 63 d7 4c 2b 6d c8 48 8d 04 52 48 8d [ 755.120939] RSP: 0018:ffff9a934018be50 EFLAGS: 00000246 [ 755.120940] RAX: ffff8dc2705c0000 RBX: 0000000000000002 RCX: 000000000000001f [ 755.120941] RDX: 000000afd0b532d3 RSI: ffffffff93b7cbe9 RDI: ffffffff93b8b66e [ 755.120942] RBP: ffff9a934018be88 R08: 0000000000000002 R09: 0000000000030500 [ 755.120942] R10: ffff9a934018be18 R11: 0000000000000741 R12: ffffba933fdc0600 [ 755.120943] R13: 000000afd0b532d3 R14: ffffffff93fcbc60 R15: 0000000000000002 [ 755.120945] cpuidle_enter+0x2e/0x40 [ 755.120946] call_cpuidle+0x23/0x40 [ 755.120948] do_idle+0x1ff/0x260 [ 755.120950] cpu_startup_entry+0x1d/0x20 [ 755.120951] start_secondary+0x10d/0x130 [ 755.120953] secondary_startup_64_no_verify+0xd3/0xdb [ 755.120956] [ 755.120956] Modules linked in: michael_mic rfcomm cmac algif_hash algif_skcipher af_alg bnep qrtr_mhi intel_rapl_msr intel_rapl_common x86_pkg_temp_thermal intel_powerclamp coretemp snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio kvm_intel qrtr snd_hda_codec_hdmi kvm irqbypass ath12k snd_hda_intel snd_seq_midi crct10dif_pclmul mhi ghash_clmulni_intel snd_intel_dspcfg snd_seq_midi_event aesni_intel qmi_helpers i915 snd_rawmidi crypto_simd snd_hda_codec cryptd cec intel_cstate snd_hda_core mac80211 rc_core nouveau snd_seq snd_hwdep btusb drm_buddy drm_ttm_helper nls_iso8859_1 snd_pcm ttm btrtl snd_seq_device wmi_bmof mxm_wmi input_leds cfg80211 joydev btbcm drm_display_helper snd_timer btintel mei_me libarc4 drm_kms_helper bluetooth i2c_algo_bit snd fb_sys_fops syscopyarea mei sysfillrect ecdh_generic soundcore sysimgblt ecc acpi_pad mac_hid sch_fq_codel ipmi_devintf ipmi_msghandler msr parport_pc ppdev lp ramoops parport reed_solomon drm efi_pstore ip_tables x_tables autofs4 [ 755.120992] hid_generic usbhid hid ax88179_178a usbnet mii nvme nvme_core rtsx_pci_sdmmc crc32_pclmul i2c_i801 intel_lpss_pci i2c_smbus intel_lpss rtsx_pci idma64 virt_dma vmd wmi video [ 755.121002] CR2: 0000000000000000 The crash is because, for WCN7850, only ab->pdev[0] is initialized, while mac_id here is misused to retrieve pdev and it is not zero, leading to a NULL pointer access. Fix this issue by getting pdev_id first and then use it to retrieve pdev. Also fix some other code snippets which have the same issue. 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 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230714080658.3140-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_rx.c | 11 +++++++---- drivers/net/wireless/ath/ath12k/dp_tx.c | 8 +++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index ffd9a2018610f..67f8c140840fb 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -2539,7 +2539,7 @@ static void ath12k_dp_rx_process_received_packets(struct ath12k_base *ab, struct ath12k_skb_rxcb *rxcb; struct sk_buff *msdu; struct ath12k *ar; - u8 mac_id; + u8 mac_id, pdev_id; int ret; if (skb_queue_empty(msdu_list)) @@ -2550,8 +2550,9 @@ static void ath12k_dp_rx_process_received_packets(struct ath12k_base *ab, while ((msdu = __skb_dequeue(msdu_list))) { rxcb = ATH12K_SKB_RXCB(msdu); mac_id = rxcb->mac_id; - ar = ab->pdevs[mac_id].ar; - if (!rcu_dereference(ab->pdevs_active[mac_id])) { + pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id); + ar = ab->pdevs[pdev_id].ar; + if (!rcu_dereference(ab->pdevs_active[pdev_id])) { dev_kfree_skb_any(msdu); continue; } @@ -3385,6 +3386,7 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, dma_addr_t paddr; bool is_frag; bool drop = false; + int pdev_id; tot_n_bufs_reaped = 0; quota = budget; @@ -3440,7 +3442,8 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, mac_id = le32_get_bits(reo_desc->info0, HAL_REO_DEST_RING_INFO0_SRC_LINK_ID); - ar = ab->pdevs[mac_id].ar; + pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id); + ar = ab->pdevs[pdev_id].ar; if (!ath12k_dp_process_rx_err_buf(ar, reo_desc, drop, msdu_cookies[i])) diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index d3c7c76d6b75e..d661fe586651f 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -347,6 +347,7 @@ static void ath12k_dp_tx_free_txbuf(struct ath12k_base *ab, { struct ath12k *ar; struct ath12k_skb_cb *skb_cb; + u8 pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id); skb_cb = ATH12K_SKB_CB(msdu); @@ -357,7 +358,7 @@ static void ath12k_dp_tx_free_txbuf(struct ath12k_base *ab, dev_kfree_skb_any(msdu); - ar = ab->pdevs[mac_id].ar; + ar = ab->pdevs[pdev_id].ar; if (atomic_dec_and_test(&ar->dp.num_tx_pending)) wake_up(&ar->dp.tx_empty_waitq); } @@ -536,7 +537,7 @@ void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id) struct hal_tx_status ts = { 0 }; struct dp_tx_ring *tx_ring = &dp->tx_ring[ring_id]; struct hal_wbm_release_ring *desc; - u8 mac_id; + u8 mac_id, pdev_id; u64 desc_va; spin_lock_bh(&status_ring->lock); @@ -605,7 +606,8 @@ void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id) continue; } - ar = ab->pdevs[mac_id].ar; + pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id); + ar = ab->pdevs[pdev_id].ar; if (atomic_dec_and_test(&ar->dp.num_tx_pending)) wake_up(&ar->dp.tx_empty_waitq); From 68c35cc39b41dca8f6cb54915bdfd60dd7397b01 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Fri, 14 Jul 2023 05:25:55 -0400 Subject: [PATCH 17/32] wifi: ath12k: trigger station disconnect on hardware restart Currently after the hardware restart triggered from the driver, the station interface connection remains intact, since a disconnect trigger is not sent to userspace. This can lead to a problem in targets where the wifi mac sequence is added by the firmware. After the target restart, its wifi mac sequence number gets reset to zero. Hence AP to which our device is connected will receive frames with a wifi mac sequence number jump to the past, thereby resulting in the AP dropping all these frames, until the frame arrives with a wifi mac sequence number which AP was expecting. To avoid such frame drops, its better to trigger a station disconnect upon target hardware restart which can be done with API ieee80211_reconfig_disconnect exposed to mac80211. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Wen Gong Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230714092555.2018-1-quic_wgong@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index d165b24094ad5..13f477eb4707f 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -6391,6 +6391,7 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, { struct ath12k *ar = hw->priv; struct ath12k_base *ab = ar->ab; + struct ath12k_vif *arvif; int recovery_count; if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART) @@ -6419,6 +6420,26 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, ath12k_dbg(ab, ATH12K_DBG_BOOT, "reset success\n"); } } + + list_for_each_entry(arvif, &ar->arvifs, list) { + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "reconfig cipher %d up %d vdev type %d\n", + arvif->key_cipher, + arvif->is_up, + arvif->vdev_type); + /* After trigger disconnect, then upper layer will + * trigger connect again, then the PN number of + * upper layer will be reset to keep up with AP + * side, hence PN number mis-match will not happened. + */ + if (arvif->is_up && + arvif->vdev_type == WMI_VDEV_TYPE_STA && + arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) { + ieee80211_hw_restart_disconnect(arvif->vif); + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "restart disconnect\n"); + } + } } mutex_unlock(&ar->conf_mutex); From 3742928a52d6859731d525f06c09decff87ffa01 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Sun, 16 Jul 2023 23:34:31 -0400 Subject: [PATCH 18/32] wifi: ath12k: change to use dynamic memory for channel list of scan Currently there are about 60 channels for 6 GHz, then the size of chan_list in struct scan_req_params which is 40 is not enough to fill all the channel list of 6 GHz. Use dynamic memory to save the channel list of scan. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Wen Gong Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230717033431.21983-1-quic_wgong@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 10 ++++++++++ drivers/net/wireless/ath/ath12k/wmi.h | 3 +-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 13f477eb4707f..4fa565a115e34 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -2773,6 +2773,14 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, if (req->n_channels) { arg.num_chan = req->n_channels; + arg.chan_list = kcalloc(arg.num_chan, sizeof(*arg.chan_list), + GFP_KERNEL); + + if (!arg.chan_list) { + ret = -ENOMEM; + goto exit; + } + for (i = 0; i < arg.num_chan; i++) arg.chan_list[i] = req->channels[i]->center_freq; } @@ -2791,6 +2799,8 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, ATH12K_MAC_SCAN_TIMEOUT_MSECS)); exit: + kfree(arg.chan_list); + if (req->ie_len) kfree(arg.extraie.ptr); diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index d89c12bfb009f..9b8ba87049047 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -3034,7 +3034,6 @@ enum scan_dwelltime_adaptive_mode { #define WLAN_SCAN_MAX_NUM_SSID 10 #define WLAN_SCAN_MAX_NUM_BSSID 10 -#define WLAN_SCAN_MAX_NUM_CHANNELS 40 struct ath12k_wmi_element_info_arg { u32 len; @@ -3243,7 +3242,7 @@ struct ath12k_wmi_scan_req_arg { u32 num_bssid; u32 num_ssids; u32 n_probes; - u32 chan_list[WLAN_SCAN_MAX_NUM_CHANNELS]; + u32 *chan_list; u32 notify_scan_events; struct cfg80211_ssid ssid[WLAN_SCAN_MAX_NUM_SSID]; struct ath12k_wmi_mac_addr_params bssid_list[WLAN_SCAN_MAX_NUM_BSSID]; From e22f5b780c691ae2ed0d5e7743ccd6183baf5dc2 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Wed, 2 Aug 2023 20:04:00 +0300 Subject: [PATCH 19/32] wifi: ath12k: rename HE capabilities setup/copy functions Functions ath12k_mac_setup_he_cap() and ath12k_mac_copy_he_cap() propagate HE and 6GHz capabilities to the userspace using an instance of struct ieee80211_sband_iftype_data. This structure now has a new member 'eht_cap' to include EHT capabilities as well. Rename the above mentioned functions to indicate that their use is not limited to HE. Also, replace the local variable 'band' with 'sband' and reuse 'band' for the type enum nl80211_band. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230725224034.14045-2-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 58 ++++++++++++++------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 4fa565a115e34..4d04b6f67043c 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -4222,10 +4222,10 @@ static __le16 ath12k_mac_setup_he_6ghz_cap(struct ath12k_pdev_cap *pcap, return cpu_to_le16(bcap->he_6ghz_capa); } -static int ath12k_mac_copy_he_cap(struct ath12k *ar, - struct ath12k_pdev_cap *cap, - struct ieee80211_sband_iftype_data *data, - int band) +static int ath12k_mac_copy_sband_iftype_data(struct ath12k *ar, + struct ath12k_pdev_cap *cap, + struct ieee80211_sband_iftype_data *data, + int band) { int i, idx = 0; @@ -4310,38 +4310,42 @@ static int ath12k_mac_copy_he_cap(struct ath12k *ar, return idx; } -static void ath12k_mac_setup_he_cap(struct ath12k *ar, - struct ath12k_pdev_cap *cap) +static void ath12k_mac_setup_sband_iftype_data(struct ath12k *ar, + struct ath12k_pdev_cap *cap) { - struct ieee80211_supported_band *band; + struct ieee80211_supported_band *sband; + enum nl80211_band band; int count; if (cap->supported_bands & WMI_HOST_WLAN_2G_CAP) { - count = ath12k_mac_copy_he_cap(ar, cap, - ar->mac.iftype[NL80211_BAND_2GHZ], - NL80211_BAND_2GHZ); - band = &ar->mac.sbands[NL80211_BAND_2GHZ]; - band->iftype_data = ar->mac.iftype[NL80211_BAND_2GHZ]; - band->n_iftype_data = count; + band = NL80211_BAND_2GHZ; + count = ath12k_mac_copy_sband_iftype_data(ar, cap, + ar->mac.iftype[band], + band); + sband = &ar->mac.sbands[band]; + sband->iftype_data = ar->mac.iftype[band]; + sband->n_iftype_data = count; } if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP) { - count = ath12k_mac_copy_he_cap(ar, cap, - ar->mac.iftype[NL80211_BAND_5GHZ], - NL80211_BAND_5GHZ); - band = &ar->mac.sbands[NL80211_BAND_5GHZ]; - band->iftype_data = ar->mac.iftype[NL80211_BAND_5GHZ]; - band->n_iftype_data = count; + band = NL80211_BAND_5GHZ; + count = ath12k_mac_copy_sband_iftype_data(ar, cap, + ar->mac.iftype[band], + band); + sband = &ar->mac.sbands[band]; + sband->iftype_data = ar->mac.iftype[band]; + sband->n_iftype_data = count; } if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP && ar->supports_6ghz) { - count = ath12k_mac_copy_he_cap(ar, cap, - ar->mac.iftype[NL80211_BAND_6GHZ], - NL80211_BAND_6GHZ); - band = &ar->mac.sbands[NL80211_BAND_6GHZ]; - band->iftype_data = ar->mac.iftype[NL80211_BAND_6GHZ]; - band->n_iftype_data = count; + band = NL80211_BAND_6GHZ; + count = ath12k_mac_copy_sband_iftype_data(ar, cap, + ar->mac.iftype[band], + band); + sband = &ar->mac.sbands[band]; + sband->iftype_data = ar->mac.iftype[band]; + sband->n_iftype_data = count; } } @@ -4386,7 +4390,7 @@ static int __ath12k_set_antenna(struct ath12k *ar, u32 tx_ant, u32 rx_ant) /* Reload HT/VHT/HE capability */ ath12k_mac_setup_ht_vht_cap(ar, &ar->pdev->cap, NULL); - ath12k_mac_setup_he_cap(ar, &ar->pdev->cap); + ath12k_mac_setup_sband_iftype_data(ar, &ar->pdev->cap); return 0; } @@ -6888,7 +6892,7 @@ static int __ath12k_mac_register(struct ath12k *ar) goto err; ath12k_mac_setup_ht_vht_cap(ar, cap, &ht_cap); - ath12k_mac_setup_he_cap(ar, cap); + ath12k_mac_setup_sband_iftype_data(ar, cap); ret = ath12k_mac_setup_iface_combinations(ar); if (ret) { From a7a6a45d37fe868b30363255d3a37a44acd1cf37 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Wed, 2 Aug 2023 20:04:01 +0300 Subject: [PATCH 20/32] wifi: ath12k: move HE capabilities processing to a new function The function ath12k_mac_copy_sband_iftype_data() is currently used HE capabilities propagation but it can be extended to include EHT data. Move the HE specific functionality from to ath12k_mac_copy_he_cap() to make EHT additions easier. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230725224034.14045-3-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 111 +++++++++++++------------- 1 file changed, 55 insertions(+), 56 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 4d04b6f67043c..8fedbf4879d6d 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -4222,18 +4222,69 @@ static __le16 ath12k_mac_setup_he_6ghz_cap(struct ath12k_pdev_cap *pcap, return cpu_to_le16(bcap->he_6ghz_capa); } +static void ath12k_mac_copy_he_cap(struct ath12k_band_cap *band_cap, + int iftype, u8 num_tx_chains, + struct ieee80211_sta_he_cap *he_cap) +{ + struct ieee80211_he_cap_elem *he_cap_elem = &he_cap->he_cap_elem; + struct ieee80211_he_mcs_nss_supp *mcs_nss = &he_cap->he_mcs_nss_supp; + + he_cap->has_he = true; + memcpy(he_cap_elem->mac_cap_info, band_cap->he_cap_info, + sizeof(he_cap_elem->mac_cap_info)); + memcpy(he_cap_elem->phy_cap_info, band_cap->he_cap_phy_info, + sizeof(he_cap_elem->phy_cap_info)); + + he_cap_elem->mac_cap_info[1] &= + IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK; + + he_cap_elem->phy_cap_info[5] &= + ~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK; + he_cap_elem->phy_cap_info[5] &= + ~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK; + he_cap_elem->phy_cap_info[5] |= num_tx_chains - 1; + + switch (iftype) { + case NL80211_IFTYPE_AP: + he_cap_elem->phy_cap_info[3] &= + ~IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK; + he_cap_elem->phy_cap_info[9] |= + IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU; + break; + case NL80211_IFTYPE_STATION: + he_cap_elem->mac_cap_info[0] &= ~IEEE80211_HE_MAC_CAP0_TWT_RES; + he_cap_elem->mac_cap_info[0] |= IEEE80211_HE_MAC_CAP0_TWT_REQ; + he_cap_elem->phy_cap_info[9] |= + IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU; + break; + case NL80211_IFTYPE_MESH_POINT: + ath12k_mac_filter_he_cap_mesh(he_cap_elem); + break; + } + + mcs_nss->rx_mcs_80 = cpu_to_le16(band_cap->he_mcs & 0xffff); + mcs_nss->tx_mcs_80 = cpu_to_le16(band_cap->he_mcs & 0xffff); + mcs_nss->rx_mcs_160 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); + mcs_nss->tx_mcs_160 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); + mcs_nss->rx_mcs_80p80 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); + mcs_nss->tx_mcs_80p80 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); + + memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres)); + if (he_cap_elem->phy_cap_info[6] & + IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) + ath12k_gen_ppe_thresh(&band_cap->he_ppet, he_cap->ppe_thres); +} + static int ath12k_mac_copy_sband_iftype_data(struct ath12k *ar, struct ath12k_pdev_cap *cap, struct ieee80211_sband_iftype_data *data, int band) { + struct ath12k_band_cap *band_cap = &cap->band[band]; int i, idx = 0; for (i = 0; i < NUM_NL80211_IFTYPES; i++) { struct ieee80211_sta_he_cap *he_cap = &data[idx].he_cap; - struct ath12k_band_cap *band_cap = &cap->band[band]; - struct ieee80211_he_cap_elem *he_cap_elem = - &he_cap->he_cap_elem; switch (i) { case NL80211_IFTYPE_STATION: @@ -4246,60 +4297,8 @@ static int ath12k_mac_copy_sband_iftype_data(struct ath12k *ar, } data[idx].types_mask = BIT(i); - he_cap->has_he = true; - memcpy(he_cap_elem->mac_cap_info, band_cap->he_cap_info, - sizeof(he_cap_elem->mac_cap_info)); - memcpy(he_cap_elem->phy_cap_info, band_cap->he_cap_phy_info, - sizeof(he_cap_elem->phy_cap_info)); - - he_cap_elem->mac_cap_info[1] &= - IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK; - - he_cap_elem->phy_cap_info[5] &= - ~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK; - he_cap_elem->phy_cap_info[5] &= - ~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK; - he_cap_elem->phy_cap_info[5] |= ar->num_tx_chains - 1; - - switch (i) { - case NL80211_IFTYPE_AP: - he_cap_elem->phy_cap_info[3] &= - ~IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK; - he_cap_elem->phy_cap_info[9] |= - IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU; - break; - case NL80211_IFTYPE_STATION: - he_cap_elem->mac_cap_info[0] &= - ~IEEE80211_HE_MAC_CAP0_TWT_RES; - he_cap_elem->mac_cap_info[0] |= - IEEE80211_HE_MAC_CAP0_TWT_REQ; - he_cap_elem->phy_cap_info[9] |= - IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU; - break; - case NL80211_IFTYPE_MESH_POINT: - ath12k_mac_filter_he_cap_mesh(he_cap_elem); - break; - } - - he_cap->he_mcs_nss_supp.rx_mcs_80 = - cpu_to_le16(band_cap->he_mcs & 0xffff); - he_cap->he_mcs_nss_supp.tx_mcs_80 = - cpu_to_le16(band_cap->he_mcs & 0xffff); - he_cap->he_mcs_nss_supp.rx_mcs_160 = - cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); - he_cap->he_mcs_nss_supp.tx_mcs_160 = - cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); - he_cap->he_mcs_nss_supp.rx_mcs_80p80 = - cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); - he_cap->he_mcs_nss_supp.tx_mcs_80p80 = - cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); - - memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres)); - if (he_cap_elem->phy_cap_info[6] & - IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) - ath12k_gen_ppe_thresh(&band_cap->he_ppet, - he_cap->ppe_thres); + ath12k_mac_copy_he_cap(band_cap, i, ar->num_tx_chains, he_cap); if (band == NL80211_BAND_6GHZ) { data[idx].he_6ghz_capa.capa = ath12k_mac_setup_he_6ghz_cap(cap, band_cap); From 1476014fadb6625c6720c4439ff0c4b5b5431137 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Wed, 2 Aug 2023 20:04:02 +0300 Subject: [PATCH 21/32] wifi: ath12k: WMI support to process EHT capabilities Add WMI support to process the EHT capabilities passed by the firmware. Add required EHT specific definitions in structures ath12k_band_cap and ath12k_wmi_svc_rdy_ext_parse. For single_pdev chip such as WCN7850, only one pdev is created and only one hardware is registered to mac80211. This one pdev manages both 2.4 GHz radio and 5 GHz/6 GHz 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-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Aloka Dixit Co-developed-by: Pradeep Kumar Chitrapu Signed-off-by: Pradeep Kumar Chitrapu Co-developed-by: Wen Gong Signed-off-by: Wen Gong Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230725224034.14045-4-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath12k/core.h | 33 ++++++ drivers/net/wireless/ath/ath12k/wmi.c | 147 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/wmi.h | 38 +++++++ 3 files changed, 218 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 2f93296db792a..d0b625fea6336 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -580,6 +580,14 @@ struct ath12k_band_cap { u32 he_cap_phy_info[PSOC_HOST_MAX_PHY_SIZE]; struct ath12k_wmi_ppe_threshold_arg he_ppet; u16 he_6ghz_capa; + u32 eht_cap_mac_info[WMI_MAX_EHTCAP_MAC_SIZE]; + u32 eht_cap_phy_info[WMI_MAX_EHTCAP_PHY_SIZE]; + u32 eht_mcs_20_only; + u32 eht_mcs_80; + u32 eht_mcs_160; + u32 eht_mcs_320; + struct ath12k_wmi_ppe_threshold_arg eht_ppet; + u32 eht_cap_info_internal; }; struct ath12k_pdev_cap { @@ -614,6 +622,12 @@ struct ath12k_pdev { struct mlo_timestamp timestamp; }; +struct ath12k_fw_pdev { + u32 pdev_id; + u32 phy_id; + u32 supported_bands; +}; + struct ath12k_board_data { const struct firmware *fw; const void *data; @@ -669,7 +683,26 @@ struct ath12k_base { struct mutex core_lock; /* Protects data like peers */ spinlock_t base_lock; + + /* Single pdev device (struct ath12k_hw_params::single_pdev_only): + * + * Firmware maintains data for all bands but advertises a single + * phy to the host which is stored as a single element in this + * array. + * + * Other devices: + * + * This array will contain as many elements as the number of + * radios. + */ struct ath12k_pdev pdevs[MAX_RADIOS]; + + /* struct ath12k_hw_params::single_pdev_only devices use this to + * store phy specific data + */ + struct ath12k_fw_pdev fw_pdev[MAX_RADIOS]; + u8 fw_pdev_count; + struct ath12k_pdev __rcu *pdevs_active[MAX_RADIOS]; struct ath12k_wmi_hal_reg_capabilities_ext_arg hal_reg_cap[MAX_RADIOS]; unsigned long long free_vdev_map; diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index e6033ab158255..63e6c08c767c8 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -65,6 +65,8 @@ struct ath12k_wmi_svc_rdy_ext_parse { struct ath12k_wmi_svc_rdy_ext2_parse { struct ath12k_wmi_dma_ring_caps_parse dma_caps_parse; bool dma_ring_cap_done; + bool spectral_bin_scaling_done; + bool mac_phy_caps_ext_done; }; struct ath12k_wmi_rdy_parse { @@ -445,8 +447,10 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, const struct ath12k_wmi_soc_mac_phy_hw_mode_caps_params *hw_caps = svc->hw_caps; const struct ath12k_wmi_hw_mode_cap_params *wmi_hw_mode_caps = svc->hw_mode_caps; const struct ath12k_wmi_mac_phy_caps_params *wmi_mac_phy_caps = svc->mac_phy_caps; + struct ath12k_base *ab = wmi_handle->wmi_ab->ab; struct ath12k_band_cap *cap_band; struct ath12k_pdev_cap *pdev_cap = &pdev->cap; + struct ath12k_fw_pdev *fw_pdev; u32 phy_map; u32 hw_idx, phy_idx = 0; int i; @@ -475,6 +479,12 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, pdev_cap->supported_bands |= le32_to_cpu(mac_caps->supported_bands); pdev_cap->ampdu_density = le32_to_cpu(mac_caps->ampdu_density); + fw_pdev = &ab->fw_pdev[ab->fw_pdev_count]; + fw_pdev->supported_bands = le32_to_cpu(mac_caps->supported_bands); + fw_pdev->pdev_id = le32_to_cpu(mac_caps->pdev_id); + fw_pdev->phy_id = le32_to_cpu(mac_caps->phy_id); + ab->fw_pdev_count++; + /* Take non-zero tx/rx chainmask. If tx/rx chainmask differs from * band to band for a single radio, need to see how this should be * handled. @@ -3815,6 +3825,7 @@ static int ath12k_wmi_ext_soc_hal_reg_caps_parse(struct ath12k_base *soc, soc->num_radios = 0; phy_id_map = le32_to_cpu(svc_rdy_ext->pref_hw_mode_caps.phy_id_map); + soc->fw_pdev_count = 0; while (phy_id_map && soc->num_radios < MAX_RADIOS) { ret = ath12k_pull_mac_phy_cap_svc_ready_ext(wmi_handle, @@ -4042,6 +4053,125 @@ static int ath12k_service_ready_ext_event(struct ath12k_base *ab, return ret; } +static void ath12k_wmi_eht_caps_parse(struct ath12k_pdev *pdev, u32 band, + const __le32 cap_mac_info[], + const __le32 cap_phy_info[], + const __le32 supp_mcs[], + const struct ath12k_wmi_ppe_threshold_params *ppet, + __le32 cap_info_internal) +{ + struct ath12k_band_cap *cap_band = &pdev->cap.band[band]; + u8 i; + + for (i = 0; i < WMI_MAX_EHTCAP_MAC_SIZE; i++) + cap_band->eht_cap_mac_info[i] = le32_to_cpu(cap_mac_info[i]); + + for (i = 0; i < WMI_MAX_EHTCAP_PHY_SIZE; i++) + cap_band->eht_cap_phy_info[i] = le32_to_cpu(cap_phy_info[i]); + + cap_band->eht_mcs_20_only = le32_to_cpu(supp_mcs[0]); + cap_band->eht_mcs_80 = le32_to_cpu(supp_mcs[1]); + if (band != NL80211_BAND_2GHZ) { + cap_band->eht_mcs_160 = le32_to_cpu(supp_mcs[2]); + cap_band->eht_mcs_320 = le32_to_cpu(supp_mcs[3]); + } + + cap_band->eht_ppet.numss_m1 = le32_to_cpu(ppet->numss_m1); + cap_band->eht_ppet.ru_bit_mask = le32_to_cpu(ppet->ru_info); + for (i = 0; i < WMI_MAX_NUM_SS; i++) + cap_band->eht_ppet.ppet16_ppet8_ru3_ru0[i] = + le32_to_cpu(ppet->ppet16_ppet8_ru3_ru0[i]); + + cap_band->eht_cap_info_internal = le32_to_cpu(cap_info_internal); +} + +static int +ath12k_wmi_tlv_mac_phy_caps_ext_parse(struct ath12k_base *ab, + const struct ath12k_wmi_caps_ext_params *caps, + struct ath12k_pdev *pdev) +{ + u32 bands; + int i; + + if (ab->hw_params->single_pdev_only) { + for (i = 0; i < ab->fw_pdev_count; i++) { + struct ath12k_fw_pdev *fw_pdev = &ab->fw_pdev[i]; + + if (fw_pdev->pdev_id == le32_to_cpu(caps->pdev_id) && + fw_pdev->phy_id == le32_to_cpu(caps->phy_id)) { + bands = fw_pdev->supported_bands; + break; + } + } + + if (i == ab->fw_pdev_count) + return -EINVAL; + } else { + bands = pdev->cap.supported_bands; + } + + if (bands & WMI_HOST_WLAN_2G_CAP) { + ath12k_wmi_eht_caps_parse(pdev, NL80211_BAND_2GHZ, + caps->eht_cap_mac_info_2ghz, + caps->eht_cap_phy_info_2ghz, + caps->eht_supp_mcs_ext_2ghz, + &caps->eht_ppet_2ghz, + caps->eht_cap_info_internal); + } + + if (bands & WMI_HOST_WLAN_5G_CAP) { + ath12k_wmi_eht_caps_parse(pdev, NL80211_BAND_5GHZ, + caps->eht_cap_mac_info_5ghz, + caps->eht_cap_phy_info_5ghz, + caps->eht_supp_mcs_ext_5ghz, + &caps->eht_ppet_5ghz, + caps->eht_cap_info_internal); + + ath12k_wmi_eht_caps_parse(pdev, NL80211_BAND_6GHZ, + caps->eht_cap_mac_info_5ghz, + caps->eht_cap_phy_info_5ghz, + caps->eht_supp_mcs_ext_5ghz, + &caps->eht_ppet_5ghz, + caps->eht_cap_info_internal); + } + + return 0; +} + +static int ath12k_wmi_tlv_mac_phy_caps_ext(struct ath12k_base *ab, u16 tag, + u16 len, const void *ptr, + void *data) +{ + const struct ath12k_wmi_caps_ext_params *caps = ptr; + int i = 0, ret; + + if (tag != WMI_TAG_MAC_PHY_CAPABILITIES_EXT) + return -EPROTO; + + if (ab->hw_params->single_pdev_only) { + if (ab->wmi_ab.preferred_hw_mode != le32_to_cpu(caps->hw_mode_id)) + return 0; + } else { + for (i = 0; i < ab->num_radios; i++) { + if (ab->pdevs[i].pdev_id == le32_to_cpu(caps->pdev_id)) + break; + } + + if (i == ab->num_radios) + return -EINVAL; + } + + ret = ath12k_wmi_tlv_mac_phy_caps_ext_parse(ab, caps, &ab->pdevs[i]); + if (ret) { + ath12k_warn(ab, + "failed to parse extended MAC PHY capabilities for pdev %d: %d\n", + ret, ab->pdevs[i].pdev_id); + return ret; + } + + return 0; +} + static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab, u16 tag, u16 len, const void *ptr, void *data) @@ -4058,6 +4188,23 @@ static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab, return ret; parse->dma_ring_cap_done = true; + } else if (!parse->spectral_bin_scaling_done) { + /* TODO: This is a place-holder as WMI tag for + * spectral scaling is before + * WMI_TAG_MAC_PHY_CAPABILITIES_EXT + */ + parse->spectral_bin_scaling_done = true; + } else if (!parse->mac_phy_caps_ext_done) { + ret = ath12k_wmi_tlv_iter(ab, ptr, len, + ath12k_wmi_tlv_mac_phy_caps_ext, + parse); + if (ret) { + ath12k_warn(ab, "failed to parse extended MAC PHY capabilities WMI TLV: %d\n", + ret); + return ret; + } + + parse->mac_phy_caps_ext_done = true; } break; default: diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 9b8ba87049047..bafcaa7f16294 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2581,6 +2581,44 @@ struct ath12k_wmi_soc_hal_reg_caps_params { __le32 num_phy; } __packed; +#define WMI_MAX_EHTCAP_MAC_SIZE 2 +#define WMI_MAX_EHTCAP_PHY_SIZE 3 + +/* Used for EHT MCS-NSS array. Data at each array index follows the format given + * in IEEE P802.11be/D2.0, May 20229.4.2.313.4. + * + * Index interpretation: + * 0 - 20 MHz only sta, all 4 bytes valid + * 1 - index for bandwidths <= 80 MHz except 20 MHz-only, first 3 bytes valid + * 2 - index for 160 MHz, first 3 bytes valid + * 3 - index for 320 MHz, first 3 bytes valid + */ +#define WMI_MAX_EHT_SUPP_MCS_2G_SIZE 2 +#define WMI_MAX_EHT_SUPP_MCS_5G_SIZE 4 + +struct ath12k_wmi_caps_ext_params { + __le32 hw_mode_id; + union { + struct { + __le16 pdev_id; + __le16 hw_link_id; + } __packed ath12k_wmi_pdev_to_link_map; + __le32 pdev_id; + }; + __le32 phy_id; + __le32 wireless_modes_ext; + __le32 eht_cap_mac_info_2ghz[WMI_MAX_EHTCAP_MAC_SIZE]; + __le32 eht_cap_mac_info_5ghz[WMI_MAX_EHTCAP_MAC_SIZE]; + __le32 rsvd0[2]; + __le32 eht_cap_phy_info_2ghz[WMI_MAX_EHTCAP_PHY_SIZE]; + __le32 eht_cap_phy_info_5ghz[WMI_MAX_EHTCAP_PHY_SIZE]; + struct ath12k_wmi_ppe_threshold_params eht_ppet_2ghz; + struct ath12k_wmi_ppe_threshold_params eht_ppet_5ghz; + __le32 eht_cap_info_internal; + __le32 eht_supp_mcs_ext_2ghz[WMI_MAX_EHT_SUPP_MCS_2G_SIZE]; + __le32 eht_supp_mcs_ext_5ghz[WMI_MAX_EHT_SUPP_MCS_5G_SIZE]; +} __packed; + /* 2 word representation of MAC addr */ struct ath12k_wmi_mac_addr_params { u8 addr[ETH_ALEN]; From dbe90679bfa1287651b8bb8304b7ce46b00a5f81 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Wed, 2 Aug 2023 20:04:02 +0300 Subject: [PATCH 22/32] wifi: ath12k: propagate EHT capabilities to userspace Propagate EHT capabilities to the userspace using a new member 'eht_cap' in structure ieee80211_sband_iftype_data. MCS-NSS capabilities are copied depending on the supported bandwidths for the given band. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Signed-off-by: Pradeep Kumar Chitrapu Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230725224034.14045-5-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 111 ++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 8fedbf4879d6d..c64cd8079e20c 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -4275,6 +4275,115 @@ static void ath12k_mac_copy_he_cap(struct ath12k_band_cap *band_cap, ath12k_gen_ppe_thresh(&band_cap->he_ppet, he_cap->ppe_thres); } +static void +ath12k_mac_copy_eht_mcs_nss(struct ath12k_band_cap *band_cap, + struct ieee80211_eht_mcs_nss_supp *mcs_nss, + const struct ieee80211_he_cap_elem *he_cap, + const struct ieee80211_eht_cap_elem_fixed *eht_cap) +{ + if ((he_cap->phy_cap_info[0] & + (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)) == 0) + memcpy(&mcs_nss->only_20mhz, &band_cap->eht_mcs_20_only, + sizeof(struct ieee80211_eht_mcs_nss_supp_20mhz_only)); + + if (he_cap->phy_cap_info[0] & + (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) + memcpy(&mcs_nss->bw._80, &band_cap->eht_mcs_80, + sizeof(struct ieee80211_eht_mcs_nss_supp_bw)); + + if (he_cap->phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) + memcpy(&mcs_nss->bw._160, &band_cap->eht_mcs_160, + sizeof(struct ieee80211_eht_mcs_nss_supp_bw)); + + if (eht_cap->phy_cap_info[0] & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ) + memcpy(&mcs_nss->bw._320, &band_cap->eht_mcs_320, + sizeof(struct ieee80211_eht_mcs_nss_supp_bw)); +} + +static void ath12k_mac_copy_eht_ppe_thresh(struct ath12k_wmi_ppe_threshold_arg *fw_ppet, + struct ieee80211_sta_eht_cap *cap) +{ + u16 bit = IEEE80211_EHT_PPE_THRES_INFO_HEADER_SIZE; + u8 i, nss, ru, ppet_bit_len_per_ru = IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE * 2; + + u8p_replace_bits(&cap->eht_ppe_thres[0], fw_ppet->numss_m1, + IEEE80211_EHT_PPE_THRES_NSS_MASK); + + u16p_replace_bits((u16 *)&cap->eht_ppe_thres[0], fw_ppet->ru_bit_mask, + IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK); + + for (nss = 0; nss <= fw_ppet->numss_m1; nss++) { + for (ru = 0; + ru < hweight16(IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK); + ru++) { + u32 val = 0; + + if ((fw_ppet->ru_bit_mask & BIT(ru)) == 0) + continue; + + u32p_replace_bits(&val, fw_ppet->ppet16_ppet8_ru3_ru0[nss] >> + (ru * ppet_bit_len_per_ru), + GENMASK(ppet_bit_len_per_ru - 1, 0)); + + for (i = 0; i < ppet_bit_len_per_ru; i++) { + cap->eht_ppe_thres[bit / 8] |= + (((val >> i) & 0x1) << ((bit % 8))); + bit++; + } + } + } +} + +static void ath12k_mac_copy_eht_cap(struct ath12k_band_cap *band_cap, + struct ieee80211_he_cap_elem *he_cap_elem, + int iftype, + struct ieee80211_sta_eht_cap *eht_cap) +{ + struct ieee80211_eht_cap_elem_fixed *eht_cap_elem = &eht_cap->eht_cap_elem; + + memset(eht_cap, 0, sizeof(struct ieee80211_sta_eht_cap)); + eht_cap->has_eht = true; + memcpy(eht_cap_elem->mac_cap_info, band_cap->eht_cap_mac_info, + sizeof(eht_cap_elem->mac_cap_info)); + memcpy(eht_cap_elem->phy_cap_info, band_cap->eht_cap_phy_info, + sizeof(eht_cap_elem->phy_cap_info)); + + switch (iftype) { + case NL80211_IFTYPE_AP: + eht_cap_elem->phy_cap_info[0] &= + ~IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ; + eht_cap_elem->phy_cap_info[4] &= + ~IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO; + eht_cap_elem->phy_cap_info[5] &= + ~IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP; + break; + case NL80211_IFTYPE_STATION: + eht_cap_elem->phy_cap_info[7] &= + ~(IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ | + IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ | + IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ); + eht_cap_elem->phy_cap_info[7] &= + ~(IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ | + IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ | + IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ); + break; + default: + break; + } + + ath12k_mac_copy_eht_mcs_nss(band_cap, &eht_cap->eht_mcs_nss_supp, + he_cap_elem, eht_cap_elem); + + if (eht_cap_elem->phy_cap_info[5] & + IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT) + ath12k_mac_copy_eht_ppe_thresh(&band_cap->eht_ppet, eht_cap); +} + static int ath12k_mac_copy_sband_iftype_data(struct ath12k *ar, struct ath12k_pdev_cap *cap, struct ieee80211_sband_iftype_data *data, @@ -4303,6 +4412,8 @@ static int ath12k_mac_copy_sband_iftype_data(struct ath12k *ar, data[idx].he_6ghz_capa.capa = ath12k_mac_setup_he_6ghz_cap(cap, band_cap); } + ath12k_mac_copy_eht_cap(band_cap, &he_cap->he_cap_elem, i, + &data[idx].eht_cap); idx++; } From 38013653a69734e2bcf84ce951f7a4aee3966320 Mon Sep 17 00:00:00 2001 From: Muna Sinada Date: Wed, 2 Aug 2023 20:04:03 +0300 Subject: [PATCH 23/32] wifi: ath12k: add EHT PHY modes Add support to retrieve and configure the phy modes supported by the hardware. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Muna Sinada Signed-off-by: Aloka Dixit Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230725224034.14045-6-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 101 +++++++++++++++++++++----- drivers/net/wireless/ath/ath12k/mac.h | 2 +- drivers/net/wireless/ath/ath12k/wmi.h | 13 +++- 3 files changed, 94 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index c64cd8079e20c..8ea1ac5ab356c 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -182,32 +182,35 @@ ath12k_phymodes[NUM_NL80211_BANDS][ATH12K_CHAN_WIDTH_NUM] = { [NL80211_BAND_2GHZ] = { [NL80211_CHAN_WIDTH_5] = MODE_UNKNOWN, [NL80211_CHAN_WIDTH_10] = MODE_UNKNOWN, - [NL80211_CHAN_WIDTH_20_NOHT] = MODE_11AX_HE20_2G, - [NL80211_CHAN_WIDTH_20] = MODE_11AX_HE20_2G, - [NL80211_CHAN_WIDTH_40] = MODE_11AX_HE40_2G, - [NL80211_CHAN_WIDTH_80] = MODE_11AX_HE80_2G, + [NL80211_CHAN_WIDTH_20_NOHT] = MODE_11BE_EHT20_2G, + [NL80211_CHAN_WIDTH_20] = MODE_11BE_EHT20_2G, + [NL80211_CHAN_WIDTH_40] = MODE_11BE_EHT40_2G, + [NL80211_CHAN_WIDTH_80] = MODE_UNKNOWN, [NL80211_CHAN_WIDTH_80P80] = MODE_UNKNOWN, [NL80211_CHAN_WIDTH_160] = MODE_UNKNOWN, + [NL80211_CHAN_WIDTH_320] = MODE_UNKNOWN, }, [NL80211_BAND_5GHZ] = { [NL80211_CHAN_WIDTH_5] = MODE_UNKNOWN, [NL80211_CHAN_WIDTH_10] = MODE_UNKNOWN, - [NL80211_CHAN_WIDTH_20_NOHT] = MODE_11AX_HE20, - [NL80211_CHAN_WIDTH_20] = MODE_11AX_HE20, - [NL80211_CHAN_WIDTH_40] = MODE_11AX_HE40, - [NL80211_CHAN_WIDTH_80] = MODE_11AX_HE80, - [NL80211_CHAN_WIDTH_160] = MODE_11AX_HE160, - [NL80211_CHAN_WIDTH_80P80] = MODE_11AX_HE80_80, + [NL80211_CHAN_WIDTH_20_NOHT] = MODE_11BE_EHT20, + [NL80211_CHAN_WIDTH_20] = MODE_11BE_EHT20, + [NL80211_CHAN_WIDTH_40] = MODE_11BE_EHT40, + [NL80211_CHAN_WIDTH_80] = MODE_11BE_EHT80, + [NL80211_CHAN_WIDTH_160] = MODE_11BE_EHT160, + [NL80211_CHAN_WIDTH_80P80] = MODE_11BE_EHT80_80, + [NL80211_CHAN_WIDTH_320] = MODE_11BE_EHT320, }, [NL80211_BAND_6GHZ] = { [NL80211_CHAN_WIDTH_5] = MODE_UNKNOWN, [NL80211_CHAN_WIDTH_10] = MODE_UNKNOWN, - [NL80211_CHAN_WIDTH_20_NOHT] = MODE_11AX_HE20, - [NL80211_CHAN_WIDTH_20] = MODE_11AX_HE20, - [NL80211_CHAN_WIDTH_40] = MODE_11AX_HE40, - [NL80211_CHAN_WIDTH_80] = MODE_11AX_HE80, - [NL80211_CHAN_WIDTH_160] = MODE_11AX_HE160, - [NL80211_CHAN_WIDTH_80P80] = MODE_11AX_HE80_80, + [NL80211_CHAN_WIDTH_20_NOHT] = MODE_11BE_EHT20, + [NL80211_CHAN_WIDTH_20] = MODE_11BE_EHT20, + [NL80211_CHAN_WIDTH_40] = MODE_11BE_EHT40, + [NL80211_CHAN_WIDTH_80] = MODE_11BE_EHT80, + [NL80211_CHAN_WIDTH_160] = MODE_11BE_EHT160, + [NL80211_CHAN_WIDTH_80P80] = MODE_11BE_EHT80_80, + [NL80211_CHAN_WIDTH_320] = MODE_11BE_EHT320, }, }; @@ -292,6 +295,24 @@ static const char *ath12k_mac_phymode_str(enum wmi_phy_mode mode) return "11ax-he40-2g"; case MODE_11AX_HE80_2G: return "11ax-he80-2g"; + case MODE_11BE_EHT20: + return "11be-eht20"; + case MODE_11BE_EHT40: + return "11be-eht40"; + case MODE_11BE_EHT80: + return "11be-eht80"; + case MODE_11BE_EHT80_80: + return "11be-eht80+80"; + case MODE_11BE_EHT160: + return "11be-eht160"; + case MODE_11BE_EHT160_160: + return "11be-eht160+160"; + case MODE_11BE_EHT320: + return "11be-eht320"; + case MODE_11BE_EHT20_2G: + return "11be-eht20-2g"; + case MODE_11BE_EHT40_2G: + return "11be-eht40-2g"; case MODE_UNKNOWN: /* skip */ break; @@ -1929,6 +1950,41 @@ static enum wmi_phy_mode ath12k_mac_get_phymode_he(struct ath12k *ar, return MODE_UNKNOWN; } +static enum wmi_phy_mode ath12k_mac_get_phymode_eht(struct ath12k *ar, + struct ieee80211_sta *sta) +{ + if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_320) + if (sta->deflink.eht_cap.eht_cap_elem.phy_cap_info[0] & + IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ) + return MODE_11BE_EHT320; + + if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) { + if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) + return MODE_11BE_EHT160; + + if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) + return MODE_11BE_EHT80_80; + + ath12k_warn(ar->ab, "invalid EHT PHY capability info for 160 Mhz: %d\n", + sta->deflink.he_cap.he_cap_elem.phy_cap_info[0]); + + return MODE_11BE_EHT160; + } + + if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_80) + return MODE_11BE_EHT80; + + if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_40) + return MODE_11BE_EHT40; + + if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_20) + return MODE_11BE_EHT20; + + return MODE_UNKNOWN; +} + static void ath12k_peer_assoc_h_phymode(struct ath12k *ar, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -1950,7 +2006,12 @@ static void ath12k_peer_assoc_h_phymode(struct ath12k *ar, switch (band) { case NL80211_BAND_2GHZ: - if (sta->deflink.he_cap.has_he) { + if (sta->deflink.eht_cap.has_eht) { + if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_40) + phymode = MODE_11BE_EHT40_2G; + else + phymode = MODE_11BE_EHT20_2G; + } else if (sta->deflink.he_cap.has_he) { if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_80) phymode = MODE_11AX_HE80_2G; else if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_40) @@ -1977,8 +2038,10 @@ static void ath12k_peer_assoc_h_phymode(struct ath12k *ar, break; case NL80211_BAND_5GHZ: case NL80211_BAND_6GHZ: - /* Check HE first */ - if (sta->deflink.he_cap.has_he) { + /* Check EHT first */ + if (sta->deflink.eht_cap.has_eht) { + phymode = ath12k_mac_get_phymode_eht(ar, sta); + } else if (sta->deflink.he_cap.has_he) { phymode = ath12k_mac_get_phymode_he(ar, sta); } else if (sta->deflink.vht_cap.vht_supported && !ath12k_peer_assoc_h_vht_masked(vht_mcs_mask)) { diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h index 57f4295420bb8..7b16b70df4fa8 100644 --- a/drivers/net/wireless/ath/ath12k/mac.h +++ b/drivers/net/wireless/ath/ath12k/mac.h @@ -33,7 +33,7 @@ struct ath12k_generic_iter { #define IEEE80211_VHT_MCS_SUPPORT_0_11_MASK GENMASK(23, 16) #define IEEE80211_DISABLE_VHT_MCS_SUPPORT_0_11 BIT(24) -#define ATH12K_CHAN_WIDTH_NUM 8 +#define ATH12K_CHAN_WIDTH_NUM 14 #define ATH12K_TX_POWER_MAX_VAL 70 #define ATH12K_TX_POWER_MIN_VAL 0 diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index bafcaa7f16294..0aa73908a65ff 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2796,8 +2796,17 @@ enum wmi_phy_mode { MODE_11AX_HE20_2G = 21, MODE_11AX_HE40_2G = 22, MODE_11AX_HE80_2G = 23, - MODE_UNKNOWN = 24, - MODE_MAX = 24 + MODE_11BE_EHT20 = 24, + MODE_11BE_EHT40 = 25, + MODE_11BE_EHT80 = 26, + MODE_11BE_EHT80_80 = 27, + MODE_11BE_EHT160 = 28, + MODE_11BE_EHT160_160 = 29, + MODE_11BE_EHT320 = 30, + MODE_11BE_EHT20_2G = 31, + MODE_11BE_EHT40_2G = 32, + MODE_UNKNOWN = 33, + MODE_MAX = 33, }; struct wmi_vdev_start_req_arg { From 17bbb8aa74fded03527427c25f43a29590c6a9ab Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Wed, 2 Aug 2023 20:04:04 +0300 Subject: [PATCH 24/32] wifi: ath12k: prepare EHT peer assoc parameters Add new parameters and prepare the association data for an EHT peer. MCS data uses the format described in IEEE P802.11be/D2.0, May 2022, 9.4.2.313.4, convert it into the format expected by the firmware. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Signed-off-by: Pradeep Kumar Chitrapu Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230725224034.14045-7-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 144 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/wmi.h | 17 +++ 2 files changed, 161 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 8ea1ac5ab356c..5b7a892e1f79a 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -2067,6 +2067,149 @@ static void ath12k_peer_assoc_h_phymode(struct ath12k *ar, WARN_ON(phymode == MODE_UNKNOWN); } +static void ath12k_mac_set_eht_mcs(u8 rx_tx_mcs7, u8 rx_tx_mcs9, + u8 rx_tx_mcs11, u8 rx_tx_mcs13, + u32 *rx_mcs, u32 *tx_mcs) +{ + *rx_mcs = 0; + u32p_replace_bits(rx_mcs, + u8_get_bits(rx_tx_mcs7, IEEE80211_EHT_MCS_NSS_RX), + WMI_EHT_MCS_NSS_0_7); + u32p_replace_bits(rx_mcs, + u8_get_bits(rx_tx_mcs9, IEEE80211_EHT_MCS_NSS_RX), + WMI_EHT_MCS_NSS_8_9); + u32p_replace_bits(rx_mcs, + u8_get_bits(rx_tx_mcs11, IEEE80211_EHT_MCS_NSS_RX), + WMI_EHT_MCS_NSS_10_11); + u32p_replace_bits(rx_mcs, + u8_get_bits(rx_tx_mcs13, IEEE80211_EHT_MCS_NSS_RX), + WMI_EHT_MCS_NSS_12_13); + + *tx_mcs = 0; + u32p_replace_bits(tx_mcs, + u8_get_bits(rx_tx_mcs7, IEEE80211_EHT_MCS_NSS_TX), + WMI_EHT_MCS_NSS_0_7); + u32p_replace_bits(tx_mcs, + u8_get_bits(rx_tx_mcs9, IEEE80211_EHT_MCS_NSS_TX), + WMI_EHT_MCS_NSS_8_9); + u32p_replace_bits(tx_mcs, + u8_get_bits(rx_tx_mcs11, IEEE80211_EHT_MCS_NSS_TX), + WMI_EHT_MCS_NSS_10_11); + u32p_replace_bits(tx_mcs, + u8_get_bits(rx_tx_mcs13, IEEE80211_EHT_MCS_NSS_TX), + WMI_EHT_MCS_NSS_12_13); +} + +static void ath12k_mac_set_eht_ppe_threshold(const u8 *ppe_thres, + struct ath12k_wmi_ppe_threshold_arg *ppet) +{ + u32 bit_pos = IEEE80211_EHT_PPE_THRES_INFO_HEADER_SIZE, val; + u8 nss, ru, i; + u8 ppet_bit_len_per_ru = IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE * 2; + + ppet->numss_m1 = u8_get_bits(ppe_thres[0], IEEE80211_EHT_PPE_THRES_NSS_MASK); + ppet->ru_bit_mask = u16_get_bits(get_unaligned_le16(ppe_thres), + IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK); + + for (nss = 0; nss <= ppet->numss_m1; nss++) { + for (ru = 0; + ru < hweight16(IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK); + ru++) { + if ((ppet->ru_bit_mask & BIT(ru)) == 0) + continue; + + val = 0; + for (i = 0; i < ppet_bit_len_per_ru; i++) { + val |= (((ppe_thres[bit_pos / 8] >> + (bit_pos % 8)) & 0x1) << i); + bit_pos++; + } + ppet->ppet16_ppet8_ru3_ru0[nss] |= + (val << (ru * ppet_bit_len_per_ru)); + } + } +} + +static void ath12k_peer_assoc_h_eht(struct ath12k *ar, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ath12k_wmi_peer_assoc_arg *arg) +{ + const struct ieee80211_sta_eht_cap *eht_cap = &sta->deflink.eht_cap; + const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap; + const struct ieee80211_eht_mcs_nss_supp_20mhz_only *bw_20; + const struct ieee80211_eht_mcs_nss_supp_bw *bw; + u32 *rx_mcs, *tx_mcs; + + if (!sta->deflink.he_cap.has_he || !eht_cap->has_eht) + return; + + arg->eht_flag = true; + + if ((eht_cap->eht_cap_elem.phy_cap_info[5] & + IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT) && + eht_cap->eht_ppe_thres[0] != 0) + ath12k_mac_set_eht_ppe_threshold(eht_cap->eht_ppe_thres, + &arg->peer_eht_ppet); + + memcpy(arg->peer_eht_cap_mac, eht_cap->eht_cap_elem.mac_cap_info, + sizeof(eht_cap->eht_cap_elem.mac_cap_info)); + memcpy(arg->peer_eht_cap_phy, eht_cap->eht_cap_elem.phy_cap_info, + sizeof(eht_cap->eht_cap_elem.phy_cap_info)); + + rx_mcs = arg->peer_eht_rx_mcs_set; + tx_mcs = arg->peer_eht_tx_mcs_set; + + switch (sta->deflink.bandwidth) { + case IEEE80211_STA_RX_BW_320: + bw = &eht_cap->eht_mcs_nss_supp.bw._320; + ath12k_mac_set_eht_mcs(bw->rx_tx_mcs9_max_nss, + bw->rx_tx_mcs9_max_nss, + bw->rx_tx_mcs11_max_nss, + bw->rx_tx_mcs13_max_nss, + &rx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_320], + &tx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_320]); + arg->peer_eht_mcs_count++; + fallthrough; + case IEEE80211_STA_RX_BW_160: + bw = &eht_cap->eht_mcs_nss_supp.bw._160; + ath12k_mac_set_eht_mcs(bw->rx_tx_mcs9_max_nss, + bw->rx_tx_mcs9_max_nss, + bw->rx_tx_mcs11_max_nss, + bw->rx_tx_mcs13_max_nss, + &rx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_160], + &tx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_160]); + arg->peer_eht_mcs_count++; + fallthrough; + default: + if ((he_cap->he_cap_elem.phy_cap_info[0] & + (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)) == 0) { + bw_20 = &eht_cap->eht_mcs_nss_supp.only_20mhz; + + ath12k_mac_set_eht_mcs(bw_20->rx_tx_mcs7_max_nss, + bw_20->rx_tx_mcs9_max_nss, + bw_20->rx_tx_mcs11_max_nss, + bw_20->rx_tx_mcs13_max_nss, + &rx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_80], + &tx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_80]); + } else { + bw = &eht_cap->eht_mcs_nss_supp.bw._80; + ath12k_mac_set_eht_mcs(bw->rx_tx_mcs9_max_nss, + bw->rx_tx_mcs9_max_nss, + bw->rx_tx_mcs11_max_nss, + bw->rx_tx_mcs13_max_nss, + &rx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_80], + &tx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_80]); + } + + arg->peer_eht_mcs_count++; + break; + } +} + static void ath12k_peer_assoc_prepare(struct ath12k *ar, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -2086,6 +2229,7 @@ static void ath12k_peer_assoc_prepare(struct ath12k *ar, ath12k_peer_assoc_h_ht(ar, vif, sta, arg); ath12k_peer_assoc_h_vht(ar, vif, sta, arg); ath12k_peer_assoc_h_he(ar, vif, sta, arg); + ath12k_peer_assoc_h_eht(ar, vif, sta, arg); ath12k_peer_assoc_h_qos(ar, vif, sta, arg); ath12k_peer_assoc_h_phymode(ar, vif, sta, arg); ath12k_peer_assoc_h_smps(sta, arg); diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 0aa73908a65ff..dae895b479c79 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2583,6 +2583,7 @@ struct ath12k_wmi_soc_hal_reg_caps_params { #define WMI_MAX_EHTCAP_MAC_SIZE 2 #define WMI_MAX_EHTCAP_PHY_SIZE 3 +#define WMI_MAX_EHTCAP_RATE_SET 3 /* Used for EHT MCS-NSS array. Data at each array index follows the format given * in IEEE P802.11be/D2.0, May 20229.4.2.313.4. @@ -2596,6 +2597,15 @@ struct ath12k_wmi_soc_hal_reg_caps_params { #define WMI_MAX_EHT_SUPP_MCS_2G_SIZE 2 #define WMI_MAX_EHT_SUPP_MCS_5G_SIZE 4 +#define WMI_EHTCAP_TXRX_MCS_NSS_IDX_80 0 +#define WMI_EHTCAP_TXRX_MCS_NSS_IDX_160 1 +#define WMI_EHTCAP_TXRX_MCS_NSS_IDX_320 2 + +#define WMI_EHT_MCS_NSS_0_7 GENMASK(3, 0) +#define WMI_EHT_MCS_NSS_8_9 GENMASK(7, 4) +#define WMI_EHT_MCS_NSS_10_11 GENMASK(11, 8) +#define WMI_EHT_MCS_NSS_12_13 GENMASK(15, 12) + struct ath12k_wmi_caps_ext_params { __le32 hw_mode_id; union { @@ -3564,6 +3574,13 @@ struct ath12k_wmi_peer_assoc_arg { bool twt_responder; bool twt_requester; struct ath12k_wmi_ppe_threshold_arg peer_ppet; + bool eht_flag; + u32 peer_eht_cap_mac[WMI_MAX_EHTCAP_MAC_SIZE]; + u32 peer_eht_cap_phy[WMI_MAX_EHTCAP_PHY_SIZE]; + u32 peer_eht_mcs_count; + u32 peer_eht_rx_mcs_set[WMI_MAX_EHTCAP_RATE_SET]; + u32 peer_eht_tx_mcs_set[WMI_MAX_EHTCAP_RATE_SET]; + struct ath12k_wmi_ppe_threshold_arg peer_eht_ppet; }; struct wmi_peer_assoc_complete_cmd { From 5b70ec6036c1c755fd1c1aa80ace3d349d91f3a5 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Wed, 2 Aug 2023 20:04:04 +0300 Subject: [PATCH 25/32] wifi: ath12k: add WMI support for EHT peer Add new WMI tag and pass the EHT parameters for peer association to firmware. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Signed-off-by: Pradeep Kumar Chitrapu Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230725224034.14045-8-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.c | 40 +++++++++++++++++++++++++-- drivers/net/wireless/ath/ath12k/wmi.h | 20 ++++++++++++++ 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 63e6c08c767c8..b1bc227ad54ed 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -1801,6 +1801,7 @@ static void ath12k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd, bool hw_crypto_disabled) { cmd->peer_flags = 0; + cmd->peer_flags_ext = 0; if (arg->is_wme_set) { if (arg->qos_flag) @@ -1842,6 +1843,8 @@ static void ath12k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd, cmd->peer_flags |= cpu_to_le32(WMI_PEER_TWT_REQ); if (arg->twt_responder) cmd->peer_flags |= cpu_to_le32(WMI_PEER_TWT_RESP); + if (arg->eht_flag) + cmd->peer_flags_ext |= cpu_to_le32(WMI_PEER_EXT_EHT); } /* Suppress authorization for all AUTH modes that need 4-way handshake @@ -1886,6 +1889,7 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, struct wmi_peer_assoc_complete_cmd *cmd; struct ath12k_wmi_vht_rate_set_params *mcs; struct ath12k_wmi_he_rate_set_params *he_mcs; + struct ath12k_wmi_eht_rate_set_params *eht_mcs; struct sk_buff *skb; struct wmi_tlv *tlv; void *ptr; @@ -1902,7 +1906,8 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, TLV_HDR_SIZE + (peer_legacy_rates_align * sizeof(u8)) + TLV_HDR_SIZE + (peer_ht_rates_align * sizeof(u8)) + sizeof(*mcs) + TLV_HDR_SIZE + - (sizeof(*he_mcs) * arg->peer_he_mcs_count); + (sizeof(*he_mcs) * arg->peer_he_mcs_count) + + TLV_HDR_SIZE + (sizeof(*eht_mcs) * arg->peer_eht_mcs_count); skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) @@ -1949,6 +1954,16 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, cmd->peer_ppet.ppet16_ppet8_ru3_ru0[i] = cpu_to_le32(arg->peer_ppet.ppet16_ppet8_ru3_ru0[i]); + /* Update 11be capabilities */ + memcpy_and_pad(cmd->peer_eht_cap_mac, sizeof(cmd->peer_eht_cap_mac), + arg->peer_eht_cap_mac, sizeof(arg->peer_eht_cap_mac), + 0); + memcpy_and_pad(cmd->peer_eht_cap_phy, sizeof(cmd->peer_eht_cap_phy), + arg->peer_eht_cap_phy, sizeof(arg->peer_eht_cap_phy), + 0); + memcpy_and_pad(&cmd->peer_eht_ppet, sizeof(cmd->peer_eht_ppet), + &arg->peer_eht_ppet, sizeof(arg->peer_eht_ppet), 0); + /* Update peer legacy rate information */ ptr += sizeof(*cmd); @@ -2015,8 +2030,24 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, ptr += sizeof(*he_mcs); } + /* Loop through the EHT rate set */ + len = arg->peer_eht_mcs_count * sizeof(*eht_mcs); + tlv = ptr; + tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len); + ptr += TLV_HDR_SIZE; + + for (i = 0; i < arg->peer_eht_mcs_count; i++) { + eht_mcs = ptr; + eht_mcs->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_HE_RATE_SET, + sizeof(*eht_mcs)); + + eht_mcs->rx_mcs_set = cpu_to_le32(arg->peer_eht_rx_mcs_set[i]); + eht_mcs->tx_mcs_set = cpu_to_le32(arg->peer_eht_tx_mcs_set[i]); + ptr += sizeof(*eht_mcs); + } + ath12k_dbg(ar->ab, ATH12K_DBG_WMI, - "wmi peer assoc vdev id %d assoc id %d peer mac %pM peer_flags %x rate_caps %x peer_caps %x listen_intval %d ht_caps %x max_mpdu %d nss %d phymode %d peer_mpdu_density %d vht_caps %x he cap_info %x he ops %x he cap_info_ext %x he phy %x %x %x peer_bw_rxnss_override %x\n", + "wmi peer assoc vdev id %d assoc id %d peer mac %pM peer_flags %x rate_caps %x peer_caps %x listen_intval %d ht_caps %x max_mpdu %d nss %d phymode %d peer_mpdu_density %d vht_caps %x he cap_info %x he ops %x he cap_info_ext %x he phy %x %x %x peer_bw_rxnss_override %x peer_flags_ext %x eht mac_cap %x %x eht phy_cap %x %x %x\n", cmd->vdev_id, cmd->peer_associd, arg->peer_mac, cmd->peer_flags, cmd->peer_rate_caps, cmd->peer_caps, cmd->peer_listen_intval, cmd->peer_ht_caps, @@ -2026,7 +2057,10 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, cmd->peer_he_ops, cmd->peer_he_cap_info_ext, cmd->peer_he_cap_phy[0], cmd->peer_he_cap_phy[1], cmd->peer_he_cap_phy[2], - cmd->peer_bw_rxnss_override); + cmd->peer_bw_rxnss_override, cmd->peer_flags_ext, + cmd->peer_eht_cap_mac[0], cmd->peer_eht_cap_mac[1], + cmd->peer_eht_cap_phy[0], cmd->peer_eht_cap_phy[1], + cmd->peer_eht_cap_phy[2]); ret = ath12k_wmi_cmd_send(wmi, skb, WMI_PEER_ASSOC_CMDID); if (ret) { diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index dae895b479c79..5e8c4a23c6ba0 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -1167,6 +1167,10 @@ enum wmi_tlv_peer_flags { }; +enum wmi_tlv_peer_flags_ext { + WMI_PEER_EXT_EHT = BIT(0), +}; + /** Enum list of TLV Tags for each parameter structure type. */ enum wmi_tlv_tag { WMI_TAG_LAST_RESERVED = 15, @@ -1924,6 +1928,7 @@ enum wmi_tlv_tag { WMI_TAG_MAC_PHY_CAPABILITIES_EXT = 0x36F, WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9, WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT, + WMI_TAG_EHT_RATE_SET = 0x3C4, WMI_TAG_MAX }; @@ -3612,6 +3617,15 @@ struct wmi_peer_assoc_complete_cmd { __le32 peer_he_cap_info_internal; __le32 min_data_rate; __le32 peer_he_caps_6ghz; + __le32 sta_type; + __le32 bss_max_idle_option; + __le32 auth_mode; + __le32 peer_flags_ext; + __le32 puncture_20mhz_bitmap; + __le32 peer_eht_cap_mac[WMI_MAX_EHTCAP_MAC_SIZE]; + __le32 peer_eht_cap_phy[WMI_MAX_EHTCAP_PHY_SIZE]; + __le32 peer_eht_ops; + struct ath12k_wmi_ppe_threshold_params peer_eht_ppet; } __packed; struct wmi_stop_scan_cmd { @@ -3839,6 +3853,12 @@ struct ath12k_wmi_he_rate_set_params { __le32 tx_mcs_set; } __packed; +struct ath12k_wmi_eht_rate_set_params { + __le32 tlv_header; + __le32 rx_mcs_set; + __le32 tx_mcs_set; +} __packed; + #define MAX_REG_RULES 10 #define REG_ALPHA2_LEN 2 #define MAX_6G_REG_RULES 5 From 6734cf9b4cc7ae017ec1e9ab44a8ba0d8c512d5d Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Wed, 2 Aug 2023 20:04:05 +0300 Subject: [PATCH 26/32] wifi: ath12k: peer assoc for 320 MHz Add required peer association definitions and processing if the bandwidth is 320 MHz. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Signed-off-by: Pradeep Kumar Chitrapu Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230725224034.14045-9-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.c | 2 ++ drivers/net/wireless/ath/ath12k/wmi.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index b1bc227ad54ed..6e9b7c5fb0289 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -1816,6 +1816,8 @@ static void ath12k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd, cmd->peer_flags |= cpu_to_le32(WMI_PEER_80MHZ); if (arg->bw_160) cmd->peer_flags |= cpu_to_le32(WMI_PEER_160MHZ); + if (arg->bw_320) + cmd->peer_flags |= cpu_to_le32(WMI_PEER_EXT_320MHZ); /* Typically if STBC is enabled for VHT it should be enabled * for HT as well diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 5e8c4a23c6ba0..93a70426df287 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -1169,6 +1169,7 @@ enum wmi_tlv_peer_flags { enum wmi_tlv_peer_flags_ext { WMI_PEER_EXT_EHT = BIT(0), + WMI_PEER_EXT_320MHZ = BIT(1), }; /** Enum list of TLV Tags for each parameter structure type. */ @@ -3552,6 +3553,7 @@ struct ath12k_wmi_peer_assoc_arg { bool bw_40; bool bw_80; bool bw_160; + bool bw_320; bool stbc_flag; bool ldpc_flag; bool static_mimops_flag; From 22e1d1166c27ed9099f1312cd2043a480b1bda14 Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Wed, 2 Aug 2023 20:04:06 +0300 Subject: [PATCH 27/32] wifi: ath12k: add MLO header in peer association Add tags with length 0 for MLO header and partner links which are required by the firmware for a successful association. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Pradeep Kumar Chitrapu Signed-off-by: Aloka Dixit Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230725224034.14045-10-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 6e9b7c5fb0289..24f6c1dbd7439 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -1909,7 +1909,8 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, TLV_HDR_SIZE + (peer_ht_rates_align * sizeof(u8)) + sizeof(*mcs) + TLV_HDR_SIZE + (sizeof(*he_mcs) * arg->peer_he_mcs_count) + - TLV_HDR_SIZE + (sizeof(*eht_mcs) * arg->peer_eht_mcs_count); + TLV_HDR_SIZE + (sizeof(*eht_mcs) * arg->peer_eht_mcs_count) + + TLV_HDR_SIZE + TLV_HDR_SIZE; skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) @@ -2032,6 +2033,12 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, ptr += sizeof(*he_mcs); } + /* MLO header tag with 0 length */ + len = 0; + tlv = ptr; + tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len); + ptr += TLV_HDR_SIZE; + /* Loop through the EHT rate set */ len = arg->peer_eht_mcs_count * sizeof(*eht_mcs); tlv = ptr; @@ -2048,6 +2055,12 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, ptr += sizeof(*eht_mcs); } + /* ML partner links tag with 0 length */ + len = 0; + tlv = ptr; + tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len); + ptr += TLV_HDR_SIZE; + ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "wmi peer assoc vdev id %d assoc id %d peer mac %pM peer_flags %x rate_caps %x peer_caps %x listen_intval %d ht_caps %x max_mpdu %d nss %d phymode %d peer_mpdu_density %d vht_caps %x he cap_info %x he ops %x he cap_info_ext %x he phy %x %x %x peer_bw_rxnss_override %x peer_flags_ext %x eht mac_cap %x %x eht phy_cap %x %x %x\n", cmd->vdev_id, cmd->peer_associd, arg->peer_mac, From 9211df5c025a5e50de8b8cb0798c1120f8593d8a Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Wed, 2 Aug 2023 20:04:06 +0300 Subject: [PATCH 28/32] wifi: ath12k: parse WMI service ready ext2 event Parse WMI service ready ext2 event. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230725224034.14045-11-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.c | 48 +++++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/wmi.h | 16 +++++++++ 2 files changed, 64 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 24f6c1dbd7439..35f65b7e23920 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -62,7 +62,23 @@ struct ath12k_wmi_svc_rdy_ext_parse { bool dma_ring_cap_done; }; +struct ath12k_wmi_svc_rdy_ext2_arg { + u32 reg_db_version; + u32 hw_min_max_tx_power_2ghz; + u32 hw_min_max_tx_power_5ghz; + u32 chwidth_num_peer_caps; + u32 preamble_puncture_bw; + u32 max_user_per_ppdu_ofdma; + u32 max_user_per_ppdu_mumimo; + u32 target_cap_flags; + u32 eht_cap_mac_info[WMI_MAX_EHTCAP_MAC_SIZE]; + u32 max_num_linkview_peers; + u32 max_num_msduq_supported_per_tid; + u32 default_num_msduq_supported_per_tid; +}; + struct ath12k_wmi_svc_rdy_ext2_parse { + struct ath12k_wmi_svc_rdy_ext2_arg arg; struct ath12k_wmi_dma_ring_caps_parse dma_caps_parse; bool dma_ring_cap_done; bool spectral_bin_scaling_done; @@ -4102,6 +4118,26 @@ static int ath12k_service_ready_ext_event(struct ath12k_base *ab, return ret; } +static int ath12k_pull_svc_ready_ext2(struct ath12k_wmi_pdev *wmi_handle, + const void *ptr, + struct ath12k_wmi_svc_rdy_ext2_arg *arg) +{ + const struct wmi_service_ready_ext2_event *ev = ptr; + + if (!ev) + return -EINVAL; + + arg->reg_db_version = le32_to_cpu(ev->reg_db_version); + arg->hw_min_max_tx_power_2ghz = le32_to_cpu(ev->hw_min_max_tx_power_2ghz); + arg->hw_min_max_tx_power_5ghz = le32_to_cpu(ev->hw_min_max_tx_power_5ghz); + arg->chwidth_num_peer_caps = le32_to_cpu(ev->chwidth_num_peer_caps); + arg->preamble_puncture_bw = le32_to_cpu(ev->preamble_puncture_bw); + arg->max_user_per_ppdu_ofdma = le32_to_cpu(ev->max_user_per_ppdu_ofdma); + arg->max_user_per_ppdu_mumimo = le32_to_cpu(ev->max_user_per_ppdu_mumimo); + arg->target_cap_flags = le32_to_cpu(ev->target_cap_flags); + return 0; +} + static void ath12k_wmi_eht_caps_parse(struct ath12k_pdev *pdev, u32 band, const __le32 cap_mac_info[], const __le32 cap_phy_info[], @@ -4225,10 +4261,22 @@ static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab, u16 tag, u16 len, const void *ptr, void *data) { + struct ath12k_wmi_pdev *wmi_handle = &ab->wmi_ab.wmi[0]; struct ath12k_wmi_svc_rdy_ext2_parse *parse = data; int ret; switch (tag) { + case WMI_TAG_SERVICE_READY_EXT2_EVENT: + ret = ath12k_pull_svc_ready_ext2(wmi_handle, ptr, + &parse->arg); + if (ret) { + ath12k_warn(ab, + "failed to extract wmi service ready ext2 parameters: %d\n", + ret); + return ret; + } + break; + case WMI_TAG_ARRAY_STRUCT: if (!parse->dma_ring_cap_done) { ret = ath12k_wmi_dma_ring_caps(ab, len, ptr, diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 93a70426df287..fdb79124ad9d3 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -1925,6 +1925,7 @@ enum wmi_tlv_tag { /* TODO add all the missing cmds */ WMI_TAG_PDEV_PEER_PKTLOG_FILTER_CMD = 0x301, WMI_TAG_PDEV_PEER_PKTLOG_FILTER_INFO, + WMI_TAG_SERVICE_READY_EXT2_EVENT = 0x334, WMI_TAG_FILS_DISCOVERY_TMPL_CMD = 0x344, WMI_TAG_MAC_PHY_CAPABILITIES_EXT = 0x36F, WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9, @@ -2612,6 +2613,21 @@ struct ath12k_wmi_soc_hal_reg_caps_params { #define WMI_EHT_MCS_NSS_10_11 GENMASK(11, 8) #define WMI_EHT_MCS_NSS_12_13 GENMASK(15, 12) +struct wmi_service_ready_ext2_event { + __le32 reg_db_version; + __le32 hw_min_max_tx_power_2ghz; + __le32 hw_min_max_tx_power_5ghz; + __le32 chwidth_num_peer_caps; + __le32 preamble_puncture_bw; + __le32 max_user_per_ppdu_ofdma; + __le32 max_user_per_ppdu_mumimo; + __le32 target_cap_flags; + __le32 eht_cap_mac_info[WMI_MAX_EHTCAP_MAC_SIZE]; + __le32 max_num_linkview_peers; + __le32 max_num_msduq_supported_per_tid; + __le32 default_num_msduq_supported_per_tid; +} __packed; + struct ath12k_wmi_caps_ext_params { __le32 hw_mode_id; union { From 07c01b86f21dd499bd487b70c1536f868fede241 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Wed, 2 Aug 2023 20:04:07 +0300 Subject: [PATCH 29/32] wifi: ath12k: configure puncturing bitmap Enable the feature flag to indicate the driver support for preamble puncturing. Firmware will support this feature by default from IEEE 802.11be onwards. Configure the bitmap as part of VDEV start/restart and peer association commands. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Signed-off-by: Muna Sinada Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230725224034.14045-12-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath12k/core.h | 1 + drivers/net/wireless/ath/ath12k/mac.c | 16 ++++++++++++++-- drivers/net/wireless/ath/ath12k/wmi.c | 2 ++ drivers/net/wireless/ath/ath12k/wmi.h | 12 +++++++++++- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index d0b625fea6336..4389ff40b49db 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -238,6 +238,7 @@ struct ath12k_vif { u32 key_cipher; u8 tx_encap_type; u8 vdev_stats_id; + u32 punct_bitmap; }; struct ath12k_vif_iter { diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 5b7a892e1f79a..48cf3f10a3bcd 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -842,6 +842,7 @@ static int ath12k_mac_monitor_vdev_start(struct ath12k *ar, int vdev_id, arg.pref_tx_streams = ar->num_tx_chains; arg.pref_rx_streams = ar->num_rx_chains; + arg.punct_bitmap = 0xFFFFFFFF; arg.passive |= !!(chandef->chan->flags & IEEE80211_CHAN_NO_IR); @@ -2139,6 +2140,7 @@ static void ath12k_peer_assoc_h_eht(struct ath12k *ar, const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap; const struct ieee80211_eht_mcs_nss_supp_20mhz_only *bw_20; const struct ieee80211_eht_mcs_nss_supp_bw *bw; + struct ath12k_vif *arvif = (struct ath12k_vif *)vif->drv_priv; u32 *rx_mcs, *tx_mcs; if (!sta->deflink.he_cap.has_he || !eht_cap->has_eht) @@ -2208,6 +2210,8 @@ static void ath12k_peer_assoc_h_eht(struct ath12k *ar, arg->peer_eht_mcs_count++; break; } + + arg->punct_bitmap = ~arvif->punct_bitmap; } static void ath12k_peer_assoc_prepare(struct ath12k *ar, @@ -2761,6 +2765,9 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP) ath12k_mac_fils_discovery(arvif, info); + if (changed & BSS_CHANGED_EHT_PUNCTURING) + arvif->punct_bitmap = info->eht_puncturing; + mutex_unlock(&ar->conf_mutex); } @@ -5800,6 +5807,7 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, arg.vdev_id = arvif->vdev_id; arg.dtim_period = arvif->dtim_period; arg.bcn_intval = arvif->beacon_interval; + arg.punct_bitmap = ~arvif->punct_bitmap; arg.freq = chandef->chan->center_freq; arg.band_center_freq1 = chandef->center_freq1; @@ -5842,9 +5850,9 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, arg.passive |= !!(chandef->chan->flags & IEEE80211_CHAN_NO_IR); ath12k_dbg(ab, ATH12K_DBG_MAC, - "mac vdev %d start center_freq %d phymode %s\n", + "mac vdev %d start center_freq %d phymode %s punct_bitmap 0x%x\n", arg.vdev_id, arg.freq, - ath12k_mac_phymode_str(arg.mode)); + ath12k_mac_phymode_str(arg.mode), arg.punct_bitmap); ret = ath12k_wmi_vdev_start(ar, &arg, restart); if (ret) { @@ -6171,6 +6179,8 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, "mac chanctx assign ptr %pK vdev_id %i\n", ctx, arvif->vdev_id); + arvif->punct_bitmap = link_conf->eht_puncturing; + /* for some targets bss peer must be created before vdev_start */ if (ab->hw_params->vdev_start_delay && arvif->vdev_type != WMI_VDEV_TYPE_AP && @@ -7298,6 +7308,8 @@ static int __ath12k_mac_register(struct ath12k *ar) NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP); } + wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_PUNCT); + ath12k_reg_init(ar); if (!test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) { diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 35f65b7e23920..c611a19c73645 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -1021,6 +1021,7 @@ int ath12k_wmi_vdev_start(struct ath12k *ar, struct wmi_vdev_start_req_arg *arg, cmd->cac_duration_ms = cpu_to_le32(arg->cac_duration_ms); cmd->regdomain = cpu_to_le32(arg->regdomain); cmd->he_ops = cpu_to_le32(arg->he_ops); + cmd->punct_bitmap = cpu_to_le32(arg->punct_bitmap); if (!restart) { if (arg->ssid) { @@ -1942,6 +1943,7 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, cmd->peer_new_assoc = cpu_to_le32(arg->peer_new_assoc); cmd->peer_associd = cpu_to_le32(arg->peer_associd); + cmd->punct_bitmap = cpu_to_le32(arg->punct_bitmap); ath12k_wmi_copy_peer_flags(cmd, arg, test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index fdb79124ad9d3..8c047a9623f9b 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2775,6 +2775,11 @@ struct wmi_vdev_start_request_cmd { __le32 he_ops; __le32 cac_duration_ms; __le32 regdomain; + __le32 min_data_rate; + __le32 mbssid_flags; + __le32 mbssid_tx_vdev_id; + __le32 eht_ops; + __le32 punct_bitmap; } __packed; #define MGMT_TX_DL_FRM_LEN 64 @@ -2874,6 +2879,10 @@ struct wmi_vdev_start_req_arg { u32 pref_rx_streams; u32 pref_tx_streams; u32 num_noa_descriptors; + u32 min_data_rate; + u32 mbssid_flags; + u32 mbssid_tx_vdev_id; + u32 punct_bitmap; }; struct ath12k_wmi_peer_create_arg { @@ -3604,6 +3613,7 @@ struct ath12k_wmi_peer_assoc_arg { u32 peer_eht_rx_mcs_set[WMI_MAX_EHTCAP_RATE_SET]; u32 peer_eht_tx_mcs_set[WMI_MAX_EHTCAP_RATE_SET]; struct ath12k_wmi_ppe_threshold_arg peer_eht_ppet; + u32 punct_bitmap; }; struct wmi_peer_assoc_complete_cmd { @@ -3639,7 +3649,7 @@ struct wmi_peer_assoc_complete_cmd { __le32 bss_max_idle_option; __le32 auth_mode; __le32 peer_flags_ext; - __le32 puncture_20mhz_bitmap; + __le32 punct_bitmap; __le32 peer_eht_cap_mac[WMI_MAX_EHTCAP_MAC_SIZE]; __le32 peer_eht_cap_phy[WMI_MAX_EHTCAP_PHY_SIZE]; __le32 peer_eht_ops; From 89a9dda1430a71fe95ad2b4f8056e7aa15b4aee7 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Wed, 2 Aug 2023 20:04:09 +0300 Subject: [PATCH 30/32] wifi: ath12k: relax list iteration in ath12k_mac_vif_unref() In ath12k_mac_vif_unref() dp->tx_desc_used_list[i] is not altered so list_for_each_entry() should be safe. Signed-off-by: Dmitry Antipov Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230704173718.73462-1-dmantipov@yandex.ru --- drivers/net/wireless/ath/ath12k/mac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 48cf3f10a3bcd..0f2af2f14ef76 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5542,7 +5542,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, static void ath12k_mac_vif_unref(struct ath12k_dp *dp, struct ieee80211_vif *vif) { - struct ath12k_tx_desc_info *tx_desc_info, *tmp1; + struct ath12k_tx_desc_info *tx_desc_info; struct ath12k_skb_cb *skb_cb; struct sk_buff *skb; int i; @@ -5550,8 +5550,8 @@ static void ath12k_mac_vif_unref(struct ath12k_dp *dp, struct ieee80211_vif *vif for (i = 0; i < ATH12K_HW_MAX_QUEUES; i++) { spin_lock_bh(&dp->tx_desc_lock[i]); - list_for_each_entry_safe(tx_desc_info, tmp1, &dp->tx_desc_used_list[i], - list) { + list_for_each_entry(tx_desc_info, &dp->tx_desc_used_list[i], + list) { skb = tx_desc_info->skb; if (!skb) continue; From 9632ea57be659887ab0d28a2a1d7b901dfddd263 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Sun, 16 Jul 2023 23:44:57 -0400 Subject: [PATCH 31/32] wifi: ath12k: add handler for scan event WMI_SCAN_EVENT_DEQUEUED When wlan interface is up, and 11d scan is sent to the firmware, then firmware needs to spend couple of seconds to complete the 11d scan. If normal scan from user space arrives to ath12k at this moment, then the normal scan request is also sent to the firmware, but the scan started event will be reported to ath12k until the 11d scan complete. When timed out for the scan started in ath12k, ath12k stops the normal scan and the firmware reports WMI_SCAN_EVENT_DEQUEUED to ath12k for the normal scan. ath12k has no handler for the event and then timed out for the scan completed in ath12k_scan_stop(), and ath12k prints the following error message. [ 1491.604750] ath12k_pci 0000:02:00.0: failed to receive scan abort comple: timed out [ 1491.604756] ath12k_pci 0000:02:00.0: failed to stop scan: -110 [ 1491.604758] ath12k_pci 0000:02:00.0: failed to start hw scan: -110 Add a handler for WMI_SCAN_EVENT_DEQUEUED and then complete the scan to get rid of the above error message. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Wen Gong Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230717034457.22162-1-quic_wgong@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index c611a19c73645..fab4d33c89843 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -5948,6 +5948,8 @@ static void ath12k_scan_event(struct ath12k_base *ab, struct sk_buff *skb) ath12k_wmi_event_scan_start_failed(ar); break; case WMI_SCAN_EVENT_DEQUEUED: + __ath12k_mac_scan_finish(ar); + break; case WMI_SCAN_EVENT_PREEMPTED: case WMI_SCAN_EVENT_RESTARTED: case WMI_SCAN_EVENT_FOREIGN_CHAN_EXIT: From 8198950ccb7d311f8b4389441d8dcb597f926340 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Mon, 17 Jul 2023 22:47:24 -0400 Subject: [PATCH 32/32] wifi: ath12k: avoid deadlock by change ieee80211_queue_work for regd_update_work Deadlock is easily happened while shutdown wlan interface such as run "ifconfig wlan0 down". The reason is because when ar->regd_update_work is ran, it will call wiphy_lock(ar->hw->wiphy) in function ath12k_regd_update() which is running in workqueue of ieee80211_local queued by ieee80211_queue_work(). Another thread from "ifconfig wlan0 down" will also accuqire the lock by wiphy_lock(sdata->local->hw.wiphy) in function ieee80211_stop(), and then it call ieee80211_stop_device() to flush_workqueue(local->workqueue), this will wait the workqueue of ieee80211_local finished. Then deadlock will happen easily if the two thread run meanwhile. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Wen Gong Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230718024724.29120-1-quic_wgong@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index fab4d33c89843..9ed33e2d6da02 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -5473,7 +5473,7 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk ar = ab->pdevs[pdev_idx].ar; kfree(ab->new_regd[pdev_idx]); ab->new_regd[pdev_idx] = regd; - ieee80211_queue_work(ar->hw, &ar->regd_update_work); + queue_work(ab->workqueue, &ar->regd_update_work); } else { /* Multiple events for the same *ar is not expected. But we * can still clear any previously stored default_regd if we