* [PATCH v3 2/2] wifi: ath12k: release QMI handle on late init failures
From: Guangshuo Li @ 2026-07-18 7:40 UTC (permalink / raw)
To: Jeff Johnson, Pradeep Kumar Chitrapu, Vasanthakumar Thiagarajan,
Sathishkumar Muruganandam, Anilkumar Kolli, Ganesh Sesetti,
Baochen Qiang, linux-wireless, ath11k, linux-kernel, ath12k
Cc: Guangshuo Li
In-Reply-To: <20260718074026.3085688-1-lgs201920130244@gmail.com>
ath12k_qmi_init_service() initializes the QMI handle before allocating
the QMI event workqueue and registering the service lookup.
If either of these later initialization steps fails, the function
returns without releasing the initialized QMI handle. Since the failed
device is skipped by the hardware group rollback path, the handle is
leaked.
Release the QMI handle on the late failure paths.
ath12k_qmi_deinit_service() uses ab->qmi.ab to determine whether QMI
service initialization completed successfully. Set it only after all
initialization steps succeed.
Fixes: 088a099690e4 ("wifi: ath12k: fix error handling in creating hardware group")
Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
---
drivers/net/wireless/ath/ath12k/qmi.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c
index fd762b5d7bb5..692f1b2c2031 100644
--- a/drivers/net/wireless/ath/ath12k/qmi.c
+++ b/drivers/net/wireless/ath/ath12k/qmi.c
@@ -4041,7 +4041,6 @@ int ath12k_qmi_init_service(struct ath12k_base *ab)
memset(&ab->qmi.target, 0, sizeof(struct target_info));
memset(&ab->qmi.target_mem, 0, sizeof(struct target_mem_chunk));
- ab->qmi.ab = ab;
ab->qmi.target_mem_mode = ab->target_mem_mode;
ret = qmi_handle_init(&ab->qmi.handle, ATH12K_QMI_RESP_LEN_MAX,
@@ -4054,7 +4053,8 @@ int ath12k_qmi_init_service(struct ath12k_base *ab)
ab->qmi.event_wq = alloc_ordered_workqueue("ath12k_qmi_driver_event", 0);
if (!ab->qmi.event_wq) {
ath12k_err(ab, "failed to allocate workqueue\n");
- return -EFAULT;
+ ret = -EFAULT;
+ goto err_release_qmi_handle;
}
INIT_LIST_HEAD(&ab->qmi.event_list);
@@ -4067,9 +4067,16 @@ int ath12k_qmi_init_service(struct ath12k_base *ab)
if (ret < 0) {
ath12k_warn(ab, "failed to add qmi lookup\n");
destroy_workqueue(ab->qmi.event_wq);
- return ret;
+ goto err_release_qmi_handle;
}
+ ab->qmi.ab = ab;
+
+ return ret;
+
+err_release_qmi_handle:
+ qmi_handle_release(&ab->qmi.handle);
+
return ret;
}
--
2.43.0
^ permalink raw reply related
* [PATCH v3 1/2] wifi: ath11k: release QMI handle on late init failures
From: Guangshuo Li @ 2026-07-18 7:40 UTC (permalink / raw)
To: Jeff Johnson, Pradeep Kumar Chitrapu, Vasanthakumar Thiagarajan,
Sathishkumar Muruganandam, Anilkumar Kolli, Ganesh Sesetti,
Baochen Qiang, linux-wireless, ath11k, linux-kernel, ath12k
Cc: Guangshuo Li
In-Reply-To: <20260718074026.3085688-1-lgs201920130244@gmail.com>
ath11k_qmi_init_service() initializes the QMI handle before allocating
the QMI event workqueue and registering the service lookup.
If either of these later initialization steps fails, the function
returns without releasing the initialized QMI handle, leaking its
resources.
Release the QMI handle on the late failure paths.
Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices")
Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
---
drivers/net/wireless/ath/ath11k/qmi.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c
index 410a7ee076a0..6e3f82169d24 100644
--- a/drivers/net/wireless/ath/ath11k/qmi.c
+++ b/drivers/net/wireless/ath/ath11k/qmi.c
@@ -3329,7 +3329,8 @@ int ath11k_qmi_init_service(struct ath11k_base *ab)
ab->qmi.event_wq = alloc_ordered_workqueue("ath11k_qmi_driver_event", 0);
if (!ab->qmi.event_wq) {
ath11k_err(ab, "failed to allocate workqueue\n");
- return -EFAULT;
+ ret = -EFAULT;
+ goto err_release_qmi_handle;
}
INIT_LIST_HEAD(&ab->qmi.event_list);
@@ -3342,9 +3343,14 @@ int ath11k_qmi_init_service(struct ath11k_base *ab)
if (ret < 0) {
ath11k_warn(ab, "failed to add qmi lookup: %d\n", ret);
destroy_workqueue(ab->qmi.event_wq);
- return ret;
+ goto err_release_qmi_handle;
}
+ return ret;
+
+err_release_qmi_handle:
+ qmi_handle_release(&ab->qmi.handle);
+
return ret;
}
--
2.43.0
^ permalink raw reply related
* [PATCH v3 0/2] wifi: ath11k/ath12k: release QMI handles on late init failures
From: Guangshuo Li @ 2026-07-18 7:40 UTC (permalink / raw)
To: Jeff Johnson, Pradeep Kumar Chitrapu, Vasanthakumar Thiagarajan,
Sathishkumar Muruganandam, Anilkumar Kolli, Ganesh Sesetti,
Baochen Qiang, linux-wireless, ath11k, linux-kernel, ath12k
Cc: Guangshuo Li
This series fixes QMI handle leaks in the late initialization failure
paths of ath11k and ath12k.
Both drivers initialize the QMI handle before allocating the QMI event
workqueue and registering the service lookup. If either of these later
steps fails, the initialized QMI handle is not released.
Patch 1 fixes the leak in ath11k.
Patch 2 fixes the leak in ath12k and sets ab->qmi.ab only after QMI
service initialization completes successfully.
v3:
- Split the ath11k and ath12k changes into separate patches, as
requested by Jeff Johnson.
v2:
- Set ath12k ab->qmi.ab only after QMI service initialization succeeds,
as suggested by Baochen Qiang.
- Fix the same late initialization QMI handle leak in ath11k, as
suggested by Vasanthakumar Thiagarajan.
- Drop the Reviewed-by tag due to the code changes.
Guangshuo Li (2):
wifi: ath11k: release QMI handle on late init failures
wifi: ath12k: release QMI handle on late init failures
drivers/net/wireless/ath/ath11k/qmi.c | 10 ++++++++--
drivers/net/wireless/ath/ath12k/qmi.c | 13 ++++++++++---
2 files changed, 18 insertions(+), 5 deletions(-)
--
2.43.0
^ permalink raw reply
* Re: [PATCH v2] wifi: ath11k/ath12k: release QMI handles on late init failures
From: Guangshuo Li @ 2026-07-18 7:06 UTC (permalink / raw)
To: Jeff Johnson
Cc: Jeff Johnson, Anilkumar Kolli, Sriram R, Shashidhar Lakkavalli,
Kalle Valo, Venkateswara Naralasetty, Vasanthakumar Thiagarajan,
Baochen Qiang, linux-wireless, ath11k, linux-kernel, ath12k
In-Reply-To: <faf48c76-373a-42c1-9c69-cfbc5178640a@oss.qualcomm.com>
Hi Jeff,
Thank you for the review.
On Thu, 16 Jul 2026 at 08:59, Jeff Johnson
<jeff.johnson@oss.qualcomm.com> wrote:
>
> On 7/14/2026 11:40 PM, Guangshuo Li wrote:
> > ath11k and ath12k initialize their QMI handles before allocating the QMI
> > event workqueues and registering the service lookups.
> >
> > If either of these later initialization steps fails, the functions
> > return without releasing the initialized QMI handles, leaking their
> > resources.
> >
> > Release the QMI handles on the late failure paths in both drivers.
> >
> > ath12k_qmi_deinit_service() uses ab->qmi.ab to determine whether QMI
> > service initialization completed successfully. Set it only after all
> > initialization steps succeed. Keep the ath11k assignment unchanged
> > because ath11k does not use it as an initialization-success guard.
> >
> > Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices")
> > Fixes: 088a099690e4 ("wifi: ath12k: fix error handling in creating hardware group")
> > Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
> > ---
> > v2:
> > - Set ath12k ab->qmi.ab only after QMI service initialization succeeds,
> > as suggested by Baochen Qiang.
> > - Fix the same late initialization QMI handle leak in ath11k, as
> > suggested by Vasanthakumar Thiagarajan.
> > - Drop the Reviewed-by tag due to the code changes.
> >
> > drivers/net/wireless/ath/ath11k/qmi.c | 10 ++++++++--
> > drivers/net/wireless/ath/ath12k/qmi.c | 13 ++++++++++---
> > 2 files changed, 18 insertions(+), 5 deletions(-)
>
> Please split into two patches, one for ath11k and one for ath12k
>
I will split the ath11k and ath12k changes
into two separate patches and send a v3 series.
Best regards,
Guangshuo
^ permalink raw reply
* [PATCH v2 2/2] wifi: brcmfmac: drain bus_reset work on device removal
From: Fan Wu @ 2026-07-18 2:43 UTC (permalink / raw)
To: arend.vanspriel, kvalo
Cc: eddiephillips, franky.lin, hante.meuleman, wright.feng,
linux-wireless, brcm80211, brcm80211-dev-list.pdl,
SHA-cyfmac-dev-list, linux-kernel, Fan Wu, stable
In-Reply-To: <20260718024353.3147201-1-fanwu01@zju.edu.cn>
brcmf_fw_crashed() and the debugfs "reset" entry both schedule
drvr->bus_reset, whose callback recovers drvr through container_of()
and dereferences it. The removal path frees drvr (brcmf_free ->
wiphy_free) without draining the work, so a bus_reset callback pending
or running during removal can outlive drvr.
Cancellation cannot live in brcmf_detach() or brcmf_free(): the work
callback reaches teardown through the bus .reset op (PCIe
brcmf_pcie_reset -> brcmf_detach; SDIO brcmf_sdio_bus_reset ->
brcmf_sdiod_remove -> brcmf_free), so cancelling there would wait for
the running work and deadlock.
Add a per-bus mutex (bus_reset_lock) and route all arming through
brcmf_bus_schedule_reset(), which under the lock skips when the bus is
marked removing. Each bus remove entry calls
brcmf_bus_cancel_reset_work(), which under the same lock sets removing
and cancels the work. Holding the mutex across cancel_work_sync() makes
the set-removing + drain step atomic. Every producer reaches the arming
path from process context -- the PCIe firmware-halt notification runs in
the threaded IRQ handler (brcmf_pcie_isr_thread) and the SDIO hostmail
path runs from the data workqueue -- so the mutex is taken only in
sleepable contexts. Where applicable the remove entry first stops the
firmware-crash producer: on PCIe mask the mailbox and synchronize_irq;
on SDIO unregister the bus interrupt and cancel the data worker, which
also reports firmware halts through brcmf_fw_crashed(). The mutex is
initialized at bus allocation. The SDIO suspend power-off path frees
drvr through the same brcmf_sdiod_remove() and takes the same lock;
resume re-allows the work only on a successful re-probe.
Also guard brcmf_fw_crashed() against a NULL bus_if/drvr: it can fire
before brcmf_attach() wires up drvr, and it dereferences drvr
(bphy_err/brcmf_dev_coredump) before reaching the arming gate.
The bus_reset work is shared across buses, so the drain is applied to
every remove path: PCIe (the .reset op introduced by the Fixes commit),
SDIO (arms the same work through brcmf_fw_crashed()), and USB (via the
debugfs "reset" entry). cancel_work_sync() drains a running or pending
bus_reset work item before removal frees drvr, and patch 1/2 makes the
scratch-buffer release safe when reset teardown has already released
those DMA buffers.
This patch fixes the lifetime of the bus_reset work item itself. It does
not attempt to address the separate, pre-existing lifetime of the
asynchronous firmware completion started by the PCIe reset path. That
callback needs its own lifetime/ownership protocol and is being tracked
separately.
This issue was found by an in-house static analysis tool.
Fixes: 4684997d9eea ("brcmfmac: reset PCIe bus on a firmware crash")
Cc: stable@vger.kernel.org
Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
Assisted-by: Codex:gpt-5.6
---
.../broadcom/brcm80211/brcmfmac/bcmsdh.c | 13 ++++++
.../broadcom/brcm80211/brcmfmac/bus.h | 6 +++
.../broadcom/brcm80211/brcmfmac/core.c | 46 +++++++++++++++++--
.../broadcom/brcm80211/brcmfmac/pcie.c | 6 +++
.../broadcom/brcm80211/brcmfmac/sdio.c | 6 +++
.../broadcom/brcm80211/brcmfmac/sdio.h | 1 +
.../broadcom/brcm80211/brcmfmac/usb.c | 3 ++
7 files changed, 77 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
index d24b80e49..ec487c6f2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -1069,6 +1069,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
bus_if = kzalloc_obj(*bus_if);
if (!bus_if)
return -ENOMEM;
+ mutex_init(&bus_if->bus_reset_lock);
sdiodev = kzalloc_obj(*sdiodev);
if (!sdiodev) {
kfree(bus_if);
@@ -1130,6 +1131,14 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func)
if (func->num != 1)
return;
+ /* Drain bus_reset before the shared brcmf_sdiod_remove()
+ * teardown, which the SDIO reset callback also reaches. The
+ * data worker can arm bus_reset via brcmf_fw_crashed(); cancel
+ * it first.
+ */
+ brcmf_sdio_cancel_datawork(sdiodev->bus);
+ brcmf_bus_cancel_reset_work(bus_if);
+
/* only proceed with rest of cleanup if func 1 */
brcmf_sdiod_remove(sdiodev);
@@ -1204,6 +1213,8 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
} else {
/* power will be cut so remove device, probe again in resume */
brcmf_sdiod_intr_unregister(sdiodev);
+ brcmf_sdio_cancel_datawork(sdiodev->bus);
+ brcmf_bus_cancel_reset_work(bus_if);
ret = brcmf_sdiod_remove(sdiodev);
if (ret)
brcmf_err("Failed to remove device on suspend\n");
@@ -1229,6 +1240,8 @@ static int brcmf_ops_sdio_resume(struct device *dev)
ret = brcmf_sdiod_probe(sdiodev);
if (ret)
brcmf_err("Failed to probe device on resume\n");
+ else
+ brcmf_bus_allow_reset_work(bus_if);
} else {
if (sdiodev->wowl_enabled && sdiodev->settings->bus.sdio.oob_irq_supported)
disable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
index fe31051a9..9371c1489 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
@@ -9,6 +9,7 @@
#include <linux/kernel.h>
#include <linux/firmware.h>
#include <linux/device.h>
+#include <linux/mutex.h>
#include "debug.h"
/* IDs of the 6 default common rings of msgbuf protocol */
@@ -179,6 +180,8 @@ struct brcmf_bus {
enum brcmf_fwvendor fwvid;
bool always_use_fws_queue;
bool wowl_supported;
+ bool removing; /* device removal in progress; quiesce async work */
+ struct mutex bus_reset_lock;
const struct brcmf_bus_ops *ops;
struct brcmf_bus_msgbuf *msgbuf;
@@ -186,6 +189,9 @@ struct brcmf_bus {
struct list_head list;
};
+void brcmf_bus_cancel_reset_work(struct brcmf_bus *bus_if);
+void brcmf_bus_allow_reset_work(struct brcmf_bus *bus_if);
+
/*
* callback wrappers
*/
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index ec1706478..dad6f4563 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -1167,6 +1167,35 @@ static int brcmf_revinfo_read(struct seq_file *s, void *data)
return 0;
}
+/*
+ * Serialize arming from debugfs reset and brcmf_fw_crashed() against
+ * teardown. The remove path sets ->removing and drains the work while
+ * holding bus_reset_lock, so a racing armer is either drained or skips it.
+ */
+static void brcmf_bus_schedule_reset(struct brcmf_bus *bus_if)
+{
+ mutex_lock(&bus_if->bus_reset_lock);
+ if (bus_if->drvr && bus_if->drvr->bus_reset.func && !bus_if->removing)
+ schedule_work(&bus_if->drvr->bus_reset);
+ mutex_unlock(&bus_if->bus_reset_lock);
+}
+
+void brcmf_bus_cancel_reset_work(struct brcmf_bus *bus_if)
+{
+ mutex_lock(&bus_if->bus_reset_lock);
+ bus_if->removing = true;
+ if (bus_if->drvr)
+ cancel_work_sync(&bus_if->drvr->bus_reset);
+ mutex_unlock(&bus_if->bus_reset_lock);
+}
+
+void brcmf_bus_allow_reset_work(struct brcmf_bus *bus_if)
+{
+ mutex_lock(&bus_if->bus_reset_lock);
+ bus_if->removing = false;
+ mutex_unlock(&bus_if->bus_reset_lock);
+}
+
static void brcmf_core_bus_reset(struct work_struct *work)
{
struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
@@ -1187,7 +1216,7 @@ static ssize_t bus_reset_write(struct file *file, const char __user *user_buf,
if (value != 1)
return -EINVAL;
- schedule_work(&drvr->bus_reset);
+ brcmf_bus_schedule_reset(drvr->bus_if);
return count;
}
@@ -1417,14 +1446,23 @@ void brcmf_dev_coredump(struct device *dev)
void brcmf_fw_crashed(struct device *dev)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_pub *drvr = bus_if->drvr;
+ struct brcmf_pub *drvr;
+
+ /* May fire before brcmf_attach() wires up drvr, or after removal
+ * has cleared it; guard the derefs below (and the arming gate in
+ * brcmf_bus_schedule_reset() already checks drvr/->removing).
+ */
+ if (!bus_if)
+ return;
+ drvr = bus_if->drvr;
+ if (!drvr)
+ return;
bphy_err(drvr, "Firmware has halted or crashed\n");
brcmf_dev_coredump(dev);
- if (drvr->bus_reset.func)
- schedule_work(&drvr->bus_reset);
+ brcmf_bus_schedule_reset(bus_if);
}
void brcmf_detach(struct device *dev)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
index 9f10b3fff..55f4d7b97 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -2503,6 +2503,7 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ret = -ENOMEM;
goto fail;
}
+ mutex_init(&bus->bus_reset_lock);
bus->msgbuf = kzalloc_obj(*bus->msgbuf);
if (!bus->msgbuf) {
ret = -ENOMEM;
@@ -2598,6 +2599,11 @@ brcmf_pcie_remove(struct pci_dev *pdev)
if (devinfo->ci)
brcmf_pcie_intr_disable(devinfo);
+ if (devinfo->irq_allocated)
+ synchronize_irq(pdev->irq);
+
+ brcmf_bus_cancel_reset_work(bus);
+
brcmf_detach(&pdev->dev);
brcmf_free(&pdev->dev);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index 8fb595733..f541c0130 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -4560,6 +4560,12 @@ int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
return ret;
}
+void brcmf_sdio_cancel_datawork(struct brcmf_sdio *bus)
+{
+ if (bus)
+ cancel_work_sync(&bus->datawork);
+}
+
/* Detach and free everything */
void brcmf_sdio_remove(struct brcmf_sdio *bus)
{
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
index 80180d5c6..b93d153a8 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
@@ -361,6 +361,7 @@ int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev);
int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev);
void brcmf_sdio_remove(struct brcmf_sdio *bus);
void brcmf_sdio_isr(struct brcmf_sdio *bus, bool in_isr);
+void brcmf_sdio_cancel_datawork(struct brcmf_sdio *bus);
void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, bool active);
void brcmf_sdio_wowl_config(struct device *dev, bool enabled);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
index 0b52f968b..b41949a9b 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
@@ -1260,6 +1260,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo,
ret = -ENOMEM;
goto fail;
}
+ mutex_init(&bus->bus_reset_lock);
bus->dev = dev;
bus_pub->bus = bus;
@@ -1329,6 +1330,8 @@ brcmf_usb_disconnect_cb(struct brcmf_usbdev_info *devinfo)
return;
brcmf_dbg(USB, "Enter, bus_pub %p\n", devinfo);
+ brcmf_bus_cancel_reset_work(devinfo->bus_pub.bus);
+
brcmf_detach(devinfo->dev);
brcmf_free(devinfo->dev);
kfree(devinfo->bus_pub.bus);
--
2.34.1
^ permalink raw reply related
* [PATCH v2 0/2] wifi: brcmfmac: fix bus_reset work lifetime and scratch-buffer DMA double-free
From: Fan Wu @ 2026-07-18 2:43 UTC (permalink / raw)
To: arend.vanspriel, kvalo
Cc: eddiephillips, franky.lin, hante.meuleman, wright.feng,
linux-wireless, brcm80211, brcm80211-dev-list.pdl,
SHA-cyfmac-dev-list, linux-kernel, Fan Wu
This series fixes two narrow reset/remove teardown bugs: a use-after-free
where the bus_reset work can outlive drvr (freed on removal via
brcmf_free() -> wiphy_free()), and a DMA double-free in the PCIe
reset/remove teardown.
Patch 1/2 makes brcmf_pcie_release_scratchbuffers() safe to call again
after a prior release: it freed the scratch/ringupd DMA buffers without
clearing the pointers, so reset teardown followed by remove() could
double-free them. Split out as its own fix so it can be reviewed and
backported independently.
Patch 2/2 drains the bus_reset work item on device removal. A per-bus
mutex serializes arming against that drain
(brcmf_bus_cancel_reset_work() sets "removing" and cancels the work
under the lock, before any free), and brcmf_fw_crashed() is NULL-guarded
before it dereferences drvr. The mutex is safe because every arming
producer runs in process context (the PCIe firmware-halt notification
runs in the threaded IRQ handler; the SDIO one in the data workqueue).
This series does not attempt to address the separate, pre-existing
lifetime of the asynchronous firmware completion started by the PCIe
reset path. That callback needs its own lifetime/ownership protocol and
is being tracked separately.
---
Changes in v2:
- Following the v1 discussion with Eddie Phillips and Arend van Spriel,
retain the mutex approach.
- Split the scratch-buffer DMA double-free into 1/2.
- Add the NULL guard before the drvr dereferences in 2/2.
- Rebased onto wl-next/main.
Link: https://lore.kernel.org/linux-wireless/20260709101635.103005-1-fanwu01@zju.edu.cn/
Fan Wu (2):
wifi: brcmfmac: make release_scratchbuffers idempotent
wifi: brcmfmac: drain bus_reset work on device removal
.../broadcom/brcm80211/brcmfmac/bcmsdh.c | 13 ++++++
.../broadcom/brcm80211/brcmfmac/bus.h | 6 +++
.../broadcom/brcm80211/brcmfmac/core.c | 46 +++++++++++++++++--
.../broadcom/brcm80211/brcmfmac/pcie.c | 14 ++++++-
.../broadcom/brcm80211/brcmfmac/sdio.c | 6 +++
.../broadcom/brcm80211/brcmfmac/sdio.h | 1 +
.../broadcom/brcm80211/brcmfmac/usb.c | 3 ++
7 files changed, 83 insertions(+), 6 deletions(-)
--
2.34.1
^ permalink raw reply
* [PATCH v2 1/2] wifi: brcmfmac: make release_scratchbuffers idempotent
From: Fan Wu @ 2026-07-18 2:43 UTC (permalink / raw)
To: arend.vanspriel, kvalo
Cc: eddiephillips, franky.lin, hante.meuleman, wright.feng,
linux-wireless, brcm80211, brcm80211-dev-list.pdl,
SHA-cyfmac-dev-list, linux-kernel, Fan Wu, stable
In-Reply-To: <20260718024353.3147201-1-fanwu01@zju.edu.cn>
brcmf_pcie_release_scratchbuffers() frees the shared.scratch and
shared.ringupd DMA buffers with dma_free_coherent() but does not clear
the pointers afterwards, unlike the sibling release_ringbuffers() which
NULLs commonrings/flowrings/idxbuf on release.
Both the bus_reset .reset callback (brcmf_pcie_reset) and
brcmf_pcie_remove() call release_scratchbuffers. When reset teardown
has run before removal, remove's own teardown would call
dma_free_coherent() a second time on the already-freed DMA allocation.
NULL the pointers after free, matching release_ringbuffers(), so a later
release observes that the allocation has already been released. This
patch makes repeated sequential release safe; the reset-work lifetime is
handled separately by the following patch.
This issue was found by an in-house static analysis tool.
Fixes: 4684997d9eea ("brcmfmac: reset PCIe bus on a firmware crash")
Cc: stable@vger.kernel.org
Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
Assisted-by: Codex:gpt-5.6
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
index 13662aa4b..9f10b3fff 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -1383,16 +1383,20 @@ static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo)
static void
brcmf_pcie_release_scratchbuffers(struct brcmf_pciedev_info *devinfo)
{
- if (devinfo->shared.scratch)
+ if (devinfo->shared.scratch) {
dma_free_coherent(&devinfo->pdev->dev,
BRCMF_DMA_D2H_SCRATCH_BUF_LEN,
devinfo->shared.scratch,
devinfo->shared.scratch_dmahandle);
- if (devinfo->shared.ringupd)
+ devinfo->shared.scratch = NULL;
+ }
+ if (devinfo->shared.ringupd) {
dma_free_coherent(&devinfo->pdev->dev,
BRCMF_DMA_D2H_RINGUPD_BUF_LEN,
devinfo->shared.ringupd,
devinfo->shared.ringupd_dmahandle);
+ devinfo->shared.ringupd = NULL;
+ }
}
static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo)
--
2.34.1
^ permalink raw reply related
* [regression] rtw89_8852be: silent RX stalls since v7.1; reverting bda294ed0ed0 appears to fix it
From: Armin Breiteneder @ 2026-07-17 22:48 UTC (permalink / raw)
To: Ping-Ke Shih; +Cc: o-Hao Huang, linux-wireless, linux-kernel
In-Reply-To: <7de74e5c-3ad4-4264-a250-fcb1e66675be@breiteneder.me>
Hi,
I am hitting a reproducible WiFi regression with rtw89_8852be
(RTL8852BE, 10ec:b852, CV:1 RFE:1, firmware 0.29.29.18) on Fedora 44.
Good: 7.0.14-201.fc44
Bad: 7.1.3-200.fc44, and v7.1 vanilla
Reverting bda294ed0ed0 ("wifi: rtw89: Drop malformed AMPDU frames with
abnormal PN") on top of v7.1 appears to fix it -- the stalls are gone.
Symptom: every few minutes the RX data path stalls silently for 1-7
minutes at a time. The radio link stays perfectly healthy -- still
associated, signal unchanged (~-62 dBm), "tx failed" and "tx retries"
both 0 (the AP ACKs every frame we send), "beacon loss" 0 -- and the
station's rx_packets counter keeps climbing at ~23 frames/s. Yet almost
nothing is delivered to the network stack. The kernel logs nothing at
all. Then it recovers on its own, without re-association, and the whole
backlog is delivered in one burst.
Quantified over one 54-second stall (mac80211 station counter vs. the
napi_gro_receive tracepoint):
frames received and counted from the AP : ~1230
frames delivered to the network stack : ~211
frames withheld : ~1000
delivered in one interval on recovery : +5070
Everything that does get through during the stall is broadcast/multicast
only (ARP, IPv6 multicast, vendor ethertypes) -- exactly the traffic
that bypasses Block-Ack reordering.
That fits the suspected commit: dropping a frame inside an A-MPDU leaves
a hole in the sequence numbers, so the RX reorder buffer waits for
something that never arrives, everything behind it piles up, and it is
only released once a timeout fires. I have not verified this in the code
beyond reading the commit, so please treat the mechanism as a hypothesis
-- the revert result is the solid part.
The AP is a FRITZ!Box 4040 on channel 36 (5180 MHz, VHT80), non-DFS.
Already ruled out:
- Powersave: disabled (NetworkManager wifi.powersave=2, confirmed via iw).
- ASPM: disable_clkreq=y disable_aspm_l1=y disable_aspm_l1ss=y
disable_ps_mode=y
all set and confirmed active. The stall still occurs -- note this is the
workaround that reportedly fixes the CachyOS case below; it does not
help here.
- Signal / range / DFS: signal constant across the stall, channel is
non-DFS.
- TX path: txf=0 and txr=0 throughout.
- Stable patches: "git log v7.1..v7.1.3 -- net/mac80211/
drivers/net/wireless/
realtek/rtw89/" is empty, so this came in with the v7.1 merge window.
I could not find a way to trigger the stall on demand, so I could not
bisect; the suspect was found by reading the v7.0..v7.1 commits touching
the RX/AMPDU path and running a targeted revert test.
A regression with the same version boundary was reported against the
CachyOS kernel: https://github.com/CachyOS/linux-cachyos/issues/921
Fedora bug: https://bugzilla.redhat.com/show_bug.cgi?id=2501974
Happy to run a debug build or test patches -- I have the affected
hardware and the failure shows up within minutes of normal use, so
turnaround is fast.
#regzbot introduced: bda294ed0ed0
Thanks,
Armin
^ permalink raw reply
* [PATCH wireless-next] wifi: rt2x00: Use device-managed register buffers
From: Rosen Penev @ 2026-07-17 22:00 UTC (permalink / raw)
To: linux-wireless; +Cc: Stanislaw Gruszka, open list
The rt2x00 PCI and USB probe paths allocate EEPROM and RF storage with
plain kzalloc() and then free it from bus-specific teardown helpers. The
USB path also manages the CSR cache the same way. These buffers are
tied to the device lifetime, so the explicit free paths add probe and
disconnect cleanup without providing separate ownership.
Allocate the buffers with devm_kzalloc() before the mac80211 hardware is
allocated, then attach the resulting storage to struct rt2x00_dev after
the driver-private state exists. This lets driver detach and probe
failure rely on device-managed cleanup and removes the duplicated
bus-specific buffer freeing.
Assisted-by: Codex:GPT-5.5
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
.../net/wireless/ralink/rt2x00/rt2x00pci.c | 104 ++++--------------
.../net/wireless/ralink/rt2x00/rt2x00usb.c | 67 ++++-------
2 files changed, 43 insertions(+), 128 deletions(-)
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00pci.c b/drivers/net/wireless/ralink/rt2x00/rt2x00pci.c
index cabeef0dde45..d4635b531481 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00pci.c
@@ -19,84 +19,50 @@
#include "rt2x00.h"
#include "rt2x00pci.h"
-/*
- * PCI driver handlers.
- */
-static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev)
-{
- kfree(rt2x00dev->rf);
- rt2x00dev->rf = NULL;
-
- kfree(rt2x00dev->eeprom);
- rt2x00dev->eeprom = NULL;
-
- if (rt2x00dev->csr.base) {
- iounmap(rt2x00dev->csr.base);
- rt2x00dev->csr.base = NULL;
- }
-}
-
-static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev)
-{
- struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev);
-
- rt2x00dev->csr.base = pci_ioremap_bar(pci_dev, 0);
- if (!rt2x00dev->csr.base)
- goto exit;
-
- rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
- if (!rt2x00dev->eeprom)
- goto exit;
-
- rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL);
- if (!rt2x00dev->rf)
- goto exit;
-
- return 0;
-
-exit:
- rt2x00_probe_err("Failed to allocate registers\n");
-
- rt2x00pci_free_reg(rt2x00dev);
-
- return -ENOMEM;
-}
-
int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops)
{
- struct ieee80211_hw *hw;
struct rt2x00_dev *rt2x00dev;
+ struct ieee80211_hw *hw;
+ void __iomem *base;
+ __le16 *eeprom;
int retval;
u16 chip;
+ u32 *rf;
- retval = pci_enable_device(pci_dev);
+ retval = pcim_enable_device(pci_dev);
if (retval) {
rt2x00_probe_err("Enable device failed\n");
return retval;
}
- retval = pci_request_regions(pci_dev, pci_name(pci_dev));
- if (retval) {
- rt2x00_probe_err("PCI request regions failed\n");
- goto exit_disable_device;
+ base = pcim_iomap_region(pci_dev, 0, pci_name(pci_dev));
+ if (IS_ERR(base)) {
+ rt2x00_probe_err("PCI iomap region failed\n");
+ return PTR_ERR(base);
}
pci_set_master(pci_dev);
- if (pci_set_mwi(pci_dev))
+ if (pcim_set_mwi(pci_dev))
rt2x00_probe_err("MWI not available\n");
if (dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32))) {
rt2x00_probe_err("PCI DMA not supported\n");
- retval = -EIO;
- goto exit_release_regions;
+ return -EIO;
}
+ eeprom = devm_kzalloc(&pci_dev->dev, ops->eeprom_size, GFP_KERNEL);
+ if (!eeprom)
+ return -ENOMEM;
+
+ rf = devm_kzalloc(&pci_dev->dev, ops->rf_size, GFP_KERNEL);
+ if (!rf)
+ return -ENOMEM;
+
hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
if (!hw) {
rt2x00_probe_err("Failed to allocate hardware\n");
- retval = -ENOMEM;
- goto exit_release_regions;
+ return -ENOMEM;
}
pci_set_drvdata(pci_dev, hw);
@@ -105,18 +71,17 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops)
rt2x00dev->dev = &pci_dev->dev;
rt2x00dev->ops = ops;
rt2x00dev->hw = hw;
+ rt2x00dev->csr.base = base;
rt2x00dev->irq = pci_dev->irq;
rt2x00dev->name = ops->name;
+ rt2x00dev->eeprom = eeprom;
+ rt2x00dev->rf = rf;
if (pci_is_pcie(pci_dev))
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCIE);
else
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
- retval = rt2x00pci_alloc_reg(rt2x00dev);
- if (retval)
- goto exit_free_device;
-
/*
* Because rt3290 chip use different efuse offset to read efuse data.
* So before read efuse it need to indicate it is the
@@ -127,23 +92,13 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops)
retval = rt2x00lib_probe_dev(rt2x00dev);
if (retval)
- goto exit_free_reg;
+ goto exit_free_device;
return 0;
-exit_free_reg:
- rt2x00pci_free_reg(rt2x00dev);
-
exit_free_device:
ieee80211_free_hw(hw);
-exit_release_regions:
- pci_clear_mwi(pci_dev);
- pci_release_regions(pci_dev);
-
-exit_disable_device:
- pci_disable_device(pci_dev);
-
return retval;
}
EXPORT_SYMBOL_GPL(rt2x00pci_probe);
@@ -153,19 +108,8 @@ void rt2x00pci_remove(struct pci_dev *pci_dev)
struct ieee80211_hw *hw = pci_get_drvdata(pci_dev);
struct rt2x00_dev *rt2x00dev = hw->priv;
- /*
- * Free all allocated data.
- */
rt2x00lib_remove_dev(rt2x00dev);
- rt2x00pci_free_reg(rt2x00dev);
ieee80211_free_hw(hw);
-
- /*
- * Free the PCI device data.
- */
- pci_clear_mwi(pci_dev);
- pci_disable_device(pci_dev);
- pci_release_regions(pci_dev);
}
EXPORT_SYMBOL_GPL(rt2x00pci_remove);
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
index 47e427ea8622..938320478728 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
@@ -755,55 +755,31 @@ void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev)
}
EXPORT_SYMBOL_GPL(rt2x00usb_uninitialize);
-/*
- * USB driver handlers.
- */
-static void rt2x00usb_free_reg(struct rt2x00_dev *rt2x00dev)
-{
- kfree(rt2x00dev->rf);
- rt2x00dev->rf = NULL;
-
- kfree(rt2x00dev->eeprom);
- rt2x00dev->eeprom = NULL;
-
- kfree(rt2x00dev->csr.cache);
- rt2x00dev->csr.cache = NULL;
-}
-
-static int rt2x00usb_alloc_reg(struct rt2x00_dev *rt2x00dev)
-{
- rt2x00dev->csr.cache = kzalloc(CSR_CACHE_SIZE, GFP_KERNEL);
- if (!rt2x00dev->csr.cache)
- goto exit;
-
- rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
- if (!rt2x00dev->eeprom)
- goto exit;
-
- rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL);
- if (!rt2x00dev->rf)
- goto exit;
-
- return 0;
-
-exit:
- rt2x00_probe_err("Failed to allocate registers\n");
-
- rt2x00usb_free_reg(rt2x00dev);
-
- return -ENOMEM;
-}
-
int rt2x00usb_probe(struct usb_interface *usb_intf,
const struct rt2x00_ops *ops)
{
struct usb_device *usb_dev = interface_to_usbdev(usb_intf);
- struct ieee80211_hw *hw;
struct rt2x00_dev *rt2x00dev;
+ struct ieee80211_hw *hw;
+ __le16 *eeprom;
+ void *cache;
int retval;
+ u32* rf;
usb_reset_device(usb_dev);
+ cache = devm_kzalloc(&usb_intf->dev, CSR_CACHE_SIZE, GFP_KERNEL);
+ if (!cache)
+ return -ENOMEM;
+
+ eeprom = devm_kzalloc(&usb_intf->dev, ops->eeprom_size, GFP_KERNEL);
+ if (!eeprom)
+ return -ENOMEM;
+
+ rf = devm_kzalloc(&usb_intf->dev, ops->rf_size, GFP_KERNEL);
+ if (!rf)
+ return -ENOMEM;
+
hw = ieee80211_alloc_hw(struct_size(rt2x00dev, anchor, 1), ops->hw);
if (!hw) {
rt2x00_probe_err("Failed to allocate hardware\n");
@@ -816,16 +792,15 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
rt2x00dev->dev = &usb_intf->dev;
rt2x00dev->ops = ops;
rt2x00dev->hw = hw;
+ rt2x00dev->csr.cache = cache;
+ rt2x00dev->eeprom = eeprom;
+ rt2x00dev->rf = rf;
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_USB);
INIT_WORK(&rt2x00dev->rxdone_work, rt2x00usb_work_rxdone);
INIT_WORK(&rt2x00dev->txdone_work, rt2x00usb_work_txdone);
- retval = rt2x00usb_alloc_reg(rt2x00dev);
- if (retval)
- goto exit_free_device;
-
init_usb_anchor(rt2x00dev->anchor);
retval = rt2x00lib_probe_dev(rt2x00dev);
@@ -836,9 +811,6 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
exit_free_anchor:
usb_kill_anchored_urbs(rt2x00dev->anchor);
- rt2x00usb_free_reg(rt2x00dev);
-
-exit_free_device:
ieee80211_free_hw(hw);
usb_set_intfdata(usb_intf, NULL);
@@ -855,7 +827,6 @@ void rt2x00usb_disconnect(struct usb_interface *usb_intf)
* Free all allocated data.
*/
rt2x00lib_remove_dev(rt2x00dev);
- rt2x00usb_free_reg(rt2x00dev);
ieee80211_free_hw(hw);
usb_set_intfdata(usb_intf, NULL);
--
2.55.0
^ permalink raw reply related
* Re: [PATCH] wifi: cfg80211: Constify struct cfg80211_ops
From: Jeff Johnson @ 2026-07-17 17:08 UTC (permalink / raw)
To: Christophe JAILLET; +Cc: linux-kernel, kernel-janitors, linux-wireless
In-Reply-To: <5aace954b6ef5c42017b83a1bffb859618e9498a.1784013180.git.christophe.jaillet@wanadoo.fr>
On 7/14/2026 12:14 AM, Christophe JAILLET wrote:
subject tags should be wifi: ath6kl:
I can fix this when I take the patch if there are no other comments
> 'struct cfg80211_ops' is not modified in this driver.
>
> Constifying this structure moves some data to a read-only section, so
> increases overall security, especially when the structure holds some
> function pointers.
>
> On a x86_64, with allmodconfig, as an example:
> Before:
> ======
> text data bss dec hex filename
> 143726 34579 192 178497 2b941 drivers/net/wireless/ath/ath6kl/cfg80211.o
>
> After:
> =====
> text data bss dec hex filename
> 144814 33491 192 178497 2b941 drivers/net/wireless/ath/ath6kl/cfg80211.o
>
> Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
> ---
> Compile tested only.
> ---
> drivers/net/wireless/ath/ath6kl/cfg80211.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
> index cc0f2c45fc3a..ecde91159b54 100644
> --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
> +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
> @@ -3437,7 +3437,7 @@ ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
> },
> };
>
> -static struct cfg80211_ops ath6kl_cfg80211_ops = {
> +static const struct cfg80211_ops ath6kl_cfg80211_ops = {
> .add_virtual_intf = ath6kl_cfg80211_add_iface,
> .del_virtual_intf = ath6kl_cfg80211_del_iface,
> .change_virtual_intf = ath6kl_cfg80211_change_iface,
^ permalink raw reply
* Re: [PATCH 1/1] wifi: ath11k: move ATH11K_FIRMWARE_MODE_OFF to ath11k_firmware_mode
From: Jeff Johnson @ 2026-07-17 16:57 UTC (permalink / raw)
To: Ziyang Huang, johannes; +Cc: jjohnson, linux-wireless, ath11k, linux-kernel
In-Reply-To: <TYZPR01MB55561DF4543A0265B47A58CDC9C92@TYZPR01MB5556.apcprd01.prod.exchangelabs.com>
On 3/3/2025 7:31 AM, Ziyang Huang wrote:
> Put it together with other modes.
your commit text should be more descriptive:
Describe your changes ... as if you are giving orders to the codebase to
change its behaviour.
>
> Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
> ---
> drivers/net/wireless/ath/ath11k/core.h | 3 +++
> drivers/net/wireless/ath/ath11k/qmi.h | 1 -
> 2 files changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
> index a9dc7fe7765a..bfa2e8b21b5f 100644
> --- a/drivers/net/wireless/ath/ath11k/core.h
> +++ b/drivers/net/wireless/ath/ath11k/core.h
> @@ -158,6 +158,9 @@ enum ath11k_firmware_mode {
> /* factory tests etc */
> ATH11K_FIRMWARE_MODE_FTM,
>
> + /* power off */
> + ATH11K_FIRMWARE_MODE_OFF = 4,
> +
> /* Cold boot calibration */
> ATH11K_FIRMWARE_MODE_COLD_BOOT = 7,
> };
> diff --git a/drivers/net/wireless/ath/ath11k/qmi.h b/drivers/net/wireless/ath/ath11k/qmi.h
> index 7e06d100af57..5e8fd22bb9a0 100644
> --- a/drivers/net/wireless/ath/ath11k/qmi.h
> +++ b/drivers/net/wireless/ath/ath11k/qmi.h
> @@ -36,7 +36,6 @@
> #define QMI_WLFW_FW_INIT_DONE_IND_V01 0x0038
>
> #define QMI_WLANFW_MAX_DATA_SIZE_V01 6144
> -#define ATH11K_FIRMWARE_MODE_OFF 4
> #define ATH11K_COLD_BOOT_FW_RESET_DELAY (60 * HZ)
>
> #define ATH11K_QMI_DEVICE_BAR_SIZE 0x200000
I like what this is doing, however IMO there is room for improvement.
the firmware mode is part of the QMI ABI and hence the enum should actually be
located in qmi.h. And that means any .c files which need the relocated enum
would need to include qmi.h
And if you post a v2, use ath-next as the branch tag, [PATCH ath-next v2]
/jeff
^ permalink raw reply
* Re: [RFC PATCH net-next 0/6] net: add GeoNetworking protocol
From: Simon Dietz @ 2026-07-17 15:40 UTC (permalink / raw)
To: andrew
Cc: andrew+netdev, davem, dietz23838, edumazet, johannes, kuniyu,
linux-wireless, netdev, simon.dietz
In-Reply-To: <9db571aa-4d5c-456a-ab24-796119c9807b@lunn.ch>
> I'm probably doing a deep dive too early, but ...
Thanks for your time and the fast response.
> Nothing new has been added to /proc for a long time. Please consider
> a different interface. I've not yet looked to see what is there, but
> networking now pretty much only uses netlink.
/proc has been used during the development of the gn module for passing
gps data from the user space to the kernel. This behaviour has been
changed to ioctl. Procfs has only been kept for debugging reasons. It
can safely be removed and will be in the next patch version.
> New IOCTL code is also very likely to be rejected. The functionality
> should go through netlink.
I'll take a look into netlink and rewrite the new IOCTL code.
> Generally, inline functions in a .c file are rejected. It is better
> to let the compiler decide. The exception would be if you have a
> benchmark which shows inline actually helps.
Noted. No inline functions (besides proven by benchmarks).
> This seems like debug. At minimum, it should be _dbg(), but maybe it
> should be removed altogether.
I thought to have changed all pr_info to pr_debug, this one slipped
through.
> When does this wrap around? Maybe add it as a comment.
Noted.
> Commented out code is not something we want in the kernel.
Indeed all BUG calls should have been removed with one of the
subsequent patches together with most of the commented out code. I'll
take another look to ensure all comment out code is removed.
> Maybe one of your later patches fixes this. We might want to consider
> squashing them, so the review is done on the final clean code.
That's good advice. I'll adhere to it.
> netdev uses reverse christmas tree, longest lines first, shortest
> last. It should apply to all functions.
Fixed in patch 6/6. And partially included in squashing subsequent
patches so they fully adhere to the coding style from the start.
> Not the sort of thing you normally see in the kernel.
> I've not looked at the code enough to see the big picture, but
> generally, the kernel routing table is static, and fed from a user
> space daemon. Should all this code be in user space?
In GeoNetworking routing decisions can be and are in non broadcast
situations based on the distance to the other vehicle/host. To be more
precise routing is based on if the reciever is in the same area as the
sender. If the sender needs to forward a packet to a reciever outside
its own range, it is forward to the intermediary closest to the
reciever.
That's kind of the core idea/feature of GeoNetworking. I don't see the
possibility to move this part into the userspace. But this does not
mean that there is no option at all.
>> static void debug_loc_te(void) ...
> debugfs? a netlink dump operation?
I'd like to keep this debug function for now. I agree that it should be
removed/changed in the final patch before an actual merge to net-next.
Simon
^ permalink raw reply
* Re: [PATCH] wifi: rtw89: 8852au: Add support for Mercusys MA72XH
From: Abhishek Tamboli @ 2026-07-17 15:24 UTC (permalink / raw)
To: Ping-Ke Shih; +Cc: linux-wireless, linux-kernel
In-Reply-To: <8fb9ced500144618b7f43e54c12a25ff@realtek.com>
On Wed, Jul 15, 2026 at 09:16:09AM +0000, Ping-Ke Shih wrote:
> I seems that my Windows desktop can't access this link, but
> Ubuntu is fine. I have not idea why.
>
> Anyway, the reporter is still not confirmed if this patch works.
> Can you post the update here when getting acked?
Sure, I will update here.
And sorry for the late reply.
Abhishek
^ permalink raw reply
* [BUG] mt7925e: MT7927 stuck in D3 after VFIO guest reboot
From: Michał Wiśniewski @ 2026-07-17 15:07 UTC (permalink / raw)
To: linux-wireless
Cc: nbd, lorenzo, shayne.chen, deren.wu, linux-mediatek, linux-kernel
Hello,
I have a MediaTek MT7927 passed through with VFIO to a Kali Linux VM.
The card works normally after starting the VM, but running systemctl
reboot inside Kali causes the VM to hang and the physical MT7927 to
stop responding.
After the failure:
PCI configuration space reads as all ff;
lspci reports Unknown header type 7f;
FLR and secondary bus reset do not recover the card;
QEMU remains in D state even after SIGKILL;
only fully disconnecting AC power from the host restores the card.
The main host messages are:
kvm: vfio: Unable to power on device, stuck in D3
pcieport 0000:00:1c.0: retraining failed
vfio-pci 0000:02:00.0: not ready 65535ms after FLR; giving up
pcieport 0000:00:1c.0: Data Link Layer Link Active not set in 100 msec
Hardware:
MediaTek MT7927
PCI ID: 14c3:7927
subsystem ID: 105b:e104
Guest:
Kali Linux 2026.2
driver: mt7925e
linux-next tag: next-20260716
commit: 1a1757b76427f6201bfe0bf1bea9f7574f332a93
uname -r: 7.2.0-rc3-next-20260716-mt7927-test
Host:
Proxmox VE 9.2.4
kernel: 7.0.14-5-pve
QEMU: 11.0.2
driver: vfio-pci
Regards,
Michał Wiśniewski
^ permalink raw reply
* Re: (subset) [PATCH 14/16] carl9170: main: guard op_config and bss_info_changed against non-STARTED state
From: Jeff Johnson @ 2026-07-17 15:06 UTC (permalink / raw)
To: Christian Lamparter, Masi Osmani; +Cc: linux-wireless
In-Reply-To: <AM7PPF5613FA0B6FDA6759CDCBE2421A8039441A@AM7PPF5613FA0B6.EURP251.PROD.OUTLOOK.COM>
On Tue, 17 Mar 2026 12:06:32 +0100, Masi Osmani wrote:
> During driver deregistration (USB unbind or restart), mac80211 calls
> carl9170_op_config() and carl9170_op_bss_info_changed() which write
> hardware registers such as AR9170_MAC_REG_SLOT_TIME (0x1c36f0) via
> carl9170_set_slot_time(). At this point the firmware is already dead:
> carl9170_restart() has transitioned the state machine from STARTED to
> IDLE, and IS_ACCEPTING_CMD() returns true for IDLE (state >= IDLE),
> so the USB command is attempted but times out with -EIO:
>
> [...]
Applied, thanks!
[16/16] carl9170: cmd: downgrade transient register I/O errors to wiphy_dbg
commit: 14941957d2825f62228a7db1fa6dc9cfba9fca60
Best regards,
--
Jeff Johnson <jeff.johnson@oss.qualcomm.com>
^ permalink raw reply
* Re: (subset) [PATCH 01/10] carl9170: mac80211: enable Short Guard Interval for 20 MHz
From: Jeff Johnson @ 2026-07-17 15:06 UTC (permalink / raw)
To: Christian Lamparter, Masi Osmani; +Cc: linux-wireless, ath9k-devel
In-Reply-To: <AM7PPF5613FA0B662B9909BAEB554565F499444A@AM7PPF5613FA0B6.EURP251.PROD.OUTLOOK.COM>
On Thu, 12 Mar 2026 11:37:56 +0100, Masi Osmani wrote:
> The AR9170 hardware supports Short Guard Interval (400ns) for both
> 20 MHz and 40 MHz channel widths. SGI_40 was already advertised in
> the HT capabilities, but SGI_20 was missing. This reduces the OFDM
> symbol duration from 800ns to 400ns on 20 MHz channels, increasing
> the maximum PHY rate from 130 Mbps to 144.4 Mbps (MCS 15, 2SS).
>
> ath9k (the PCI sibling for the same AR9xxx chipset family) has
> always advertised both SGI_20 and SGI_40.
>
> [...]
Applied, thanks!
[03/10] carl9170: mac80211: document spatial multiplexing power save handler
commit: 031e27f95761fa3e14de4af53939a6694be1ab0a
[05/10] carl9170: rx: track PHY errors via debugfs
commit: b2de486100b0cf7b770a2ab46e9a1c4b2b8f3fd8
Best regards,
--
Jeff Johnson <jeff.johnson@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH 16/16] carl9170: cmd: downgrade transient register I/O errors to wiphy_dbg
From: Jeff Johnson @ 2026-07-17 15:06 UTC (permalink / raw)
To: Christian Lamparter, Masi Osmani; +Cc: linux-wireless
In-Reply-To: <AM7PPF5613FA0B67FB95CB5305CEF9DAA209441A@AM7PPF5613FA0B6.EURP251.PROD.OUTLOOK.COM>
On Tue, 17 Mar 2026 12:06:34 +0100, Masi Osmani wrote:
> Register read/write failures during deauth/teardown transitions are
> harmless — mac80211 tries to read survey stats or write slot_time
> while the firmware is in a transitional state. The command times
> out with -EIO but the adapter recovers and re-authenticates normally.
>
> Downgrade both "writing reg ... failed" and "reading regs failed"
> from wiphy_err to wiphy_dbg to reduce dmesg noise. The errors are
> still visible with dynamic debug enabled for investigation.
>
> [...]
Applied, thanks!
[16/16] carl9170: cmd: downgrade transient register I/O errors to wiphy_dbg
commit: 14941957d2825f62228a7db1fa6dc9cfba9fca60
Best regards,
--
Jeff Johnson <jeff.johnson@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH v2] wifi: ath12k: Constify struct ath12k_dp_arch_ops
From: Jeff Johnson @ 2026-07-17 15:06 UTC (permalink / raw)
To: Jeff Johnson, Christophe JAILLET
Cc: linux-kernel, kernel-janitors, linux-wireless, ath12k
In-Reply-To: <969d732e2c6f169e1aa5e89c7e01743a1adb55df.1784010931.git.christophe.jaillet@wanadoo.fr>
On Tue, 14 Jul 2026 10:39:14 +0200, Christophe JAILLET wrote:
> 'struct ath12k_dp_arch_ops' is not modified in this driver.
>
> Constifying this structure moves some data to a read-only section, so
> increases overall security, especially when the structure holds some
> function pointers.
>
> On a x86_64, with allmodconfig, as an example:
> Before:
> ======
> text data bss dec hex filename
> 6318 3384 0 9702 25e6 drivers/net/wireless/ath/ath12k/wifi7/dp.o
>
> [...]
Applied, thanks!
[1/1] wifi: ath12k: Constify struct ath12k_dp_arch_ops
commit: ca435fd0650ac512ab6c5bdfeb90ed130b8f7574
Best regards,
--
Jeff Johnson <jeff.johnson@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH v2] wifi: ath12k: fix scan command endianness on big endian
From: Jeff Johnson @ 2026-07-17 15:06 UTC (permalink / raw)
To: Jeff Johnson, Baochen Qiang, Alexander Wilhelm
Cc: linux-wireless, ath12k, linux-kernel
In-Reply-To: <20260703-fix-channel-list-copy-v2-1-372c39306d79@westermo.com>
On Fri, 03 Jul 2026 09:35:38 +0200, Alexander Wilhelm wrote:
> ath12k_wmi_scan_req_arg stores scan parameters in CPU-native byte order,
> while ath12k_wmi_send_scan_start_cmd() writes them into a WMI command
> buffer whose contents must be in little-endian format. The existing code
> copies the channel list and writes s_ssid and hint_bssid related values to
> the command buffer without endian conversion. As a result, scan requests
> contain invalid parameters on big-endian systems and fail.
>
> [...]
Applied, thanks!
[1/1] wifi: ath12k: fix scan command endianness on big endian
commit: 8e3d6b596453c518a7ebdef2c785550c5e291dc0
Best regards,
--
Jeff Johnson <jeff.johnson@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH ath-next 0/2] wifi: ath: Correctly copy the hint BSSID in WMI scan request
From: Jeff Johnson @ 2026-07-17 15:06 UTC (permalink / raw)
To: Jeff Johnson, Jeff Johnson
Cc: linux-wireless, ath11k, ath12k, linux-kernel, Baochen Qiang
In-Reply-To: <20260713-ath12k_wmi_send_scan_start_cmd-bad-hint_bssid-v1-0-4ffc4a472992@oss.qualcomm.com>
On Mon, 13 Jul 2026 09:15:48 -0700, Jeff Johnson wrote:
> Issue was reported in ath12k, but exists in ath11k as well.
>
Applied, thanks!
[1/2] wifi: ath12k: Correctly copy the hint BSSID in WMI scan request
commit: b127f79a49335679d117406257cedab4fc20596a
[2/2] wifi: ath11k: Correctly copy the hint BSSID in WMI scan request
commit: 0db9d58c8757d0be5ed546109e37bcb10f6c1fb6
Best regards,
--
Jeff Johnson <jeff.johnson@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH ath-next v2 0/3] wifi: ath12k: Fix memory allocation and improve reserved memory handling
From: Jeff Johnson @ 2026-07-17 15:06 UTC (permalink / raw)
To: ath12k, Aaradhana Sahu; +Cc: linux-wireless
In-Reply-To: <20260630062048.1615178-1-aaradhana.sahu@oss.qualcomm.com>
On Tue, 30 Jun 2026 11:50:45 +0530, Aaradhana Sahu wrote:
> The current implementation relies on index-based device tree reserved
> memory lookup. Different platform variants define reserved memory
> regions in different orders and combinations, making the index-based
> lookup fragile across platforms.
>
> Currently, the driver allocates the HOST_DDR_REGION_TYPE
> starting from the base of the Q6 region, which overlaps the Q6 read-only
> firmware section. This causes firmware assertions during QMI memory
> allocation, as the firmware expects writable regions to be placed after the
> read-only section.
>
> [...]
Applied, thanks!
[1/3] wifi: ath12k: switch to name-based reserved memory lookup
commit: 2a1ac0368e1a891b1d1fa91192a2eaf865495f08
[2/3] wifi: ath12k: refactor QMI memory assignment
commit: db4e4af6e8261d83c5658fc9a84fce37a9ae692a
[3/3] wifi: ath12k: allocate HOST_DDR and BDF regions after Q6 RO region
commit: 3ed52d62f47de46dc1113671c057ff376d0fec27
Best regards,
--
Jeff Johnson <jeff.johnson@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH ath-next] wifi: ath12k: Set congestion control max MSDU count
From: Jeff Johnson @ 2026-07-17 15:06 UTC (permalink / raw)
To: ath12k, Thiraviyam Mariyappan; +Cc: linux-wireless
In-Reply-To: <20260622062614.760166-1-thiraviyam.mariyappan@oss.qualcomm.com>
On Mon, 22 Jun 2026 11:56:14 +0530, Thiraviyam Mariyappan wrote:
> Currently when running 128 clients UDP DL test in 5 GHz HE80 (NSS 2x2),
> firmware uses the default max MSDU count (16K MSDUs). This lower limit
> causes the firmware to compute a smaller TQM drop threshold, aggregate
> packets at a reduced rate, and results in increased packet drops with
> TQM drop threshold as the completion reason.
>
> To fix this issue, set WMI_PDEV_PARAM_SET_CONG_CTRL_MAX_MSDUS to the TX
> descriptor count using ath12k_wmi_pdev_set_param(). This increases the
> TQM drop threshold, reduces drop events, and improves throughput from
> ~722 Mbps to ~1060 Mbps with 1200 Mbps ingress.
>
> [...]
Applied, thanks!
[1/1] wifi: ath12k: Set congestion control max MSDU count
commit: 78ad50d9071d07510e190d858a76b27a8339932f
Best regards,
--
Jeff Johnson <jeff.johnson@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH v3 ath-current] wifi: ath12k: convert scan timeout to wiphy delayed work
From: Jeff Johnson @ 2026-07-17 14:40 UTC (permalink / raw)
To: Runyu Xiao, Jeff Johnson
Cc: linux-wireless, ath12k, linux-kernel, Johannes Berg, Jianhao Xu,
stable
In-Reply-To: <20260717025602.262916-1-runyu.xiao@seu.edu.cn>
On 7/16/2026 7:56 PM, Runyu Xiao wrote:
> ath12k_mac_op_stop() is called with the wiphy mutex held and calls
> ath12k_mac_stop(), which cancels ar->scan.timeout. The timeout worker
you are missing a very important detail, namely it is a synchronous cancel
> also takes the wiphy mutex before aborting the scan, so synchronously
> cancelling it from the stop path can deadlock if the worker has started
> and is waiting for the same mutex.
>
> Do not drop the wiphy mutex inside the mac80211 stop callback. Convert
What does this mean? Where are we currently dropping the wiphy mutex?
You should describe the patch in terms of the current code, not in terms of
any prior versions of your patch.
> ar->scan.timeout to wiphy_delayed_work instead, so the timeout callback
> runs in wiphy work context with the wiphy mutex held. This matches the
> locking model used by the scan vdev cleanup work and lets stop/cancel
> paths use wiphy_delayed_work_cancel() while they already hold the wiphy
> mutex.
>
> The old scan-finish path could cancel the delayed work directly from WMI
what is "old"? There is the current code and the new proposed code.
> event context. With wiphy_delayed_work that cancellation must happen from
> wiphy context, so keep it in scan.vdev_clean_wk. Mark scans whose cleanup
> work has been queued so a timeout work item that was already queued before
> cleanup runs does not abort a scan that is already finishing.
My AI review agent thinks this logic is unnecessary, but I haven't looked at
this in detail.
"summary": "finish_queued flag is a redundant substitute for
wiphy_delayed_work_cancel: __ath12k_mac_scan_finish is always called under
wiphy lock, making direct cancellation safe",
"failure_scenario": "Every caller of __ath12k_mac_scan_finish holds the wiphy
lock (directly or via wiphy_work dispatch), so wiphy_delayed_work_cancel could
be called there directly — as the old cancel_delayed_work was. The new
finish_queued flag instead defers suppression to the timeout work itself.
Since ath12k_scan_abort already has an explicit ATH12K_SCAN_IDLE bail-out path
(line 5232) with a comment covering the timeout-vs-completion race, the
finish_queued guard in ath12k_scan_timeout_work provides no additional safety.
The cost is 8 reset sites (lines 5337, 5624, 5681, 5775, 10971, 13969, 14012,
15061) where a future error path that forgets the reset leaves
finish_queued=true, silently suppressing the next legitimate timeout abort and
leaving the driver wedged in SCAN_RUNNING with no recovery."
>
> Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices")
> Suggested-by: Johannes Berg <johannes@sipsolutions.net>
> Cc: stable@vger.kernel.org
> Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
> ---
> Changes in v3:
> - Convert scan.timeout to wiphy_delayed_work instead of dropping the
> mac80211-owned wiphy lock in ath12k_mac_op_stop().
> - Cancel the timeout from scan.vdev_clean_wk to preserve the
> scan-finish cancellation from wiphy context.
> - Add scan.finish_queued so an already queued timeout work item does not
> abort a scan that has already queued its cleanup work.
>
> Changes in v2:
> - Rebase on ath.git ath-current.
> - Use ath-current subject tag as requested.
> - Move the synchronous scan timeout drain out of the locked stop path
> instead of adding it in the wrong start-path context.
> - Update Fixes to the ath12k commit that introduced the stop-time
> scan.timeout drain.
FWIW I'd suggest looking into using the 'b4' tool for future contributions.
It will help you with patch history, including providing links to the prior
versions
https://b4.docs.kernel.org/en/latest/#for-developers
>
> drivers/net/wireless/ath/ath12k/core.c | 2 +-
> drivers/net/wireless/ath/ath12k/core.h | 3 +-
> drivers/net/wireless/ath/ath12k/mac.c | 50 ++++++++++++++++++--------
> 3 files changed, 38 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
> index 742d4fd1b598..95673d3be9da 100644
> --- a/drivers/net/wireless/ath/ath12k/core.c
> +++ b/drivers/net/wireless/ath/ath12k/core.c
> @@ -1463,7 +1463,7 @@ void ath12k_core_halt(struct ath12k *ar)
>
> ath12k_mac_scan_finish(ar);
> ath12k_mac_peer_cleanup_all(ar);
> - cancel_delayed_work_sync(&ar->scan.timeout);
> + wiphy_delayed_work_cancel(ath12k_ar_to_hw(ar)->wiphy, &ar->scan.timeout);
> cancel_work_sync(&ar->regd_update_work);
> cancel_work_sync(&ar->regd_channel_update_work);
> cancel_work_sync(&ab->rfkill_work);
> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
> index fc5127b5c1a3..b6fd5e9dfdb7 100644
> --- a/drivers/net/wireless/ath/ath12k/core.h
> +++ b/drivers/net/wireless/ath/ath12k/core.h
> @@ -635,11 +635,12 @@ struct ath12k {
> struct completion started;
> struct completion completed;
> struct completion on_channel;
> - struct delayed_work timeout;
> + struct wiphy_delayed_work timeout;
> enum ath12k_scan_state state;
> bool is_roc;
> int roc_freq;
> bool roc_notify;
> + bool finish_queued;
> struct wiphy_work vdev_clean_wk;
> struct ath12k_link_vif *arvif;
> } scan;
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 51c4df32e716..f53df8d4c808 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -5162,7 +5162,7 @@ void __ath12k_mac_scan_finish(struct ath12k *ar)
> ieee80211_remain_on_channel_expired(hw);
> fallthrough;
> case ATH12K_SCAN_STARTING:
> - cancel_delayed_work(&ar->scan.timeout);
> + ar->scan.finish_queued = true;
> complete_all(&ar->scan.completed);
> wiphy_work_queue(ar->ah->hw->wiphy, &ar->scan.vdev_clean_wk);
> break;
> @@ -5254,14 +5254,23 @@ static void ath12k_scan_abort(struct ath12k *ar)
> spin_unlock_bh(&ar->data_lock);
> }
>
> -static void ath12k_scan_timeout_work(struct work_struct *work)
> +static void ath12k_scan_timeout_work(struct wiphy *wiphy,
> + struct wiphy_work *work)
> {
> - struct ath12k *ar = container_of(work, struct ath12k,
> - scan.timeout.work);
> + struct wiphy_delayed_work *dwork;
> + struct ath12k *ar;
> +
> + dwork = container_of(work, struct wiphy_delayed_work, work);
> + ar = container_of(dwork, struct ath12k, scan.timeout);
> +
> + spin_lock_bh(&ar->data_lock);
> + if (ar->scan.finish_queued) {
> + spin_unlock_bh(&ar->data_lock);
> + return;
> + }
> + spin_unlock_bh(&ar->data_lock);
if the flag is necessary, all of that could become:
scoped_guard(spinlock_bh, &ar->data_lock)
if (ar->scan.finish_queued)
return;
>
> - wiphy_lock(ath12k_ar_to_hw(ar)->wiphy);
> ath12k_scan_abort(ar);
> - wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
> }
>
> static void ath12k_mac_scan_send_complete(struct ath12k *ar,
> @@ -5292,6 +5301,8 @@ static void ath12k_scan_vdev_clean_work(struct wiphy *wiphy, struct wiphy_work *
>
> arvif = ar->scan.arvif;
>
> + wiphy_delayed_work_cancel(wiphy, &ar->scan.timeout);
> +
> /* The scan vdev has already been deleted. This can occur when a
> * new scan request is made on the same vif with a different
> * frequency, causing the scan arvif to move from one radio to
> @@ -5323,6 +5334,7 @@ static void ath12k_scan_vdev_clean_work(struct wiphy *wiphy, struct wiphy_work *
> }
>
> ar->scan.state = ATH12K_SCAN_IDLE;
> + ar->scan.finish_queued = false;
> ar->scan_channel = NULL;
> ar->scan.roc_freq = 0;
> spin_unlock_bh(&ar->data_lock);
> @@ -5609,6 +5621,7 @@ static int ath12k_mac_initiate_hw_scan(struct ieee80211_hw *hw,
> reinit_completion(&ar->scan.completed);
> ar->scan.state = ATH12K_SCAN_STARTING;
> ar->scan.is_roc = false;
> + ar->scan.finish_queued = false;
> ar->scan.arvif = arvif;
> ret = 0;
> break;
> @@ -5665,6 +5678,7 @@ static int ath12k_mac_initiate_hw_scan(struct ieee80211_hw *hw,
>
> spin_lock_bh(&ar->data_lock);
> ar->scan.state = ATH12K_SCAN_IDLE;
> + ar->scan.finish_queued = false;
> spin_unlock_bh(&ar->data_lock);
> goto exit;
> }
> @@ -5672,9 +5686,10 @@ static int ath12k_mac_initiate_hw_scan(struct ieee80211_hw *hw,
> ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac scan started");
>
> /* Add a margin to account for event/command processing */
> - ieee80211_queue_delayed_work(ath12k_ar_to_hw(ar), &ar->scan.timeout,
> - msecs_to_jiffies(arg->max_scan_time +
> - ATH12K_MAC_SCAN_TIMEOUT_MSECS));
> + wiphy_delayed_work_queue(ath12k_ar_to_hw(ar)->wiphy,
> + &ar->scan.timeout,
> + msecs_to_jiffies(arg->max_scan_time +
> + ATH12K_MAC_SCAN_TIMEOUT_MSECS));
>
> exit:
> if (arg) {
> @@ -5757,6 +5772,7 @@ int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
> spin_lock_bh(&ar->data_lock);
> ar->scan.arvif = NULL;
> ar->scan.state = ATH12K_SCAN_IDLE;
> + ar->scan.finish_queued = false;
> ar->scan_channel = NULL;
> ar->scan.roc_freq = 0;
> spin_unlock_bh(&ar->data_lock);
> @@ -5792,7 +5808,7 @@ void ath12k_mac_op_cancel_hw_scan(struct ieee80211_hw *hw,
>
> ath12k_scan_abort(ar);
>
> - cancel_delayed_work_sync(&ar->scan.timeout);
> + wiphy_delayed_work_cancel(hw->wiphy, &ar->scan.timeout);
> }
> }
> EXPORT_SYMBOL(ath12k_mac_op_cancel_hw_scan);
> @@ -9935,7 +9951,7 @@ static void ath12k_mac_stop(struct ath12k *ar)
>
> clear_bit(ATH12K_FLAG_CAC_RUNNING, &ar->dev_flags);
>
> - cancel_delayed_work_sync(&ar->scan.timeout);
> + wiphy_delayed_work_cancel(ath12k_ar_to_hw(ar)->wiphy, &ar->scan.timeout);
> wiphy_work_cancel(ath12k_ar_to_hw(ar)->wiphy, &ar->scan.vdev_clean_wk);
> cancel_work_sync(&ar->regd_channel_update_work);
> cancel_work_sync(&ar->regd_update_work);
> @@ -10962,6 +10978,7 @@ void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw,
> }
>
> ar->scan.state = ATH12K_SCAN_IDLE;
> + ar->scan.finish_queued = false;
> ar->scan_channel = NULL;
> ar->scan.roc_freq = 0;
> spin_unlock_bh(&ar->data_lock);
> @@ -13876,7 +13893,7 @@ int ath12k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw,
>
> ath12k_scan_abort(ar);
>
> - cancel_delayed_work_sync(&ar->scan.timeout);
> + wiphy_delayed_work_cancel(hw->wiphy, &ar->scan.timeout);
> wiphy_work_flush(hw->wiphy, &ar->scan.vdev_clean_wk);
>
> return 0;
> @@ -13956,6 +13973,7 @@ int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
> reinit_completion(&ar->scan.on_channel);
> ar->scan.state = ATH12K_SCAN_STARTING;
> ar->scan.is_roc = true;
> + ar->scan.finish_queued = false;
> ar->scan.arvif = arvif;
> ar->scan.roc_freq = chan->center_freq;
> ar->scan.roc_notify = true;
> @@ -13998,6 +14016,7 @@ int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
>
> spin_lock_bh(&ar->data_lock);
> ar->scan.state = ATH12K_SCAN_IDLE;
> + ar->scan.finish_queued = false;
> spin_unlock_bh(&ar->data_lock);
> return ret;
> }
> @@ -14011,8 +14030,8 @@ int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
> return -ETIMEDOUT;
> }
>
> - ieee80211_queue_delayed_work(hw, &ar->scan.timeout,
> - msecs_to_jiffies(duration));
> + wiphy_delayed_work_queue(hw->wiphy, &ar->scan.timeout,
> + msecs_to_jiffies(duration));
>
> return 0;
> }
> @@ -15052,6 +15071,7 @@ static void ath12k_mac_setup(struct ath12k *ar)
> ar->num_tx_chains = hweight32(pdev->cap.tx_chain_mask);
> ar->num_rx_chains = hweight32(pdev->cap.rx_chain_mask);
> ar->scan.arvif = NULL;
> + ar->scan.finish_queued = false;
> ar->vdev_id_11d_scan = ATH12K_11D_INVALID_VDEV_ID;
>
> spin_lock_init(&ar->data_lock);
> @@ -15077,7 +15097,7 @@ static void ath12k_mac_setup(struct ath12k *ar)
> ar->thermal.temperature = 0;
> ar->thermal.hwmon_dev = NULL;
>
> - INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work);
> + wiphy_delayed_work_init(&ar->scan.timeout, ath12k_scan_timeout_work);
> wiphy_work_init(&ar->scan.vdev_clean_wk, ath12k_scan_vdev_clean_work);
> INIT_WORK(&ar->regd_channel_update_work, ath12k_regd_update_chan_list_work);
> INIT_LIST_HEAD(&ar->regd_channel_update_queue);
^ permalink raw reply
* [PATCH iwlwifi-fixes 5/5] wifi: iwlwifi: validate SEC_RT TLV minimum size
From: Miri Korenblit @ 2026-07-17 14:33 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Emmanuel Grumbach
In-Reply-To: <20260717143340.2321964-1-miriam.rachel.korenblit@intel.com>
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Reject firmware section TLVs that are shorter than the offset field
before subtracting sizeof(offset) from the section size.
This prevents size underflow for malformed TLVs.
Assisted-by: GitHubCopilot:GPT-5.3-Codex
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
index 001895f4f4bd..7f1515dfc5bf 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
@@ -492,7 +492,7 @@ static void set_sec_offset(struct iwl_firmware_pieces *pieces,
* Gets uCode section from tlv.
*/
static int iwl_store_ucode_sec(struct fw_img_parsing *img,
- const void *data, int size)
+ const void *data, size_t size)
{
struct fw_sec *sec;
const struct fw_sec_parsing *sec_parse;
@@ -501,6 +501,9 @@ static int iwl_store_ucode_sec(struct fw_img_parsing *img,
if (WARN_ON(!img || !data))
return -EINVAL;
+ if (size < sizeof(sec_parse->offset))
+ return -EINVAL;
+
sec_parse = (const struct fw_sec_parsing *)data;
alloc_size = sizeof(*img->sec) * (img->sec_counter + 1);
--
2.34.1
^ permalink raw reply related
* [PATCH iwlwifi-fixes 4/5] wifi: iwlwifi: uefi: bound PPAG revision bitmap shift
From: Miri Korenblit @ 2026-07-17 14:33 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Emmanuel Grumbach
In-Reply-To: <20260717143340.2321964-1-miriam.rachel.korenblit@intel.com>
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Validate revision is below 32 before BIT(revision) in PPAG parsing.
Assisted-by: GitHubCopilot:GPT-5.3-Codex
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
index 2ef0a7a920ad..014f22c42f41 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
@@ -700,7 +700,7 @@ int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt)
return -EINVAL;
parse_table:
- if (!(BIT(data->revision) & valid_rev)) {
+ if (data->revision >= 32 || !(BIT(data->revision) & valid_rev)) {
ret = -EINVAL;
IWL_DEBUG_RADIO(fwrt,
"Unsupported UEFI PPAG revision:%d\n",
--
2.34.1
^ permalink raw reply related
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