--- /dev/null
+From ee5fb641c4ccac8406c668d3e947eb20ce44f233 Mon Sep 17 00:00:00 2001
+From: Runyu Xiao <runyu.xiao@seu.edu.cn>
+Date: Wed, 17 Jun 2026 23:23:19 +0800
+Subject: mmc: vub300: defer reset until cmd_mutex is unlocked
+
+From: Runyu Xiao <runyu.xiao@seu.edu.cn>
+
+commit ee5fb641c4ccac8406c668d3e947eb20ce44f233 upstream.
+
+vub300_cmndwork_thread() holds cmd_mutex while it sends a command and
+waits for the command response. If the response wait times out,
+__vub300_command_response() kills the command URBs and then synchronously
+resets the USB device through usb_reset_device().
+
+That reset path re-enters the driver through vub300_pre_reset(), which
+also takes cmd_mutex. The worker therefore tries to acquire the same
+mutex recursively while it is still holding it from the command path.
+
+This issue was found by our static analysis tool and then manually
+reviewed against the current tree.
+
+The grounded PoC kept the real worker and timeout/reset carrier:
+
+ vub300_cmndwork_thread()
+ __vub300_command_response()
+ usb_lock_device_for_reset()
+ usb_reset_device()
+ vub300_pre_reset()
+
+Lockdep reported the same-task recursive acquisition on cmd_mutex:
+
+ WARNING: possible recursive locking detected
+ ... (&test_vub300.cmd_mutex) ... at: usb_reset_device... [vuln_msv]
+ ... (&test_vub300.cmd_mutex) ... at: vub300_cmndwork_thread+0x12/0x20 [vuln_msv]
+ Workqueue: vub300_cmd_wq vub300_cmndwork_thread [vuln_msv]
+ *** DEADLOCK ***
+
+Return a flag from __vub300_command_response() when the timeout path needs
+a device reset, then perform the reset after vub300_cmndwork_thread() has
+cleared the in-flight command state and dropped cmd_mutex. The reset is
+still attempted before mmc_request_done(), preserving the existing request
+completion ordering while avoiding the recursive lock.
+
+Fixes: 88095e7b473a ("mmc: Add new VUB300 USB-to-SD/SDIO/MMC driver")
+Cc: stable@vger.kernel.org
+Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
+Signed-off-by: Ulf Hansson <ulfh@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/mmc/host/vub300.c | 26 +++++++++++++++++---------
+ 1 file changed, 17 insertions(+), 9 deletions(-)
+
+--- a/drivers/mmc/host/vub300.c
++++ b/drivers/mmc/host/vub300.c
+@@ -1585,7 +1585,7 @@ static int __command_write_data(struct v
+ return linear_length;
+ }
+
+-static void __vub300_command_response(struct vub300_mmc_host *vub300,
++static bool __vub300_command_response(struct vub300_mmc_host *vub300,
+ struct mmc_command *cmd,
+ struct mmc_data *data, int data_length)
+ {
+@@ -1597,17 +1597,11 @@ static void __vub300_command_response(st
+ msecs_to_jiffies(msec_timeout));
+ if (respretval == 0) { /* TIMED OUT */
+ /* we don't know which of "out" and "res" if any failed */
+- int result;
+ vub300->usb_timed_out = 1;
+ usb_kill_urb(vub300->command_out_urb);
+ usb_kill_urb(vub300->command_res_urb);
+ cmd->error = -ETIMEDOUT;
+- result = usb_lock_device_for_reset(vub300->udev,
+- vub300->interface);
+- if (result == 0) {
+- result = usb_reset_device(vub300->udev);
+- usb_unlock_device(vub300->udev);
+- }
++ return true;
+ } else if (respretval < 0) {
+ /* we don't know which of "out" and "res" if any failed */
+ usb_kill_urb(vub300->command_out_urb);
+@@ -1703,6 +1697,8 @@ static void __vub300_command_response(st
+ } else {
+ cmd->error = -EINVAL;
+ }
++
++ return false;
+ }
+
+ static void construct_request_response(struct vub300_mmc_host *vub300,
+@@ -1748,6 +1744,7 @@ static void vub300_cmndwork_thread(struc
+ struct mmc_request *req = vub300->req;
+ struct mmc_command *cmd = vub300->cmd;
+ struct mmc_data *data = vub300->data;
++ bool reset_device;
+ int data_length;
+ mutex_lock(&vub300->cmd_mutex);
+ init_completion(&vub300->command_complete);
+@@ -1770,7 +1767,8 @@ static void vub300_cmndwork_thread(struc
+ data_length = __command_read_data(vub300, cmd, data);
+ else
+ data_length = __command_write_data(vub300, cmd, data);
+- __vub300_command_response(vub300, cmd, data, data_length);
++ reset_device = __vub300_command_response(vub300, cmd,
++ data, data_length);
+ vub300->req = NULL;
+ vub300->cmd = NULL;
+ vub300->data = NULL;
+@@ -1778,6 +1776,16 @@ static void vub300_cmndwork_thread(struc
+ if (cmd->error == -ENOMEDIUM)
+ check_vub300_port_status(vub300);
+ mutex_unlock(&vub300->cmd_mutex);
++ if (reset_device) {
++ int result;
++
++ result = usb_lock_device_for_reset(vub300->udev,
++ vub300->interface);
++ if (result == 0) {
++ result = usb_reset_device(vub300->udev);
++ usb_unlock_device(vub300->udev);
++ }
++ }
+ mmc_request_done(vub300->mmc, req);
+ kref_put(&vub300->kref, vub300_delete);
+ return;
--- /dev/null
+From d322e40f4edf92bf0ca329e5aa4ae1c0316feb38 Mon Sep 17 00:00:00 2001
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Date: Fri, 3 Jul 2026 15:40:52 +0800
+Subject: mtd: mchp23k256: use SPI match data for chip caps
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+commit d322e40f4edf92bf0ca329e5aa4ae1c0316feb38 upstream.
+
+The driver stores chip capacity information in both the OF match table
+and the SPI id table. Probe currently uses of_device_get_match_data(),
+so a non-OF SPI modalias match falls back to mchp23k256_caps even when
+the SPI id table selected a different part.
+
+Use spi_get_device_match_data() so SPI id-table driver_data is consumed
+when OF match data is absent. This keeps the existing default fallback
+while avoiding the wrong MTD geometry for id-table-only matches.
+
+Fixes: 4379075a870b ("mtd: mchp23k256: Add support for mchp23lcv1024")
+Cc: stable@vger.kernel.org
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/mtd/devices/mchp23k256.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/mtd/devices/mchp23k256.c
++++ b/drivers/mtd/devices/mchp23k256.c
+@@ -188,7 +188,7 @@ static int mchp23k256_probe(struct spi_d
+
+ data = dev_get_platdata(&spi->dev);
+
+- flash->caps = of_device_get_match_data(&spi->dev);
++ flash->caps = spi_get_device_match_data(spi);
+ if (!flash->caps)
+ flash->caps = &mchp23k256_caps;
+
--- /dev/null
+From d03a19bd6c7f86b99ca8fb61a6ec2345cee1d9d6 Mon Sep 17 00:00:00 2001
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Date: Fri, 3 Jul 2026 15:43:50 +0800
+Subject: mtd: onenand: samsung: report DMA completion timeouts
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+commit d03a19bd6c7f86b99ca8fb61a6ec2345cee1d9d6 upstream.
+
+The S5PC110 OneNAND DMA helpers have bounded waits for transfer
+completion. The polling helper falls out of its timeout loop and returns
+success, and the IRQ helper ignores wait_for_completion_timeout().
+
+Return -ETIMEDOUT when the DMA transfer-done bit or completion does not
+arrive before the timeout so callers can treat the buffer transfer as
+failed.
+
+Fixes: e23abf4b7743 ("mtd: OneNAND: S5PC110: Implement DMA interrupt method")
+Cc: stable@vger.kernel.org
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/mtd/nand/onenand/onenand_samsung.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/mtd/nand/onenand/onenand_samsung.c
++++ b/drivers/mtd/nand/onenand/onenand_samsung.c
+@@ -554,6 +554,9 @@ static int s5pc110_dma_poll(dma_addr_t d
+ } while (!(status & S5PC110_DMA_TRANS_STATUS_TD) &&
+ time_before(jiffies, timeout));
+
++ if (!(status & S5PC110_DMA_TRANS_STATUS_TD))
++ return -ETIMEDOUT;
++
+ writel(S5PC110_DMA_TRANS_CMD_TDC, base + S5PC110_DMA_TRANS_CMD);
+
+ return 0;
+@@ -608,7 +611,9 @@ static int s5pc110_dma_irq(dma_addr_t ds
+
+ writel(S5PC110_DMA_TRANS_CMD_TR, base + S5PC110_DMA_TRANS_CMD);
+
+- wait_for_completion_timeout(&onenand->complete, msecs_to_jiffies(20));
++ if (!wait_for_completion_timeout(&onenand->complete,
++ msecs_to_jiffies(20)))
++ return -ETIMEDOUT;
+
+ return 0;
+ }
--- /dev/null
+From f9a13e05a327080c3a1c8165adf9e678fb68fef2 Mon Sep 17 00:00:00 2001
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Date: Fri, 3 Jul 2026 15:42:33 +0800
+Subject: mtd: rawnand: fsl_ifc: return errors for failed page reads
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+commit f9a13e05a327080c3a1c8165adf9e678fb68fef2 upstream.
+
+fsl_ifc_run_command() logs controller timeout and other non-OPC
+completion states in ctrl->nand_stat. fsl_ifc_read_page() then only
+increments the ECC failure counter for non-OPC status and still returns
+max_bitflips, which can be zero.
+
+Return -ETIMEDOUT when the command did not complete at all and -EIO for
+other non-OPC read completions so the NAND core does not treat a failed
+page read as a clean page.
+
+Fixes: 82771882d960 ("NAND Machine support for Integrated Flash Controller")
+Cc: stable@vger.kernel.org
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/mtd/nand/raw/fsl_ifc_nand.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+--- a/drivers/mtd/nand/raw/fsl_ifc_nand.c
++++ b/drivers/mtd/nand/raw/fsl_ifc_nand.c
+@@ -683,8 +683,15 @@ static int fsl_ifc_read_page(struct nand
+ return check_erased_page(chip, buf);
+ }
+
+- if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
++ if (!ctrl->nand_stat) {
+ mtd->ecc_stats.failed++;
++ return -ETIMEDOUT;
++ }
++
++ if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) {
++ mtd->ecc_stats.failed++;
++ return -EIO;
++ }
+
+ return nctrl->max_bitflips;
+ }
--- /dev/null
+From dbf590b662695b16fbf5917ef129697be4410ea9 Mon Sep 17 00:00:00 2001
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Date: Fri, 3 Jul 2026 15:37:59 +0800
+Subject: mtd: rawnand: lpc32xx_mlc: fail DMA transfers on timeout
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+commit dbf590b662695b16fbf5917ef129697be4410ea9 upstream.
+
+lpc32xx_xmit_dma() starts a DMA transfer and waits up to one second
+for its completion, but it ignores the wait result and returns success
+after unmapping the buffer.
+
+A timed out read can therefore return success with incomplete data, and
+a timed out write can continue the NAND operation without proof that the
+DMA payload reached the controller.
+
+Terminate the DMA channel on timeout, unmap the scatterlist through the
+existing cleanup path, and return -ETIMEDOUT to the NAND read/write
+callers. Initialize the shared cleanup-path result before using it for
+dmaengine_prep_slave_sg() failures.
+
+Fixes: 70f7cb78ec53 ("mtd: add LPC32xx MLC NAND driver")
+Cc: stable@vger.kernel.org
+Reviewed-by: Vladimir Zapolskiy <vz@kernel.org>
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/mtd/nand/raw/lpc32xx_mlc.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+--- a/drivers/mtd/nand/raw/lpc32xx_mlc.c
++++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c
+@@ -396,6 +396,7 @@ static int lpc32xx_xmit_dma(struct mtd_i
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+ struct dma_async_tx_descriptor *desc;
+ int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
++ unsigned long time_left;
+ int res;
+
+ sg_init_one(&host->sgl, mem, len);
+@@ -410,6 +411,7 @@ static int lpc32xx_xmit_dma(struct mtd_i
+ flags);
+ if (!desc) {
+ dev_err(mtd->dev.parent, "Failed to prepare slave sg\n");
++ res = -ENXIO;
+ goto out1;
+ }
+
+@@ -420,7 +422,13 @@ static int lpc32xx_xmit_dma(struct mtd_i
+ dmaengine_submit(desc);
+ dma_async_issue_pending(host->dma_chan);
+
+- wait_for_completion_timeout(&host->comp_dma, msecs_to_jiffies(1000));
++ time_left = wait_for_completion_timeout(&host->comp_dma,
++ msecs_to_jiffies(1000));
++ if (!time_left) {
++ dmaengine_terminate_sync(host->dma_chan);
++ res = -ETIMEDOUT;
++ goto out1;
++ }
+
+ dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+ DMA_BIDIRECTIONAL);
+@@ -428,7 +436,7 @@ static int lpc32xx_xmit_dma(struct mtd_i
+ out1:
+ dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+ DMA_BIDIRECTIONAL);
+- return -ENXIO;
++ return res;
+ }
+
+ static int lpc32xx_read_page(struct nand_chip *chip, uint8_t *buf,
--- /dev/null
+From 17a8ce84964f243c8f89dc7353ac7e8d3137bc74 Mon Sep 17 00:00:00 2001
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Date: Fri, 3 Jul 2026 15:39:43 +0800
+Subject: mtd: rawnand: lpc32xx_slc: fail DMA transfer on completion timeout
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+commit 17a8ce84964f243c8f89dc7353ac7e8d3137bc74 upstream.
+
+lpc32xx_xmit_dma() waits for the DMA completion callback but ignores
+wait_for_completion_timeout(). A timed out DMA transfer is therefore
+unmapped and reported as successful to the NAND read/write path.
+
+Return -ETIMEDOUT when the completion wait expires. Terminate the DMA
+channel before unmapping the scatterlist so the timed out transfer cannot
+continue to access the buffer after the error is returned.
+
+Fixes: 2944a44da09e ("mtd: add LPC32xx SLC NAND driver")
+Cc: stable@vger.kernel.org
+Reviewed-by: Vladimir Zapolskiy <vz@kernel.org>
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/mtd/nand/raw/lpc32xx_slc.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+--- a/drivers/mtd/nand/raw/lpc32xx_slc.c
++++ b/drivers/mtd/nand/raw/lpc32xx_slc.c
+@@ -430,6 +430,7 @@ static int lpc32xx_xmit_dma(struct mtd_i
+ struct dma_async_tx_descriptor *desc;
+ int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
+ int res;
++ unsigned long time_left;
+
+ host->dma_slave_config.direction = dir;
+ host->dma_slave_config.src_addr = dma;
+@@ -467,12 +468,19 @@ static int lpc32xx_xmit_dma(struct mtd_i
+ dmaengine_submit(desc);
+ dma_async_issue_pending(host->dma_chan);
+
+- wait_for_completion_timeout(&host->comp, msecs_to_jiffies(1000));
++ time_left = wait_for_completion_timeout(&host->comp,
++ msecs_to_jiffies(1000));
++ if (!time_left) {
++ dmaengine_terminate_sync(host->dma_chan);
++ res = -ETIMEDOUT;
++ } else {
++ res = 0;
++ }
+
+ dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+ DMA_BIDIRECTIONAL);
+
+- return 0;
++ return res;
+ out1:
+ dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+ DMA_BIDIRECTIONAL);
--- /dev/null
+From 47b87f469a35b5ffc81c16eee6b13a9b6c8d55c6 Mon Sep 17 00:00:00 2001
+From: Junrui Luo <moonafterrain@outlook.com>
+Date: Mon, 1 Jun 2026 15:50:00 +0800
+Subject: powerpc/spufs: fix out-of-bounds access in spufs_mem_mmap_access()
+
+From: Junrui Luo <moonafterrain@outlook.com>
+
+commit 47b87f469a35b5ffc81c16eee6b13a9b6c8d55c6 upstream.
+
+spufs_mem_mmap_access() computes the local store offset as
+address - vma->vm_start, but bounds-checks it against vma->vm_end
+instead of the local store size. On 64-bit, offset is always well
+below vma->vm_end, so the clamp never fires and len stays unbounded
+against the LS_SIZE buffer returned by ctx->ops->get_ls().
+
+Reject offsets at or beyond LS_SIZE and clamp len to the remaining
+space, mirroring the guard already used by spufs_mem_mmap_fault() and
+spufs_ps_fault().
+
+Fixes: a352894d0705 ("spufs: use new vm_ops->access to allow local state access from gdb")
+Reported-by: Yuhao Jiang <danisjiang@gmail.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Junrui Luo <moonafterrain@outlook.com>
+Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com>
+Link: https://patch.msgid.link/SYBPR01MB7881EE775E8B51C09F5A29E7AF152@SYBPR01MB7881.ausprd01.prod.outlook.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/powerpc/platforms/cell/spufs/file.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/arch/powerpc/platforms/cell/spufs/file.c
++++ b/arch/powerpc/platforms/cell/spufs/file.c
+@@ -268,10 +268,12 @@ static int spufs_mem_mmap_access(struct
+
+ if (write && !(vma->vm_flags & VM_WRITE))
+ return -EACCES;
++ if (offset >= LS_SIZE)
++ return -EFAULT;
+ if (spu_acquire(ctx))
+ return -EINTR;
+- if ((offset + len) > vma->vm_end)
+- len = vma->vm_end - offset;
++ if ((offset + len) > LS_SIZE)
++ len = LS_SIZE - offset;
+ local_store = ctx->ops->get_ls(ctx);
+ if (write)
+ memcpy_toio(local_store + offset, buf, len);
ipvs-reload-ip-header-after-head-reallocation.patch
reset-imx7-correct-polarity-of-mipi-csi-resets-on-i.mx8mq.patch
reset-sunxi-fix-memory-region-leak-on-ioremap-failure.patch
+powerpc-spufs-fix-out-of-bounds-access-in-spufs_mem_mmap_access.patch
+wifi-mac80211-free-ack-status-frame-on-tx-header-build-failure.patch
+wifi-mwifiex-fix-permanently-busy-scans-after-multiple-roam-iterations.patch
+mtd-onenand-samsung-report-dma-completion-timeouts.patch
+mtd-mchp23k256-use-spi-match-data-for-chip-caps.patch
+mmc-vub300-defer-reset-until-cmd_mutex-is-unlocked.patch
+mtd-rawnand-fsl_ifc-return-errors-for-failed-page-reads.patch
+mtd-rawnand-lpc32xx_mlc-fail-dma-transfers-on-timeout.patch
+mtd-rawnand-lpc32xx_slc-fail-dma-transfer-on-completion-timeout.patch
--- /dev/null
+From 2c51457d930f723e5f2903af90f5847f7df53f42 Mon Sep 17 00:00:00 2001
+From: Zhiling Zou <roxy520tt@gmail.com>
+Date: Sat, 27 Jun 2026 00:58:30 +0800
+Subject: wifi: mac80211: free ack status frame on TX header build failure
+
+From: Zhiling Zou <roxy520tt@gmail.com>
+
+commit 2c51457d930f723e5f2903af90f5847f7df53f42 upstream.
+
+ieee80211_build_hdr() stores an ACK status frame before it has
+finished all validation and header construction. If a later error path
+is taken, the transmit skb is freed but the stored ACK status frame
+remains in local->ack_status_frames.
+
+This can happen for control port frames when the requested MLO link ID
+does not match the link selected for a non-MLO station. Repeated
+failures can fill the ACK status IDR and leave pending ACK frames until
+hardware teardown.
+
+Remove any stored ACK status frame before returning an error after it
+has been inserted into the IDR.
+
+Fixes: a729cff8ad51 ("mac80211: implement wifi TX status")
+Cc: stable@vger.kernel.org
+Reported-by: Yuan Tan <yuantan098@gmail.com>
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Reported-by: Xin Liu <bird@lzu.edu.cn>
+Assisted-by: Codex:gpt-5.4
+Signed-off-by: Zhiling Zou <roxy520tt@gmail.com>
+Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
+Link: https://patch.msgid.link/9de0423da840e92084915b8f92e66a421245c4b8.1782462409.git.roxy520tt@gmail.com
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mac80211/tx.c | 17 ++++++++++++++++-
+ 1 file changed, 16 insertions(+), 1 deletion(-)
+
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -2568,6 +2568,18 @@ static u16 ieee80211_store_ack_skb(struc
+ return info_id;
+ }
+
++static void ieee80211_remove_ack_skb(struct ieee80211_local *local, u16 info_id)
++{
++ struct sk_buff *ack_skb;
++ unsigned long flags;
++
++ spin_lock_irqsave(&local->ack_status_lock, flags);
++ ack_skb = idr_remove(&local->ack_status_frames, info_id);
++ spin_unlock_irqrestore(&local->ack_status_lock, flags);
++
++ kfree_skb(ack_skb);
++}
++
+ /**
+ * ieee80211_build_hdr - build 802.11 header in the given frame
+ * @sdata: virtual interface to build the header for
+@@ -2925,7 +2937,8 @@ static struct sk_buff *ieee80211_build_h
+ if (ieee80211_skb_resize(sdata, skb, head_need, ENCRYPT_DATA)) {
+ ieee80211_free_txskb(&local->hw, skb);
+ skb = NULL;
+- return ERR_PTR(-ENOMEM);
++ ret = -ENOMEM;
++ goto free;
+ }
+ }
+
+@@ -2990,6 +3003,8 @@ static struct sk_buff *ieee80211_build_h
+
+ return skb;
+ free:
++ if (info_id)
++ ieee80211_remove_ack_skb(local, info_id);
+ kfree_skb(skb);
+ return ERR_PTR(ret);
+ }
--- /dev/null
+From d78a407bad6f500884a8606aea1a5a9207be4030 Mon Sep 17 00:00:00 2001
+From: Rafael Beims <rafael.beims@toradex.com>
+Date: Fri, 12 Jun 2026 09:25:46 -0300
+Subject: wifi: mwifiex: fix permanently busy scans after multiple roam iterations
+
+From: Rafael Beims <rafael.beims@toradex.com>
+
+commit d78a407bad6f500884a8606aea1a5a9207be4030 upstream.
+
+In order for the firmware to sleep, the driver has to confirm a
+previously received sleep request. The normal sequence of evets goes
+like this:
+EVENT_SLEEP -> adapter->ps_state = PS_STATE_PRE_SLEEP -> sleep-confirm
+-> SLEEP -> EVENT_AWAKE -> AWAKE.
+Before sending the sleep-confirm command, the driver must make sure
+there are no commands either running or waiting to be completed.
+
+mwifiex_ret_802_11_associate() unconditionally sets
+ps_state = PS_STATE_AWAKE when it processes the association command
+response, outside of the normal powersave management flow. If
+EVENT_SLEEP arrives while the association command is in flight,
+ps_state is PRE_SLEEP when the association command response is parsed,
+and the forced AWAKE overwrites it. The deferred sleep-confirm is
+never sent.
+
+A subsequent scan_start command is correctly acknowledged, but the
+firmware doesn't generate scan_result events. The scan request never
+finishes, and additional requests from userspace fail with -EBUSY.
+
+After testing on both IW412 and W8997, I could only trigger the bug on
+the IW412 and observed the firmwares behave differently. On the IW412
+the firmware still sends EVENT_SLEEP while the authentication /
+association process is ongoing. A W8997 under the same
+conditions seems to suppress power-save for the duration of the
+association, so PRE_SLEEP never coincided with the association response
+even after extended periods of testing using the loops
+described below (>12hours).
+
+On the IW412, the delay between commands that triggers an EVENT_SLEEP
+was empirically determined to be ~20ms. This delay can naturally occur
+when the driver is outputting debugging information
+(debug_mask = 0x00000037), in which situation the busy scans issue is
+repeatable while running "test 1)" as described below. If the delay
+between commands is less than ~20ms, the firmware stays awake and
+the issue was not reproducible running the same test.
+
+The host_mlme=false path also behaves differently. In this case, the
+entire authentication / association transaction is executed by one
+command (HostCmd_CMD_802_11_ASSOCIATE), and the firmware doesn't emit
+EVENT_SLEEP while the command is running.
+
+Remove the assignment so the ps_state is only manipulated in the paths
+that are related to powersave event handling and on the main workqueue
+for correct sleep confirmation.
+
+The following loop tests were performed (with debugging output enabled):
+1) force roaming between two AP's, one 5GHz and one 2.4GHz, same
+SSID. Use wpa_cli to trigger the roaming behavior, sleep 2s
+between iterations.
+2) force a disconnection to AP 1 and a connection to AP 2, test
+scan. Use wpa_cli to trigger the connection changes, sleep 2s
+between iterations.
+
+Each test ran in each device for at least 3 hours.
+
+Fixes: 5e6e3a92b9a4 ("wireless: mwifiex: initial commit for Marvell mwifiex driver")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-7
+Signed-off-by: Rafael Beims <rafael.beims@toradex.com>
+Reviewed-by: Jeff Chen <jeff.chen_1@nxp.com>
+Link: https://patch.msgid.link/20260612122547.1586872-2-rafael@beims.me
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/marvell/mwifiex/join.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/net/wireless/marvell/mwifiex/join.c
++++ b/drivers/net/wireless/marvell/mwifiex/join.c
+@@ -690,7 +690,6 @@ int mwifiex_ret_802_11_associate(struct
+ /* Send a Media Connected event, according to the Spec */
+ priv->media_connected = true;
+
+- priv->adapter->ps_state = PS_STATE_AWAKE;
+ priv->adapter->pps_uapsd_mode = false;
+ priv->adapter->tx_lock_flag = false;
+