Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [PATCH 6.1.y] wifi: mac80211: check tdls flag in ieee80211_tdls_oper
From: Sasha Levin @ 2026-05-25 15:33 UTC (permalink / raw)
  To: gregkh, stable, kartikey406
  Cc: Sasha Levin, patches, linux-kernel, johannes, davem, edumazet,
	kuba, pabeni, linux-wireless, netdev, johannes.berg, Li hongliang
In-Reply-To: <20260525054854.2457807-1-1468888505@139.com>

On Mon, May 25, 2026 at 01:48:54PM +0800, Li hongliang wrote:
> From: Deepanshu Kartikey <kartikey406@gmail.com>
>
> [ Upstream commit 7d73872d949c488a1d7c308031d6a9d89b5e0a8b ]
>
> When NL80211_TDLS_ENABLE_LINK is called, the code only checks if the
> station exists but not whether it is actually a TDLS station.

Queued for 6.1, thanks.

-- 
Thanks,
Sasha

^ permalink raw reply

* Re: [PATCH 6.6.y] wifi: mac80211: check tdls flag in ieee80211_tdls_oper
From: Sasha Levin @ 2026-05-25 15:33 UTC (permalink / raw)
  To: gregkh, stable, kartikey406
  Cc: Sasha Levin, patches, linux-kernel, johannes, davem, edumazet,
	kuba, pabeni, linux-wireless, netdev, johannes.berg, Li hongliang
In-Reply-To: <20260525054835.2457749-1-1468888505@139.com>

On Mon, May 25, 2026 at 01:48:35PM +0800, Li hongliang wrote:
> From: Deepanshu Kartikey <kartikey406@gmail.com>
>
> [ Upstream commit 7d73872d949c488a1d7c308031d6a9d89b5e0a8b ]
>
> When NL80211_TDLS_ENABLE_LINK is called, the code only checks if the
> station exists but not whether it is actually a TDLS station.

Queued for 6.6, thanks.

-- 
Thanks,
Sasha

^ permalink raw reply

* Re: [BUG] mt7921e: Intermittent connection failure
From: silverducks @ 2026-05-25 14:15 UTC (permalink / raw)
  To: Sean Wang
  Cc: linux-wireless, nbd, lorenzo, ryder.lee, shayne.chen, sean.wang,
	matthias.bgg, angelogioacchino.delregno,
	moderated list:ARM/Mediatek SoC support
In-Reply-To: <4d4f7e6a-b887-4541-9928-0f255bc61ee7@altlinux.org>

Greetings!

Update:
As of kernel version 7.1-rc4 the error is no longer reproduced.

^ permalink raw reply

* ath11k: WCN6855 WoWLAN resume leaves RX in unrecoverable reorder state → TCP collapses
From: Hauke Mehrtens @ 2026-05-25 13:24 UTC (permalink / raw)
  To: Jeff Johnson, linux-wireless, ath11k, Baochen Qiang

I used AI to help me debug this problem.

On Lenovo ThinkPad P14s G4 AMD (QCNFA765 / WCN6855 hw2.1), ~1 in 10
suspend/resume cycles leaves the ath11k RX path delivering MSDUs out of
order (~16% of TCP segments). TCP cwnd stays at 1-3 MSS and goodput
collapses to ~3 Mbit/s; UDP on the same link in the same minute pushes
100+ Mbit/s.

This machine is in the DMI quirk list at
`drivers/net/wireless/ath/ath11k/core.c` that forces `ATH11K_PM_WOW`.
In WOW mode the firmware is kept alive across suspend; the WOW resume
path does not re-initialise REO HW or per-TID BA state.
The PM_WOW quirk was added as a workaround for unexpected-wakeup bug
https://bugzilla.kernel.org/show_bug.cgi?id=219196

## Affected components

- **Driver:** ath11k_pci
- **Chip:** WCN6855 hw2.1 (`17cb:1103`, QCNFA765)
- **Firmware:** 
`WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.41`
   (fw_version `0x11088c35`, 2024-04-17)
- **Kernel:** observed on 7.0.9-arch1-1; also present across many
   earlier kernel versions over the past >1 year on this hardware
- **Machine:** Lenovo ThinkPad P14s G4 AMD, DMI `21K5CTO1WW` (matches
   quirk entry "P14s G4 AMD #1" at `core.c:961-966` via `"21K5"`
   substring)

## Reproduce

1. Associate to an HE AP (characterised at 6 GHz, HE-MCS 5/6 NSS 2
    160 MHz, -56 dBm, using MT7915 with OpenWrt 25.12).
2. Suspend, wake, test `iperf3` TCP. Repeat. On average within ~10
    cycles, one resume leaves the link broken.
3. In the broken state: `iw dev wlpXsY link` still reports ~1.3 Gbit/s
    "bitrate". Ping and UDP iperf3 look fine. TCP iperf3 collapses to
    ~3 Mbit/s with cwnd stuck at 1-3 MSS.

## Evidence

### iperf3, same link same minute

```
AP -> STA, UDP -b 200M -l 1400 -t 15:
   sender:   200 Mbit/s, 267876 datagrams
   receiver: 102 Mbit/s, 137290 received, 130585 "lost"
   (not real loss; iperf3 UDP counts out-of-window arrivals as lost)

AP -> STA, TCP -t 15:
   3.43 Mbit/s, 521 retransmits, cwnd 1.41-5.66 KB throughout
```

### UDP run: no real loss anywhere

- `ip -s link` delta: `+267,953 packets`, `0 errors`, `0 dropped`
   (AP sent 267,876).
- `/proc/net/snmp` Udp: `RcvbufErrors 0, InErrors 0`.
- ath11k `pdev_stats` delta: `MSDUs delivered to HTT +267,985`.
- `soc_dp_stats` entirely zero: no RXDMA / REO / HAL / TCL / backpressure
   errors of any kind.
- AP `iw station get`: ~1.3% retry rate, -65 dBm ACK signal,
   `expected throughput 1049 Mbps`.

→ Air link clean. Host data path clean. Firmware delivered every
datagram. No drops anywhere.

### TCP socket reorder (`ss -tin` once per second during TCP iperf3)

```
    t (s)    bytes_rx   segs_in   rcv_ooopack
    0        1,291,653       895          158
    1        1,717,365     1,189          210
    2        2,060,541     1,426          274
    3        2,519,557     1,743          335
    4        3,050,973     2,110          397
    5        3,446,277     2,383          450
    6        3,906,741     2,701          513
```

~60 ooo packets/s out of ~370 segs/s = **~16% out-of-order**, sustained.

### Packet-level pattern (`tcpdump` on wlpXsY)

Seq normalised to 0 at flow start:

```
22 ms     2896:4344
25 ms     4344:5792
27 ms     1448:2896           <-- late; fills gap from 5 ms earlier
28 ms     5792:7240
54 ms     8688:10136
55 ms     10136:11584
57 ms     7240:8688           <-- late
107 ms    26064:27512
107 ms    28960:30408
108 ms    30408:31856
109 ms    27512:28960         <-- late
156 ms    57920:59368
156 ms    59368:60816
157 ms    56472:57920         <-- late
```

Fingerprint: A-MPDU subframe lost on first transmission, retried, retry
arrives 2-5 ms later. Working REO HW would buffer the continuation
until the missing subframe arrived or the per-TID reorder timeout
(`HAL_DEFAULT_REO_TIMEOUT_USEC`, 40 ms) expired. Here both continuation
and retry pass through unordered.

## Diagnosis

- Air link healthy; host data path clean; REO HW error counters all
   zero — REO simply isn't enforcing order for this peer's TIDs.
- dmesg across 3 days of suspend cycles shows zero ath11k re-init
   activity (no `fw_version` reprint, no `wcn6855 hw2.1` reprint). The
   firmware instance is the same one from the most recent `modprobe`.
   `ath11k_core_suspend_wow` / `ath11k_core_resume_wow` neither power
   down the device nor re-initialise REO.
- `rmmod` triggers full `ath11k_hif_power_down` + chip re-init on next
   `modprobe`, which re-runs `ath11k_hw_wcn6855_reo_setup`. This is the
   only reliable recovery, so the corrupted state lives in firmware /
   REO HW that the WOW resume path never touches.

The non-WOW path (`ath11k_core_suspend_default`) does power-down + full
re-init on resume, re-running `ath11k_dp_srng_common_setup()` →
`hw_ops->reo_setup()`. The WOW path does not.

## Related

- Bug #219196 — unexpected wakeups; the WOW workaround was added to
   mitigate this
- `ce8669a27016` — introduced the WOW quirk table (2025-03-28, Baochen 
Qiang)
- `0eb002c93c3b` — added `21K5` / `21K6` (this laptop) to the quirk
   table (2025-09-29, Mark Pearson)
- `4015b1972763` — adds Z13/Z16 Gen1 to WOW quirk (Nov 2025)

Hauke

^ permalink raw reply

* [PATCH] wifi: iwlwifi: dvm: fix off-by-one in iwl_rx_dispatch command index
From: Junrui Luo @ 2026-05-25 12:23 UTC (permalink / raw)
  To: Miri Korenblit, Emmanuel Grumbach, Wey-Yi Guy
  Cc: linux-wireless, linux-kernel, Yuhao Jiang, stable, Junrui Luo

iwl_rx_dispatch() indexes priv->rx_handlers[] and priv->rx_handlers_stats[]
by pkt->hdr.cmd without bounds checking. Both arrays are declared with
REPLY_MAX (0xff = 255) entries, but pkt->hdr.cmd is a u8 spanning 0..255,
so cmd == 0xff reads and writes one element past the end of each array.

The OOB read on rx_handlers[] lands on the adjacent notif_wait field,
whose ->next pointer is non-NULL after init, causing the function pointer
check to pass and the kernel to call a heap address. The OOB increment on
rx_handlers_stats[] corrupts rf_reset.reset_request_count.

Add a bounds check against ARRAY_SIZE(priv->rx_handlers) before indexing,
so out-of-range commands fall through to the existing debug log branch.

Fixes: 1ab9f6c11b00 ("iwlagn: move the Rx dispatching to the upper layer")
Reported-by: Yuhao Jiang <danisjiang@gmail.com>
Cc: stable@vger.kernel.org
Signed-off-by: Junrui Luo <moonafterrain@outlook.com>
---
 drivers/net/wireless/intel/iwlwifi/dvm/rx.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c
index 088302a238de..a5a58cf331d4 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c
@@ -1008,7 +1008,8 @@ void iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct napi_struct *napi,
 	/* Based on type of command response or notification,
 	 *   handle those that need handling via function in
 	 *   rx_handlers table.  See iwl_setup_rx_handlers() */
-	if (priv->rx_handlers[pkt->hdr.cmd]) {
+	if (pkt->hdr.cmd < ARRAY_SIZE(priv->rx_handlers) &&
+	    priv->rx_handlers[pkt->hdr.cmd]) {
 		priv->rx_handlers_stats[pkt->hdr.cmd]++;
 		priv->rx_handlers[pkt->hdr.cmd](priv, rxb);
 	} else {

---
base-commit: c369299895a591d96745d6492d4888259b004a9e
change-id: 20260525-fixes-a32bbe287204

Best regards,
-- 
Junrui Luo <moonafterrain@outlook.com>


^ permalink raw reply related

* Re: [PATCH v3 0/7] b43: complete N-PHY rev 8 + radio 2057 rev 8 support
From: Alessio Ferri @ 2026-05-25 12:04 UTC (permalink / raw)
  To: Michael Büsch; +Cc: linux-wireless, b43-dev, linux-kernel
In-Reply-To: <20260525100752.16cdb59e@barney>

Il giorno Mon, 25 May 2026 10:07:52 +0200
Michael Büsch <m@bues.ch> ha scritto:

> On Sun, 24 May 2026 23:56:17 +0200
> Alessio Ferri <alessio.ferri@mythread.it> wrote:
> 
> > Alessio Ferri (7):
> >       b43: add firmware mappings and remove comments wondering
> > about rev22 initvals b43: add d11 core revision 0x16 to id table
> >       b43: route d11 corerev 22 to 24-bit indirect radio access
> >       b43: support radio 2057 rev 8
> >       b43: add IPA TX gain table for N-PHY r8 + radio 2057 r8
> >       b43: add channel info table for N-PHY r8 + radio 2057 r8
> >       b43: add RF power offset for N-PHY r8 + radio 2057 r8
> > 
> >  drivers/net/wireless/broadcom/b43/main.c        |  22 ++-
> >  drivers/net/wireless/broadcom/b43/radio_2057.c  | 230
> > ++++++++++++++++++++++--
> > drivers/net/wireless/broadcom/b43/tables_nphy.c |  58 ++++++ 3
> > files changed, 290 insertions(+), 20 deletions(-)  
> 
> 
> Looks good and in general low risk because it doesn't change any code
> paths of supported hw revisions.
> I'd still prefer if somebody could test this change on another
> supported 2057 radio. I don't have such a device unfortunately.
> 
> Does the D-Link DSL-3580L work with full expected wireless throughput
> after this change or are there any remaining known issues?
> 
> Acked-by: Michael Büsch <m@bues.ch>
> 

Please clarify "full expected wireless throughput", HT is
not supported by b43, so it runs only with NOHT in g-like speed:

wireless.radio0=wifi-device
wireless.radio0.type='mac80211'
wireless.radio0.path='platform/ubus/10007000.wlan/10004000.axi/bcma0:1'
wireless.radio0.band='2g'
wireless.radio0.channel='36'
wireless.radio0.htmode='NOHT'
wireless.radio0.country='IT'
wireless.default_radio0=wifi-iface
wireless.default_radio0.device='radio0'
wireless.default_radio0.network='lan'
wireless.default_radio0.mode='ap'
wireless.default_radio0.ssid='DSL3580L'
wireless.default_radio0.encryption='psk2'
wireless.default_radio0.disabled='0'

Enabling HT for N chips is out of scope, also there nothing to
gain and a lot to risk, so i won't do it.

Once this lands, i would move to fix AC support for the only two chips
that require b43 to work (4352 & 4360). I own them both, in multiple
routers, so i can safely develop for them. It is also low risk as there
are no existings users.


^ permalink raw reply

* [PATCH ath-next 6/6] wifi: ath12k: Handle 4-address EAPOL frames from WBM error path
From: Tamizh Chelvam Raja @ 2026-05-25 11:09 UTC (permalink / raw)
  To: ath12k; +Cc: linux-wireless, Tamizh Chelvam Raja, Sathishkumar Muruganandam
In-Reply-To: <20260525110942.2890212-1-tamizh.raja@oss.qualcomm.com>

Whenever hardware receives 4-address EAPOL frames from an unauthorized
station it is routed through WBM/RXDMA error path with the
HAL_REO_ENTR_RING_RXDMA_ECODE_UNAUTH_WDS_ERR error code. But, the
current driver does not handle the 4-address EAPOL frames
in the WBM error path. As a result, these frames are dropped,
causing authentication failures and connectivity issues for 4-address
stations.

Add support to correctly process these frames and forward them to mac80211
for proper handling. This prevents the loss of 4-address EAPOL frames and
ensures reliable connectivity for WDS/4-address clients.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1

Co-developed-by: Sathishkumar Muruganandam <quic_murugana@quicinc.com>
Signed-off-by: Sathishkumar Muruganandam <quic_murugana@quicinc.com>
Signed-off-by: Tamizh Chelvam Raja <tamizh.raja@oss.qualcomm.com>
---
 drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c | 53 +++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
index 43bb8631827f..d1d63c49d014 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
@@ -1702,6 +1702,56 @@ static bool ath12k_wifi7_dp_rx_h_tkip_mic_err(struct ath12k_pdev_dp *dp_pdev,
 	return false;
 }
 
+static bool ath12k_wifi7_dp_rx_h_unauth_wds_err(struct ath12k_pdev_dp *dp_pdev,
+						struct sk_buff *msdu,
+						struct hal_rx_desc_data *rx_info)
+{
+	struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu);
+	struct ath12k_dp *dp = dp_pdev->dp;
+	u32 hdr_len, hal_rx_desc_sz = dp->ab->hal.hal_desc_sz;
+	u8 l3pad_bytes = rx_info->l3_pad_bytes;
+	struct ath12k_dp_rx_rfc1042_hdr *llc;
+	u16 msdu_len = rx_info->msdu_len;
+	struct ath12k_dp_peer *peer;
+	struct ieee80211_hdr *hdr;
+	int ret;
+
+	guard(rcu)();
+	peer = ath12k_dp_peer_find_by_peerid(dp_pdev, rxcb->peer_id);
+	if (!peer) {
+		ath12k_dbg(dp->ab, ATH12K_DBG_DATA,
+			   "failed to find the peer to process unauth wds err handling peer_id %d\n",
+			   rxcb->peer_id);
+		return true;
+	}
+
+	if ((hal_rx_desc_sz + l3pad_bytes + msdu_len) > DP_RX_BUFFER_SIZE)
+		return true;
+
+	skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
+	skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
+
+	if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(dp, msdu,
+							     rx_info)))
+		return true;
+
+	ath12k_dp_rx_h_ppdu(dp_pdev, rx_info);
+
+	ret = ath12k_wifi7_dp_rx_h_mpdu(dp_pdev, msdu, rx_info);
+	if (ret)
+		return true;
+
+	rxcb->tid = rx_info->tid;
+
+	hdr = (struct ieee80211_hdr *)msdu->data;
+	hdr_len = ieee80211_hdrlen(hdr->frame_control);
+	llc = (struct ath12k_dp_rx_rfc1042_hdr *)(msdu->data + hdr_len);
+	if (llc->snap_type != cpu_to_be16(ETH_P_PAE))
+		return true;
+
+	return false;
+}
+
 static bool ath12k_wifi7_dp_rx_h_rxdma_err(struct ath12k_pdev_dp *dp_pdev,
 					   struct sk_buff *msdu,
 					   struct hal_rx_desc_data *rx_info)
@@ -1713,6 +1763,9 @@ static bool ath12k_wifi7_dp_rx_h_rxdma_err(struct ath12k_pdev_dp *dp_pdev,
 	dp->device_stats.rxdma_error[rxcb->err_code]++;
 
 	switch (rxcb->err_code) {
+	case HAL_REO_ENTR_RING_RXDMA_ECODE_UNAUTH_WDS_ERR:
+		drop = ath12k_wifi7_dp_rx_h_unauth_wds_err(dp_pdev, msdu, rx_info);
+		break;
 	case HAL_REO_ENTR_RING_RXDMA_ECODE_DECRYPT_ERR:
 	case HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR:
 		if (rx_info->err_bitmap & HAL_RX_MPDU_ERR_TKIP_MIC) {
-- 
2.34.1


^ permalink raw reply related

* [PATCH ath-next 5/6] wifi: ath12k: Add support for 4-address frame notification
From: Tamizh Chelvam Raja @ 2026-05-25 11:09 UTC (permalink / raw)
  To: ath12k; +Cc: linux-wireless, Tamizh Chelvam Raja
In-Reply-To: <20260525110942.2890212-1-tamizh.raja@oss.qualcomm.com>

mac80211 currently relies on receiving 4-address frames from connected
stations to trigger AP_VLAN interface creation. However, when ethernet
encapsulation offload is enabled, mac80211 only receives 802.3 frames
and cannot differentiate between 3-address and 4-address formats,
preventing AP_VLAN creation.

Enable mac80211 to detect 4-address traffic by converting 802.3 frames
back into 802.11 frames in the driver and setting the FROM_DS and TO_DS
bits using the RX_MSDU_END_INFO5_FROM_DS and RX_MSDU_END_INFO5_TO_DS
fields. This restores 4-address frame visibility to mac80211 and allows
it to trigger AP_VLAN interface creation.

Skip this frame conversion once the AP_VLAN interface is created and the
station is attached to it.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1

Signed-off-by: Tamizh Chelvam Raja <tamizh.raja@oss.qualcomm.com>
---
 drivers/net/wireless/ath/ath12k/dp_peer.h     |  2 +
 drivers/net/wireless/ath/ath12k/dp_rx.c       | 10 ++++-
 drivers/net/wireless/ath/ath12k/dp_rx.h       |  3 +-
 drivers/net/wireless/ath/ath12k/hal.h         |  4 +-
 drivers/net/wireless/ath/ath12k/mac.c         |  1 +
 drivers/net/wireless/ath/ath12k/peer.c        |  3 ++
 drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c | 38 ++++++++++++++-----
 .../wireless/ath/ath12k/wifi7/hal_qcc2072.c   | 16 ++++++++
 .../wireless/ath/ath12k/wifi7/hal_qcn9274.c   | 16 ++++++++
 .../wireless/ath/ath12k/wifi7/hal_wcn7850.c   | 16 ++++++++
 10 files changed, 97 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/dp_peer.h b/drivers/net/wireless/ath/ath12k/dp_peer.h
index 113b8040010f..f5067e66f1e1 100644
--- a/drivers/net/wireless/ath/ath12k/dp_peer.h
+++ b/drivers/net/wireless/ath/ath12k/dp_peer.h
@@ -143,6 +143,8 @@ struct ath12k_dp_peer {
 	struct ath12k_dp_link_peer __rcu *link_peers[ATH12K_NUM_MAX_LINKS];
 	struct ath12k_reoq_buf reoq_bufs[IEEE80211_NUM_TIDS + 1];
 	struct ath12k_dp_rx_tid rx_tid[IEEE80211_NUM_TIDS + 1];
+
+	bool use_4addr;
 };
 
 struct ath12k_dp_link_peer *
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
index a4fec1dc55c6..bccb1bc0b41e 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
@@ -1139,7 +1139,8 @@ static void ath12k_dp_rx_h_undecap_eth(struct ath12k_pdev_dp *dp_pdev,
 void ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu,
 			    enum hal_encrypt_type enctype,
 			    bool decrypted,
-			    struct hal_rx_desc_data *rx_info)
+			    struct hal_rx_desc_data *rx_info,
+			    struct ath12k_dp_peer *peer)
 {
 	enum ath12k_dp_rx_decap_type decap_type = rx_info->decap_type;
 	struct ethhdr *ehdr;
@@ -1163,6 +1164,13 @@ void ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu
 			break;
 		}
 
+		if (peer && !peer->use_4addr &&
+		    rx_info->is_from_ds && rx_info->is_to_ds) {
+			ath12k_dp_rx_h_undecap_eth(dp_pdev, msdu, enctype, rx_info,
+						   decap_type);
+			break;
+		}
+
 		/* PN for mcast packets will be validated in mac80211;
 		 * remove eth header and add 802.11 header.
 		 */
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h
index 55a31e669b3b..0660db070e92 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.h
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.h
@@ -190,7 +190,8 @@ void ath12k_dp_extract_rx_desc_data(struct ath12k_hal *hal,
 void ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu,
 			    enum hal_encrypt_type enctype,
 			    bool decrypted,
-			    struct hal_rx_desc_data *rx_info);
+			    struct hal_rx_desc_data *rx_info,
+			    struct ath12k_dp_peer *peer);
 void ath12k_dp_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev, struct napi_struct *napi,
 			       struct sk_buff *msdu,
 			       struct hal_rx_desc_data *rx_info);
diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h
index bf4f7dbae866..21c551d8b248 100644
--- a/drivers/net/wireless/ath/ath12k/hal.h
+++ b/drivers/net/wireless/ath/ath12k/hal.h
@@ -738,7 +738,9 @@ struct hal_rx_desc_data {
 	    addr2_present:1,
 	    is_mcbc:1,
 	    seq_ctl_valid:1,
-	    fc_valid:1;
+	    fc_valid:1,
+	    is_to_ds:1,
+	    is_from_ds:1;
 	u16 msdu_len;
 	u16 peer_id;
 	u16 seq_no;
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 2f437ecae84d..d6f7e8974c33 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -6626,6 +6626,7 @@ static int ath12k_mac_sta_set_4addr(struct wiphy *wiphy, struct ath12k_sta *ahst
 								 arsta->addr);
 		if (peer && peer->dp_peer) {
 			peer->dp_peer->ucast_ra_only = true;
+			peer->dp_peer->use_4addr = true;
 		} else {
 			spin_unlock_bh(&dp->dp_lock);
 			ath12k_warn(ar->ab, "failed to find DP peer for %pM\n",
diff --git a/drivers/net/wireless/ath/ath12k/peer.c b/drivers/net/wireless/ath/ath12k/peer.c
index b5a0ba149a28..c222bdaa333c 100644
--- a/drivers/net/wireless/ath/ath12k/peer.c
+++ b/drivers/net/wireless/ath/ath12k/peer.c
@@ -255,6 +255,9 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
 						 ar->hw_link_id);
 	}
 
+	if (vif->type == NL80211_IFTYPE_AP && peer->dp_peer)
+		peer->dp_peer->ucast_ra_only = true;
+
 	return ret;
 }
 
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
index 945680b3ebdf..43bb8631827f 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
@@ -323,9 +323,9 @@ static void ath12k_wifi7_dp_rx_h_csum_offload(struct sk_buff *msdu,
 			   CHECKSUM_NONE : CHECKSUM_UNNECESSARY;
 }
 
-static void ath12k_wifi7_dp_rx_h_mpdu(struct ath12k_pdev_dp *dp_pdev,
-				      struct sk_buff *msdu,
-				      struct hal_rx_desc_data *rx_info)
+static int ath12k_wifi7_dp_rx_h_mpdu(struct ath12k_pdev_dp *dp_pdev,
+				     struct sk_buff *msdu,
+				     struct hal_rx_desc_data *rx_info)
 {
 	struct ath12k_skb_rxcb *rxcb;
 	enum hal_encrypt_type enctype;
@@ -347,6 +347,18 @@ static void ath12k_wifi7_dp_rx_h_mpdu(struct ath12k_pdev_dp *dp_pdev,
 
 	peer = ath12k_dp_peer_find_by_peerid(dp_pdev, rxcb->peer_id);
 	if (peer) {
+		/*
+		 * Drop the 3-address multicast packet from 4-address
+		 * peer To avoid receiving the duplicate multicast packet
+		 * Specifically from AP interface in 3-address format
+		 */
+		if (rxcb->is_mcbc &&
+		    rx_info->decap_type == DP_RX_DECAP_TYPE_ETHERNET2_DIX) {
+			if (peer->use_4addr &&
+			    !(rx_info->is_from_ds && rx_info->is_to_ds))
+				return -EINVAL;
+		}
+
 		/* resetting mcbc bit because mcbc packets are unicast
 		 * packets only for AP as STA sends unicast packets.
 		 */
@@ -387,15 +399,18 @@ static void ath12k_wifi7_dp_rx_h_mpdu(struct ath12k_pdev_dp *dp_pdev,
 	}
 
 	ath12k_wifi7_dp_rx_h_csum_offload(msdu, rx_info);
-	ath12k_dp_rx_h_undecap(dp_pdev, msdu, enctype, is_decrypted, rx_info);
+	ath12k_dp_rx_h_undecap(dp_pdev, msdu, enctype, is_decrypted, rx_info,
+			       peer);
 
 	if (!is_decrypted || rx_info->is_mcbc)
-		return;
+		return 0;
 
 	if (rx_info->decap_type != DP_RX_DECAP_TYPE_ETHERNET2_DIX) {
 		hdr = (void *)msdu->data;
 		hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED);
 	}
+
+	return 0;
 }
 
 static int ath12k_wifi7_dp_rx_msdu_coalesce(struct ath12k_hal *hal,
@@ -554,7 +569,9 @@ static int ath12k_wifi7_dp_rx_process_msdu(struct ath12k_pdev_dp *dp_pdev,
 	}
 
 	ath12k_dp_rx_h_ppdu(dp_pdev, rx_info);
-	ath12k_wifi7_dp_rx_h_mpdu(dp_pdev, msdu, rx_info);
+	ret = ath12k_wifi7_dp_rx_h_mpdu(dp_pdev, msdu, rx_info);
+	if (ret)
+		goto free_out;
 
 	rx_info->rx_status->flag |= RX_FLAG_SKIP_MONITOR | RX_FLAG_DUP_VALIDATED;
 
@@ -1033,7 +1050,7 @@ static int ath12k_wifi7_dp_rx_h_verify_tkip_mic(struct ath12k_pdev_dp *dp_pdev,
 
 	ath12k_dp_rx_h_ppdu(dp_pdev, rx_info);
 	ath12k_dp_rx_h_undecap(dp_pdev, msdu, HAL_ENCRYPT_TYPE_TKIP_MIC, true,
-			       rx_info);
+			       rx_info, NULL);
 	ieee80211_rx(ath12k_pdev_dp_to_hw(dp_pdev), msdu);
 	return -EINVAL;
 }
@@ -1588,6 +1605,7 @@ static int ath12k_wifi7_dp_rx_h_null_q_desc(struct ath12k_pdev_dp *dp_pdev,
 	u8 l3pad_bytes = rx_info->l3_pad_bytes;
 	struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu);
 	u32 hal_rx_desc_sz = dp->ab->hal.hal_desc_sz;
+	int ret;
 
 	if (!rxcb->is_frag && ((msdu_len + hal_rx_desc_sz) > DP_RX_BUFFER_SIZE)) {
 		/* First buffer will be freed by the caller, so deduct it's length */
@@ -1632,7 +1650,9 @@ static int ath12k_wifi7_dp_rx_h_null_q_desc(struct ath12k_pdev_dp *dp_pdev,
 		return -EINVAL;
 
 	ath12k_dp_rx_h_ppdu(dp_pdev, rx_info);
-	ath12k_wifi7_dp_rx_h_mpdu(dp_pdev, msdu, rx_info);
+	ret = ath12k_wifi7_dp_rx_h_mpdu(dp_pdev, msdu, rx_info);
+	if (ret)
+		return ret;
 
 	rxcb->tid = rx_info->tid;
 
@@ -1678,7 +1698,7 @@ static bool ath12k_wifi7_dp_rx_h_tkip_mic_err(struct ath12k_pdev_dp *dp_pdev,
 				     RX_FLAG_DECRYPTED);
 
 	ath12k_dp_rx_h_undecap(dp_pdev, msdu, HAL_ENCRYPT_TYPE_TKIP_MIC, false,
-			       rx_info);
+			       rx_info, NULL);
 	return false;
 }
 
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_qcc2072.c b/drivers/net/wireless/ath/ath12k/wifi7/hal_qcc2072.c
index 1eefb931a853..8cebb229ebed 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hal_qcc2072.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_qcc2072.c
@@ -184,6 +184,20 @@ static u8 ath12k_hal_rx_desc_get_l3_pad_bytes_qcc2072(struct hal_rx_desc *desc)
 			     RX_MSDU_END_INFO5_L3_HDR_PADDING);
 }
 
+static inline
+u8 ath12k_wifi7_hal_rx_h_from_ds_qcc2072(struct hal_rx_desc *desc)
+{
+	return le16_get_bits(desc->u.qcc2072.msdu_end.info5,
+			     RX_MSDU_END_INFO5_FROM_DS);
+}
+
+static inline
+u8 ath12k_wifi7_hal_rx_h_to_ds_qcc2072(struct hal_rx_desc *desc)
+{
+	return le16_get_bits(desc->u.qcc2072.msdu_end.info5,
+			     RX_MSDU_END_INFO5_TO_DS);
+}
+
 static u32 ath12k_hal_rx_desc_get_mpdu_start_tag_qcc2072(struct hal_rx_desc *desc)
 {
 	return le32_get_bits(desc->u.qcc2072.mpdu_start_tag,
@@ -397,6 +411,8 @@ static void ath12k_hal_extract_rx_desc_data_qcc2072(struct hal_rx_desc_data *rx_
 	rx_desc_data->seq_no = ath12k_hal_rx_desc_get_mpdu_start_seq_no_qcc2072(rx_desc);
 	rx_desc_data->msdu_len = ath12k_hal_rx_desc_get_msdu_len_qcc2072(ldesc);
 	rx_desc_data->sgi = ath12k_hal_rx_desc_get_msdu_sgi_qcc2072(rx_desc);
+	rx_desc_data->is_from_ds = ath12k_wifi7_hal_rx_h_from_ds_qcc2072(rx_desc);
+	rx_desc_data->is_to_ds = ath12k_wifi7_hal_rx_h_to_ds_qcc2072(rx_desc);
 	rx_desc_data->rate_mcs = ath12k_hal_rx_desc_get_msdu_rate_mcs_qcc2072(rx_desc);
 	rx_desc_data->bw = ath12k_hal_rx_desc_get_msdu_rx_bw_qcc2072(rx_desc);
 	rx_desc_data->phy_meta_data = ath12k_hal_rx_desc_get_msdu_freq_qcc2072(rx_desc);
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.c b/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.c
index ba9ce1e718e8..9d5180ef83b4 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.c
@@ -699,6 +699,20 @@ u8 ath12k_hal_rx_desc_get_mpdu_tid_qcn9274(struct hal_rx_desc *desc)
 			     RX_MSDU_END_INFO5_TID);
 }
 
+static inline
+u8 ath12k_wifi7_hal_rx_h_from_ds_qcn9274(struct hal_rx_desc *desc)
+{
+	return le16_get_bits(desc->u.qcn9274_compact.msdu_end.info5,
+			     RX_MSDU_END_INFO5_FROM_DS);
+}
+
+static inline
+u8 ath12k_wifi7_hal_rx_h_to_ds_qcn9274(struct hal_rx_desc *desc)
+{
+	return le16_get_bits(desc->u.qcn9274_compact.msdu_end.info5,
+			     RX_MSDU_END_INFO5_TO_DS);
+}
+
 static inline
 u16 ath12k_hal_rx_desc_get_mpdu_peer_id_qcn9274(struct hal_rx_desc *desc)
 {
@@ -914,6 +928,8 @@ void ath12k_hal_extract_rx_desc_data_qcn9274(struct hal_rx_desc_data *rx_desc_da
 	rx_desc_data->seq_ctl_valid =
 		ath12k_hal_rx_desc_get_mpdu_seq_ctl_vld_qcn9274(rx_desc);
 	rx_desc_data->fc_valid = ath12k_hal_rx_desc_get_mpdu_fc_valid_qcn9274(rx_desc);
+	rx_desc_data->is_from_ds = ath12k_wifi7_hal_rx_h_from_ds_qcn9274(rx_desc);
+	rx_desc_data->is_to_ds = ath12k_wifi7_hal_rx_h_to_ds_qcn9274(rx_desc);
 	rx_desc_data->seq_no = ath12k_hal_rx_desc_get_mpdu_start_seq_no_qcn9274(rx_desc);
 	rx_desc_data->msdu_len = ath12k_hal_rx_desc_get_msdu_len_qcn9274(ldesc);
 	rx_desc_data->sgi = ath12k_hal_rx_desc_get_msdu_sgi_qcn9274(rx_desc);
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_wcn7850.c b/drivers/net/wireless/ath/ath12k/wifi7/hal_wcn7850.c
index e64e512cac7d..efbbc1cbd3e4 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hal_wcn7850.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_wcn7850.c
@@ -280,6 +280,20 @@ u8 ath12k_hal_rx_desc_get_l3_pad_bytes_wcn7850(struct hal_rx_desc *desc)
 			    RX_MSDU_END_INFO5_L3_HDR_PADDING);
 }
 
+static inline
+u8 ath12k_wifi7_hal_rx_h_from_ds_wcn7850(struct hal_rx_desc *desc)
+{
+	return le16_get_bits(desc->u.wcn7850.msdu_end.info5,
+			     RX_MSDU_END_INFO5_FROM_DS);
+}
+
+static inline
+u8 ath12k_wifi7_hal_rx_h_to_ds_wcn7850(struct hal_rx_desc *desc)
+{
+	return le16_get_bits(desc->u.wcn7850.msdu_end.info5,
+			     RX_MSDU_END_INFO5_TO_DS);
+}
+
 static inline
 bool ath12k_hal_rx_desc_encrypt_valid_wcn7850(struct hal_rx_desc *desc)
 {
@@ -599,6 +613,8 @@ void ath12k_hal_extract_rx_desc_data_wcn7850(struct hal_rx_desc_data *rx_desc_da
 	rx_desc_data->seq_no = ath12k_hal_rx_desc_get_mpdu_start_seq_no_wcn7850(rx_desc);
 	rx_desc_data->msdu_len = ath12k_hal_rx_desc_get_msdu_len_wcn7850(ldesc);
 	rx_desc_data->sgi = ath12k_hal_rx_desc_get_msdu_sgi_wcn7850(rx_desc);
+	rx_desc_data->is_from_ds = ath12k_wifi7_hal_rx_h_from_ds_wcn7850(rx_desc);
+	rx_desc_data->is_to_ds = ath12k_wifi7_hal_rx_h_to_ds_wcn7850(rx_desc);
 	rx_desc_data->rate_mcs = ath12k_hal_rx_desc_get_msdu_rate_mcs_wcn7850(rx_desc);
 	rx_desc_data->bw = ath12k_hal_rx_desc_get_msdu_rx_bw_wcn7850(rx_desc);
 	rx_desc_data->phy_meta_data = ath12k_hal_rx_desc_get_msdu_freq_wcn7850(rx_desc);
-- 
2.34.1


^ permalink raw reply related

* [PATCH ath-next 4/6] wifi: ath12k: Add support for 4-address NULL frame handling
From: Tamizh Chelvam Raja @ 2026-05-25 11:09 UTC (permalink / raw)
  To: ath12k; +Cc: linux-wireless, Tamizh Chelvam Raja, Sarika Sharma
In-Reply-To: <20260525110942.2890212-1-tamizh.raja@oss.qualcomm.com>

Currently, the firmware processes all NULL frames internally and
does not forward them to the host. As a result, the host never
receives 4-address NULL frames sent by a 4-address station.
These 4-address NULL frames are sent by the station to indicate
to the AP that it is operating in 4-address mode.

Enable WMI_RSRC_CFG_FLAGS2_WDS_NULL_FRAME_SUPPORT flag during WMI
initialization after verifying the WMI_SERVICE_WDS_NULL_FRAME_SUPPORT
service capability. This enables the firmware to forward all NULL frames
to the host. Add host-side handling to parse 4-address NULL frames and
forward them to mac80211 to support proper AP_VLAN interface creation.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1

Co-developed-by: Sarika Sharma <sarika.sharma@oss.qualcomm.com>
Signed-off-by: Sarika Sharma <sarika.sharma@oss.qualcomm.com>
Signed-off-by: Tamizh Chelvam Raja <tamizh.raja@oss.qualcomm.com>
---
 drivers/net/wireless/ath/ath12k/peer.c |  7 ++--
 drivers/net/wireless/ath/ath12k/wmi.c  | 44 ++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h  |  3 ++
 3 files changed, 50 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/peer.c b/drivers/net/wireless/ath/ath12k/peer.c
index f7f0f613b393..b5a0ba149a28 100644
--- a/drivers/net/wireless/ath/ath12k/peer.c
+++ b/drivers/net/wireless/ath/ath12k/peer.c
@@ -220,10 +220,9 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
 					  ahsta->link[link_id]);
 		/* TODO: Split DP related field usage to DP peer structure */
 		arsta->tcl_metadata = u16_encode_bits(0, HTT_TCL_META_DATA_TYPE) |
-				       u16_encode_bits(peer->peer_id,
-						       HTT_TCL_META_DATA_PEER_ID) |
-				       u16_encode_bits(0,
-						       HTT_TCL_META_DATA_VALID_HTT);
+				      u16_encode_bits(peer->peer_id,
+						      HTT_TCL_META_DATA_PEER_ID) |
+				      u16_encode_bits(0, HTT_TCL_META_DATA_VALID_HTT);
 		arsta->ast_hash = peer->ast_hash;
 		arsta->ast_idx = peer->hw_peer_id;
 		peer->link_id = arsta->link_id;
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index eaed1c4ddd55..ffe51adcd12c 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -4194,6 +4194,10 @@ ath12k_wmi_copy_resource_config(struct ath12k_base *ab,
 	wmi_cfg->ema_max_profile_period = cpu_to_le32(tg_cfg->ema_max_profile_period);
 	wmi_cfg->flags2 |= cpu_to_le32(WMI_RSRC_CFG_FLAGS2_CALC_NEXT_DTIM_COUNT_SET |
 				       WMI_RSRC_CFG_FLAGS2_FW_AST_INDICATION_DISABLE);
+
+	if (tg_cfg->is_wds_null_frame_supported)
+		wmi_cfg->flags2 |=
+			cpu_to_le32(WMI_RSRC_CFG_FLAGS2_WDS_NULL_FRAME_SUPPORT);
 }
 
 static int ath12k_init_cmd_send(struct ath12k_wmi_pdev *wmi,
@@ -4403,6 +4407,9 @@ int ath12k_wmi_cmd_init(struct ath12k_base *ab)
 		     ab->wmi_ab.svc_map))
 		arg.res_cfg.is_reg_cc_ext_event_supported = true;
 
+	if (test_bit(WMI_TLV_SERVICE_WDS_NULL_FRAME_SUPPORT, ab->wmi_ab.svc_map))
+		arg.res_cfg.is_wds_null_frame_supported = true;
+
 	ab->hw_params->wmi_init(ab, &arg.res_cfg);
 	ab->wow.wmi_conf_rx_decap_mode = arg.res_cfg.rx_decap_mode;
 
@@ -7224,7 +7231,11 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb)
 	struct ath12k_wmi_mgmt_rx_arg rx_ev = {};
 	struct ath12k *ar;
 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+	struct ieee80211_sta *pubsta = NULL;
+	struct ath12k_dp_link_peer *peer;
 	struct ieee80211_hdr *hdr;
+	bool is_4addr_null_pkt;
+	struct ath12k_dp *dp;
 	u16 fc;
 	struct ieee80211_supported_band *sband;
 	s32 noise_floor;
@@ -7299,6 +7310,38 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb)
 	hdr = (struct ieee80211_hdr *)skb->data;
 	fc = le16_to_cpu(hdr->frame_control);
 
+	is_4addr_null_pkt = (ieee80211_is_nullfunc(hdr->frame_control) ||
+			     ieee80211_is_qos_nullfunc(hdr->frame_control)) &&
+			    ieee80211_has_a4(hdr->frame_control);
+
+	/*
+	 * Add check to drop frames other than 4-address NULL frame. Since
+	 * firmware sends all NULL frames in this path (3-address and 4-address)
+	 */
+	if (ieee80211_is_data(hdr->frame_control) && !is_4addr_null_pkt) {
+		dev_kfree_skb(skb);
+		goto exit;
+	}
+
+	if (is_4addr_null_pkt) {
+		dp = ath12k_ab_to_dp(ar->ab);
+		spin_lock_bh(&dp->dp_lock);
+		peer = ath12k_dp_link_peer_find_by_pdev_and_addr(dp, ar->pdev_idx,
+								 hdr->addr2);
+		if (!peer) {
+			spin_unlock_bh(&dp->dp_lock);
+			dev_kfree_skb(skb);
+			goto exit;
+		}
+		pubsta = peer->sta;
+		if (pubsta && pubsta->valid_links) {
+			status->link_valid = 1;
+			status->link_id = peer->link_id;
+		}
+		spin_unlock_bh(&dp->dp_lock);
+		goto send_rx;
+	}
+
 	/* Firmware is guaranteed to report all essential management frames via
 	 * WMI while it can deliver some extra via HTT. Since there can be
 	 * duplicates split the reporting wrt monitor/sniffing.
@@ -7322,6 +7365,7 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb)
 	if (ieee80211_is_beacon(hdr->frame_control))
 		ath12k_mac_handle_beacon(ar, skb);
 
+send_rx:
 	ath12k_dbg(ab, ATH12K_DBG_MGMT,
 		   "event mgmt rx skb %p len %d ftype %02x stype %02x\n",
 		   skb, skb->len,
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 13d82f706d79..c452e3d57a29 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -2278,6 +2278,7 @@ enum wmi_tlv_service {
 
 	WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT = 365,
 	WMI_TLV_SERVICE_THERM_THROT_POUT_REDUCTION = 410,
+	WMI_TLV_SERVICE_WDS_NULL_FRAME_SUPPORT = 421,
 	WMI_TLV_SERVICE_IS_TARGET_IPA = 425,
 	WMI_TLV_SERVICE_THERM_THROT_TX_CHAIN_MASK = 426,
 	WMI_TLV_SERVICE_THERM_THROT_5_LEVELS = 429,
@@ -2511,6 +2512,7 @@ struct ath12k_wmi_resource_config_arg {
 	u32 ema_max_vap_cnt;
 	u32 ema_max_profile_period;
 	bool is_reg_cc_ext_event_supported;
+	bool is_wds_null_frame_supported;
 };
 
 struct ath12k_wmi_init_cmd_arg {
@@ -2568,6 +2570,7 @@ struct wmi_init_cmd {
 #define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64	BIT(5)
 #define WMI_RSRC_CFG_FLAGS2_CALC_NEXT_DTIM_COUNT_SET      BIT(9)
 #define WMI_RSRC_CFG_FLAGS2_FW_AST_INDICATION_DISABLE	BIT(18)
+#define WMI_RSRC_CFG_FLAGS2_WDS_NULL_FRAME_SUPPORT		BIT(22)
 #define WMI_RSRC_CFG_FLAG1_ACK_RSSI	BIT(18)
 
 struct ath12k_wmi_resource_config_params {
-- 
2.34.1


^ permalink raw reply related

* [PATCH ath-next 3/6] wifi: ath12k: Add 4-address mode support for eth offload
From: Tamizh Chelvam Raja @ 2026-05-25 11:09 UTC (permalink / raw)
  To: ath12k; +Cc: linux-wireless, Tamizh Chelvam Raja
In-Reply-To: <20260525110942.2890212-1-tamizh.raja@oss.qualcomm.com>

Currently driver does not enable the hardware/firmware support for handling
4-address multicast frames in the Tx/Rx path when 8023_ENCAP_OFFLOAD is
enabled. Add the required support to ensure correct processing of multicast
traffic in 4-address mode.

Enable this functionality by setting the WMI_VDEV_PARAM_AP_ENABLE_NAWDS
vdev parameter when the 8023_ENCAP_OFFLOAD feature is active. Override
peer metadata values for 4-address multicast packet transmission by using
the station's ast_hash and ast_idx instead of vdev-level metadata,
and set HAL_TCL_DATA_CMD_INFO4_IDX_LOOKUP_OVERRIDE to indicate this
override.

Suppress firmware peer-map events for 4-address frames by setting the
WMI_RSRC_CFG_FLAGS2_FW_AST_INDICATION_DISABLE flag during WMI
initialization. This prevents inconsistencies in the host's peer list.

Add the IEEE80211_OFFLOAD_ENCAP_4ADDR VIF offload flag to notify mac80211
that 4-address Ethernet encapsulation offload is supported.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1

Signed-off-by: Tamizh Chelvam Raja <tamizh.raja@oss.qualcomm.com>
---
 drivers/net/wireless/ath/ath12k/core.h        |  3 ++
 drivers/net/wireless/ath/ath12k/mac.c         | 28 ++++++++++++---
 drivers/net/wireless/ath/ath12k/peer.c        |  2 ++
 drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c | 35 +++++++++++++++----
 .../net/wireless/ath/ath12k/wifi7/hal_tx.c    |  4 ++-
 .../net/wireless/ath/ath12k/wifi7/hal_tx.h    |  1 +
 drivers/net/wireless/ath/ath12k/wmi.c         |  3 +-
 drivers/net/wireless/ath/ath12k/wmi.h         |  9 +++++
 8 files changed, 72 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 70ad9742c21d..fc5127b5c1a3 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -355,6 +355,7 @@ struct ath12k_link_vif {
 	struct wiphy_work bcn_tx_work;
 
 	bool set_wds_vdev_param;
+	bool nawds_enabled;
 };
 
 struct ath12k_vif {
@@ -495,6 +496,8 @@ struct ath12k_link_sta {
 	u8 addr[ETH_ALEN];
 
 	u16 tcl_metadata;
+	u16 ast_hash;
+	u16 ast_idx;
 
 	/* the following are protected by ar->data_lock */
 	u32 changed; /* IEEE80211_RC_* */
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 0105a1fc7929..2f437ecae84d 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -6572,6 +6572,7 @@ static int ath12k_mac_sta_set_4addr(struct wiphy *wiphy, struct ath12k_sta *ahst
 	struct ath12k_dp_link_peer *peer;
 	struct ath12k_link_vif *arvif;
 	struct ath12k_link_sta *arsta;
+	struct ath12k_vif *ahvif;
 	struct ath12k_dp *dp;
 	unsigned long links;
 	struct ath12k *ar;
@@ -6585,10 +6586,11 @@ static int ath12k_mac_sta_set_4addr(struct wiphy *wiphy, struct ath12k_sta *ahst
 			continue;
 
 		arvif = arsta->arvif;
+		ahvif = arvif->ahvif;
 		ar = arvif->ar;
 
 		if (arvif->set_wds_vdev_param)
-			goto skip_use_4addr;
+			goto skip_nawds;
 
 		ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
 			   "setting USE_4ADDR for peer %pM\n", arsta->addr);
@@ -6603,7 +6605,21 @@ static int ath12k_mac_sta_set_4addr(struct wiphy *wiphy, struct ath12k_sta *ahst
 			return ret;
 		}
 
-skip_use_4addr:
+		if (ahvif->dp_vif.tx_encap_type != ATH12K_HW_TXRX_ETHERNET)
+			goto skip_nawds;
+
+		ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+						    WMI_VDEV_PARAM_AP_ENABLE_NAWDS,
+						    WDS_EXT_ENABLE);
+		if (ret) {
+			ath12k_warn(ar->ab, "failed to set vdev %d nawds parameter: %d\n",
+				    arvif->vdev_id, ret);
+			return ret;
+		}
+
+		arvif->nawds_enabled = true;
+
+skip_nawds:
 		dp = ath12k_ab_to_dp(ar->ab);
 		spin_lock_bh(&dp->dp_lock);
 		peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, arvif->vdev_id,
@@ -10094,12 +10110,14 @@ static void ath12k_mac_update_vif_offload(struct ath12k_link_vif *arvif)
 		vif->offload_flags &= ~(IEEE80211_OFFLOAD_ENCAP_ENABLED |
 					IEEE80211_OFFLOAD_DECAP_ENABLED);
 
-	if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED)
+	if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) {
 		ahvif->dp_vif.tx_encap_type = ATH12K_HW_TXRX_ETHERNET;
-	else if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags))
+		vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR;
+	} else if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) {
 		ahvif->dp_vif.tx_encap_type = ATH12K_HW_TXRX_RAW;
-	else
+	} else {
 		ahvif->dp_vif.tx_encap_type = ATH12K_HW_TXRX_NATIVE_WIFI;
+	}
 
 	ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
 					    param_id, ahvif->dp_vif.tx_encap_type);
diff --git a/drivers/net/wireless/ath/ath12k/peer.c b/drivers/net/wireless/ath/ath12k/peer.c
index 42488b465540..f7f0f613b393 100644
--- a/drivers/net/wireless/ath/ath12k/peer.c
+++ b/drivers/net/wireless/ath/ath12k/peer.c
@@ -224,6 +224,8 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
 						       HTT_TCL_META_DATA_PEER_ID) |
 				       u16_encode_bits(0,
 						       HTT_TCL_META_DATA_VALID_HTT);
+		arsta->ast_hash = peer->ast_hash;
+		arsta->ast_idx = peer->hw_peer_id;
 		peer->link_id = arsta->link_id;
 
 		/* Fill ML info into created peer */
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c
index 5f298133dee9..d2749de44553 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c
@@ -57,6 +57,8 @@ static int ath12k_wifi7_dp_prepare_htt_metadata(struct sk_buff *skb)
 	return 0;
 }
 
+#define ATH12K_AST_HASH_MASK	0xF
+
 /* TODO: Remove the export once this file is built with wifi7 ko */
 int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *arvif,
 		       struct ath12k_link_sta *arsta, struct sk_buff *skb,
@@ -78,6 +80,7 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a
 	struct ath12k_dp_vif *dp_vif = &ahvif->dp_vif;
 	struct ath12k_dp_link_vif *dp_link_vif;
 	struct dp_tx_ring *tx_ring;
+	struct ethhdr *eth = NULL;
 	u8 pool_id;
 	u8 hal_ring_id;
 	int ret;
@@ -96,6 +99,9 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a
 	    !ieee80211_is_data(hdr->frame_control))
 		return -EOPNOTSUPP;
 
+	if (skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP)
+		eth = (struct ethhdr *)skb->data;
+
 	pool_id = skb_get_queue_mapping(skb) & (ATH12K_HW_MAX_QUEUES - 1);
 
 	/* Let the default ring selection be based on current processor
@@ -124,9 +130,16 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a
 
 	ti.bank_id = dp_link_vif->bank_id;
 	ti.meta_data_flags = dp_link_vif->tcl_metadata;
+	ti.bss_ast_hash = dp_link_vif->ast_hash;
+	ti.bss_ast_idx = dp_link_vif->ast_idx;
 
-	if (ieee80211_has_a4(hdr->frame_control) &&
-	    is_multicast_ether_addr(hdr->addr3) && arsta) {
+	if (eth && is_multicast_ether_addr(eth->h_dest) && arsta) {
+		ti.meta_data_flags = arsta->tcl_metadata;
+		ti.bss_ast_hash = arsta->ast_hash & ATH12K_AST_HASH_MASK;
+		ti.bss_ast_idx = arsta->ast_idx;
+		ti.lookup_override = true;
+	} else if (!eth && ieee80211_has_a4(hdr->frame_control) &&
+		   is_multicast_ether_addr(hdr->addr3) && arsta) {
 		ti.meta_data_flags = arsta->tcl_metadata;
 		ti.flags0 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TO_FW);
 	}
@@ -146,7 +159,7 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a
 		msdu_ext_desc = true;
 	}
 
-	if (gsn_valid) {
+	if (gsn_valid && !ti.lookup_override) {
 		/* Reset and Initialize meta_data_flags with Global Sequence
 		 * Number (GSN) info.
 		 */
@@ -154,6 +167,14 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a
 			u32_encode_bits(HTT_TCL_META_DATA_TYPE_GLOBAL_SEQ_NUM,
 					HTT_TCL_META_DATA_TYPE) |
 			u32_encode_bits(mcbc_gsn, HTT_TCL_META_DATA_GLOBAL_SEQ_NUM);
+
+		/*
+		 * Since NAWDS enabled for this vdev firmware expects
+		 * this flag to be set for sending 3-address multicast frame.
+		 */
+		ti.meta_data_flags |=
+			u32_encode_bits(arvif->nawds_enabled,
+					HTT_TCL_META_DATA_GLOBAL_SEQ_HOST_INSPECTED);
 	}
 
 	ti.encap_type = ath12k_dp_tx_get_encap_type(ab, skb);
@@ -164,11 +185,13 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a
 	ti.lmac_id = dp_link_vif->lmac_id;
 
 	ti.vdev_id = dp_link_vif->vdev_id;
-	if (gsn_valid)
+
+	if (gsn_valid && !ti.lookup_override)
 		ti.vdev_id += HTT_TX_MLO_MCAST_HOST_REINJECT_BASE_VDEV_ID;
+	else if (arvif->nawds_enabled && is_mcast && !ti.lookup_override)
+		ti.meta_data_flags |=
+			u32_encode_bits(1, HTT_TCL_META_DATA_HOST_INSPECTED_MISSION);
 
-	ti.bss_ast_hash = dp_link_vif->ast_hash;
-	ti.bss_ast_idx = dp_link_vif->ast_idx;
 	ti.dscp_tid_tbl_idx = 0;
 
 	if (skb->ip_summed == CHECKSUM_PARTIAL &&
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.c b/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.c
index 02d3cadf03fe..eeabe9db776e 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.c
@@ -59,7 +59,9 @@ void ath12k_wifi7_hal_tx_cmd_desc_setup(struct ath12k_base *ab,
 		le32_encode_bits(ti->lmac_id, HAL_TCL_DATA_CMD_INFO3_PMAC_ID) |
 		le32_encode_bits(ti->vdev_id, HAL_TCL_DATA_CMD_INFO3_VDEV_ID);
 
-	tcl_cmd->info4 = le32_encode_bits(ti->bss_ast_idx,
+	tcl_cmd->info4 = le32_encode_bits(ti->lookup_override,
+					  HAL_TCL_DATA_CMD_INFO4_IDX_LOOKUP_OVERRIDE) |
+			 le32_encode_bits(ti->bss_ast_idx,
 					  HAL_TCL_DATA_CMD_INFO4_SEARCH_INDEX) |
 			 le32_encode_bits(ti->bss_ast_hash,
 					  HAL_TCL_DATA_CMD_INFO4_CACHE_SET_NUM);
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.h b/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.h
index 9d2b1552c2f5..c548a0fbf1bb 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.h
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.h
@@ -34,6 +34,7 @@ struct hal_tx_info {
 	u8 dscp_tid_tbl_idx;
 	bool enable_mesh;
 	int bank_id;
+	bool lookup_override;
 };
 
 /* TODO: Check if the actual desc macros can be used instead */
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 25e61cc7e5ac..eaed1c4ddd55 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -4192,7 +4192,8 @@ ath12k_wmi_copy_resource_config(struct ath12k_base *ab,
 			cpu_to_le32(1 << WMI_RSRC_CFG_HOST_SVC_FLAG_REO_QREF_SUPPORT_BIT);
 	wmi_cfg->ema_max_vap_cnt = cpu_to_le32(tg_cfg->ema_max_vap_cnt);
 	wmi_cfg->ema_max_profile_period = cpu_to_le32(tg_cfg->ema_max_profile_period);
-	wmi_cfg->flags2 |= cpu_to_le32(WMI_RSRC_CFG_FLAGS2_CALC_NEXT_DTIM_COUNT_SET);
+	wmi_cfg->flags2 |= cpu_to_le32(WMI_RSRC_CFG_FLAGS2_CALC_NEXT_DTIM_COUNT_SET |
+				       WMI_RSRC_CFG_FLAGS2_FW_AST_INDICATION_DISABLE);
 }
 
 static int ath12k_init_cmd_send(struct ath12k_wmi_pdev *wmi,
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index a827b3c99f8f..13d82f706d79 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -2334,6 +2334,14 @@ enum wmi_preamble {
 	WMI_VDEV_PREAMBLE_SHORT = 2,
 };
 
+/*
+ * This will be used to set for  WMI_VDEV_PARAM_AP_ENABLE_NAWDS
+ * whenever 4addr station connects in wds offload case.
+ * This is for enabling multicast to unicast conversion support in
+ * firmware
+ */
+#define WDS_EXT_ENABLE 1
+
 enum wmi_peer_4addr_allow_frame {
 	WMI_PEER_4ADDR_ALLOW_DATA_FRAME = 1,
 	WMI_PEER_4ADDR_ALLOW_EAPOL_DATA_FRAME = 2,
@@ -2559,6 +2567,7 @@ struct wmi_init_cmd {
 #define WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION		GENMASK(5, 4)
 #define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64	BIT(5)
 #define WMI_RSRC_CFG_FLAGS2_CALC_NEXT_DTIM_COUNT_SET      BIT(9)
+#define WMI_RSRC_CFG_FLAGS2_FW_AST_INDICATION_DISABLE	BIT(18)
 #define WMI_RSRC_CFG_FLAG1_ACK_RSSI	BIT(18)
 
 struct ath12k_wmi_resource_config_params {
-- 
2.34.1


^ permalink raw reply related

* [PATCH ath-next 2/6] wifi: ath12k: Add support for 4-address mode
From: Tamizh Chelvam Raja @ 2026-05-25 11:09 UTC (permalink / raw)
  To: ath12k; +Cc: linux-wireless, Tamizh Chelvam Raja
In-Reply-To: <20260525110942.2890212-1-tamizh.raja@oss.qualcomm.com>

The current driver does not support enabling 4-address mode data traffic
in WDS mode. Add the required functionality by introducing the
sta_set_4addr() API, which is invoked when a 4-address AP/STA connects.
This API sends the WMI_PEER_USE_4ADDR peer parameter to notify firmware
about the 4-address peer, allowing firmware and hardware to transmit
and receive frames in 4-address format for that peer.

For 4-address multicast packet transmission, update the handling
to set peer metadata values in HAL_TCL_DATA_CMD_INFO1_CMD_NUM instead
of using vdev metadata values. Vdev metadata is used only for 3-address
and 4-address unicast traffic and for 3-address multicast traffic.
The peer metadata path embeds the correct peer_id, enabling proper
multicast transmission in 4-address mode.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1

Signed-off-by: Tamizh Chelvam Raja <tamizh.raja@oss.qualcomm.com>
---
 drivers/net/wireless/ath/ath12k/core.h        |  6 ++
 drivers/net/wireless/ath/ath12k/mac.c         | 79 +++++++++++++++++++
 drivers/net/wireless/ath/ath12k/mac.h         |  3 +
 drivers/net/wireless/ath/ath12k/peer.c        |  7 +-
 drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c | 10 ++-
 drivers/net/wireless/ath/ath12k/wifi7/dp_tx.h |  4 +-
 drivers/net/wireless/ath/ath12k/wifi7/hw.c    | 18 ++++-
 drivers/net/wireless/ath/ath12k/wmi.h         |  5 ++
 8 files changed, 125 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index f6d8ec9ef7b0..70ad9742c21d 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -353,6 +353,8 @@ struct ath12k_link_vif {
 	u16 num_stations;
 	bool is_csa_in_progress;
 	struct wiphy_work bcn_tx_work;
+
+	bool set_wds_vdev_param;
 };
 
 struct ath12k_vif {
@@ -492,6 +494,8 @@ struct ath12k_link_sta {
 	/* link address similar to ieee80211_link_sta */
 	u8 addr[ETH_ALEN];
 
+	u16 tcl_metadata;
+
 	/* the following are protected by ar->data_lock */
 	u32 changed; /* IEEE80211_RC_* */
 	u32 bw;
@@ -527,6 +531,8 @@ struct ath12k_sta {
 	u16 free_logical_link_idx_map;
 
 	enum ieee80211_sta_state state;
+
+	bool enable_4addr;
 };
 
 #define ATH12K_HALF_20MHZ_BW	10
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 2d02a6a8d54f..0105a1fc7929 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -6567,6 +6567,62 @@ static int ath12k_mac_station_disassoc(struct ath12k *ar,
 	return 0;
 }
 
+static int ath12k_mac_sta_set_4addr(struct wiphy *wiphy, struct ath12k_sta *ahsta)
+{
+	struct ath12k_dp_link_peer *peer;
+	struct ath12k_link_vif *arvif;
+	struct ath12k_link_sta *arsta;
+	struct ath12k_dp *dp;
+	unsigned long links;
+	struct ath12k *ar;
+	u8 link_id;
+	int ret;
+
+	links = ahsta->links_map;
+	for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
+		arsta = wiphy_dereference(wiphy, ahsta->link[link_id]);
+		if (!arsta)
+			continue;
+
+		arvif = arsta->arvif;
+		ar = arvif->ar;
+
+		if (arvif->set_wds_vdev_param)
+			goto skip_use_4addr;
+
+		ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
+			   "setting USE_4ADDR for peer %pM\n", arsta->addr);
+
+		ret = ath12k_wmi_set_peer_param(ar, arsta->addr,
+						arvif->vdev_id,
+						WMI_PEER_USE_4ADDR,
+						WMI_PEER_4ADDR_ALLOW_EAPOL_DATA_FRAME);
+		if (ret) {
+			ath12k_warn(ar->ab, "failed to set peer %pM 4addr capability: %d\n",
+				    arsta->addr, ret);
+			return ret;
+		}
+
+skip_use_4addr:
+		dp = ath12k_ab_to_dp(ar->ab);
+		spin_lock_bh(&dp->dp_lock);
+		peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, arvif->vdev_id,
+								 arsta->addr);
+		if (peer && peer->dp_peer) {
+			peer->dp_peer->ucast_ra_only = true;
+		} else {
+			spin_unlock_bh(&dp->dp_lock);
+			ath12k_warn(ar->ab, "failed to find DP peer for %pM\n",
+				    arsta->addr);
+			return -ENOENT;
+		}
+
+		spin_unlock_bh(&dp->dp_lock);
+	}
+
+	return 0;
+}
+
 static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk)
 {
 	struct ieee80211_link_sta *link_sta;
@@ -7861,6 +7917,28 @@ int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw,
 }
 EXPORT_SYMBOL(ath12k_mac_op_sta_set_txpwr);
 
+void ath12k_mac_op_sta_set_4addr(struct ieee80211_hw *hw,
+				 struct ieee80211_vif *vif,
+				 struct ieee80211_sta *sta, bool enabled)
+{
+	struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta);
+
+	lockdep_assert_wiphy(hw->wiphy);
+
+	/*
+	 * 4-address mode disabled option is available only for station
+	 * interface from mac80211, and we have wds_vdev_param for station
+	 * interface and target will not allow to disable the wds_vdev_param
+	 * during run time. So, add support only for enable case, for
+	 * disable case station interface needs to be reconnect.
+	 */
+	if (enabled && !ahsta->enable_4addr) {
+		if (!ath12k_mac_sta_set_4addr(hw->wiphy, ahsta))
+			ahsta->enable_4addr = true;
+	}
+}
+EXPORT_SYMBOL(ath12k_mac_op_sta_set_4addr);
+
 void ath12k_mac_op_link_sta_rc_update(struct ieee80211_hw *hw,
 				      struct ieee80211_vif *vif,
 				      struct ieee80211_link_sta *link_sta,
@@ -10417,6 +10495,7 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif)
 					    ret);
 				goto err_peer_del;
 			}
+			arvif->set_wds_vdev_param = true;
 		}
 
 		if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ab->wmi_ab.svc_map) &&
diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
index 7b50c5976384..aba98afd4365 100644
--- a/drivers/net/wireless/ath/ath12k/mac.h
+++ b/drivers/net/wireless/ath/ath12k/mac.h
@@ -255,6 +255,9 @@ int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
 int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw,
 				struct ieee80211_vif *vif,
 				struct ieee80211_sta *sta);
+void ath12k_mac_op_sta_set_4addr(struct ieee80211_hw *hw,
+				 struct ieee80211_vif *vif,
+				 struct ieee80211_sta *sta, bool enabled);
 void ath12k_mac_op_link_sta_rc_update(struct ieee80211_hw *hw,
 				      struct ieee80211_vif *vif,
 				      struct ieee80211_link_sta *link_sta,
diff --git a/drivers/net/wireless/ath/ath12k/peer.c b/drivers/net/wireless/ath/ath12k/peer.c
index 2e875176baaa..42488b465540 100644
--- a/drivers/net/wireless/ath/ath12k/peer.c
+++ b/drivers/net/wireless/ath/ath12k/peer.c
@@ -218,7 +218,12 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
 		ahsta = ath12k_sta_to_ahsta(sta);
 		arsta = wiphy_dereference(ath12k_ar_to_hw(ar)->wiphy,
 					  ahsta->link[link_id]);
-
+		/* TODO: Split DP related field usage to DP peer structure */
+		arsta->tcl_metadata = u16_encode_bits(0, HTT_TCL_META_DATA_TYPE) |
+				       u16_encode_bits(peer->peer_id,
+						       HTT_TCL_META_DATA_PEER_ID) |
+				       u16_encode_bits(0,
+						       HTT_TCL_META_DATA_VALID_HTT);
 		peer->link_id = arsta->link_id;
 
 		/* Fill ML info into created peer */
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c
index 629084aa36d8..5f298133dee9 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c
@@ -59,8 +59,8 @@ static int ath12k_wifi7_dp_prepare_htt_metadata(struct sk_buff *skb)
 
 /* TODO: Remove the export once this file is built with wifi7 ko */
 int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *arvif,
-		       struct sk_buff *skb, bool gsn_valid, int mcbc_gsn,
-		       bool is_mcast)
+		       struct ath12k_link_sta *arsta, struct sk_buff *skb,
+		       bool gsn_valid, int mcbc_gsn, bool is_mcast)
 {
 	struct ath12k_dp *dp = dp_pdev->dp;
 	struct ath12k_hal *hal = dp->hal;
@@ -125,6 +125,12 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a
 	ti.bank_id = dp_link_vif->bank_id;
 	ti.meta_data_flags = dp_link_vif->tcl_metadata;
 
+	if (ieee80211_has_a4(hdr->frame_control) &&
+	    is_multicast_ether_addr(hdr->addr3) && arsta) {
+		ti.meta_data_flags = arsta->tcl_metadata;
+		ti.flags0 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TO_FW);
+	}
+
 	if (dp_vif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW &&
 	    test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags)) {
 		if (skb_cb->flags & ATH12K_SKB_CIPHER_SET) {
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.h b/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.h
index 24cf7972d41b..86bc813878c0 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.h
+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.h
@@ -8,8 +8,8 @@
 #define ATH12K_DP_TX_WIFI7_H
 
 int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *arvif,
-		       struct sk_buff *skb, bool gsn_valid, int mcbc_gsn,
-		       bool is_mcast);
+		       struct ath12k_link_sta *arsta, struct sk_buff *skb,
+		       bool gsn_valid, int mcbc_gsn, bool is_mcast);
 void ath12k_wifi7_dp_tx_completion_handler(struct ath12k_dp *dp, int ring_id);
 u32 ath12k_wifi7_dp_tx_get_vdev_bank_config(struct ath12k_base *ab,
 					    struct ath12k_link_vif *arvif);
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hw.c b/drivers/net/wireless/ath/ath12k/wifi7/hw.c
index cb3185850439..06ab5b46b47d 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hw.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hw.c
@@ -859,7 +859,9 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct ieee80211_key_conf *key = info->control.hw_key;
 	struct ieee80211_sta *sta = control->sta;
+	struct ath12k_link_sta *arsta = NULL;
 	struct ath12k_link_vif *tmp_arvif;
+	struct ath12k_sta *ahsta = NULL;
 	u32 info_flags = info->flags;
 	struct sk_buff *msdu_copied;
 	struct ath12k *ar, *tmp_ar;
@@ -941,6 +943,12 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
 	if (!(info_flags & IEEE80211_TX_CTL_HW_80211_ENCAP))
 		is_mcast = is_multicast_ether_addr(hdr->addr1);
 
+	if (sta) {
+		ahsta = ath12k_sta_to_ahsta(control->sta);
+		if (ahsta && ahsta->enable_4addr)
+			arsta = rcu_dereference(ahsta->link[link_id]);
+	}
+
 	/* This is case only for P2P_GO */
 	if (vif->type == NL80211_IFTYPE_AP && vif->p2p)
 		ath12k_mac_add_p2p_noa_ie(ar, vif, skb, is_prb_rsp);
@@ -961,7 +969,7 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
 	if (!vif->valid_links || !is_mcast || is_dvlan ||
 	    (skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) ||
 	    test_bit(ATH12K_FLAG_RAW_MODE, &ar->ab->dev_flags)) {
-		ret = ath12k_wifi7_dp_tx(dp_pdev, arvif, skb, false, 0, is_mcast);
+		ret = ath12k_wifi7_dp_tx(dp_pdev, arvif, arsta, skb, false, 0, is_mcast);
 		if (unlikely(ret)) {
 			ath12k_warn(ar->ab, "failed to transmit frame %d\n", ret);
 			ieee80211_free_txskb(ar->ah->hw, skb);
@@ -999,6 +1007,11 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
 			skb_cb->vif = vif;
 			skb_cb->ar = tmp_ar;
 
+			if (ahsta && ahsta->enable_4addr)
+				arsta = rcu_dereference(ahsta->link[link_id]);
+			else
+				arsta = NULL;
+
 			/* For open mode, skip peer find logic */
 			if (unlikely(!ahvif->dp_vif.key_cipher))
 				goto skip_peer_find;
@@ -1030,7 +1043,7 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
 			spin_unlock_bh(&tmp_dp->dp_lock);
 
 skip_peer_find:
-			ret = ath12k_wifi7_dp_tx(tmp_dp_pdev, tmp_arvif,
+			ret = ath12k_wifi7_dp_tx(tmp_dp_pdev, tmp_arvif, arsta,
 						 msdu_copied, true, mcbc_gsn, is_mcast);
 			if (unlikely(ret)) {
 				if (ret == -ENOMEM) {
@@ -1075,6 +1088,7 @@ static const struct ieee80211_ops ath12k_ops_wifi7 = {
 	.sta_state                      = ath12k_mac_op_sta_state,
 	.sta_set_txpwr			= ath12k_mac_op_sta_set_txpwr,
 	.link_sta_rc_update		= ath12k_mac_op_link_sta_rc_update,
+	.sta_set_4addr                  = ath12k_mac_op_sta_set_4addr,
 	.conf_tx                        = ath12k_mac_op_conf_tx,
 	.set_antenna			= ath12k_mac_op_set_antenna,
 	.get_antenna			= ath12k_mac_op_get_antenna,
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 14b8dcdf881d..a827b3c99f8f 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -2334,6 +2334,11 @@ enum wmi_preamble {
 	WMI_VDEV_PREAMBLE_SHORT = 2,
 };
 
+enum wmi_peer_4addr_allow_frame {
+	WMI_PEER_4ADDR_ALLOW_DATA_FRAME = 1,
+	WMI_PEER_4ADDR_ALLOW_EAPOL_DATA_FRAME = 2,
+};
+
 enum wmi_peer_smps_state {
 	WMI_PEER_SMPS_PS_NONE =	0,
 	WMI_PEER_SMPS_STATIC  = 1,
-- 
2.34.1


^ permalink raw reply related

* [PATCH ath-next 1/6] wifi: ath12k: Set WDS vdev parameter for 4-address station interface
From: Tamizh Chelvam Raja @ 2026-05-25 11:09 UTC (permalink / raw)
  To: ath12k; +Cc: linux-wireless, Tamizh Chelvam Raja, Ramya Gnanasekar
In-Reply-To: <20260525110942.2890212-1-tamizh.raja@oss.qualcomm.com>

Set WDS vdev parameter during station interface creation to enable
4-address mode. Unlike AP interfaces that set peer-specific 4-address
mode parameters after receiving 4-address frames from stations, station
interfaces must send all data frames in 4-address mode immediately after
association, including 4-address NULL frames.

Firmware requires 4-address notification for station interfaces during
vdev creation. Configure the WDS vdev parameter for station interfaces.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1

Co-developed-by: Ramya Gnanasekar <ramya.gnanasekar@oss.qualcomm.com>
Signed-off-by: Ramya Gnanasekar <ramya.gnanasekar@oss.qualcomm.com>
Signed-off-by: Tamizh Chelvam Raja <tamizh.raja@oss.qualcomm.com>
---
 drivers/net/wireless/ath/ath12k/mac.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 54081beb9a5f..2d02a6a8d54f 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -10231,6 +10231,7 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif)
 	struct ieee80211_hw *hw = ah->hw;
 	struct ath12k_vif *ahvif = arvif->ahvif;
 	struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif);
+	struct wireless_dev *wdev = ieee80211_vif_to_wdev(vif);
 	struct ath12k_wmi_vdev_create_arg vdev_arg = {};
 	struct ath12k_wmi_peer_create_arg peer_param = {};
 	struct ieee80211_bss_conf *link_conf = NULL;
@@ -10399,6 +10400,25 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif)
 			goto err_peer_del;
 		}
 
+		/*
+		 * There could be race condition in firmware for the station
+		 * interface between enabling 4-address peer WMI param and
+		 * sending 4-address frame (NULL or EAPOL via TCL).
+		 * Make the station as WDS while bringup itself
+		 * to avoid the race condition
+		 */
+		if (vif->type == NL80211_IFTYPE_STATION &&
+		    (wdev && wdev->use_4addr)) {
+			ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+							    WMI_VDEV_PARAM_WDS,
+							    1);
+			if (ret) {
+				ath12k_warn(ar->ab, "failed to set WDS vdev param: %d\n",
+					    ret);
+				goto err_peer_del;
+			}
+		}
+
 		if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ab->wmi_ab.svc_map) &&
 		    ahvif->vdev_type == WMI_VDEV_TYPE_STA &&
 		    ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) {
-- 
2.34.1


^ permalink raw reply related

* [PATCH ath-next 0/6] wifi: ath12k: Add driver support for WDS mode
From: Tamizh Chelvam Raja @ 2026-05-25 11:09 UTC (permalink / raw)
  To: ath12k; +Cc: linux-wireless, Tamizh Chelvam Raja

This patch series introduces support for WDS in the driver by adding
below changes

Handling of 4-address frame formats required for WDS operation.
Proper setting of peer 4-address WMI param to ensure correct transmission
and reception of multicast and unicast frames in WDS mode.
Conversion of eth offload Rx frame to 802.11 frame for mac80211 to
detect 4address frame and initiate AP_VLAN creation.

Tamizh Chelvam Raja (6):
  wifi: ath12k: Set WDS vdev parameter for 4-address station interface
  wifi: ath12k: Add support for 4-address mode
  wifi: ath12k: Add 4-address mode support for eth offload
  wifi: ath12k: Add support for 4-address NULL frame handling
  wifi: ath12k: Add support for 4-address frame notification
  wifi: ath12k: Handle 4-address EAPOL frames from WBM error path

 drivers/net/wireless/ath/ath12k/core.h        |   9 ++
 drivers/net/wireless/ath/ath12k/dp_peer.h     |   2 +
 drivers/net/wireless/ath/ath12k/dp_rx.c       |  10 +-
 drivers/net/wireless/ath/ath12k/dp_rx.h       |   3 +-
 drivers/net/wireless/ath/ath12k/hal.h         |   4 +-
 drivers/net/wireless/ath/ath12k/mac.c         | 124 +++++++++++++++++-
 drivers/net/wireless/ath/ath12k/mac.h         |   3 +
 drivers/net/wireless/ath/ath12k/peer.c        |  11 +-
 drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c |  91 +++++++++++--
 drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c |  41 +++++-
 drivers/net/wireless/ath/ath12k/wifi7/dp_tx.h |   4 +-
 .../wireless/ath/ath12k/wifi7/hal_qcc2072.c   |  16 +++
 .../wireless/ath/ath12k/wifi7/hal_qcn9274.c   |  16 +++
 .../net/wireless/ath/ath12k/wifi7/hal_tx.c    |   4 +-
 .../net/wireless/ath/ath12k/wifi7/hal_tx.h    |   1 +
 .../wireless/ath/ath12k/wifi7/hal_wcn7850.c   |  16 +++
 drivers/net/wireless/ath/ath12k/wifi7/hw.c    |  18 ++-
 drivers/net/wireless/ath/ath12k/wmi.c         |  47 ++++++-
 drivers/net/wireless/ath/ath12k/wmi.h         |  17 +++
 19 files changed, 409 insertions(+), 28 deletions(-)


base-commit: 30d516006fa1f72f957c18c6171f5680dcdebfb0
-- 
2.34.1


^ permalink raw reply

* [PATCH 1/1] wifi: mac80211: validate minstrel HT tx status rates
From: Ren Wei @ 2026-05-25 11:07 UTC (permalink / raw)
  To: linux-wireless
  Cc: johannes, nbd, linville, yuantan098, zcliangcn, bird, xuyuqiabc,
	n05ec
In-Reply-To: <cover.1779619788.git.xuyq21@lenovo.com>

From: Yuqi Xu <xuyq21@lenovo.com>

minstrel_ht_tx_status() accepts both legacy tx status entries and
rate_info-based status entries, then turns the reported HT/VHT rate
into a minstrel group and rate index.

The validation helpers only checked that the entry was present and had
tries recorded. They did not verify that the reported HT stream count,
VHT NSS, VHT bandwidth encoding, and MCS value were representable by
minstrel_ht's rate tables. As a result, malformed tx status metadata
could produce group or rate indices outside the tables that
minstrel_ht_get_stats() and minstrel_ht_ri_get_stats() index.

Teach the existing tx status validation path to enforce the exact
constraints used by minstrel HT's tables for both status formats.
Reject HT rates beyond the supported stream groups, and reject VHT
rates with unsupported bandwidth encodings, invalid NSS values, or
MCS values outside the table.

This keeps the fix at the existing trust boundary and leaves the
stats lookup path unchanged.

Fixes: ec8aa669b839 ("mac80211: add the minstrel_ht rate control algorithm")
Cc: stable@kernel.org
Reported-by: Yuan Tan <yuantan098@gmail.com>
Reported-by: Zhengchuan Liang <zcliangcn@gmail.com>
Reported-by: Xin Liu <bird@lzu.edu.cn>
Assisted-by: Codex:GPT-5.4
Signed-off-by: Yuqi Xu <xuyuqiabc@gmail.com>
Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
---
 net/mac80211/rc80211_minstrel_ht.c | 47 +++++++++++++++++++++++++++---
 1 file changed, 43 insertions(+), 4 deletions(-)

diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index b73ef3adfcc5..a35d42c77ac5 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -323,6 +323,43 @@ minstrel_ht_is_legacy_group(int group)
 	       group == MINSTREL_OFDM_GROUP;
 }
 
+static bool
+minstrel_ht_txstat_valid_rate(struct ieee80211_tx_rate *rate)
+{
+	unsigned int bw;
+
+	if (rate->flags & IEEE80211_TX_RC_MCS)
+		return rate->idx < MINSTREL_MAX_STREAMS * 8;
+
+	if (!(rate->flags & IEEE80211_TX_RC_VHT_MCS))
+		return true;
+
+	bw = !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) +
+	     2 * !!(rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH);
+
+	return !(rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH) &&
+	       bw <= BW_80 &&
+	       ieee80211_rate_get_vht_nss(rate) <= MINSTREL_MAX_STREAMS &&
+	       ieee80211_rate_get_vht_mcs(rate) < MCS_GROUP_RATES;
+}
+
+static bool
+minstrel_ht_ri_txstat_valid_rate(struct rate_info *rate)
+{
+	if (rate->flags & RATE_INFO_FLAGS_MCS)
+		return rate->mcs < MINSTREL_MAX_STREAMS * 8;
+
+	if (!(rate->flags & RATE_INFO_FLAGS_VHT_MCS))
+		return true;
+
+	return (rate->bw == RATE_INFO_BW_20 ||
+		rate->bw == RATE_INFO_BW_40 ||
+		rate->bw == RATE_INFO_BW_80) &&
+	       rate->nss >= 1 &&
+	       rate->nss <= MINSTREL_MAX_STREAMS &&
+	       rate->mcs < MCS_GROUP_RATES;
+}
+
 /*
  * Look up an MCS group index based on mac80211 rate information
  */
@@ -1205,8 +1242,9 @@ minstrel_ht_txstat_valid(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
 	if (!rate->count)
 		return false;
 
-	if (rate->flags & IEEE80211_TX_RC_MCS ||
-	    rate->flags & IEEE80211_TX_RC_VHT_MCS)
+	if (rate->flags & IEEE80211_TX_RC_MCS ||
+	    rate->flags & IEEE80211_TX_RC_VHT_MCS)
+		return minstrel_ht_txstat_valid_rate(rate);
 
 	for (i = 0; i < ARRAY_SIZE(mp->cck_rates); i++)
@@ -1235,8 +1273,9 @@ minstrel_ht_ri_txstat_valid(struct minstrel_priv *mp,
 	if (!rate_status->try_count)
 		return false;
 
-	if (rate_status->rate_idx.flags & RATE_INFO_FLAGS_MCS ||
-	    rate_status->rate_idx.flags & RATE_INFO_FLAGS_VHT_MCS)
+	if (rate_status->rate_idx.flags & RATE_INFO_FLAGS_MCS ||
+	    rate_status->rate_idx.flags & RATE_INFO_FLAGS_VHT_MCS)
+		return minstrel_ht_ri_txstat_valid_rate(&rate_status->rate_idx);
 
 	for (i = 0; i < ARRAY_SIZE(mp->cck_rates); i++) {
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH 02/10] [v3] input: gpio-keys: make legacy gpiolib optional
From: Linus Walleij @ 2026-05-25  8:57 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-gpio, linux-kernel, Arnd Bergmann, Christian Lamparter,
	Johannes Berg, Aaro Koskinen, Andreas Kemnade, Kevin Hilman,
	Roger Quadros, Tony Lindgren, Thomas Bogendoerfer,
	John Paul Adrian Glaubitz, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Bartosz Golaszewski, Dmitry Torokhov, Lee Jones, Pavel Machek,
	Matti Vaittinen, Florian Fainelli, Jonas Gorski, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, linux-wireless, linux-omap, linux-arm-kernel,
	linux-mips, linux-sh, linux-input, linux-leds, netdev
In-Reply-To: <20260520183815.2510387-3-arnd@kernel.org>

On Wed, May 20, 2026 at 8:38 PM Arnd Bergmann <arnd@kernel.org> wrote:

> From: Arnd Bergmann <arnd@arndb.de>
>
> Most users of gpio-keys and gpio-keys-polled use modern gpiolib
> interfaces, but there are still number of ancient sh, arm32 and x86
> machines that have never been converted.
>
> Add an #ifdef block for the parts of the driver that are only used on
> those legacy machines.
>
> The two Rohm PMIC drivers use a gpio-keys device without an actual GPIO,
> passing an IRQ number instead. In order to keep this working both with
> and with CONFIG_GPIOLIB_LEGACY, change the gpio-keys driver to ignore
> the gpio number if an IRQ is passed.
>
> Link: https://lore.kernel.org/all/b3c94552-c104-42e3-be15-7e8362e8039e@gmail.com/
> Link: https://lore.kernel.org/all/afJXG4_rtaj3l2Dk@google.com/
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>

Reviewed-by: Linus Walleij <linusw@kernel.org>

Yours,
Linus Walleij

^ permalink raw reply

* [PATCH v2 rtw-next 2/2] wifi: rtw89: usb: add serial_number and uuid sysfs attributes for 0x28de:0x2432
From: Ping-Ke Shih @ 2026-05-25  8:51 UTC (permalink / raw)
  To: linux-wireless
  Cc: driver-core, johannes, wenjie.tsai, mh_chen, charlesl, sabae
In-Reply-To: <20260525085148.35180-1-pkshih@realtek.com>

From: Johnson Tsai <wenjie.tsai@realtek.com>

Expose the device's Serial Number (SN) and UUID from EFUSE via two
read-only sysfs attributes, `serial_number` and `uuid`, on the ieee80211
phy device under the `rtw89_usb` attribute group.

This hardware identification information is essential for user-space
applications to uniquely identify, track, and manage specific Wi-Fi
adapters. For example, in automated factory provisioning or device
management systems, user-space tools rely on the EFUSE serial number and
UUID to bind configurations to specific physical adapters. Currently,
standard wireless APIs do not expose this low-level hardware
information, making these sysfs nodes the only viable solution for
user space to extract this data.

The attributes are gated behind a new RTW89_QUIRK_HW_INFO_SYSFS quirk,
enabled only for the VID 0x28de / PID 0x2432 device via the
dev_id_quirks field in rtw89_driver_info.

Example usage from user-space:
  $ cat /sys/class/ieee80211/phy0/rtw89_usb/serial_number
  3642000123
  $ cat /sys/class/ieee80211/phy0/rtw89_usb/uuid
  aaec2b7c-0a55-4727-8de0-b30febccbbaa

Cc: Elliot Saba <sabae@valvesoftware.com>
Cc: Charles Lohr <charlesl@valvesoftware.com>
Signed-off-by: Johnson Tsai <wenjie.tsai@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 .../ABI/testing/sysfs-class-ieee80211-rtw89   | 24 ++++++++
 drivers/net/wireless/realtek/rtw89/core.h     |  6 ++
 drivers/net/wireless/realtek/rtw89/rtw8852c.c | 10 ++++
 drivers/net/wireless/realtek/rtw89/rtw8852c.h |  6 +-
 .../net/wireless/realtek/rtw89/rtw8852cu.c    | 12 +++-
 drivers/net/wireless/realtek/rtw89/usb.c      | 57 +++++++++++++++++++
 6 files changed, 113 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-class-ieee80211-rtw89

diff --git a/Documentation/ABI/testing/sysfs-class-ieee80211-rtw89 b/Documentation/ABI/testing/sysfs-class-ieee80211-rtw89
new file mode 100644
index 000000000000..7dfdce08a42f
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-ieee80211-rtw89
@@ -0,0 +1,24 @@
+What:		/sys/class/ieee80211/phyX/rtw89_usb/serial_number
+Date:		May 2026
+Contact:	Johnson Tsai <wenjie.tsai@realtek.com>, linux-wireless@vger.kernel.org
+Description:	(Read) Serial number burned into EFUSE of the RTL8852CU-based
+		USB Wi-Fi adapter.  Only present on devices that set the
+		RTW89_QUIRK_HW_INFO_SYSFS quirk (currently VID 0x28de /
+		PID 0x2432).
+
+		Format: %10phN (5 raw bytes printed as 10 lowercase hex
+		digits, no separators).
+
+		Example: 3642000123
+
+What:		/sys/class/ieee80211/phyX/rtw89_usb/uuid
+Date:		May 2026
+Contact:	Johnson Tsai <wenjie.tsai@realtek.com>, linux-wireless@vger.kernel.org
+Description:	(Read) UUID burned into EFUSE of the RTL8852CU-based USB Wi-Fi
+		adapter.  Only present on devices that set the
+		RTW89_QUIRK_HW_INFO_SYSFS quirk (currently VID 0x28de /
+		PID 0x2432).
+
+		Format: %pUb (RFC 4122 UUID in lowercase with hyphens).
+
+		Example: aaec2b7c-0a55-4727-8de0-b30febccbbaa
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index e687216da5b6..09f17d958075 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -3615,6 +3615,9 @@ struct rtw89_sta_link {
 	u32 data_tx_cnt_lmt:6;
 };
 
+#define RTW89_EFUSE_SN_LEN 5
+#define RTW89_EFUSE_UUID_LEN 16
+
 struct rtw89_efuse {
 	bool valid;
 	bool power_k_valid;
@@ -3625,6 +3628,8 @@ struct rtw89_efuse {
 	u8 adc_td;
 	u8 bt_setting_2;
 	u8 bt_setting_3;
+	u8 sn[RTW89_EFUSE_SN_LEN];
+	u8 uuid[RTW89_EFUSE_UUID_LEN];
 };
 
 struct rtw89_phy_rate_pattern {
@@ -5373,6 +5378,7 @@ enum rtw89_quirks {
 	RTW89_QUIRK_PCI_BER,
 	RTW89_QUIRK_THERMAL_PROT_120C,
 	RTW89_QUIRK_THERMAL_PROT_110C,
+	RTW89_QUIRK_HW_INFO_SYSFS,
 
 	NUM_OF_RTW89_QUIRKS,
 };
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index 7bb1264bcaef..3861cce42b1b 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -621,6 +621,15 @@ static void rtw8852c_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev,
 	gain->offset_valid = valid;
 }
 
+static void rtw8852c_efuse_copy_sn_uuid_usb(struct rtw89_dev *rtwdev,
+					    const struct rtw8852c_efuse *map)
+{
+	struct rtw89_efuse *efuse = &rtwdev->efuse;
+
+	memcpy(efuse->sn, map->u.sn, sizeof(efuse->sn));
+	memcpy(efuse->uuid, map->u.uuid, sizeof(efuse->uuid));
+}
+
 static int rtw8852c_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map,
 			       enum rtw89_efuse_block block)
 {
@@ -640,6 +649,7 @@ static int rtw8852c_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map,
 		break;
 	case RTW89_HCI_TYPE_USB:
 		ether_addr_copy(efuse->addr, map->u.mac_addr);
+		rtw8852c_efuse_copy_sn_uuid_usb(rtwdev, map);
 		break;
 	default:
 		return -ENOTSUPP;
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.h b/drivers/net/wireless/realtek/rtw89/rtw8852c.h
index 8585921ac6c4..b1d7c354c18e 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.h
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.h
@@ -13,7 +13,11 @@
 struct rtw8852c_u_efuse {
 	u8 rsvd[0x88];
 	u8 mac_addr[ETH_ALEN];
-};
+	u8 rsvd1[8];
+	u8 sn[RTW89_EFUSE_SN_LEN];
+	u8 rsvd2[29];
+	u8 uuid[RTW89_EFUSE_UUID_LEN];
+} __packed;
 
 struct rtw8852c_e_efuse {
 	u8 mac_addr[ETH_ALEN];
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
index 8f89f9a31455..81ee96b0a048 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
@@ -39,6 +39,16 @@ static const struct rtw89_driver_info rtw89_8852cu_info = {
 	},
 };
 
+static const struct rtw89_driver_info rtw89_8852cu_valve_info = {
+	.chip = &rtw8852c_chip_info,
+	.variant = NULL,
+	.quirks = NULL,
+	.dev_id_quirks = BIT(RTW89_QUIRK_HW_INFO_SYSFS),
+	.bus = {
+		.usb = &rtw8852c_usb_info,
+	},
+};
+
 static const struct usb_device_id rtw_8852cu_id_table[] = {
 	{ USB_DEVICE_AND_INTERFACE_INFO(0x0411, 0x03a6, 0xff, 0xff, 0xff),
 	  .driver_info = (kernel_ulong_t)&rtw89_8852cu_info },
@@ -53,7 +63,7 @@ static const struct usb_device_id rtw_8852cu_id_table[] = {
 	{ USB_DEVICE_AND_INTERFACE_INFO(0x0db0, 0x991d, 0xff, 0xff, 0xff),
 	  .driver_info = (kernel_ulong_t)&rtw89_8852cu_info },
 	{ USB_DEVICE_AND_INTERFACE_INFO(0x28de, 0x2432, 0xff, 0xff, 0xff),
-	  .driver_info = (kernel_ulong_t)&rtw89_8852cu_info },
+	  .driver_info = (kernel_ulong_t)&rtw89_8852cu_valve_info },
 	{ USB_DEVICE_AND_INTERFACE_INFO(0x2c7c, 0x8206, 0xff, 0xff, 0xff),
 	  .driver_info = (kernel_ulong_t)&rtw89_8852cu_info },
 	{ USB_DEVICE_AND_INTERFACE_INFO(0x35b2, 0x0502, 0xff, 0xff, 0xff),
diff --git a/drivers/net/wireless/realtek/rtw89/usb.c b/drivers/net/wireless/realtek/rtw89/usb.c
index 88d7ec200837..7e23d0a32025 100644
--- a/drivers/net/wireless/realtek/rtw89/usb.c
+++ b/drivers/net/wireless/realtek/rtw89/usb.c
@@ -1059,6 +1059,61 @@ static void rtw89_usb_intf_deinit(struct rtw89_dev *rtwdev,
 	usb_set_intfdata(intf, NULL);
 }
 
+static ssize_t serial_number_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct wiphy *wiphy = container_of(dev, struct wiphy, dev);
+	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+	struct rtw89_dev *rtwdev = hw->priv;
+	struct rtw89_efuse *efuse = &rtwdev->efuse;
+
+	return sysfs_emit(buf, "%*phN\n",
+			  (int)sizeof(efuse->sn), efuse->sn);
+}
+static DEVICE_ATTR_RO(serial_number);
+
+static ssize_t uuid_show(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	struct wiphy *wiphy = container_of(dev, struct wiphy, dev);
+	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+	struct rtw89_dev *rtwdev = hw->priv;
+	struct rtw89_efuse *efuse = &rtwdev->efuse;
+
+	return sysfs_emit(buf, "%pUb\n", efuse->uuid);
+}
+static DEVICE_ATTR_RO(uuid);
+
+static struct attribute *rtw89_usb_attrs[] = {
+	&dev_attr_serial_number.attr,
+	&dev_attr_uuid.attr,
+	NULL,
+};
+
+static const struct attribute_group rtw89_usb_group = {
+	.name = "rtw89_usb",
+	.attrs = rtw89_usb_attrs,
+};
+__ATTRIBUTE_GROUPS(rtw89_usb);
+
+static void rtw89_usb_sysfs_create(struct rtw89_dev *rtwdev)
+{
+	int ret;
+
+	if (!test_bit(RTW89_QUIRK_HW_INFO_SYSFS, rtwdev->quirks))
+		return;
+
+	ret = sysfs_create_groups(&rtwdev->hw->wiphy->dev.kobj,
+				  rtw89_usb_groups);
+	if (ret)
+		rtw89_warn(rtwdev, "failed to create sysfs groups: %d\n", ret);
+}
+
+static void rtw89_usb_sysfs_remove(struct rtw89_dev *rtwdev)
+{
+	sysfs_remove_groups(&rtwdev->hw->wiphy->dev.kobj, rtw89_usb_groups);
+}
+
 int rtw89_usb_probe(struct usb_interface *intf,
 		    const struct usb_device_id *id)
 {
@@ -1123,6 +1178,7 @@ int rtw89_usb_probe(struct usb_interface *intf,
 		goto err_core_deinit;
 	}
 
+	rtw89_usb_sysfs_create(rtwdev);
 	rtw89_usb_start_rx(rtwdev);
 
 	set_bit(RTW89_FLAG_PROBE_DONE, rtwdev->flags);
@@ -1159,6 +1215,7 @@ void rtw89_usb_disconnect(struct usb_interface *intf)
 	rtw89_usb_cancel_rx_bufs(rtwusb);
 	rtw89_usb_cancel_tx_bufs(rtwusb);
 
+	rtw89_usb_sysfs_remove(rtwdev);
 	rtw89_core_unregister(rtwdev);
 	rtw89_core_deinit(rtwdev);
 	rtw89_usb_deinit_rx(rtwdev);
-- 
2.25.1


^ permalink raw reply related

* [PATCH v2 rtw-next 1/2] wifi: rtw89: add dev_id_quirks to driver_info for per-device quirk control
From: Ping-Ke Shih @ 2026-05-25  8:51 UTC (permalink / raw)
  To: linux-wireless
  Cc: driver-core, johannes, wenjie.tsai, mh_chen, charlesl, sabae
In-Reply-To: <20260525085148.35180-1-pkshih@realtek.com>

From: Johnson Tsai <wenjie.tsai@realtek.com>

Add a dev_id_quirks field to rtw89_driver_info so that per-device
(VID/PID) quirks can be expressed independently of chip-level
default_quirks. Apply the bitmap in rtw89_alloc_ieee80211_hw() so
both USB and PCI probes benefit automatically.

All existing driver_info structs initialize dev_id_quirks to 0;
no behavior change.

Signed-off-by: Johnson Tsai <wenjie.tsai@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/core.c       | 9 +++++++--
 drivers/net/wireless/realtek/rtw89/core.h       | 4 ++--
 drivers/net/wireless/realtek/rtw89/pci.c        | 3 +--
 drivers/net/wireless/realtek/rtw89/rtw8851be.c  | 1 +
 drivers/net/wireless/realtek/rtw89/rtw8851bu.c  | 1 +
 drivers/net/wireless/realtek/rtw89/rtw8852ae.c  | 1 +
 drivers/net/wireless/realtek/rtw89/rtw8852au.c  | 1 +
 drivers/net/wireless/realtek/rtw89/rtw8852be.c  | 1 +
 drivers/net/wireless/realtek/rtw89/rtw8852bte.c | 1 +
 drivers/net/wireless/realtek/rtw89/rtw8852bu.c  | 1 +
 drivers/net/wireless/realtek/rtw89/rtw8852ce.c  | 1 +
 drivers/net/wireless/realtek/rtw89/rtw8852cu.c  | 1 +
 drivers/net/wireless/realtek/rtw89/rtw8922ae.c  | 2 ++
 drivers/net/wireless/realtek/rtw89/rtw8922au.c  | 1 +
 drivers/net/wireless/realtek/rtw89/rtw8922de.c  | 2 ++
 drivers/net/wireless/realtek/rtw89/usb.c        | 3 +--
 16 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index c1df3e2ba11e..68dad6090f87 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -7532,9 +7532,11 @@ EXPORT_SYMBOL(rtw89_core_unregister);
 
 struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
 					   u32 bus_data_size,
-					   const struct rtw89_chip_info *chip,
-					   const struct rtw89_chip_variant *variant)
+					   const struct rtw89_driver_info *info)
 {
+	const unsigned long *dev_id_quirks = &info->dev_id_quirks;
+	const struct rtw89_chip_variant *variant = info->variant;
+	const struct rtw89_chip_info *chip = info->chip;
 	struct rtw89_fw_info early_fw = {};
 	const struct firmware *firmware;
 	struct ieee80211_hw *hw;
@@ -7600,6 +7602,9 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
 	rtwdev->fw.fw_format = fw_format;
 	rtwdev->support_mlo = support_mlo;
 
+	bitmap_or(rtwdev->quirks, rtwdev->quirks, dev_id_quirks,
+		  NUM_OF_RTW89_QUIRKS);
+
 	rtw89_debug(rtwdev, RTW89_DBG_CHAN, "probe driver %s chanctx\n",
 		    no_chanctx ? "without" : "with");
 	rtw89_debug(rtwdev, RTW89_DBG_CHAN, "probe driver %s MLO cap\n",
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 27d9a916d58c..e687216da5b6 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -4800,6 +4800,7 @@ struct rtw89_driver_info {
 	const struct rtw89_chip_info *chip;
 	const struct rtw89_chip_variant *variant;
 	const struct dmi_system_id *quirks;
+	unsigned long dev_id_quirks; /* bitmap of rtw89_quirks */
 	union rtw89_bus_info bus;
 };
 
@@ -8126,8 +8127,7 @@ int rtw89_core_register(struct rtw89_dev *rtwdev);
 void rtw89_core_unregister(struct rtw89_dev *rtwdev);
 struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
 					   u32 bus_data_size,
-					   const struct rtw89_chip_info *chip,
-					   const struct rtw89_chip_variant *variant);
+					   const struct rtw89_driver_info *info);
 void rtw89_free_ieee80211_hw(struct rtw89_dev *rtwdev);
 u8 rtw89_acquire_mac_id(struct rtw89_dev *rtwdev);
 void rtw89_release_mac_id(struct rtw89_dev *rtwdev, u8 mac_id);
diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c
index fe1152c560bd..102bae488180 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.c
+++ b/drivers/net/wireless/realtek/rtw89/pci.c
@@ -4772,8 +4772,7 @@ int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	info = (const struct rtw89_driver_info *)id->driver_data;
 
 	rtwdev = rtw89_alloc_ieee80211_hw(&pdev->dev,
-					  sizeof(struct rtw89_pci),
-					  info->chip, info->variant);
+					  sizeof(struct rtw89_pci), info);
 	if (!rtwdev) {
 		dev_err(&pdev->dev, "failed to allocate hw\n");
 		return -ENOMEM;
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851be.c b/drivers/net/wireless/realtek/rtw89/rtw8851be.c
index ce59ac9f56ba..640672eb0d26 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8851be.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8851be.c
@@ -73,6 +73,7 @@ static const struct rtw89_driver_info rtw89_8851be_info = {
 	.chip = &rtw8851b_chip_info,
 	.variant = NULL,
 	.quirks = NULL,
+	.dev_id_quirks = 0,
 	.bus = {
 		.pci = &rtw8851b_pci_info,
 	},
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851bu.c b/drivers/net/wireless/realtek/rtw89/rtw8851bu.c
index 6a8d31544314..e7933174398e 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8851bu.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8851bu.c
@@ -31,6 +31,7 @@ static const struct rtw89_driver_info rtw89_8851bu_info = {
 	.chip = &rtw8851b_chip_info,
 	.variant = NULL,
 	.quirks = NULL,
+	.dev_id_quirks = 0,
 	.bus = {
 		.usb = &rtw8851b_usb_info,
 	}
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c
index 9e05e831569d..64306cdc1ee4 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c
@@ -71,6 +71,7 @@ static const struct rtw89_driver_info rtw89_8852ae_info = {
 	.chip = &rtw8852a_chip_info,
 	.variant = NULL,
 	.quirks = NULL,
+	.dev_id_quirks = 0,
 	.bus = {
 		.pci = &rtw8852a_pci_info,
 	},
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852au.c b/drivers/net/wireless/realtek/rtw89/rtw8852au.c
index 4cced4619b7d..29b7f7769370 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852au.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852au.c
@@ -33,6 +33,7 @@ static const struct rtw89_driver_info rtw89_8852au_info = {
 	.chip = &rtw8852a_chip_info,
 	.variant = NULL,
 	.quirks = NULL,
+	.dev_id_quirks = 0,
 	.bus = {
 		.usb = &rtw8852a_usb_info,
 	}
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852be.c b/drivers/net/wireless/realtek/rtw89/rtw8852be.c
index 12db0d0be547..5bc0a6a99d1d 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852be.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852be.c
@@ -73,6 +73,7 @@ static const struct rtw89_driver_info rtw89_8852be_info = {
 	.chip = &rtw8852b_chip_info,
 	.variant = NULL,
 	.quirks = NULL,
+	.dev_id_quirks = 0,
 	.bus = {
 		.pci = &rtw8852b_pci_info,
 	},
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bte.c b/drivers/net/wireless/realtek/rtw89/rtw8852bte.c
index 8c995aa95325..49a72ca835ac 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852bte.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852bte.c
@@ -79,6 +79,7 @@ static const struct rtw89_driver_info rtw89_8852bte_info = {
 	.chip = &rtw8852bt_chip_info,
 	.variant = NULL,
 	.quirks = NULL,
+	.dev_id_quirks = 0,
 	.bus = {
 		.pci = &rtw8852bt_pci_info,
 	},
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bu.c b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c
index 37111fed276f..308d3d570ff3 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852bu.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c
@@ -31,6 +31,7 @@ static const struct rtw89_driver_info rtw89_8852bu_info = {
 	.chip = &rtw8852b_chip_info,
 	.variant = NULL,
 	.quirks = NULL,
+	.dev_id_quirks = 0,
 	.bus = {
 		.usb = &rtw8852b_usb_info,
 	}
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c
index 150fed189414..3c64c0539205 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c
@@ -102,6 +102,7 @@ static const struct rtw89_driver_info rtw89_8852ce_info = {
 	.chip = &rtw8852c_chip_info,
 	.variant = NULL,
 	.quirks = rtw8852c_pci_quirks,
+	.dev_id_quirks = 0,
 	.bus = {
 		.pci = &rtw8852c_pci_info,
 	},
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
index 790fd1dec66d..8f89f9a31455 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
@@ -33,6 +33,7 @@ static const struct rtw89_driver_info rtw89_8852cu_info = {
 	.chip = &rtw8852c_chip_info,
 	.variant = NULL,
 	.quirks = NULL,
+	.dev_id_quirks = 0,
 	.bus = {
 		.usb = &rtw8852c_usb_info,
 	},
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c
index 90c62b757c57..5527a8db393b 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c
@@ -77,6 +77,7 @@ static const struct rtw89_driver_info rtw89_8922ae_info = {
 	.chip = &rtw8922a_chip_info,
 	.variant = NULL,
 	.quirks = NULL,
+	.dev_id_quirks = 0,
 	.bus = {
 		.pci = &rtw8922a_pci_info,
 	},
@@ -86,6 +87,7 @@ static const struct rtw89_driver_info rtw89_8922ae_vs_info = {
 	.chip = &rtw8922a_chip_info,
 	.variant = &rtw8922ae_vs_variant,
 	.quirks = NULL,
+	.dev_id_quirks = 0,
 	.bus = {
 		.pci = &rtw8922a_pci_info,
 	},
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922au.c b/drivers/net/wireless/realtek/rtw89/rtw8922au.c
index 347bde171391..2b81de501d62 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922au.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922au.c
@@ -32,6 +32,7 @@ static const struct rtw89_driver_info rtw89_8922au_info = {
 	.chip = &rtw8922a_chip_info,
 	.variant = NULL,
 	.quirks = NULL,
+	.dev_id_quirks = 0,
 	.bus = {
 		.usb = &rtw8922a_usb_info,
 	},
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922de.c b/drivers/net/wireless/realtek/rtw89/rtw8922de.c
index f144e7fc76de..a1a81c338be3 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922de.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922de.c
@@ -73,6 +73,7 @@ static const struct rtw89_driver_info rtw89_8922de_vs_info = {
 	.chip = &rtw8922d_chip_info,
 	.variant = &rtw8922de_vs_variant,
 	.quirks = NULL,
+	.dev_id_quirks = 0,
 	.bus = {
 		.pci = &rtw8922d_pci_info,
 	},
@@ -82,6 +83,7 @@ static const struct rtw89_driver_info rtw89_8922de_info = {
 	.chip = &rtw8922d_chip_info,
 	.variant = NULL,
 	.quirks = NULL,
+	.dev_id_quirks = 0,
 	.bus = {
 		.pci = &rtw8922d_pci_info,
 	},
diff --git a/drivers/net/wireless/realtek/rtw89/usb.c b/drivers/net/wireless/realtek/rtw89/usb.c
index c6d55e669776..88d7ec200837 100644
--- a/drivers/net/wireless/realtek/rtw89/usb.c
+++ b/drivers/net/wireless/realtek/rtw89/usb.c
@@ -1070,8 +1070,7 @@ int rtw89_usb_probe(struct usb_interface *intf,
 	info = (const struct rtw89_driver_info *)id->driver_info;
 
 	rtwdev = rtw89_alloc_ieee80211_hw(&intf->dev,
-					  sizeof(struct rtw89_usb),
-					  info->chip, info->variant);
+					  sizeof(struct rtw89_usb), info);
 	if (!rtwdev) {
 		dev_err(&intf->dev, "failed to allocate hw\n");
 		return -ENOMEM;
-- 
2.25.1


^ permalink raw reply related

* [PATCH v2 rtw-next 0/2] wifi: rtw89: usb: read serial_number and uuid via sysfs
From: Ping-Ke Shih @ 2026-05-25  8:51 UTC (permalink / raw)
  To: linux-wireless
  Cc: driver-core, johannes, wenjie.tsai, mh_chen, charlesl, sabae

As what we learned in RFC v1, add sysfs entries
 - /sys/class/ieee80211/phy0/rtw89_usb/serial_number
 - /sys/class/ieee80211/phy0/rtw89_usb/uuid

These entries only present if specific USB device is in use. We add a
quirk as a flag for this.

Above info is fully documented in
Documentation/ABI/testing/sysfs-class-ieee80211-rtw89

v2:
 - add specific sysfs entries in /sys/class/ieee80211/phy0/rtw89_usb/
   * serial_number and uuid
 - add Documentation/ABI/testing/sysfs-class-ieee80211-rtw89 to
   describe ABI
 - add sysfs entries by quirk according to specific device ID
 - include patch 1/2 which does quirk infrastructure by device ID

v1 (RFC):
 - https://lore.kernel.org/linux-wireless/20260519072415.25746-1-pkshih@realtek.com/

Johnson Tsai (2):
  wifi: rtw89: add dev_id_quirks to driver_info for per-device quirk
    control
  wifi: rtw89: usb: add serial_number and uuid sysfs attributes for
    0x28de:0x2432

 .../ABI/testing/sysfs-class-ieee80211-rtw89   | 24 ++++++++
 drivers/net/wireless/realtek/rtw89/core.c     |  9 ++-
 drivers/net/wireless/realtek/rtw89/core.h     | 10 +++-
 drivers/net/wireless/realtek/rtw89/pci.c      |  3 +-
 .../net/wireless/realtek/rtw89/rtw8851be.c    |  1 +
 .../net/wireless/realtek/rtw89/rtw8851bu.c    |  1 +
 .../net/wireless/realtek/rtw89/rtw8852ae.c    |  1 +
 .../net/wireless/realtek/rtw89/rtw8852au.c    |  1 +
 .../net/wireless/realtek/rtw89/rtw8852be.c    |  1 +
 .../net/wireless/realtek/rtw89/rtw8852bte.c   |  1 +
 .../net/wireless/realtek/rtw89/rtw8852bu.c    |  1 +
 drivers/net/wireless/realtek/rtw89/rtw8852c.c | 10 ++++
 drivers/net/wireless/realtek/rtw89/rtw8852c.h |  6 +-
 .../net/wireless/realtek/rtw89/rtw8852ce.c    |  1 +
 .../net/wireless/realtek/rtw89/rtw8852cu.c    | 13 +++-
 .../net/wireless/realtek/rtw89/rtw8922ae.c    |  2 +
 .../net/wireless/realtek/rtw89/rtw8922au.c    |  1 +
 .../net/wireless/realtek/rtw89/rtw8922de.c    |  2 +
 drivers/net/wireless/realtek/rtw89/usb.c      | 60 ++++++++++++++++++-
 19 files changed, 138 insertions(+), 10 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-class-ieee80211-rtw89


base-commit: 6b964941bbfe6e0f18b1a5e008486dbb62df440a
-- 
2.25.1


^ permalink raw reply

* Re: wifi: rtw89: 8851bu: add Mercusys MA60XNB (2c4e:0128)
From: Guillem Servera Negre @ 2026-05-25  8:42 UTC (permalink / raw)
  To: Ping-Ke Shih, linux-wireless@vger.kernel.org
In-Reply-To: <c6af176e57de41b8bcfd4868a6057e00@realtek.com>

Hi,

Yes, that's correct. The adapter works with this ID after compiling and 
probing your patch.

Tested-by: Guillermo Servera Negre <guillem@gservera.com>

Thanks for the quick patch!

Guillem

El 25/5/26 a las 3:19, Ping-Ke Shih escribió:
> Guillermo Servera Negre <guillem@gservera.com> wrote:
>>   { USB_DEVICE_AND_INTERFACE_INFO(0x2C4E, 0x0128, 0xff, 0xff, 0xff), .driver_info =
>> (kernel_ulong_t)&rtw89_8851bu_info },
> I made a format patch [1] by this ID. Please check if it is expected.
>
> [1] https://lore.kernel.org/linux-wireless/20260525011728.6836-1-pkshih@realtek.com/T/#u
>

^ permalink raw reply

* [PATCH] wifi: brcmfmac: 43430 and 43455 are CYW parts
From: Shelley Yang @ 2026-05-25  8:39 UTC (permalink / raw)
  To: linux-wireless
  Cc: Johannes Berg, wlan-kernel-dev-list, Shelley Yang, Phil Elwell

From: Phil Elwell <phil@raspberrypi.com>

The brcmfmac driver uses the SDIO vendor ID values to identify which
vendor's driver extensions to use. However, the Cypress/Infineon devices
have a vendor ID of 02d0, which is Broadcom.

In order to use the Cypress driver extensions, modify the static mapping
for "43430", "4345" (sic) and "43455"
to indicate that they are Cypress parts.

Signed-off-by: Phil Elwell <phil@raspberrypi.com>
Signed-off-by: Shelley Yang <shelley.yang@infineon.com>
---
 drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
index d24b80e492e0..5926811c5411 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -988,10 +988,10 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = {
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43364, WCC),
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339, WCC),
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4339, WCC),
-	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43430, WCC),
+	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43430, CYW),
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43439, WCC),
-	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4345, WCC),
-	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43455, WCC),
+	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4345, CYW),
+	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43455, CYW),
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354, WCC),
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4356, WCC),
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4359, WCC),
-- 
2.25.1


^ permalink raw reply related

* [PATCH] wifi: brcmfmac: fix 802.11x-SHA256 call trace warning
From: Shelley Yang @ 2026-05-25  8:38 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg, wlan-kernel-dev-list, Shelley Yang

Based on wpa_auth as 1x_256 mode, need to set up
"use_fwsup" with BRCMF_PROFILE_FWSUP_1X.
Or it will happen trace warning when call brcmf_cfg80211_set_pmk().

[ 4481.831101] ------------[ cut here ]------------
[ 4481.831102] WARNING: CPU: 1 PID: 2997 at
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c:7242 brcmf_cfg80211_set_pmk+0x77/0xd0 [brcmfmac]
[...]
[ 4481.831202] Call Trace:
[ 4481.831204]  <TASK>
[ 4481.831205]  nl80211_set_pmk+0x183/0x250 [cfg80211]
[ 4481.831233]  genl_family_rcv_msg_doit+0xea/0x150
[ 4481.831237]  genl_rcv_msg+0x104/0x240
[ 4481.831239]  ? cfg80211_probe_status+0x2c0/0x2c0 [cfg80211]
[ 4481.831257]  ? genl_family_rcv_msg_doit+0x150/0x150
[ 4481.831259]  netlink_rcv_skb+0x4e/0x100
[ 4481.831261]  genl_rcv+0x24/0x40
[ 4481.831262]  netlink_unicast+0x236/0x380
[ 4481.831264]  netlink_sendmsg+0x250/0x4b0
[ 4481.831266]  sock_sendmsg+0x5c/0x70
[ 4481.831269]  ____sys_sendmsg+0x236/0x2b0
[ 4481.831271]  ? copy_msghdr_from_user+0x6d/0xa0
[ 4481.831272]  ___sys_sendmsg+0x86/0xd0
[ 4481.831274]  ? avc_has_perm+0x8c/0x1a0
[ 4481.831276]  ? preempt_count_add+0x6a/0xa0
[ 4481.831279]  ? sock_has_perm+0x82/0xa0
[ 4481.831280]  __sys_sendmsg+0x57/0xa0
[ 4481.831282]  do_syscall_64+0x38/0x90
[ 4481.831284]  entry_SYSCALL_64_after_hwframe+0x63/0xcd
[ 4481.831286] RIP: 0033:0x7fd270d369b4

Fixes: 2526ff21aa77 ("brcmfmac: support 4-way handshake offloading for 802.1X")

Signed-off-by: Shelley Yang <shelley.yang@infineon.com>
---
 drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 0b55d445895f..89f61710a210 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -2146,7 +2146,7 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
 				 sme->crypto.akm_suites[0]);
 			return -EINVAL;
 		}
-	} else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
+	} else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_1X_SHA256)) {
 		switch (sme->crypto.akm_suites[0]) {
 		case WLAN_AKM_SUITE_8021X:
 			val = WPA2_AUTH_UNSPECIFIED;
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next] wifi: rtw89: usb: skip ACPI capability check for USB devices
From: Ping-Ke Shih @ 2026-05-25  8:26 UTC (permalink / raw)
  To: linux-wireless; +Cc: sc.lee

From: David Lee <sc.lee@realtek.com>

Skip the ACPI capability check for all USB devices by default,
allowing them to use their default configurations.

For USB dongles, customers will manage their own compliance and
certification. This initial patch focuses on the generic USB skip
infrastructure; specific customer certifications and localized
configurations will be handled by quirks afterward.

Signed-off-by: David Lee <sc.lee@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/regd.c | 24 +++++++++++++++++++++++
 drivers/net/wireless/realtek/rtw89/sar.c  |  4 ++++
 2 files changed, 28 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c
index 28466cb35ea2..14fab6b1a74a 100644
--- a/drivers/net/wireless/realtek/rtw89/regd.c
+++ b/drivers/net/wireless/realtek/rtw89/regd.c
@@ -360,6 +360,7 @@ static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev,
 				   struct wiphy *wiphy)
 {
 	struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
+	bool skip_acpi_dsm = rtwdev->hci.type == RTW89_HCI_TYPE_USB;
 	const struct rtw89_chip_info *chip = rtwdev->chip;
 	struct ieee80211_supported_band *sband;
 	struct rtw89_acpi_dsm_result res = {};
@@ -377,6 +378,9 @@ static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev,
 		return;
 	}
 
+	if (skip_acpi_dsm)
+		return;
+
 	bitmap_fill(regulatory->block_unii4, RTW89_REGD_MAX_COUNTRY_NUM);
 
 	ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_UNII4_SUP, &res);
@@ -426,6 +430,7 @@ static void __rtw89_regd_setup_policy_6ghz(struct rtw89_dev *rtwdev, bool block,
 static void rtw89_regd_setup_policy_6ghz(struct rtw89_dev *rtwdev)
 {
 	struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
+	bool skip_acpi_dsm = rtwdev->hci.type == RTW89_HCI_TYPE_USB;
 	const struct rtw89_acpi_country_code *country;
 	const struct rtw89_acpi_policy_6ghz *ptr;
 	struct rtw89_acpi_dsm_result res = {};
@@ -433,6 +438,9 @@ static void rtw89_regd_setup_policy_6ghz(struct rtw89_dev *rtwdev)
 	int i, j;
 	int ret;
 
+	if (skip_acpi_dsm)
+		return;
+
 	ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6G_BP, &res);
 	if (ret) {
 		rtw89_debug(rtwdev, RTW89_DBG_REGD,
@@ -478,12 +486,16 @@ static void rtw89_regd_setup_policy_6ghz(struct rtw89_dev *rtwdev)
 static void rtw89_regd_setup_policy_6ghz_sp(struct rtw89_dev *rtwdev)
 {
 	struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
+	bool skip_acpi_dsm = rtwdev->hci.type == RTW89_HCI_TYPE_USB;
 	const struct rtw89_acpi_policy_6ghz_sp *ptr;
 	struct rtw89_acpi_dsm_result res = {};
 	bool enable;
 	u8 index;
 	int ret;
 
+	if (skip_acpi_dsm)
+		return;
+
 	ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP, &res);
 	if (ret) {
 		rtw89_debug(rtwdev, RTW89_DBG_REGD,
@@ -524,6 +536,7 @@ static void rtw89_regd_setup_policy_6ghz_sp(struct rtw89_dev *rtwdev)
 static void rtw89_regd_setup_policy_6ghz_vlp(struct rtw89_dev *rtwdev)
 {
 	struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
+	bool skip_acpi_dsm = rtwdev->hci.type == RTW89_HCI_TYPE_USB;
 	const struct rtw89_acpi_policy_6ghz_vlp *ptr = NULL;
 	struct rtw89_acpi_dsm_result res = {};
 	bool enable;
@@ -531,6 +544,9 @@ static void rtw89_regd_setup_policy_6ghz_vlp(struct rtw89_dev *rtwdev)
 	int ret;
 	u8 val;
 
+	if (skip_acpi_dsm)
+		return;
+
 	/* By default, allow 6 GHz VLP on all countries except US and CA. */
 	val = ~(RTW89_ACPI_CONF_6GHZ_VLP_US | RTW89_ACPI_CONF_6GHZ_VLP_CA);
 
@@ -574,6 +590,7 @@ static void rtw89_regd_setup_6ghz(struct rtw89_dev *rtwdev, struct wiphy *wiphy)
 {
 	const struct rtw89_chip_info *chip = rtwdev->chip;
 	bool chip_support_6ghz = chip->support_bands & BIT(NL80211_BAND_6GHZ);
+	bool skip_acpi_dsm = rtwdev->hci.type == RTW89_HCI_TYPE_USB;
 	bool regd_allow_6ghz = chip_support_6ghz;
 	struct ieee80211_supported_band *sband;
 	struct rtw89_acpi_dsm_result res = {};
@@ -583,6 +600,9 @@ static void rtw89_regd_setup_6ghz(struct rtw89_dev *rtwdev, struct wiphy *wiphy)
 	if (!chip_support_6ghz)
 		goto bottom;
 
+	if (skip_acpi_dsm)
+		goto bottom;
+
 	ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6G_DIS, &res);
 	if (ret) {
 		rtw89_debug(rtwdev, RTW89_DBG_REGD,
@@ -661,10 +681,14 @@ const char *rtw89_regd_get_string(enum rtw89_regulation_type regd)
 static void rtw89_regd_setup_reg_rules(struct rtw89_dev *rtwdev)
 {
 	struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
+	bool skip_acpi_dsm = rtwdev->hci.type == RTW89_HCI_TYPE_USB;
 	const struct rtw89_acpi_policy_reg_rules *ptr;
 	struct rtw89_acpi_dsm_result res = {};
 	int ret;
 
+	if (skip_acpi_dsm)
+		return;
+
 	regulatory->txpwr_uk_follow_etsi = true;
 
 	ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_REG_RULES_EN, &res);
diff --git a/drivers/net/wireless/realtek/rtw89/sar.c b/drivers/net/wireless/realtek/rtw89/sar.c
index 7886ffaf5695..6fe3822eb598 100644
--- a/drivers/net/wireless/realtek/rtw89/sar.c
+++ b/drivers/net/wireless/realtek/rtw89/sar.c
@@ -693,6 +693,7 @@ static bool rtw89_tas_rolling_average(struct rtw89_dev *rtwdev)
 
 static void rtw89_tas_init(struct rtw89_dev *rtwdev)
 {
+	bool skip_acpi_dsm = rtwdev->hci.type == RTW89_HCI_TYPE_USB;
 	const struct rtw89_chip_info *chip = rtwdev->chip;
 	struct rtw89_tas_info *tas = &rtwdev->tas;
 	const struct rtw89_acpi_policy_tas *ptr;
@@ -702,6 +703,9 @@ static void rtw89_tas_init(struct rtw89_dev *rtwdev)
 	if (!chip->support_tas)
 		return;
 
+	if (skip_acpi_dsm)
+		return;
+
 	ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_TAS_EN, &res);
 	if (ret) {
 		rtw89_debug(rtwdev, RTW89_DBG_SAR,

base-commit: 6b964941bbfe6e0f18b1a5e008486dbb62df440a
-- 
2.25.1


^ permalink raw reply related

* Re: [PATCH v3 0/7] b43: complete N-PHY rev 8 + radio 2057 rev 8 support
From: Michael Büsch @ 2026-05-25  8:07 UTC (permalink / raw)
  To: Alessio Ferri; +Cc: linux-wireless, b43-dev, linux-kernel
In-Reply-To: <20260524-b43_complete_n_phy_rev_8_radio_2057_rev_8_support-v1-0-cdad2c8526c6@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1272 bytes --]

On Sun, 24 May 2026 23:56:17 +0200
Alessio Ferri <alessio.ferri@mythread.it> wrote:

> Alessio Ferri (7):
>       b43: add firmware mappings and remove comments wondering about rev22 initvals
>       b43: add d11 core revision 0x16 to id table
>       b43: route d11 corerev 22 to 24-bit indirect radio access
>       b43: support radio 2057 rev 8
>       b43: add IPA TX gain table for N-PHY r8 + radio 2057 r8
>       b43: add channel info table for N-PHY r8 + radio 2057 r8
>       b43: add RF power offset for N-PHY r8 + radio 2057 r8
> 
>  drivers/net/wireless/broadcom/b43/main.c        |  22 ++-
>  drivers/net/wireless/broadcom/b43/radio_2057.c  | 230 ++++++++++++++++++++++--
>  drivers/net/wireless/broadcom/b43/tables_nphy.c |  58 ++++++
>  3 files changed, 290 insertions(+), 20 deletions(-)


Looks good and in general low risk because it doesn't change any code
paths of supported hw revisions.
I'd still prefer if somebody could test this change on another supported 2057 radio.
I don't have such a device unfortunately.

Does the D-Link DSL-3580L work with full expected wireless throughput after this change
or are there any remaining known issues?

Acked-by: Michael Büsch <m@bues.ch>

-- 
Michael Büsch
https://bues.ch/

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply

* [PATCH rtw-next 2/2] wifi: rtw89: fw: support scan offload v2 for WiFi 7 chips
From: Ping-Ke Shih @ 2026-05-25  7:07 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <20260525070735.27659-1-pkshih@realtek.com>

The format of scan offload v2 is to extend fields to consider channel
noise as a factor to adjust dwell time of certain channels. Leave empty
for now to ignore this factor.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/core.h | 1 +
 drivers/net/wireless/realtek/rtw89/fw.c   | 9 +++++++--
 drivers/net/wireless/realtek/rtw89/fw.h   | 2 ++
 3 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 27d9a916d58c..8461c3913bcd 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -4908,6 +4908,7 @@ enum rtw89_fw_feature {
 	RTW89_FW_FEATURE_BEACON_FILTER,
 	RTW89_FW_FEATURE_MACID_PAUSE_SLEEP,
 	RTW89_FW_FEATURE_SCAN_OFFLOAD_BE_V0,
+	RTW89_FW_FEATURE_SCAN_OFFLOAD_BE_V1,
 	RTW89_FW_FEATURE_WOW_REASON_V1,
 	RTW89_FW_FEATURE_GROUP(WITH_RFK_PRE_NOTIFY,
 			       RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V0,
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index ecfae90e280b..ed5827cb3732 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -933,6 +933,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = {
 	__CFG_FW_FEAT(RTL8922A, ge, 0, 35, 92, 0, TX_HISTORY_V1),
 	__CFG_FW_FEAT(RTL8922A, ge, 0, 35, 100, 0, SER_POST_RECOVER_DMAC),
 	__CFG_FW_FEAT(RTL8922A, ge, 0, 35, 108, 0, SIM_SER_L0L1_BY_HALT_H2C),
+	__CFG_FW_FEAT(RTL8922A, lt, 0, 35, 109, 1, SCAN_OFFLOAD_BE_V1),
 	__CFG_FW_FEAT(RTL8922D, ge, 0, 0, 0, 0, MACID_PAUSE_SLEEP),
 	__CFG_FW_FEAT(RTL8922D, ge, 0, 35, 75, 2, SCAN_OFFLOAD),
 	__CFG_FW_FEAT(RTL8922D, ge, 0, 35, 75, 2, BEACON_FILTER),
@@ -946,6 +947,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = {
 	__CFG_FW_FEAT(RTL8922D, ge, 0, 35, 100, 0, SER_POST_RECOVER_DMAC),
 	__CFG_FW_FEAT(RTL8922D, ge, 0, 35, 104, 0, TX_HISTORY_V1),
 	__CFG_FW_FEAT(RTL8922D, ge, 0, 35, 108, 0, SIM_SER_L0L1_BY_HALT_H2C),
+	__CFG_FW_FEAT(RTL8922D, lt, 0, 35, 109, 1, SCAN_OFFLOAD_BE_V1),
 };
 
 static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw,
@@ -6831,7 +6833,10 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev,
 
 	rtw89_scan_get_6g_disabled_chan(rtwdev, option);
 
-	if (RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD_BE_V0, &rtwdev->fw)) {
+	if (RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD_BE_V1, &rtwdev->fw)) {
+		cfg_len = offsetofend(typeof(*h2c), w9);
+		scan_offload_ver = 1;
+	} else if (RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD_BE_V0, &rtwdev->fw)) {
 		cfg_len = offsetofend(typeof(*h2c), w8);
 		scan_offload_ver = 0;
 	}
@@ -6910,7 +6915,7 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev,
 	if (scan_offload_ver == 0)
 		goto flex_member;
 
-	h2c->w9 = le32_encode_bits(sizeof(*h2c) / sizeof(h2c->w0),
+	h2c->w9 = le32_encode_bits(cfg_len / sizeof(h2c->w0),
 				   RTW89_H2C_SCANOFLD_BE_W9_SIZE_CFG) |
 		  le32_encode_bits(sizeof(*macc_role) / sizeof(macc_role->w0),
 				   RTW89_H2C_SCANOFLD_BE_W9_SIZE_MACC) |
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index cde8fd34723b..d9e1f27699ed 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -3063,6 +3063,8 @@ struct rtw89_h2c_scanofld_be {
 	__le32 w7;
 	__le32 w8;
 	__le32 w9; /* Added after SCAN_OFFLOAD_BE_V1 */
+	__le32 w10; /* Added after SCAN_OFFLOAD_BE_V2 */
+	__le32 w11; /* Added after SCAN_OFFLOAD_BE_V2 */
 	/* struct rtw89_h2c_scanofld_be_macc_role (flexible number) */
 	/* struct rtw89_h2c_scanofld_be_opch (flexible number) */
 } __packed;
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 1/2] wifi: rtw89: fw: add first set of firmware features by version for RTL8922D
From: Ping-Ke Shih @ 2026-05-25  7:07 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <20260525070735.27659-1-pkshih@realtek.com>

The firmware features including version of command/event format are
maintained by this table, which enables features by firmware version.
Define the first feature set accordingly.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/fw.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index eb5683d64461..ecfae90e280b 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -933,6 +933,19 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = {
 	__CFG_FW_FEAT(RTL8922A, ge, 0, 35, 92, 0, TX_HISTORY_V1),
 	__CFG_FW_FEAT(RTL8922A, ge, 0, 35, 100, 0, SER_POST_RECOVER_DMAC),
 	__CFG_FW_FEAT(RTL8922A, ge, 0, 35, 108, 0, SIM_SER_L0L1_BY_HALT_H2C),
+	__CFG_FW_FEAT(RTL8922D, ge, 0, 0, 0, 0, MACID_PAUSE_SLEEP),
+	__CFG_FW_FEAT(RTL8922D, ge, 0, 35, 75, 2, SCAN_OFFLOAD),
+	__CFG_FW_FEAT(RTL8922D, ge, 0, 35, 75, 2, BEACON_FILTER),
+	__CFG_FW_FEAT(RTL8922D, ge, 0, 35, 76, 0, LPS_DACK_BY_C2H_REG),
+	__CFG_FW_FEAT(RTL8922D, ge, 0, 35, 84, 0, CRASH_TRIGGER_TYPE_1),
+	__CFG_FW_FEAT(RTL8922D, lt, 0, 35, 84, 0, ADDR_CAM_V0),
+	__CFG_FW_FEAT(RTL8922D, ge, 0, 35, 87, 0, BEACON_LOSS_COUNT_V1),
+	__CFG_FW_FEAT(RTL8922D, ge, 0, 35, 91, 0, RFK_PRE_NOTIFY_MCC_V2),
+	__CFG_FW_FEAT(RTL8922D, ge, 0, 35, 91, 4, LPS_ML_INFO_V1),
+	__CFG_FW_FEAT(RTL8922D, ge, 0, 35, 93, 0, NOTIFY_AP_INFO),
+	__CFG_FW_FEAT(RTL8922D, ge, 0, 35, 100, 0, SER_POST_RECOVER_DMAC),
+	__CFG_FW_FEAT(RTL8922D, ge, 0, 35, 104, 0, TX_HISTORY_V1),
+	__CFG_FW_FEAT(RTL8922D, ge, 0, 35, 108, 0, SIM_SER_L0L1_BY_HALT_H2C),
 };
 
 static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw,
-- 
2.25.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