]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 17 Aug 2020 12:55:49 +0000 (14:55 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 17 Aug 2020 12:55:49 +0000 (14:55 +0200)
added patches:
arm-8992-1-fix-unwind_frame-for-clang-built-kernels.patch
irqdomain-treewide-free-firmware-node-after-domain-removal.patch
mtd-rawnand-qcom-avoid-write-to-unavailable-register.patch
parisc-implement-__smp_store_release-and-__smp_load_acquire-barriers.patch
parisc-mask-out-enable-and-reserved-bits-from-sba-imask.patch
spi-spidev-align-buffers-for-dma.patch

queue-4.14/arm-8992-1-fix-unwind_frame-for-clang-built-kernels.patch [new file with mode: 0644]
queue-4.14/irqdomain-treewide-free-firmware-node-after-domain-removal.patch [new file with mode: 0644]
queue-4.14/mtd-rawnand-qcom-avoid-write-to-unavailable-register.patch [new file with mode: 0644]
queue-4.14/parisc-implement-__smp_store_release-and-__smp_load_acquire-barriers.patch [new file with mode: 0644]
queue-4.14/parisc-mask-out-enable-and-reserved-bits-from-sba-imask.patch [new file with mode: 0644]
queue-4.14/series
queue-4.14/spi-spidev-align-buffers-for-dma.patch [new file with mode: 0644]

diff --git a/queue-4.14/arm-8992-1-fix-unwind_frame-for-clang-built-kernels.patch b/queue-4.14/arm-8992-1-fix-unwind_frame-for-clang-built-kernels.patch
new file mode 100644 (file)
index 0000000..a322251
--- /dev/null
@@ -0,0 +1,80 @@
+From b4d5ec9b39f8b31d98f65bc5577b5d15d93795d7 Mon Sep 17 00:00:00 2001
+From: Nathan Huckleberry <nhuck@google.com>
+Date: Fri, 10 Jul 2020 20:23:37 +0100
+Subject: ARM: 8992/1: Fix unwind_frame for clang-built kernels
+
+From: Nathan Huckleberry <nhuck@google.com>
+
+commit b4d5ec9b39f8b31d98f65bc5577b5d15d93795d7 upstream.
+
+Since clang does not push pc and sp in function prologues, the current
+implementation of unwind_frame does not work. By using the previous
+frame's lr/fp instead of saved pc/sp we get valid unwinds on clang-built
+kernels.
+
+The bounds check on next frame pointer must be changed as well since
+there are 8 less bytes between frames.
+
+This fixes /proc/<pid>/stack.
+
+Link: https://github.com/ClangBuiltLinux/linux/issues/912
+
+Reported-by: Miles Chen <miles.chen@mediatek.com>
+Tested-by: Miles Chen <miles.chen@mediatek.com>
+Cc: stable@vger.kernel.org
+Reviewed-by: Nick Desaulniers <ndesaulniers@google.com>
+Signed-off-by: Nathan Huckleberry <nhuck@google.com>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/arm/kernel/stacktrace.c |   24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+--- a/arch/arm/kernel/stacktrace.c
++++ b/arch/arm/kernel/stacktrace.c
+@@ -20,6 +20,19 @@
+  * A simple function epilogue looks like this:
+  *    ldm     sp, {fp, sp, pc}
+  *
++ * When compiled with clang, pc and sp are not pushed. A simple function
++ * prologue looks like this when built with clang:
++ *
++ *    stmdb   {..., fp, lr}
++ *    add     fp, sp, #x
++ *    sub     sp, sp, #y
++ *
++ * A simple function epilogue looks like this when built with clang:
++ *
++ *    sub     sp, fp, #x
++ *    ldm     {..., fp, pc}
++ *
++ *
+  * Note that with framepointer enabled, even the leaf functions have the same
+  * prologue and epilogue, therefore we can ignore the LR value in this case.
+  */
+@@ -32,6 +45,16 @@ int notrace unwind_frame(struct stackfra
+       low = frame->sp;
+       high = ALIGN(low, THREAD_SIZE);
++#ifdef CONFIG_CC_IS_CLANG
++      /* check current frame pointer is within bounds */
++      if (fp < low + 4 || fp > high - 4)
++              return -EINVAL;
++
++      frame->sp = frame->fp;
++      frame->fp = *(unsigned long *)(fp);
++      frame->pc = frame->lr;
++      frame->lr = *(unsigned long *)(fp + 4);
++#else
+       /* check current frame pointer is within bounds */
+       if (fp < low + 12 || fp > high - 4)
+               return -EINVAL;
+@@ -40,6 +63,7 @@ int notrace unwind_frame(struct stackfra
+       frame->fp = *(unsigned long *)(fp - 12);
+       frame->sp = *(unsigned long *)(fp - 8);
+       frame->pc = *(unsigned long *)(fp - 4);
++#endif
+       return 0;
+ }
diff --git a/queue-4.14/irqdomain-treewide-free-firmware-node-after-domain-removal.patch b/queue-4.14/irqdomain-treewide-free-firmware-node-after-domain-removal.patch
new file mode 100644 (file)
index 0000000..d2636b6
--- /dev/null
@@ -0,0 +1,103 @@
+From ec0160891e387f4771f953b888b1fe951398e5d9 Mon Sep 17 00:00:00 2001
+From: Jon Derrick <jonathan.derrick@intel.com>
+Date: Tue, 21 Jul 2020 14:26:09 -0600
+Subject: irqdomain/treewide: Free firmware node after domain removal
+
+From: Jon Derrick <jonathan.derrick@intel.com>
+
+commit ec0160891e387f4771f953b888b1fe951398e5d9 upstream.
+
+Commit 711419e504eb ("irqdomain: Add the missing assignment of
+domain->fwnode for named fwnode") unintentionally caused a dangling pointer
+page fault issue on firmware nodes that were freed after IRQ domain
+allocation. Commit e3beca48a45b fixed that dangling pointer issue by only
+freeing the firmware node after an IRQ domain allocation failure. That fix
+no longer frees the firmware node immediately, but leaves the firmware node
+allocated after the domain is removed.
+
+The firmware node must be kept around through irq_domain_remove, but should be
+freed it afterwards.
+
+Add the missing free operations after domain removal where where appropriate.
+
+Fixes: e3beca48a45b ("irqdomain/treewide: Keep firmware node unconditionally allocated")
+Signed-off-by: Jon Derrick <jonathan.derrick@intel.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Acked-by: Bjorn Helgaas <bhelgaas@google.com>  # drivers/pci
+Cc: stable@vger.kernel.org
+Link: https://lkml.kernel.org/r/1595363169-7157-1-git-send-email-jonathan.derrick@intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/kernel/apic/io_apic.c      |    5 +++++
+ drivers/iommu/intel_irq_remapping.c |    8 ++++++++
+ drivers/pci/host/vmd.c              |    3 +++
+ 3 files changed, 16 insertions(+)
+
+--- a/arch/x86/kernel/apic/io_apic.c
++++ b/arch/x86/kernel/apic/io_apic.c
+@@ -2252,8 +2252,13 @@ static int mp_irqdomain_create(int ioapi
+ static void ioapic_destroy_irqdomain(int idx)
+ {
++      struct ioapic_domain_cfg *cfg = &ioapics[idx].irqdomain_cfg;
++      struct fwnode_handle *fn = ioapics[idx].irqdomain->fwnode;
++
+       if (ioapics[idx].irqdomain) {
+               irq_domain_remove(ioapics[idx].irqdomain);
++              if (!cfg->dev)
++                      irq_domain_free_fwnode(fn);
+               ioapics[idx].irqdomain = NULL;
+       }
+ }
+--- a/drivers/iommu/intel_irq_remapping.c
++++ b/drivers/iommu/intel_irq_remapping.c
+@@ -601,13 +601,21 @@ out_free_table:
+ static void intel_teardown_irq_remapping(struct intel_iommu *iommu)
+ {
++      struct fwnode_handle *fn;
++
+       if (iommu && iommu->ir_table) {
+               if (iommu->ir_msi_domain) {
++                      fn = iommu->ir_msi_domain->fwnode;
++
+                       irq_domain_remove(iommu->ir_msi_domain);
++                      irq_domain_free_fwnode(fn);
+                       iommu->ir_msi_domain = NULL;
+               }
+               if (iommu->ir_domain) {
++                      fn = iommu->ir_domain->fwnode;
++
+                       irq_domain_remove(iommu->ir_domain);
++                      irq_domain_free_fwnode(fn);
+                       iommu->ir_domain = NULL;
+               }
+               free_pages((unsigned long)iommu->ir_table->base,
+--- a/drivers/pci/host/vmd.c
++++ b/drivers/pci/host/vmd.c
+@@ -651,6 +651,7 @@ static int vmd_enable_domain(struct vmd_
+       if (!vmd->bus) {
+               pci_free_resource_list(&resources);
+               irq_domain_remove(vmd->irq_domain);
++              irq_domain_free_fwnode(fn);
+               return -ENODEV;
+       }
+@@ -753,6 +754,7 @@ static void vmd_cleanup_srcu(struct vmd_
+ static void vmd_remove(struct pci_dev *dev)
+ {
+       struct vmd_dev *vmd = pci_get_drvdata(dev);
++      struct fwnode_handle *fn = vmd->irq_domain->fwnode;
+       sysfs_remove_link(&vmd->dev->dev.kobj, "domain");
+       pci_stop_root_bus(vmd->bus);
+@@ -761,6 +763,7 @@ static void vmd_remove(struct pci_dev *d
+       vmd_teardown_dma_ops(vmd);
+       vmd_detach_resources(vmd);
+       irq_domain_remove(vmd->irq_domain);
++      irq_domain_free_fwnode(fn);
+ }
+ #ifdef CONFIG_PM_SLEEP
diff --git a/queue-4.14/mtd-rawnand-qcom-avoid-write-to-unavailable-register.patch b/queue-4.14/mtd-rawnand-qcom-avoid-write-to-unavailable-register.patch
new file mode 100644 (file)
index 0000000..682123c
--- /dev/null
@@ -0,0 +1,68 @@
+From 443440cc4a901af462239d286cd10721aa1c7dfc Mon Sep 17 00:00:00 2001
+From: Sivaprakash Murugesan <sivaprak@codeaurora.org>
+Date: Fri, 12 Jun 2020 13:28:15 +0530
+Subject: mtd: rawnand: qcom: avoid write to unavailable register
+
+From: Sivaprakash Murugesan <sivaprak@codeaurora.org>
+
+commit 443440cc4a901af462239d286cd10721aa1c7dfc upstream.
+
+SFLASHC_BURST_CFG is only available on older ipq NAND platforms, this
+register has been removed when the NAND controller got implemented in
+the qpic controller.
+
+Avoid writing this register on devices which are based on qpic NAND
+controller.
+
+Fixes: dce84760b09f ("mtd: nand: qcom: Support for IPQ8074 QPIC NAND controller")
+Cc: stable@vger.kernel.org
+Signed-off-by: Sivaprakash Murugesan <sivaprak@codeaurora.org>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Link: https://lore.kernel.org/linux-mtd/1591948696-16015-2-git-send-email-sivaprak@codeaurora.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/mtd/nand/qcom_nandc.c |    7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/mtd/nand/qcom_nandc.c
++++ b/drivers/mtd/nand/qcom_nandc.c
+@@ -435,11 +435,13 @@ struct qcom_nand_host {
+  * among different NAND controllers.
+  * @ecc_modes - ecc mode for NAND
+  * @is_bam - whether NAND controller is using BAM
++ * @is_qpic - whether NAND CTRL is part of qpic IP
+  * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
+  */
+ struct qcom_nandc_props {
+       u32 ecc_modes;
+       bool is_bam;
++      bool is_qpic;
+       u32 dev_cmd_reg_start;
+ };
+@@ -2508,7 +2510,8 @@ static int qcom_nandc_setup(struct qcom_
+       u32 nand_ctrl;
+       /* kill onenand */
+-      nandc_write(nandc, SFLASHC_BURST_CFG, 0);
++      if (!nandc->props->is_qpic)
++              nandc_write(nandc, SFLASHC_BURST_CFG, 0);
+       nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD),
+                   NAND_DEV_CMD_VLD_VAL);
+@@ -2779,12 +2782,14 @@ static const struct qcom_nandc_props ipq
+ static const struct qcom_nandc_props ipq4019_nandc_props = {
+       .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
+       .is_bam = true,
++      .is_qpic = true,
+       .dev_cmd_reg_start = 0x0,
+ };
+ static const struct qcom_nandc_props ipq8074_nandc_props = {
+       .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
+       .is_bam = true,
++      .is_qpic = true,
+       .dev_cmd_reg_start = 0x7000,
+ };
diff --git a/queue-4.14/parisc-implement-__smp_store_release-and-__smp_load_acquire-barriers.patch b/queue-4.14/parisc-implement-__smp_store_release-and-__smp_load_acquire-barriers.patch
new file mode 100644 (file)
index 0000000..8cbcfec
--- /dev/null
@@ -0,0 +1,92 @@
+From e96ebd589debd9a6a793608c4ec7019c38785dea Mon Sep 17 00:00:00 2001
+From: John David Anglin <dave.anglin@bell.net>
+Date: Thu, 30 Jul 2020 08:59:12 -0400
+Subject: parisc: Implement __smp_store_release and __smp_load_acquire barriers
+
+From: John David Anglin <dave.anglin@bell.net>
+
+commit e96ebd589debd9a6a793608c4ec7019c38785dea upstream.
+
+This patch implements the __smp_store_release and __smp_load_acquire barriers
+using ordered stores and loads.  This avoids the sync instruction present in
+the generic implementation.
+
+Cc: <stable@vger.kernel.org> # 4.14+
+Signed-off-by: Dave Anglin <dave.anglin@bell.net>
+Signed-off-by: Helge Deller <deller@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/parisc/include/asm/barrier.h |   61 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 61 insertions(+)
+
+--- a/arch/parisc/include/asm/barrier.h
++++ b/arch/parisc/include/asm/barrier.h
+@@ -26,6 +26,67 @@
+ #define __smp_rmb()   mb()
+ #define __smp_wmb()   mb()
++#define __smp_store_release(p, v)                                     \
++do {                                                                  \
++      typeof(p) __p = (p);                                            \
++        union { typeof(*p) __val; char __c[1]; } __u =                        \
++                { .__val = (__force typeof(*p)) (v) };                        \
++      compiletime_assert_atomic_type(*p);                             \
++      switch (sizeof(*p)) {                                           \
++      case 1:                                                         \
++              asm volatile("stb,ma %0,0(%1)"                          \
++                              : : "r"(*(__u8 *)__u.__c), "r"(__p)     \
++                              : "memory");                            \
++              break;                                                  \
++      case 2:                                                         \
++              asm volatile("sth,ma %0,0(%1)"                          \
++                              : : "r"(*(__u16 *)__u.__c), "r"(__p)    \
++                              : "memory");                            \
++              break;                                                  \
++      case 4:                                                         \
++              asm volatile("stw,ma %0,0(%1)"                          \
++                              : : "r"(*(__u32 *)__u.__c), "r"(__p)    \
++                              : "memory");                            \
++              break;                                                  \
++      case 8:                                                         \
++              if (IS_ENABLED(CONFIG_64BIT))                           \
++                      asm volatile("std,ma %0,0(%1)"                  \
++                              : : "r"(*(__u64 *)__u.__c), "r"(__p)    \
++                              : "memory");                            \
++              break;                                                  \
++      }                                                               \
++} while (0)
++
++#define __smp_load_acquire(p)                                         \
++({                                                                    \
++      union { typeof(*p) __val; char __c[1]; } __u;                   \
++      typeof(p) __p = (p);                                            \
++      compiletime_assert_atomic_type(*p);                             \
++      switch (sizeof(*p)) {                                           \
++      case 1:                                                         \
++              asm volatile("ldb,ma 0(%1),%0"                          \
++                              : "=r"(*(__u8 *)__u.__c) : "r"(__p)     \
++                              : "memory");                            \
++              break;                                                  \
++      case 2:                                                         \
++              asm volatile("ldh,ma 0(%1),%0"                          \
++                              : "=r"(*(__u16 *)__u.__c) : "r"(__p)    \
++                              : "memory");                            \
++              break;                                                  \
++      case 4:                                                         \
++              asm volatile("ldw,ma 0(%1),%0"                          \
++                              : "=r"(*(__u32 *)__u.__c) : "r"(__p)    \
++                              : "memory");                            \
++              break;                                                  \
++      case 8:                                                         \
++              if (IS_ENABLED(CONFIG_64BIT))                           \
++                      asm volatile("ldd,ma 0(%1),%0"                  \
++                              : "=r"(*(__u64 *)__u.__c) : "r"(__p)    \
++                              : "memory");                            \
++              break;                                                  \
++      }                                                               \
++      __u.__val;                                                      \
++})
+ #include <asm-generic/barrier.h>
+ #endif /* !__ASSEMBLY__ */
diff --git a/queue-4.14/parisc-mask-out-enable-and-reserved-bits-from-sba-imask.patch b/queue-4.14/parisc-mask-out-enable-and-reserved-bits-from-sba-imask.patch
new file mode 100644 (file)
index 0000000..bb219e4
--- /dev/null
@@ -0,0 +1,33 @@
+From 5b24993c21cbf2de11aff077a48c5cb0505a0450 Mon Sep 17 00:00:00 2001
+From: Sven Schnelle <svens@stackframe.org>
+Date: Tue, 11 Aug 2020 18:19:19 +0200
+Subject: parisc: mask out enable and reserved bits from sba imask
+
+From: Sven Schnelle <svens@stackframe.org>
+
+commit 5b24993c21cbf2de11aff077a48c5cb0505a0450 upstream.
+
+When using kexec the SBA IOMMU IBASE might still have the RE
+bit set. This triggers a WARN_ON when trying to write back the
+IBASE register later, and it also makes some mask calculations fail.
+
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Sven Schnelle <svens@stackframe.org>
+Signed-off-by: Helge Deller <deller@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/parisc/sba_iommu.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/parisc/sba_iommu.c
++++ b/drivers/parisc/sba_iommu.c
+@@ -1291,7 +1291,7 @@ sba_ioc_init_pluto(struct parisc_device
+       ** (one that doesn't overlap memory or LMMIO space) in the
+       ** IBASE and IMASK registers.
+       */
+-      ioc->ibase = READ_REG(ioc->ioc_hpa + IOC_IBASE);
++      ioc->ibase = READ_REG(ioc->ioc_hpa + IOC_IBASE) & ~0x1fffffULL;
+       iova_space_size = ~(READ_REG(ioc->ioc_hpa + IOC_IMASK) & 0xFFFFFFFFUL) + 1;
+       if ((ioc->ibase < 0xfed00000UL) && ((ioc->ibase + iova_space_size) > 0xfee00000UL)) {
index b073bd1a8f3a220e0e84a50eeb95d0e22cd50bf2..9c32bffed799a7c4fd7e9fe797163dad93e1dc2d 100644 (file)
@@ -155,3 +155,9 @@ fs-minix-don-t-allow-getting-deleted-inodes.patch
 fs-minix-reject-too-large-maximum-file-size.patch
 alsa-usb-audio-work-around-streaming-quirk-for-macrosilicon-ms2109.patch
 9p-fix-memory-leak-in-v9fs_mount.patch
+spi-spidev-align-buffers-for-dma.patch
+mtd-rawnand-qcom-avoid-write-to-unavailable-register.patch
+parisc-implement-__smp_store_release-and-__smp_load_acquire-barriers.patch
+parisc-mask-out-enable-and-reserved-bits-from-sba-imask.patch
+arm-8992-1-fix-unwind_frame-for-clang-built-kernels.patch
+irqdomain-treewide-free-firmware-node-after-domain-removal.patch
diff --git a/queue-4.14/spi-spidev-align-buffers-for-dma.patch b/queue-4.14/spi-spidev-align-buffers-for-dma.patch
new file mode 100644 (file)
index 0000000..cfaf602
--- /dev/null
@@ -0,0 +1,94 @@
+From aa9e862d7d5bcecd4dca9f39e8b684b93dd84ee7 Mon Sep 17 00:00:00 2001
+From: Christian Eggers <ceggers@arri.de>
+Date: Tue, 28 Jul 2020 12:08:32 +0200
+Subject: spi: spidev: Align buffers for DMA
+
+From: Christian Eggers <ceggers@arri.de>
+
+commit aa9e862d7d5bcecd4dca9f39e8b684b93dd84ee7 upstream.
+
+Simply copying all xfers from userspace into one bounce buffer causes
+alignment problems if the SPI controller uses DMA.
+
+Ensure that all transfer data blocks within the rx and tx bounce buffers
+are aligned for DMA (according to ARCH_KMALLOC_MINALIGN).
+
+Alignment may increase the usage of the bounce buffers. In some cases,
+the buffers may need to be increased using the "bufsiz" module
+parameter.
+
+Signed-off-by: Christian Eggers <ceggers@arri.de>
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20200728100832.24788-1-ceggers@arri.de
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/spi/spidev.c |   21 +++++++++++++--------
+ 1 file changed, 13 insertions(+), 8 deletions(-)
+
+--- a/drivers/spi/spidev.c
++++ b/drivers/spi/spidev.c
+@@ -232,6 +232,11 @@ static int spidev_message(struct spidev_
+       for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
+                       n;
+                       n--, k_tmp++, u_tmp++) {
++              /* Ensure that also following allocations from rx_buf/tx_buf will meet
++               * DMA alignment requirements.
++               */
++              unsigned int len_aligned = ALIGN(u_tmp->len, ARCH_KMALLOC_MINALIGN);
++
+               k_tmp->len = u_tmp->len;
+               total += k_tmp->len;
+@@ -247,17 +252,17 @@ static int spidev_message(struct spidev_
+               if (u_tmp->rx_buf) {
+                       /* this transfer needs space in RX bounce buffer */
+-                      rx_total += k_tmp->len;
++                      rx_total += len_aligned;
+                       if (rx_total > bufsiz) {
+                               status = -EMSGSIZE;
+                               goto done;
+                       }
+                       k_tmp->rx_buf = rx_buf;
+-                      rx_buf += k_tmp->len;
++                      rx_buf += len_aligned;
+               }
+               if (u_tmp->tx_buf) {
+                       /* this transfer needs space in TX bounce buffer */
+-                      tx_total += k_tmp->len;
++                      tx_total += len_aligned;
+                       if (tx_total > bufsiz) {
+                               status = -EMSGSIZE;
+                               goto done;
+@@ -267,7 +272,7 @@ static int spidev_message(struct spidev_
+                                               (uintptr_t) u_tmp->tx_buf,
+                                       u_tmp->len))
+                               goto done;
+-                      tx_buf += k_tmp->len;
++                      tx_buf += len_aligned;
+               }
+               k_tmp->cs_change = !!u_tmp->cs_change;
+@@ -297,16 +302,16 @@ static int spidev_message(struct spidev_
+               goto done;
+       /* copy any rx data out of bounce buffer */
+-      rx_buf = spidev->rx_buffer;
+-      for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {
++      for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
++                      n;
++                      n--, k_tmp++, u_tmp++) {
+               if (u_tmp->rx_buf) {
+                       if (copy_to_user((u8 __user *)
+-                                      (uintptr_t) u_tmp->rx_buf, rx_buf,
++                                      (uintptr_t) u_tmp->rx_buf, k_tmp->rx_buf,
+                                       u_tmp->len)) {
+                               status = -EFAULT;
+                               goto done;
+                       }
+-                      rx_buf += u_tmp->len;
+               }
+       }
+       status = total;