Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [PATCH v8 3/6] wifi: mac80211: Use struct instead of macro for PERR frame
From: Johannes Berg @ 2026-05-28  8:00 UTC (permalink / raw)
  To: Masashi Honma, linux-wireless
In-Reply-To: <20260521225842.31815-3-masashi.honma@gmail.com>

Hi,

So I was just about to apply this set, but now I'm thinking about this:


> +struct ieee80211_mesh_hwmp_perr_dst {
> +	u8 flags;
> +	u8 addr[ETH_ALEN];
> +	__le32 sn;
> +	/* optional Destination External Address */
> +	u8 variable[];
> +} __packed;

This has a variable member, and the presence of the address in
'variable' depends on the flags (AE_F set there.)

> +struct ieee80211_mesh_hwmp_perr {
> +	u8 ttl;
> +	u8 number_of_dst;
> +	struct ieee80211_mesh_hwmp_perr_dst dsts[];
> +} __packed;

However this declares an array of these, and that doesn't really seem
right. It effectively puts non-variable fields (e.g. dsts[1].ttl) after
the variable field dsts[0].variable. I _think_ some compilers (versions)
will also (rightfully) complain about this.

It seems like this should just be

struct ... {
	u8 ttl;
	u8 number_of_dst;

	/* list of variably sized struct ieee80211_mesh_hwmp_perr_dst
*/
	u8 dsts[];
} __packed;

> +static inline u16
> +ieee80211_mesh_hwmp_perr_get_rcode(const u8 *ie, u8 dst_idx)
> +{
> +	struct ieee80211_mesh_hwmp_perr *perr_ie = (void *)ie;
> +	struct ieee80211_mesh_hwmp_perr_dst *dst =
> +		&perr_ie->dsts[dst_idx];

And especially this indexing doesn't seem like it could work - you have
to walk through all of them to see if each has the AE_F set and skip
sizeof() + optional ETH_ALEN.

> +
> +	return get_unaligned_le16(&dst->variable[
> +		(dst->flags & AE_F) ? ETH_ALEN : 0]);

This looks like the comment above should be

	/* optional Destination External Address, rcode */
	u8 variable[];
	
or so?

> +	target_rcode = ieee80211_mesh_hwmp_perr_get_rcode(perr_elem, 0);

but evidently, this doesn't really matter right now if only one
destination entry is ever read.

Still, please fix that, if only to avoid the compiler warnings I'm
imagining will happen.

johannes

^ permalink raw reply

* Re: [PATCH ath-next] wifi: ath12k: avoid setting 320MHZ support on non 6GHz band
From: Rameshkumar Sundaram @ 2026-05-28  7:56 UTC (permalink / raw)
  To: Nicolas Escande, ath12k; +Cc: linux-wireless
In-Reply-To: <20260123144224.2216923-1-nico.escande@gmail.com>

On 1/23/2026 8:12 PM, Nicolas Escande wrote:
> On a split phy qcn9274 (2.4GHz + 5GHz low), "iw phy" reports 320MHz
> realated features on the 5GHz band while it should not:
> 
>      Wiphy phy1
>      [...]
>          Band 2:
>      [...]
>              EHT Iftypes: managed
>      [...]
>                  EHT PHY Capabilities: (0xe2ffdbe018778000):
>                      320MHz in 6GHz Supported
>      [...]
>                      Beamformee SS (320MHz): 7
>      [...]
>                      Number Of Sounding Dimensions (320MHz): 3
>      [...]
>                  EHT MCS/NSS: (0x22222222222222222200000000):
> 
> This is also reflected in the beacons sent by a mesh interface started on
> that band. They erroneously advertise 320MHZ support too.
> 
> This should not happen as the spec at section 9.4.2.323.3 says we should
> not set the 320MHz related fields when not operating on a 6GHz band.
> For example it says about Bit 0 "Support For 320 MHz In 6 GHz"
> 
>    "Reserved if the EHT Capabilities element is indicating capabilities for
>     the 2.4 GHz or 5 GHz bands."
> 
> Fix this by clearing the related bits when converting from WMI eht phy
> capabilities to mac80211 phy capabilities, for bands other than 6GHz.
> 
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00218-QCAHKSWPL_SILICONZ-1
> 
> Signed-off-by: Nicolas Escande <nico.escande@gmail.com>
> ---
>   drivers/net/wireless/ath/ath12k/wmi.c | 9 ++++++++-
>   1 file changed, 8 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index 84c29e4896a4..14947fdb9813 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -4888,6 +4888,7 @@ static void ath12k_wmi_eht_caps_parse(struct ath12k_pdev *pdev, u32 band,
>   				       __le32 cap_info_internal)
>   {
>   	struct ath12k_band_cap *cap_band = &pdev->cap.band[band];
> +	u8 *phy_cap = (u8 *)&cap_band->eht_cap_phy_info[0];
>   	u32 support_320mhz;
>   	u8 i;
>   
> @@ -4901,8 +4902,14 @@ static void ath12k_wmi_eht_caps_parse(struct ath12k_pdev *pdev, u32 band,
>   	for (i = 0; i < WMI_MAX_EHTCAP_PHY_SIZE; i++)
>   		cap_band->eht_cap_phy_info[i] = le32_to_cpu(cap_phy_info[i]);
>   
> -	if (band == NL80211_BAND_6GHZ)
> +	if (band == NL80211_BAND_6GHZ) {
>   		cap_band->eht_cap_phy_info[0] |= support_320mhz;
> +	} else {
> +		phy_cap[0] &= ~IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ;
> +		phy_cap[1] &= ~IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK;
> +		phy_cap[2] &= ~IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK;

This field is split across PHY capability byte 2 and byte 3, so should
IEEE80211_EHT_PHY_CAP3_SOUNDING_DIM_320MHZ_MASK be cleared as well ?


> +		phy_cap[6] &= ~IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_320MHZ;
> +	}
>   
>   	cap_band->eht_mcs_20_only = le32_to_cpu(supp_mcs[0]);
>   	cap_band->eht_mcs_80 = le32_to_cpu(supp_mcs[1]);


Since you said "On a split phy qcn9274 (2.4GHz + 5GHz low)" i wonder how 
firmware set 6GHz capability bits in this case. That said, the approach 
looks fine to me, although I would prefer to clear the remaining related 
bits as well:

   IEEE80211_EHT_PHY_CAP3_SOUNDING_DIM_320MHZ_MASK
   IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_320MHZ
   IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP
   IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ
   IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ


-- 
--
Ramesh


^ permalink raw reply

* Re: [PATCH v3 1/7] b43: add firmware mappings and remove comments wondering about rev22 initvals
From: Johannes Berg @ 2026-05-28  7:43 UTC (permalink / raw)
  To: Alessio Ferri, linux-wireless, b43-dev, linux-kernel
In-Reply-To: <20260524-b43_complete_n_phy_rev_8_radio_2057_rev_8_support-v1-1-cdad2c8526c6@gmail.com>

On Sun, 2026-05-24 at 23:56 +0200, Alessio Ferri wrote:
> Assisted-by: Claude:claude-4.7-opus
> Signed-off-by: Alessio Ferri <alessio.ferri@mythread.it>

Please don't squeeze the entire commit message into the subject and then
omit the real one.

johannes

^ permalink raw reply

* Re: [PATCH wireless-next v2 00/31] wifi: mm81x: add mm81x driver
From: Lachlan Hodges @ 2026-05-28  6:48 UTC (permalink / raw)
  To: johannes; +Cc: arien.judge, dan.callaghan, ayman.grais, linux-wireless
In-Reply-To: <20260430045615.334669-1-lachlan.hodges@morsemicro.com>

Hi,

I have just posted the first RFC for the S1G work in hostapd that can
be used with this driver if anyone is wanting to test this out.

https://patchwork.ozlabs.org/project/hostap/cover/20260528063857.950556-1-lachlan.hodges@morsemicro.com/

lachlan

^ permalink raw reply

* [PATCH 5.15.y] wifi: brcmfmac: fix use-after-free when rescheduling brcmf_btcoex_info work
From: Robert Garcia @ 2026-05-28  5:54 UTC (permalink / raw)
  To: stable, Duoming Zhou
  Cc: Johannes Berg, Arend van Spriel, Franky Lin, Hante Meuleman,
	Chi-hsien Lin, Wright Feng, Chung-hsien Hsu, Kalle Valo,
	David S . Miller, Jakub Kicinski, Piotr Haber, John W . Linville,
	Pieter-Paul Giesberts, Robert Garcia, linux-wireless,
	brcm80211-dev-list.pdl, SHA-cyfmac-dev-list, netdev, linux-kernel

From: Duoming Zhou <duoming@zju.edu.cn>

[ Upstream commit 9cb83d4be0b9b697eae93d321e0da999f9cdfcfc ]

The brcmf_btcoex_detach() only shuts down the btcoex timer, if the
flag timer_on is false. However, the brcmf_btcoex_timerfunc(), which
runs as timer handler, sets timer_on to false. This creates critical
race conditions:

1.If brcmf_btcoex_detach() is called while brcmf_btcoex_timerfunc()
is executing, it may observe timer_on as false and skip the call to
timer_shutdown_sync().

2.The brcmf_btcoex_timerfunc() may then reschedule the brcmf_btcoex_info
worker after the cancel_work_sync() has been executed, resulting in
use-after-free bugs.

The use-after-free bugs occur in two distinct scenarios, depending on
the timing of when the brcmf_btcoex_info struct is freed relative to
the execution of its worker thread.

Scenario 1: Freed before the worker is scheduled

The brcmf_btcoex_info is deallocated before the worker is scheduled.
A race condition can occur when schedule_work(&bt_local->work) is
called after the target memory has been freed. The sequence of events
is detailed below:

CPU0                           | CPU1
brcmf_btcoex_detach            | brcmf_btcoex_timerfunc
                               |   bt_local->timer_on = false;
  if (cfg->btcoex->timer_on)   |
    ...                        |
  cancel_work_sync();          |
  ...                          |
  kfree(cfg->btcoex); // FREE  |
                               |   schedule_work(&bt_local->work); // USE

Scenario 2: Freed after the worker is scheduled

The brcmf_btcoex_info is freed after the worker has been scheduled
but before or during its execution. In this case, statements within
the brcmf_btcoex_handler() — such as the container_of macro and
subsequent dereferences of the brcmf_btcoex_info object will cause
a use-after-free access. The following timeline illustrates this
scenario:

CPU0                            | CPU1
brcmf_btcoex_detach             | brcmf_btcoex_timerfunc
                                |   bt_local->timer_on = false;
  if (cfg->btcoex->timer_on)    |
    ...                         |
  cancel_work_sync();           |
  ...                           |   schedule_work(); // Reschedule
                                |
  kfree(cfg->btcoex); // FREE   |   brcmf_btcoex_handler() // Worker
  /*                            |     btci = container_of(....); // USE
   The kfree() above could      |     ...
   also occur at any point      |     btci-> // USE
   during the worker's execution|
   */                           |

To resolve the race conditions, drop the conditional check and call
timer_shutdown_sync() directly. It can deactivate the timer reliably,
regardless of its current state. Once stopped, the timer_on state is
then set to false.

Fixes: 61730d4dfffc ("brcmfmac: support critical protocol API for DHCP")
Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
Signed-off-by: Duoming Zhou <duoming@zju.edu.cn>
Link: https://patch.msgid.link/20250822050839.4413-1-duoming@zju.edu.cn
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Robert Garcia <rob_garcia@163.com>
---
 drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c
index f9f18ff451ea..f46e40900217 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c
@@ -392,10 +392,8 @@ void brcmf_btcoex_detach(struct brcmf_cfg80211_info *cfg)
 	if (!cfg->btcoex)
 		return;
 
-	if (cfg->btcoex->timer_on) {
-		cfg->btcoex->timer_on = false;
-		del_timer_sync(&cfg->btcoex->timer);
-	}
+	del_timer_sync(&cfg->btcoex->timer);
+	cfg->btcoex->timer_on = false;
 
 	cancel_work_sync(&cfg->btcoex->work);
 
-- 
2.34.1


^ permalink raw reply related

* [PATCH v2] wifi: mt76: add wcid publish check in mt76_sta_add
From: Jiajia Liu @ 2026-05-28  3:38 UTC (permalink / raw)
  To: Felix Fietkau, Lorenzo Bianconi, Ryder Lee, Shayne Chen,
	Sean Wang, Matthias Brugger, AngeloGioacchino Del Regno,
	Ming Yen Hsieh, Leon Yen
  Cc: linux-wireless, linux-kernel, linux-arm-kernel, linux-mediatek,
	Jiajia Liu

Since mt7925_mac_sta_add publishes wcid, add publish check in mt76_sta_add
to avoid reinitializing the wcid->poll_list.

Found dev->sta_poll_list corruption when using mt7925 and 7.1-rc4.
According to the corruption information, prev->next was changed to itself.

wlan0: disconnect from AP 90:fb:5d:94:8b:e3 for new auth to 90:fb:5d:94:8b:e2
wlan0: authenticate with 90:fb:5d:94:8b:e2 (local address=84:9e:56:9c:7e:6b)
wlan0: send auth to 90:fb:5d:94:8b:e2 (try 1/3)
 slab kmalloc-8k start ffff8c80958a6000 pointer offset 4160 size 8192
list_add corruption. prev->next should be next (ffff8c808a7488f8), but was ffff8c80958a7040. (prev=ffff8c80958a7040).

 mt76_wcid_add_poll+0x95/0xd0 [mt76]
 mt7925_mac_add_txs.part.0+0xa5/0xe0 [mt7925_common]
 mt7925_rx_check+0xa7/0xc0 [mt7925_common]
 mt76_dma_rx_poll+0x50d/0x790 [mt76]
 mt792x_poll_rx+0x52/0xe0 [mt792x_lib]

Signed-off-by: Jiajia Liu <liujiajia@kylinos.cn>
---

Changes in v2:
  - use dev->wcid table instead of adding MT_WCID_FLAG_DRV_PUBLSH for
    wcid publish check suggested by Sean
  - subject and commit message update

---
 drivers/net/wireless/mediatek/mt76/mac80211.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index 4ae5e4715a9c..b78b4cd206e0 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -1576,6 +1576,7 @@ mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif,
 {
 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
 	struct mt76_dev *dev = phy->dev;
+	struct mt76_wcid *published;
 	int ret;
 	int i;
 
@@ -1595,11 +1596,19 @@ mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif,
 		mtxq->wcid = wcid->idx;
 	}
 
-	ewma_signal_init(&wcid->rssi);
-	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
+	published = rcu_dereference_protected(dev->wcid[wcid->idx],
+					      lockdep_is_held(&dev->mutex));
+	if (published != wcid) {
+		WARN_ON_ONCE(published);
+		ewma_signal_init(&wcid->rssi);
+		rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
+		mt76_wcid_init(wcid, phy->band_idx);
+	} else {
+		wcid->phy_idx = phy->band_idx;
+	}
+
 	phy->num_sta++;
 
-	mt76_wcid_init(wcid, phy->band_idx);
 out:
 	mutex_unlock(&dev->mutex);
 
-- 
2.53.0


^ permalink raw reply related

* [RESEND] Ongoing instability and connection loops with MT7922 (mt7921e driver)
From: Angel Parra @ 2026-05-28  1:44 UTC (permalink / raw)
  To: Linux Wireless Mailing List

Hello,
I was advised to reach out to this mailing list regarding severe 
wireless connection issues with my MediaTek card. I am writing to 
request a review of the `mt7921e` driver. While I appreciate the 
significant improvements made to the `mt7902` driver recently, the 
support for some newer chipsets currently feels almost unusable in 
real-world conditions.

My hardware details are as follows:
```text
02:00.0 Network controller: MEDIATEK Corp. MT7922 802.11ax PCI Express 
Wireless Network Adapter
         Subsystem: Foxconn International, Inc. Device e0cd
         Kernel driver in use: mt7921e
```

Below are the most consistent bugs and instabilities I have observed to 
the date that constantly interrupt our workflow:

* The adapter often fails to discover nearby access points, despite 
multiple mobile phones confirming their active presence.
* Both 2.4GHz and 5GHz WLANs frequently remain undetected, even when the 
laptop is directly next to the router.
* Regardless of physical proximity to the modem, the connection process 
regularly hangs on "Configuring interface" (in the KDE Plasma desktop 
applet) for over 15 seconds. After this delay, the connection either 
succeeds or fails completely.
* When successfully connected to 2.4GHz bands, download speeds are 
remarkably slow and fall significantly below what my phone achieves on 
the same connection.
* The detection range is severely limited; establishing a link to a 5GHz 
SSID requires being in the exact same room as the access point.
* Introducing a single wall between the router and the laptop triggers 
the aforementioned 15-second "Configuring interface" hang, usually 
resulting in a failed connection.
* Upon failing to connect to an otherwise healthy access point, the 
system enters an infinite loop. It hangs on configuration, fails, jumps 
to the next saved SSID, fails again, and cycles endlessly through all 
saved profiles.
* Overall connection stability is exceptionally poor. A successful 
connection might persist only if the laptop remains perfectly 
stationary. Otherwise, the link randomly drops after a few minutes with 
a "Connection deactivated" state, triggering the failed connection loop.
* Attempting to bypass these issues by tethering to a mobile hotspot 
directly next to the laptop also fails. The adapter either cannot detect 
the hotspot at all or hangs during configuration, leaving the machine 
entirely offline.

The failing connection loop in `dmesg` looks like this over a span of 
several minutes, clearly illustrating the continuous authentication 
timeouts as the adapter cycles through my saved profiles:

```text
[148485.661369] PM: suspend exit
[148488.781860] wlp2s0: authenticate with f8:64:b8:b8:3d:7a (local 
address=38:d5:7a:12:c2:3b)
[148488.795305] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 1/3)
[148488.843935] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 2/3)
[148488.996043] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 3/3)
[148489.044916] wlp2s0: authentication with f8:64:b8:b8:3d:7a timed out
[148491.867424] wlp2s0: authenticate with f8:64:b8:b8:3d:7a (local 
address=38:d5:7a:12:c2:3b)
[148491.880895] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 1/3)
[148491.939014] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 2/3)
[148492.094896] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 3/3)
[148492.142676] wlp2s0: authentication with f8:64:b8:b8:3d:7a timed out
[148495.354718] wlp2s0: authenticate with f8:64:b8:b8:3d:7a (local 
address=38:d5:7a:12:c2:3b)
[148495.368216] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 1/3)
[148495.418798] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 2/3)
[148495.577799] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 3/3)
[148495.625990] wlp2s0: authentication with f8:64:b8:b8:3d:7a timed out
[148499.324558] wlp2s0: authenticate with f8:64:b8:b8:3d:7a (local 
address=38:d5:7a:12:c2:3b)
[148499.337991] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 1/3)
[148499.387641] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 2/3)
[148499.542987] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 3/3)
[148499.593575] wlp2s0: authentication with f8:64:b8:b8:3d:7a timed out
[148510.294935] wlp2s0: authenticate with f8:64:b8:b8:3d:7a (local 
address=38:d5:7a:12:c2:3b)
[148510.308356] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 1/3)
[148510.360427] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 2/3)
[148510.406754] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 3/3)
[148510.566970] wlp2s0: authentication with f8:64:b8:b8:3d:7a timed out
[148520.573843] wlp2s0: authenticate with 84:d8:1b:9f:91:10 (local 
address=38:d5:7a:12:c2:3b)
[148520.587285] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 1/3)
[148520.644274] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 2/3)
[148520.693177] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 3/3)
[148521.140382] wlp2s0: authentication with 84:d8:1b:9f:91:10 timed out
[148541.462597] wlp2s0: authenticate with 84:d8:1b:9f:91:10 (local 
address=38:d5:7a:12:c2:3b)
[148541.476062] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 1/3)
[148541.522330] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 2/3)
[148541.973505] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 3/3)
[148542.022304] wlp2s0: authentication with 84:d8:1b:9f:91:10 timed out
[148548.610998] wlp2s0: authenticate with f8:64:b8:b8:3d:7a (local 
address=38:d5:7a:12:c2:3b)
[148548.624376] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 1/3)
[148549.075668] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 2/3)
[148549.121771] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 3/3)
[148549.574886] wlp2s0: authentication with f8:64:b8:b8:3d:7a timed out
[148552.427178] wlp2s0: authenticate with 84:d8:1b:9f:91:10 (local 
address=38:d5:7a:12:c2:3b)
[148552.430014] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 1/3)
[148552.470639] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 2/3)
[148552.513942] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 3/3)
[148552.556374] wlp2s0: authentication with 84:d8:1b:9f:91:10 timed out
[148565.252575] wlp2s0: authenticate with 84:d8:1b:9f:91:10 (local 
address=38:d5:7a:12:c2:3b)
[148565.266023] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 1/3)
[148565.396382] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 2/3)
[148565.446749] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 3/3)
[148565.605849] wlp2s0: authentication with 84:d8:1b:9f:91:10 timed out
[148579.997166] wlp2s0: authenticate with 84:d8:1b:9f:91:10 (local 
address=38:d5:7a:12:c2:3b)
[148580.010594] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 1/3)
[148580.072257] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 2/3)
[148580.112398] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 3/3)
[148580.152361] wlp2s0: authentication with 84:d8:1b:9f:91:10 timed out
[148592.848439] wlp2s0: authenticate with 84:d8:1b:9f:91:10 (local 
address=38:d5:7a:12:c2:3b)
[148592.861867] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 1/3)
[148592.903480] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 2/3)
[148592.995422] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 3/3)
[148593.041528] wlp2s0: authentication with 84:d8:1b:9f:91:10 timed out
[148607.612953] wlp2s0: authenticate with f8:64:b8:b8:3d:7a (local 
address=38:d5:7a:12:c2:3b)
[148607.626393] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 1/3)
[148607.698476] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 2/3)
[148607.742091] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 3/3)
[148607.783429] wlp2s0: authentication with f8:64:b8:b8:3d:7a timed out
[148620.219579] wlp2s0: authenticate with 84:d8:1b:9f:91:10 (local 
address=38:d5:7a:12:c2:3b)
[148620.233011] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 1/3)
[148620.328013] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 2/3)
[148620.374159] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 3/3)
[148620.534020] wlp2s0: authentication with 84:d8:1b:9f:91:10 timed out
[148633.224869] wlp2s0: authenticate with 84:d8:1b:9f:91:10 (local 
address=38:d5:7a:12:c2:3b)
[148633.238306] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 1/3)
[148633.303939] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 2/3)
[148633.356603] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 3/3)
[148633.514978] wlp2s0: authentication with 84:d8:1b:9f:91:10 timed out
[148637.634640] wlp2s0: authenticate with f8:64:b8:b8:3d:7a (local 
address=38:d5:7a:12:c2:3b)
[148637.647620] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 1/3)
[148637.694360] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 2/3)
[148637.743291] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 3/3)
[148638.192244] wlp2s0: authentication with f8:64:b8:b8:3d:7a timed out
[148655.509368] wlp2s0: authenticate with 84:d8:1b:9f:91:10 (local 
address=38:d5:7a:12:c2:3b)
[148655.522809] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 1/3)
[148655.572981] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 2/3)
[148656.021379] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 3/3)
[148656.070061] wlp2s0: authentication with 84:d8:1b:9f:91:10 timed out
[148677.626050] wlp2s0: authenticate with f8:64:b8:b8:3d:7a (local 
address=38:d5:7a:12:c2:3b)
[148677.639450] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 1/3)
[148677.704689] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 2/3)
[148677.753188] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 3/3)
[148677.914243] wlp2s0: authentication with f8:64:b8:b8:3d:7a timed out
[148680.509871] wlp2s0: authenticate with 84:d8:1b:9f:91:10 (local 
address=38:d5:7a:12:c2:3b)
[148680.512694] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 1/3)
[148680.530021] wlp2s0: authenticated
[148680.530280] wlp2s0: associate with 84:d8:1b:9f:91:10 (try 1/3)
[148680.555487] wlp2s0: RX AssocResp from 84:d8:1b:9f:91:10 (capab=0x411 
status=0 aid=4)
[148680.582777] wlp2s0: associated
[149142.517235] nvidia-modeset: WARNING: GPU:0: Correcting number of 
heads for current head configuration (0x00)
[149361.823195] wlp2s0: Connection to AP 84:d8:1b:9f:91:10 lost
[149418.133906] wlp2s0: authenticate with 84:d8:1b:9f:91:10 (local 
address=38:d5:7a:12:c2:3b)
[149418.145316] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 1/3)
[149418.194402] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 2/3)
[149418.242746] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 3/3)
[149418.692292] wlp2s0: authentication with 84:d8:1b:9f:91:10 timed out
[149437.001016] wlp2s0: authenticate with 84:d8:1b:9f:91:10 (local 
address=38:d5:7a:12:c2:3b)
[149437.012391] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 1/3)
[149437.095855] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 2/3)
[149437.142168] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 3/3)
[149437.593548] wlp2s0: authentication with 84:d8:1b:9f:91:10 timed out
[149464.557438] wlp2s0: authenticate with 84:d8:1b:9f:91:10 (local 
address=38:d5:7a:12:c2:3b)
[149464.568407] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 1/3)
[149464.730630] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 2/3)
[149464.777125] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 3/3)
[149464.932766] wlp2s0: authentication with 84:d8:1b:9f:91:10 timed out
[149474.631073] wlp2s0: authenticate with 84:d8:1b:9f:91:10 (local 
address=38:d5:7a:12:c2:3b)
[149474.644554] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 1/3)
[149474.690700] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 2/3)
[149474.849313] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 3/3)
[149474.895328] wlp2s0: authentication with 84:d8:1b:9f:91:10 timed out
[149535.532981] wlp2s0: authenticate with 84:d8:1b:9f:91:10 (local 
address=38:d5:7a:12:c2:3b)
[149535.546820] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 1/3)
[149535.678835] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 2/3)
[149535.725111] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 3/3)
[149535.880819] wlp2s0: authentication with 84:d8:1b:9f:91:10 timed out
[149879.705065] wlp2s0: authenticate with 84:d8:1b:9f:91:10 (local 
address=38:d5:7a:12:c2:3b)
[149879.718556] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 1/3)
[149879.794297] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 2/3)
[149879.843592] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 3/3)
[149880.017253] wlp2s0: authentication with 84:d8:1b:9f:91:10 timed out
[149888.633997] wlp2s0: authenticate with 84:d8:1b:9f:91:10 (local 
address=38:d5:7a:12:c2:3b)
[149888.647548] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 1/3)
[149888.805077] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 2/3)
[149888.856075] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 3/3)
[149889.015401] wlp2s0: authentication with 84:d8:1b:9f:91:10 timed out
[149928.562888] wlp2s0: authenticate with 84:d8:1b:9f:91:10 (local 
address=38:d5:7a:12:c2:3b)
[149928.576448] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 1/3)
[149928.619097] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 2/3)
[149928.661687] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 3/3)
[149928.737998] wlp2s0: authentication with 84:d8:1b:9f:91:10 timed out
[149941.444820] wlp2s0: authenticate with 84:d8:1b:9f:91:10 (local 
address=38:d5:7a:12:c2:3b)
[149941.458370] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 1/3)
[149941.615999] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 2/3)
[149941.662509] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 3/3)
[149941.711201] wlp2s0: authentication with 84:d8:1b:9f:91:10 timed out
[149956.605669] wlp2s0: authenticate with 84:d8:1b:9f:91:10 (local 
address=38:d5:7a:12:c2:3b)
[149956.619156] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 1/3)
[149956.673039] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 2/3)
[149956.721411] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 3/3)
[149957.172885] wlp2s0: authentication with 84:d8:1b:9f:91:10 timed out
[149969.882794] wlp2s0: authenticate with 84:d8:1b:9f:91:10 (local 
address=38:d5:7a:12:c2:3b)
[149969.896301] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 1/3)
[149969.943140] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 2/3)
[149969.990954] wlp2s0: send auth to 84:d8:1b:9f:91:10 (try 3/3)
[149970.442757] wlp2s0: authentication with 84:d8:1b:9f:91:10 timed out
[149984.624558] wlp2s0: authenticate with f8:64:b8:b8:3d:7a (local 
address=38:d5:7a:12:c2:3b)
[149984.638187] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 1/3)
[149984.697458] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 2/3)
[149984.737544] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 3/3)
[149984.778744] wlp2s0: authentication with f8:64:b8:b8:3d:7a timed out
[150016.560488] wlp2s0: authenticate with f8:64:b8:b8:3d:7a (local 
address=38:d5:7a:12:c2:3b)
[150016.573492] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 1/3)
[150016.614971] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 2/3)
[150016.673246] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 3/3)
[150016.721924] wlp2s0: authentication with f8:64:b8:b8:3d:7a timed out
[150051.575890] wlp2s0: authenticate with f8:64:b8:b8:3d:7a (local 
address=38:d5:7a:12:c2:3b)
[150051.589489] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 1/3)
[150051.636535] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 2/3)
[150051.685162] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 3/3)
[150052.134899] wlp2s0: authentication with f8:64:b8:b8:3d:7a timed out
[150064.827990] wlp2s0: authenticate with f8:64:b8:b8:3d:7a (local 
address=38:d5:7a:12:c2:3b)
[150064.841478] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 1/3)
[150064.966855] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 2/3)
[150065.015378] wlp2s0: send auth to f8:64:b8:b8:3d:7a (try 3/3)
[150065.174847] wlp2s0: authentication with f8:64:b8:b8:3d:7a timed out
```

Thank you for your time and for reading through this report. I would 
greatly appreciate it if this could be routed to the appropriate 
maintainers to help address these driver issues. Have a great day 
wherever you are.

^ permalink raw reply

* Re: [PATCH v7 02/15] firmware: qcom: Add a generic PAS service
From: Amirreza Zarrabi @ 2026-05-28  0:45 UTC (permalink / raw)
  To: Sumit Garg, andersson
  Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
	netdev, linux-wireless, ath12k, linux-remoteproc, konradybcio,
	robh, krzk+dt, conor+dt, robin.clark, sean, akhilpo, lumag,
	abhinav.kumar, jesszhan0024, marijn.suijten, airlied, simona,
	vikash.garodia, dikshita.agarwal, bod, mchehab, elder,
	andrew+netdev, davem, edumazet, kuba, pabeni, jjohnson,
	mathieu.poirier, trilokkumar.soni, mukesh.ojha, pavan.kondeti,
	jorge.ramirez, tonyh, vignesh.viswanathan, srinivas.kandagatla,
	jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg,
	Harshal Dev
In-Reply-To: <20260522115936.201208-3-sumit.garg@kernel.org>

Hi Sumit,

On 5/22/2026 9:59 PM, Sumit Garg wrote:
> From: Sumit Garg <sumit.garg@oss.qualcomm.com>
> 
> Qcom platforms has the legacy of using non-standard SCM calls
> splintered over the various kernel drivers. These SCM calls aren't
> compliant with the standard SMC calling conventions which is a
> prerequisite to enable migration to the FF-A specifications from Arm.
> 
> OP-TEE as an alternative trusted OS to Qualcomm TEE (QTEE) can't
> support these non-standard SCM calls. And even for newer architectures
> using S-EL2 with Hafnium support, QTEE won't be able to support SCM
> calls either with FF-A requirements coming in. And with both OP-TEE
> and QTEE drivers well integrated in the TEE subsystem, it makes further
> sense to reuse the TEE bus client drivers infrastructure.
> 
> The added benefit of TEE bus infrastructure is that there is support
> for discoverable/enumerable services. With that client drivers don't
> have to manually invoke a special SCM call to know the service status.
> 
> So enable the generic Peripheral Authentication Service (PAS) provided
> by the firmware. It acts as the common layer with different TZ
> backends plugged in whether it's an SCM implementation or a proper
> TEE bus based PAS service implementation.
> 
> Reviewed-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
> Tested-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com> # Lemans
> Reviewed-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
> Tested-by: Vignesh Viswanathan <vignesh.viswanathan@oss.qualcomm.com> # IPQ9650
> Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
> ---
>  drivers/firmware/qcom/Kconfig          |   8 +
>  drivers/firmware/qcom/Makefile         |   1 +
>  drivers/firmware/qcom/qcom_pas.c       | 291 +++++++++++++++++++++++++
>  drivers/firmware/qcom/qcom_pas.h       |  50 +++++
>  include/linux/firmware/qcom/qcom_pas.h |  43 ++++
>  5 files changed, 393 insertions(+)
>  create mode 100644 drivers/firmware/qcom/qcom_pas.c
>  create mode 100644 drivers/firmware/qcom/qcom_pas.h
>  create mode 100644 include/linux/firmware/qcom/qcom_pas.h
> 
> diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig
> index b477d54b495a..9f66cc774508 100644
> --- a/drivers/firmware/qcom/Kconfig
> +++ b/drivers/firmware/qcom/Kconfig
> @@ -6,6 +6,14 @@
>  
>  menu "Qualcomm firmware drivers"
>  
> +config QCOM_PAS
> +	tristate "Qualcomm generic PAS interface driver"
> +	help
> +	  Enable the generic Peripheral Authentication Service (PAS) provided
> +	  by the firmware. It acts as the common layer with different TZ
> +	  backends plugged in whether it's an SCM implementation or a proper
> +	  TEE bus based PAS service implementation.
> +
>  config QCOM_SCM
>  	select QCOM_TZMEM
>  	tristate
> diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile
> index 0be40a1abc13..dc5ab45f906a 100644
> --- a/drivers/firmware/qcom/Makefile
> +++ b/drivers/firmware/qcom/Makefile
> @@ -8,3 +8,4 @@ qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
>  obj-$(CONFIG_QCOM_TZMEM)	+= qcom_tzmem.o
>  obj-$(CONFIG_QCOM_QSEECOM)	+= qcom_qseecom.o
>  obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o
> +obj-$(CONFIG_QCOM_PAS)		+= qcom_pas.o
> diff --git a/drivers/firmware/qcom/qcom_pas.c b/drivers/firmware/qcom/qcom_pas.c
> new file mode 100644
> index 000000000000..bc6c42f2b3c6
> --- /dev/null
> +++ b/drivers/firmware/qcom/qcom_pas.c
> @@ -0,0 +1,291 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2010,2015,2019 The Linux Foundation. All rights reserved.
> + * Copyright (C) 2015 Linaro Ltd.
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#include <linux/device/devres.h>
> +#include <linux/firmware/qcom/qcom_pas.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +
> +#include "qcom_pas.h"
> +
> +static struct qcom_pas_ops *ops_ptr;
> +
> +/**
> + * devm_qcom_pas_context_alloc() - Allocate peripheral authentication service
> + *				   context for a given peripheral
> + *
> + * PAS context is device-resource managed, so the caller does not need
> + * to worry about freeing the context memory.
> + *
> + * @dev:	  PAS firmware device
> + * @pas_id:	  peripheral authentication service id
> + * @mem_phys:	  Subsystem reserve memory start address
> + * @mem_size:	  Subsystem reserve memory size
> + *
> + * Return: The new PAS context, or ERR_PTR() on failure.
> + */
> +struct qcom_pas_context *devm_qcom_pas_context_alloc(struct device *dev,
> +						     u32 pas_id,
> +						     phys_addr_t mem_phys,
> +						     size_t mem_size)
> +{
> +	struct qcom_pas_context *ctx;
> +
> +	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
> +	if (!ctx)
> +		return ERR_PTR(-ENOMEM);
> +
> +	ctx->dev = dev;
> +	ctx->pas_id = pas_id;
> +	ctx->mem_phys = mem_phys;
> +	ctx->mem_size = mem_size;
> +
> +	return ctx;
> +}
> +EXPORT_SYMBOL_GPL(devm_qcom_pas_context_alloc);
> +
> +/**
> + * qcom_pas_init_image() - Initialize peripheral authentication service state
> + *			   machine for a given peripheral, using the metadata
> + * @pas_id:	peripheral authentication service id
> + * @metadata:	pointer to memory containing ELF header, program header table
> + *		and optional blob of data used for authenticating the metadata
> + *		and the rest of the firmware
> + * @size:	size of the metadata
> + * @ctx:	optional pas context
> + *
> + * Return: 0 on success.
> + *
> + * Upon successful return, the PAS metadata context (@ctx) will be used to
> + * track the metadata allocation, this needs to be released by invoking
> + * qcom_pas_metadata_release() by the caller.
> + */
> +int qcom_pas_init_image(u32 pas_id, const void *metadata, size_t size,
> +			struct qcom_pas_context *ctx)
> +{
> +	if (!ops_ptr)
> +		return -ENODEV;
> +
> +	return ops_ptr->init_image(ops_ptr->dev, pas_id, metadata, size, ctx);
> +}
> +EXPORT_SYMBOL_GPL(qcom_pas_init_image);
> +
> +/**
> + * qcom_pas_metadata_release() - release metadata context
> + * @ctx:	pas context
> + */
> +void qcom_pas_metadata_release(struct qcom_pas_context *ctx)
> +{
> +	if (!ops_ptr || !ctx || !ctx->ptr)
> +		return;
> +
> +	ops_ptr->metadata_release(ops_ptr->dev, ctx);
> +}
> +EXPORT_SYMBOL_GPL(qcom_pas_metadata_release);
> +
> +/**
> + * qcom_pas_mem_setup() - Prepare the memory related to a given peripheral
> + *			  for firmware loading
> + * @pas_id:	peripheral authentication service id
> + * @addr:	start address of memory area to prepare
> + * @size:	size of the memory area to prepare
> + *
> + * Return: 0 on success.
> + */
> +int qcom_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
> +{
> +	if (!ops_ptr)
> +		return -ENODEV;
> +
> +	return ops_ptr->mem_setup(ops_ptr->dev, pas_id, addr, size);
> +}
> +EXPORT_SYMBOL_GPL(qcom_pas_mem_setup);
> +
> +/**
> + * qcom_pas_get_rsc_table() - Retrieve the resource table in passed output buffer
> + *			      for a given peripheral.
> + *
> + * Qualcomm remote processor may rely on both static and dynamic resources for
> + * its functionality. Static resources typically refer to memory-mapped
> + * addresses required by the subsystem and are often embedded within the
> + * firmware binary and dynamic resources, such as shared memory in DDR etc.,
> + * are determined at runtime during the boot process.
> + *
> + * On Qualcomm Technologies devices, it's possible that static resources are
> + * not embedded in the firmware binary and instead are provided by TrustZone.
> + * However, dynamic resources are always expected to come from TrustZone. This
> + * indicates that for Qualcomm devices, all resources (static and dynamic) will
> + * be provided by TrustZone PAS service.
> + *
> + * If the remote processor firmware binary does contain static resources, they
> + * should be passed in input_rt. These will be forwarded to TrustZone for
> + * authentication. TrustZone will then append the dynamic resources and return
> + * the complete resource table in output_rt_tzm.
> + *
> + * If the remote processor firmware binary does not include a resource table,
> + * the caller of this function should set input_rt as NULL and input_rt_size
> + * as zero respectively.
> + *
> + * More about documentation on resource table data structures can be found in
> + * include/linux/remoteproc.h
> + *
> + * @ctx:	    PAS context
> + * @pas_id:	    peripheral authentication service id
> + * @input_rt:       resource table buffer which is present in firmware binary
> + * @input_rt_size:  size of the resource table present in firmware binary
> + * @output_rt_size: TrustZone expects caller should pass worst case size for
> + *		    the output_rt_tzm.
> + *
> + * Return:
> + *  On success, returns a pointer to the allocated buffer containing the final
> + *  resource table and output_rt_size will have actual resource table size from
> + *  TrustZone. The caller is responsible for freeing the buffer. On failure,
> + *  returns ERR_PTR(-errno).
> + */
> +struct resource_table *qcom_pas_get_rsc_table(struct qcom_pas_context *ctx,
> +					      void *input_rt,
> +					      size_t input_rt_size,
> +					      size_t *output_rt_size)
> +{
> +	if (!ops_ptr)
> +		return ERR_PTR(-ENODEV);
> +	if (!ctx)
> +		return ERR_PTR(-EINVAL);
> +
> +	return ops_ptr->get_rsc_table(ops_ptr->dev, ctx, input_rt,
> +				      input_rt_size, output_rt_size);
> +}
> +EXPORT_SYMBOL_GPL(qcom_pas_get_rsc_table);
> +
> +/**
> + * qcom_pas_auth_and_reset() - Authenticate the given peripheral firmware
> + *			       and reset the remote processor
> + * @pas_id:	peripheral authentication service id
> + *
> + * Return: 0 on success.
> + */
> +int qcom_pas_auth_and_reset(u32 pas_id)
> +{
> +	if (!ops_ptr)
> +		return -ENODEV;
> +
> +	return ops_ptr->auth_and_reset(ops_ptr->dev, pas_id);
> +}
> +EXPORT_SYMBOL_GPL(qcom_pas_auth_and_reset);
> +
> +/**
> + * qcom_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the
> + *				       remote processor
> + *
> + * @ctx:	Context saved during call to devm_qcom_pas_context_alloc()
> + *
> + * This function performs the necessary steps to prepare a PAS subsystem,
> + * authenticate it using the provided metadata, and initiate a reset sequence.
> + *
> + * It should be used when Linux is in control setting up the IOMMU hardware
> + * for remote subsystem during secure firmware loading processes. The
> + * preparation step sets up a shmbridge over the firmware memory before
> + * TrustZone accesses the firmware memory region for authentication. The
> + * authentication step verifies the integrity and authenticity of the firmware
> + * or configuration using secure metadata. Finally, the reset step ensures the
> + * subsystem starts in a clean and sane state.
> + *
> + * Return: 0 on success, negative errno on failure.
> + */
> +int qcom_pas_prepare_and_auth_reset(struct qcom_pas_context *ctx)
> +{
> +	if (!ops_ptr)
> +		return -ENODEV;
> +	if (!ctx)
> +		return -EINVAL;
> +
> +	return ops_ptr->prepare_and_auth_reset(ops_ptr->dev, ctx);
> +}
> +EXPORT_SYMBOL_GPL(qcom_pas_prepare_and_auth_reset);
> +
> +/**
> + * qcom_pas_set_remote_state() - Set the remote processor state
> + * @state:	peripheral state
> + * @pas_id:	peripheral authentication service id
> + *
> + * Return: 0 on success.
> + */
> +int qcom_pas_set_remote_state(u32 state, u32 pas_id)
> +{
> +	if (!ops_ptr)
> +		return -ENODEV;
> +
> +	return ops_ptr->set_remote_state(ops_ptr->dev, state, pas_id);
> +}
> +EXPORT_SYMBOL_GPL(qcom_pas_set_remote_state);
> +
> +/**
> + * qcom_pas_shutdown() - Shut down the remote processor
> + * @pas_id:	peripheral authentication service id
> + *
> + * Return: 0 on success.
> + */
> +int qcom_pas_shutdown(u32 pas_id)
> +{
> +	if (!ops_ptr)
> +		return -ENODEV;
> +
> +	return ops_ptr->shutdown(ops_ptr->dev, pas_id);
> +}
> +EXPORT_SYMBOL_GPL(qcom_pas_shutdown);
> +
> +/**
> + * qcom_pas_supported() - Check if the peripheral authentication service is
> + *			  available for the given peripheral
> + * @pas_id:	peripheral authentication service id
> + *
> + * Return: true if PAS is supported for this peripheral, otherwise false.
> + */
> +bool qcom_pas_supported(u32 pas_id)
> +{
> +	if (!ops_ptr)
> +		return false;
> +
> +	return ops_ptr->supported(ops_ptr->dev, pas_id);
> +}
> +EXPORT_SYMBOL_GPL(qcom_pas_supported);
> +
> +bool qcom_pas_is_available(void)
> +{
> +	/*
> +	 * The barrier for ops_ptr is intended to synchronize the data stores
> +	 * for the ops data structure when client drivers are in parallel
> +	 * checking for PAS service availability.
> +	 *
> +	 * Once the PAS backend becomes available, it is allowed for multiple
> +	 * threads to enter TZ for parallel bringup of co-processors during
> +	 * boot.
> +	 */
> +	return !!smp_load_acquire(&ops_ptr);
> +}
> +EXPORT_SYMBOL_GPL(qcom_pas_is_available);
> +
> +void qcom_pas_ops_register(struct qcom_pas_ops *ops)
> +{
> +	if (!qcom_pas_is_available())
> +		/* Paired with smp_load_acquire() in qcom_pas_is_available() */
> +		smp_store_release(&ops_ptr, ops);
> +	else
> +		pr_err("qcom_pas: ops already registered by %s\n",
> +		       ops_ptr->drv_name);
> +}
> +EXPORT_SYMBOL_GPL(qcom_pas_ops_register);
> +
> +void qcom_pas_ops_unregister(void)
> +{
> +	/* Paired with smp_load_acquire() in qcom_pas_is_available() */
> +	smp_store_release(&ops_ptr, NULL);
> +}
> +EXPORT_SYMBOL_GPL(qcom_pas_ops_unregister);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Qualcomm generic TZ PAS driver");
> diff --git a/drivers/firmware/qcom/qcom_pas.h b/drivers/firmware/qcom/qcom_pas.h
> new file mode 100644
> index 000000000000..8643e2760602
> --- /dev/null
> +++ b/drivers/firmware/qcom/qcom_pas.h
> @@ -0,0 +1,50 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#ifndef __QCOM_PAS_INT_H
> +#define __QCOM_PAS_INT_H
> +
> +struct device;
> +
> +/**
> + * struct qcom_pas_ops - Qcom Peripheral Authentication Service (PAS) ops
> + * @drv_name:			PAS driver name.
> + * @dev:			PAS device pointer.
> + * @supported:			Peripheral supported callback.
> + * @init_image:			Peripheral image initialization callback.
> + * @mem_setup:			Peripheral memory setup callback.
> + * @get_rsc_table:		Peripheral get resource table callback.
> + * @prepare_and_auth_reset:	Peripheral prepare firmware authentication and
> + *				reset callback.
> + * @auth_and_reset:		Peripheral firmware authentication and reset
> + *				callback.
> + * @set_remote_state:		Peripheral set remote state callback.
> + * @shutdown:			Peripheral shutdown callback.
> + * @metadata_release:		Image metadata release callback.
> + */
> +struct qcom_pas_ops {
> +	const char *drv_name;
> +	struct device *dev;
> +	bool (*supported)(struct device *dev, u32 pas_id);
> +	int (*init_image)(struct device *dev, u32 pas_id, const void *metadata,
> +			  size_t size, struct qcom_pas_context *ctx);
> +	int (*mem_setup)(struct device *dev, u32 pas_id, phys_addr_t addr,
> +			 phys_addr_t size);
> +	void *(*get_rsc_table)(struct device *dev, struct qcom_pas_context *ctx,
> +			       void *input_rt, size_t input_rt_size,
> +			       size_t *output_rt_size);
> +	int (*prepare_and_auth_reset)(struct device *dev,
> +				      struct qcom_pas_context *ctx);
> +	int (*auth_and_reset)(struct device *dev, u32 pas_id);
> +	int (*set_remote_state)(struct device *dev, u32 state, u32 pas_id);
> +	int (*shutdown)(struct device *dev, u32 pas_id);
> +	void (*metadata_release)(struct device *dev,
> +				 struct qcom_pas_context *ctx);
> +};
> +
> +void qcom_pas_ops_register(struct qcom_pas_ops *ops);
> +void qcom_pas_ops_unregister(void);
> +
> +#endif /* __QCOM_PAS_INT_H */
> diff --git a/include/linux/firmware/qcom/qcom_pas.h b/include/linux/firmware/qcom/qcom_pas.h
> new file mode 100644
> index 000000000000..65b1c9564458
> --- /dev/null
> +++ b/include/linux/firmware/qcom/qcom_pas.h
> @@ -0,0 +1,43 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2010-2015, 2018-2019 The Linux Foundation. All rights reserved.
> + * Copyright (C) 2015 Linaro Ltd.
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#ifndef __QCOM_PAS_H
> +#define __QCOM_PAS_H
> +
> +#include <linux/err.h>
> +#include <linux/types.h>
> +
> +struct qcom_pas_context {
> +	struct device *dev;
> +	u32 pas_id;
> +	phys_addr_t mem_phys;
> +	size_t mem_size;
> +	void *ptr;
> +	dma_addr_t phys;
> +	ssize_t size;
> +	bool use_tzmem;
> +};
> +
> +bool qcom_pas_is_available(void);
> +struct qcom_pas_context *devm_qcom_pas_context_alloc(struct device *dev,
> +						     u32 pas_id,
> +						     phys_addr_t mem_phys,
> +						     size_t mem_size);
> +int qcom_pas_init_image(u32 pas_id, const void *metadata, size_t size,
> +			struct qcom_pas_context *ctx);
> +struct resource_table *qcom_pas_get_rsc_table(struct qcom_pas_context *ctx,
> +					      void *input_rt, size_t input_rt_size,
> +					      size_t *output_rt_size);
> +int qcom_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size);
> +int qcom_pas_auth_and_reset(u32 pas_id);
> +int qcom_pas_prepare_and_auth_reset(struct qcom_pas_context *ctx);
> +int qcom_pas_set_remote_state(u32 state, u32 pas_id);
> +int qcom_pas_shutdown(u32 pas_id);
> +bool qcom_pas_supported(u32 pas_id);
> +void qcom_pas_metadata_release(struct qcom_pas_context *ctx);
> +
> +#endif /* __QCOM_PAS_H */

I have a question about the shape of the generic PAS abstraction.

Looking at the current interface, it seems that pas_id is still treated as
the primary identity for most PAS operations, while struct qcom_pas_context
is used as optional extended state for the operations that need it. I can see
how this maps well to the existing SCM PAS interface and keeps the transition
simple.

However, I wonder if this makes the abstraction less generic in the long term.
Some callbacks in struct qcom_pas_ops receive only pas_id, while others
receive struct qcom_pas_context *ctx. This works as long as pas_id is
sufficient for those operations. But if a backend needs per-peripheral
private state for operations such as auth_and_reset,
shutdown, or set_remote_state, it would need to reconstruct that state from
pas_id or maintain a separate pas_id to backend-context mapping.

Would it be cleaner to make struct qcom_pas_context the common
per-peripheral object and pass it consistently to all per-peripheral callbacks?
Existing backends could still use ctx->pas_id, but future backends would not
need to perform a separate lookup only because the callback was passed a raw
pas_id.

I also wonder whether struct qcom_pas_context is exposing some
implementation-specific state. Fields such as ptr, phys, size, and
use_tzmem seem to describe how the current SCM/QTEE implementations manage
metadata memory, rather than generic PAS state. For another backend, the
per-operation state might be a tee_shm, an FF-A memory handle, shared or lent
memory state, or something else transport-specific.

Would it make sense to keep only the common PAS fields in
struct qcom_pas_context, such as dev, pas_id, and possibly the firmware
memory address/size if those are truly generic, and add a backend-private
pointer for implementation-specific state?

I may be missing a reason why the pas_id-only callbacks are preferred, but if
this is intended to be the long-term generic PAS layer rather than mainly a
shim over the existing SCM API shape, using the context consistently and keeping
backend-specific state private seems easier to extend.

Regards,
Amir

^ permalink raw reply

* Ongoing instability and connection loops with MT7922 (mt7921e driver)
From: lito.15 @ 2026-05-28  0:11 UTC (permalink / raw)
  To: linux-wireless@vger.kernel.org

Empty Message

^ permalink raw reply

* [PATCH wireless-next] wifi: cfg80211: use strscpy in cfg80211_wext_giwname
From: Thorsten Blum @ 2026-05-28  0:10 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Thorsten Blum, linux-wireless, linux-kernel

strcpy() has been deprecated [1] because it performs no bounds checking
on the destination buffer, which can lead to buffer overflows.

While the current code works correctly, replace strcpy() with the safer
strscpy() to follow secure coding best practices.

[1] https://www.kernel.org/doc/html/latest/process/deprecated.html#strcpy

Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
---
 net/wireless/wext-compat.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 1241fda78a68..1d6c60d3ad5b 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -16,6 +16,7 @@
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
 #include <linux/slab.h>
+#include <linux/string.h>
 #include <net/iw_handler.h>
 #include <net/cfg80211.h>
 #include <net/cfg80211-wext.h>
@@ -27,7 +28,7 @@ int cfg80211_wext_giwname(struct net_device *dev,
 			  struct iw_request_info *info,
 			  union iwreq_data *wrqu, char *extra)
 {
-	strcpy(wrqu->name, "IEEE 802.11");
+	strscpy(wrqu->name, "IEEE 802.11");
 	return 0;
 }
 

^ permalink raw reply related

* Re: [patch 24/24] ptp: Switch to ktime_get_snapshot_id() for pre/post timestamps
From: Jakub Kicinski @ 2026-05-27 23:56 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, David Woodhouse, Miroslav Lichvar, John Stultz,
	Stephen Boyd, Anna-Maria Behnsen, Frederic Weisbecker,
	thomas.weissschuh, Arthur Kiyanovski, Rodolfo Giometti,
	Vincent Donnefort, Marc Zyngier, Oliver Upton, kvmarm,
	Oliver Upton, Richard Cochran, netdev, Takashi Iwai,
	Miri Korenblit, Johannes Berg, Jacob Keller, Tony Nguyen,
	Saeed Mahameed, Peter Hilber, Michael S. Tsirkin, virtualization,
	linux-wireless, linux-sound
In-Reply-To: <20260526171224.499777655@kernel.org>

On Tue, 26 May 2026 19:15:27 +0200 Thomas Gleixner wrote:
> -	if (sts && bp->ts_window_adjust) {
> -		s64 ns = timespec64_to_ns(&sts->post_ts);
> -
> -		sts->post_ts = ns_to_timespec64(ns - bp->ts_window_adjust);
> -	}
> +	if (sts && bp->ts_window_adjust)
> +		sts->post_ts.sys -= bp->ts_window_adjust;

FWIW build says:

drivers/ptp/ptp_ocp.c:1495:8: error: no member named 'post_ts' in 'struct ptp_system_timestamp'
 1495 |                 sts->post_ts.sys -= bp->ts_window_adjust;
      |                 ~~~  ^

^ permalink raw reply

* Re: [bug report] wifi: mt76: mt7921: mt7925monitor-mode per-channel retune emits narrowband RF burst
From: Sean Wang @ 2026-05-27 23:08 UTC (permalink / raw)
  To: John Henry
  Cc: Javier Tia, Bradley Pizzimenti, linux-wireless, linux-kernel, nbd,
	lorenzo, ryder.lee, shayne.chen, sean.wang,
	moderated list:ARM/Mediatek SoC support, Deren Wu, Nick Morrow
In-Reply-To: <CAN6xzWcVDRLVTV-SQcs6osZjnfhLM728NP7+W8+sFcTDmeVipw@mail.gmail.com>

Hi John,

On Wed, May 27, 2026 at 7:24 AM John Henry <jshenry1963@gmail.com> wrote:
>
> Just a kind reminder of this issue.
>
> Please advise if this is already taken up in a separate issue I am
> unaware of, but it is not directly related to the "iw set txpower
> fixed accepted but ignored" issue.
>
> On products available in the market, e.g.  the Alfa AWUS036AXML
> consumer product and the Netgear Nighthawk A9000, in Monitor Mode
> there is RF generated when scanning through channels and we get to 5
> or more channels in succession.
> This does not seem to occur at all in managed mode.
>
> This means if we scan the 2.4GHz channel list, an RF Spectrum analyzer
> will show a narrow pulse generated on each channel as we progress
> through the channels.
> This can 100% be reproduced using standard iw set channel commands as
> shown below:
> FACE=$(iw dev | awk '/Interface wl/ {print $2; exit}')
> iw reg set US ; sleep 1
> ip link set "$IFACE" down
> iw dev "$IFACE" set type monitor
> ip link set "$IFACE" up
>
> # This triggers narrowband bursts at channel center on each retune:
> while true; do
>   for f in 2412 2417 2422 2427 2432; do
>     iw dev "$IFACE" set freq "$f" HT20
>   done
> done
>

I have thought about this issue for a while. A possible workaround
would be to reset WFSYS / firmware after five consecutive `set
channel` operations in monitor mode, then restore the current monitor
channel context. The WFSYS reset may take hundreds of milliseconds to
complete, which is the cost we would need to pay.

> No special software required to reproduce.
> I have shown that this occurs on all MT7921 based products, along with
> MT7925 based products.
> It does not occur if the channel list is set to the same 4 over and
> over, no RF generated.
>
> There are no calibration channel commands going from the driver to the
> firmware, so I believe this is a firmware bug.
>
> Best Regards,
> John Henry
>
> On Sun, May 17, 2026 at 9:01 AM John Henry <jshenry1963@gmail.com> wrote:
> >
> > Just a kind reminder of this issue, has anyone been able to reproduce
> > this monitor mode issue?
> > When scanning through channels, and the list of channels is > 4, there
> > is a large transmit tick/burst coming from the MT7921u and the MT7925.
> > This can easily be seen on an RF Spectrum Analyzer.
> > Confirmed on an Alfa AWUS036AXML consumer product and the Netgear
> > Nighthawk A9000.
> > This can be reproduced with simple scripts.
> >
> > Reproduction with stock iw commands (no custom code):
> >
> > IFACE=$(iw dev | awk '/Interface wl/ {print $2; exit}')
> > iw reg set US ; sleep 1
> > ip link set "$IFACE" down
> > iw dev "$IFACE" set type monitor
> > ip link set "$IFACE" up
> >
> > # This triggers narrowband bursts at channel center on each retune:
> > while true; do
> >   for f in 2412 2417 2422 2427 2432; do
> >     iw dev "$IFACE" set freq "$f" HT20
> >   done
> > done
> >
> > # This does NOT (only 4 frequencies):
> > while true; do
> >   for f in 2412 2422 2462 2484; do
> >     iw dev "$IFACE" set freq "$f" HT20
> >   done
> > done
> >
> > Bursts are ~800 kHz wide at the base, -30 to -50 dBm OTA at close
> > range, brief (estimated few hundred microseconds), at channel
> > frequency. tx_stats counters remain zero throughout.
> > On Mon, May 11, 2026 at 1:58 PM John Henry <jshenry1963@gmail.com> wrote:
> > >
> > > Bradley/Sean,
> > >
> > > Thank you all very much for the information.
> > > I tested this on mt7921u based Alfa AWUS unit and also an mt7925 based
> > > Netgear Nighthawk unit.
> > > I can confirm that the RF tick issue is present on both models when in
> > > Monitor Mode. I'm assuming it is in the base mt76?
> > >
> > > I attempted sudo iw dev wlxxx set txpower fixed nn where nn is the
> > > minimum value, next few values up, and then a few near the max values,
> > > and see no change in the signal strength of the RF Ticks when scanning
> > > through 5 or more channels.
> > >
> > > Please keep this in mind when attempting to resolve the known txpower
> > > 3dBm issue if possible, or please generate a new bug report for that
> > > specifically so that I can track when it is patched, or in ??? version
> > > so that I can test here locally.
> > >
> > > Incidentally, I'd appreciate it if anyone could please attempt to
> > > repeat using the scripts I had shown in the previous posts and confirm
> > > it is indeed seen by others.
> > >
> > > Thank you very much for your time and assistance
> > >
> > > John Henry
> > >
> > >
> > >
> > >
> > > From: Bradley Pizzimenti <brad.pizzimenti@gmail.com>
> > > To: linux-wireless@vger.kernel.org
> > > Cc: linux-kernel@vger.kernel.org, nbd@nbd.name, lorenzo@kernel.org,
> > > ryder.lee@mediatek.com, shayne.chen@mediatek.com,
> > > sean.wang@mediatek.com
> > > Subject: [bug report] wifi: mt76: mt7925: iw set txpower fixed
> > > accepted but ignored
> > > Date: Mon, 4 May 2026 15:04:35 -0700 [thread overview]
> > > Message-ID: <CACjnFagN9zeSkwEv3-CSPJDUENPcEcOLjKyQoLQ91Yjn=rq5ww@mail.gmail.com>
> > > (raw)
> > >
> > > Hi there maintainers,
> > >
> > > `iw dev <iface> set txpower fixed N` returns success on mt7925 for any
> > > N tested, but the reported txpower never changes from a stuck value of
> > > 3.00 dBm. The kernel accepts and ignores the call silently in both
> > > directions (above and below the displayed value), and well below the
> > > regulatory ceiling.
> > >
> > > I'm aware there's prior art on the cosmetic 3.00 dBm display issue
> > > (Razvan Grigore's v2 series, Feb 2025; Ming Yen Hsieh's txpower init
> > > refactor, Sept 2025). What seems potentially distinct here is that the
> > > user-issued `iw set txpower fixed N` itself is silently no-op'd,
> > > separate from the reported-value question. Reporting as breadcrumbs
> > > in case the second observation is a separate bug rather than the same
> > > one.
> > >
> > > Hardware
> > > --------
> > > MEDIATEK MT7925 [Filogic 360], 802.11be 2x2, PCI 14c3:7925
> > > ASIC revision 0x79250000
> > > Driver in use: mt7925e (in-tree)
> > >
> > > Firmware (from dmesg at probe)
> > > ------------------------------
> > > mt7925e 0000:01:00.0: HW/SW Version: 0x8a108a10,
> > >                      Build Time: 20260106153007a
> > > mt7925e 0000:01:00.0: WM Firmware Version: ____000000,
> > >                      Build Time: 20260106153120
> > > Files: mediatek/mt7925/WIFI_MT7925_PATCH_MCU_1_1_hdr.bin
> > >        mediatek/mt7925/WIFI_RAM_CODE_MT7925_1_1.bin
> > >
> > > Kernel
> > > ------
> > > 6.18.18-1-MANJARO (close to vanilla 6.18 stable; not yet tested on
> > > wireless-next or nbd168/wireless HEAD -- happy to retest if needed,
> > > but flagging the data point in case it helps as-is).
> > >
> > > Tools: iw version 6.17
> > >
> > > Regulatory
> > > ----------
> > > $ iw reg get
> > > country US: DFS-FCC
> > >    ...
> > >    (5730 - 5850 @ 80), (N/A, 30), (N/A), AUTO-BW
> > >    ...
> > >
> > > Connection context: 5GHz channel 161 (5805 MHz), 80 MHz, VHT-MCS,
> > > NSS 1. So we are on a band with a 30 dBm regulatory cap.
> > >
> > > Observed
> > > --------
> > > $ iw dev wlp1s0 info | grep txpower
> > >         txpower 3.00 dBm
> > >
> > > $ sudo iw dev wlp1s0 set txpower fixed 100   # 1 dBm
> > > $ iw dev wlp1s0 info | grep txpower
> > >         txpower 3.00 dBm
> > >
> > > $ sudo iw dev wlp1s0 set txpower fixed 1500  # 15 dBm
> > > $ iw dev wlp1s0 info | grep txpower
> > >         txpower 3.00 dBm
> > >
> > > $ sudo iw dev wlp1s0 set txpower auto
> > > $ iw dev wlp1s0 info | grep txpower
> > >         txpower 3.00 dBm
> > >
> > > All four `set` invocations return exit code 0. The reported value
> > > never moves.
> > >
> > > Expected
> > > --------
> > > Either:
> > >   - The reported txpower follows the requested value (or, where
> > >     capped, the actual applied value with extack indicating the
> > >     cap reason), or
> > >   - The set call returns an error rather than silently ignoring the
> > >     request.
> > >
> > > Caveats
> > > -------
> > > - Not yet tested on wireless-next or nbd168/wireless HEAD. If a
> > >   reproduction on a current dev tree would be useful, I can do that.
> > > - I have not verified whether the actual radiated TX power changes
> > >   in response to `set txpower fixed`; I am reporting only the
> > >   user-visible behavior.
> > >
> > > Thanks,
> > > Bradley
> > >
> > > On Wed, May 6, 2026 at 8:12 PM Sean Wang <sean.wang@kernel.org> wrote:
> > > >
> > > > Hi,
> > > >
> > > > The TX power reporting issue has already been investigated by Lucid
> > > > from the Linux WiFi USB community, and there is a proposed solution.
> > > > I think we can continue checking whether there are any remaining
> > > > issues on top of that work. Please refer to the patches here:
> > > > https://lists.infradead.org/pipermail/linux-mediatek/2026-April/105726.html
> > > > Thanks everyone for reporting and raising these concerns.
> > > >
> > > > On Wed, May 6, 2026 at 3:09 PM Javier Tia <floss@jetm.me> wrote:
> > > > >
> > > > > On Sun May  4 22:04:48 2026 Bradley Pizzimenti wrote:
> > > > > > `iw dev <iface> set txpower fixed N` returns success on mt7925 for
> > > > > > any N tested, but the reported txpower never changes from a stuck
> > > > > > value of 3.00 dBm.
> > > > >
> > > > > Hi Bradley,
> > > > >
> > > > > The 3 dBm display bug is a known issue we have seen when using mt7927
> > > > > and a tested fix has been working well so far. The root cause is that
> > > > > mt7925_mcu_set_rate_txpower() programs the per-band SKU tables into
> > > > > firmware but never assigns phy->txpower_cur. mt76_get_txpower() then
> > > > > computes:
> > > > >
> > > > >   DIV_ROUND_UP(0 + 6, 2) = 3
> > > > >
> > > > > regardless of the actual power level. The RF output is unaffected;
> > > > > it is a display-only bug.
> > > > >
> > > > > The fix reads the effective TX power back from the rate power limits
> > > > > after programming the SKU tables and writes it to phy->txpower_cur,
> > > > > following the same pattern used by mt7996:
> > > > >
> > > > >   https://github.com/jetm/mediatek-mt7927-dkms/blob/master/mt7927-wifi-14-fix-reported-txpower-always-showing-3-db.patch
> > > > >
> > > > > This is part of a series we are targeting for wireless-next; not
> > > > > yet upstream.
> > > > >
> > > > > > What seems potentially distinct here is that the user-issued
> > > > > > `iw set txpower fixed N` itself is silently no-op'd, separate
> > > > > > from the reported-value question.
> > > > >
> > > > > Agreed those are two separate issues. Our patch addresses the
> > > > > display-only side: after applying it, iw will report the value the
> > > > > firmware is actually using based on the SKU tables, rather than
> > > > > always 3 dBm. Whether `set txpower fixed N` propagates to firmware
> > > > > to change actual output power is orthogonal and not addressed here.
> > > > >
> > > > > If you can test the patch on your MT7925 and confirm the displayed
> > > > > value reflects the correct power after association, a Tested-by
> > > > > would be appreciated.
> > > > >
> > > > > Best,
> > > > > Javier
> > > > >
> > > >

^ permalink raw reply

* Re: [PATCH 1/1] wifi: ath12k: support calibration-variant from device tree
From: Andrew LaMarche @ 2026-05-27 21:01 UTC (permalink / raw)
  To: Jeff Johnson; +Cc: Jeff Johnson, linux-wireless, ath12k, linux-kernel
In-Reply-To: <dc8c9c9c-dc85-40dd-9313-845a808a35f4@oss.qualcomm.com>

Ack on the deprecation of qcom,ath12k-calibration-variant in favor of the
generic qcom,calibration-variant. 

However, drivers/net/wireless/ath/ath12k/core.c still misses the logic to 
actually load in the BDF, which this patch also accomplishes. I don’t see that
in the Qualcomm-authored series you linked. Perhaps a v2 to address this?

Andrew

> On May 27, 2026, at 3:52 PM, Jeff Johnson <jeff.johnson@oss.qualcomm.com> wrote:
> 
> On 5/27/2026 9:12 AM, Andrew LaMarche wrote:
>> Hi,
>> 
>> A kind ping here. I’m not sure why this functionality is missing in the first place, but it is needed for loading caldata from the device tree.
> 
> Your patch duplicates functionality in the Qualcomm authored series:
> https://msgid.link/20250228184214.337119-1-quic_rajkbhag@quicinc.com
> 
> And note the upstream device bindings for ath10k and ath11k only support the
> generic binding qcom,calibration-variant.
> 
> There are no longer any generation-specific bindings, see:
> https://msgid.link/20250225-b-wifi-qcom-calibration-variant-v1-0-3b2aa3f89c53@linaro.org
> 
> /jeff


^ permalink raw reply

* [PATCH iwlwifi-next 15/15] wifi: iwlwifi: mld: Require HT support for NAN
From: Miri Korenblit @ 2026-05-27 20:05 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ilan Peer
In-Reply-To: <20260527200512.506707-1-miriam.rachel.korenblit@intel.com>

From: Ilan Peer <ilan.peer@intel.com>

NAN cannot be supported if HT is not supported, so check that
HT is supported before declaring that NAN is supported.

Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mld/nan.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.c b/drivers/net/wireless/intel/iwlwifi/mld/nan.c
index d34a9a2cbeae..dbe7a54a38b7 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/nan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.c
@@ -25,7 +25,8 @@ bool iwl_mld_nan_supported(struct iwl_mld *mld)
 	    iwl_fw_lookup_cmd_ver(fw, WIDE_ID(MAC_CONF_GROUP, NAN_PEER_CMD), 0) >= 1 &&
 	    iwl_fw_lookup_cmd_ver(fw, WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD), 0) >= 3 &&
 	    iwl_fw_lookup_cmd_ver(fw, WIDE_ID(MAC_CONF_GROUP, MAC_CONFIG_CMD), 0) >= 4 &&
-	    iwl_fw_lookup_cmd_ver(fw, WIDE_ID(DATA_PATH_GROUP, TLC_MNG_CONFIG_CMD), 0) >= 6)
+	    iwl_fw_lookup_cmd_ver(fw, WIDE_ID(DATA_PATH_GROUP, TLC_MNG_CONFIG_CMD), 0) >= 6 &&
+		mld->nvm_data->nan_phy_capa.ht.ht_supported)
 		return true;
 	return false;
 }
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 14/15] wifi: iwlwifi: mvm: fix P2P-Device binding handling
From: Miri Korenblit @ 2026-05-27 20:05 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260527200512.506707-1-miriam.rachel.korenblit@intel.com>

From: Johannes Berg <johannes.berg@intel.com>

Our binding handling for P2P-Device can run into the following
scenario, as observed by our testing:

 - a station interface is connected on some channel
 - the P2P-Device does a remain-on-channel (ROC) on that channel
 - the ROC ends, and the P2P-Device is removed from the binding,
   but the phy_ctxt pointer is left around as a PHY cache so we
   don't need to recalibrate to the channel again and again in
   case it's not shared
 - a binding update by the station interface, even a removal,
   will re-add the P2P-Device to the binding
 - the P2P-Device is removed, which removes the PHY context, but
   it's still in the binding so the firmware crashes

Since the P2P device is removed from the binding and only re-
added by unrelated code, but we want to keep the phy_ctxt around
as a cache for future ROC usage, fix it by adding a boolean that
indicates whether or not the P2P-Device should be added to the
binding, and handle that in the binding iterator. That way, the
station interface cannot re-add the P2P-Device to the binding
when that isn't active.

Assisted-by: Github Copilot:claude-opus-4-6
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mvm/binding.c    |  5 ++++-
 drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c   | 12 +++++++++++-
 drivers/net/wireless/intel/iwlwifi/mvm/mvm.h        |  3 +++
 drivers/net/wireless/intel/iwlwifi/mvm/time-event.c |  3 ++-
 4 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/binding.c b/drivers/net/wireless/intel/iwlwifi/mvm/binding.c
index 58e9a940024d..0812522edea0 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/binding.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/binding.c
@@ -2,7 +2,7 @@
 /*
  * Copyright (C) 2012-2014, 2020 Intel Corporation
  * Copyright (C) 2016 Intel Deutschland GmbH
- * Copyright (C) 2022, 2024 Intel Corporation
+ * Copyright (C) 2022, 2024, 2026 Intel Corporation
  */
 #include <net/mac80211.h>
 #include "fw-api.h"
@@ -76,6 +76,9 @@ static void iwl_mvm_iface_iterator(void *_data, u8 *mac,
 	if (vif == data->ignore_vif)
 		return;
 
+	if (vif->type == NL80211_IFTYPE_P2P_DEVICE && !mvmvif->p2p_in_binding)
+		return;
+
 	if (mvmvif->deflink.phy_ctxt != data->phyctxt)
 		return;
 
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index c256cbc6602e..74bd4038fd56 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -1104,6 +1104,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
 	spin_unlock_bh(&mvm->time_event_lock);
 
 	mvmvif->roc_activity = ROC_NUM_ACTIVITIES;
+	mvmvif->p2p_in_binding = false;
 
 	mvmvif->bf_enabled = false;
 	mvmvif->ba_enabled = false;
@@ -4634,6 +4635,7 @@ static int iwl_mvm_add_aux_sta_for_hs20(struct iwl_mvm *mvm, u32 lmac_id)
 
 static int iwl_mvm_roc_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 {
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 	int ret;
 
 	lockdep_assert_held(&mvm->mutex);
@@ -4642,10 +4644,18 @@ static int iwl_mvm_roc_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 	if (WARN(ret, "Failed binding P2P_DEVICE\n"))
 		return ret;
 
+	mvmvif->p2p_in_binding = true;
+
 	/* The station and queue allocation must be done only after the binding
 	 * is done, as otherwise the FW might incorrectly configure its state.
 	 */
-	return iwl_mvm_add_p2p_bcast_sta(mvm, vif);
+	ret = iwl_mvm_add_p2p_bcast_sta(mvm, vif);
+	if (ret) {
+		iwl_mvm_binding_remove_vif(mvm, vif);
+		mvmvif->p2p_in_binding = false;
+	}
+
+	return ret;
 }
 
 static int iwl_mvm_roc(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index e09b63516230..6bf71092faa1 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -383,6 +383,8 @@ struct iwl_mvm_vif_link_info {
  * @pm_enabled: indicates powersave is enabled
  * @roc_activity: currently running ROC activity for this vif (or
  *	ROC_NUM_ACTIVITIES if no activity is running).
+ * @p2p_in_binding: indicates that this P2P-Device interface should be
+ *	added to the binding, i.e. is running ROC right now
  * @session_prot_connection_loss: the connection was lost due to session
  *	protection ending without receiving a beacon, so we need to now
  *	protect the deauth separately
@@ -492,6 +494,7 @@ struct iwl_mvm_vif {
 	struct iwl_mvm_time_event_data time_event_data;
 	struct iwl_mvm_time_event_data hs_time_event_data;
 	enum iwl_roc_activity roc_activity;
+	bool p2p_in_binding;
 
 	/* TCP Checksum Offload */
 	netdev_features_t features;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
index 2b52a4f3bff9..1692b6e75f57 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * Copyright (C) 2012-2014, 2018-2025 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2026 Intel Corporation
  * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
  * Copyright (C) 2017 Intel Deutschland GmbH
  */
@@ -88,6 +88,7 @@ static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm)
 			} else {
 				iwl_mvm_rm_p2p_bcast_sta(mvm, vif);
 				iwl_mvm_binding_remove_vif(mvm, vif);
+				mvmvif->p2p_in_binding = false;
 			}
 
 			/* Do not remove the PHY context as removing and adding
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 13/15] wifi: iwlwifi: mld: add KUnit tests for duplicated beacon RSSI adjustment
From: Miri Korenblit @ 2026-05-27 20:05 UTC (permalink / raw)
  To: linux-wireless; +Cc: Avinash Bhatt
In-Reply-To: <20260527200512.506707-1-miriam.rachel.korenblit@intel.com>

From: Avinash Bhatt <avinash.bhatt@intel.com>

Add KUnit tests to verify RSSI adjustment for 6 GHz duplicated
beacons across different operational bandwidths and validate
detection of the duplicated beacon bit.

Signed-off-by: Avinash Bhatt <avinash.bhatt@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mld/link.c |   3 +-
 drivers/net/wireless/intel/iwlwifi/mld/link.h |   5 +
 .../wireless/intel/iwlwifi/mld/tests/link.c   | 102 +++++++++++++++++-
 .../wireless/intel/iwlwifi/mld/tests/utils.c  |  60 +++++++++++
 .../wireless/intel/iwlwifi/mld/tests/utils.h  |   7 +-
 5 files changed, 173 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.c b/drivers/net/wireless/intel/iwlwifi/mld/link.c
index 234821f6a441..98b9c4eef583 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/link.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/link.c
@@ -1024,7 +1024,7 @@ iwl_mld_get_avail_chan_load(struct iwl_mld *mld,
 	return MAX_CHAN_LOAD - iwl_mld_get_chan_load(mld, link_conf);
 }
 
-static s8
+VISIBLE_IF_IWLWIFI_KUNIT s8
 iwl_mld_get_dup_beacon_rssi_adjust(struct iwl_mld *mld,
 				   struct ieee80211_bss_conf *link_conf)
 {
@@ -1077,6 +1077,7 @@ iwl_mld_get_dup_beacon_rssi_adjust(struct iwl_mld *mld,
 		return 0;
 	}
 }
+EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_get_dup_beacon_rssi_adjust);
 
 static s8 iwl_mld_get_primary_psd(const struct ieee80211_parsed_tpe_psd *psd,
 				  const struct cfg80211_chan_def *chandef,
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.h b/drivers/net/wireless/intel/iwlwifi/mld/link.h
index f1997e280058..d0aa577de81d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/link.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/link.h
@@ -142,6 +142,11 @@ int iwl_mld_link_set_associated(struct iwl_mld *mld, struct ieee80211_vif *vif,
 unsigned int iwl_mld_get_link_grade(struct iwl_mld *mld,
 				    struct ieee80211_bss_conf *link_conf);
 
+#if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS)
+s8 iwl_mld_get_dup_beacon_rssi_adjust(struct iwl_mld *mld,
+				      struct ieee80211_bss_conf *link_conf);
+#endif
+
 unsigned int iwl_mld_get_chan_load(struct iwl_mld *mld,
 				   struct ieee80211_bss_conf *link_conf);
 
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tests/link.c b/drivers/net/wireless/intel/iwlwifi/mld/tests/link.c
index 69a0d67858bf..21bcc341cd7d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/tests/link.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/tests/link.c
@@ -1,8 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * KUnit tests for channel helper functions
+ * KUnit tests for link helper functions
  *
- * Copyright (C) 2024-2025 Intel Corporation
+ * Copyright (C) 2024-2026 Intel Corporation
  */
 #include <kunit/static_stub.h>
 
@@ -96,8 +96,106 @@ static void test_missed_beacon(struct kunit *test)
 	/* TODO: add test cases for esr and check */
 }
 
+struct dup_beacon_test_case {
+	const char *desc;
+	enum nl80211_chan_width bandwidth;
+	bool has_he_oper;
+	bool dup_beacon_bit;
+	s8 expected_adj;
+};
+
+static const struct dup_beacon_test_case dup_beacon_cases[] = {
+	{
+		.desc = "20 MHz - no duplication",
+		.bandwidth = NL80211_CHAN_WIDTH_20,
+		.has_he_oper = true,
+		.dup_beacon_bit = true,
+		.expected_adj = 0,
+	},
+	{
+		.desc = "40 MHz with duplication - 3 dB",
+		.bandwidth = NL80211_CHAN_WIDTH_40,
+		.has_he_oper = true,
+		.dup_beacon_bit = true,
+		.expected_adj = 3,
+	},
+	{
+		.desc = "80 MHz with duplication - 6 dB",
+		.bandwidth = NL80211_CHAN_WIDTH_80,
+		.has_he_oper = true,
+		.dup_beacon_bit = true,
+		.expected_adj = 6,
+	},
+	{
+		.desc = "160 MHz with duplication - 9 dB",
+		.bandwidth = NL80211_CHAN_WIDTH_160,
+		.has_he_oper = true,
+		.dup_beacon_bit = true,
+		.expected_adj = 9,
+	},
+	{
+		.desc = "320 MHz with duplication - 12 dB",
+		.bandwidth = NL80211_CHAN_WIDTH_320,
+		.has_he_oper = true,
+		.dup_beacon_bit = true,
+		.expected_adj = 12,
+	},
+	{
+		.desc = "80 MHz without dup bit - no adjustment",
+		.bandwidth = NL80211_CHAN_WIDTH_80,
+		.has_he_oper = true,
+		.dup_beacon_bit = false,
+		.expected_adj = 0,
+	},
+	{
+		.desc = "80 MHz without HE oper - no adjustment",
+		.bandwidth = NL80211_CHAN_WIDTH_80,
+		.has_he_oper = false,
+		.dup_beacon_bit = true,
+		.expected_adj = 0,
+	},
+};
+
+KUNIT_ARRAY_PARAM_DESC(test_dup_beacon_rssi_adjust, dup_beacon_cases, desc);
+
+static void test_dup_beacon_rssi_adjust(struct kunit *test)
+{
+	const struct dup_beacon_test_case *params = test->param_value;
+	struct iwl_mld *mld = test->priv;
+	struct ieee80211_bss_conf *link_conf;
+	struct cfg80211_bss *bss;
+	struct element *he_elem = NULL;
+	s8 result;
+
+	KUNIT_ALLOC_AND_ASSERT(test, link_conf);
+	KUNIT_ALLOC_AND_ASSERT(test, bss);
+	link_conf->bss = bss;
+
+	link_conf->chanreq.oper.chan = &chan_6ghz;
+	link_conf->chanreq.oper.width = params->bandwidth;
+
+	if (params->has_he_oper) {
+		struct ieee80211_he_6ghz_oper he_6ghz = {};
+
+		if (params->dup_beacon_bit)
+			he_6ghz.control =
+				IEEE80211_HE_6GHZ_OPER_CTRL_DUP_BEACON;
+		he_elem = iwlmld_kunit_create_he_6ghz_oper(he_6ghz);
+	}
+
+	rcu_assign_pointer(bss->beacon_ies,
+			   iwlmld_kunit_create_bss_ies(he_elem));
+
+	guard(wiphy)(mld->wiphy);
+	result = iwl_mld_get_dup_beacon_rssi_adjust(mld, link_conf);
+
+	KUNIT_EXPECT_EQ(test, result, params->expected_adj);
+}
+
 static struct kunit_case link_cases[] = {
 	KUNIT_CASE_PARAM(test_missed_beacon, test_missed_beacon_gen_params),
+	KUNIT_CASE_PARAM(test_dup_beacon_rssi_adjust,
+			 test_dup_beacon_rssi_adjust_gen_params),
 	{},
 };
 
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.c b/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.c
index cb1968b07452..fdeab7082e78 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.c
@@ -439,6 +439,66 @@ struct ieee80211_vif *iwlmld_kunit_assoc_emlsr(struct iwl_mld_kunit_link *link1,
 	return vif;
 }
 
+struct element *
+iwlmld_kunit_create_he_6ghz_oper(struct ieee80211_he_6ghz_oper he_6ghz)
+{
+	struct kunit *test = kunit_get_current_test();
+	u8 *data;
+	size_t data_len;
+	size_t offset = 0;
+	__le32 he_oper_params;
+	__le16 he_mcs_nss_set = 0;
+
+	/* Build HE Operation IE with 6 GHz info using raw buffer.
+	 * Cannot use struct embedding because ieee80211_he_operation
+	 * has a flexible array member (optional[]).
+	 *
+	 * Layout:
+	 *   1 byte:         ext_id (WLAN_EID_EXT_HE_OPERATION)
+	 *   he_oper_params: he_oper_params (from ieee80211_he_operation)
+	 *   he_mcs_nss_set: he_mcs_nss_set (from ieee80211_he_operation)
+	 *   he_6ghz:        ieee80211_he_6ghz_oper (goes into optional[])
+	 */
+	data_len = 1 + sizeof(he_oper_params) + sizeof(he_mcs_nss_set) +
+		   sizeof(struct ieee80211_he_6ghz_oper);
+
+	data = kunit_kzalloc(test, data_len, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, data);
+
+	data[offset++] = WLAN_EID_EXT_HE_OPERATION;
+
+	he_oper_params = cpu_to_le32(IEEE80211_HE_OPERATION_6GHZ_OP_INFO);
+	memcpy(&data[offset], &he_oper_params, sizeof(he_oper_params));
+	offset += sizeof(he_oper_params);
+
+	memcpy(&data[offset], &he_mcs_nss_set, sizeof(he_mcs_nss_set));
+	offset += sizeof(he_mcs_nss_set);
+
+	memcpy(&data[offset], &he_6ghz, sizeof(he_6ghz));
+
+	return iwlmld_kunit_gen_element(WLAN_EID_EXTENSION, data, data_len);
+}
+
+struct cfg80211_bss_ies *iwlmld_kunit_create_bss_ies(struct element *elem)
+{
+	struct kunit *test = kunit_get_current_test();
+	struct cfg80211_bss_ies *ies;
+	size_t ies_len = 0;
+
+	if (elem)
+		ies_len = sizeof(*elem) + elem->datalen;
+
+	ies = kunit_kzalloc(test, sizeof(*ies) + ies_len, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, ies);
+
+	ies->len = ies_len;
+
+	if (elem)
+		memcpy(ies->data, elem, ies_len);
+
+	return ies;
+}
+
 struct element *iwlmld_kunit_gen_element(u8 id, const void *data, size_t len)
 {
 	struct kunit *test = kunit_get_current_test();
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.h b/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.h
index edf8eef4e81a..cfed5acaac3a 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2024-2025 Intel Corporation
+ * Copyright (C) 2024-2026 Intel Corporation
  */
 
 #ifndef __iwl_mld_kunit_utils_h__
@@ -121,6 +121,11 @@ iwlmld_kunit_assoc_emlsr(struct iwl_mld_kunit_link *link1,
 
 struct element *iwlmld_kunit_gen_element(u8 id, const void *data, size_t len);
 
+struct element *
+iwlmld_kunit_create_he_6ghz_oper(struct ieee80211_he_6ghz_oper he_6ghz);
+
+struct cfg80211_bss_ies *iwlmld_kunit_create_bss_ies(struct element *elem);
+
 /**
  * iwlmld_kunit_get_phy_of_link - Get the phy of a link
  *
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 12/15] wifi: iwlwifi: mld: don't WARN on WoWLAN suspend w/o netdetect
From: Miri Korenblit @ 2026-05-27 20:05 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg, Emmanuel Grumbach
In-Reply-To: <20260527200512.506707-1-miriam.rachel.korenblit@intel.com>

From: Johannes Berg <johannes.berg@intel.com>

Clearly, from a user perspective, it must be valid to configure
WoWLAN and then suspend while not connected to a network. Since
mac80211 doesn't distinguish these cases and simply calls the
driver to suspend whenever WoWLAN is configured, the driver has
to cleanly handle the case where it's called for WoWLAN, it's
not connected but there's also no netdetect configured.

Remove the WARN_ON() and keep returning 1 to disconnect and
then suspend.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mld/d3.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c
index fc0a5871df2f..458a668ba916 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c
@@ -2066,8 +2066,11 @@ int iwl_mld_wowlan_suspend(struct iwl_mld *mld, struct cfg80211_wowlan *wowlan)
 
 	if (!bss_vif->cfg.assoc) {
 		int ret;
-		/* If we're not associated, this must be netdetect */
-		if (WARN_ON(!wowlan->nd_config))
+		/*
+		 * If not associated we can only do netdetect, if
+		 * that's not enabled then just suspend normally.
+		 */
+		if (!wowlan->nd_config)
 			return 1;
 
 		ret = iwl_mld_netdetect_config(mld, bss_vif, wowlan);
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 11/15] wifi: iwlwifi: cfg: Revert "wifi: iwlwifi: cfg: move the MODULE_FIRMWARE to the per-rf file"
From: Miri Korenblit @ 2026-05-27 20:05 UTC (permalink / raw)
  To: linux-wireless; +Cc: Shahar Tzarfati
In-Reply-To: <20260527200512.506707-1-miriam.rachel.korenblit@intel.com>

From: Shahar Tzarfati <shahar.tzarfati@intel.com>

IWL_BZ_UCODE_CORE_MAX is undefined in cfg/rf-fm.c, this
causes __stringify(core) to turn it into the literal
token text, so MODULE_FIRMWARE entries are generated as
"iwlwifi...-cIWL_BZ_UCODE_CORE_MAX.ucode",
instead of the actual number.

This reverts the commit below.

Fixes: e4d47493c6be ("wifi: iwlwifi: cfg: move the MODULE_FIRMWARE to the per-rf file")
Signed-off-by: Shahar Tzarfati <shahar.tzarfati@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/cfg/bz.c    | 12 ++++++++++++
 drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c | 12 ------------
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
index ecb4f81a99f5..9cdc4f142c7f 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
@@ -15,6 +15,12 @@
 /* Lowest firmware core release supported */
 #define IWL_BZ_UCODE_CORE_MIN	101
 
+#define IWL_BZ_A_FM_B_FW_PRE		"iwlwifi-bz-a0-fm-b0"
+#define IWL_BZ_A_FM_C_FW_PRE		"iwlwifi-bz-a0-fm-c0"
+#define IWL_BZ_A_FM4_B_FW_PRE		"iwlwifi-bz-a0-fm4-b0"
+#define IWL_GL_B_FM_B_FW_PRE		"iwlwifi-gl-b0-fm-b0"
+#define IWL_GL_C_FM_C_FW_PRE		"iwlwifi-gl-c0-fm-c0"
+
 static const struct iwl_family_base_params iwl_bz_base = {
 	.num_of_queues = 512,
 	.max_tfd_queue_size = 65536,
@@ -85,3 +91,9 @@ const struct iwl_mac_cfg iwl_gl_mac_cfg = {
 	.xtal_latency = 12000,
 	.low_latency_xtal = true,
 };
+
+IWL_CORE_FW(IWL_BZ_A_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
+IWL_CORE_FW(IWL_BZ_A_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
+IWL_CORE_FW(IWL_BZ_A_FM4_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
+IWL_CORE_FW(IWL_GL_B_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
+IWL_CORE_FW(IWL_GL_C_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c
index 294cf25ae2a6..35b1618f3474 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c
@@ -5,12 +5,6 @@
  */
 #include "iwl-config.h"
 
-#define IWL_BZ_A_FM_B_FW_PRE		"iwlwifi-bz-a0-fm-b0"
-#define IWL_BZ_A_FM_C_FW_PRE		"iwlwifi-bz-a0-fm-c0"
-#define IWL_BZ_A_FM4_B_FW_PRE		"iwlwifi-bz-a0-fm4-b0"
-#define IWL_GL_B_FM_B_FW_PRE		"iwlwifi-gl-b0-fm-b0"
-#define IWL_GL_C_FM_C_FW_PRE		"iwlwifi-gl-c0-fm-c0"
-
 #define IWL_DEVICE_FM							\
 	.ht_params = {							\
 		.stbc = true,						\
@@ -54,9 +48,3 @@ const char iwl_be201_name[] = "Intel(R) Wi-Fi 7 BE201 320MHz";
 const char iwl_be200_name[] = "Intel(R) Wi-Fi 7 BE200 320MHz";
 const char iwl_be202_name[] = "Intel(R) Wi-Fi 7 BE202 160MHz";
 const char iwl_be401_name[] = "Intel(R) Wi-Fi 7 BE401 320MHz";
-
-IWL_CORE_FW(IWL_BZ_A_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
-IWL_CORE_FW(IWL_BZ_A_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
-IWL_CORE_FW(IWL_BZ_A_FM4_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
-IWL_CORE_FW(IWL_GL_B_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
-IWL_CORE_FW(IWL_GL_C_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 10/15] wifi: iwlwifi: mld: set fast-balance scan for active EMLSR
From: Miri Korenblit @ 2026-05-27 20:05 UTC (permalink / raw)
  To: linux-wireless; +Cc: Pagadala Yesu Anjaneyulu
In-Reply-To: <20260527200512.506707-1-miriam.rachel.korenblit@intel.com>

From: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>

While associated to MLD AP with active EMLSR, set all scan
operations as fast-balance scans. The only exception is when a
fragmented scan is planned (high traffic or low latency), in
which case the fragmented scan is preserved.

Signed-off-by: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mld/scan.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.c b/drivers/net/wireless/intel/iwlwifi/mld/scan.c
index b3836423e53e..d80a1cfc2ed5 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * Copyright (C) 2024-2025 Intel Corporation
+ * Copyright (C) 2024-2026 Intel Corporation
  */
 #include <linux/crc32.h>
 
@@ -237,6 +237,12 @@ iwl_mld_scan_type iwl_mld_get_scan_type(struct iwl_mld *mld,
 	    vif->type != NL80211_IFTYPE_P2P_DEVICE)
 		return IWL_SCAN_TYPE_FRAGMENTED;
 
+	/* While associated to MLD AP with active EMLSR, set all scan
+	 * operations as fast-balance scans.
+	 */
+	if (iwl_mld_emlsr_active(vif))
+		return IWL_SCAN_TYPE_FAST_BALANCE;
+
 	/* In case of DCM with P2P GO set all scan requests as
 	 * fast-balance scan
 	 */
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 09/15] wifi: iwlwifi: mld: support FW TLV for NAN max channel switch time
From: Miri Korenblit @ 2026-05-27 20:05 UTC (permalink / raw)
  To: linux-wireless; +Cc: Israel Kozitz
In-Reply-To: <20260527200512.506707-1-miriam.rachel.korenblit@intel.com>

From: Israel Kozitz <israel.kozitz@intel.com>

Add a new FW TLV (IWL_UCODE_TLV_FW_NAN_MAX_CHAN_SWITCH_TIME) that
allows the firmware to specify the NAN maximum channel switch time
in microseconds.

When the TLV is present, use its value for the NAN device capability.
Otherwise, fall back to the default of 4 milliseconds.

Signed-off-by: Israel Kozitz <israel.kozitz@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/fw/file.h      | 1 +
 drivers/net/wireless/intel/iwlwifi/fw/img.h       | 1 +
 drivers/net/wireless/intel/iwlwifi/iwl-drv.c      | 6 ++++++
 drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 9 +++++++--
 4 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h
index 197c88c25f72..a26ed82a8106 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/file.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h
@@ -112,6 +112,7 @@ enum iwl_ucode_tlv_type {
 	IWL_UCODE_TLV_FW_NUM_LINKS		= IWL_UCODE_TLV_CONST_BASE + 1,
 	IWL_UCODE_TLV_FW_NUM_BEACONS		= IWL_UCODE_TLV_CONST_BASE + 2,
 	IWL_UCODE_TLV_FW_NUM_MCAST_KEY_ENTRIES	= IWL_UCODE_TLV_CONST_BASE + 3,
+	IWL_UCODE_TLV_FW_NAN_MAX_CHAN_SWITCH_TIME = IWL_UCODE_TLV_CONST_BASE + 4,
 
 	IWL_UCODE_TLV_TYPE_DEBUG_INFO		= IWL_UCODE_TLV_DEBUG_BASE + 0,
 	IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION	= IWL_UCODE_TLV_DEBUG_BASE + 1,
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/img.h b/drivers/net/wireless/intel/iwlwifi/fw/img.h
index 75b1344f6cbe..95b45a253641 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/img.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/img.h
@@ -54,6 +54,7 @@ struct iwl_ucode_capabilities {
 	u32 num_links;
 	u32 num_beacons;
 	u32 num_mcast_key_entries;
+	u16 nan_max_chan_switch_time;
 	DECLARE_BITMAP(_api, NUM_IWL_UCODE_TLV_API);
 	DECLARE_BITMAP(_capa, NUM_IWL_UCODE_TLV_CAPA);
 
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
index 488524529538..842586d4fc5c 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
@@ -1337,6 +1337,12 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
 			capa->num_mcast_key_entries =
 				le32_to_cpup((const __le32 *)tlv_data);
 			break;
+		case IWL_UCODE_TLV_FW_NAN_MAX_CHAN_SWITCH_TIME:
+			if (tlv_len != sizeof(u32))
+				goto invalid_tlv_len;
+			capa->nan_max_chan_switch_time =
+				le32_to_cpup((const __le32 *)tlv_data);
+			break;
 		case IWL_UCODE_TLV_UMAC_DEBUG_ADDRS: {
 			const struct iwl_umac_debug_addrs *dbg_ptrs =
 				(const void *)tlv_data;
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
index 92858b8f7395..56e0c19e0f81 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
@@ -291,8 +291,13 @@ static void iwl_mld_hw_set_nan(struct iwl_mld *mld)
 		  NAN_DEV_CAPA_NUM_RX_ANT_POS) &
 		 NAN_DEV_CAPA_NUM_RX_ANT_MASK);
 
-	/* Maximal channel switch time is 4 msec */
-	hw->wiphy->nan_capa.max_channel_switch_time = 4 * USEC_PER_MSEC;
+	/* Maximal channel switch time - use FW TLV value if available */
+	if (mld->fw->ucode_capa.nan_max_chan_switch_time)
+		hw->wiphy->nan_capa.max_channel_switch_time =
+			mld->fw->ucode_capa.nan_max_chan_switch_time;
+	else
+		hw->wiphy->nan_capa.max_channel_switch_time =
+			4 * USEC_PER_MSEC;
 
 	hw->wiphy->nan_capa.phy.ht = mld->nvm_data->nan_phy_capa.ht;
 	hw->wiphy->nan_capa.phy.vht = mld->nvm_data->nan_phy_capa.vht;
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 08/15] wifi: iwlwifi: mld: always allow mimo in NAN
From: Miri Korenblit @ 2026-05-27 20:05 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <20260527200512.506707-1-miriam.rachel.korenblit@intel.com>

The mimo field of the sta command is badly named. It really carries the
initial SMPS value as it is in the association request of the client
station (when we are the AP).

In NAN we don't have this information, just mark SMPS as disabled.

Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mld/sta.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/sta.c b/drivers/net/wireless/intel/iwlwifi/mld/sta.c
index 77eeeed66116..e18d86f021dc 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/sta.c
@@ -538,6 +538,12 @@ int iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld,
 		break;
 	}
 
+	/* In NAN, there is no association request so no initial SMPS info */
+	if (mld_sta->vif->type == NL80211_IFTYPE_NAN_DATA) {
+		cmd.mimo = cpu_to_le32(1);
+		cmd.mimo_protection = cpu_to_le32(0);
+	}
+
 	iwl_mld_fill_ampdu_size_and_dens(link_sta, is_6ghz,
 					 &cmd.tx_ampdu_max_size,
 					 &cmd.tx_ampdu_spacing);
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 07/15] wifi: iwlwifi: move iwl_fw_rate_idx_to_plcp() to mvm
From: Miri Korenblit @ 2026-05-27 20:05 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260527200512.506707-1-miriam.rachel.korenblit@intel.com>

From: Johannes Berg <johannes.berg@intel.com>

It's only needed by mvm, so there's no need to have it in
iwlwifi and export it, just move it to mvm itself.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 .../net/wireless/intel/iwlwifi/fw/api/rs.h    |  3 +-
 drivers/net/wireless/intel/iwlwifi/fw/rs.c    | 27 -----------------
 .../net/wireless/intel/iwlwifi/mvm/mac-ctxt.c |  2 +-
 drivers/net/wireless/intel/iwlwifi/mvm/mvm.h  |  1 +
 .../net/wireless/intel/iwlwifi/mvm/utils.c    | 30 +++++++++++++++++--
 5 files changed, 30 insertions(+), 33 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h
index ae6be3ed32f8..f90e743caa7e 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2012-2014, 2018-2022, 2024-2025 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2022, 2024-2026 Intel Corporation
  * Copyright (C) 2017 Intel Deutschland GmbH
  */
 #ifndef __iwl_fw_api_rs_h__
@@ -889,7 +889,6 @@ struct iwl_lq_cmd {
 	__le32 ss_params;
 }; /* LINK_QUALITY_CMD_API_S_VER_1 */
 
-u8 iwl_fw_rate_idx_to_plcp(int idx);
 const struct iwl_rate_mcs_info *iwl_rate_mcs(int idx);
 const char *iwl_rs_pretty_ant(u8 ant);
 const char *iwl_rs_pretty_bw(int bw);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/rs.c b/drivers/net/wireless/intel/iwlwifi/fw/rs.c
index 2aa300b26158..ccdd6856572b 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/rs.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/rs.c
@@ -8,27 +8,6 @@
 #include "iwl-drv.h"
 #include "iwl-config.h"
 
-#define IWL_DECLARE_RATE_INFO(r) \
-	[IWL_RATE_##r##M_INDEX] = IWL_RATE_##r##M_PLCP
-
-/*
- * Translate from fw_rate_index (IWL_RATE_XXM_INDEX) to PLCP
- * */
-static const u8 fw_rate_idx_to_plcp[IWL_RATE_COUNT] = {
-	IWL_DECLARE_RATE_INFO(1),
-	IWL_DECLARE_RATE_INFO(2),
-	IWL_DECLARE_RATE_INFO(5),
-	IWL_DECLARE_RATE_INFO(11),
-	IWL_DECLARE_RATE_INFO(6),
-	IWL_DECLARE_RATE_INFO(9),
-	IWL_DECLARE_RATE_INFO(12),
-	IWL_DECLARE_RATE_INFO(18),
-	IWL_DECLARE_RATE_INFO(24),
-	IWL_DECLARE_RATE_INFO(36),
-	IWL_DECLARE_RATE_INFO(48),
-	IWL_DECLARE_RATE_INFO(54),
-};
-
 /* mbps, mcs */
 static const struct iwl_rate_mcs_info rate_mcs[IWL_RATE_COUNT] = {
 	{  "1", "BPSK DSSS"},
@@ -61,12 +40,6 @@ static const char * const pretty_bw[] = {
 	"320Mhz",
 };
 
-u8 iwl_fw_rate_idx_to_plcp(int idx)
-{
-	return fw_rate_idx_to_plcp[idx];
-}
-IWL_EXPORT_SYMBOL(iwl_fw_rate_idx_to_plcp);
-
 const struct iwl_rate_mcs_info *iwl_rate_mcs(int idx)
 {
 	return &rate_mcs[idx];
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
index 3e5084d10a60..d6a8624b1ae5 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
@@ -937,7 +937,7 @@ u16 iwl_mvm_mac_ctxt_get_beacon_flags(const struct iwl_fw *fw, u8 rate_idx)
 	if (iwl_fw_lookup_cmd_ver(fw, TX_CMD, 0) > 8)
 		flags |= iwl_mvm_rate_idx_to_fw_idx(fw, rate_idx);
 	else
-		flags |= iwl_fw_rate_idx_to_plcp(rate_idx);
+		flags |= iwl_mvm_rate_idx_to_plcp(rate_idx);
 
 	return flags;
 }
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 393acf5c5f55..e09b63516230 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -1646,6 +1646,7 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm);
 int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm);
 
 /* Utils */
+u8 iwl_mvm_rate_idx_to_plcp(int idx);
 int iwl_mvm_legacy_hw_idx_to_mac80211_idx(u32 rate_n_flags,
 					  enum nl80211_band band);
 int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index 8aba9768afcf..2e12f93ad32b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -14,6 +14,30 @@
 #include "fw/api/rs.h"
 #include "fw/img.h"
 
+#define IWL_DECLARE_RATE_INFO(r) \
+	[IWL_RATE_##r##M_INDEX] = IWL_RATE_##r##M_PLCP
+
+/* Translate from fw_rate_index (IWL_RATE_XXM_INDEX) to PLCP */
+static const u8 fw_rate_idx_to_plcp[IWL_RATE_COUNT] = {
+	IWL_DECLARE_RATE_INFO(1),
+	IWL_DECLARE_RATE_INFO(2),
+	IWL_DECLARE_RATE_INFO(5),
+	IWL_DECLARE_RATE_INFO(11),
+	IWL_DECLARE_RATE_INFO(6),
+	IWL_DECLARE_RATE_INFO(9),
+	IWL_DECLARE_RATE_INFO(12),
+	IWL_DECLARE_RATE_INFO(18),
+	IWL_DECLARE_RATE_INFO(24),
+	IWL_DECLARE_RATE_INFO(36),
+	IWL_DECLARE_RATE_INFO(48),
+	IWL_DECLARE_RATE_INFO(54),
+};
+
+u8 iwl_mvm_rate_idx_to_plcp(int idx)
+{
+	return fw_rate_idx_to_plcp[idx];
+}
+
 /*
  * Will return 0 even if the cmd failed when RFKILL is asserted unless
  * CMD_WANT_SKB is set in cmd->flags.
@@ -151,7 +175,7 @@ int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,
 	if (band != NL80211_BAND_2GHZ)
 		band_offset = IWL_FIRST_OFDM_RATE;
 	for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++)
-		if (iwl_fw_rate_idx_to_plcp(idx) == rate)
+		if (iwl_mvm_rate_idx_to_plcp(idx) == rate)
 			return idx - band_offset;
 
 	return -1;
@@ -1243,7 +1267,7 @@ static u32 iwl_legacy_rate_to_fw_idx(u32 rate_n_flags)
 	int last = ofdm ? IWL_RATE_COUNT_LEGACY : IWL_FIRST_OFDM_RATE;
 
 	for (idx = offset; idx < last; idx++)
-		if (iwl_fw_rate_idx_to_plcp(idx) == rate)
+		if (iwl_mvm_rate_idx_to_plcp(idx) == rate)
 			return idx - offset;
 	return IWL_RATE_INVALID;
 }
@@ -1353,7 +1377,7 @@ __le32 iwl_mvm_v3_rate_to_fw(u32 rate, u8 rate_ver)
 		rate_idx = u32_get_bits(rate, RATE_LEGACY_RATE_MSK);
 		if (!(result & RATE_MCS_CCK_MSK_V1))
 			rate_idx += IWL_FIRST_OFDM_RATE;
-		result |= u32_encode_bits(iwl_fw_rate_idx_to_plcp(rate_idx),
+		result |= u32_encode_bits(iwl_mvm_rate_idx_to_plcp(rate_idx),
 					  RATE_LEGACY_RATE_MSK_V1);
 		break;
 	case RATE_MCS_MOD_TYPE_HT:
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 06/15] wifi: iwlwifi: mvm: rename iwl_mvm_mac80211_idx_to_hwrate()
From: Miri Korenblit @ 2026-05-27 20:05 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260527200512.506707-1-miriam.rachel.korenblit@intel.com>

From: Johannes Berg <johannes.berg@intel.com>

Given that we now use v3 rates with FW index throughout,
_to_hwrate() is confusing, since the hardware still uses
the PLCP value, the driver just doesn't see that now (as
it talks to firmware, not hardware.)

Rename this to iwl_mvm_rate_idx_to_fw_idx() to more
clearly indicate what it's doing.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c |  4 ++--
 drivers/net/wireless/intel/iwlwifi/mvm/mvm.h      |  2 +-
 drivers/net/wireless/intel/iwlwifi/mvm/tx.c       | 10 +++++-----
 drivers/net/wireless/intel/iwlwifi/mvm/utils.c    |  2 +-
 4 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
index 8ffa72aca3cf..3e5084d10a60 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
@@ -935,7 +935,7 @@ u16 iwl_mvm_mac_ctxt_get_beacon_flags(const struct iwl_fw *fw, u8 rate_idx)
 			  : IWL_MAC_BEACON_CCK_V1;
 
 	if (iwl_fw_lookup_cmd_ver(fw, TX_CMD, 0) > 8)
-		flags |= iwl_mvm_mac80211_idx_to_hwrate(fw, rate_idx);
+		flags |= iwl_mvm_rate_idx_to_fw_idx(fw, rate_idx);
 	else
 		flags |= iwl_fw_rate_idx_to_plcp(rate_idx);
 
@@ -998,7 +998,7 @@ static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm,
 	else
 		rate_n_flags |= RATE_MCS_MOD_TYPE_LEGACY_OFDM;
 
-	rate_n_flags |= iwl_mvm_mac80211_idx_to_hwrate(mvm->fw, rate);
+	rate_n_flags |= iwl_mvm_rate_idx_to_fw_idx(mvm->fw, rate);
 
 	tx_params->rate_n_flags = iwl_mvm_v3_rate_to_fw(rate_n_flags,
 							mvm->fw_rates_ver);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index be89b84204fb..393acf5c5f55 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -1653,7 +1653,7 @@ int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,
 void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,
 			       enum nl80211_band band,
 			       struct ieee80211_tx_rate *r);
-u8 iwl_mvm_mac80211_idx_to_hwrate(const struct iwl_fw *fw, int rate_idx);
+u8 iwl_mvm_rate_idx_to_fw_idx(const struct iwl_fw *fw, int rate_idx);
 u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac);
 bool iwl_mvm_is_nic_ack_enabled(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index bca13417e82c..dc69c71faa76 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * Copyright (C) 2012-2014, 2018-2025 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2026 Intel Corporation
  * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
  * Copyright (C) 2016-2017 Intel Deutschland GmbH
  */
@@ -268,7 +268,6 @@ static u32 iwl_mvm_convert_rate_idx(struct iwl_mvm *mvm,
 				    int rate_idx)
 {
 	u32 rate_flags = 0;
-	u8 rate_plcp;
 	bool is_cck;
 
 	/* if the rate isn't a well known legacy rate, take the lowest one */
@@ -277,8 +276,9 @@ static u32 iwl_mvm_convert_rate_idx(struct iwl_mvm *mvm,
 							    info,
 							    info->control.vif);
 
-	/* Get PLCP rate for tx_cmd->rate_n_flags */
-	rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(mvm->fw, rate_idx);
+	/* Get FW rate for tx_cmd->rate_n_flags */
+	rate_flags |= iwl_mvm_rate_idx_to_fw_idx(mvm->fw, rate_idx);
+
 	is_cck = (rate_idx >= IWL_FIRST_CCK_RATE) &&
 		 (rate_idx <= IWL_LAST_CCK_RATE);
 
@@ -288,7 +288,7 @@ static u32 iwl_mvm_convert_rate_idx(struct iwl_mvm *mvm,
 	else
 		rate_flags |= RATE_MCS_MOD_TYPE_CCK;
 
-	return (u32)rate_plcp | rate_flags;
+	return rate_flags;
 }
 
 static u32 iwl_mvm_get_inject_tx_rate(struct iwl_mvm *mvm,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index f052537e9567..8aba9768afcf 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -157,7 +157,7 @@ int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,
 	return -1;
 }
 
-u8 iwl_mvm_mac80211_idx_to_hwrate(const struct iwl_fw *fw, int rate_idx)
+u8 iwl_mvm_rate_idx_to_fw_idx(const struct iwl_fw *fw, int rate_idx)
 {
 	return rate_idx >= IWL_FIRST_OFDM_RATE ?
 		rate_idx - IWL_FIRST_OFDM_RATE :
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 05/15] wifi: iwlwifi: fix STEP_URM register address for SC devices
From: Miri Korenblit @ 2026-05-27 20:05 UTC (permalink / raw)
  To: linux-wireless; +Cc: Moriya Itzchaki
In-Reply-To: <20260527200512.506707-1-miriam.rachel.korenblit@intel.com>

From: Moriya Itzchaki <moriya.itzchaki@intel.com>

The CNVI_PMU_STEP_FLOW register address differs between device families.
For SC and newer devices, the register is at 0xA2D688,
while for BZ devices it's at 0xA2D588.

Signed-off-by: Moriya Itzchaki <moriya.itzchaki@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/iwl-prph.h        |  3 ++-
 .../wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c  | 12 ++++++++----
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
index 6ca1f51b69a1..50acfe0d4f79 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
@@ -385,7 +385,8 @@ enum {
 #define   CNVI_SCU_REG_FOR_ECO_1_WIAMT_KNOWN		BIT(4)
 #define   CNVI_SCU_REG_FOR_ECO_1_WIAMT_PRESENT		BIT(5)
 
-#define CNVI_PMU_STEP_FLOW				0xA2D588
+#define CNVI_PMU_STEP_FLOW_BZ				0xA2D588
+#define CNVI_PMU_STEP_FLOW_SC				0xA2D688
 #define CNVI_PMU_STEP_FLOW_FORCE_URM			BIT(2)
 
 #define PREG_AUX_BUS_WPROT_0		0xA04CC0
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c
index 0e324aeb9055..f41cbe62e7aa 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c
@@ -376,6 +376,7 @@ static void iwl_pcie_get_rf_name(struct iwl_trans *trans)
 void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans)
 {
 	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	u32 step_reg;
 
 	iwl_pcie_reset_ict(trans);
 
@@ -404,10 +405,13 @@ void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans)
 	iwl_pcie_get_rf_name(trans);
 	mutex_unlock(&trans_pcie->mutex);
 
-	if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ)
-		trans->step_urm = !!(iwl_read_prph(trans,
-						   CNVI_PMU_STEP_FLOW) &
-				     CNVI_PMU_STEP_FLOW_FORCE_URM);
+	if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_BZ)
+		return;
+
+	step_reg = trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_SC ?
+		   CNVI_PMU_STEP_FLOW_SC : CNVI_PMU_STEP_FLOW_BZ;
+	trans->step_urm = !!(iwl_read_prph(trans, step_reg) &
+			     CNVI_PMU_STEP_FLOW_FORCE_URM);
 }
 
 static bool iwl_pcie_set_ltr(struct iwl_trans *trans)
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 04/15] wifi: iwlwifi: mld: fix smatch warning
From: Miri Korenblit @ 2026-05-27 20:05 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <20260527200512.506707-1-miriam.rachel.korenblit@intel.com>

We dereference the mld_sta pointer before checking for NULL.
But we do check the sta pointer, and sta != NULL means mld_sta != NULL,
so there is no real issue.
Fix it anyway to silence the warning.

Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mld/tx.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tx.c b/drivers/net/wireless/intel/iwlwifi/mld/tx.c
index 1e8716cbb4ce..2185dade95f8 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/tx.c
@@ -563,7 +563,8 @@ iwl_mld_fill_tx_cmd(struct iwl_mld *mld, struct sk_buff *skb,
 	 * - when no sta is given.
 	 * - frames that are sent to an NMI sta, which is only used for management.
 	 */
-	if (unlikely(!sta || mld_sta->vif->type == NL80211_IFTYPE_NAN ||
+	if (unlikely(!sta ||
+		     (mld_sta && mld_sta->vif->type == NL80211_IFTYPE_NAN) ||
 		     info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT)) {
 		flags |= IWL_TX_FLAGS_CMD_RATE;
 		rate_n_flags = iwl_mld_get_tx_rate_n_flags(mld, info, sta,
-- 
2.34.1


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox