* [PATCH wireless-next 00/28] iwlwifi + mac80211 stability
From: greearb @ 2026-03-11 23:07 UTC (permalink / raw)
To: linux-wireless; +Cc: Ben Greear
From: Ben Greear <greearb@candelatech.com>
mac80211 and iwlwifi stability patches from our internal
tree.
General test case is 40 be200 radios attempting to connect and
run max traffic against an AP that doesn't really like that many
eMLSR stations. Firmware crashes, AP rejections, assoc timeouts,
and other problems are seen often, and that seems to hit a lot
of edge cases. Kernel has kasan, lockdep and other debugging
enabled.
This was primarily tested against 6.18.14 stable kernel, but has been
revised to work against wireless-next and it is passing at least the
first hour of tests so far. Likely some problems still remain in
this area.
checkpatch seems mostly satisfied.
Ben Greear (28):
wifi: iwlwifi: mld: Check for NULL before lookup.
wifi: iwlwifi: mld: Fix un-set return value in error case.
wifi: iwlwifi: mld: Add check for null vif in stats callback.
wifi: mac80211: Check debugfs creation return values.
wifi: mac80211: do not fail taking sta to lower state.
wifi: mac80211: Mark sta as uploaded if single transition succeeds.
wifi: mac80211: Fix use-after-free of debugfs inodes.
wifi: mac80211: Debugfs safety checks.
wifi: mac80211: Use warn-on-once in drv_remove_chanctxt
wifi: mac80211: Ensure sta debugfs is not double-freed.
wifi: iwlwifi: mld: Fix stale reference in fw_id_to_link_sta
wifi: iwlwifi: mld: Improve logging in error cases.
wifi: iwlwifi: mld: Remove warning about BAID.
wifi: mac80211: Add dmesg log regarding warn-on in drv-stop.
wifi: iwlwifi: mld: Fix use-after-free of bss_conf
wifi: iwlwifi: mld: Check for null in iwl_mld_wait_sta_txqs_empty
wifi: iwlwifi: mld: use warn-on-once in error path.
wifi: iwlwifi: mld: Use warn-on-once in emlsr exit logic.
wifi: iwlwifi: mld: Improve error message in rx path.
wifi: iwlwifi: mld: Improve logging message.
wifi: iwlwifi: mld: Protect from null mld_sta
wifi: mac80211: Add force-cleanup call to driver.
wifi: iwlwifi: mld: Support force-cleanup op
wifi: iwlwifi: mld: Fix NPE in flush logic.
wifi: iwlwifi: mld: Fix bad return address in tx code.
wifi: mac80211: Ensure link work-items are only initialized once.
wifi: iwlwifi: mld: Convert to WARN_ONCE in link removal path.
wifi: mac80211: Decrease WARN spam.
drivers/net/wireless/intel/iwlwifi/mld/agg.c | 20 +++-
drivers/net/wireless/intel/iwlwifi/mld/link.c | 42 +++++--
.../net/wireless/intel/iwlwifi/mld/mac80211.c | 21 +++-
drivers/net/wireless/intel/iwlwifi/mld/mlo.c | 5 +-
drivers/net/wireless/intel/iwlwifi/mld/rx.c | 4 +-
drivers/net/wireless/intel/iwlwifi/mld/sta.c | 20 +++-
drivers/net/wireless/intel/iwlwifi/mld/sta.h | 2 +-
.../net/wireless/intel/iwlwifi/mld/stats.c | 2 +-
drivers/net/wireless/intel/iwlwifi/mld/tx.h | 2 +
include/net/mac80211.h | 7 ++
net/mac80211/debugfs.c | 11 ++
net/mac80211/debugfs_key.c | 6 +
net/mac80211/debugfs_netdev.c | 106 +++++++++++++++++-
net/mac80211/debugfs_sta.c | 15 +++
net/mac80211/driver-ops.c | 10 +-
net/mac80211/driver-ops.h | 12 +-
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/link.c | 29 +++--
net/mac80211/sta_info.c | 8 +-
net/mac80211/util.c | 8 +-
20 files changed, 286 insertions(+), 45 deletions(-)
--
2.42.0
^ permalink raw reply
* [PATCH wireless-next 01/28] wifi: iwlwifi: mld: Check for NULL before lookup.
From: greearb @ 2026-03-11 23:07 UTC (permalink / raw)
To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <20260311230730.163348-1-greearb@candelatech.com>
From: Ben Greear <greearb@candelatech.com>
Do not call iwl_mld_sta_from_mac80211(sta) unless we have
verified sta is non NULL.
Signed-off-by: Ben Greear <greearb@candelatech.com>
---
drivers/net/wireless/intel/iwlwifi/mld/agg.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/agg.c b/drivers/net/wireless/intel/iwlwifi/mld/agg.c
index 3bf36f8f6874..a757077b0a7a 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/agg.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/agg.c
@@ -194,7 +194,7 @@ iwl_mld_reorder(struct iwl_mld *mld, struct napi_struct *napi,
struct iwl_mld_baid_data *baid_data;
struct iwl_mld_reorder_buffer *buffer;
struct iwl_mld_reorder_buf_entry *entries;
- struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
+ struct iwl_mld_sta *mld_sta;
struct iwl_mld_link_sta *mld_link_sta;
u32 reorder = le32_to_cpu(desc->reorder_data);
bool amsdu, last_subframe, is_old_sn, is_dup;
@@ -221,6 +221,8 @@ iwl_mld_reorder(struct iwl_mld *mld, struct napi_struct *napi,
"Got valid BAID without a valid station assigned\n"))
return IWL_MLD_PASS_SKB;
+ mld_sta = iwl_mld_sta_from_mac80211(sta);
+
/* not a data packet */
if (!ieee80211_is_data_qos(hdr->frame_control) ||
is_multicast_ether_addr(hdr->addr1))
--
2.42.0
^ permalink raw reply related
* [PATCH wireless-next 03/28] wifi: iwlwifi: mld: Add check for null vif in stats callback.
From: greearb @ 2026-03-11 23:07 UTC (permalink / raw)
To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <20260311230730.163348-1-greearb@candelatech.com>
From: Ben Greear <greearb@candelatech.com>
A crash was seen in this area, protect against null.
Signed-off-by: Ben Greear <greearb@candelatech.com>
---
drivers/net/wireless/intel/iwlwifi/mld/stats.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/stats.c b/drivers/net/wireless/intel/iwlwifi/mld/stats.c
index 7b8709716324..8d6bd7219b94 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/stats.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/stats.c
@@ -415,7 +415,7 @@ iwl_mld_process_per_link_stats(struct iwl_mld *mld,
bss_conf = wiphy_dereference(mld->wiphy,
mld->fw_id_to_bss_conf[fw_id]);
- if (!bss_conf || bss_conf->vif->type != NL80211_IFTYPE_STATION)
+ if (!bss_conf || !bss_conf->vif || bss_conf->vif->type != NL80211_IFTYPE_STATION)
continue;
link_stats = &per_link[fw_id];
--
2.42.0
^ permalink raw reply related
* Re: [PATCH 49/61] media: Prefer IS_ERR_OR_NULL over manual NULL check
From: Kieran Bingham @ 2026-03-11 23:03 UTC (permalink / raw)
To: Philipp Hahn, amd-gfx, apparmor, bpf, ceph-devel, cocci, dm-devel,
dri-devel, gfs2, intel-gfx, intel-wired-lan, iommu, kvm,
linux-arm-kernel, linux-block, linux-bluetooth, linux-btrfs,
linux-cifs, linux-clk, linux-erofs, linux-ext4, linux-fsdevel,
linux-gpio, linux-hyperv, linux-input, linux-kernel, linux-leds,
linux-media, linux-mips, linux-mm, linux-modules, linux-mtd,
linux-nfs, linux-omap, linux-phy, lin
Cc: Shuah Khan, Mauro Carvalho Chehab
In-Reply-To: <20260310-b4-is_err_or_null-v1-49-bd63b656022d@avm.de>
Quoting Philipp Hahn (2026-03-10 11:49:15)
> Prefer using IS_ERR_OR_NULL() over using IS_ERR() and a manual NULL
> check.
>
> Change generated with coccinelle.
>
> To: Shuah Khan <skhan@linuxfoundation.org>
> To: Kieran Bingham <kieran.bingham@ideasonboard.com>
> To: Mauro Carvalho Chehab <mchehab@kernel.org>
> Cc: linux-media@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> Signed-off-by: Philipp Hahn <phahn-oss@avm.de>
> ---
> drivers/media/test-drivers/vimc/vimc-streamer.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/media/test-drivers/vimc/vimc-streamer.c b/drivers/media/test-drivers/vimc/vimc-streamer.c
> index 15d863f97cbf96b7ca7fbf3d7b6b6ec39fcc8ae3..da5aca50bcb4990c06f28e5a883eb398606991e9 100644
> --- a/drivers/media/test-drivers/vimc/vimc-streamer.c
> +++ b/drivers/media/test-drivers/vimc/vimc-streamer.c
> @@ -167,7 +167,7 @@ static int vimc_streamer_thread(void *data)
> for (i = stream->pipe_size - 1; i >= 0; i--) {
> frame = stream->ved_pipeline[i]->process_frame(
> stream->ved_pipeline[i], frame);
> - if (!frame || IS_ERR(frame))
> + if (IS_ERR_OR_NULL(frame))
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> break;
> }
> //wait for 60hz
>
> --
> 2.43.0
>
^ permalink raw reply
* Re: [PATCH v3 19/21] wifi: rtl8xxxu: add hw crypto support for AP mode
From: Bitterblue Smith @ 2026-03-11 22:16 UTC (permalink / raw)
To: Ping-Ke Shih, Martin Kaistra, linux-wireless@vger.kernel.org
Cc: Jes Sorensen, Sebastian Andrzej Siewior
In-Reply-To: <deb687c2fd62467ebcf139acd8aae9c0@realtek.com>
On 11/03/2026 04:38, Ping-Ke Shih wrote:
> Bitterblue Smith <rtl8821cerfe2@gmail.com> wrote:
>> On 25/02/2026 04:28, Ping-Ke Shih wrote:
>>> Martin Kaistra <martin.kaistra@linutronix.de> wrote:
>>>> Am 21.02.26 um 23:09 schrieb Bitterblue Smith:
>>>>> On 22/12/2023 12:14, Martin Kaistra wrote:
>>>>>> Add a custom function for allocating entries in the sec cam. This allows
>>>>>> us to store multiple keys with the same keyidx.
>>>>>>
>>>>>> The maximum number of sec cam entries for 8188f is 16 according to the
>>>>>> vendor driver. Add the number to rtl8xxxu_fileops, so that other chips
>>>>>> which might support more entries, can set a different number there.
>>>>>>
>>>>>> Set the bssid as mac address for group keys instead of just using the
>>>>>> ethernet broadcast address and use BIT(6) in the sec cam ctrl entry
>>>>>> for differentiating them from pairwise keys like in the vendor driver.
>>>>>>
>>>>>> Add the TXDESC_EN_DESC_ID bit and the hw_key_idx to tx
>>>>>> broadcast/multicast packets in AP mode.
>>>>>>
>>>>>> Finally, allow the usage of rtl8xxxu_set_key() for AP mode.
>>>>>>
>>>>>> Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
>>>>>> Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
>>>>>> ---
>>>>>> .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 5 ++
>>>>>> .../realtek/rtl8xxxu/rtl8xxxu_8188f.c | 1 +
>>>>>> .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 48 +++++++++++++++----
>>>>>> 3 files changed, 44 insertions(+), 10 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
>>>> b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
>>>>>> index c5e6d8f7d26bd..62e6318bc0924 100644
>>>>>> --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
>>>>>> +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
>>>>>> @@ -498,6 +498,7 @@ struct rtl8xxxu_txdesc40 {
>>>>>> #define DESC_RATE_ID_SHIFT 16
>>>>>> #define DESC_RATE_ID_MASK 0xf
>>>>>> #define TXDESC_NAVUSEHDR BIT(20)
>>>>>> +#define TXDESC_EN_DESC_ID BIT(21)
>>>>>> #define TXDESC_SEC_RC4 0x00400000
>>>>>> #define TXDESC_SEC_AES 0x00c00000
>>>>>> #define TXDESC_PKT_OFFSET_SHIFT 26
>>>>>> @@ -1775,6 +1776,7 @@ struct rtl8xxxu_cfo_tracking {
>>>>>> #define RTL8XXXU_MAX_MAC_ID_NUM 128
>>>>>> #define RTL8XXXU_BC_MC_MACID 0
>>>>>> #define RTL8XXXU_BC_MC_MACID1 1
>>>>>> +#define RTL8XXXU_MAX_SEC_CAM_NUM 64
>>>>>>
>>>>>> struct rtl8xxxu_priv {
>>>>>> struct ieee80211_hw *hw;
>>>>>> @@ -1908,6 +1910,7 @@ struct rtl8xxxu_priv {
>>>>>> char led_name[32];
>>>>>> struct led_classdev led_cdev;
>>>>>> DECLARE_BITMAP(mac_id_map, RTL8XXXU_MAX_MAC_ID_NUM);
>>>>>> + DECLARE_BITMAP(cam_map, RTL8XXXU_MAX_SEC_CAM_NUM);
>>>>>> };
>>>>>>
>>>>>> struct rtl8xxxu_sta_info {
>>>>>> @@ -1919,6 +1922,7 @@ struct rtl8xxxu_sta_info {
>>>>>>
>>>>>> struct rtl8xxxu_vif {
>>>>>> int port_num;
>>>>>> + u8 hw_key_idx;
>>>>>> };
>>>>>>
>>>>>> struct rtl8xxxu_rx_urb {
>>>>>> @@ -1993,6 +1997,7 @@ struct rtl8xxxu_fileops {
>>>>>> u16 max_aggr_num;
>>>>>> u8 supports_ap:1;
>>>>>> u16 max_macid_num;
>>>>>> + u16 max_sec_cam_num;
>>>>>> u32 adda_1t_init;
>>>>>> u32 adda_1t_path_on;
>>>>>> u32 adda_2t_path_on_a;
>>>>>> diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c
>>>> b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c
>>>>>> index 1e1c8fa194cb8..574a5fe951543 100644
>>>>>> --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c
>>>>>> +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c
>>>>>> @@ -1751,6 +1751,7 @@ struct rtl8xxxu_fileops rtl8188fu_fops = {
>>>>>> .max_aggr_num = 0x0c14,
>>>>>> .supports_ap = 1,
>>>>>> .max_macid_num = 16,
>>>>>> + .max_sec_cam_num = 16,
>>>>>> .adda_1t_init = 0x03c00014,
>>>>>> .adda_1t_path_on = 0x03c00014,
>>>>>> .trxff_boundary = 0x3f7f,
>>>>>> diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
>>>> b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
>>>>>> index ecf54eb8dba61..7aafae9fe76b8 100644
>>>>>> --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
>>>>>> +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
>>>>>> @@ -4559,8 +4559,10 @@ static void rtl8xxxu_cam_write(struct rtl8xxxu_priv
>> *priv,
>>>>>> * This is a bit of a hack - the lower bits of the cipher
>>>>>> * suite selector happens to match the cipher index in the CAM
>>>>>> */
>>>>>> - addr = key->keyidx << CAM_CMD_KEY_SHIFT;
>>>>>> + addr = key->hw_key_idx << CAM_CMD_KEY_SHIFT;
>>>>>> ctrl = (key->cipher & 0x0f) << 2 | key->keyidx | CAM_WRITE_VALID;
>>>>>> + if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
>>>>>> + ctrl |= BIT(6);
>>>>>>
>>>>>> for (j = 5; j >= 0; j--) {
>>>>>> switch (j) {
>>>>>> @@ -5546,13 +5548,14 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw,
>>>>>> struct rtl8xxxu_tx_urb *tx_urb;
>>>>>> struct ieee80211_sta *sta = NULL;
>>>>>> struct ieee80211_vif *vif = tx_info->control.vif;
>>>>>> + struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv;
>>>>>> struct device *dev = &priv->udev->dev;
>>>>>> u32 queue, rts_rate;
>>>>>> u16 pktlen = skb->len;
>>>>>> int tx_desc_size = priv->fops->tx_desc_size;
>>>>>> u8 macid;
>>>>>> int ret;
>>>>>> - bool ampdu_enable, sgi = false, short_preamble = false;
>>>>>> + bool ampdu_enable, sgi = false, short_preamble = false, bmc = false;
>>>>>>
>>>>>> if (skb_headroom(skb) < tx_desc_size) {
>>>>>> dev_warn(dev,
>>>>>> @@ -5594,10 +5597,14 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw,
>>>>>> tx_desc->txdw0 =
>>>>>> TXDESC_OWN | TXDESC_FIRST_SEGMENT |
>> TXDESC_LAST_SEGMENT;
>>>>>> if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) ||
>>>>>> - is_broadcast_ether_addr(ieee80211_get_DA(hdr)))
>>>>>> + is_broadcast_ether_addr(ieee80211_get_DA(hdr))) {
>>>>>> tx_desc->txdw0 |= TXDESC_BROADMULTICAST;
>>>>>> + bmc = true;
>>>>>> + }
>>>>>> +
>>>>>>
>>>>>> tx_desc->txdw1 = cpu_to_le32(queue << TXDESC_QUEUE_SHIFT);
>>>>>> + macid = rtl8xxxu_get_macid(priv, sta);
>>>>>>
>>>>>> if (tx_info->control.hw_key) {
>>>>>> switch (tx_info->control.hw_key->cipher) {
>>>>>> @@ -5612,6 +5619,10 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw,
>>>>>> default:
>>>>>> break;
>>>>>> }
>>>>>> + if (bmc && rtlvif->hw_key_idx != 0xff) {
>>>>>> + tx_desc->txdw1 |= TXDESC_EN_DESC_ID;
>>>>>> + macid = rtlvif->hw_key_idx;
>>>>>> + }
>>>>>> }
>>>>>>
>>>>>> /* (tx_info->flags & IEEE80211_TX_CTL_AMPDU) && */
>>>>>> @@ -5655,7 +5666,6 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw,
>>>>>> else
>>>>>> rts_rate = 0;
>>>>>>
>>>>>> - macid = rtl8xxxu_get_macid(priv, sta);
>>>>>> priv->fops->fill_txdesc(hw, hdr, tx_info, tx_desc, sgi,
>> short_preamble,
>>>>>> ampdu_enable, rts_rate, macid);
>>>>>>
>>>>>> @@ -6667,6 +6677,7 @@ static int rtl8xxxu_add_interface(struct ieee80211_hw
>> *hw,
>>>>>>
>>>>>> priv->vifs[port_num] = vif;
>>>>>> rtlvif->port_num = port_num;
>>>>>> + rtlvif->hw_key_idx = 0xff;
>>>>>>
>>>>>> rtl8xxxu_set_linktype(priv, vif->type, port_num);
>>>>>> ether_addr_copy(priv->mac_addr, vif->addr);
>>>>>> @@ -6843,11 +6854,19 @@ static int rtl8xxxu_set_rts_threshold(struct
>> ieee80211_hw *hw, u32 rts)
>>>>>> return 0;
>>>>>> }
>>>>>>
>>>>>> +static int rtl8xxxu_get_free_sec_cam(struct ieee80211_hw *hw)
>>>>>> +{
>>>>>> + struct rtl8xxxu_priv *priv = hw->priv;
>>>>>> +
>>>>>> + return find_first_zero_bit(priv->cam_map,
>> priv->fops->max_sec_cam_num);
>>>>>> +}
>>>>>> +
>>>>>> static int rtl8xxxu_set_key(struct ieee80211_hw *hw, enum set_key_cmd
>> cmd,
>>>>>> struct ieee80211_vif *vif,
>>>>>> struct ieee80211_sta *sta,
>>>>>> struct ieee80211_key_conf *key)
>>>>>> {
>>>>>> + struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv;
>>>>>> struct rtl8xxxu_priv *priv = hw->priv;
>>>>>> struct device *dev = &priv->udev->dev;
>>>>>> u8 mac_addr[ETH_ALEN];
>>>>>> @@ -6859,9 +6878,6 @@ static int rtl8xxxu_set_key(struct ieee80211_hw *hw,
>> enum set_key_cmd cmd,
>>>>>> dev_dbg(dev, "%s: cmd %02x, cipher %08x, index %i\n",
>>>>>> __func__, cmd, key->cipher, key->keyidx);
>>>>>>
>>>>>> - if (vif->type != NL80211_IFTYPE_STATION)
>>>>>> - return -EOPNOTSUPP;
>>>>>> -
>>>>>> if (key->keyidx > 3)
>>>>>> return -EOPNOTSUPP;
>>>>>>
>>>>>> @@ -6885,7 +6901,7 @@ static int rtl8xxxu_set_key(struct ieee80211_hw *hw,
>> enum set_key_cmd cmd,
>>>>>> ether_addr_copy(mac_addr, sta->addr);
>>>>>> } else {
>>>>>> dev_dbg(dev, "%s: group key\n", __func__);
>>>>>> - eth_broadcast_addr(mac_addr);
>>>>>> + ether_addr_copy(mac_addr, vif->bss_conf.bssid);
>>>>>> }
>>>>>>
>>>>>> val16 = rtl8xxxu_read16(priv, REG_CR);
>>>>>> @@ -6899,16 +6915,28 @@ static int rtl8xxxu_set_key(struct ieee80211_hw *hw,
>> enum set_key_cmd cmd,
>>>>>>
>>>>>> switch (cmd) {
>>>>>> case SET_KEY:
>>>>>> - key->hw_key_idx = key->keyidx;
>>>>>> +
>>>>>> + retval = rtl8xxxu_get_free_sec_cam(hw);
>>>>>> + if (retval < 0)
>>>>>> + return -EOPNOTSUPP;
>>>>>> +
>>>>>> + key->hw_key_idx = retval;
>>>>>> +
>>>>>> + if (vif->type == NL80211_IFTYPE_AP && !(key->flags &
>> IEEE80211_KEY_FLAG_PAIRWISE))
>>>>>> + rtlvif->hw_key_idx = key->hw_key_idx;
>>>>>> +
>>>>>> key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
>>>>>> rtl8xxxu_cam_write(priv, key, mac_addr);
>>>>>> + set_bit(key->hw_key_idx, priv->cam_map);
>>>>>
>>>>> Hi Martin,
>>>>
>>>> Hi Bitterblue,
>>>>
>>>>>
>>>>> It turns out RTL8188CUS and RTL8192CU don't like this patch, specifically
>>>>> when we use iwd. After the WPA2 handshake no more data is transmitted.
>>>>>
>>>>> Before this patch, key->hw_key_idx was the same as key->keyidx. After
>>>>> this patch, when we use iwd, the group key is installed first. It has
>>>>> key->keyidx = 1, but it gets key->hw_key_idx = 0. The pairwise key is
>>>>> installed second. It has key->keyidx = 0, but it gets key->hw_key_idx = 1.
>>>>> Both keyidx and hw_key_idx are passed to the chip in rtl8xxxu_cam_write().
>>>>>
>>>>> It's fine with wpa_supplicant. wpa_supplicant installs the pairwise key
>>>>> first, with key->keyidx = 0, then the group key, with key->keyidx = 1.
>>>>>
>>>>> This patch imitating rtw88 makes the old chips work again with iwd.
>>>>> What do you think?
>>>>
>>>> So you reserve the first 4 entries for group keys and use key->keyidx as
>>>> key->hw_key_idx directly for those, right? Does that work if 2 virtual
>>>> interfaces are used at the same time?
>>>> I will do some tests in the next days, but I suspect this be an issue.
>>>
>>> Ah. I'm not aware that rtl8xxxu can support 2 virtual interfaces, and
>>> only RTL8188FU declares .supports_concurrent = 1, so maybe we can have
>>> special handling for this chip?
>>
>> I would like to enable supports_concurrent for more chips, if I can test
>> this feature.
>>
>>>
>>> I'd share some information about security CAM for reference. Since data is
>>> quite old (10+ years), I can't guarantee all are correct.
>>>
>>> 1. default key switch in rtl8xxxu_set_key()
>>> SEC_CFG_TXBC_USE_DEFKEY and SEC_CFG_RXBC_USE_DEFKEY mean that
>>> broadcast/multicast packets use default key (CAM entries 0~3 for
>>> keyidx 0~3).
>>> For two interfaces case, that'd a problem, so maybe we should use
>>> software encryption/decryption for non-pairwise key.
>>>
>>> val8 = SEC_CFG_TX_SEC_ENABLE | SEC_CFG_TXBC_USE_DEFKEY |
>>> SEC_CFG_RX_SEC_ENABLE | SEC_CFG_RXBC_USE_DEFKEY;
>>> val8 |= SEC_CFG_TX_USE_DEFKEY | SEC_CFG_RX_USE_DEFKEY;
>>> rtl8xxxu_write8(priv, REG_SECURITY_CFG, val8);
>>>
>>> 2. group key (GK) field of security CAM in rtl8xxxu_cam_write()
>>> The group key field of security CAM is BIT(6) which isn't supported
>>> by earlier chips (sorry I have no data about the exact chips).
>>>
>>
>> BIT 6 is used in the rtl8188eu driver, and not used in the rtl8192cu driver,
>> so I assume it's just the older RTL8188CU/RTL8192CU and RTL8723AU that don't
>> support it.
>>
>>> If a chip can support group key field, the CAM layout with default key
>>> enabled for two interfaces (STA-1+AP-1) can be
>>>
>>> STA-1 <-> AP-10
>>> AP-1 <-> STA-20
>>>
>>> CAM GK MAC KEY
>>> 0
>>> 1 1 00: AP-1 (GTK) // should be on entry 0~3 depends on key_idx
>>> 2
>>> 3
>>> 4
>>> 5 1 AP-10 AP-10 (GTK) // can be on any entry after 4
>>> 6
>>>
>>
>> What are the numbers 1, 10, and 20 in "AP-1", "AP-10", "STA-20" ?
>
> Just represent different roles.
>
> For rtl8xxxu, two interfaces are STA-1 and AP-1, and STA-1 connect to AP-10,
> and AP-1 is connected from STA-20.
>
> I don't add pairwise key to above example, because it is simple, just one
> entry to a PTK. Instead, I only list group key in the example.
>
> For AP role (AP-1), it can send broadcast packets to many stations, so
> use default key.
> (but it should not receive a broadcast packet from stations)
>
> For station role (STA-1), it should receive broadcast packets from
> specific AP-10, so add an entry with AP-10's MAC address.
>
Oh, now I understand, thank you.
>>
>>> (pairwise key can be on any entry after 4)
>>>
>>> if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
>>> ctrl |= BIT(6);
>>>
>>> My perspective are
>>> 1. currently default key is enabled, so we should treat CAM entry 0~3 as
>>> special cases. That means rtl8xxxu_get_free_sec_cam() should be modified
>>> as Bitterblue's version.
>>>
>>> 2. For two interfaces, I guess RTL8188FU can support GK bit, so it'd be worth
>>> to try the method of example 2 above.
>>>
>>> If we want earlier chips can support two interfaces, I think we should
>>> disable default key.
>>
>> Indeed, the rtl8192cu driver (out of kernel) doesn't set SEC_CFG_TXBC_USE_DEFKEY
>> and SEC_CFG_RXBC_USE_DEFKEY when concurrent mode is enabled.
>>
>>> Seemingly, it is not possible that using hardware
>>> crypto when operating one interface and then switching to use software>
>> crypto when operating two interfaces. That means broadcast/multicast
>>> packets should be by software crypto entirely if we want to support two
>>> interfaces.
>>>
>>> 3. I think rtw88 has similar problem for two interfaces.
>>>
>>>>
>>>>>
>>>>> diff --git a/drivers/net/wireless/realtek/rtl8xxxu/core.c
>>>> b/drivers/net/wireless/realtek/rtl8xxxu/core.c
>>>>> index ee278f0548e4..f7b35655bec5 100644
>>>>> --- a/drivers/net/wireless/realtek/rtl8xxxu/core.c
>>>>> +++ b/drivers/net/wireless/realtek/rtl8xxxu/core.c
>>>>> @@ -6942,7 +6942,8 @@ static int rtl8xxxu_get_free_sec_cam(struct
>> ieee80211_hw *hw)
>>>>> {
>>>>> struct rtl8xxxu_priv *priv = hw->priv;
>>>>>
>>>>> - return find_first_zero_bit(priv->cam_map,
>> priv->fops->max_sec_cam_num);
>>>>> + return find_next_zero_bit(priv->cam_map,
>> priv->fops->max_sec_cam_num,
>>>>> + RTL8XXXU_SEC_DEFAULT_KEY_NUM);
>>>>> }
>>>>>
>>>>> static int rtl8xxxu_set_key(struct ieee80211_hw *hw, enum set_key_cmd
>> cmd,
>>>>> @@ -6999,12 +7000,15 @@ static int rtl8xxxu_set_key(struct ieee80211_hw *hw,
>> enum set_key_cmd cmd,
>>>>>
>>>>> switch (cmd) {
>>>>> case SET_KEY:
>>>>> + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
>>>>> + retval = rtl8xxxu_get_free_sec_cam(hw);
>>>>> + if (retval < 0)
>>>>> + return -EOPNOTSUPP;
>>>>>
>>>>> - retval = rtl8xxxu_get_free_sec_cam(hw);
>>>>> - if (retval < 0)
>>>>> - return -EOPNOTSUPP;
>>>>> -
>>>>> - key->hw_key_idx = retval;
>>>>> + key->hw_key_idx = retval;
>>>>> + } else {
>>>>> + key->hw_key_idx = key->keyidx;
>>>>> + }
>>>>>
>>>>> if (vif->type == NL80211_IFTYPE_AP && !(key->flags &
>> IEEE80211_KEY_FLAG_PAIRWISE))
>>>>> rtlvif->hw_key_idx = key->hw_key_idx;
>>>>> diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
>>>> b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
>>>>> index 4b05dba22e67..188f4bbe99cd 100644
>>>>> --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
>>>>> +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
>>>>> @@ -1788,6 +1788,7 @@ struct rtl8xxxu_cfo_tracking {
>>>>> #define RTL8XXXU_BC_MC_MACID 0
>>>>> #define RTL8XXXU_BC_MC_MACID1 1
>>>>> #define RTL8XXXU_MAX_SEC_CAM_NUM 64
>>>>> +#define RTL8XXXU_SEC_DEFAULT_KEY_NUM 4
>>>>>
>>>>> struct rtl8xxxu_priv {
>>>>> struct ieee80211_hw *hw;
>>>
>
^ permalink raw reply
* Re: [PATCH 1/2] mt76: connac: fix txpower_cur not updated in mt76_connac_mcu_set_rate_txpower()
From: bryam vargas @ 2026-03-11 20:58 UTC (permalink / raw)
To: Sean Wang
Cc: linux-wireless, nbd, lorenzo,
moderated list:ARM/Mediatek SoC support
In-Reply-To: <CANAPQzgD312EPSbvaQTE6U+wn85L65+xZHms7DP509ApxWvSZA@mail.gmail.com>
From 9fabc33e722f321b4048ada6d4667ddacbb1495a Mon Sep 17 00:00:00 2001
From: bryam <bryamestebanvargas@gmail.com>
Date: Mon, 9 Mar 2026 12:25:37 -0500
Subject: [PATCH v2 2/2] mt76: mt7921u: trigger USB reset only on wfsys timeout
Instead of unconditionally scheduling a USB device reset at the start
of the reset sequence, trigger it only when mt792xu_wfsys_reset()
returns -ETIMEDOUT, which indicates the chip is in a latched state
(SEFI - Single Event Functional Interrupt) where register writes over
USB become silent no-ops.
This avoids the race condition where usb_queue_reset_device() was
scheduled asynchronously while the driver continued normal reset
operations on the same device.
Tested-on: Minisforum NAB9 (MT7921U USB adapter) at 2400m altitude,
Bogota, Colombia. Cosmic radiation causes periodic SEFI
events; USB reset restores connectivity without intervention.
Signed-off-by: Bryam Vargas <bryamestebanvargas@gmail.com>
---
.../net/wireless/mediatek/mt76/mt7921/usb.c | 32 +++++++++----------
.../net/wireless/mediatek/mt76/mt792x_usb.c | 16 ++++------
2 files changed, 23 insertions(+), 25 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
index 8c8c78f..44c7437 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
@@ -86,33 +86,33 @@ static int mt7921u_mcu_init(struct mt792x_dev *dev)
static int mt7921u_mac_reset(struct mt792x_dev *dev)
{
- struct usb_interface *intf = to_usb_interface(dev->mt76.dev);
int err;
mt76_txq_schedule_all(&dev->mphy);
mt76_worker_disable(&dev->mt76.tx_worker);
-
set_bit(MT76_RESET, &dev->mphy.state);
set_bit(MT76_MCU_RESET, &dev->mphy.state);
-
wake_up(&dev->mt76.mcu.wait);
skb_queue_purge(&dev->mt76.mcu.res_q);
-
mt76u_stop_rx(&dev->mt76);
mt76u_stop_tx(&dev->mt76);
- /* When the chip enters a latched state (SEFI - Single Event
- * Functional Interrupt, e.g. from cosmic radiation at altitude),
- * all register writes over USB become silent no-ops.
- * usb_queue_reset_device() electrically resets the chip via the
- * USB hub regardless of internal state -- identical to probe().
- * Async variant required to avoid deadlock in workqueue context.
- */
- dev_warn(dev->mt76.dev,
- "mt7921u: scheduling USB reset for chip recovery\n");
- usb_queue_reset_device(intf);
-
- mt792xu_wfsys_reset(dev);
+ err = mt792xu_wfsys_reset(dev);
+ if (err == -ETIMEDOUT) {
+ /* Chip is in a latched state (SEFI - Single Event Functional
+ * Interrupt, e.g. from cosmic radiation at altitude).
+ * Register writes over USB become silent no-ops; schedule an
+ * electrical USB reset via the hub as last resort.
+ * usb_queue_reset_device() is async to avoid deadlock in
+ * workqueue context.
+ */
+ struct usb_interface *intf = to_usb_interface(dev->mt76.dev);
+
+ dev_warn(dev->mt76.dev,
+ "mt7921u: wfsys reset timed out, scheduling USB reset\n");
+ usb_queue_reset_device(intf);
+ goto out;
+ }
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
err = mt76u_resume_rx(&dev->mt76);
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
index cfd385e..4737384 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
@@ -269,7 +269,6 @@ EXPORT_SYMBOL_GPL(mt792xu_wfsys_reset);
int mt792xu_init_reset(struct mt792x_dev *dev)
{
- struct usb_interface *intf = to_usb_interface(dev->mt76.dev);
set_bit(MT76_RESET, &dev->mphy.state);
@@ -279,15 +278,14 @@ int mt792xu_init_reset(struct mt792x_dev *dev)
mt76u_stop_rx(&dev->mt76);
mt76u_stop_tx(&dev->mt76);
- /* Same rationale as mt7921u_mac_reset(): if the chip is in a
- * latched state (SEFI), register writes over USB are no-ops.
- * Schedule a USB port reset before software reset sequence.
- */
- dev_warn(dev->mt76.dev,
- "mt7921u: scheduling USB device reset (init_reset path)\n");
- usb_queue_reset_device(intf);
+ if (mt792xu_wfsys_reset(dev) == -ETIMEDOUT) {
+ struct usb_interface *intf = to_usb_interface(dev->mt76.dev);
+
+ dev_warn(dev->mt76.dev,
+ "mt792xu: wfsys reset timed out, scheduling USB reset\n");
+ usb_queue_reset_device(intf);
+ }
- mt792xu_wfsys_reset(dev);
clear_bit(MT76_RESET, &dev->mphy.state);
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 1/2] mt76: connac: fix txpower_cur not updated in mt76_connac_mcu_set_rate_txpower()
From: bryam vargas @ 2026-03-11 20:57 UTC (permalink / raw)
To: Sean Wang
Cc: linux-wireless, nbd, lorenzo,
moderated list:ARM/Mediatek SoC support
In-Reply-To: <CANAPQzgiE1rMP3F=5NJg3hp2uBXtq44+vTRBdkHwdfHyXJ8MQQ@mail.gmail.com>
From 6c75ad481f0c3667d6ae2a2c8f7c2df08b1d52b5 Mon Sep 17 00:00:00 2001
From: bryam <bryamestebanvargas@gmail.com>
Date: Mon, 9 Mar 2026 11:52:53 -0500
Subject: [PATCH v2 1/2] mt76: mt7921: add mt7921-specific get_txpower callback
Instead of updating txpower_cur in the write path
(mt76_connac_mcu_set_rate_txpower), implement a mt7921-specific
.get_txpower callback that derives the reported TX power directly
from the SKU limits at query time.
This avoids mixing write-side configuration with reporting logic.
The callback uses mt76_get_power_bound() for SAR constraints and
chain delta, then mt76_get_rate_power_limits() for per-rate EEPROM
limits, yielding the actual TX power value.
Fixes: 3b4a3bdba808 ("mt76: mt7921: add support for reporting tx power")
Signed-off-by: Bryam Vargas <bryamestebanvargas@gmail.com>
---
.../net/wireless/mediatek/mt76/mt7921/main.c | 27 ++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index 67383c4..35454e5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -1517,6 +1517,31 @@ static void mt7921_rfkill_poll(struct ieee80211_hw *hw)
wiphy_rfkill_set_hw_state(hw->wiphy, ret ? false : true);
}
+
+static int mt7921_get_txpower(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, int *dbm)
+{
+ struct mt76_phy *phy = mt76_vif_phy(hw, vif);
+ struct mt76_power_limits limits;
+ int n_chains, delta;
+ s8 tx_power;
+
+ if (!phy)
+ return -EINVAL;
+
+ if (!phy->chandef.chan)
+ return mt76_get_txpower(hw, vif, link_id, dbm);
+
+ n_chains = hweight16(phy->chainmask);
+ delta = mt76_tx_power_path_delta(n_chains);
+ tx_power = mt76_get_power_bound(phy, phy->chandef.chan->max_power);
+ tx_power = mt76_get_rate_power_limits(phy, phy->chandef.chan,
+ &limits, tx_power);
+ *dbm = DIV_ROUND_UP(tx_power + delta, 2);
+ return 0;
+}
+
const struct ieee80211_ops mt7921_ops = {
.tx = mt792x_tx,
.start = mt7921_start,
@@ -1541,7 +1566,7 @@ const struct ieee80211_ops mt7921_ops = {
.wake_tx_queue = mt76_wake_tx_queue,
.release_buffered_frames = mt76_release_buffered_frames,
.channel_switch_beacon = mt7921_channel_switch_beacon,
- .get_txpower = mt76_get_txpower,
+ .get_txpower = mt7921_get_txpower,
.get_stats = mt792x_get_stats,
.get_et_sset_count = mt792x_get_et_sset_count,
.get_et_strings = mt792x_get_et_strings,
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 1/2] mt76: connac: fix txpower_cur not updated in mt76_connac_mcu_set_rate_txpower()
From: bryam vargas @ 2026-03-11 20:55 UTC (permalink / raw)
To: Sean Wang
Cc: linux-wireless, nbd, lorenzo,
moderated list:ARM/Mediatek SoC support
In-Reply-To: <CANAPQzjiBf8Rqphn2SypYN2O6bddj6vB=63Mp=T5YVEt2oGvyw@mail.gmail.com>
Changes in v2:
- patch 1: implement mt7921-specific .get_txpower callback instead of
updating txpower_cur in the write path, as suggested by Sean Wang
- patch 2: trigger USB reset only when mt792xu_wfsys_reset() returns
-ETIMEDOUT, avoiding the race condition with async
usb_queue_reset_device(), as suggested by Sean Wang
Both patches compile clean against v6.18 and tested for two days on
MT7921U USB at 2400m altitude (Bogotá, Colombia).
Bryam Vargas (2):
mt76: mt7921: add mt7921-specific get_txpower callback
mt76: mt7921u: trigger USB reset only on wfsys timeout
^ permalink raw reply
* [PATCH] dt-bindings: net: wireless: marvell,sd8787: Relax length constraints
From: Fabio Estevam @ 2026-03-11 19:45 UTC (permalink / raw)
To: johannes
Cc: robh, krzk+dt, conor+dt, briannorris, Frank.Li, kvalo,
linux-wireless, devicetree, linux-kernel, Fabio Estevam
Commit 31ed9d9d71ec ("ARM: dts: rockchip: Limit WiFi TX power on
rk3288-veyron-jerry") added calibration data for the rk3288-veyron-jerry
platform. The commit message explicitly notes that "the length can vary
between hw versions", as documented in the original text binding.
The current YAML schema enforces fixed maximum lengths for calibration
data arrays, which causes dtbs_check warnings for rk3288-veyron-jerry.dts.
Relax the constraints for the two properties that have
variable-length data in this platform by adding minItems based on the
actual data used in the downstream kernel:
- marvell,caldata-txpwrlimit-2g: 508 bytes (from rk3288-veyron-jerry.dts)
- marvell,caldata-txpwrlimit-5g-sub2: 744 bytes (from
rk3288-veyron-jerry.dts)
The original maxItems values are preserved as upper bounds to maintain
validation for other platforms while accommodating this specific
hardware variant.
Fixes: 25f855413885 ("dt-bindings: net: wireless: convert marvel-8xxx.txt to yaml format")
Signed-off-by: Fabio Estevam <festevam@gmail.com>
---
.../devicetree/bindings/net/wireless/marvell,sd8787.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/net/wireless/marvell,sd8787.yaml b/Documentation/devicetree/bindings/net/wireless/marvell,sd8787.yaml
index 930b700b73d0..0d5b4274f151 100644
--- a/Documentation/devicetree/bindings/net/wireless/marvell,sd8787.yaml
+++ b/Documentation/devicetree/bindings/net/wireless/marvell,sd8787.yaml
@@ -37,6 +37,7 @@ properties:
marvell,caldata-txpwrlimit-2g:
$ref: /schemas/types.yaml#/definitions/uint8-array
description: Calibration data for the 2GHz band.
+ minItems: 508
maxItems: 566
marvell,caldata-txpwrlimit-5g-sub0:
@@ -52,6 +53,7 @@ properties:
marvell,caldata-txpwrlimit-5g-sub2:
$ref: /schemas/types.yaml#/definitions/uint8-array
description: Calibration data for sub-band 2 in the 5GHz band.
+ minItems: 316
maxItems: 750
marvell,caldata-txpwrlimit-5g-sub3:
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 00/18] wifi: mt76: mt7925: add MT7927 (Filogic 380) support
From: Shengyu Qu @ 2026-03-11 18:50 UTC (permalink / raw)
To: Sean Wang, Javier Tia
Cc: wiagn233, linux-wireless, Felix Fietkau, Lorenzo Bianconi,
Ryder Lee, Shayne Chen, Sean Wang, Matthias Brugger,
AngeloGioacchino Del Regno, Deren Wu, Ming Yen Hsieh,
linux-kernel, linux-arm-kernel, linux-mediatek, Marcin FM,
Cristian-Florin Radoi, George Salukvadze, Evgeny Kapusta,
Samu Toljamo, Ariel Rosenfeld, Chapuis Dario,
Thibaut François, 张旭涵
In-Reply-To: <CAGp9Lzq1motdBxa9uk59Nhx0rxt4XJAp5OynpWVsB_sAm6Lx8Q@mail.gmail.com>
[-- Attachment #1.1.1: Type: text/plain, Size: 10307 bytes --]
Hello Sean,
Could you upload the firmware of this chip to linux-firmware repo? Also
could you(or someone who is more familiar with this chip) do a deep
review of these code? This series is heavily AI-assisted when
developing, so there might be some hidden bugs or something else that
haven't been discovered.
Best regards,
Shengyu
在 2026/3/7 15:08, Sean Wang 写道:
> Hi Javier,
>
> On Fri, Mar 6, 2026 at 6:33 PM Javier Tia <floss@jetm.me> wrote:
>>
>> This series adds support for the MediaTek MT7927 (Filogic 380) combo
>> WiFi 7 + BT 5.4 module to the mt7925 driver. The MT7927 uses PCI ID
>> 14c3:7927 (some hardware reports 14c3:6639) and shares the mt7925
>> firmware interface but requires different DMA ring layout, IRQ mapping,
>> chip initialization, and power management handling.
>>
>> Tested hardware:
>> - ASUS ROG Crosshair X870E Hero (BT 0489:e13a, WiFi 14c3:6639)
>> - ASUS ProArt X870E-Creator WiFi (BT 0489:e13a / 13d3:3588, WiFi 14c3:6639)
>> - ASUS ROG Strix X870E-E (BT 0489:e13a, WiFi 14c3:7927)
>> - Gigabyte X870E Aorus Master X3D (BT 0489:e10f, WiFi 14c3:7927)
>> - Gigabyte Z790 AORUS MASTER X (BT 0489:e10f, WiFi 14c3:7927)
>> - Lenovo Legion Pro 7 16ARX9 (BT 0489:e0fa, WiFi 14c3:7927)
>> - TP-Link Archer TBE550E PCIe (BT 0489:e116, WiFi 14c3:7927)
>> - EDUP EP-MT7927BE M.2 card (WiFi 14c3:7927)
>> - Foxconn/Azurewave M.2 modules (WiFi 14c3:6639)
>> - AMD RZ738 reference design (WiFi 14c3:0738)
>>
>
> Thanks for coordinating the work and delivering the driver.
>
>> Tested on Arch Linux, CachyOS, EndeavourOS, Fedora (Bazzite), NixOS,
>> openSUSE Tumbleweed, and Ubuntu across kernels 6.13-6.19.
>>
>> What works:
>> - WiFi 7 with EHT 320MHz on 2.4/5/6 GHz bands
>> - 320MHz data path verified at 841 Mbps (iperf3 -t30 -P8)
>> - PCIe initialization with CBTOP remap and MT7927-specific DMA layout
>> - Runtime power management and suspend/resume (S3)
>> - DBDC (dual-band concurrent) mode
>> - Explicit band_idx assignment for stable 5GHz/6GHz operation
>> - ASPM disabled for MT7927 to prevent throughput collapse
>>
>> Known limitations (planned as follow-up series):
>> - MLO (Multi-Link Operation): tested working on 5GHz+2.4GHz STR
>> (776 Mbps) but requires additional patches for link lifetime
>> and error handling. Sean Wang's series [1] addresses these;
>> MLO support will be submitted as a follow-up on top of that.
>>
>> [1] https://lore.kernel.org/linux-wireless/20260306232238.2039675-1-sean.wang@kernel.org/
>> - TX retransmissions: elevated retry rate on all bands, firmware-side
>> rate adaptation issue not addressable in the driver.
>>
>> Patches 1-11 bring up the basic driver (chip ID, firmware, DMA, init,
>> power management, 320MHz MCS, mac_reset guard, IRQ map, probe fix).
>> Patch 12 advertises EHT 320MHz capabilities, guarded by is_mt7927().
>> Patches 13-14 fix DMASHDL PM wake and disable ASPM.
>> Patch 15 adds 320MHz bandwidth handling in RXV/TXS status reporting.
>> Patch 16 fixes stale pointer comparisons in change_vif_links.
>> Patch 17 assigns explicit band_idx for stable 5GHz/6GHz operation.
>> Patch 18 adds the missing 320MHz case in bss_rlm_tlv() so firmware
>> receives the correct bandwidth when associated to a 320MHz BSS.
>>
>> The WiFi firmware ships as part of the linux-firmware package
>> (mediatek/mt6639/ directory - the firmware uses the mobile SoC codename).
>>
>> To: linux-wireless@vger.kernel.org
>> To: Felix Fietkau <nbd@nbd.name>
>> To: Lorenzo Bianconi <lorenzo@kernel.org>
>> To: Ryder Lee <ryder.lee@mediatek.com>
>> To: Shayne Chen <shayne.chen@mediatek.com>
>> To: Sean Wang <sean.wang@mediatek.com>
>> To: Matthias Brugger <matthias.bgg@gmail.com>
>> To: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
>> To: Deren Wu <deren.wu@mediatek.com>
>> To: Ming Yen Hsieh <mingyen.hsieh@mediatek.com>
>> Cc: linux-kernel@vger.kernel.org
>> Cc: linux-arm-kernel@lists.infradead.org
>> Cc: linux-mediatek@lists.infradead.org
>> Tested-by: Marcin FM <marcin@lgic.pl>
>> Tested-by: Cristian-Florin Radoi <radoi.chris@gmail.com>
>> Tested-by: George Salukvadze <giosal90@gmail.com>
>> Tested-by: Evgeny Kapusta <3193631@gmail.com>
>> Tested-by: Samu Toljamo <samu.toljamo@gmail.com>
>> Tested-by: Ariel Rosenfeld <ariel.rosenfeld.750@gmail.com>
>> Tested-by: Chapuis Dario <chapuisdario4@gmail.com>
>> Tested-by: Thibaut François <tibo@humeurlibre.fr>
>> Tested-by: 张旭涵 <Loong.0x00@gmail.com>
>>
>> Signed-off-by: Javier Tia <floss@jetm.me>
>> ---
>> Javier Tia (18):
>> wifi: mt76: mt7925: add MT7927 chip ID helpers
>> wifi: mt76: mt7925: add MT7927 firmware paths and PCI device IDs
>> wifi: mt76: mt7925: add MT7927 CBTOP remap and chip initialization
>> wifi: mt76: mt7925: add MT7927 DMA ring layout, IRQ map, and prefetch
>> wifi: mt76: mt7925: skip CLR_OWN in mt7925e_mcu_init for MT7927
>> wifi: mt76: mt7925: add MT7927 power management, DBDC, and CNM fixes
>> wifi: mt76: mt7925: use irq_map fields instead of MT_INT_RX_DONE_ALL
>> wifi: mt76: mt7925: guard mac_reset against MT7927 DMA destruction
>> wifi: mt76: mt7925: populate EHT 320MHz MCS map in sta_rec
>> wifi: mt76: mt7925: enable MT7927 runtime power management
>> wifi: mt76: mt7925: fix uninitialized is_mt7927_hw in probe
>> wifi: mt76: mt7925: advertise EHT 320MHz capabilities for 6GHz band
>> wifi: mt76: mt7925: restore FW_DWLD_BYPASS_DMASHDL in MT7927 PM wake path
>> wifi: mt76: mt7925: disable ASPM for MT7927 to fix throughput collapse
>> wifi: mt76: mt7925: handle 320MHz bandwidth in RXV and TXS
>> wifi: mt76: mt7925: fix stale pointer comparisons in change_vif_links
>> wifi: mt76: mt7925: fix MT7927 band_idx for stable 5GHz/6GHz operation
>> wifi: mt76: mt7925: add 320MHz bandwidth to bss_rlm_tlv
>>
>
> The patchset should be ordered so that common changes (e.g., enabling
> 320 MHz support) are added first,
> while chip-specific changes are introduced later (e.g.,
> MT7927-specific IRQ, DMA, and hardware initialization sequences).
> Before introducing chip-specific logic, try to make the functions
> generic enough so that other chips can reuse them in the same way.
> Checks such as is_mt7927 and duplicated function should only be added
> if they cannot be avoided
>
> The more code we can reuse across chips, the fewer maintenance
> concerns there will be, and we can focus more effort on the
> chip-specific parts.
>
> Please reorganize the patchset order as follows:
>
> 1. Common patches that can be reused by other chipsets (now or in the
> future) should come first we don't need to mention mt7927
>
> "wifi: mt76: mt7925: fix stale pointer comparisons in change_vif_links"
> "wifi: mt76: mt7925: add 320MHz bandwidth to bss_rlm_tlv"
> "wifi: mt76: mt7925: handle 320MHz bandwidth in RXV and TXS"
> "wifi: mt76: mt7925: populate EHT 320MHz MCS map in sta_rec"
> "wifi: mt76: mt7925: advertise EHT 320MHz capabilities for 6GHz band"
>
> Here we can add a helper like is_320MHz_supported() and then advertise
> EHT 320MHz capabilities, but do not need to mention is_mt7927() yet.
>
> 2. Then introduce MT7927-related changes
>
> wifi: mt76: mt7925: add MT7927 chip ID helpers
> Keep the MCU part of "wifi: mt76: mt7925: add MT7927 firmware paths
> and PCI device IDs" but leave enabling the PCI device table for the
> last patch.
>
> 3. IRQ handling
>
> Combine
>
> wifi: mt76: mt7925: use irq_map fields instead of MT_INT_RX_DONE_ALL
> the IRQ part of wifi: mt76: mt7925: add MT7927 DMA ring layout, IRQ
> map, and prefetch
> into one patch about irq_map handling, trying to reuse mt7925_irq as
> much as possible.
>
> 4. DMA handling
>
> Combine
>
> the DMA part of "wifi: mt76: mt7925: add MT7927 DMA ring layout, IRQ
> map, and prefetch"
> "wifi: mt76: mt7925: restore FW_DWLD_BYPASS_DMASHDL in MT7927 PM wake path"
> into one patch about DMA handling, trying to reuse mt7925_dma_init as
> much as possible.
>
> 5. Hardware initialization
>
> Combine
>
> "wifi: mt76: mt7925: add MT7927 CBTOP remap and chip initialization"
> "wifi: mt76: mt7925: fix uninitialized is_mt7927_hw in probe"
> "wifi: mt76: mt7925: skip CLR_OWN in mt7925e_mcu_init for MT7927"
> "wifi: mt76: mt7925: add MT7927 power management, DBDC, and CNM fixes"
>
> into one or more patches focused on pure hardware initialization in
> logical order. If the register definition is used by MT7927, add
> MT7927_ as the prefix.
>
> 6. Band index fix
>
> "wifi: mt76: mt7925: fix MT7927 band_idx for stable 5GHz/6GHz operation"
> This is worth introducing helper functions and using them instead of
> implementing the logic inline.
>
> 7. Low power support
>
> Combine
>
> "wifi: mt76: mt7925: enable MT7927 runtime power management"
> "wifi: mt76: mt7925: disable ASPM for MT7927 to fix throughput collapse"
>
> into one or more patches related to enabling or disabling low power support.
>
> 8. Final patch
> The last patch should enable the MT7927 PCI device table.
>
>> drivers/net/wireless/mediatek/mt76/mt76_connac.h | 8 +-
>> drivers/net/wireless/mediatek/mt76/mt7925/init.c | 12 +
>> drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 9 +
>> drivers/net/wireless/mediatek/mt76/mt7925/main.c | 72 +++++-
>> drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 59 ++++-
>> drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h | 12 +
>> drivers/net/wireless/mediatek/mt76/mt7925/pci.c | 248 ++++++++++++++++++++-
>> .../net/wireless/mediatek/mt76/mt7925/pci_mac.c | 13 +-
>> .../net/wireless/mediatek/mt76/mt7925/pci_mcu.c | 19 +-
>> drivers/net/wireless/mediatek/mt76/mt792x.h | 6 +
>> drivers/net/wireless/mediatek/mt76/mt792x_dma.c | 26 ++-
>> drivers/net/wireless/mediatek/mt76/mt792x_regs.h | 30 +++
>> 12 files changed, 479 insertions(+), 35 deletions(-)
>> ---
>> base-commit: 97492c019da4b62df83255e968b23b81c0315530
>> change-id: 20260305-mt7927-wifi-support-02f9738a3962
>>
>> Best regards,
>> --
>> Javier Tia <floss@jetm.me>
>>
>>
[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 6977 bytes --]
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]
^ permalink raw reply
* Re: [PATCH 2/2] wifi: mt76: mt792x: fix mt7925u USB WFSYS reset handling
From: Satadru Pramanik @ 2026-03-11 18:15 UTC (permalink / raw)
To: Nick
Cc: Sean Wang, nbd, lorenzo.bianconi, linux-wireless, linux-mediatek,
Sean Wang, stable
In-Reply-To: <CAFrh3J-PsVQ1u_hGFxTVKK0uOs6KxT=euK+jbGvWCueqvynAgw@mail.gmail.com>
After rebuilding the kernel with 7.0-rc3 and the two patches at
https://patchwork.kernel.org/project/linux-wireless/list/?series=1064695,
I can confirm that after a warm reboot booted from that kernel, the
mt7925u-based adapter is once again visible.
Thanks!
Regards,
Satadru Pramanik
On Wed, Mar 11, 2026 at 12:42 PM Satadru Pramanik <satadru@gmail.com> wrote:
>
> Hello all, I'm rebuilding this kernel one more time in case I mispatched, and will let you know shortly if a new kernel build works.
>
> Regards,
>
> Satadru
>
> On Wed, Mar 11, 2026 at 12:15 PM Nick <morrownr@gmail.com> wrote:
>>
>> > From: Sean Wang <sean.wang@mediatek.com>
>> >
>> > mt7925u uses different reset/status registers from mt7921u. Reusing the
>> > mt7921u register set causes the WFSYS reset to fail.
>> >
>> > Add a chip-specific descriptor in mt792xu_wfsys_reset() to select the
>> > correct registers and fix mt7925u failing to initialize after a warm
>> > reboot.
>> >
>> > Fixes: d28e1a48952e ("wifi: mt76: mt792x: introduce mt792x-usb module")
>> > Cc: stable@vger.kernel.org
>> > Signed-off-by: Sean Wang <sean.wang@mediatek.com>
>> > ---
>> > drivers/net/wireless/mediatek/mt76/mt792x_regs.h | 4 ++++
>> > drivers/net/wireless/mediatek/mt76/mt792x_usb.c | 13 ++++++++++++-
>> > 2 files changed, 16 insertions(+), 1 deletion(-)
>> >
>> > diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_regs.h b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h
>> > index 7ddde9286861..d2a8b2b0df32 100644
>> > --- a/drivers/net/wireless/mediatek/mt76/mt792x_regs.h
>> > +++ b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h
>> > @@ -392,6 +392,10 @@
>> > #define MT_CBTOP_RGU_WF_SUBSYS_RST MT_CBTOP_RGU(0x600)
>> > #define MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH BIT(0)
>> >
>> > +#define MT7925_CBTOP_RGU_WF_SUBSYS_RST 0x70028600
>> > +#define MT7925_WFSYS_INIT_DONE_ADDR 0x184c1604
>> > +#define MT7925_WFSYS_INIT_DONE 0x00001d1e
>> > +
>> > #define MT_HW_BOUND 0x70010020
>> > #define MT_HW_CHIPID 0x70010200
>> > #define MT_HW_REV 0x70010204
>> > diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
>> > index a92e872226cf..47827d1c5ccb 100644
>> > --- a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
>> > +++ b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
>> > @@ -224,6 +224,15 @@ static const struct mt792xu_wfsys_desc mt7921_wfsys_desc = {
>> > .need_status_sel = true,
>> > };
>> >
>> > +static const struct mt792xu_wfsys_desc mt7925_wfsys_desc = {
>> > + .rst_reg = MT7925_CBTOP_RGU_WF_SUBSYS_RST,
>> > + .done_reg = MT7925_WFSYS_INIT_DONE_ADDR,
>> > + .done_mask = U32_MAX,
>> > + .done_val = MT7925_WFSYS_INIT_DONE,
>> > + .delay_ms = 20,
>> > + .need_status_sel = false,
>> > +};
>> > +
>> > int mt792xu_dma_init(struct mt792x_dev *dev, bool resume)
>> > {
>> > int err;
>> > @@ -254,7 +263,9 @@ EXPORT_SYMBOL_GPL(mt792xu_dma_init);
>> >
>> > int mt792xu_wfsys_reset(struct mt792x_dev *dev)
>> > {
>> > - const struct mt792xu_wfsys_desc *desc = &mt7921_wfsys_desc;
>> > + const struct mt792xu_wfsys_desc *desc = is_mt7925(&dev->mt76) ?
>> > + &mt7925_wfsys_desc :
>> > + &mt7921_wfsys_desc;
>> > u32 val;
>> > int i;
>> >
>> > --
>> > 2.43.0
>> >
>>
>> Sean, testing results from: Satadru Pramanik <satadru@gmail.com>
>>
>> "The updated patches from
>> https://patchwork.kernel.org/project/linux-wireless/list/?series=1064695
>> do NOT work. I get the -110 error with them on a warm reboot.
>> Reverting to the kernel with the older patch restores my adapter
>> connection on a warm reboot."
>>
>> You are welcome to stop by the Github issue where this issue is being discussed:
>>
>> https://github.com/morrownr/USB-WiFi/issues/688#
>>
>> Nick
^ permalink raw reply
* Re: [PATCH 2/2] wifi: mt76: mt792x: fix mt7925u USB WFSYS reset handling
From: Nick @ 2026-03-11 16:14 UTC (permalink / raw)
To: Sean Wang
Cc: nbd, lorenzo.bianconi, linux-wireless, linux-mediatek, Sean Wang,
stable, Satadru Pramanik
In-Reply-To: <20260311002825.15502-2-sean.wang@kernel.org>
> From: Sean Wang <sean.wang@mediatek.com>
>
> mt7925u uses different reset/status registers from mt7921u. Reusing the
> mt7921u register set causes the WFSYS reset to fail.
>
> Add a chip-specific descriptor in mt792xu_wfsys_reset() to select the
> correct registers and fix mt7925u failing to initialize after a warm
> reboot.
>
> Fixes: d28e1a48952e ("wifi: mt76: mt792x: introduce mt792x-usb module")
> Cc: stable@vger.kernel.org
> Signed-off-by: Sean Wang <sean.wang@mediatek.com>
> ---
> drivers/net/wireless/mediatek/mt76/mt792x_regs.h | 4 ++++
> drivers/net/wireless/mediatek/mt76/mt792x_usb.c | 13 ++++++++++++-
> 2 files changed, 16 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_regs.h b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h
> index 7ddde9286861..d2a8b2b0df32 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt792x_regs.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h
> @@ -392,6 +392,10 @@
> #define MT_CBTOP_RGU_WF_SUBSYS_RST MT_CBTOP_RGU(0x600)
> #define MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH BIT(0)
>
> +#define MT7925_CBTOP_RGU_WF_SUBSYS_RST 0x70028600
> +#define MT7925_WFSYS_INIT_DONE_ADDR 0x184c1604
> +#define MT7925_WFSYS_INIT_DONE 0x00001d1e
> +
> #define MT_HW_BOUND 0x70010020
> #define MT_HW_CHIPID 0x70010200
> #define MT_HW_REV 0x70010204
> diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
> index a92e872226cf..47827d1c5ccb 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
> @@ -224,6 +224,15 @@ static const struct mt792xu_wfsys_desc mt7921_wfsys_desc = {
> .need_status_sel = true,
> };
>
> +static const struct mt792xu_wfsys_desc mt7925_wfsys_desc = {
> + .rst_reg = MT7925_CBTOP_RGU_WF_SUBSYS_RST,
> + .done_reg = MT7925_WFSYS_INIT_DONE_ADDR,
> + .done_mask = U32_MAX,
> + .done_val = MT7925_WFSYS_INIT_DONE,
> + .delay_ms = 20,
> + .need_status_sel = false,
> +};
> +
> int mt792xu_dma_init(struct mt792x_dev *dev, bool resume)
> {
> int err;
> @@ -254,7 +263,9 @@ EXPORT_SYMBOL_GPL(mt792xu_dma_init);
>
> int mt792xu_wfsys_reset(struct mt792x_dev *dev)
> {
> - const struct mt792xu_wfsys_desc *desc = &mt7921_wfsys_desc;
> + const struct mt792xu_wfsys_desc *desc = is_mt7925(&dev->mt76) ?
> + &mt7925_wfsys_desc :
> + &mt7921_wfsys_desc;
> u32 val;
> int i;
>
> --
> 2.43.0
>
Sean, testing results from: Satadru Pramanik <satadru@gmail.com>
"The updated patches from
https://patchwork.kernel.org/project/linux-wireless/list/?series=1064695
do NOT work. I get the -110 error with them on a warm reboot.
Reverting to the kernel with the older patch restores my adapter
connection on a warm reboot."
You are welcome to stop by the Github issue where this issue is being discussed:
https://github.com/morrownr/USB-WiFi/issues/688#
Nick
^ permalink raw reply
* Re: [BUG] wifi: rtw88: Hard system freeze on RTL8821CE when power_save is enabled (LPS/ASPM conflict)
From: LB F @ 2026-03-11 15:22 UTC (permalink / raw)
To: Ping-Ke Shih; +Cc: linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <CALdGYqQn8GGXXjZTsL+a5Mfdmw5HRYB2Jyvqq5M5SUwxK9yd_g@mail.gmail.com>
Hi Ping-Ke,
I successfully applied your patch out-of-tree and performed rigorous
testing on the host machine.
I can officially confirm that the patch works flawlessly. The DMI
quirk triggered correctly and successfully prevented the
hardware-level PCIe bus lockups on my HP P3S95EA#ACB.
Testing Environment & Methodology:
- Kernel: CachyOS Linux 6.19.6-2-cachyos x86_64
- Toolchain: Clang/LLVM 21.1.8 (`make CC=clang LLVM=1 modules`)
- Extraction: We fetched the strict
`drivers/net/wireless/realtek/rtw88` sub-tree out of the
torvalds/linux `v6.19` tree utilizing `git sparse-checkout` to cleanly
apply the patch without having to compile the entire 2.5GB+ kernel.
- The resulting `.ko` object files were compressed to `.zst` and
installed successfully over the generic CachyOS system driver objects.
Verification Conditions:
- Removed ALL local workarounds. `disable_aspm=Y` is no longer forced
via `/etc/modprobe.d/` overrides.
- Power saving remains natively ON `wifi.powersave = 3` (managed by
NetworkManager).
- Left the laptop in multiple 5-10 minute complete idle states to
enforce sleep modes.
Post-Boot Log Analysis & Potential Improvement Proposition:
The system remained 100% stable without any kernel panics or UI freezes.
However, I continuously monitored the `dmesg` ring buffer and noticed
an intriguing behavior. While the laptop sits completely idle
(NetworkManager connected, but no active traffic), the `rtw88` driver
starts flooded the logs with thousands of firmware errors:
[ 1084.746485] rtw88_8821ce 0000:13:00.0: firmware failed to leave lps state
[ 1084.749662] rtw88_8821ce 0000:13:00.0: failed to send h2c command
[ 1084.752895] rtw88_8821ce 0000:13:00.0: failed to send h2c command
If my understanding of this architecture is correct, previously, when
ASPM wasn't disabled, this exact failure of the adapter firmare inside
`LPS_DEEP_MODE_LCLK` would violently lock up the PCIe bus and crash
the host. Now, thanks to your DMI ASPM quirk at the `rtw88_pci` level,
the host PCIe controller doesn't enter `L1` and is perfectly shielded
from the adapter locking itself up! The OS handles the timeouts
gracefully and driver recovery prevents a hard freeze.
A question for your consideration: Given the immense volume of these
`h2c` timeout errors (and the underlying firmware's fundamental
inability to cleanly enter/exit its own sleep states without L1
participation on this HP model), do you think it would be beneficial
to *also* dynamically disable LPS Deep sleep when this specific ASPM
quirk is triggered?
For example, dynamically forcing `rtwdev->lps_conf.deep_mode =
LPS_DEEP_MODE_NONE` when the DMI ASPM flag is active, strictly to
prevent the firmware from attempting a sleep cycle that is doomed to
fail and polluting the queues and logs? Perhaps this might also save
microscopic CPU interrupts from continuous H2C polling timeouts?
If you believe that simply letting the driver recover and tolerating
the error spam in `dmesg` is the preferred/safer upstream approach, I
am perfectly happy. The patch functions as advertised and system
stability is unequivocally restored!
Thank you immensely for your rapid debugging and definitive patch for
this long-standing issue and for bringing stability to this model.
Tested-by: Oleksandr Havrylov <goainwo@gmail.com>
*(Note: I was a bit unsure which of the two active mailing list
threads was the most appropriate place for this final report — the
original bug discussion or the new RFT patch submission thread — so I
replied to both just to ensure it is correctly attached to the patch.
Apologies for the duplicate email!)*
Best regards,
Oleksandr Havrylov
ср, 11 мар. 2026 г. в 13:00, LB F <goainwo@gmail.com>:
>
> Hi Ping-Ke,
>
> Thank you for the incredibly fast turnaround and for providing the RFT
> patch with the DMI quirk!
>
> First, I want to mention that I am not an IT professional or a
> programmer. I am just a regular Linux user who really wants to help
> solve this problem. I am trying my best to verify everything
> carefully, so please forgive me if my terminology or induction was
> slightly off.
>
> To answer your clarifying questions from the previous emails:
>
> > Just want to clarify that these logs only appear in test 3, right?
> > No these logs in test 1/2.
>
> Yes, exactly. The `failed to send h2c command` errors only caused a
> complete system freeze when no workarounds were active and the adapter
> attempted to sleep (Test 3).
>
> > I think this is your perspective and induction, right? Did you measure
> > real hardware signals?
>
> You are entirely correct. This is just my induction based solely on
> the timing of the logs and system behavior. I do not have access to an
> oscilloscope or any hardware diagnostic tools. Given this, I
> completely agree that your approach of applying a platform-specific
> quirk is the safest and best solution.
>
> > Forgot to say. Could you share your full name for me as a reporter
> > in commit message?
>
> My full name is Oleksandr Havrylov. I would be honored to be included
> as the reporter in the commit message.
>
> ### Recent Baseline Testing Before Your Patch
>
> Before applying your patch today, we ran a few more controlled tests
> to double-check our baseline. We verified that our local workaround
> (`modprobe.d disable_aspm=y`) **does indeed keep the system completely
> stable** and prevents the hard freeze, even when NetworkManager's
> `wifi.powersave` is set to ON (default).
>
> However, we noticed one interesting detail in the kernel logs: while
> the system no longer freezes with `disable_aspm=y`, `dmesg` still
> constantly logs `firmware failed to leave lps state` and `failed to
> send h2c command` when the laptop is completely idle. It seems the
> firmware still crashes during LPS, but because ASPM is disabled, the
> PCIe bus ignores the crash and the system survives perfectly fine. I
> just wanted to mention this for completeness!
>
> ### Testing Plan
>
> I have **not** applied your RFT patch just yet. I wanted to make sure
> our testing baseline was 100% clean and documented first.
>
> I will compile your patch and perform rigorous testing this evening (I
> am in the EET timezone, Ukraine). I will test it with the native
> `power_save` fully enabled to ensure your patch successfully prevents
> the hard lockups as intended.
>
> I will stay in touch and reply back to this thread with a formal
> `Tested-by` confirmation (and any logs if needed) as soon as my
> testing is complete. Thank you again for all your help!
>
> Best regards,
> Oleksandr Havrylov
>
> ср, 11 мар. 2026 г. в 04:22, Ping-Ke Shih <pkshih@realtek.com>:
> >
> > Ping-Ke Shih <pkshih@realtek.com> wrote:
> > >
> > > LB F <goainwo@gmail.com> wrote:
> > > >
> > > > Hi Ping-Ke,
> > > >
> > > > Thank you for the incredibly fast response and assistance!
> > > >
> > > > > Can you dig kernel log (by netconsole or ramoops) if something useful?
> > > > > I'd like to know this is hardware level freeze or kernel can capture something
> > > > wrong.
> > > >
> > > > I managed to pull a call trace from a historic journald log just
> > > > before the system hung. The kernel gets trapped in an IRQ thread
> > > > inside `rtw_pci_interrupt_threadfn`, calling up into `mac80211`
> > > > `ieee80211_rx_list` before everything freezes. Here is the relevant
> > > > snippet:
> > > >
> > > > ```text
> > > > Call Trace:
> > > > <IRQ>
> > > > ? __alloc_skb+0x23a/0x2a0
> > > > ? __alloc_skb+0x10c/0x2a0
> > > > ? __pfx_irq_thread_fn+0x10/0x10
> > > > [ ... truncated module list ... ]
> > > > Tainted: G W I 6.19.6-2-cachyos #1 PREEMPT(full)
> > > > Hardware name: HP HP Notebook/81F0, BIOS F.50 11/20/2020
> > > > RIP: 0010:ieee80211_rx_list+0x1012/0x1020 [mac80211]
> > > > CPU: 2 UID: 0 PID: 765 Comm: irq/56-rtw88_pc
> > > > rtw_pci_interrupt_threadfn+0x239/0x310 [rtw88_pci]
> > > > ```
> > > >
> > > > It behaves exactly like a PCIe bus deadlock or a hardware fault that
> > > > eventually brings down the CPU handling the IRQ.
> > >
> > > I wonder if there is a malformed data, causing this trace and the leads
> > > kernel freezes. If we can do validation on RX data before calling
> > > ieee80211_rx_list(), maybe trace disappears and everything will be fine?
> > > Even no need workaround.
> > >
> > > >
> > > > > Are these totally needed to workaround the problem? Or disable_aspm is enough?
> > > > > I'd list them in order of power consumption impact:
> > > > > 1. disable_aspm=y
> > > > > 2. disable_lps_deep=y
> > > > > 3. disable WiFi power save
> > > >
> > > > To verify which parameters are strictly necessary, I performed
> > > > isolated testing today. I ensured no other modprobe configs were
> > > > active, rebuilt the initramfs, and manually enforced that
> > > > `wifi.powersave` was active via `iw dev wlan0 set power_save on`
> > > > during all tests (as the OS power management profiles were defaulting
> > > > it to off, which initially masked the issue).
> > > >
> > > > I tested each workaround individually across multiple sleep/wake
> > > > cycles and active usage:
> > > >
> > > > **Test 1 (ASPM Disabled, LPS Deep Enabled):**
> > > > - Kernel parameters: `rtw88_pci disable_aspm=y` (and `rtw88_core
> > > > disable_lps_deep=n`)
> > > > - Result: Stable. No freezes were observed during usage or transitions
> > > > into/out of S3 sleep while power saving was enforced.
> > > >
> > > > **Test 2 (ASPM Enabled, LPS Deep Disabled):**
> > > > - Kernel parameters: `rtw88_core disable_lps_deep=y` (and `rtw88_pci
> > > > disable_aspm=n`)
> > > > - Result: Stable. No freezes were observed under the same forced power
> > > > save conditions.
> > > >
> > > > **Conclusion:** It appears we do not need both workarounds
> > > > simultaneously for this specific hardware. Using only `disable_aspm=y`
> > > > seems to be sufficient to prevent the system freeze. Given your note
> > > > about the power consumption impact ranking, this looks like the
> > > > optimal path forward.
> > >
> > > Let's test my RFT patch to disable ASPM then.
> > >
> > > >
> > > > > But what does 'deadlock' mean? As I know NAPI poll is scheduled by ISR,
> > > > > and going to receive packets. The rx_no_aspm workaround is to forcely turn
> > > > > off ASPM during this period.
> > > >
> > > > By "deadlock" I meant a hardware-level bus lockup. It seems the
> > > > physical RTL8821CE chip itself crashes or hangs the system's PCIe bus
> > > > when trying to negotiate waking up from ASPM L1 while simultaneously
> > > > existing in `LPS_DEEP_MODE_LCLK`. The `rx_no_aspm` workaround in NAPI
> > > > helps during active Rx decoding, but the laptop often freezes while
> > > > completely idle, presumably when the AP sends a basic beacon, the chip
> > > > attempts to leave LPS Deep + L1, and the hardware simply gives up and
> > > > halts the system.
> > >
> > > I think this is your perspective and induction, right? Did you measure
> > > real hardware signals?
> > >
> > > My point is that if this is a hardware-level bus lockup, let's apply
> > > quirk. If some malformed data causing kernel hangs, I'd add sanity check
> > > on RX data, but I don't actually know what we should check for now.
> > >
> > > >
> > > > > We have not modified RTL8821CE for a long time, so I'd add workaround
> > > > > to specific platform as mentioned above.
> > > >
> > > > Adding a DMI/platform quirk specifically for this laptop to disable
> > > > ASPM would be wonderful and deeply appreciated. I agree it is safer
> > > > than touching the global flags for hardware that is functioning
> > > > correctly out in the wild.
> > > >
> > > > Here is the exact identifying information for my system:
> > > >
> > > > System Vendor: HP
> > > > Product Name: HP Notebook
> > > > SKU Number: P3S95EA#ACB
> > > > Family: 103C_5335KV
> > > > PCI ID: 10ec:c821
> > > > Subsystem ID: 103c:831a
> > > >
> > > > I am completely ready to test any patch or quirk you send my way.
> > > > Thank you so much for your time and helping track this down!
> > >
> > > I sent a RFT [1] for test. Please check if it works on your HP notebook.
> > > If you check rtw88 log, you can see I added similar patch 5 years ago,
> > > and replaced by preferred the change of "rtwpci->rx_no_aspm", which I
> > > think it can only resolve problem on partial notebooks though....
> > >
> > > [1]
> > > https://lore.kernel.org/linux-wireless/20260311020816.7065-1-pkshih@realtek.
> > > com/T/#u
> >
> > Forgot to say. Could you share your full name for me as a reporter
> > in commit message?
> >
> >
^ permalink raw reply
* Re: [RFT rtw-next] wifi: rtw88: add quirks to disable PCI ASPM for HP P3S95EA#ACB
From: LB F @ 2026-03-11 15:19 UTC (permalink / raw)
To: Ping-Ke Shih; +Cc: linux-wireless
In-Reply-To: <20260311020816.7065-1-pkshih@realtek.com>
Hi Ping-Ke,
I successfully applied your patch out-of-tree and performed rigorous
testing on the host machine.
I can officially confirm that the patch works flawlessly. The DMI
quirk triggered correctly and successfully prevented the
hardware-level PCIe bus lockups on my HP P3S95EA#ACB.
Testing Environment & Methodology:
- Kernel: CachyOS Linux 6.19.6-2-cachyos x86_64
- Toolchain: Clang/LLVM 21.1.8 (`make CC=clang LLVM=1 modules`)
- Extraction: We fetched the strict
`drivers/net/wireless/realtek/rtw88` sub-tree out of the
torvalds/linux `v6.19` tree utilizing `git sparse-checkout` to cleanly
apply the patch without having to compile the entire 2.5GB+ kernel.
- The resulting `.ko` object files were compressed to `.zst` and
installed successfully over the generic CachyOS system driver objects.
Verification Conditions:
- Removed ALL local workarounds. `disable_aspm=Y` is no longer forced
via `/etc/modprobe.d/` overrides.
- Power saving remains natively ON `wifi.powersave = 3` (managed by
NetworkManager).
- Left the laptop in multiple 5-10 minute complete idle states to
enforce sleep modes.
Post-Boot Log Analysis & Potential Improvement Proposition:
The system remained 100% stable without any kernel panics or UI freezes.
However, I continuously monitored the `dmesg` ring buffer and noticed
an intriguing behavior. While the laptop sits completely idle
(NetworkManager connected, but no active traffic), the `rtw88` driver
starts flooded the logs with thousands of firmware errors:
[ 1084.746485] rtw88_8821ce 0000:13:00.0: firmware failed to leave lps state
[ 1084.749662] rtw88_8821ce 0000:13:00.0: failed to send h2c command
[ 1084.752895] rtw88_8821ce 0000:13:00.0: failed to send h2c command
If my understanding of this architecture is correct, previously, when
ASPM wasn't disabled, this exact failure of the adapter firmare inside
`LPS_DEEP_MODE_LCLK` would violently lock up the PCIe bus and crash
the host. Now, thanks to your DMI ASPM quirk at the `rtw88_pci` level,
the host PCIe controller doesn't enter `L1` and is perfectly shielded
from the adapter locking itself up! The OS handles the timeouts
gracefully and driver recovery prevents a hard freeze.
A question for your consideration: Given the immense volume of these
`h2c` timeout errors (and the underlying firmware's fundamental
inability to cleanly enter/exit its own sleep states without L1
participation on this HP model), do you think it would be beneficial
to *also* dynamically disable LPS Deep sleep when this specific ASPM
quirk is triggered?
For example, dynamically forcing `rtwdev->lps_conf.deep_mode =
LPS_DEEP_MODE_NONE` when the DMI ASPM flag is active, strictly to
prevent the firmware from attempting a sleep cycle that is doomed to
fail and polluting the queues and logs? Perhaps this might also save
microscopic CPU interrupts from continuous H2C polling timeouts?
If you believe that simply letting the driver recover and tolerating
the error spam in `dmesg` is the preferred/safer upstream approach, I
am perfectly happy. The patch functions as advertised and system
stability is unequivocally restored!
Thank you immensely for your rapid debugging and definitive patch for
this long-standing issue and for bringing stability to this model.
Tested-by: Oleksandr Havrylov <goainwo@gmail.com>
*(Note: I was a bit unsure which of the two active mailing list
threads was the most appropriate place for this final report — the
original bug discussion or the new RFT patch submission thread — so I
replied to both just to ensure it is correctly attached to the patch.
Apologies for the duplicate email!)*
Best regards,
Oleksandr Havrylov
ср, 11 мар. 2026 г. в 04:08, Ping-Ke Shih <pkshih@realtek.com>:
>
> On an HP laptop (P3S95EA#ACB) equipped with a Realtek RTL8821CE 802.11ac
> PCIe adapter (PCI ID: 10ec:c821), the system experiences a hard lockup
> (complete freeze of the UI and kernel, sysrq doesn't work, requires
> holding the power button) when the WiFi adapter enters the power
> saving state.
>
> Add a quirk to disable ASPM.
>
> Reported-by: LB F <goainwo@gmail.com>
> Closes: https://lore.kernel.org/linux-wireless/CALdGYqSQ1Ko2TTBhUizMu_FvLMUAuQfFrVwS10n_C-LSQJQQkQ@mail.gmail.com/
> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
> ---
> drivers/net/wireless/realtek/rtw88/pci.c | 30 ++++++++++++++++++++++++
> 1 file changed, 30 insertions(+)
>
> diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c
> index ec0a45bfb670..0b60a0ce96a1 100644
> --- a/drivers/net/wireless/realtek/rtw88/pci.c
> +++ b/drivers/net/wireless/realtek/rtw88/pci.c
> @@ -2,6 +2,7 @@
> /* Copyright(c) 2018-2019 Realtek Corporation
> */
>
> +#include <linux/dmi.h>
> #include <linux/module.h>
> #include <linux/pci.h>
> #include "main.h"
> @@ -1744,6 +1745,34 @@ const struct pci_error_handlers rtw_pci_err_handler = {
> };
> EXPORT_SYMBOL(rtw_pci_err_handler);
>
> +enum rtw88_quirk_dis_pci_caps {
> + QUIRK_DIS_PCI_CAP_ASPM,
> +};
> +
> +static int disable_pci_caps(const struct dmi_system_id *dmi)
> +{
> + uintptr_t dis_caps = (uintptr_t)dmi->driver_data;
> +
> + if (dis_caps & BIT(QUIRK_DIS_PCI_CAP_ASPM))
> + rtw_pci_disable_aspm = true;
> +
> + return 1;
> +}
> +
> +static const struct dmi_system_id rtw88_pci_quirks[] = {
> + {
> + .callback = disable_pci_caps,
> + .ident = "HP Notebook - P3S95EA#ACB",
> + .matches = {
> + DMI_MATCH(DMI_SYS_VENDOR, "HP"),
> + DMI_MATCH(DMI_PRODUCT_NAME, "HP Notebook"),
> + DMI_MATCH(DMI_PRODUCT_SKU, "P3S95EA#ACB"),
> + },
> + .driver_data = (void *)BIT(QUIRK_DIS_PCI_CAP_ASPM),
> + },
> + {}
> +};
> +
> int rtw_pci_probe(struct pci_dev *pdev,
> const struct pci_device_id *id)
> {
> @@ -1808,6 +1837,7 @@ int rtw_pci_probe(struct pci_dev *pdev,
> bridge && bridge->vendor == PCI_VENDOR_ID_INTEL)
> rtwpci->rx_no_aspm = true;
>
> + dmi_check_system(rtw88_pci_quirks);
> rtw_pci_phy_cfg(rtwdev);
>
> ret = rtw_register_hw(rtwdev, hw);
> --
> 2.25.1
>
^ permalink raw reply
* Re: [PATCH 01/61] Coccinelle: Prefer IS_ERR_OR_NULL over manual NULL check
From: Markus Elfring @ 2026-03-11 15:12 UTC (permalink / raw)
To: Philipp Hahn, cocci, Julia Lawall, Nicolas Palix
Cc: amd-gfx, apparmor, bpf, ceph-devel, dm-devel, dri-devel, gfs2,
intel-gfx, intel-wired-lan, iommu, kvm, linux-arm-kernel,
linux-block, linux-bluetooth, linux-btrfs, linux-cifs, linux-clk,
linux-erofs, linux-ext4, linux-fsdevel, linux-gpio, linux-hyperv,
linux-input, linux-leds, linux-media, linux-mips, linux-mm,
linux-modules, linux-mtd, linux-nfs, linux-omap, linux-phy,
linux-pm, linux-rockchip, linux-s390, linux-scsi, linux-sctp,
linux-security-module, linux-sh, linux-sound, linux-stm32,
linux-trace-kernel, linux-usb, linux-wireless, netdev, ntfs3,
samba-technical, sched-ext, target-devel, tipc-discussion, v9fs,
LKML
In-Reply-To: <20260310-b4-is_err_or_null-v1-1-bd63b656022d@avm.de>
…
> +// Confidence: High
Some contributors presented discerning comments for this change approach.
Thus I became also curious how much they can eventually be taken better into account
by the means of the semantic patch language (Coccinelle software).
…
+@p1 depends on patch@
+expression E;
+@@
+(
> +- E != NULL && !IS_ERR(E)
> ++ !IS_ERR_OR_NULL(E)
> +|
> +- E == NULL || IS_ERR(E)
> ++ IS_ERR_OR_NULL(E)
> +|
> +- !IS_ERR(E) && E != NULL
> ++ !IS_ERR_OR_NULL(E)
> +|
> +- IS_ERR(E) || E == NULL
> ++ IS_ERR_OR_NULL(E)
> +)
Several detected expressions should refer to return values from function calls.
https://en.wikipedia.org/wiki/Return_statement
* Do any development challenges hinder still the determination of corresponding
failure predicates?
* How will interests evolve to improve data processing any further for such
use cases?
Regards,
Markus
^ permalink raw reply
* Re: [PATCH 15/61] trace: Prefer IS_ERR_OR_NULL over manual NULL check
From: Geert Uytterhoeven @ 2026-03-11 14:06 UTC (permalink / raw)
To: Steven Rostedt
Cc: Masami Hiramatsu (Google), Philipp Hahn, amd-gfx, apparmor, bpf,
ceph-devel, cocci, dm-devel, dri-devel, gfs2, intel-gfx,
intel-wired-lan, iommu, kvm, linux-arm-kernel, linux-block,
linux-bluetooth, linux-btrfs, linux-cifs, linux-clk, linux-erofs,
linux-ext4, linux-fsdevel, linux-gpio, linux-hyperv, linux-input,
linux-kernel, linux-leds, linux-media, linux-mips, linux-mm,
linux-modules, linux-mtd, linux-nfs, linux-omap, linux-phy,
linux-pm, linux-rockchip, linux-s390, linux-scsi, linux-sctp,
linux-security-module, linux-sh, linux-sound, linux-stm32,
linux-trace-kernel, linux-usb, linux-wireless, netdev, ntfs3,
samba-technical, sched-ext, target-devel, tipc-discussion, v9fs,
Mathieu Desnoyers
In-Reply-To: <20260311100332.6a2ce4b1@gandalf.local.home>
Hi Steven,
On Wed, 11 Mar 2026 at 15:03, Steven Rostedt <rostedt@goodmis.org> wrote:
> On Wed, 11 Mar 2026 14:13:32 +0900
> Masami Hiramatsu (Google) <mhiramat@kernel.org> wrote:
>
> > Hmm, now IS_ERR_OR_NULL() is an inline function, so it is safe.
> > But if you want to use IS_ERR_OR_NULL() here, it will be better something like
> >
> > node = rhashtable_walk_next(&iter);
> > while (!IS_ERR_OR_NULL(node)) {
> > fprobe_remove_node_in_module(mod, node, &alist);
> > node = rhashtable_walk_next(&iter);
> > }
>
> But now you need to have a duplicate code in order to acquire "node"
>
> I think the patch just makes the code worse.
Obviously we need a new for_each_*() helper hiding all the gory internals?
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH 15/61] trace: Prefer IS_ERR_OR_NULL over manual NULL check
From: Steven Rostedt @ 2026-03-11 14:03 UTC (permalink / raw)
To: Masami Hiramatsu (Google)
Cc: Philipp Hahn, amd-gfx, apparmor, bpf, ceph-devel, cocci, dm-devel,
dri-devel, gfs2, intel-gfx, intel-wired-lan, iommu, kvm,
linux-arm-kernel, linux-block, linux-bluetooth, linux-btrfs,
linux-cifs, linux-clk, linux-erofs, linux-ext4, linux-fsdevel,
linux-gpio, linux-hyperv, linux-input, linux-kernel, linux-leds,
linux-media, linux-mips, linux-mm, linux-modules, linux-mtd,
linux-nfs, linux-omap, linux-phy, linux-pm, linux-rockchip,
linux-s390, linux-scsi, linux-sctp, linux-security-module,
linux-sh, linux-sound, linux-stm32, linux-trace-kernel, linux-usb,
linux-wireless, netdev, ntfs3, samba-technical, sched-ext,
target-devel, tipc-discussion, v9fs, Mathieu Desnoyers
In-Reply-To: <20260311141332.b611237d36b61b2409e66cb3@kernel.org>
On Wed, 11 Mar 2026 14:13:32 +0900
Masami Hiramatsu (Google) <mhiramat@kernel.org> wrote:
> Hmm, now IS_ERR_OR_NULL() is an inline function, so it is safe.
> But if you want to use IS_ERR_OR_NULL() here, it will be better something like
>
> node = rhashtable_walk_next(&iter);
> while (!IS_ERR_OR_NULL(node)) {
> fprobe_remove_node_in_module(mod, node, &alist);
> node = rhashtable_walk_next(&iter);
> }
But now you need to have a duplicate code in order to acquire "node"
I think the patch just makes the code worse.
-- Steve
^ permalink raw reply
* Re: [PATCH 36/61] arch/sh: Prefer IS_ERR_OR_NULL over manual NULL check
From: Geert Uytterhoeven @ 2026-03-11 13:15 UTC (permalink / raw)
To: Philipp Hahn
Cc: amd-gfx, apparmor, bpf, ceph-devel, cocci, dm-devel, dri-devel,
gfs2, intel-gfx, intel-wired-lan, iommu, kvm, linux-arm-kernel,
linux-block, linux-bluetooth, linux-btrfs, linux-cifs, linux-clk,
linux-erofs, linux-ext4, linux-fsdevel, linux-gpio, linux-hyperv,
linux-input, linux-kernel, linux-leds, linux-media, linux-mips,
linux-mm, linux-modules, linux-mtd, linux-nfs, linux-omap,
linux-phy, linux-pm, linux-rockchip, linux-s390, linux-scsi,
linux-sctp, linux-security-module, linux-sh, linux-sound,
linux-stm32, linux-trace-kernel, linux-usb, linux-wireless,
netdev, ntfs3, samba-technical, sched-ext, target-devel,
tipc-discussion, v9fs, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz
In-Reply-To: <20260310-b4-is_err_or_null-v1-36-bd63b656022d@avm.de>
On Tue, 10 Mar 2026 at 12:56, Philipp Hahn <phahn-oss@avm.de> wrote:
> Prefer using IS_ERR_OR_NULL() over using IS_ERR() and a manual NULL
> check.
>
> Change generated with coccinelle.
>
> To: Yoshinori Sato <ysato@users.sourceforge.jp>
> To: Rich Felker <dalias@libc.org>
> To: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
> Cc: linux-sh@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> Signed-off-by: Philipp Hahn <phahn-oss@avm.de>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH wireless-next v2] wifi: cfg80211: init S1G properly when creating chandef
From: Johannes Berg @ 2026-03-11 11:55 UTC (permalink / raw)
To: Lachlan Hodges; +Cc: linux-wireless, arien.judge
In-Reply-To: <6eitsqhsmmhwgd3cobhpdhhzn5m5siw4ser53g3ilvd7kdhy2u@rkilpa5ek26y>
On Wed, 2026-03-11 at 22:48 +1100, Lachlan Hodges wrote:
> Initially reading this I was a bit concerned because it means any
> path calling cfg80211_chandef_create() wouldn't work for S1G
Yes, I agree, but I tend to think it fundamentally doesn't work for S1G
anyway the way it's defined with 20 or 40 MHz width. Now you had
somewhat made it work by just ignoring the chantype, but that seems
confusing too, at least in the long run.
> But it's
> actually only a couple of places now that call it and - being forward
> looking - for example with channel switching we would probably have
> an S1G specific path similar to processing a S1G connection anyway.
Right, for mac80211: I don't know if you will have IBSS on S1G, if not
that's right out, TDLS might be an issue, mesh support is probably not
there, HT/HE operation elements (util.c) are irrelevant, which basically
leaves the one I patched, and CSA that you mentioned.
For cfg80211 it's a similar story, but maybe we need to look - but
anything that can hit 60 GHz today would already be invalid too...
> No
> important paths (will confirm this) call this function anyway they
> seem to build the chandef locally.
There are a lot of places calling it in drivers so I don't think we can
remove the function, but all existing drivers without S1G anyway. In
mac80211 there might be paths, but then with the warning I guess syzbot
can find them ;)
johannes
^ permalink raw reply
* Re: [PATCH wireless-next v2] wifi: cfg80211: init S1G properly when creating chandef
From: Lachlan Hodges @ 2026-03-11 11:48 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, arien.judge
In-Reply-To: <b725c0be05df1a9595c177aada4cc148bf555448.camel@sipsolutions.net>
On Wed, Mar 11, 2026 at 11:56:37AM +0100, Johannes Berg wrote:
> On Wed, 2026-03-11 at 21:21 +1100, Lachlan Hodges wrote:
> > On Wed, Mar 11, 2026 at 10:55:46AM +0100, Johannes Berg wrote:
> > > On Wed, 2026-03-11 at 17:43 +1100, Lachlan Hodges wrote:
> > > > When creating a chandef, the initial width is determined by the
> > > > chan_type argument leading to a default width of 20/20_NOHT/40 which
> > > > does not make sense for S1G channels. Fix this by ensuring we default
> > > > S1G chandefs to a width of 1MHz.
> > > >
> > > > Signed-off-by: Lachlan Hodges <lachlan.hodges@morsemicro.com>
> > > > ---
> > > > v1 -> v2:
> > > >
> > > > - Remove the mac80211-based wording in the commit message and keep it
> > > > simple.
> > >
> > > Thanks :)
> > >
> > > Now with more tea and all that, do we really want it to completely
> > > ignore the width? Should that be documented? Almost feels like it should
> > > WARN if you use it wrong, with an S1G channel but a regular width, and
> > > mac80211 should be fixed?
> >
> > When you say "ignore the width"
>
> Sorry, I meant the channel type (chantype argument).
>
> > do you mean nothing checks it?
>
> I meant for s1g the chantype argument would be ignored now, not that it
> wasn't checked.
>
> > If
> > that's the case we probably need to add something within
> > cfg80211_chandef_valid() to ensure if we have an S1G chan we don't
> > have a non-S1G width i.e > 16MHz. That would fix mac80211 from
> > giving it to the driver in the first place.
>
> We don't have that? Seems like an oversight too,
Yea we have one way not the other, I will send a fix for that at
some point.
> but I was thinking like
> this (overall changes, not split to commits), since
> cfg80211_chandef_create() really doesn't work for S1G since the chantype
> is 20MHz-non-HT, 20MHz-HT, HT40+ or HT40-.
>
>
> diff --git a/net/mac80211/main.c b/net/mac80211/main.c
> index b0451f1c8e79..9a055dfb445a 100644
> --- a/net/mac80211/main.c
> +++ b/net/mac80211/main.c
> @@ -1118,6 +1118,19 @@ ieee80211_ifcomb_check(const struct ieee80211_iface_combination *c, int n_comb)
> return true;
> }
>
> +static void ieee80211_create_default_chandef(struct cfg80211_chan_def *chandef,
> + struct ieee80211_channel *chan)
> +{
> + *chandef = (struct cfg80211_chan_def) {
> + .chan = chan,
> + .width = chan->band == NL80211_BAND_S1GHZ ?
> + NL80211_CHAN_WIDTH_1 :
> + NL80211_CHAN_WIDTH_20_NOHT,
> + .center_freq1 = chan->center_freq,
> + .freq1_offset = chan->freq_offset,
> + }
> +}
> +
> int ieee80211_register_hw(struct ieee80211_hw *hw)
> {
> struct ieee80211_local *local = hw_to_local(hw);
> @@ -1261,9 +1274,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
> /* if none found then use the first anyway */
> if (i == sband->n_channels)
> i = 0;
> - cfg80211_chandef_create(&dflt_chandef,
> - &sband->channels[i],
> - NL80211_CHAN_NO_HT);
> + ieee80211_create_default_chandef(&dflt_chandef,
> + &sband->channels[i]);
> /* init channel we're on */
> local->monitor_chanreq.oper = dflt_chandef;
> if (local->emulate_chanctx) {
> diff --git a/net/wireless/chan.c b/net/wireless/chan.c
> index d9d4e043bb39..4ae2f6ca0378 100644
> --- a/net/wireless/chan.c
> +++ b/net/wireless/chan.c
> @@ -29,9 +29,10 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
>
> *chandef = (struct cfg80211_chan_def) {
> .chan = chan,
> - .freq1_offset = chan->freq_offset,
> };
>
> + WARN_ON(chan->band == NL80211_BAND_S1GHZ);
> +
> switch (chan_type) {
> case NL80211_CHAN_NO_HT:
> chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
>
Initially reading this I was a bit concerned because it means any
path calling cfg80211_chandef_create() wouldn't work for S1G; But it's
actually only a couple of places now that call it and - being forward
looking - for example with channel switching we would probably have
an S1G specific path similar to processing a S1G connection anyway. No
important paths (will confirm this) call this function anyway they
seem to build the chandef locally.
I'll do some testing, if it seems OK will send a new patchset.
lachlan
^ permalink raw reply
* Re: [PATCH wireless-next v2] wifi: cfg80211: init S1G properly when creating chandef
From: Johannes Berg @ 2026-03-11 11:07 UTC (permalink / raw)
To: Lachlan Hodges; +Cc: linux-wireless, arien.judge
In-Reply-To: <b725c0be05df1a9595c177aada4cc148bf555448.camel@sipsolutions.net>
On Wed, 2026-03-11 at 11:56 +0100, Johannes Berg wrote:
>
> +++ b/net/wireless/chan.c
> @@ -29,9 +29,10 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
>
> *chandef = (struct cfg80211_chan_def) {
> .chan = chan,
> - .freq1_offset = chan->freq_offset,
> };
>
> + WARN_ON(chan->band == NL80211_BAND_S1GHZ);
>
Hm, no, I guess that really should only allow 2.4, 5 and 6 GHz.
johannes
^ permalink raw reply
* Re: [BUG] wifi: rtw88: Hard system freeze on RTL8821CE when power_save is enabled (LPS/ASPM conflict)
From: LB F @ 2026-03-11 11:00 UTC (permalink / raw)
To: Ping-Ke Shih; +Cc: linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <e6720993c8c14245981432cfa4ae902b@realtek.com>
Hi Ping-Ke,
Thank you for the incredibly fast turnaround and for providing the RFT
patch with the DMI quirk!
First, I want to mention that I am not an IT professional or a
programmer. I am just a regular Linux user who really wants to help
solve this problem. I am trying my best to verify everything
carefully, so please forgive me if my terminology or induction was
slightly off.
To answer your clarifying questions from the previous emails:
> Just want to clarify that these logs only appear in test 3, right?
> No these logs in test 1/2.
Yes, exactly. The `failed to send h2c command` errors only caused a
complete system freeze when no workarounds were active and the adapter
attempted to sleep (Test 3).
> I think this is your perspective and induction, right? Did you measure
> real hardware signals?
You are entirely correct. This is just my induction based solely on
the timing of the logs and system behavior. I do not have access to an
oscilloscope or any hardware diagnostic tools. Given this, I
completely agree that your approach of applying a platform-specific
quirk is the safest and best solution.
> Forgot to say. Could you share your full name for me as a reporter
> in commit message?
My full name is Oleksandr Havrylov. I would be honored to be included
as the reporter in the commit message.
### Recent Baseline Testing Before Your Patch
Before applying your patch today, we ran a few more controlled tests
to double-check our baseline. We verified that our local workaround
(`modprobe.d disable_aspm=y`) **does indeed keep the system completely
stable** and prevents the hard freeze, even when NetworkManager's
`wifi.powersave` is set to ON (default).
However, we noticed one interesting detail in the kernel logs: while
the system no longer freezes with `disable_aspm=y`, `dmesg` still
constantly logs `firmware failed to leave lps state` and `failed to
send h2c command` when the laptop is completely idle. It seems the
firmware still crashes during LPS, but because ASPM is disabled, the
PCIe bus ignores the crash and the system survives perfectly fine. I
just wanted to mention this for completeness!
### Testing Plan
I have **not** applied your RFT patch just yet. I wanted to make sure
our testing baseline was 100% clean and documented first.
I will compile your patch and perform rigorous testing this evening (I
am in the EET timezone, Ukraine). I will test it with the native
`power_save` fully enabled to ensure your patch successfully prevents
the hard lockups as intended.
I will stay in touch and reply back to this thread with a formal
`Tested-by` confirmation (and any logs if needed) as soon as my
testing is complete. Thank you again for all your help!
Best regards,
Oleksandr Havrylov
ср, 11 мар. 2026 г. в 04:22, Ping-Ke Shih <pkshih@realtek.com>:
>
> Ping-Ke Shih <pkshih@realtek.com> wrote:
> >
> > LB F <goainwo@gmail.com> wrote:
> > >
> > > Hi Ping-Ke,
> > >
> > > Thank you for the incredibly fast response and assistance!
> > >
> > > > Can you dig kernel log (by netconsole or ramoops) if something useful?
> > > > I'd like to know this is hardware level freeze or kernel can capture something
> > > wrong.
> > >
> > > I managed to pull a call trace from a historic journald log just
> > > before the system hung. The kernel gets trapped in an IRQ thread
> > > inside `rtw_pci_interrupt_threadfn`, calling up into `mac80211`
> > > `ieee80211_rx_list` before everything freezes. Here is the relevant
> > > snippet:
> > >
> > > ```text
> > > Call Trace:
> > > <IRQ>
> > > ? __alloc_skb+0x23a/0x2a0
> > > ? __alloc_skb+0x10c/0x2a0
> > > ? __pfx_irq_thread_fn+0x10/0x10
> > > [ ... truncated module list ... ]
> > > Tainted: G W I 6.19.6-2-cachyos #1 PREEMPT(full)
> > > Hardware name: HP HP Notebook/81F0, BIOS F.50 11/20/2020
> > > RIP: 0010:ieee80211_rx_list+0x1012/0x1020 [mac80211]
> > > CPU: 2 UID: 0 PID: 765 Comm: irq/56-rtw88_pc
> > > rtw_pci_interrupt_threadfn+0x239/0x310 [rtw88_pci]
> > > ```
> > >
> > > It behaves exactly like a PCIe bus deadlock or a hardware fault that
> > > eventually brings down the CPU handling the IRQ.
> >
> > I wonder if there is a malformed data, causing this trace and the leads
> > kernel freezes. If we can do validation on RX data before calling
> > ieee80211_rx_list(), maybe trace disappears and everything will be fine?
> > Even no need workaround.
> >
> > >
> > > > Are these totally needed to workaround the problem? Or disable_aspm is enough?
> > > > I'd list them in order of power consumption impact:
> > > > 1. disable_aspm=y
> > > > 2. disable_lps_deep=y
> > > > 3. disable WiFi power save
> > >
> > > To verify which parameters are strictly necessary, I performed
> > > isolated testing today. I ensured no other modprobe configs were
> > > active, rebuilt the initramfs, and manually enforced that
> > > `wifi.powersave` was active via `iw dev wlan0 set power_save on`
> > > during all tests (as the OS power management profiles were defaulting
> > > it to off, which initially masked the issue).
> > >
> > > I tested each workaround individually across multiple sleep/wake
> > > cycles and active usage:
> > >
> > > **Test 1 (ASPM Disabled, LPS Deep Enabled):**
> > > - Kernel parameters: `rtw88_pci disable_aspm=y` (and `rtw88_core
> > > disable_lps_deep=n`)
> > > - Result: Stable. No freezes were observed during usage or transitions
> > > into/out of S3 sleep while power saving was enforced.
> > >
> > > **Test 2 (ASPM Enabled, LPS Deep Disabled):**
> > > - Kernel parameters: `rtw88_core disable_lps_deep=y` (and `rtw88_pci
> > > disable_aspm=n`)
> > > - Result: Stable. No freezes were observed under the same forced power
> > > save conditions.
> > >
> > > **Conclusion:** It appears we do not need both workarounds
> > > simultaneously for this specific hardware. Using only `disable_aspm=y`
> > > seems to be sufficient to prevent the system freeze. Given your note
> > > about the power consumption impact ranking, this looks like the
> > > optimal path forward.
> >
> > Let's test my RFT patch to disable ASPM then.
> >
> > >
> > > > But what does 'deadlock' mean? As I know NAPI poll is scheduled by ISR,
> > > > and going to receive packets. The rx_no_aspm workaround is to forcely turn
> > > > off ASPM during this period.
> > >
> > > By "deadlock" I meant a hardware-level bus lockup. It seems the
> > > physical RTL8821CE chip itself crashes or hangs the system's PCIe bus
> > > when trying to negotiate waking up from ASPM L1 while simultaneously
> > > existing in `LPS_DEEP_MODE_LCLK`. The `rx_no_aspm` workaround in NAPI
> > > helps during active Rx decoding, but the laptop often freezes while
> > > completely idle, presumably when the AP sends a basic beacon, the chip
> > > attempts to leave LPS Deep + L1, and the hardware simply gives up and
> > > halts the system.
> >
> > I think this is your perspective and induction, right? Did you measure
> > real hardware signals?
> >
> > My point is that if this is a hardware-level bus lockup, let's apply
> > quirk. If some malformed data causing kernel hangs, I'd add sanity check
> > on RX data, but I don't actually know what we should check for now.
> >
> > >
> > > > We have not modified RTL8821CE for a long time, so I'd add workaround
> > > > to specific platform as mentioned above.
> > >
> > > Adding a DMI/platform quirk specifically for this laptop to disable
> > > ASPM would be wonderful and deeply appreciated. I agree it is safer
> > > than touching the global flags for hardware that is functioning
> > > correctly out in the wild.
> > >
> > > Here is the exact identifying information for my system:
> > >
> > > System Vendor: HP
> > > Product Name: HP Notebook
> > > SKU Number: P3S95EA#ACB
> > > Family: 103C_5335KV
> > > PCI ID: 10ec:c821
> > > Subsystem ID: 103c:831a
> > >
> > > I am completely ready to test any patch or quirk you send my way.
> > > Thank you so much for your time and helping track this down!
> >
> > I sent a RFT [1] for test. Please check if it works on your HP notebook.
> > If you check rtw88 log, you can see I added similar patch 5 years ago,
> > and replaced by preferred the change of "rtwpci->rx_no_aspm", which I
> > think it can only resolve problem on partial notebooks though....
> >
> > [1]
> > https://lore.kernel.org/linux-wireless/20260311020816.7065-1-pkshih@realtek.
> > com/T/#u
>
> Forgot to say. Could you share your full name for me as a reporter
> in commit message?
>
>
^ permalink raw reply
* Re: [PATCH wireless-next v2] wifi: cfg80211: init S1G properly when creating chandef
From: Johannes Berg @ 2026-03-11 10:56 UTC (permalink / raw)
To: Lachlan Hodges; +Cc: linux-wireless, arien.judge
In-Reply-To: <4dhrrbuvxdgve2doc7qvabzjancimtqpounngyrxspk4d4rbls@xnad5bwciz7c>
On Wed, 2026-03-11 at 21:21 +1100, Lachlan Hodges wrote:
> On Wed, Mar 11, 2026 at 10:55:46AM +0100, Johannes Berg wrote:
> > On Wed, 2026-03-11 at 17:43 +1100, Lachlan Hodges wrote:
> > > When creating a chandef, the initial width is determined by the
> > > chan_type argument leading to a default width of 20/20_NOHT/40 which
> > > does not make sense for S1G channels. Fix this by ensuring we default
> > > S1G chandefs to a width of 1MHz.
> > >
> > > Signed-off-by: Lachlan Hodges <lachlan.hodges@morsemicro.com>
> > > ---
> > > v1 -> v2:
> > >
> > > - Remove the mac80211-based wording in the commit message and keep it
> > > simple.
> >
> > Thanks :)
> >
> > Now with more tea and all that, do we really want it to completely
> > ignore the width? Should that be documented? Almost feels like it should
> > WARN if you use it wrong, with an S1G channel but a regular width, and
> > mac80211 should be fixed?
>
> When you say "ignore the width"
Sorry, I meant the channel type (chantype argument).
> do you mean nothing checks it?
I meant for s1g the chantype argument would be ignored now, not that it
wasn't checked.
> If
> that's the case we probably need to add something within
> cfg80211_chandef_valid() to ensure if we have an S1G chan we don't
> have a non-S1G width i.e > 16MHz. That would fix mac80211 from
> giving it to the driver in the first place.
We don't have that? Seems like an oversight too, but I was thinking like
this (overall changes, not split to commits), since
cfg80211_chandef_create() really doesn't work for S1G since the chantype
is 20MHz-non-HT, 20MHz-HT, HT40+ or HT40-.
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index b0451f1c8e79..9a055dfb445a 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1118,6 +1118,19 @@ ieee80211_ifcomb_check(const struct ieee80211_iface_combination *c, int n_comb)
return true;
}
+static void ieee80211_create_default_chandef(struct cfg80211_chan_def *chandef,
+ struct ieee80211_channel *chan)
+{
+ *chandef = (struct cfg80211_chan_def) {
+ .chan = chan,
+ .width = chan->band == NL80211_BAND_S1GHZ ?
+ NL80211_CHAN_WIDTH_1 :
+ NL80211_CHAN_WIDTH_20_NOHT,
+ .center_freq1 = chan->center_freq,
+ .freq1_offset = chan->freq_offset,
+ }
+}
+
int ieee80211_register_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
@@ -1261,9 +1274,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
/* if none found then use the first anyway */
if (i == sband->n_channels)
i = 0;
- cfg80211_chandef_create(&dflt_chandef,
- &sband->channels[i],
- NL80211_CHAN_NO_HT);
+ ieee80211_create_default_chandef(&dflt_chandef,
+ &sband->channels[i]);
/* init channel we're on */
local->monitor_chanreq.oper = dflt_chandef;
if (local->emulate_chanctx) {
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index d9d4e043bb39..4ae2f6ca0378 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -29,9 +29,10 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
*chandef = (struct cfg80211_chan_def) {
.chan = chan,
- .freq1_offset = chan->freq_offset,
};
+ WARN_ON(chan->band == NL80211_BAND_S1GHZ);
+
switch (chan_type) {
case NL80211_CHAN_NO_HT:
chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
johannes
^ permalink raw reply related
* [PATCH v4] wifi: ath12k: fix endianness handling for SRNG ring pointer accesses
From: Alexander Wilhelm @ 2026-03-11 10:24 UTC (permalink / raw)
To: Jeff Johnson; +Cc: Baochen Qiang, ath12k, linux-wireless, linux-kernel
The SRNG head and tail ring pointers are stored in device memory as
little-endian values. On big-endian systems, direct dereferencing of these
pointers leads to incorrect values being read or written, causing ring
management issues and potentially breaking data flow.
This patch ensures all accesses to SRNG ring pointers use the appropriate
endianness conversions. This affects both read and write paths for source
and destination rings, as well as debug output. The changes guarantee
correct operation on both little- and big-endian architectures.
Signed-off-by: Alexander Wilhelm <alexander.wilhelm@westermo.com>
Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
---
Changes in v4:
- Rebase on latest 'ath' master
- Remove volatile from `hp_addr` due to the `checkpatch.pl` warning
- Fix opening braces at the end of line due to the `checkpatch.pl` error
- Fix `u32 *` cast in `wifi7/hal.c` due to the `sparse` error
Changes in v3:
- Rebase on latest 'ath' master
- Use always 'le32_to_cpu()' macro for conversions
Changes in v2:
- Set '__le32 *' type for 'hp_addr/tp_addr' in both 'dst_ring' and 'src_ring'
---
drivers/net/wireless/ath/ath12k/hal.c | 31 ++++++++++++---------
drivers/net/wireless/ath/ath12k/hal.h | 8 +++---
drivers/net/wireless/ath/ath12k/wifi7/hal.c | 14 ++++++----
3 files changed, 30 insertions(+), 23 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c
index a164563fff28..a9c9311538b0 100644
--- a/drivers/net/wireless/ath/ath12k/hal.c
+++ b/drivers/net/wireless/ath/ath12k/hal.c
@@ -355,7 +355,7 @@ int ath12k_hal_srng_dst_num_free(struct ath12k_base *ab, struct hal_srng *srng,
tp = srng->u.dst_ring.tp;
if (sync_hw_ptr) {
- hp = *srng->u.dst_ring.hp_addr;
+ hp = le32_to_cpu(*srng->u.dst_ring.hp_addr);
srng->u.dst_ring.cached_hp = hp;
} else {
hp = srng->u.dst_ring.cached_hp;
@@ -379,7 +379,7 @@ int ath12k_hal_srng_src_num_free(struct ath12k_base *ab, struct hal_srng *srng,
hp = srng->u.src_ring.hp;
if (sync_hw_ptr) {
- tp = *srng->u.src_ring.tp_addr;
+ tp = le32_to_cpu(*srng->u.src_ring.tp_addr);
srng->u.src_ring.cached_tp = tp;
} else {
tp = srng->u.src_ring.cached_tp;
@@ -501,9 +501,9 @@ void ath12k_hal_srng_access_begin(struct ath12k_base *ab, struct hal_srng *srng)
if (srng->ring_dir == HAL_SRNG_DIR_SRC) {
srng->u.src_ring.cached_tp =
- *(volatile u32 *)srng->u.src_ring.tp_addr;
+ le32_to_cpu(*srng->u.src_ring.tp_addr);
} else {
- hp = READ_ONCE(*srng->u.dst_ring.hp_addr);
+ hp = le32_to_cpu(READ_ONCE(*srng->u.dst_ring.hp_addr));
if (hp != srng->u.dst_ring.cached_hp) {
srng->u.dst_ring.cached_hp = hp;
@@ -529,24 +529,27 @@ void ath12k_hal_srng_access_end(struct ath12k_base *ab, struct hal_srng *srng)
*/
if (srng->ring_dir == HAL_SRNG_DIR_SRC) {
srng->u.src_ring.last_tp =
- *(volatile u32 *)srng->u.src_ring.tp_addr;
+ le32_to_cpu(*srng->u.src_ring.tp_addr);
/* Make sure descriptor is written before updating the
* head pointer.
*/
dma_wmb();
- WRITE_ONCE(*srng->u.src_ring.hp_addr, srng->u.src_ring.hp);
+ WRITE_ONCE(*srng->u.src_ring.hp_addr,
+ cpu_to_le32(srng->u.src_ring.hp));
} else {
- srng->u.dst_ring.last_hp = *srng->u.dst_ring.hp_addr;
+ srng->u.dst_ring.last_hp =
+ le32_to_cpu(*srng->u.dst_ring.hp_addr);
/* Make sure descriptor is read before updating the
* tail pointer.
*/
dma_mb();
- WRITE_ONCE(*srng->u.dst_ring.tp_addr, srng->u.dst_ring.tp);
+ WRITE_ONCE(*srng->u.dst_ring.tp_addr,
+ cpu_to_le32(srng->u.dst_ring.tp));
}
} else {
if (srng->ring_dir == HAL_SRNG_DIR_SRC) {
srng->u.src_ring.last_tp =
- *(volatile u32 *)srng->u.src_ring.tp_addr;
+ le32_to_cpu(*srng->u.src_ring.tp_addr);
/* Assume implementation use an MMIO write accessor
* which has the required wmb() so that the descriptor
* is written before the updating the head pointer.
@@ -556,7 +559,8 @@ void ath12k_hal_srng_access_end(struct ath12k_base *ab, struct hal_srng *srng)
(unsigned long)ab->mem,
srng->u.src_ring.hp);
} else {
- srng->u.dst_ring.last_hp = *srng->u.dst_ring.hp_addr;
+ srng->u.dst_ring.last_hp =
+ le32_to_cpu(*srng->u.dst_ring.hp_addr);
/* Make sure descriptor is read before updating the
* tail pointer.
*/
@@ -711,7 +715,7 @@ void ath12k_hal_srng_shadow_update_hp_tp(struct ath12k_base *ab,
* HP only when then ring isn't' empty.
*/
if (srng->ring_dir == HAL_SRNG_DIR_SRC &&
- *srng->u.src_ring.tp_addr != srng->u.src_ring.hp)
+ le32_to_cpu(*srng->u.src_ring.tp_addr) != srng->u.src_ring.hp)
ath12k_hal_srng_access_end(ab, srng);
}
@@ -810,14 +814,15 @@ void ath12k_hal_dump_srng_stats(struct ath12k_base *ab)
"src srng id %u hp %u, reap_hp %u, cur tp %u, cached tp %u last tp %u napi processed before %ums\n",
srng->ring_id, srng->u.src_ring.hp,
srng->u.src_ring.reap_hp,
- *srng->u.src_ring.tp_addr, srng->u.src_ring.cached_tp,
+ le32_to_cpu(*srng->u.src_ring.tp_addr),
+ srng->u.src_ring.cached_tp,
srng->u.src_ring.last_tp,
jiffies_to_msecs(jiffies - srng->timestamp));
else if (srng->ring_dir == HAL_SRNG_DIR_DST)
ath12k_err(ab,
"dst srng id %u tp %u, cur hp %u, cached hp %u last hp %u napi processed before %ums\n",
srng->ring_id, srng->u.dst_ring.tp,
- *srng->u.dst_ring.hp_addr,
+ le32_to_cpu(*srng->u.dst_ring.hp_addr),
srng->u.dst_ring.cached_hp,
srng->u.dst_ring.last_hp,
jiffies_to_msecs(jiffies - srng->timestamp));
diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h
index bf4f7dbae866..d8dbcc846387 100644
--- a/drivers/net/wireless/ath/ath12k/hal.h
+++ b/drivers/net/wireless/ath/ath12k/hal.h
@@ -921,7 +921,7 @@ struct hal_srng {
u32 tp;
/* Shadow head pointer location to be updated by HW */
- volatile u32 *hp_addr;
+ __le32 *hp_addr;
/* Cached head pointer */
u32 cached_hp;
@@ -930,7 +930,7 @@ struct hal_srng {
* will be a register address and need not be
* accessed through SW structure
*/
- u32 *tp_addr;
+ __le32 *tp_addr;
/* Current SW loop cnt */
u32 loop_cnt;
@@ -950,7 +950,7 @@ struct hal_srng {
u32 reap_hp;
/* Shadow tail pointer location to be updated by HW */
- u32 *tp_addr;
+ __le32 *tp_addr;
/* Cached tail pointer */
u32 cached_tp;
@@ -959,7 +959,7 @@ struct hal_srng {
* will be a register address and need not be accessed
* through SW structure
*/
- u32 *hp_addr;
+ __le32 *hp_addr;
/* Low threshold - in number of ring entries */
u32 low_threshold;
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal.c b/drivers/net/wireless/ath/ath12k/wifi7/hal.c
index bd1753ca0db6..c05bfcffdf5c 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hal.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hal.c
@@ -320,7 +320,7 @@ void ath12k_wifi7_hal_set_umac_srng_ptr_addr(struct ath12k_base *ab,
if (srng->ring_dir == HAL_SRNG_DIR_SRC) {
if (!ab->hw_params->supports_shadow_regs) {
srng->u.src_ring.hp_addr =
- (u32 *)((unsigned long)ab->mem + reg_base);
+ (__le32 *)((unsigned long)ab->mem + reg_base);
} else {
ath12k_dbg(ab, ATH12K_DBG_HAL,
"hal reg_base 0x%x shadow 0x%lx\n",
@@ -331,7 +331,7 @@ void ath12k_wifi7_hal_set_umac_srng_ptr_addr(struct ath12k_base *ab,
} else {
if (!ab->hw_params->supports_shadow_regs) {
srng->u.dst_ring.tp_addr =
- (u32 *)((unsigned long)ab->mem + reg_base +
+ (__le32 *)((unsigned long)ab->mem + reg_base +
(HAL_REO1_RING_TP - HAL_REO1_RING_HP));
} else {
ath12k_dbg(ab, ATH12K_DBG_HAL,
@@ -384,11 +384,13 @@ void ath12k_wifi7_hal_srng_update_hp_tp_addr(struct ath12k_base *ab,
srng = &hal->srng_list[ring_id];
if (srng_config->ring_dir == HAL_SRNG_DIR_DST)
- srng->u.dst_ring.tp_addr = (u32 *)(HAL_SHADOW_REG(shadow_cfg_idx) +
- (unsigned long)ab->mem);
+ srng->u.dst_ring.tp_addr =
+ (__le32 *)(HAL_SHADOW_REG(shadow_cfg_idx) +
+ (unsigned long)ab->mem);
else
- srng->u.src_ring.hp_addr = (u32 *)(HAL_SHADOW_REG(shadow_cfg_idx) +
- (unsigned long)ab->mem);
+ srng->u.src_ring.hp_addr =
+ (__le32 *)(HAL_SHADOW_REG(shadow_cfg_idx) +
+ (unsigned long)ab->mem);
}
u32 ath12k_wifi7_hal_ce_get_desc_size(enum hal_ce_desc type)
base-commit: c2bcd89db970ee73cccfb9c619b7287d6da4bf88
--
2.43.0
^ permalink raw reply related
* Re: [PATCH wireless-next v2] wifi: cfg80211: init S1G properly when creating chandef
From: Lachlan Hodges @ 2026-03-11 10:21 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, arien.judge
In-Reply-To: <791eaf8ab04dcbe01e2d71612d162f71c61e573a.camel@sipsolutions.net>
On Wed, Mar 11, 2026 at 10:55:46AM +0100, Johannes Berg wrote:
> On Wed, 2026-03-11 at 17:43 +1100, Lachlan Hodges wrote:
> > When creating a chandef, the initial width is determined by the
> > chan_type argument leading to a default width of 20/20_NOHT/40 which
> > does not make sense for S1G channels. Fix this by ensuring we default
> > S1G chandefs to a width of 1MHz.
> >
> > Signed-off-by: Lachlan Hodges <lachlan.hodges@morsemicro.com>
> > ---
> > v1 -> v2:
> >
> > - Remove the mac80211-based wording in the commit message and keep it
> > simple.
>
> Thanks :)
>
> Now with more tea and all that, do we really want it to completely
> ignore the width? Should that be documented? Almost feels like it should
> WARN if you use it wrong, with an S1G channel but a regular width, and
> mac80211 should be fixed?
When you say "ignore the width" do you mean nothing checks it? If
that's the case we probably need to add something within
cfg80211_chandef_valid() to ensure if we have an S1G chan we don't
have a non-S1G width i.e > 16MHz. That would fix mac80211 from
giving it to the driver in the first place.
lachlan
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox