]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.12-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 8 Oct 2025 07:00:48 +0000 (09:00 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 8 Oct 2025 07:00:48 +0000 (09:00 +0200)
added patches:
binder-fix-double-free-in-dbitmap.patch
driver-core-pm-set-power.no_callbacks-along-with-power.no_pm.patch
nvmem-layouts-fix-automatic-module-loading.patch
serial-stm32-allow-selecting-console-when-the-driver-is-module.patch
staging-axis-fifo-fix-maximum-tx-packet-length-check.patch
staging-axis-fifo-fix-tx-handling-on-copy_from_user-failure.patch
staging-axis-fifo-flush-rx-fifo-on-read-errors.patch

queue-6.12/binder-fix-double-free-in-dbitmap.patch [new file with mode: 0644]
queue-6.12/driver-core-pm-set-power.no_callbacks-along-with-power.no_pm.patch [new file with mode: 0644]
queue-6.12/nvmem-layouts-fix-automatic-module-loading.patch [new file with mode: 0644]
queue-6.12/serial-stm32-allow-selecting-console-when-the-driver-is-module.patch [new file with mode: 0644]
queue-6.12/series
queue-6.12/staging-axis-fifo-fix-maximum-tx-packet-length-check.patch [new file with mode: 0644]
queue-6.12/staging-axis-fifo-fix-tx-handling-on-copy_from_user-failure.patch [new file with mode: 0644]
queue-6.12/staging-axis-fifo-flush-rx-fifo-on-read-errors.patch [new file with mode: 0644]

diff --git a/queue-6.12/binder-fix-double-free-in-dbitmap.patch b/queue-6.12/binder-fix-double-free-in-dbitmap.patch
new file mode 100644 (file)
index 0000000..cc20270
--- /dev/null
@@ -0,0 +1,71 @@
+From 3ebcd3460cad351f198c39c6edb4af519a0ed934 Mon Sep 17 00:00:00 2001
+From: Carlos Llamas <cmllamas@google.com>
+Date: Mon, 15 Sep 2025 22:12:47 +0000
+Subject: binder: fix double-free in dbitmap
+
+From: Carlos Llamas <cmllamas@google.com>
+
+commit 3ebcd3460cad351f198c39c6edb4af519a0ed934 upstream.
+
+A process might fail to allocate a new bitmap when trying to expand its
+proc->dmap. In that case, dbitmap_grow() fails and frees the old bitmap
+via dbitmap_free(). However, the driver calls dbitmap_free() again when
+the same process terminates, leading to a double-free error:
+
+  ==================================================================
+  BUG: KASAN: double-free in binder_proc_dec_tmpref+0x2e0/0x55c
+  Free of addr ffff00000b7c1420 by task kworker/9:1/209
+
+  CPU: 9 UID: 0 PID: 209 Comm: kworker/9:1 Not tainted 6.17.0-rc6-dirty #5 PREEMPT
+  Hardware name: linux,dummy-virt (DT)
+  Workqueue: events binder_deferred_func
+  Call trace:
+   kfree+0x164/0x31c
+   binder_proc_dec_tmpref+0x2e0/0x55c
+   binder_deferred_func+0xc24/0x1120
+   process_one_work+0x520/0xba4
+  [...]
+
+  Allocated by task 448:
+   __kmalloc_noprof+0x178/0x3c0
+   bitmap_zalloc+0x24/0x30
+   binder_open+0x14c/0xc10
+  [...]
+
+  Freed by task 449:
+   kfree+0x184/0x31c
+   binder_inc_ref_for_node+0xb44/0xe44
+   binder_transaction+0x29b4/0x7fbc
+   binder_thread_write+0x1708/0x442c
+   binder_ioctl+0x1b50/0x2900
+  [...]
+  ==================================================================
+
+Fix this issue by marking proc->map NULL in dbitmap_free().
+
+Cc: stable@vger.kernel.org
+Fixes: 15d9da3f818c ("binder: use bitmap for faster descriptor lookup")
+Signed-off-by: Carlos Llamas <cmllamas@google.com>
+Reviewed-by: Alice Ryhl <aliceryhl@google.com>
+Reviewed-by: Tiffany Yang <ynaffit@google.com>
+Link: https://lore.kernel.org/r/20250915221248.3470154-1-cmllamas@google.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/android/dbitmap.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/android/dbitmap.h b/drivers/android/dbitmap.h
+index 956f1bd087d1..c7299ce8b374 100644
+--- a/drivers/android/dbitmap.h
++++ b/drivers/android/dbitmap.h
+@@ -37,6 +37,7 @@ static inline void dbitmap_free(struct dbitmap *dmap)
+ {
+       dmap->nbits = 0;
+       kfree(dmap->map);
++      dmap->map = NULL;
+ }
+ /* Returns the nbits that a dbitmap can shrink to, 0 if not possible. */
+-- 
+2.51.0
+
diff --git a/queue-6.12/driver-core-pm-set-power.no_callbacks-along-with-power.no_pm.patch b/queue-6.12/driver-core-pm-set-power.no_callbacks-along-with-power.no_pm.patch
new file mode 100644 (file)
index 0000000..9e39868
--- /dev/null
@@ -0,0 +1,41 @@
+From c2ce2453413d429e302659abc5ace634e873f6f5 Mon Sep 17 00:00:00 2001
+From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
+Date: Thu, 28 Aug 2025 12:59:24 +0200
+Subject: driver core/PM: Set power.no_callbacks along with power.no_pm
+
+From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+commit c2ce2453413d429e302659abc5ace634e873f6f5 upstream.
+
+Devices with power.no_pm set are not expected to need any power
+management at all, so modify device_set_pm_not_required() to set
+power.no_callbacks for them too in case runtime PM will be enabled
+for any of them (which in principle may be done for convenience if
+such a device participates in a dependency chain).
+
+Since device_set_pm_not_required() must be called before device_add()
+or it would not have any effect, it can update power.no_callbacks
+without locking, unlike pm_runtime_no_callbacks() that can be called
+after registering the target device.
+
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Cc: stable <stable@kernel.org>
+Reviewed-by: Sudeep Holla <sudeep.holla@arm.com>
+Link: https://lore.kernel.org/r/1950054.tdWV9SEqCh@rafael.j.wysocki
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/device.h |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/include/linux/device.h
++++ b/include/linux/device.h
+@@ -873,6 +873,9 @@ static inline bool device_pm_not_require
+ static inline void device_set_pm_not_required(struct device *dev)
+ {
+       dev->power.no_pm = true;
++#ifdef CONFIG_PM
++      dev->power.no_callbacks = true;
++#endif
+ }
+ static inline void dev_pm_syscore_device(struct device *dev, bool val)
diff --git a/queue-6.12/nvmem-layouts-fix-automatic-module-loading.patch b/queue-6.12/nvmem-layouts-fix-automatic-module-loading.patch
new file mode 100644 (file)
index 0000000..11c6edf
--- /dev/null
@@ -0,0 +1,50 @@
+From 810b790033ccc795d55cbef3927668fd01efdfdf Mon Sep 17 00:00:00 2001
+From: Michael Walle <mwalle@kernel.org>
+Date: Fri, 12 Sep 2025 14:13:47 +0100
+Subject: nvmem: layouts: fix automatic module loading
+
+From: Michael Walle <mwalle@kernel.org>
+
+commit 810b790033ccc795d55cbef3927668fd01efdfdf upstream.
+
+To support loading of a layout module automatically the MODALIAS
+variable in the uevent is needed. Add it.
+
+Fixes: fc29fd821d9a ("nvmem: core: Rework layouts to become regular devices")
+Cc: stable@vger.kernel.org
+Signed-off-by: Michael Walle <mwalle@kernel.org>
+Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Signed-off-by: Srinivas Kandagatla <srini@kernel.org>
+Link: https://lore.kernel.org/r/20250912131347.303345-2-srini@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/layouts.c |   13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/drivers/nvmem/layouts.c
++++ b/drivers/nvmem/layouts.c
+@@ -45,11 +45,24 @@ static void nvmem_layout_bus_remove(stru
+       return drv->remove(layout);
+ }
++static int nvmem_layout_bus_uevent(const struct device *dev,
++                                 struct kobj_uevent_env *env)
++{
++      int ret;
++
++      ret = of_device_uevent_modalias(dev, env);
++      if (ret != ENODEV)
++              return ret;
++
++      return 0;
++}
++
+ static const struct bus_type nvmem_layout_bus_type = {
+       .name           = "nvmem-layout",
+       .match          = nvmem_layout_bus_match,
+       .probe          = nvmem_layout_bus_probe,
+       .remove         = nvmem_layout_bus_remove,
++      .uevent         = nvmem_layout_bus_uevent,
+ };
+ int __nvmem_layout_driver_register(struct nvmem_layout_driver *drv,
diff --git a/queue-6.12/serial-stm32-allow-selecting-console-when-the-driver-is-module.patch b/queue-6.12/serial-stm32-allow-selecting-console-when-the-driver-is-module.patch
new file mode 100644 (file)
index 0000000..7f6c1fc
--- /dev/null
@@ -0,0 +1,32 @@
+From cc4d900d0d6d8dd5c41832a93ff3cfa629a78f9a Mon Sep 17 00:00:00 2001
+From: Raphael Gallais-Pou <raphael.gallais-pou@foss.st.com>
+Date: Fri, 22 Aug 2025 16:19:23 +0200
+Subject: serial: stm32: allow selecting console when the driver is module
+
+From: Raphael Gallais-Pou <raphael.gallais-pou@foss.st.com>
+
+commit cc4d900d0d6d8dd5c41832a93ff3cfa629a78f9a upstream.
+
+Console can be enabled on the UART compile as module.
+Change dependency to allow console mode when the driver is built as module.
+
+Fixes: 48a6092fb41fa ("serial: stm32-usart: Add STM32 USART Driver")
+Cc: stable@vger.kernel.org
+Signed-off-by: Raphael Gallais-Pou <raphael.gallais-pou@foss.st.com>
+Link: https://lore.kernel.org/r/20250822141923.61133-1-raphael.gallais-pou@foss.st.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/Kconfig |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/tty/serial/Kconfig
++++ b/drivers/tty/serial/Kconfig
+@@ -1401,7 +1401,7 @@ config SERIAL_STM32
+ config SERIAL_STM32_CONSOLE
+       bool "Support for console on STM32"
+-      depends on SERIAL_STM32=y
++      depends on SERIAL_STM32
+       select SERIAL_CORE_CONSOLE
+       select SERIAL_EARLYCON
index db7f948b3fa44b07e195e18b5c20a4bdf73043cf..2394e16f8ce3d65454d8a2171b59b5282f098c64 100644 (file)
@@ -23,3 +23,10 @@ drm-amdgpu-enable-mes-lr_compute_wa-by-default.patch
 alsa-usb-audio-kill-timer-properly-at-removal.patch
 alsa-usb-audio-fix-race-condition-to-uaf-in-snd_usbmidi_free.patch
 hid-fix-i2c-read-buffer-overflow-in-raw_event-for-mcp2221.patch
+nvmem-layouts-fix-automatic-module-loading.patch
+binder-fix-double-free-in-dbitmap.patch
+serial-stm32-allow-selecting-console-when-the-driver-is-module.patch
+staging-axis-fifo-fix-maximum-tx-packet-length-check.patch
+staging-axis-fifo-fix-tx-handling-on-copy_from_user-failure.patch
+staging-axis-fifo-flush-rx-fifo-on-read-errors.patch
+driver-core-pm-set-power.no_callbacks-along-with-power.no_pm.patch
diff --git a/queue-6.12/staging-axis-fifo-fix-maximum-tx-packet-length-check.patch b/queue-6.12/staging-axis-fifo-fix-maximum-tx-packet-length-check.patch
new file mode 100644 (file)
index 0000000..44a4424
--- /dev/null
@@ -0,0 +1,71 @@
+From 52ff2b840bc723f3be1f096f8017c78e0515858c Mon Sep 17 00:00:00 2001
+From: Ovidiu Panait <ovidiu.panait.oss@gmail.com>
+Date: Sun, 17 Aug 2025 20:13:50 +0300
+Subject: staging: axis-fifo: fix maximum TX packet length check
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ovidiu Panait <ovidiu.panait.oss@gmail.com>
+
+commit 52ff2b840bc723f3be1f096f8017c78e0515858c upstream.
+
+Since commit 2ca34b508774 ("staging: axis-fifo: Correct handling of
+tx_fifo_depth for size validation"), write() operations with packets
+larger than 'tx_fifo_depth - 4' words are no longer rejected with -EINVAL.
+
+Fortunately, the packets are not actually getting transmitted to hardware,
+otherwise they would be raising a 'Transmit Packet Overrun Error'
+interrupt, which requires a reset of the TX circuit to recover from.
+
+Instead, the request times out inside wait_event_interruptible_timeout()
+and always returns -EAGAIN, since the wake up condition can never be true
+for these packets. But still, they unnecessarily block other tasks from
+writing to the FIFO and the EAGAIN return code signals userspace to retry
+the write() call, even though it will always fail and time out.
+
+According to the AXI4-Stream FIFO reference manual (PG080), the maximum
+valid packet length is 'tx_fifo_depth - 4' words, so attempting to send
+larger packets is invalid and should not be happening in the first place:
+
+> The maximum packet that can be transmitted is limited by the size of
+> the FIFO, which is (C_TX_FIFO_DEPTH–4)*(data interface width/8) bytes.
+
+Therefore, bring back the old behavior and outright reject packets larger
+than 'tx_fifo_depth - 4' with -EINVAL. Add a comment to explain why the
+check is necessary. The dev_err() message was removed to avoid cluttering
+the dmesg log if an invalid packet is received from userspace.
+
+Fixes: 2ca34b508774 ("staging: axis-fifo: Correct handling of tx_fifo_depth for size validation")
+Cc: stable@vger.kernel.org
+Signed-off-by: Ovidiu Panait <ovidiu.panait.oss@gmail.com>
+Link: https://lore.kernel.org/r/20250817171350.872105-1-ovidiu.panait.oss@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/staging/axis-fifo/axis-fifo.c |   14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+--- a/drivers/staging/axis-fifo/axis-fifo.c
++++ b/drivers/staging/axis-fifo/axis-fifo.c
+@@ -486,11 +486,17 @@ static ssize_t axis_fifo_write(struct fi
+               return -EINVAL;
+       }
+-      if (words_to_write > fifo->tx_fifo_depth) {
+-              dev_err(fifo->dt_device, "tried to write more words [%u] than slots in the fifo buffer [%u]\n",
+-                      words_to_write, fifo->tx_fifo_depth);
++      /*
++       * In 'Store-and-Forward' mode, the maximum packet that can be
++       * transmitted is limited by the size of the FIFO, which is
++       * (C_TX_FIFO_DEPTH–4)*(data interface width/8) bytes.
++       *
++       * Do not attempt to send a packet larger than 'tx_fifo_depth - 4',
++       * otherwise a 'Transmit Packet Overrun Error' interrupt will be
++       * raised, which requires a reset of the TX circuit to recover.
++       */
++      if (words_to_write > (fifo->tx_fifo_depth - 4))
+               return -EINVAL;
+-      }
+       if (fifo->write_flags & O_NONBLOCK) {
+               /*
diff --git a/queue-6.12/staging-axis-fifo-fix-tx-handling-on-copy_from_user-failure.patch b/queue-6.12/staging-axis-fifo-fix-tx-handling-on-copy_from_user-failure.patch
new file mode 100644 (file)
index 0000000..bfa3f30
--- /dev/null
@@ -0,0 +1,97 @@
+From 6d07bee10e4bdd043ec7152cbbb9deb27033c9e2 Mon Sep 17 00:00:00 2001
+From: Ovidiu Panait <ovidiu.panait.oss@gmail.com>
+Date: Fri, 12 Sep 2025 13:13:21 +0300
+Subject: staging: axis-fifo: fix TX handling on copy_from_user() failure
+
+From: Ovidiu Panait <ovidiu.panait.oss@gmail.com>
+
+commit 6d07bee10e4bdd043ec7152cbbb9deb27033c9e2 upstream.
+
+If copy_from_user() fails, write() currently returns -EFAULT, but any
+partially written data leaves the TX FIFO in an inconsistent state.
+Subsequent write() calls then fail with "transmit length mismatch"
+errors.
+
+Once partial data is written to the hardware FIFO, it cannot be removed
+without a TX reset. Commit c6e8d85fafa7 ("staging: axis-fifo: Remove
+hardware resets for user errors") removed a full FIFO reset for this case,
+which fixed a potential RX data loss, but introduced this TX issue.
+
+Fix this by introducing a bounce buffer: copy the full packet from
+userspace first, and write to the hardware FIFO only if the copy
+was successful.
+
+Fixes: c6e8d85fafa7 ("staging: axis-fifo: Remove hardware resets for user errors")
+Cc: stable@vger.kernel.org
+Signed-off-by: Ovidiu Panait <ovidiu.panait.oss@gmail.com>
+Link: https://lore.kernel.org/r/20250912101322.1282507-1-ovidiu.panait.oss@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/staging/axis-fifo/axis-fifo.c |   36 +++++++++-------------------------
+ 1 file changed, 10 insertions(+), 26 deletions(-)
+
+--- a/drivers/staging/axis-fifo/axis-fifo.c
++++ b/drivers/staging/axis-fifo/axis-fifo.c
+@@ -42,7 +42,6 @@
+ #define DRIVER_NAME "axis_fifo"
+ #define READ_BUF_SIZE 128U /* read buffer length in words */
+-#define WRITE_BUF_SIZE 128U /* write buffer length in words */
+ /* ----------------------------
+  *     IP register offsets
+@@ -466,11 +465,8 @@ static ssize_t axis_fifo_write(struct fi
+ {
+       struct axis_fifo *fifo = (struct axis_fifo *)f->private_data;
+       unsigned int words_to_write;
+-      unsigned int copied;
+-      unsigned int copy;
+-      unsigned int i;
++      u32 *txbuf;
+       int ret;
+-      u32 tmp_buf[WRITE_BUF_SIZE];
+       if (len % sizeof(u32)) {
+               dev_err(fifo->dt_device,
+@@ -535,32 +531,20 @@ static ssize_t axis_fifo_write(struct fi
+               }
+       }
+-      /* write data from an intermediate buffer into the fifo IP, refilling
+-       * the buffer with userspace data as needed
+-       */
+-      copied = 0;
+-      while (words_to_write > 0) {
+-              copy = min(words_to_write, WRITE_BUF_SIZE);
+-
+-              if (copy_from_user(tmp_buf, buf + copied * sizeof(u32),
+-                                 copy * sizeof(u32))) {
+-                      ret = -EFAULT;
+-                      goto end_unlock;
+-              }
+-
+-              for (i = 0; i < copy; i++)
+-                      iowrite32(tmp_buf[i], fifo->base_addr +
+-                                XLLF_TDFD_OFFSET);
+-
+-              copied += copy;
+-              words_to_write -= copy;
++      txbuf = vmemdup_user(buf, len);
++      if (IS_ERR(txbuf)) {
++              ret = PTR_ERR(txbuf);
++              goto end_unlock;
+       }
+-      ret = copied * sizeof(u32);
++      for (int i = 0; i < words_to_write; ++i)
++              iowrite32(txbuf[i], fifo->base_addr + XLLF_TDFD_OFFSET);
+       /* write packet size to fifo */
+-      iowrite32(ret, fifo->base_addr + XLLF_TLR_OFFSET);
++      iowrite32(len, fifo->base_addr + XLLF_TLR_OFFSET);
++      ret = len;
++      kvfree(txbuf);
+ end_unlock:
+       mutex_unlock(&fifo->write_lock);
diff --git a/queue-6.12/staging-axis-fifo-flush-rx-fifo-on-read-errors.patch b/queue-6.12/staging-axis-fifo-flush-rx-fifo-on-read-errors.patch
new file mode 100644 (file)
index 0000000..e2f874a
--- /dev/null
@@ -0,0 +1,84 @@
+From 82a051e2553b9e297cba82a975d9c538b882c79e Mon Sep 17 00:00:00 2001
+From: Ovidiu Panait <ovidiu.panait.oss@gmail.com>
+Date: Fri, 12 Sep 2025 13:13:22 +0300
+Subject: staging: axis-fifo: flush RX FIFO on read errors
+
+From: Ovidiu Panait <ovidiu.panait.oss@gmail.com>
+
+commit 82a051e2553b9e297cba82a975d9c538b882c79e upstream.
+
+Flush stale data from the RX FIFO in case of errors, to avoid reading
+old data when new packets arrive.
+
+Commit c6e8d85fafa7 ("staging: axis-fifo: Remove hardware resets for
+user errors") removed full FIFO resets from the read error paths, which
+fixed potential TX data losses, but introduced this RX issue.
+
+Fixes: c6e8d85fafa7 ("staging: axis-fifo: Remove hardware resets for user errors")
+Cc: stable@vger.kernel.org
+Signed-off-by: Ovidiu Panait <ovidiu.panait.oss@gmail.com>
+Link: https://lore.kernel.org/r/20250912101322.1282507-2-ovidiu.panait.oss@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/staging/axis-fifo/axis-fifo.c |   18 +++++++++++-------
+ 1 file changed, 11 insertions(+), 7 deletions(-)
+
+--- a/drivers/staging/axis-fifo/axis-fifo.c
++++ b/drivers/staging/axis-fifo/axis-fifo.c
+@@ -391,6 +391,7 @@ static ssize_t axis_fifo_read(struct fil
+       }
+       bytes_available = ioread32(fifo->base_addr + XLLF_RLR_OFFSET);
++      words_available = bytes_available / sizeof(u32);
+       if (!bytes_available) {
+               dev_err(fifo->dt_device, "received a packet of length 0\n");
+               ret = -EIO;
+@@ -401,7 +402,7 @@ static ssize_t axis_fifo_read(struct fil
+               dev_err(fifo->dt_device, "user read buffer too small (available bytes=%zu user buffer bytes=%zu)\n",
+                       bytes_available, len);
+               ret = -EINVAL;
+-              goto end_unlock;
++              goto err_flush_rx;
+       }
+       if (bytes_available % sizeof(u32)) {
+@@ -410,11 +411,9 @@ static ssize_t axis_fifo_read(struct fil
+                */
+               dev_err(fifo->dt_device, "received a packet that isn't word-aligned\n");
+               ret = -EIO;
+-              goto end_unlock;
++              goto err_flush_rx;
+       }
+-      words_available = bytes_available / sizeof(u32);
+-
+       /* read data into an intermediate buffer, copying the contents
+        * to userspace when the buffer is full
+        */
+@@ -426,18 +425,23 @@ static ssize_t axis_fifo_read(struct fil
+                       tmp_buf[i] = ioread32(fifo->base_addr +
+                                             XLLF_RDFD_OFFSET);
+               }
++              words_available -= copy;
+               if (copy_to_user(buf + copied * sizeof(u32), tmp_buf,
+                                copy * sizeof(u32))) {
+                       ret = -EFAULT;
+-                      goto end_unlock;
++                      goto err_flush_rx;
+               }
+               copied += copy;
+-              words_available -= copy;
+       }
++      mutex_unlock(&fifo->read_lock);
++
++      return bytes_available;
+-      ret = bytes_available;
++err_flush_rx:
++      while (words_available--)
++              ioread32(fifo->base_addr + XLLF_RDFD_OFFSET);
+ end_unlock:
+       mutex_unlock(&fifo->read_lock);