]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 6.1
authorSasha Levin <sashal@kernel.org>
Wed, 2 Oct 2024 05:17:34 +0000 (01:17 -0400)
committerSasha Levin <sashal@kernel.org>
Wed, 2 Oct 2024 05:17:34 +0000 (01:17 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
20 files changed:
queue-6.1/cpuidle-adjust-includes-to-remove-of_device.h.patch [new file with mode: 0644]
queue-6.1/cpuidle-riscv-sbi-use-scoped-device-node-handling-to.patch [new file with mode: 0644]
queue-6.1/powerpc-64-add-support-to-build-with-prefixed-instru.patch [new file with mode: 0644]
queue-6.1/powerpc-64-option-to-build-big-endian-with-elfv2-abi.patch [new file with mode: 0644]
queue-6.1/powerpc-atomic-use-yz-constraints-for-ds-form-instru.patch [new file with mode: 0644]
queue-6.1/pps-add-an-error-check-in-parport_attach.patch [new file with mode: 0644]
queue-6.1/pps-remove-usage-of-the-deprecated-ida_simple_xx-api.patch [new file with mode: 0644]
queue-6.1/series
queue-6.1/soc-versatile-realview-fix-memory-leak-during-device.patch [new file with mode: 0644]
queue-6.1/soc-versatile-realview-fix-soc_dev-leak-during-devic.patch [new file with mode: 0644]
queue-6.1/usb-misc-yurex-fix-race-between-read-and-write.patch [new file with mode: 0644]
queue-6.1/usb-xhci-fix-loss-of-data-on-cadence-xhc.patch [new file with mode: 0644]
queue-6.1/usb-yurex-replace-snprintf-with-the-safer-scnprintf-.patch [new file with mode: 0644]
queue-6.1/x86-entry-remove-unwanted-instrumentation-in-common_.patch [new file with mode: 0644]
queue-6.1/x86-idtentry-incorporate-definitions-declarations-of.patch [new file with mode: 0644]
queue-6.1/xhci-add-a-quirk-for-writing-erst-in-high-low-order.patch [new file with mode: 0644]
queue-6.1/xhci-fix-event-ring-segment-table-related-masks-and-.patch [new file with mode: 0644]
queue-6.1/xhci-preserve-rsvdp-bits-in-erstba-register-correctl.patch [new file with mode: 0644]
queue-6.1/xhci-refactor-interrupter-code-for-initial-multi-int.patch [new file with mode: 0644]
queue-6.1/xhci-remove-xhci_test_trb_in_td_math-early-developme.patch [new file with mode: 0644]

diff --git a/queue-6.1/cpuidle-adjust-includes-to-remove-of_device.h.patch b/queue-6.1/cpuidle-adjust-includes-to-remove-of_device.h.patch
new file mode 100644 (file)
index 0000000..44bb868
--- /dev/null
@@ -0,0 +1,89 @@
+From 03282e65d6bcd847a6b22651f99d263f5ffda59e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Mar 2023 10:52:13 -0500
+Subject: cpuidle: Adjust includes to remove of_device.h
+
+From: Rob Herring <robh@kernel.org>
+
+[ Upstream commit 24760e43c6a6164a33c023eed7536073bf6c68f7 ]
+
+Now that of_cpu_device_node_get() is defined in of.h, of_device.h is just
+implicitly including other includes, and is no longer needed. Adjust the
+include files with what was implicitly included by of_device.h (cpu.h,
+cpuhotplug.h, of.h, and of_platform.h) and drop including of_device.h.
+
+Acked-by: Anup Patel <anup@brainfault.org>
+Acked-by: Rafael J. Wysocki <rafael@kernel.org>
+Acked-by: Sudeep Holla <sudeep.holla@arm.com>
+Link: https://lore.kernel.org/r/20230329-dt-cpu-header-cleanups-v1-16-581e2605fe47@kernel.org
+Signed-off-by: Rob Herring <robh@kernel.org>
+Stable-dep-of: a309320ddbac ("cpuidle: riscv-sbi: Use scoped device node handling to fix missing of_node_put")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/cpuidle/cpuidle-psci.c      | 1 -
+ drivers/cpuidle/cpuidle-qcom-spm.c  | 3 +--
+ drivers/cpuidle/cpuidle-riscv-sbi.c | 2 +-
+ drivers/cpuidle/dt_idle_states.c    | 1 -
+ 4 files changed, 2 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/cpuidle/cpuidle-psci.c b/drivers/cpuidle/cpuidle-psci.c
+index 57bc3e3ae3912..9a55b0d090b02 100644
+--- a/drivers/cpuidle/cpuidle-psci.c
++++ b/drivers/cpuidle/cpuidle-psci.c
+@@ -16,7 +16,6 @@
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/of.h>
+-#include <linux/of_device.h>
+ #include <linux/platform_device.h>
+ #include <linux/psci.h>
+ #include <linux/pm_domain.h>
+diff --git a/drivers/cpuidle/cpuidle-qcom-spm.c b/drivers/cpuidle/cpuidle-qcom-spm.c
+index beedf22cbe78b..5dcfc7efe1611 100644
+--- a/drivers/cpuidle/cpuidle-qcom-spm.c
++++ b/drivers/cpuidle/cpuidle-qcom-spm.c
+@@ -11,8 +11,7 @@
+ #include <linux/io.h>
+ #include <linux/slab.h>
+ #include <linux/of.h>
+-#include <linux/of_address.h>
+-#include <linux/of_device.h>
++#include <linux/of_platform.h>
+ #include <linux/err.h>
+ #include <linux/platform_device.h>
+ #include <linux/cpuidle.h>
+diff --git a/drivers/cpuidle/cpuidle-riscv-sbi.c b/drivers/cpuidle/cpuidle-riscv-sbi.c
+index af7320a768d27..8a185116b82ee 100644
+--- a/drivers/cpuidle/cpuidle-riscv-sbi.c
++++ b/drivers/cpuidle/cpuidle-riscv-sbi.c
+@@ -8,6 +8,7 @@
+ #define pr_fmt(fmt) "cpuidle-riscv-sbi: " fmt
++#include <linux/cpuhotplug.h>
+ #include <linux/cpuidle.h>
+ #include <linux/cpumask.h>
+ #include <linux/cpu_pm.h>
+@@ -15,7 +16,6 @@
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/of.h>
+-#include <linux/of_device.h>
+ #include <linux/slab.h>
+ #include <linux/platform_device.h>
+ #include <linux/pm_domain.h>
+diff --git a/drivers/cpuidle/dt_idle_states.c b/drivers/cpuidle/dt_idle_states.c
+index 448bc796b0b40..2c3559c944dbf 100644
+--- a/drivers/cpuidle/dt_idle_states.c
++++ b/drivers/cpuidle/dt_idle_states.c
+@@ -14,7 +14,6 @@
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/of.h>
+-#include <linux/of_device.h>
+ #include "dt_idle_states.h"
+-- 
+2.43.0
+
diff --git a/queue-6.1/cpuidle-riscv-sbi-use-scoped-device-node-handling-to.patch b/queue-6.1/cpuidle-riscv-sbi-use-scoped-device-node-handling-to.patch
new file mode 100644 (file)
index 0000000..40f1490
--- /dev/null
@@ -0,0 +1,88 @@
+From 52f534c64a4fe635422e2f63ac72dcbecaf10d0e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 20 Aug 2024 11:40:22 +0200
+Subject: cpuidle: riscv-sbi: Use scoped device node handling to fix missing
+ of_node_put
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit a309320ddbac6b1583224fcb6bacd424bcf8637f ]
+
+Two return statements in sbi_cpuidle_dt_init_states() did not drop the
+OF node reference count.  Solve the issue and simplify entire error
+handling with scoped/cleanup.h.
+
+Fixes: 6abf32f1d9c5 ("cpuidle: Add RISC-V SBI CPU idle driver")
+Cc: All applicable <stable@vger.kernel.org>
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Reviewed-by: Anup Patel <anup@brainfault.org>
+Link: https://patch.msgid.link/20240820094023.61155-1-krzysztof.kozlowski@linaro.org
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/cpuidle/cpuidle-riscv-sbi.c | 21 +++++++--------------
+ 1 file changed, 7 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/cpuidle/cpuidle-riscv-sbi.c b/drivers/cpuidle/cpuidle-riscv-sbi.c
+index 8a185116b82ee..6d73ded6fa39a 100644
+--- a/drivers/cpuidle/cpuidle-riscv-sbi.c
++++ b/drivers/cpuidle/cpuidle-riscv-sbi.c
+@@ -8,6 +8,7 @@
+ #define pr_fmt(fmt) "cpuidle-riscv-sbi: " fmt
++#include <linux/cleanup.h>
+ #include <linux/cpuhotplug.h>
+ #include <linux/cpuidle.h>
+ #include <linux/cpumask.h>
+@@ -266,19 +267,16 @@ static int sbi_cpuidle_dt_init_states(struct device *dev,
+ {
+       struct sbi_cpuidle_data *data = per_cpu_ptr(&sbi_cpuidle_data, cpu);
+       struct device_node *state_node;
+-      struct device_node *cpu_node;
+       u32 *states;
+       int i, ret;
+-      cpu_node = of_cpu_device_node_get(cpu);
++      struct device_node *cpu_node __free(device_node) = of_cpu_device_node_get(cpu);
+       if (!cpu_node)
+               return -ENODEV;
+       states = devm_kcalloc(dev, state_count, sizeof(*states), GFP_KERNEL);
+-      if (!states) {
+-              ret = -ENOMEM;
+-              goto fail;
+-      }
++      if (!states)
++              return -ENOMEM;
+       /* Parse SBI specific details from state DT nodes */
+       for (i = 1; i < state_count; i++) {
+@@ -294,10 +292,8 @@ static int sbi_cpuidle_dt_init_states(struct device *dev,
+               pr_debug("sbi-state %#x index %d\n", states[i], i);
+       }
+-      if (i != state_count) {
+-              ret = -ENODEV;
+-              goto fail;
+-      }
++      if (i != state_count)
++              return -ENODEV;
+       /* Initialize optional data, used for the hierarchical topology. */
+       ret = sbi_dt_cpu_init_topology(drv, data, state_count, cpu);
+@@ -307,10 +303,7 @@ static int sbi_cpuidle_dt_init_states(struct device *dev,
+       /* Store states in the per-cpu struct. */
+       data->states = states;
+-fail:
+-      of_node_put(cpu_node);
+-
+-      return ret;
++      return 0;
+ }
+ static void sbi_cpuidle_deinit_cpu(int cpu)
+-- 
+2.43.0
+
diff --git a/queue-6.1/powerpc-64-add-support-to-build-with-prefixed-instru.patch b/queue-6.1/powerpc-64-add-support-to-build-with-prefixed-instru.patch
new file mode 100644 (file)
index 0000000..a72a333
--- /dev/null
@@ -0,0 +1,297 @@
+From 62df068a4268eaf2dfae24f43f8ffc308916b514 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Apr 2023 12:17:49 +1000
+Subject: powerpc/64: Add support to build with prefixed instructions
+
+From: Nicholas Piggin <npiggin@gmail.com>
+
+[ Upstream commit dc5dac748af9087e9240bd2ae6ae7db48d5360ae ]
+
+Add an option to build kernel and module with prefixed instructions if
+the CPU and toolchain support it.
+
+This is not related to kernel support for userspace execution of
+prefixed instructions.
+
+Building with prefixed instructions breaks some extended inline asm
+memory addressing, for example it will provide immediates that exceed
+the range of simple load/store displacement. Whether this is a
+toolchain or a kernel asm problem remains to be seen. For now, these
+are replaced with simpler and less efficient direct register addressing
+when compiling with prefixed.
+
+Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Link: https://msgid.link/20230408021752.862660-4-npiggin@gmail.com
+Stable-dep-of: 39190ac7cff1 ("powerpc/atomic: Use YZ constraints for DS-form instructions")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/Kconfig                   |  3 +++
+ arch/powerpc/Makefile                  |  4 +++
+ arch/powerpc/include/asm/atomic.h      | 24 ++++++++++++++---
+ arch/powerpc/include/asm/io.h          | 37 ++++++++++++++++++++++++++
+ arch/powerpc/include/asm/uaccess.h     | 28 +++++++++++++++++--
+ arch/powerpc/kernel/trace/ftrace.c     |  2 ++
+ arch/powerpc/platforms/Kconfig.cputype | 20 ++++++++++++++
+ 7 files changed, 112 insertions(+), 6 deletions(-)
+
+diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
+index 345b8b4c60e1e..2fa9e87b06dc8 100644
+--- a/arch/powerpc/Kconfig
++++ b/arch/powerpc/Kconfig
+@@ -4,6 +4,9 @@ source "arch/powerpc/platforms/Kconfig.cputype"
+ config CC_HAS_ELFV2
+       def_bool PPC64 && $(cc-option, -mabi=elfv2)
++config CC_HAS_PREFIXED
++      def_bool PPC64 && $(cc-option, -mcpu=power10 -mprefixed)
++
+ config 32BIT
+       bool
+       default y if PPC32
+diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
+index 487e4967b60d2..d7332c6afeaac 100644
+--- a/arch/powerpc/Makefile
++++ b/arch/powerpc/Makefile
+@@ -176,7 +176,11 @@ ifdef CONFIG_476FPE_ERR46
+ endif
+ # No prefix or pcrel
++ifdef CONFIG_PPC_KERNEL_PREFIXED
++KBUILD_CFLAGS += $(call cc-option,-mprefixed)
++else
+ KBUILD_CFLAGS += $(call cc-option,-mno-prefixed)
++endif
+ KBUILD_CFLAGS += $(call cc-option,-mno-pcrel)
+ # No AltiVec or VSX or MMA instructions when building kernel
+diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h
+index 486ab78891215..50212c44be2a9 100644
+--- a/arch/powerpc/include/asm/atomic.h
++++ b/arch/powerpc/include/asm/atomic.h
+@@ -27,14 +27,22 @@ static __inline__ int arch_atomic_read(const atomic_t *v)
+ {
+       int t;
+-      __asm__ __volatile__("lwz%U1%X1 %0,%1" : "=r"(t) : "m<>"(v->counter));
++      /* -mprefixed can generate offsets beyond range, fall back hack */
++      if (IS_ENABLED(CONFIG_PPC_KERNEL_PREFIXED))
++              __asm__ __volatile__("lwz %0,0(%1)" : "=r"(t) : "b"(&v->counter));
++      else
++              __asm__ __volatile__("lwz%U1%X1 %0,%1" : "=r"(t) : "m<>"(v->counter));
+       return t;
+ }
+ static __inline__ void arch_atomic_set(atomic_t *v, int i)
+ {
+-      __asm__ __volatile__("stw%U0%X0 %1,%0" : "=m<>"(v->counter) : "r"(i));
++      /* -mprefixed can generate offsets beyond range, fall back hack */
++      if (IS_ENABLED(CONFIG_PPC_KERNEL_PREFIXED))
++              __asm__ __volatile__("stw %1,0(%2)" : "=m"(v->counter) : "r"(i), "b"(&v->counter));
++      else
++              __asm__ __volatile__("stw%U0%X0 %1,%0" : "=m<>"(v->counter) : "r"(i));
+ }
+ #define ATOMIC_OP(op, asm_op, suffix, sign, ...)                      \
+@@ -226,14 +234,22 @@ static __inline__ s64 arch_atomic64_read(const atomic64_t *v)
+ {
+       s64 t;
+-      __asm__ __volatile__("ld%U1%X1 %0,%1" : "=r"(t) : "m<>"(v->counter));
++      /* -mprefixed can generate offsets beyond range, fall back hack */
++      if (IS_ENABLED(CONFIG_PPC_KERNEL_PREFIXED))
++              __asm__ __volatile__("ld %0,0(%1)" : "=r"(t) : "b"(&v->counter));
++      else
++              __asm__ __volatile__("ld%U1%X1 %0,%1" : "=r"(t) : "m<>"(v->counter));
+       return t;
+ }
+ static __inline__ void arch_atomic64_set(atomic64_t *v, s64 i)
+ {
+-      __asm__ __volatile__("std%U0%X0 %1,%0" : "=m<>"(v->counter) : "r"(i));
++      /* -mprefixed can generate offsets beyond range, fall back hack */
++      if (IS_ENABLED(CONFIG_PPC_KERNEL_PREFIXED))
++              __asm__ __volatile__("std %1,0(%2)" : "=m"(v->counter) : "r"(i), "b"(&v->counter));
++      else
++              __asm__ __volatile__("std%U0%X0 %1,%0" : "=m<>"(v->counter) : "r"(i));
+ }
+ #define ATOMIC64_OP(op, asm_op)                                               \
+diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h
+index 6d3ce049babdf..6010e966b1499 100644
+--- a/arch/powerpc/include/asm/io.h
++++ b/arch/powerpc/include/asm/io.h
+@@ -97,6 +97,42 @@ extern bool isa_io_special;
+  *
+  */
++/* -mprefixed can generate offsets beyond range, fall back hack */
++#ifdef CONFIG_PPC_KERNEL_PREFIXED
++#define DEF_MMIO_IN_X(name, size, insn)                               \
++static inline u##size name(const volatile u##size __iomem *addr)      \
++{                                                                     \
++      u##size ret;                                                    \
++      __asm__ __volatile__("sync;"#insn" %0,0,%1;twi 0,%0,0;isync"    \
++              : "=r" (ret) : "r" (addr) : "memory");                  \
++      return ret;                                                     \
++}
++
++#define DEF_MMIO_OUT_X(name, size, insn)                              \
++static inline void name(volatile u##size __iomem *addr, u##size val)  \
++{                                                                     \
++      __asm__ __volatile__("sync;"#insn" %1,0,%0"                     \
++              : : "r" (addr), "r" (val) : "memory");                  \
++      mmiowb_set_pending();                                           \
++}
++
++#define DEF_MMIO_IN_D(name, size, insn)                               \
++static inline u##size name(const volatile u##size __iomem *addr)      \
++{                                                                     \
++      u##size ret;                                                    \
++      __asm__ __volatile__("sync;"#insn" %0,0(%1);twi 0,%0,0;isync"\
++              : "=r" (ret) : "b" (addr) : "memory");  \
++      return ret;                                                     \
++}
++
++#define DEF_MMIO_OUT_D(name, size, insn)                              \
++static inline void name(volatile u##size __iomem *addr, u##size val)  \
++{                                                                     \
++      __asm__ __volatile__("sync;"#insn" %1,0(%0)"                    \
++              : : "b" (addr), "r" (val) : "memory");  \
++      mmiowb_set_pending();                                           \
++}
++#else
+ #define DEF_MMIO_IN_X(name, size, insn)                               \
+ static inline u##size name(const volatile u##size __iomem *addr)      \
+ {                                                                     \
+@@ -130,6 +166,7 @@ static inline void name(volatile u##size __iomem *addr, u##size val)       \
+               : "=m<>" (*addr) : "r" (val) : "memory");       \
+       mmiowb_set_pending();                                           \
+ }
++#endif
+ DEF_MMIO_IN_D(in_8,     8, lbz);
+ DEF_MMIO_OUT_D(out_8,   8, stb);
+diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
+index 661046150e49f..2d17f1193b25c 100644
+--- a/arch/powerpc/include/asm/uaccess.h
++++ b/arch/powerpc/include/asm/uaccess.h
+@@ -71,14 +71,26 @@ __pu_failed:                                                       \
+  * because we do not write to any memory gcc knows about, so there
+  * are no aliasing issues.
+  */
++/* -mprefixed can generate offsets beyond range, fall back hack */
++#ifdef CONFIG_PPC_KERNEL_PREFIXED
++#define __put_user_asm_goto(x, addr, label, op)                       \
++      asm_volatile_goto(                                      \
++              "1:     " op " %0,0(%1) # put_user\n"           \
++              EX_TABLE(1b, %l2)                               \
++              :                                               \
++              : "r" (x), "b" (addr)                           \
++              :                                               \
++              : label)
++#else
+ #define __put_user_asm_goto(x, addr, label, op)                       \
+       asm goto(                                       \
+               "1:     " op "%U1%X1 %0,%1      # put_user\n"   \
+               EX_TABLE(1b, %l2)                               \
+               :                                               \
+-              : "r" (x), "m<>" (*addr)                \
++              : "r" (x), "m<>" (*addr)                        \
+               :                                               \
+               : label)
++#endif
+ #ifdef CONFIG_CC_IS_CLANG
+ #define DS_FORM_CONSTRAINT "Z<>"
+@@ -142,14 +154,26 @@ do {                                                             \
+ #ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
++/* -mprefixed can generate offsets beyond range, fall back hack */
++#ifdef CONFIG_PPC_KERNEL_PREFIXED
++#define __get_user_asm_goto(x, addr, label, op)                       \
++      asm_volatile_goto(                                      \
++              "1:     "op" %0,0(%1)   # get_user\n"           \
++              EX_TABLE(1b, %l2)                               \
++              : "=r" (x)                                      \
++              : "b" (addr)                                    \
++              :                                               \
++              : label)
++#else
+ #define __get_user_asm_goto(x, addr, label, op)                       \
+       asm_goto_output(                                        \
+               "1:     "op"%U1%X1 %0, %1       # get_user\n"   \
+               EX_TABLE(1b, %l2)                               \
+               : "=r" (x)                                      \
+-              : "m<>" (*addr)                         \
++              : "m<>" (*addr)                                 \
+               :                                               \
+               : label)
++#endif
+ #ifdef __powerpc64__
+ #define __get_user_asm2_goto(x, addr, label)                  \
+diff --git a/arch/powerpc/kernel/trace/ftrace.c b/arch/powerpc/kernel/trace/ftrace.c
+index 7b85c3b460a3c..72864fb7a6ccd 100644
+--- a/arch/powerpc/kernel/trace/ftrace.c
++++ b/arch/powerpc/kernel/trace/ftrace.c
+@@ -194,6 +194,8 @@ __ftrace_make_nop(struct module *mod,
+        * get corrupted.
+        *
+        * Use a b +8 to jump over the load.
++       * XXX: could make PCREL depend on MPROFILE_KERNEL
++       * XXX: check PCREL && MPROFILE_KERNEL calling sequence
+        */
+       if (IS_ENABLED(CONFIG_MPROFILE_KERNEL) || IS_ENABLED(CONFIG_PPC32))
+               pop = ppc_inst(PPC_RAW_NOP());
+diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
+index ce88910d54cf0..8f3db66774577 100644
+--- a/arch/powerpc/platforms/Kconfig.cputype
++++ b/arch/powerpc/platforms/Kconfig.cputype
+@@ -176,6 +176,7 @@ config POWER10_CPU
+       bool "POWER10"
+       depends on PPC_BOOK3S_64
+       select ARCH_HAS_FAST_MULTIPLIER
++      select PPC_HAVE_PREFIXED_SUPPORT
+ config E5500_CPU
+       bool "Freescale e5500"
+@@ -449,6 +450,22 @@ config PPC_RADIX_MMU_DEFAULT
+         If you're unsure, say Y.
++config PPC_KERNEL_PREFIXED
++      depends on PPC_HAVE_PREFIXED_SUPPORT
++      depends on CC_HAS_PREFIXED
++      default n
++      bool "Build Kernel with Prefixed Instructions"
++      help
++        POWER10 and later CPUs support prefixed instructions, 8 byte
++        instructions that include large immediate, pc relative addressing,
++        and various floating point, vector, MMA.
++
++        This option builds the kernel with prefixed instructions, and
++        allows a pc relative addressing option to be selected.
++
++        Kernel support for prefixed instructions in applications and guests
++        is not affected by this option.
++
+ config PPC_KUEP
+       bool "Kernel Userspace Execution Prevention" if !40x
+       default y if !40x
+@@ -485,6 +502,9 @@ config PPC_MMU_NOHASH
+ config PPC_HAVE_PMU_SUPPORT
+       bool
++config PPC_HAVE_PREFIXED_SUPPORT
++      bool
++
+ config PMU_SYSFS
+       bool "Create PMU SPRs sysfs file"
+       default n
+-- 
+2.43.0
+
diff --git a/queue-6.1/powerpc-64-option-to-build-big-endian-with-elfv2-abi.patch b/queue-6.1/powerpc-64-option-to-build-big-endian-with-elfv2-abi.patch
new file mode 100644 (file)
index 0000000..61154a6
--- /dev/null
@@ -0,0 +1,96 @@
+From 746eaea332b24da14d885a3ff3505257da5b0b43 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 28 Nov 2022 14:15:39 +1000
+Subject: powerpc/64: Option to build big-endian with ELFv2 ABI
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Nicholas Piggin <npiggin@gmail.com>
+
+[ Upstream commit 5017b45946722bdd20ac255c9ae7273b78d1f12e ]
+
+Provide an option to build big-endian kernels using the ELFv2 ABI. This
+works on GCC only for now. Clang is rumored to support this, but core
+build files need updating first, at least.
+
+This gives big-endian kernels useful advantages of the ELFv2 ABI, e.g.,
+less stack usage, -mprofile-kernel support, better compatibility with
+eBPF tools.
+
+BE+ELFv2 is not officially supported by the GNU toolchain, but it works
+fine in testing and has been used by some userspace for some time (e.g.,
+Void Linux).
+
+Tested-by: Michal Suchánek <msuchanek@suse.de>
+Reviewed-by: Segher Boessenkool <segher@kernel.crashing.org>
+Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
+Reviewed-by: Joel Stanley <joel@jms.id.au>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Link: https://lore.kernel.org/r/20221128041539.1742489-5-npiggin@gmail.com
+Stable-dep-of: 39190ac7cff1 ("powerpc/atomic: Use YZ constraints for DS-form instructions")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/Kconfig                   | 21 +++++++++++++++++++++
+ arch/powerpc/platforms/Kconfig.cputype |  4 ++--
+ 2 files changed, 23 insertions(+), 2 deletions(-)
+
+diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
+index 6050e6e10d321..345b8b4c60e1e 100644
+--- a/arch/powerpc/Kconfig
++++ b/arch/powerpc/Kconfig
+@@ -1,6 +1,9 @@
+ # SPDX-License-Identifier: GPL-2.0
+ source "arch/powerpc/platforms/Kconfig.cputype"
++config CC_HAS_ELFV2
++      def_bool PPC64 && $(cc-option, -mabi=elfv2)
++
+ config 32BIT
+       bool
+       default y if PPC32
+@@ -583,6 +586,24 @@ config KEXEC_FILE
+ config ARCH_HAS_KEXEC_PURGATORY
+       def_bool KEXEC_FILE
++config PPC64_BIG_ENDIAN_ELF_ABI_V2
++      bool "Build big-endian kernel using ELF ABI V2 (EXPERIMENTAL)"
++      depends on PPC64 && CPU_BIG_ENDIAN
++      depends on CC_HAS_ELFV2
++      depends on LD_IS_BFD && LD_VERSION >= 22400
++      default n
++      help
++        This builds the kernel image using the "Power Architecture 64-Bit ELF
++        V2 ABI Specification", which has a reduced stack overhead and faster
++        function calls. This internal kernel ABI option does not affect
++          userspace compatibility.
++
++        The V2 ABI is standard for 64-bit little-endian, but for big-endian
++        it is less well tested by kernel and toolchain. However some distros
++        build userspace this way, and it can produce a functioning kernel.
++
++        This requires GCC and binutils 2.24 or newer.
++
+ config RELOCATABLE
+       bool "Build a relocatable kernel"
+       depends on PPC64 || (FLATMEM && (44x || PPC_85xx))
+diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
+index 54d655a647cec..ce88910d54cf0 100644
+--- a/arch/powerpc/platforms/Kconfig.cputype
++++ b/arch/powerpc/platforms/Kconfig.cputype
+@@ -585,10 +585,10 @@ config CPU_LITTLE_ENDIAN
+ endchoice
+ config PPC64_ELF_ABI_V1
+-      def_bool PPC64 && CPU_BIG_ENDIAN
++      def_bool PPC64 && (CPU_BIG_ENDIAN && !PPC64_BIG_ENDIAN_ELF_ABI_V2)
+ config PPC64_ELF_ABI_V2
+-      def_bool PPC64 && CPU_LITTLE_ENDIAN
++      def_bool PPC64 && !PPC64_ELF_ABI_V1
+ config PPC64_BOOT_WRAPPER
+       def_bool n
+-- 
+2.43.0
+
diff --git a/queue-6.1/powerpc-atomic-use-yz-constraints-for-ds-form-instru.patch b/queue-6.1/powerpc-atomic-use-yz-constraints-for-ds-form-instru.patch
new file mode 100644 (file)
index 0000000..62f8d72
--- /dev/null
@@ -0,0 +1,121 @@
+From 52f7853d80525577b9224a0a1662e393b996e9ed Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 16 Sep 2024 22:05:10 +1000
+Subject: powerpc/atomic: Use YZ constraints for DS-form instructions
+
+From: Michael Ellerman <mpe@ellerman.id.au>
+
+[ Upstream commit 39190ac7cff1fd15135fa8e658030d9646fdb5f2 ]
+
+The 'ld' and 'std' instructions require a 4-byte aligned displacement
+because they are DS-form instructions. But the "m" asm constraint
+doesn't enforce that.
+
+That can lead to build errors if the compiler chooses a non-aligned
+displacement, as seen with GCC 14:
+
+  /tmp/ccuSzwiR.s: Assembler messages:
+  /tmp/ccuSzwiR.s:2579: Error: operand out of domain (39 is not a multiple of 4)
+  make[5]: *** [scripts/Makefile.build:229: net/core/page_pool.o] Error 1
+
+Dumping the generated assembler shows:
+
+  ld 8,39(8)       # MEM[(const struct atomic64_t *)_29].counter, t
+
+Use the YZ constraints to tell the compiler either to generate a DS-form
+displacement, or use an X-form instruction, either of which prevents the
+build error.
+
+See commit 2d43cc701b96 ("powerpc/uaccess: Fix build errors seen with
+GCC 13/14") for more details on the constraint letters.
+
+Fixes: 9f0cbea0d8cc ("[POWERPC] Implement atomic{, 64}_{read, write}() without volatile")
+Cc: stable@vger.kernel.org # v2.6.24+
+Reported-by: Stephen Rothwell <sfr@canb.auug.org.au>
+Closes: https://lore.kernel.org/all/20240913125302.0a06b4c7@canb.auug.org.au
+Tested-by: Mina Almasry <almasrymina@google.com>
+Reviewed-by: Segher Boessenkool <segher@kernel.crashing.org>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Link: https://msgid.link/20240916120510.2017749-1-mpe@ellerman.id.au
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/include/asm/asm-compat.h | 6 ++++++
+ arch/powerpc/include/asm/atomic.h     | 5 +++--
+ arch/powerpc/include/asm/uaccess.h    | 7 +------
+ 3 files changed, 10 insertions(+), 8 deletions(-)
+
+diff --git a/arch/powerpc/include/asm/asm-compat.h b/arch/powerpc/include/asm/asm-compat.h
+index 2bc53c646ccd7..83848b534cb17 100644
+--- a/arch/powerpc/include/asm/asm-compat.h
++++ b/arch/powerpc/include/asm/asm-compat.h
+@@ -39,6 +39,12 @@
+ #define STDX_BE       stringify_in_c(stdbrx)
+ #endif
++#ifdef CONFIG_CC_IS_CLANG
++#define DS_FORM_CONSTRAINT "Z<>"
++#else
++#define DS_FORM_CONSTRAINT "YZ<>"
++#endif
++
+ #else /* 32-bit */
+ /* operations for longs and pointers */
+diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h
+index 50212c44be2a9..33742fec25c1b 100644
+--- a/arch/powerpc/include/asm/atomic.h
++++ b/arch/powerpc/include/asm/atomic.h
+@@ -11,6 +11,7 @@
+ #include <asm/cmpxchg.h>
+ #include <asm/barrier.h>
+ #include <asm/asm-const.h>
++#include <asm/asm-compat.h>
+ /*
+  * Since *_return_relaxed and {cmp}xchg_relaxed are implemented with
+@@ -238,7 +239,7 @@ static __inline__ s64 arch_atomic64_read(const atomic64_t *v)
+       if (IS_ENABLED(CONFIG_PPC_KERNEL_PREFIXED))
+               __asm__ __volatile__("ld %0,0(%1)" : "=r"(t) : "b"(&v->counter));
+       else
+-              __asm__ __volatile__("ld%U1%X1 %0,%1" : "=r"(t) : "m<>"(v->counter));
++              __asm__ __volatile__("ld%U1%X1 %0,%1" : "=r"(t) : DS_FORM_CONSTRAINT (v->counter));
+       return t;
+ }
+@@ -249,7 +250,7 @@ static __inline__ void arch_atomic64_set(atomic64_t *v, s64 i)
+       if (IS_ENABLED(CONFIG_PPC_KERNEL_PREFIXED))
+               __asm__ __volatile__("std %1,0(%2)" : "=m"(v->counter) : "r"(i), "b"(&v->counter));
+       else
+-              __asm__ __volatile__("std%U0%X0 %1,%0" : "=m<>"(v->counter) : "r"(i));
++              __asm__ __volatile__("std%U0%X0 %1,%0" : "=" DS_FORM_CONSTRAINT (v->counter) : "r"(i));
+ }
+ #define ATOMIC64_OP(op, asm_op)                                               \
+diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
+index 2d17f1193b25c..63e7c3107cc88 100644
+--- a/arch/powerpc/include/asm/uaccess.h
++++ b/arch/powerpc/include/asm/uaccess.h
+@@ -6,6 +6,7 @@
+ #include <asm/page.h>
+ #include <asm/extable.h>
+ #include <asm/kup.h>
++#include <asm/asm-compat.h>
+ #ifdef __powerpc64__
+ /* We use TASK_SIZE_USER64 as TASK_SIZE is not constant */
+@@ -92,12 +93,6 @@ __pu_failed:                                                        \
+               : label)
+ #endif
+-#ifdef CONFIG_CC_IS_CLANG
+-#define DS_FORM_CONSTRAINT "Z<>"
+-#else
+-#define DS_FORM_CONSTRAINT "YZ<>"
+-#endif
+-
+ #ifdef __powerpc64__
+ #define __put_user_asm2_goto(x, addr, label)                  \
+       asm goto ("1: std%U1%X1 %0,%1   # put_user\n"           \
+-- 
+2.43.0
+
diff --git a/queue-6.1/pps-add-an-error-check-in-parport_attach.patch b/queue-6.1/pps-add-an-error-check-in-parport_attach.patch
new file mode 100644 (file)
index 0000000..03f204a
--- /dev/null
@@ -0,0 +1,65 @@
+From 7a7f120554318acaa1c2f7d45db044e0a791d79a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 28 Aug 2024 21:18:14 +0800
+Subject: pps: add an error check in parport_attach
+
+From: Ma Ke <make24@iscas.ac.cn>
+
+[ Upstream commit 62c5a01a5711c8e4be8ae7b6f0db663094615d48 ]
+
+In parport_attach, the return value of ida_alloc is unchecked, witch leads
+to the use of an invalid index value.
+
+To address this issue, index should be checked. When the index value is
+abnormal, the device should be freed.
+
+Found by code review, compile tested only.
+
+Cc: stable@vger.kernel.org
+Fixes: fb56d97df70e ("pps: client: use new parport device model")
+Signed-off-by: Ma Ke <make24@iscas.ac.cn>
+Acked-by: Rodolfo Giometti <giometti@enneenne.com>
+Link: https://lore.kernel.org/r/20240828131814.3034338-1-make24@iscas.ac.cn
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pps/clients/pps_parport.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pps/clients/pps_parport.c b/drivers/pps/clients/pps_parport.c
+index af972cdc04b53..53e9c304ae0a7 100644
+--- a/drivers/pps/clients/pps_parport.c
++++ b/drivers/pps/clients/pps_parport.c
+@@ -149,6 +149,9 @@ static void parport_attach(struct parport *port)
+       }
+       index = ida_alloc(&pps_client_index, GFP_KERNEL);
++      if (index < 0)
++              goto err_free_device;
++
+       memset(&pps_client_cb, 0, sizeof(pps_client_cb));
+       pps_client_cb.private = device;
+       pps_client_cb.irq_func = parport_irq;
+@@ -159,7 +162,7 @@ static void parport_attach(struct parport *port)
+                                                   index);
+       if (!device->pardev) {
+               pr_err("couldn't register with %s\n", port->name);
+-              goto err_free;
++              goto err_free_ida;
+       }
+       if (parport_claim_or_block(device->pardev) < 0) {
+@@ -187,8 +190,9 @@ static void parport_attach(struct parport *port)
+       parport_release(device->pardev);
+ err_unregister_dev:
+       parport_unregister_device(device->pardev);
+-err_free:
++err_free_ida:
+       ida_free(&pps_client_index, index);
++err_free_device:
+       kfree(device);
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.1/pps-remove-usage-of-the-deprecated-ida_simple_xx-api.patch b/queue-6.1/pps-remove-usage-of-the-deprecated-ida_simple_xx-api.patch
new file mode 100644 (file)
index 0000000..bc7b096
--- /dev/null
@@ -0,0 +1,59 @@
+From 7c6d313c358ee5143ace0ea5c3dbe8721d75e225 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 14 Apr 2024 12:10:17 +0200
+Subject: pps: remove usage of the deprecated ida_simple_xx() API
+
+From: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+
+[ Upstream commit 55dbc5b5174d0e7d1fa397d05aa4cb145e8b887e ]
+
+ida_alloc() and ida_free() should be preferred to the deprecated
+ida_simple_get() and ida_simple_remove().
+
+This is less verbose.
+
+Link: https://lkml.kernel.org/r/9f681747d446b874952a892491387d79ffe565a9.1713089394.git.christophe.jaillet@wanadoo.fr
+Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+Cc: Rodolfo Giometti <giometti@enneenne.com>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Stable-dep-of: 62c5a01a5711 ("pps: add an error check in parport_attach")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pps/clients/pps_parport.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/pps/clients/pps_parport.c b/drivers/pps/clients/pps_parport.c
+index 42f93d4c6ee32..af972cdc04b53 100644
+--- a/drivers/pps/clients/pps_parport.c
++++ b/drivers/pps/clients/pps_parport.c
+@@ -148,7 +148,7 @@ static void parport_attach(struct parport *port)
+               return;
+       }
+-      index = ida_simple_get(&pps_client_index, 0, 0, GFP_KERNEL);
++      index = ida_alloc(&pps_client_index, GFP_KERNEL);
+       memset(&pps_client_cb, 0, sizeof(pps_client_cb));
+       pps_client_cb.private = device;
+       pps_client_cb.irq_func = parport_irq;
+@@ -188,7 +188,7 @@ static void parport_attach(struct parport *port)
+ err_unregister_dev:
+       parport_unregister_device(device->pardev);
+ err_free:
+-      ida_simple_remove(&pps_client_index, index);
++      ida_free(&pps_client_index, index);
+       kfree(device);
+ }
+@@ -208,7 +208,7 @@ static void parport_detach(struct parport *port)
+       pps_unregister_source(device->pps);
+       parport_release(pardev);
+       parport_unregister_device(pardev);
+-      ida_simple_remove(&pps_client_index, device->index);
++      ida_free(&pps_client_index, device->index);
+       kfree(device);
+ }
+-- 
+2.43.0
+
index ca2bfea1998993c964830037986308167b5095d1..89e7c92f38589374714c6f340a9be98af36b48dd 100644 (file)
@@ -356,3 +356,22 @@ fs-fix-file_set_fowner-lsm-hook-inconsistencies.patch
 nfs-fix-memory-leak-in-error-path-of-nfs4_do_reclaim.patch
 edac-igen6-fix-conversion-of-system-address-to-physical-memory-address.patch
 padata-use-integer-wrap-around-to-prevent-deadlock-on-seq_nr-overflow.patch
+soc-versatile-realview-fix-memory-leak-during-device.patch
+soc-versatile-realview-fix-soc_dev-leak-during-devic.patch
+powerpc-64-option-to-build-big-endian-with-elfv2-abi.patch
+powerpc-64-add-support-to-build-with-prefixed-instru.patch
+powerpc-atomic-use-yz-constraints-for-ds-form-instru.patch
+usb-yurex-replace-snprintf-with-the-safer-scnprintf-.patch
+usb-misc-yurex-fix-race-between-read-and-write.patch
+xhci-fix-event-ring-segment-table-related-masks-and-.patch
+xhci-remove-xhci_test_trb_in_td_math-early-developme.patch
+xhci-refactor-interrupter-code-for-initial-multi-int.patch
+xhci-preserve-rsvdp-bits-in-erstba-register-correctl.patch
+xhci-add-a-quirk-for-writing-erst-in-high-low-order.patch
+usb-xhci-fix-loss-of-data-on-cadence-xhc.patch
+pps-remove-usage-of-the-deprecated-ida_simple_xx-api.patch
+pps-add-an-error-check-in-parport_attach.patch
+x86-idtentry-incorporate-definitions-declarations-of.patch
+x86-entry-remove-unwanted-instrumentation-in-common_.patch
+cpuidle-adjust-includes-to-remove-of_device.h.patch
+cpuidle-riscv-sbi-use-scoped-device-node-handling-to.patch
diff --git a/queue-6.1/soc-versatile-realview-fix-memory-leak-during-device.patch b/queue-6.1/soc-versatile-realview-fix-memory-leak-during-device.patch
new file mode 100644 (file)
index 0000000..eb0ebf6
--- /dev/null
@@ -0,0 +1,50 @@
+From 879c926a9de9985695f293282dca15ae31bcd68e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 25 Aug 2024 20:05:23 +0200
+Subject: soc: versatile: realview: fix memory leak during device remove
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit 1c4f26a41f9d052f334f6ae629e01f598ed93508 ]
+
+If device is unbound, the memory allocated for soc_dev_attr should be
+freed to prevent leaks.
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Link: https://lore.kernel.org/20240825-soc-dev-fixes-v1-2-ff4b35abed83@linaro.org
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Stable-dep-of: c774f2564c00 ("soc: versatile: realview: fix soc_dev leak during device remove")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/versatile/soc-realview.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/soc/versatile/soc-realview.c b/drivers/soc/versatile/soc-realview.c
+index c6876d232d8fd..d304ee69287af 100644
+--- a/drivers/soc/versatile/soc-realview.c
++++ b/drivers/soc/versatile/soc-realview.c
+@@ -93,7 +93,7 @@ static int realview_soc_probe(struct platform_device *pdev)
+       if (IS_ERR(syscon_regmap))
+               return PTR_ERR(syscon_regmap);
+-      soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
++      soc_dev_attr = devm_kzalloc(&pdev->dev, sizeof(*soc_dev_attr), GFP_KERNEL);
+       if (!soc_dev_attr)
+               return -ENOMEM;
+@@ -106,10 +106,9 @@ static int realview_soc_probe(struct platform_device *pdev)
+       soc_dev_attr->family = "Versatile";
+       soc_dev_attr->custom_attr_group = realview_groups[0];
+       soc_dev = soc_device_register(soc_dev_attr);
+-      if (IS_ERR(soc_dev)) {
+-              kfree(soc_dev_attr);
++      if (IS_ERR(soc_dev))
+               return -ENODEV;
+-      }
++
+       ret = regmap_read(syscon_regmap, REALVIEW_SYS_ID_OFFSET,
+                         &realview_coreid);
+       if (ret)
+-- 
+2.43.0
+
diff --git a/queue-6.1/soc-versatile-realview-fix-soc_dev-leak-during-devic.patch b/queue-6.1/soc-versatile-realview-fix-soc_dev-leak-during-devic.patch
new file mode 100644 (file)
index 0000000..e4af07c
--- /dev/null
@@ -0,0 +1,63 @@
+From 79cd77cae071951f0befe68932cf5830ed34faeb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 25 Aug 2024 20:05:24 +0200
+Subject: soc: versatile: realview: fix soc_dev leak during device remove
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit c774f2564c0086c23f5269fd4691f233756bf075 ]
+
+If device is unbound, the soc_dev should be unregistered to prevent
+memory leak.
+
+Fixes: a2974c9c1f83 ("soc: add driver for the ARM RealView")
+Cc: stable@vger.kernel.org
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Link: https://lore.kernel.org/20240825-soc-dev-fixes-v1-3-ff4b35abed83@linaro.org
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/versatile/soc-realview.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/drivers/soc/versatile/soc-realview.c b/drivers/soc/versatile/soc-realview.c
+index d304ee69287af..cf91abe07d38d 100644
+--- a/drivers/soc/versatile/soc-realview.c
++++ b/drivers/soc/versatile/soc-realview.c
+@@ -4,6 +4,7 @@
+  *
+  * Author: Linus Walleij <linus.walleij@linaro.org>
+  */
++#include <linux/device.h>
+ #include <linux/init.h>
+ #include <linux/io.h>
+ #include <linux/slab.h>
+@@ -81,6 +82,13 @@ static struct attribute *realview_attrs[] = {
+ ATTRIBUTE_GROUPS(realview);
++static void realview_soc_socdev_release(void *data)
++{
++      struct soc_device *soc_dev = data;
++
++      soc_device_unregister(soc_dev);
++}
++
+ static int realview_soc_probe(struct platform_device *pdev)
+ {
+       struct regmap *syscon_regmap;
+@@ -109,6 +117,11 @@ static int realview_soc_probe(struct platform_device *pdev)
+       if (IS_ERR(soc_dev))
+               return -ENODEV;
++      ret = devm_add_action_or_reset(&pdev->dev, realview_soc_socdev_release,
++                                     soc_dev);
++      if (ret)
++              return ret;
++
+       ret = regmap_read(syscon_regmap, REALVIEW_SYS_ID_OFFSET,
+                         &realview_coreid);
+       if (ret)
+-- 
+2.43.0
+
diff --git a/queue-6.1/usb-misc-yurex-fix-race-between-read-and-write.patch b/queue-6.1/usb-misc-yurex-fix-race-between-read-and-write.patch
new file mode 100644 (file)
index 0000000..2b71445
--- /dev/null
@@ -0,0 +1,63 @@
+From 2e40b2c3639f1912f826150d2ae6ba0caeba2001 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Sep 2024 15:21:22 +0200
+Subject: USB: misc: yurex: fix race between read and write
+
+From: Oliver Neukum <oneukum@suse.com>
+
+[ Upstream commit 93907620b308609c72ba4b95b09a6aa2658bb553 ]
+
+The write code path touches the bbu member in a non atomic manner
+without taking the spinlock. Fix it.
+
+The bug is as old as the driver.
+
+Signed-off-by: Oliver Neukum <oneukum@suse.com>
+CC: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20240912132126.1034743-1-oneukum@suse.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/misc/yurex.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c
+index 5a13cddace0e6..44136989f6c6a 100644
+--- a/drivers/usb/misc/yurex.c
++++ b/drivers/usb/misc/yurex.c
+@@ -404,7 +404,6 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
+       struct usb_yurex *dev;
+       int len = 0;
+       char in_buffer[MAX_S64_STRLEN];
+-      unsigned long flags;
+       dev = file->private_data;
+@@ -417,9 +416,9 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
+       if (WARN_ON_ONCE(dev->bbu > S64_MAX || dev->bbu < S64_MIN))
+               return -EIO;
+-      spin_lock_irqsave(&dev->lock, flags);
++      spin_lock_irq(&dev->lock);
+       scnprintf(in_buffer, MAX_S64_STRLEN, "%lld\n", dev->bbu);
+-      spin_unlock_irqrestore(&dev->lock, flags);
++      spin_unlock_irq(&dev->lock);
+       mutex_unlock(&dev->io_mutex);
+       return simple_read_from_buffer(buffer, count, ppos, in_buffer, len);
+@@ -509,8 +508,11 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer,
+                       __func__, retval);
+               goto error;
+       }
+-      if (set && timeout)
++      if (set && timeout) {
++              spin_lock_irq(&dev->lock);
+               dev->bbu = c2;
++              spin_unlock_irq(&dev->lock);
++      }
+       return timeout ? count : -EIO;
+ error:
+-- 
+2.43.0
+
diff --git a/queue-6.1/usb-xhci-fix-loss-of-data-on-cadence-xhc.patch b/queue-6.1/usb-xhci-fix-loss-of-data-on-cadence-xhc.patch
new file mode 100644 (file)
index 0000000..abb9323
--- /dev/null
@@ -0,0 +1,117 @@
+From 2a27162a0948cdaa819023b370dc880d73ba27c5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 5 Sep 2024 07:03:28 +0000
+Subject: usb: xhci: fix loss of data on Cadence xHC
+
+From: Pawel Laszczak <pawell@cadence.com>
+
+[ Upstream commit e5fa8db0be3e8757e8641600c518425a4589b85c ]
+
+Streams should flush their TRB cache, re-read TRBs, and start executing
+TRBs from the beginning of the new dequeue pointer after a 'Set TR Dequeue
+Pointer' command.
+
+Cadence controllers may fail to start from the beginning of the dequeue
+TRB as it doesn't clear the Opaque 'RsvdO' field of the stream context
+during 'Set TR Dequeue' command. This stream context area is where xHC
+stores information about the last partially executed TD when a stream
+is stopped. xHC uses this information to resume the transfer where it left
+mid TD, when the stream is restarted.
+
+Patch fixes this by clearing out all RsvdO fields before initializing new
+Stream transfer using a 'Set TR Dequeue Pointer' command.
+
+Fixes: 3d82904559f4 ("usb: cdnsp: cdns3 Add main part of Cadence USBSSP DRD Driver")
+cc: stable@vger.kernel.org
+Signed-off-by: Pawel Laszczak <pawell@cadence.com>
+Reviewed-by: Peter Chen <peter.chen@kernel.org>
+Link: https://lore.kernel.org/r/PH7PR07MB95386A40146E3EC64086F409DD9D2@PH7PR07MB9538.namprd07.prod.outlook.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/cdns3/host.c     |  4 +++-
+ drivers/usb/host/xhci-pci.c  |  7 +++++++
+ drivers/usb/host/xhci-ring.c | 14 ++++++++++++++
+ drivers/usb/host/xhci.h      |  1 +
+ 4 files changed, 25 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/usb/cdns3/host.c b/drivers/usb/cdns3/host.c
+index ceca4d839dfd4..7ba760ee62e33 100644
+--- a/drivers/usb/cdns3/host.c
++++ b/drivers/usb/cdns3/host.c
+@@ -62,7 +62,9 @@ static const struct xhci_plat_priv xhci_plat_cdns3_xhci = {
+       .resume_quirk = xhci_cdns3_resume_quirk,
+ };
+-static const struct xhci_plat_priv xhci_plat_cdnsp_xhci;
++static const struct xhci_plat_priv xhci_plat_cdnsp_xhci = {
++      .quirks = XHCI_CDNS_SCTX_QUIRK,
++};
+ static int __cdns_host_init(struct cdns *cdns)
+ {
+diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
+index 7d1c44c562f41..18d7a94c82607 100644
+--- a/drivers/usb/host/xhci-pci.c
++++ b/drivers/usb/host/xhci-pci.c
+@@ -75,6 +75,9 @@
+ #define PCI_DEVICE_ID_ASMEDIA_2142_XHCI                       0x2142
+ #define PCI_DEVICE_ID_ASMEDIA_3242_XHCI                       0x3242
++#define PCI_DEVICE_ID_CADENCE                         0x17CD
++#define PCI_DEVICE_ID_CADENCE_SSP                     0x0200
++
+ static const char hcd_name[] = "xhci_hcd";
+ static struct hc_driver __read_mostly xhci_pci_hc_driver;
+@@ -352,6 +355,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
+                       xhci->quirks |= XHCI_ZHAOXIN_TRB_FETCH;
+       }
++      if (pdev->vendor == PCI_DEVICE_ID_CADENCE &&
++          pdev->device == PCI_DEVICE_ID_CADENCE_SSP)
++              xhci->quirks |= XHCI_CDNS_SCTX_QUIRK;
++
+       /* xHC spec requires PCI devices to support D3hot and D3cold */
+       if (xhci->hci_version >= 0x120)
+               xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
+diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
+index 29d53c4e60df5..83cd36f5d9e4b 100644
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -1384,6 +1384,20 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id,
+                       struct xhci_stream_ctx *ctx =
+                               &ep->stream_info->stream_ctx_array[stream_id];
+                       deq = le64_to_cpu(ctx->stream_ring) & SCTX_DEQ_MASK;
++
++                      /*
++                       * Cadence xHCI controllers store some endpoint state
++                       * information within Rsvd0 fields of Stream Endpoint
++                       * context. This field is not cleared during Set TR
++                       * Dequeue Pointer command which causes XDMA to skip
++                       * over transfer ring and leads to data loss on stream
++                       * pipe.
++                       * To fix this issue driver must clear Rsvd0 field.
++                       */
++                      if (xhci->quirks & XHCI_CDNS_SCTX_QUIRK) {
++                              ctx->reserved[0] = 0;
++                              ctx->reserved[1] = 0;
++                      }
+               } else {
+                       deq = le64_to_cpu(ep_ctx->deq) & ~EP_CTX_CYCLE_MASK;
+               }
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index 09fe993d67762..bd6f311a53f16 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1917,6 +1917,7 @@ struct xhci_hcd {
+ #define XHCI_ZHAOXIN_TRB_FETCH        BIT_ULL(45)
+ #define XHCI_ZHAOXIN_HOST     BIT_ULL(46)
+ #define XHCI_WRITE_64_HI_LO   BIT_ULL(47)
++#define XHCI_CDNS_SCTX_QUIRK  BIT_ULL(48)
+       unsigned int            num_active_eps;
+       unsigned int            limit_active_eps;
+-- 
+2.43.0
+
diff --git a/queue-6.1/usb-yurex-replace-snprintf-with-the-safer-scnprintf-.patch b/queue-6.1/usb-yurex-replace-snprintf-with-the-safer-scnprintf-.patch
new file mode 100644 (file)
index 0000000..c7f0682
--- /dev/null
@@ -0,0 +1,77 @@
+From 312031bb74ffb51701b453fd3ea0af4debef5a3d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 Dec 2023 16:42:37 +0000
+Subject: usb: yurex: Replace snprintf() with the safer scnprintf() variant
+
+From: Lee Jones <lee@kernel.org>
+
+[ Upstream commit 86b20af11e84c26ae3fde4dcc4f490948e3f8035 ]
+
+There is a general misunderstanding amongst engineers that {v}snprintf()
+returns the length of the data *actually* encoded into the destination
+array.  However, as per the C99 standard {v}snprintf() really returns
+the length of the data that *would have been* written if there were
+enough space for it.  This misunderstanding has led to buffer-overruns
+in the past.  It's generally considered safer to use the {v}scnprintf()
+variants in their place (or even sprintf() in simple cases).  So let's
+do that.
+
+Whilst we're at it, let's define some magic numbers to increase
+readability and ease of maintenance.
+
+Link: https://lwn.net/Articles/69419/
+Link: https://github.com/KSPP/linux/issues/105
+Cc: Tomoki Sekiyama <tomoki.sekiyama@gmail.com>
+Signed-off-by: Lee Jones <lee@kernel.org>
+Link: https://lore.kernel.org/r/20231213164246.1021885-9-lee@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 93907620b308 ("USB: misc: yurex: fix race between read and write")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/misc/yurex.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c
+index c640f98d20c54..5a13cddace0e6 100644
+--- a/drivers/usb/misc/yurex.c
++++ b/drivers/usb/misc/yurex.c
+@@ -34,6 +34,8 @@
+ #define YUREX_BUF_SIZE                8
+ #define YUREX_WRITE_TIMEOUT   (HZ*2)
++#define MAX_S64_STRLEN 20 /* {-}922337203685477580{7,8} */
++
+ /* table of devices that work with this driver */
+ static struct usb_device_id yurex_table[] = {
+       { USB_DEVICE(YUREX_VENDOR_ID, YUREX_PRODUCT_ID) },
+@@ -401,7 +403,7 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
+ {
+       struct usb_yurex *dev;
+       int len = 0;
+-      char in_buffer[20];
++      char in_buffer[MAX_S64_STRLEN];
+       unsigned long flags;
+       dev = file->private_data;
+@@ -412,14 +414,14 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
+               return -ENODEV;
+       }
++      if (WARN_ON_ONCE(dev->bbu > S64_MAX || dev->bbu < S64_MIN))
++              return -EIO;
++
+       spin_lock_irqsave(&dev->lock, flags);
+-      len = snprintf(in_buffer, 20, "%lld\n", dev->bbu);
++      scnprintf(in_buffer, MAX_S64_STRLEN, "%lld\n", dev->bbu);
+       spin_unlock_irqrestore(&dev->lock, flags);
+       mutex_unlock(&dev->io_mutex);
+-      if (WARN_ON_ONCE(len >= sizeof(in_buffer)))
+-              return -EIO;
+-
+       return simple_read_from_buffer(buffer, count, ppos, in_buffer, len);
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.1/x86-entry-remove-unwanted-instrumentation-in-common_.patch b/queue-6.1/x86-entry-remove-unwanted-instrumentation-in-common_.patch
new file mode 100644 (file)
index 0000000..7177fc6
--- /dev/null
@@ -0,0 +1,112 @@
+From 12b09ade7d32892ff1d6339ed907586bce688d16 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Jun 2024 09:50:30 +0200
+Subject: x86/entry: Remove unwanted instrumentation in common_interrupt()
+
+From: Dmitry Vyukov <dvyukov@google.com>
+
+[ Upstream commit 477d81a1c47a1b79b9c08fc92b5dea3c5143800b ]
+
+common_interrupt() and related variants call kvm_set_cpu_l1tf_flush_l1d(),
+which is neither marked noinstr nor __always_inline.
+
+So compiler puts it out of line and adds instrumentation to it.  Since the
+call is inside of instrumentation_begin/end(), objtool does not warn about
+it.
+
+The manifestation is that KCOV produces spurious coverage in
+kvm_set_cpu_l1tf_flush_l1d() in random places because the call happens when
+preempt count is not yet updated to say that the kernel is in an interrupt.
+
+Mark kvm_set_cpu_l1tf_flush_l1d() as __always_inline and move it out of the
+instrumentation_begin/end() section.  It only calls __this_cpu_write()
+which is already safe to call in noinstr contexts.
+
+Fixes: 6368558c3710 ("x86/entry: Provide IDTENTRY_SYSVEC")
+Signed-off-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Reviewed-by: Alexander Potapenko <glider@google.com>
+Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/all/3f9a1de9e415fcb53d07dc9e19fa8481bb021b1b.1718092070.git.dvyukov@google.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/hardirq.h  | 8 ++++++--
+ arch/x86/include/asm/idtentry.h | 6 +++---
+ 2 files changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h
+index 275e7fd20310f..a18df4191699c 100644
+--- a/arch/x86/include/asm/hardirq.h
++++ b/arch/x86/include/asm/hardirq.h
+@@ -62,7 +62,11 @@ extern u64 arch_irq_stat(void);
+ #if IS_ENABLED(CONFIG_KVM_INTEL)
+-static inline void kvm_set_cpu_l1tf_flush_l1d(void)
++/*
++ * This function is called from noinstr interrupt contexts
++ * and must be inlined to not get instrumentation.
++ */
++static __always_inline void kvm_set_cpu_l1tf_flush_l1d(void)
+ {
+       __this_cpu_write(irq_stat.kvm_cpu_l1tf_flush_l1d, 1);
+ }
+@@ -77,7 +81,7 @@ static __always_inline bool kvm_get_cpu_l1tf_flush_l1d(void)
+       return __this_cpu_read(irq_stat.kvm_cpu_l1tf_flush_l1d);
+ }
+ #else /* !IS_ENABLED(CONFIG_KVM_INTEL) */
+-static inline void kvm_set_cpu_l1tf_flush_l1d(void) { }
++static __always_inline void kvm_set_cpu_l1tf_flush_l1d(void) { }
+ #endif /* IS_ENABLED(CONFIG_KVM_INTEL) */
+ #endif /* _ASM_X86_HARDIRQ_H */
+diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h
+index 0c8823965952b..9c04f3c0ff18a 100644
+--- a/arch/x86/include/asm/idtentry.h
++++ b/arch/x86/include/asm/idtentry.h
+@@ -212,8 +212,8 @@ __visible noinstr void func(struct pt_regs *regs,                  \
+       irqentry_state_t state = irqentry_enter(regs);                  \
+       u32 vector = (u32)(u8)error_code;                               \
+                                                                       \
++      kvm_set_cpu_l1tf_flush_l1d();                                   \
+       instrumentation_begin();                                        \
+-      kvm_set_cpu_l1tf_flush_l1d();                                   \
+       run_irq_on_irqstack_cond(__##func, regs, vector);               \
+       instrumentation_end();                                          \
+       irqentry_exit(regs, state);                                     \
+@@ -250,7 +250,6 @@ static void __##func(struct pt_regs *regs);                                \
+                                                                       \
+ static __always_inline void instr_##func(struct pt_regs *regs)                \
+ {                                                                     \
+-      kvm_set_cpu_l1tf_flush_l1d();                                   \
+       run_sysvec_on_irqstack_cond(__##func, regs);                    \
+ }                                                                     \
+                                                                       \
+@@ -258,6 +257,7 @@ __visible noinstr void func(struct pt_regs *regs)                  \
+ {                                                                     \
+       irqentry_state_t state = irqentry_enter(regs);                  \
+                                                                       \
++      kvm_set_cpu_l1tf_flush_l1d();                                   \
+       instrumentation_begin();                                        \
+       instr_##func (regs);                                            \
+       instrumentation_end();                                          \
+@@ -288,7 +288,6 @@ static __always_inline void __##func(struct pt_regs *regs);                \
+ static __always_inline void instr_##func(struct pt_regs *regs)                \
+ {                                                                     \
+       __irq_enter_raw();                                              \
+-      kvm_set_cpu_l1tf_flush_l1d();                                   \
+       __##func (regs);                                                \
+       __irq_exit_raw();                                               \
+ }                                                                     \
+@@ -297,6 +296,7 @@ __visible noinstr void func(struct pt_regs *regs)                  \
+ {                                                                     \
+       irqentry_state_t state = irqentry_enter(regs);                  \
+                                                                       \
++      kvm_set_cpu_l1tf_flush_l1d();                                   \
+       instrumentation_begin();                                        \
+       instr_##func (regs);                                            \
+       instrumentation_end();                                          \
+-- 
+2.43.0
+
diff --git a/queue-6.1/x86-idtentry-incorporate-definitions-declarations-of.patch b/queue-6.1/x86-idtentry-incorporate-definitions-declarations-of.patch
new file mode 100644 (file)
index 0000000..fd43447
--- /dev/null
@@ -0,0 +1,225 @@
+From 316c9dd0516ed5835312b04f0cc83831f97d14d4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 5 Dec 2023 02:50:11 -0800
+Subject: x86/idtentry: Incorporate definitions/declarations of the FRED
+ entries
+
+From: Xin Li <xin3.li@intel.com>
+
+[ Upstream commit 90f357208200a941e90e75757123326684d715d0 ]
+
+FRED and IDT can share most of the definitions and declarations so
+that in the majority of cases the actual handler implementation is the
+same.
+
+The differences are the exceptions where FRED stores exception related
+information on the stack and the sysvec implementations as FRED can
+handle irqentry/exit() in the dispatcher instead of having it in each
+handler.
+
+Also add stub defines for vectors which are not used due to Kconfig
+decisions to spare the ifdeffery in the actual FRED dispatch code.
+
+Suggested-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Xin Li <xin3.li@intel.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Tested-by: Shan Kang <shan.kang@intel.com>
+Link: https://lore.kernel.org/r/20231205105030.8698-23-xin3.li@intel.com
+Stable-dep-of: 477d81a1c47a ("x86/entry: Remove unwanted instrumentation in common_interrupt()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/idtentry.h | 71 +++++++++++++++++++++++++++++----
+ 1 file changed, 63 insertions(+), 8 deletions(-)
+
+diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h
+index fca710a93eb9c..0c8823965952b 100644
+--- a/arch/x86/include/asm/idtentry.h
++++ b/arch/x86/include/asm/idtentry.h
+@@ -13,15 +13,18 @@
+ #include <asm/irq_stack.h>
++typedef void (*idtentry_t)(struct pt_regs *regs);
++
+ /**
+  * DECLARE_IDTENTRY - Declare functions for simple IDT entry points
+  *                  No error code pushed by hardware
+  * @vector:   Vector number (ignored for C)
+  * @func:     Function name of the entry point
+  *
+- * Declares three functions:
++ * Declares four functions:
+  * - The ASM entry point: asm_##func
+  * - The XEN PV trap entry point: xen_##func (maybe unused)
++ * - The C handler called from the FRED event dispatcher (maybe unused)
+  * - The C handler called from the ASM entry point
+  *
+  * Note: This is the C variant of DECLARE_IDTENTRY(). As the name says it
+@@ -31,6 +34,7 @@
+ #define DECLARE_IDTENTRY(vector, func)                                        \
+       asmlinkage void asm_##func(void);                               \
+       asmlinkage void xen_asm_##func(void);                           \
++      void fred_##func(struct pt_regs *regs);                         \
+       __visible void func(struct pt_regs *regs)
+ /**
+@@ -137,6 +141,17 @@ static __always_inline void __##func(struct pt_regs *regs,                \
+ #define DEFINE_IDTENTRY_RAW(func)                                     \
+ __visible noinstr void func(struct pt_regs *regs)
++/**
++ * DEFINE_FREDENTRY_RAW - Emit code for raw FRED entry points
++ * @func:     Function name of the entry point
++ *
++ * @func is called from the FRED event dispatcher with interrupts disabled.
++ *
++ * See @DEFINE_IDTENTRY_RAW for further details.
++ */
++#define DEFINE_FREDENTRY_RAW(func)                                    \
++noinstr void fred_##func(struct pt_regs *regs)
++
+ /**
+  * DECLARE_IDTENTRY_RAW_ERRORCODE - Declare functions for raw IDT entry points
+  *                                Error code pushed by hardware
+@@ -233,17 +248,27 @@ static noinline void __##func(struct pt_regs *regs, u32 vector)
+ #define DEFINE_IDTENTRY_SYSVEC(func)                                  \
+ static void __##func(struct pt_regs *regs);                           \
+                                                                       \
++static __always_inline void instr_##func(struct pt_regs *regs)                \
++{                                                                     \
++      kvm_set_cpu_l1tf_flush_l1d();                                   \
++      run_sysvec_on_irqstack_cond(__##func, regs);                    \
++}                                                                     \
++                                                                      \
+ __visible noinstr void func(struct pt_regs *regs)                     \
+ {                                                                     \
+       irqentry_state_t state = irqentry_enter(regs);                  \
+                                                                       \
+       instrumentation_begin();                                        \
+-      kvm_set_cpu_l1tf_flush_l1d();                                   \
+-      run_sysvec_on_irqstack_cond(__##func, regs);                    \
++      instr_##func (regs);                                            \
+       instrumentation_end();                                          \
+       irqentry_exit(regs, state);                                     \
+ }                                                                     \
+                                                                       \
++void fred_##func(struct pt_regs *regs)                                        \
++{                                                                     \
++      instr_##func (regs);                                            \
++}                                                                     \
++                                                                      \
+ static noinline void __##func(struct pt_regs *regs)
+ /**
+@@ -260,19 +285,29 @@ static noinline void __##func(struct pt_regs *regs)
+ #define DEFINE_IDTENTRY_SYSVEC_SIMPLE(func)                           \
+ static __always_inline void __##func(struct pt_regs *regs);           \
+                                                                       \
+-__visible noinstr void func(struct pt_regs *regs)                     \
++static __always_inline void instr_##func(struct pt_regs *regs)                \
+ {                                                                     \
+-      irqentry_state_t state = irqentry_enter(regs);                  \
+-                                                                      \
+-      instrumentation_begin();                                        \
+       __irq_enter_raw();                                              \
+       kvm_set_cpu_l1tf_flush_l1d();                                   \
+       __##func (regs);                                                \
+       __irq_exit_raw();                                               \
++}                                                                     \
++                                                                      \
++__visible noinstr void func(struct pt_regs *regs)                     \
++{                                                                     \
++      irqentry_state_t state = irqentry_enter(regs);                  \
++                                                                      \
++      instrumentation_begin();                                        \
++      instr_##func (regs);                                            \
+       instrumentation_end();                                          \
+       irqentry_exit(regs, state);                                     \
+ }                                                                     \
+                                                                       \
++void fred_##func(struct pt_regs *regs)                                        \
++{                                                                     \
++      instr_##func (regs);                                            \
++}                                                                     \
++                                                                      \
+ static __always_inline void __##func(struct pt_regs *regs)
+ /**
+@@ -410,15 +445,18 @@ __visible noinstr void func(struct pt_regs *regs,                        \
+ /* C-Code mapping */
+ #define DECLARE_IDTENTRY_NMI          DECLARE_IDTENTRY_RAW
+ #define DEFINE_IDTENTRY_NMI           DEFINE_IDTENTRY_RAW
++#define DEFINE_FREDENTRY_NMI          DEFINE_FREDENTRY_RAW
+ #ifdef CONFIG_X86_64
+ #define DECLARE_IDTENTRY_MCE          DECLARE_IDTENTRY_IST
+ #define DEFINE_IDTENTRY_MCE           DEFINE_IDTENTRY_IST
+ #define DEFINE_IDTENTRY_MCE_USER      DEFINE_IDTENTRY_NOIST
++#define DEFINE_FREDENTRY_MCE          DEFINE_FREDENTRY_RAW
+ #define DECLARE_IDTENTRY_DEBUG                DECLARE_IDTENTRY_IST
+ #define DEFINE_IDTENTRY_DEBUG         DEFINE_IDTENTRY_IST
+ #define DEFINE_IDTENTRY_DEBUG_USER    DEFINE_IDTENTRY_NOIST
++#define DEFINE_FREDENTRY_DEBUG                DEFINE_FREDENTRY_RAW
+ #endif
+ #else /* !__ASSEMBLY__ */
+@@ -660,23 +698,36 @@ DECLARE_IDTENTRY_SYSVEC(IRQ_MOVE_CLEANUP_VECTOR, sysvec_irq_move_cleanup);
+ DECLARE_IDTENTRY_SYSVEC(REBOOT_VECTOR,                        sysvec_reboot);
+ DECLARE_IDTENTRY_SYSVEC(CALL_FUNCTION_SINGLE_VECTOR,  sysvec_call_function_single);
+ DECLARE_IDTENTRY_SYSVEC(CALL_FUNCTION_VECTOR,         sysvec_call_function);
++#else
++# define fred_sysvec_reschedule_ipi                   NULL
++# define fred_sysvec_reboot                           NULL
++# define fred_sysvec_call_function_single             NULL
++# define fred_sysvec_call_function                    NULL
+ #endif
+ #ifdef CONFIG_X86_LOCAL_APIC
+ # ifdef CONFIG_X86_MCE_THRESHOLD
+ DECLARE_IDTENTRY_SYSVEC(THRESHOLD_APIC_VECTOR,                sysvec_threshold);
++# else
++# define fred_sysvec_threshold                                NULL
+ # endif
+ # ifdef CONFIG_X86_MCE_AMD
+ DECLARE_IDTENTRY_SYSVEC(DEFERRED_ERROR_VECTOR,                sysvec_deferred_error);
++# else
++# define fred_sysvec_deferred_error                   NULL
+ # endif
+ # ifdef CONFIG_X86_THERMAL_VECTOR
+ DECLARE_IDTENTRY_SYSVEC(THERMAL_APIC_VECTOR,          sysvec_thermal);
++# else
++# define fred_sysvec_thermal                          NULL
+ # endif
+ # ifdef CONFIG_IRQ_WORK
+ DECLARE_IDTENTRY_SYSVEC(IRQ_WORK_VECTOR,              sysvec_irq_work);
++# else
++# define fred_sysvec_irq_work                         NULL
+ # endif
+ #endif
+@@ -684,12 +735,16 @@ DECLARE_IDTENTRY_SYSVEC(IRQ_WORK_VECTOR,         sysvec_irq_work);
+ DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_VECTOR,           sysvec_kvm_posted_intr_ipi);
+ DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_WAKEUP_VECTOR,    sysvec_kvm_posted_intr_wakeup_ipi);
+ DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_NESTED_VECTOR,    sysvec_kvm_posted_intr_nested_ipi);
++#else
++# define fred_sysvec_kvm_posted_intr_ipi              NULL
++# define fred_sysvec_kvm_posted_intr_wakeup_ipi               NULL
++# define fred_sysvec_kvm_posted_intr_nested_ipi               NULL
+ #endif
+ #if IS_ENABLED(CONFIG_HYPERV)
+ DECLARE_IDTENTRY_SYSVEC(HYPERVISOR_CALLBACK_VECTOR,   sysvec_hyperv_callback);
+ DECLARE_IDTENTRY_SYSVEC(HYPERV_REENLIGHTENMENT_VECTOR,        sysvec_hyperv_reenlightenment);
+-DECLARE_IDTENTRY_SYSVEC(HYPERV_STIMER0_VECTOR,        sysvec_hyperv_stimer0);
++DECLARE_IDTENTRY_SYSVEC(HYPERV_STIMER0_VECTOR,                sysvec_hyperv_stimer0);
+ #endif
+ #if IS_ENABLED(CONFIG_ACRN_GUEST)
+-- 
+2.43.0
+
diff --git a/queue-6.1/xhci-add-a-quirk-for-writing-erst-in-high-low-order.patch b/queue-6.1/xhci-add-a-quirk-for-writing-erst-in-high-low-order.patch
new file mode 100644 (file)
index 0000000..0de92b3
--- /dev/null
@@ -0,0 +1,65 @@
+From f3eb638c7a48fe62f8da15b3137c010ebc22e5c9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Jun 2024 20:39:12 +0900
+Subject: xhci: Add a quirk for writing ERST in high-low order
+
+From: Daehwan Jung <dh10.jung@samsung.com>
+
+[ Upstream commit bc162403e33e1d57e40994977acaf19f1434e460 ]
+
+This quirk is for the controller that has a limitation in supporting
+separate ERSTBA_HI and ERSTBA_LO programming. It's supported when
+the ERSTBA is programmed ERSTBA_HI before ERSTBA_LO. That's because
+the internal initialization of event ring fetches the
+"Event Ring Segment Table Entry" based on the indication of ERSTBA_LO
+written.
+
+Signed-off-by: Daehwan Jung <dh10.jung@samsung.com>
+Link: https://lore.kernel.org/r/1718019553-111939-3-git-send-email-dh10.jung@samsung.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: e5fa8db0be3e ("usb: xhci: fix loss of data on Cadence xHC")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-mem.c | 5 ++++-
+ drivers/usb/host/xhci.h     | 2 ++
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
+index ac5fa86b0889c..88402cf424d11 100644
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -2306,7 +2306,10 @@ xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int intr_num, gfp_t flags
+       erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
+       erst_base &= ERST_BASE_RSVDP;
+       erst_base |= ir->erst.erst_dma_addr & ~ERST_BASE_RSVDP;
+-      xhci_write_64(xhci, erst_base, &ir->ir_set->erst_base);
++      if (xhci->quirks & XHCI_WRITE_64_HI_LO)
++              hi_lo_writeq(erst_base, &ir->ir_set->erst_base);
++      else
++              xhci_write_64(xhci, erst_base, &ir->ir_set->erst_base);
+       /* Set the event ring dequeue address of this interrupter */
+       xhci_set_hc_event_deq(xhci, ir);
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index 368098496d20c..09fe993d67762 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -17,6 +17,7 @@
+ #include <linux/kernel.h>
+ #include <linux/usb/hcd.h>
+ #include <linux/io-64-nonatomic-lo-hi.h>
++#include <linux/io-64-nonatomic-hi-lo.h>
+ /* Code sharing between pci-quirks and xhci hcd */
+ #include      "xhci-ext-caps.h"
+@@ -1915,6 +1916,7 @@ struct xhci_hcd {
+ #define XHCI_RESET_TO_DEFAULT BIT_ULL(44)
+ #define XHCI_ZHAOXIN_TRB_FETCH        BIT_ULL(45)
+ #define XHCI_ZHAOXIN_HOST     BIT_ULL(46)
++#define XHCI_WRITE_64_HI_LO   BIT_ULL(47)
+       unsigned int            num_active_eps;
+       unsigned int            limit_active_eps;
+-- 
+2.43.0
+
diff --git a/queue-6.1/xhci-fix-event-ring-segment-table-related-masks-and-.patch b/queue-6.1/xhci-fix-event-ring-segment-table-related-masks-and-.patch
new file mode 100644 (file)
index 0000000..f6ea476
--- /dev/null
@@ -0,0 +1,69 @@
+From f5cc8b3bdaa7de32cad2dfeb6726df368b57844e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 2 Feb 2023 17:04:55 +0200
+Subject: xhci: fix event ring segment table related masks and variables in
+ header
+
+From: Mathias Nyman <mathias.nyman@linux.intel.com>
+
+[ Upstream commit 8c1cbec9db1ab044167a7594c88bb5906c9d3ee4 ]
+
+xHC controller can supports up to 1024 interrupters.
+To fit these change the max_interrupters varable from u8 to u16.
+
+Add a separate mask for the reserve and preserve bits [5:0] in the erst
+base register and use it instead of the ERST_PRT_MASK.
+ERSR_PTR_MASK [3:0] is intended for masking bits in the
+event ring dequeue pointer register.
+
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20230202150505.618915-2-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: e5fa8db0be3e ("usb: xhci: fix loss of data on Cadence xHC")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-mem.c | 4 ++--
+ drivers/usb/host/xhci.h     | 5 ++++-
+ 2 files changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
+index 62808c98713ec..dbc9929e3259c 100644
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -2552,8 +2552,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
+                       "// Set ERST base address for ir_set 0 = 0x%llx",
+                       (unsigned long long)xhci->erst.erst_dma_addr);
+       val_64 = xhci_read_64(xhci, &xhci->ir_set->erst_base);
+-      val_64 &= ERST_PTR_MASK;
+-      val_64 |= (xhci->erst.erst_dma_addr & (u64) ~ERST_PTR_MASK);
++      val_64 &= ERST_BASE_RSVDP;
++      val_64 |= (xhci->erst.erst_dma_addr & (u64) ~ERST_BASE_RSVDP);
+       xhci_write_64(xhci, val_64, &xhci->ir_set->erst_base);
+       /* Set the event ring dequeue address */
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index c42058bfcd160..ac8fabd3eef44 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -513,6 +513,9 @@ struct xhci_intr_reg {
+ /* Preserve bits 16:31 of erst_size */
+ #define       ERST_SIZE_MASK          (0xffff << 16)
++/* erst_base bitmasks */
++#define ERST_BASE_RSVDP               (0x3f)
++
+ /* erst_dequeue bitmasks */
+ /* Dequeue ERST Segment Index (DESI) - Segment number (or alias)
+  * where the current dequeue pointer lies.  This is an optional HW hint.
+@@ -1781,7 +1784,7 @@ struct xhci_hcd {
+       u8              sbrn;
+       u16             hci_version;
+       u8              max_slots;
+-      u8              max_interrupters;
++      u16             max_interrupters;
+       u8              max_ports;
+       u8              isoc_threshold;
+       /* imod_interval in ns (I * 250ns) */
+-- 
+2.43.0
+
diff --git a/queue-6.1/xhci-preserve-rsvdp-bits-in-erstba-register-correctl.patch b/queue-6.1/xhci-preserve-rsvdp-bits-in-erstba-register-correctl.patch
new file mode 100644 (file)
index 0000000..41cdebe
--- /dev/null
@@ -0,0 +1,64 @@
+From 9c46c4e3ca2d1ffa424ec211bfba081db30e1947 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 Sep 2023 17:31:08 +0300
+Subject: xhci: Preserve RsvdP bits in ERSTBA register correctly
+
+From: Lukas Wunner <lukas@wunner.de>
+
+[ Upstream commit cf97c5e0f7dda2edc15ecd96775fe6c355823784 ]
+
+xhci_add_interrupter() erroneously preserves only the lowest 4 bits when
+writing the ERSTBA register, not the lowest 6 bits.  Fix it.
+
+Migrate the ERST_BASE_RSVDP macro to the modern GENMASK_ULL() syntax to
+avoid a u64 cast.
+
+This was previously fixed by commit 8c1cbec9db1a ("xhci: fix event ring
+segment table related masks and variables in header"), but immediately
+undone by commit b17a57f89f69 ("xhci: Refactor interrupter code for
+initial multi interrupter support.").
+
+Fixes: b17a57f89f69 ("xhci: Refactor interrupter code for initial multi interrupter support.")
+Signed-off-by: Lukas Wunner <lukas@wunner.de>
+Cc: stable@vger.kernel.org # v6.3+
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20230915143108.1532163-5-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: e5fa8db0be3e ("usb: xhci: fix loss of data on Cadence xHC")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-mem.c | 4 ++--
+ drivers/usb/host/xhci.h     | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
+index 91a41f362a58b..ac5fa86b0889c 100644
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -2304,8 +2304,8 @@ xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int intr_num, gfp_t flags
+       writel(erst_size, &ir->ir_set->erst_size);
+       erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
+-      erst_base &= ERST_PTR_MASK;
+-      erst_base |= (ir->erst.erst_dma_addr & (u64) ~ERST_PTR_MASK);
++      erst_base &= ERST_BASE_RSVDP;
++      erst_base |= ir->erst.erst_dma_addr & ~ERST_BASE_RSVDP;
+       xhci_write_64(xhci, erst_base, &ir->ir_set->erst_base);
+       /* Set the event ring dequeue address of this interrupter */
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index c46c7c097e8c5..368098496d20c 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -514,7 +514,7 @@ struct xhci_intr_reg {
+ #define       ERST_SIZE_MASK          (0xffff << 16)
+ /* erst_base bitmasks */
+-#define ERST_BASE_RSVDP               (0x3f)
++#define ERST_BASE_RSVDP               (GENMASK_ULL(5, 0))
+ /* erst_dequeue bitmasks */
+ /* Dequeue ERST Segment Index (DESI) - Segment number (or alias)
+-- 
+2.43.0
+
diff --git a/queue-6.1/xhci-refactor-interrupter-code-for-initial-multi-int.patch b/queue-6.1/xhci-refactor-interrupter-code-for-initial-multi-int.patch
new file mode 100644 (file)
index 0000000..da6e506
--- /dev/null
@@ -0,0 +1,705 @@
+From 66788ae275da6dd746bf851a5e6f02ccbb43f886 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 2 Feb 2023 17:04:57 +0200
+Subject: xhci: Refactor interrupter code for initial multi interrupter
+ support.
+
+From: Mathias Nyman <mathias.nyman@linux.intel.com>
+
+[ Upstream commit b17a57f89f69069458d0a9d9b04281ce48da7ebb ]
+
+xHC supports several interrupters, each with its own mmio register set,
+event ring and MSI/MSI-X vector. Transfers can be assigned different
+interrupters when queued. See xhci 4.17 for details.
+Current driver only supports one interrupter.
+
+Create a xhci_interrupter structure containing an event ring, pointer to
+mmio registers for this interrupter, variables to store registers over s3
+suspend, erst, etc. Add functions to create and free an interrupter, and
+pass an interrupter pointer to functions that deal with events.
+
+Secondary interrupters are also useful without having an interrupt vector.
+One use case is the xHCI audio sideband offloading where a DSP can take
+care of specific audio endpoints.
+
+When all transfer events of an offloaded endpoint can be mapped to a
+separate interrupter event ring the DSP can poll this ring, and we can mask
+these events preventing waking up the CPU.
+
+Only minor functional changes such as clearing some of the interrupter
+registers when freeing the interrupter.
+
+Still create only one primary interrupter.
+
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20230202150505.618915-4-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: e5fa8db0be3e ("usb: xhci: fix loss of data on Cadence xHC")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-debugfs.c |   2 +-
+ drivers/usb/host/xhci-mem.c     | 168 +++++++++++++++++++++-----------
+ drivers/usb/host/xhci-ring.c    |  68 +++++++------
+ drivers/usb/host/xhci.c         |  54 ++++++----
+ drivers/usb/host/xhci.h         |  24 +++--
+ 5 files changed, 196 insertions(+), 120 deletions(-)
+
+diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c
+index bd40caeeb21c6..99baa60ef50fe 100644
+--- a/drivers/usb/host/xhci-debugfs.c
++++ b/drivers/usb/host/xhci-debugfs.c
+@@ -693,7 +693,7 @@ void xhci_debugfs_init(struct xhci_hcd *xhci)
+                                    "command-ring",
+                                    xhci->debugfs_root);
+-      xhci_debugfs_create_ring_dir(xhci, &xhci->event_ring,
++      xhci_debugfs_create_ring_dir(xhci, &xhci->interrupter->event_ring,
+                                    "event-ring",
+                                    xhci->debugfs_root);
+diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
+index 70f5d3504f473..91a41f362a58b 100644
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -1821,17 +1821,43 @@ int xhci_alloc_erst(struct xhci_hcd *xhci,
+       return 0;
+ }
+-void xhci_free_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
++static void
++xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
+ {
+-      size_t size;
+       struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
++      size_t erst_size;
++      u64 tmp64;
++      u32 tmp;
+-      size = sizeof(struct xhci_erst_entry) * (erst->num_entries);
+-      if (erst->entries)
+-              dma_free_coherent(dev, size,
+-                              erst->entries,
+-                              erst->erst_dma_addr);
+-      erst->entries = NULL;
++      if (!ir)
++              return;
++
++      erst_size = sizeof(struct xhci_erst_entry) * (ir->erst.num_entries);
++      if (ir->erst.entries)
++              dma_free_coherent(dev, erst_size,
++                                ir->erst.entries,
++                                ir->erst.erst_dma_addr);
++      ir->erst.entries = NULL;
++
++      /*
++       * Clean out interrupter registers except ERSTBA. Clearing either the
++       * low or high 32 bits of ERSTBA immediately causes the controller to
++       * dereference the partially cleared 64 bit address, causing IOMMU error.
++       */
++      tmp = readl(&ir->ir_set->erst_size);
++      tmp &= ERST_SIZE_MASK;
++      writel(tmp, &ir->ir_set->erst_size);
++
++      tmp64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
++      tmp64 &= (u64) ERST_PTR_MASK;
++      xhci_write_64(xhci, tmp64, &ir->ir_set->erst_dequeue);
++
++      /* free interrrupter event ring */
++      if (ir->event_ring)
++              xhci_ring_free(xhci, ir->event_ring);
++      ir->event_ring = NULL;
++
++      kfree(ir);
+ }
+ void xhci_mem_cleanup(struct xhci_hcd *xhci)
+@@ -1841,12 +1867,9 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
+       cancel_delayed_work_sync(&xhci->cmd_timer);
+-      xhci_free_erst(xhci, &xhci->erst);
+-
+-      if (xhci->event_ring)
+-              xhci_ring_free(xhci, xhci->event_ring);
+-      xhci->event_ring = NULL;
+-      xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed event ring");
++      xhci_free_interrupter(xhci, xhci->interrupter);
++      xhci->interrupter = NULL;
++      xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed primary event ring");
+       if (xhci->cmd_ring)
+               xhci_ring_free(xhci, xhci->cmd_ring);
+@@ -1931,18 +1954,18 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
+       xhci->usb3_rhub.bus_state.bus_suspended = 0;
+ }
+-static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
++static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
+ {
+       u64 temp;
+       dma_addr_t deq;
+-      deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
+-                      xhci->event_ring->dequeue);
++      deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg,
++                      ir->event_ring->dequeue);
+       if (!deq)
+               xhci_warn(xhci, "WARN something wrong with SW event ring "
+                               "dequeue ptr.\n");
+       /* Update HC event ring dequeue pointer */
+-      temp = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
++      temp = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
+       temp &= ERST_PTR_MASK;
+       /* Don't clear the EHB bit (which is RW1C) because
+        * there might be more events to service.
+@@ -1952,7 +1975,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
+                       "// Write event ring dequeue pointer, "
+                       "preserving EHB bit");
+       xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp,
+-                      &xhci->ir_set->erst_dequeue);
++                      &ir->ir_set->erst_dequeue);
+ }
+ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
+@@ -2236,6 +2259,68 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
+       return 0;
+ }
++static struct xhci_interrupter *
++xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int intr_num, gfp_t flags)
++{
++      struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
++      struct xhci_interrupter *ir;
++      u64 erst_base;
++      u32 erst_size;
++      int ret;
++
++      if (intr_num > xhci->max_interrupters) {
++              xhci_warn(xhci, "Can't allocate interrupter %d, max interrupters %d\n",
++                        intr_num, xhci->max_interrupters);
++              return NULL;
++      }
++
++      if (xhci->interrupter) {
++              xhci_warn(xhci, "Can't allocate already set up interrupter %d\n", intr_num);
++              return NULL;
++      }
++
++      ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev));
++      if (!ir)
++              return NULL;
++
++      ir->ir_set = &xhci->run_regs->ir_set[intr_num];
++      ir->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
++                                      0, flags);
++      if (!ir->event_ring) {
++              xhci_warn(xhci, "Failed to allocate interrupter %d event ring\n", intr_num);
++              goto fail_ir;
++      }
++
++      ret = xhci_alloc_erst(xhci, ir->event_ring, &ir->erst, flags);
++      if (ret) {
++              xhci_warn(xhci, "Failed to allocate interrupter %d erst\n", intr_num);
++              goto fail_ev;
++
++      }
++      /* set ERST count with the number of entries in the segment table */
++      erst_size = readl(&ir->ir_set->erst_size);
++      erst_size &= ERST_SIZE_MASK;
++      erst_size |= ERST_NUM_SEGS;
++      writel(erst_size, &ir->ir_set->erst_size);
++
++      erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
++      erst_base &= ERST_PTR_MASK;
++      erst_base |= (ir->erst.erst_dma_addr & (u64) ~ERST_PTR_MASK);
++      xhci_write_64(xhci, erst_base, &ir->ir_set->erst_base);
++
++      /* Set the event ring dequeue address of this interrupter */
++      xhci_set_hc_event_deq(xhci, ir);
++
++      return ir;
++
++fail_ev:
++      xhci_ring_free(xhci, ir->event_ring);
++fail_ir:
++      kfree(ir);
++
++      return NULL;
++}
++
+ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
+ {
+       dma_addr_t      dma;
+@@ -2243,7 +2328,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
+       unsigned int    val, val2;
+       u64             val_64;
+       u32             page_size, temp;
+-      int             i, ret;
++      int             i;
+       INIT_LIST_HEAD(&xhci->cmd_list);
+@@ -2360,46 +2445,13 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
+                       " from cap regs base addr", val);
+       xhci->dba = (void __iomem *) xhci->cap_regs + val;
+       /* Set ir_set to interrupt register set 0 */
+-      xhci->ir_set = &xhci->run_regs->ir_set[0];
+-
+-      /*
+-       * Event ring setup: Allocate a normal ring, but also setup
+-       * the event ring segment table (ERST).  Section 4.9.3.
+-       */
+-      xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Allocating event ring");
+-      xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
+-                                      0, flags);
+-      if (!xhci->event_ring)
+-              goto fail;
+-
+-      ret = xhci_alloc_erst(xhci, xhci->event_ring, &xhci->erst, flags);
+-      if (ret)
+-              goto fail;
+-
+-      /* set ERST count with the number of entries in the segment table */
+-      val = readl(&xhci->ir_set->erst_size);
+-      val &= ERST_SIZE_MASK;
+-      val |= ERST_NUM_SEGS;
+-      xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+-                      "// Write ERST size = %i to ir_set 0 (some bits preserved)",
+-                      val);
+-      writel(val, &xhci->ir_set->erst_size);
++      /* allocate and set up primary interrupter with an event ring. */
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+-                      "// Set ERST entries to point to event ring.");
+-      /* set the segment table base address */
+-      xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+-                      "// Set ERST base address for ir_set 0 = 0x%llx",
+-                      (unsigned long long)xhci->erst.erst_dma_addr);
+-      val_64 = xhci_read_64(xhci, &xhci->ir_set->erst_base);
+-      val_64 &= ERST_BASE_RSVDP;
+-      val_64 |= (xhci->erst.erst_dma_addr & (u64) ~ERST_BASE_RSVDP);
+-      xhci_write_64(xhci, val_64, &xhci->ir_set->erst_base);
+-
+-      /* Set the event ring dequeue address */
+-      xhci_set_hc_event_deq(xhci);
+-      xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+-                      "Wrote ERST address to ir_set 0.");
++                     "Allocating primary event ring");
++      xhci->interrupter = xhci_alloc_interrupter(xhci, 0, flags);
++      if (!xhci->interrupter)
++              goto fail;
+       xhci->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX;
+diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
+index 7549c430c4f01..29d53c4e60df5 100644
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -1864,7 +1864,8 @@ static void xhci_cavium_reset_phy_quirk(struct xhci_hcd *xhci)
+ }
+ static void handle_port_status(struct xhci_hcd *xhci,
+-              union xhci_trb *event)
++                             struct xhci_interrupter *ir,
++                             union xhci_trb *event)
+ {
+       struct usb_hcd *hcd;
+       u32 port_id;
+@@ -1887,7 +1888,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
+       if ((port_id <= 0) || (port_id > max_ports)) {
+               xhci_warn(xhci, "Port change event with invalid port ID %d\n",
+                         port_id);
+-              inc_deq(xhci, xhci->event_ring);
++              inc_deq(xhci, ir->event_ring);
+               return;
+       }
+@@ -2017,7 +2018,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
+ cleanup:
+       /* Update event ring dequeue pointer before dropping the lock */
+-      inc_deq(xhci, xhci->event_ring);
++      inc_deq(xhci, ir->event_ring);
+       /* Don't make the USB core poll the roothub if we got a bad port status
+        * change event.  Besides, at that point we can't tell which roothub
+@@ -2578,7 +2579,8 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
+  * At this point, the host controller is probably hosed and should be reset.
+  */
+ static int handle_tx_event(struct xhci_hcd *xhci,
+-              struct xhci_transfer_event *event)
++                         struct xhci_interrupter *ir,
++                         struct xhci_transfer_event *event)
+ {
+       struct xhci_virt_ep *ep;
+       struct xhci_ring *ep_ring;
+@@ -2964,7 +2966,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
+                * processing missed tds.
+                */
+               if (!handling_skipped_tds)
+-                      inc_deq(xhci, xhci->event_ring);
++                      inc_deq(xhci, ir->event_ring);
+       /*
+        * If ep->skip is set, it means there are missed tds on the
+@@ -2979,8 +2981,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
+ err_out:
+       xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n",
+                (unsigned long long) xhci_trb_virt_to_dma(
+-                       xhci->event_ring->deq_seg,
+-                       xhci->event_ring->dequeue),
++                       ir->event_ring->deq_seg,
++                       ir->event_ring->dequeue),
+                lower_32_bits(le64_to_cpu(event->buffer)),
+                upper_32_bits(le64_to_cpu(event->buffer)),
+                le32_to_cpu(event->transfer_len),
+@@ -2994,7 +2996,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
+  * Returns >0 for "possibly more events to process" (caller should call again),
+  * otherwise 0 if done.  In future, <0 returns should indicate error code.
+  */
+-static int xhci_handle_event(struct xhci_hcd *xhci)
++static int xhci_handle_event(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
+ {
+       union xhci_trb *event;
+       int update_ptrs = 1;
+@@ -3002,18 +3004,18 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
+       int ret;
+       /* Event ring hasn't been allocated yet. */
+-      if (!xhci->event_ring || !xhci->event_ring->dequeue) {
+-              xhci_err(xhci, "ERROR event ring not ready\n");
++      if (!ir || !ir->event_ring || !ir->event_ring->dequeue) {
++              xhci_err(xhci, "ERROR interrupter not ready\n");
+               return -ENOMEM;
+       }
+-      event = xhci->event_ring->dequeue;
++      event = ir->event_ring->dequeue;
+       /* Does the HC or OS own the TRB? */
+       if ((le32_to_cpu(event->event_cmd.flags) & TRB_CYCLE) !=
+-          xhci->event_ring->cycle_state)
++          ir->event_ring->cycle_state)
+               return 0;
+-      trace_xhci_handle_event(xhci->event_ring, &event->generic);
++      trace_xhci_handle_event(ir->event_ring, &event->generic);
+       /*
+        * Barrier between reading the TRB_CYCLE (valid) flag above and any
+@@ -3028,11 +3030,11 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
+               handle_cmd_completion(xhci, &event->event_cmd);
+               break;
+       case TRB_PORT_STATUS:
+-              handle_port_status(xhci, event);
++              handle_port_status(xhci, ir, event);
+               update_ptrs = 0;
+               break;
+       case TRB_TRANSFER:
+-              ret = handle_tx_event(xhci, &event->trans_event);
++              ret = handle_tx_event(xhci, ir, &event->trans_event);
+               if (ret >= 0)
+                       update_ptrs = 0;
+               break;
+@@ -3056,7 +3058,7 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
+       if (update_ptrs)
+               /* Update SW event ring dequeue pointer */
+-              inc_deq(xhci, xhci->event_ring);
++              inc_deq(xhci, ir->event_ring);
+       /* Are there more items on the event ring?  Caller will call us again to
+        * check.
+@@ -3070,16 +3072,17 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
+  * - To avoid "Event Ring Full Error" condition
+  */
+ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
+-              union xhci_trb *event_ring_deq)
++                                   struct xhci_interrupter *ir,
++                                   union xhci_trb *event_ring_deq)
+ {
+       u64 temp_64;
+       dma_addr_t deq;
+-      temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
++      temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
+       /* If necessary, update the HW's version of the event ring deq ptr. */
+-      if (event_ring_deq != xhci->event_ring->dequeue) {
+-              deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
+-                              xhci->event_ring->dequeue);
++      if (event_ring_deq != ir->event_ring->dequeue) {
++              deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg,
++                              ir->event_ring->dequeue);
+               if (deq == 0)
+                       xhci_warn(xhci, "WARN something wrong with SW event ring dequeue ptr\n");
+               /*
+@@ -3097,7 +3100,7 @@ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
+       /* Clear the event handler busy flag (RW1C) */
+       temp_64 |= ERST_EHB;
+-      xhci_write_64(xhci, temp_64, &xhci->ir_set->erst_dequeue);
++      xhci_write_64(xhci, temp_64, &ir->ir_set->erst_dequeue);
+ }
+ /*
+@@ -3109,6 +3112,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
+ {
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       union xhci_trb *event_ring_deq;
++      struct xhci_interrupter *ir;
+       irqreturn_t ret = IRQ_NONE;
+       u64 temp_64;
+       u32 status;
+@@ -3141,11 +3145,13 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
+       status |= STS_EINT;
+       writel(status, &xhci->op_regs->status);
++      /* This is the handler of the primary interrupter */
++      ir = xhci->interrupter;
+       if (!hcd->msi_enabled) {
+               u32 irq_pending;
+-              irq_pending = readl(&xhci->ir_set->irq_pending);
++              irq_pending = readl(&ir->ir_set->irq_pending);
+               irq_pending |= IMAN_IP;
+-              writel(irq_pending, &xhci->ir_set->irq_pending);
++              writel(irq_pending, &ir->ir_set->irq_pending);
+       }
+       if (xhci->xhc_state & XHCI_STATE_DYING ||
+@@ -3155,22 +3161,22 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
+               /* Clear the event handler busy flag (RW1C);
+                * the event ring should be empty.
+                */
+-              temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
++              temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
+               xhci_write_64(xhci, temp_64 | ERST_EHB,
+-                              &xhci->ir_set->erst_dequeue);
++                              &ir->ir_set->erst_dequeue);
+               ret = IRQ_HANDLED;
+               goto out;
+       }
+-      event_ring_deq = xhci->event_ring->dequeue;
++      event_ring_deq = ir->event_ring->dequeue;
+       /* FIXME this should be a delayed service routine
+        * that clears the EHB.
+        */
+-      while (xhci_handle_event(xhci) > 0) {
++      while (xhci_handle_event(xhci, ir) > 0) {
+               if (event_loop++ < TRBS_PER_SEGMENT / 2)
+                       continue;
+-              xhci_update_erst_dequeue(xhci, event_ring_deq);
+-              event_ring_deq = xhci->event_ring->dequeue;
++              xhci_update_erst_dequeue(xhci, ir, event_ring_deq);
++              event_ring_deq = ir->event_ring->dequeue;
+               /* ring is half-full, force isoc trbs to interrupt more often */
+               if (xhci->isoc_bei_interval > AVOID_BEI_INTERVAL_MIN)
+@@ -3179,7 +3185,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
+               event_loop = 0;
+       }
+-      xhci_update_erst_dequeue(xhci, event_ring_deq);
++      xhci_update_erst_dequeue(xhci, ir, event_ring_deq);
+       ret = IRQ_HANDLED;
+ out:
+diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
+index ec2f6bedf003a..b072154badf33 100644
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -617,6 +617,7 @@ static int xhci_init(struct usb_hcd *hcd)
+ static int xhci_run_finished(struct xhci_hcd *xhci)
+ {
++      struct xhci_interrupter *ir = xhci->interrupter;
+       unsigned long   flags;
+       u32             temp;
+@@ -632,8 +633,8 @@ static int xhci_run_finished(struct xhci_hcd *xhci)
+       writel(temp, &xhci->op_regs->command);
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Enable primary interrupter");
+-      temp = readl(&xhci->ir_set->irq_pending);
+-      writel(ER_IRQ_ENABLE(temp), &xhci->ir_set->irq_pending);
++      temp = readl(&ir->ir_set->irq_pending);
++      writel(ER_IRQ_ENABLE(temp), &ir->ir_set->irq_pending);
+       if (xhci_start(xhci)) {
+               xhci_halt(xhci);
+@@ -669,7 +670,7 @@ int xhci_run(struct usb_hcd *hcd)
+       u64 temp_64;
+       int ret;
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+-
++      struct xhci_interrupter *ir = xhci->interrupter;
+       /* Start the xHCI host controller running only after the USB 2.0 roothub
+        * is setup.
+        */
+@@ -684,17 +685,17 @@ int xhci_run(struct usb_hcd *hcd)
+       if (ret)
+               return ret;
+-      temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
++      temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
+       temp_64 &= ~ERST_PTR_MASK;
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "ERST deq = 64'h%0lx", (long unsigned int) temp_64);
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "// Set the interrupt modulation register");
+-      temp = readl(&xhci->ir_set->irq_control);
++      temp = readl(&ir->ir_set->irq_control);
+       temp &= ~ER_IRQ_INTERVAL_MASK;
+       temp |= (xhci->imod_interval / 250) & ER_IRQ_INTERVAL_MASK;
+-      writel(temp, &xhci->ir_set->irq_control);
++      writel(temp, &ir->ir_set->irq_control);
+       if (xhci->quirks & XHCI_NEC_HOST) {
+               struct xhci_command *command;
+@@ -773,8 +774,8 @@ static void xhci_stop(struct usb_hcd *hcd)
+                       "// Disabling event ring interrupts");
+       temp = readl(&xhci->op_regs->status);
+       writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
+-      temp = readl(&xhci->ir_set->irq_pending);
+-      writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending);
++      temp = readl(&xhci->interrupter->ir_set->irq_pending);
++      writel(ER_IRQ_DISABLE(temp), &xhci->interrupter->ir_set->irq_pending);
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init, "cleaning up memory");
+       xhci_mem_cleanup(xhci);
+@@ -836,28 +837,36 @@ EXPORT_SYMBOL_GPL(xhci_shutdown);
+ #ifdef CONFIG_PM
+ static void xhci_save_registers(struct xhci_hcd *xhci)
+ {
++      struct xhci_interrupter *ir = xhci->interrupter;
++
+       xhci->s3.command = readl(&xhci->op_regs->command);
+       xhci->s3.dev_nt = readl(&xhci->op_regs->dev_notification);
+       xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
+       xhci->s3.config_reg = readl(&xhci->op_regs->config_reg);
+-      xhci->s3.erst_size = readl(&xhci->ir_set->erst_size);
+-      xhci->s3.erst_base = xhci_read_64(xhci, &xhci->ir_set->erst_base);
+-      xhci->s3.erst_dequeue = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
+-      xhci->s3.irq_pending = readl(&xhci->ir_set->irq_pending);
+-      xhci->s3.irq_control = readl(&xhci->ir_set->irq_control);
++
++      if (!ir)
++              return;
++
++      ir->s3_erst_size = readl(&ir->ir_set->erst_size);
++      ir->s3_erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
++      ir->s3_erst_dequeue = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
++      ir->s3_irq_pending = readl(&ir->ir_set->irq_pending);
++      ir->s3_irq_control = readl(&ir->ir_set->irq_control);
+ }
+ static void xhci_restore_registers(struct xhci_hcd *xhci)
+ {
++      struct xhci_interrupter *ir = xhci->interrupter;
++
+       writel(xhci->s3.command, &xhci->op_regs->command);
+       writel(xhci->s3.dev_nt, &xhci->op_regs->dev_notification);
+       xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr);
+       writel(xhci->s3.config_reg, &xhci->op_regs->config_reg);
+-      writel(xhci->s3.erst_size, &xhci->ir_set->erst_size);
+-      xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base);
+-      xhci_write_64(xhci, xhci->s3.erst_dequeue, &xhci->ir_set->erst_dequeue);
+-      writel(xhci->s3.irq_pending, &xhci->ir_set->irq_pending);
+-      writel(xhci->s3.irq_control, &xhci->ir_set->irq_control);
++      writel(ir->s3_erst_size, &ir->ir_set->erst_size);
++      xhci_write_64(xhci, ir->s3_erst_base, &ir->ir_set->erst_base);
++      xhci_write_64(xhci, ir->s3_erst_dequeue, &ir->ir_set->erst_dequeue);
++      writel(ir->s3_irq_pending, &ir->ir_set->irq_pending);
++      writel(ir->s3_irq_control, &ir->ir_set->irq_control);
+ }
+ static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
+@@ -1222,8 +1231,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
+               xhci_dbg(xhci, "// Disabling event ring interrupts\n");
+               temp = readl(&xhci->op_regs->status);
+               writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
+-              temp = readl(&xhci->ir_set->irq_pending);
+-              writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending);
++              temp = readl(&xhci->interrupter->ir_set->irq_pending);
++              writel(ER_IRQ_DISABLE(temp), &xhci->interrupter->ir_set->irq_pending);
+               xhci_dbg(xhci, "cleaning up memory\n");
+               xhci_mem_cleanup(xhci);
+@@ -5362,6 +5371,11 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
+       if (xhci->hci_version > 0x100)
+               xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2);
++      /* xhci-plat or xhci-pci might have set max_interrupters already */
++      if ((!xhci->max_interrupters) ||
++          xhci->max_interrupters > HCS_MAX_INTRS(xhci->hcs_params1))
++              xhci->max_interrupters = HCS_MAX_INTRS(xhci->hcs_params1);
++
+       xhci->quirks |= quirks;
+       get_quirks(dev, xhci);
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index ac8fabd3eef44..c46c7c097e8c5 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1694,11 +1694,6 @@ struct s3_save {
+       u32     dev_nt;
+       u64     dcbaa_ptr;
+       u32     config_reg;
+-      u32     irq_pending;
+-      u32     irq_control;
+-      u32     erst_size;
+-      u64     erst_base;
+-      u64     erst_dequeue;
+ };
+ /* Use for lpm */
+@@ -1725,7 +1720,18 @@ struct xhci_bus_state {
+       struct completion       u3exit_done[USB_MAXCHILDREN];
+ };
+-
++struct xhci_interrupter {
++      struct xhci_ring        *event_ring;
++      struct xhci_erst        erst;
++      struct xhci_intr_reg __iomem *ir_set;
++      unsigned int            intr_num;
++      /* For interrupter registers save and restore over suspend/resume */
++      u32     s3_irq_pending;
++      u32     s3_irq_control;
++      u32     s3_erst_size;
++      u64     s3_erst_base;
++      u64     s3_erst_dequeue;
++};
+ /*
+  * It can take up to 20 ms to transition from RExit to U0 on the
+  * Intel Lynx Point LP xHCI host.
+@@ -1768,8 +1774,6 @@ struct xhci_hcd {
+       struct xhci_op_regs __iomem *op_regs;
+       struct xhci_run_regs __iomem *run_regs;
+       struct xhci_doorbell_array __iomem *dba;
+-      /* Our HCD's current interrupter register set */
+-      struct  xhci_intr_reg __iomem *ir_set;
+       /* Cached register copies of read-only HC data */
+       __u32           hcs_params1;
+@@ -1804,6 +1808,7 @@ struct xhci_hcd {
+       struct reset_control *reset;
+       /* data structures */
+       struct xhci_device_context_array *dcbaa;
++      struct xhci_interrupter *interrupter;
+       struct xhci_ring        *cmd_ring;
+       unsigned int            cmd_ring_state;
+ #define CMD_RING_STATE_RUNNING         (1 << 0)
+@@ -1814,8 +1819,7 @@ struct xhci_hcd {
+       struct delayed_work     cmd_timer;
+       struct completion       cmd_ring_stop_completion;
+       struct xhci_command     *current_cmd;
+-      struct xhci_ring        *event_ring;
+-      struct xhci_erst        erst;
++
+       /* Scratchpad */
+       struct xhci_scratchpad  *scratchpad;
+-- 
+2.43.0
+
diff --git a/queue-6.1/xhci-remove-xhci_test_trb_in_td_math-early-developme.patch b/queue-6.1/xhci-remove-xhci_test_trb_in_td_math-early-developme.patch
new file mode 100644 (file)
index 0000000..60d8d23
--- /dev/null
@@ -0,0 +1,205 @@
+From 6c4bfab46f6b0b0561b935347b5dcaa1072d9303 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 2 Feb 2023 17:04:56 +0200
+Subject: xhci: remove xhci_test_trb_in_td_math early development check
+
+From: Mathias Nyman <mathias.nyman@linux.intel.com>
+
+[ Upstream commit 54f9927dfe2266402a226d5f51d38236bdca0590 ]
+
+Time to remove this test trb in td math check that was added
+in early stage of xhci driver development.
+
+It verified that the size, alignment and boundaries of the event and
+command rings allocated by the driver itself are correct.
+
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20230202150505.618915-3-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: e5fa8db0be3e ("usb: xhci: fix loss of data on Cadence xHC")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-mem.c | 160 ------------------------------------
+ 1 file changed, 160 deletions(-)
+
+diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
+index dbc9929e3259c..70f5d3504f473 100644
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -1931,164 +1931,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
+       xhci->usb3_rhub.bus_state.bus_suspended = 0;
+ }
+-static int xhci_test_trb_in_td(struct xhci_hcd *xhci,
+-              struct xhci_segment *input_seg,
+-              union xhci_trb *start_trb,
+-              union xhci_trb *end_trb,
+-              dma_addr_t input_dma,
+-              struct xhci_segment *result_seg,
+-              char *test_name, int test_number)
+-{
+-      unsigned long long start_dma;
+-      unsigned long long end_dma;
+-      struct xhci_segment *seg;
+-
+-      start_dma = xhci_trb_virt_to_dma(input_seg, start_trb);
+-      end_dma = xhci_trb_virt_to_dma(input_seg, end_trb);
+-
+-      seg = trb_in_td(xhci, input_seg, start_trb, end_trb, input_dma, false);
+-      if (seg != result_seg) {
+-              xhci_warn(xhci, "WARN: %s TRB math test %d failed!\n",
+-                              test_name, test_number);
+-              xhci_warn(xhci, "Tested TRB math w/ seg %p and "
+-                              "input DMA 0x%llx\n",
+-                              input_seg,
+-                              (unsigned long long) input_dma);
+-              xhci_warn(xhci, "starting TRB %p (0x%llx DMA), "
+-                              "ending TRB %p (0x%llx DMA)\n",
+-                              start_trb, start_dma,
+-                              end_trb, end_dma);
+-              xhci_warn(xhci, "Expected seg %p, got seg %p\n",
+-                              result_seg, seg);
+-              trb_in_td(xhci, input_seg, start_trb, end_trb, input_dma,
+-                        true);
+-              return -1;
+-      }
+-      return 0;
+-}
+-
+-/* TRB math checks for xhci_trb_in_td(), using the command and event rings. */
+-static int xhci_check_trb_in_td_math(struct xhci_hcd *xhci)
+-{
+-      struct {
+-              dma_addr_t              input_dma;
+-              struct xhci_segment     *result_seg;
+-      } simple_test_vector [] = {
+-              /* A zeroed DMA field should fail */
+-              { 0, NULL },
+-              /* One TRB before the ring start should fail */
+-              { xhci->event_ring->first_seg->dma - 16, NULL },
+-              /* One byte before the ring start should fail */
+-              { xhci->event_ring->first_seg->dma - 1, NULL },
+-              /* Starting TRB should succeed */
+-              { xhci->event_ring->first_seg->dma, xhci->event_ring->first_seg },
+-              /* Ending TRB should succeed */
+-              { xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 1)*16,
+-                      xhci->event_ring->first_seg },
+-              /* One byte after the ring end should fail */
+-              { xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 1)*16 + 1, NULL },
+-              /* One TRB after the ring end should fail */
+-              { xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT)*16, NULL },
+-              /* An address of all ones should fail */
+-              { (dma_addr_t) (~0), NULL },
+-      };
+-      struct {
+-              struct xhci_segment     *input_seg;
+-              union xhci_trb          *start_trb;
+-              union xhci_trb          *end_trb;
+-              dma_addr_t              input_dma;
+-              struct xhci_segment     *result_seg;
+-      } complex_test_vector [] = {
+-              /* Test feeding a valid DMA address from a different ring */
+-              {       .input_seg = xhci->event_ring->first_seg,
+-                      .start_trb = xhci->event_ring->first_seg->trbs,
+-                      .end_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
+-                      .input_dma = xhci->cmd_ring->first_seg->dma,
+-                      .result_seg = NULL,
+-              },
+-              /* Test feeding a valid end TRB from a different ring */
+-              {       .input_seg = xhci->event_ring->first_seg,
+-                      .start_trb = xhci->event_ring->first_seg->trbs,
+-                      .end_trb = &xhci->cmd_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
+-                      .input_dma = xhci->cmd_ring->first_seg->dma,
+-                      .result_seg = NULL,
+-              },
+-              /* Test feeding a valid start and end TRB from a different ring */
+-              {       .input_seg = xhci->event_ring->first_seg,
+-                      .start_trb = xhci->cmd_ring->first_seg->trbs,
+-                      .end_trb = &xhci->cmd_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
+-                      .input_dma = xhci->cmd_ring->first_seg->dma,
+-                      .result_seg = NULL,
+-              },
+-              /* TRB in this ring, but after this TD */
+-              {       .input_seg = xhci->event_ring->first_seg,
+-                      .start_trb = &xhci->event_ring->first_seg->trbs[0],
+-                      .end_trb = &xhci->event_ring->first_seg->trbs[3],
+-                      .input_dma = xhci->event_ring->first_seg->dma + 4*16,
+-                      .result_seg = NULL,
+-              },
+-              /* TRB in this ring, but before this TD */
+-              {       .input_seg = xhci->event_ring->first_seg,
+-                      .start_trb = &xhci->event_ring->first_seg->trbs[3],
+-                      .end_trb = &xhci->event_ring->first_seg->trbs[6],
+-                      .input_dma = xhci->event_ring->first_seg->dma + 2*16,
+-                      .result_seg = NULL,
+-              },
+-              /* TRB in this ring, but after this wrapped TD */
+-              {       .input_seg = xhci->event_ring->first_seg,
+-                      .start_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3],
+-                      .end_trb = &xhci->event_ring->first_seg->trbs[1],
+-                      .input_dma = xhci->event_ring->first_seg->dma + 2*16,
+-                      .result_seg = NULL,
+-              },
+-              /* TRB in this ring, but before this wrapped TD */
+-              {       .input_seg = xhci->event_ring->first_seg,
+-                      .start_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3],
+-                      .end_trb = &xhci->event_ring->first_seg->trbs[1],
+-                      .input_dma = xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 4)*16,
+-                      .result_seg = NULL,
+-              },
+-              /* TRB not in this ring, and we have a wrapped TD */
+-              {       .input_seg = xhci->event_ring->first_seg,
+-                      .start_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3],
+-                      .end_trb = &xhci->event_ring->first_seg->trbs[1],
+-                      .input_dma = xhci->cmd_ring->first_seg->dma + 2*16,
+-                      .result_seg = NULL,
+-              },
+-      };
+-
+-      unsigned int num_tests;
+-      int i, ret;
+-
+-      num_tests = ARRAY_SIZE(simple_test_vector);
+-      for (i = 0; i < num_tests; i++) {
+-              ret = xhci_test_trb_in_td(xhci,
+-                              xhci->event_ring->first_seg,
+-                              xhci->event_ring->first_seg->trbs,
+-                              &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
+-                              simple_test_vector[i].input_dma,
+-                              simple_test_vector[i].result_seg,
+-                              "Simple", i);
+-              if (ret < 0)
+-                      return ret;
+-      }
+-
+-      num_tests = ARRAY_SIZE(complex_test_vector);
+-      for (i = 0; i < num_tests; i++) {
+-              ret = xhci_test_trb_in_td(xhci,
+-                              complex_test_vector[i].input_seg,
+-                              complex_test_vector[i].start_trb,
+-                              complex_test_vector[i].end_trb,
+-                              complex_test_vector[i].input_dma,
+-                              complex_test_vector[i].result_seg,
+-                              "Complex", i);
+-              if (ret < 0)
+-                      return ret;
+-      }
+-      xhci_dbg(xhci, "TRB math tests passed.\n");
+-      return 0;
+-}
+-
+ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
+ {
+       u64 temp;
+@@ -2529,8 +2371,6 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
+                                       0, flags);
+       if (!xhci->event_ring)
+               goto fail;
+-      if (xhci_check_trb_in_td_math(xhci) < 0)
+-              goto fail;
+       ret = xhci_alloc_erst(xhci, xhci->event_ring, &xhci->erst, flags);
+       if (ret)
+-- 
+2.43.0
+