--- /dev/null
+From 1aadaa1217609ff4e1723af15d1b7014e86866a6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Mar 2025 17:20:38 +0100
+Subject: ARM: dts: opos6ul: add ksz8081 phy properties
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Sébastien Szymanski <sebastien.szymanski@armadeus.com>
+
+[ Upstream commit 6e1a7bc8382b0d4208258f7d2a4474fae788dd90 ]
+
+Commit c7e73b5051d6 ("ARM: imx: mach-imx6ul: remove 14x14 EVK specific
+PHY fixup") removed a PHY fixup that setted the clock mode and the LED
+mode.
+Make the Ethernet interface work again by doing as advised in the
+commit's log, set clock mode and the LED mode in the device tree.
+
+Fixes: c7e73b5051d6 ("ARM: imx: mach-imx6ul: remove 14x14 EVK specific PHY fixup")
+Signed-off-by: Sébastien Szymanski <sebastien.szymanski@armadeus.com>
+Reviewed-by: Oleksij Rempel <o.rempel@pengutronix.de>
+Signed-off-by: Shawn Guo <shawnguo@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/boot/dts/nxp/imx/imx6ul-imx6ull-opos6ul.dtsi | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/arch/arm/boot/dts/nxp/imx/imx6ul-imx6ull-opos6ul.dtsi b/arch/arm/boot/dts/nxp/imx/imx6ul-imx6ull-opos6ul.dtsi
+index f2386dcb9ff2c..dda4fa91b2f2c 100644
+--- a/arch/arm/boot/dts/nxp/imx/imx6ul-imx6ull-opos6ul.dtsi
++++ b/arch/arm/boot/dts/nxp/imx/imx6ul-imx6ull-opos6ul.dtsi
+@@ -40,6 +40,9 @@
+ reg = <1>;
+ interrupt-parent = <&gpio4>;
+ interrupts = <16 IRQ_TYPE_LEVEL_LOW>;
++ micrel,led-mode = <1>;
++ clocks = <&clks IMX6UL_CLK_ENET_REF>;
++ clock-names = "rmii-ref";
+ status = "okay";
+ };
+ };
+--
+2.39.5
+
--- /dev/null
+From f6eb25904b67b34ecfa7420a1d11a5ce303d5213 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 28 Apr 2025 14:06:58 +0200
+Subject: arm64: dts: st: Adjust interrupt-controller for stm32mp25 SoCs
+
+From: Christian Bruel <christian.bruel@foss.st.com>
+
+[ Upstream commit de2b2107d5a41a91ab603e135fb6e408abbee28e ]
+
+Use gic-400 compatible and remove address-cells = <1> on aarch64
+
+Fixes: 5d30d03aaf785 ("arm64: dts: st: introduce stm32mp25 SoCs family")
+Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
+Link: https://lore.kernel.org/r/20250415111654.2103767-2-christian.bruel@foss.st.com
+Signed-off-by: Alexandre Torgue <alexandre.torgue@foss.st.com>
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/st/stm32mp251.dtsi | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi
+index 5268a43218415..3219a8ea1e6a7 100644
+--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
++++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi
+@@ -73,9 +73,8 @@
+ };
+
+ intc: interrupt-controller@4ac00000 {
+- compatible = "arm,cortex-a7-gic";
++ compatible = "arm,gic-400";
+ #interrupt-cells = <3>;
+- #address-cells = <1>;
+ interrupt-controller;
+ reg = <0x0 0x4ac10000 0x0 0x1000>,
+ <0x0 0x4ac20000 0x0 0x2000>,
+--
+2.39.5
+
--- /dev/null
+From 452e47e89885b1a6c3c5927670273bf9ebc7cbee Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 28 Apr 2025 14:06:59 +0200
+Subject: arm64: dts: st: Use 128kB size for aliased GIC400 register access on
+ stm32mp25 SoCs
+
+From: Christian Bruel <christian.bruel@foss.st.com>
+
+[ Upstream commit 06c231fe953a26f4bc9d7a37ba1b9b288a59c7c2 ]
+
+Adjust the size of 8kB GIC regions to 128kB so that each 4kB is mapped 16
+times over a 64kB region.
+The offset is then adjusted in the irq-gic driver.
+
+see commit 12e14066f4835 ("irqchip/GIC: Add workaround for aliased GIC400")
+
+Fixes: 5d30d03aaf785 ("arm64: dts: st: introduce stm32mp25 SoCs family")
+Suggested-by: Marc Zyngier <maz@kernel.org>
+Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
+Acked-by: Marc Zyngier <maz@kernel.org>
+Link: https://lore.kernel.org/r/20250415111654.2103767-3-christian.bruel@foss.st.com
+Signed-off-by: Alexandre Torgue <alexandre.torgue@foss.st.com>
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/st/stm32mp251.dtsi | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi
+index 3219a8ea1e6a7..ce5409acae1ce 100644
+--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
++++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi
+@@ -77,9 +77,9 @@
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0x0 0x4ac10000 0x0 0x1000>,
+- <0x0 0x4ac20000 0x0 0x2000>,
+- <0x0 0x4ac40000 0x0 0x2000>,
+- <0x0 0x4ac60000 0x0 0x2000>;
++ <0x0 0x4ac20000 0x0 0x20000>,
++ <0x0 0x4ac40000 0x0 0x20000>,
++ <0x0 0x4ac60000 0x0 0x20000>;
+ };
+
+ psci {
+--
+2.39.5
+
--- /dev/null
+From 4629e907d1ba9d61016ecf1db2f068f697337979 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 25 Mar 2024 18:02:42 +0100
+Subject: cpufreq: intel_pstate: Do not update global.turbo_disabled after
+ initialization
+
+From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+[ Upstream commit 0940f1a8011fd69be5082015068e0dc31c800c20 ]
+
+The global.turbo_disabled is updated quite often, especially in the
+passive mode in which case it is updated every time the scheduler calls
+into the driver. However, this is generally not necessary and it adds
+MSR read overhead to scheduler code paths (and that particular MSR is
+slow to read).
+
+For this reason, make the driver read MSR_IA32_MISC_ENABLE_TURBO_DISABLE
+just once at the cpufreq driver registration time and remove all of the
+in-flight updates of global.turbo_disabled.
+
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+Stable-dep-of: ac4e04d9e378 ("cpufreq: intel_pstate: Unchecked MSR aceess in legacy mode")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/cpufreq/intel_pstate.c | 51 ++++++----------------------------
+ 1 file changed, 8 insertions(+), 43 deletions(-)
+
+diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
+index b69bff009e780..255746c053b4c 100644
+--- a/drivers/cpufreq/intel_pstate.c
++++ b/drivers/cpufreq/intel_pstate.c
+@@ -172,7 +172,6 @@ struct vid_data {
+ * based on the MSR_IA32_MISC_ENABLE value and whether or
+ * not the maximum reported turbo P-state is different from
+ * the maximum reported non-turbo one.
+- * @turbo_disabled_mf: The @turbo_disabled value reflected by cpuinfo.max_freq.
+ * @min_perf_pct: Minimum capacity limit in percent of the maximum turbo
+ * P-state capacity.
+ * @max_perf_pct: Maximum capacity limit in percent of the maximum turbo
+@@ -181,7 +180,6 @@ struct vid_data {
+ struct global_params {
+ bool no_turbo;
+ bool turbo_disabled;
+- bool turbo_disabled_mf;
+ int max_perf_pct;
+ int min_perf_pct;
+ };
+@@ -592,12 +590,13 @@ static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu)
+ cpu->pstate.min_pstate = intel_pstate_freq_to_hwp(cpu, freq);
+ }
+
+-static inline void update_turbo_state(void)
++static bool turbo_is_disabled(void)
+ {
+ u64 misc_en;
+
+ rdmsrl(MSR_IA32_MISC_ENABLE, misc_en);
+- global.turbo_disabled = misc_en & MSR_IA32_MISC_ENABLE_TURBO_DISABLE;
++
++ return !!(misc_en & MSR_IA32_MISC_ENABLE_TURBO_DISABLE);
+ }
+
+ static int min_perf_pct_min(void)
+@@ -1152,40 +1151,16 @@ static void intel_pstate_update_policies(void)
+ static void __intel_pstate_update_max_freq(struct cpudata *cpudata,
+ struct cpufreq_policy *policy)
+ {
+- policy->cpuinfo.max_freq = global.turbo_disabled_mf ?
++ policy->cpuinfo.max_freq = global.turbo_disabled ?
+ cpudata->pstate.max_freq : cpudata->pstate.turbo_freq;
+ refresh_frequency_limits(policy);
+ }
+
+-static void intel_pstate_update_max_freq(unsigned int cpu)
+-{
+- struct cpufreq_policy *policy = cpufreq_cpu_acquire(cpu);
+-
+- if (!policy)
+- return;
+-
+- __intel_pstate_update_max_freq(all_cpu_data[cpu], policy);
+-
+- cpufreq_cpu_release(policy);
+-}
+-
+ static void intel_pstate_update_limits(unsigned int cpu)
+ {
+ mutex_lock(&intel_pstate_driver_lock);
+
+- update_turbo_state();
+- /*
+- * If turbo has been turned on or off globally, policy limits for
+- * all CPUs need to be updated to reflect that.
+- */
+- if (global.turbo_disabled_mf != global.turbo_disabled) {
+- global.turbo_disabled_mf = global.turbo_disabled;
+- arch_set_max_freq_ratio(global.turbo_disabled);
+- for_each_possible_cpu(cpu)
+- intel_pstate_update_max_freq(cpu);
+- } else {
+- cpufreq_update_policy(cpu);
+- }
++ cpufreq_update_policy(cpu);
+
+ mutex_unlock(&intel_pstate_driver_lock);
+ }
+@@ -1285,7 +1260,6 @@ static ssize_t show_no_turbo(struct kobject *kobj,
+ return -EAGAIN;
+ }
+
+- update_turbo_state();
+ if (global.turbo_disabled)
+ ret = sprintf(buf, "%u\n", global.turbo_disabled);
+ else
+@@ -1315,7 +1289,6 @@ static ssize_t store_no_turbo(struct kobject *a, struct kobj_attribute *b,
+
+ mutex_lock(&intel_pstate_limits_lock);
+
+- update_turbo_state();
+ if (global.turbo_disabled) {
+ pr_notice_once("Turbo disabled by BIOS or unavailable on processor\n");
+ mutex_unlock(&intel_pstate_limits_lock);
+@@ -2296,8 +2269,6 @@ static void intel_pstate_adjust_pstate(struct cpudata *cpu)
+ struct sample *sample;
+ int target_pstate;
+
+- update_turbo_state();
+-
+ target_pstate = get_target_pstate(cpu);
+ target_pstate = intel_pstate_prepare_request(cpu, target_pstate);
+ trace_cpu_frequency(target_pstate * cpu->pstate.scaling, cpu->cpu);
+@@ -2607,7 +2578,6 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
+ * be invoked on them.
+ */
+ intel_pstate_clear_update_util_hook(policy->cpu);
+- update_turbo_state();
+ intel_pstate_set_pstate(cpu, pstate);
+ } else {
+ intel_pstate_set_update_util_hook(policy->cpu);
+@@ -2651,7 +2621,6 @@ static void intel_pstate_verify_cpu_policy(struct cpudata *cpu,
+ {
+ int max_freq;
+
+- update_turbo_state();
+ if (hwp_active) {
+ intel_pstate_get_hwp_cap(cpu);
+ max_freq = global.no_turbo || global.turbo_disabled ?
+@@ -2748,8 +2717,6 @@ static int __intel_pstate_cpu_init(struct cpufreq_policy *policy)
+
+ /* cpuinfo and default policy values */
+ policy->cpuinfo.min_freq = cpu->pstate.min_freq;
+- update_turbo_state();
+- global.turbo_disabled_mf = global.turbo_disabled;
+ policy->cpuinfo.max_freq = global.turbo_disabled ?
+ cpu->pstate.max_freq : cpu->pstate.turbo_freq;
+
+@@ -2915,8 +2882,6 @@ static int intel_cpufreq_target(struct cpufreq_policy *policy,
+ struct cpufreq_freqs freqs;
+ int target_pstate;
+
+- update_turbo_state();
+-
+ freqs.old = policy->cur;
+ freqs.new = target_freq;
+
+@@ -2938,8 +2903,6 @@ static unsigned int intel_cpufreq_fast_switch(struct cpufreq_policy *policy,
+ struct cpudata *cpu = all_cpu_data[policy->cpu];
+ int target_pstate;
+
+- update_turbo_state();
+-
+ target_pstate = intel_pstate_freq_to_hwp(cpu, target_freq);
+
+ target_pstate = intel_cpufreq_update_pstate(policy, target_pstate, true);
+@@ -2957,7 +2920,6 @@ static void intel_cpufreq_adjust_perf(unsigned int cpunum,
+ int old_pstate = cpu->pstate.current_pstate;
+ int cap_pstate, min_pstate, max_pstate, target_pstate;
+
+- update_turbo_state();
+ cap_pstate = global.turbo_disabled ? HWP_GUARANTEED_PERF(hwp_cap) :
+ HWP_HIGHEST_PERF(hwp_cap);
+
+@@ -3147,6 +3109,9 @@ static int intel_pstate_register_driver(struct cpufreq_driver *driver)
+
+ memset(&global, 0, sizeof(global));
+ global.max_perf_pct = 100;
++ global.turbo_disabled = turbo_is_disabled();
++
++ arch_set_max_freq_ratio(global.turbo_disabled);
+
+ intel_pstate_driver = driver;
+ ret = cpufreq_register_driver(intel_pstate_driver);
+--
+2.39.5
+
--- /dev/null
+From dc370f49bc51fd5519a1e4805969faf0fc904cdf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 25 Mar 2024 18:01:58 +0100
+Subject: cpufreq: intel_pstate: Fold intel_pstate_max_within_limits() into
+ caller
+
+From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+[ Upstream commit 032c5565eb80edb6f2faeb31939540c897987119 ]
+
+Fold intel_pstate_max_within_limits() into its only caller.
+
+No functional impact.
+
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+Stable-dep-of: ac4e04d9e378 ("cpufreq: intel_pstate: Unchecked MSR aceess in legacy mode")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/cpufreq/intel_pstate.c | 13 ++++---------
+ 1 file changed, 4 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
+index 7cb35842f68a1..b69bff009e780 100644
+--- a/drivers/cpufreq/intel_pstate.c
++++ b/drivers/cpufreq/intel_pstate.c
+@@ -2027,14 +2027,6 @@ static void intel_pstate_set_min_pstate(struct cpudata *cpu)
+ intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate);
+ }
+
+-static void intel_pstate_max_within_limits(struct cpudata *cpu)
+-{
+- int pstate = max(cpu->pstate.min_pstate, cpu->max_perf_ratio);
+-
+- update_turbo_state();
+- intel_pstate_set_pstate(cpu, pstate);
+-}
+-
+ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
+ {
+ int perf_ctl_max_phys = pstate_funcs.get_max_physical(cpu->cpu);
+@@ -2608,12 +2600,15 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
+ intel_pstate_update_perf_limits(cpu, policy->min, policy->max);
+
+ if (cpu->policy == CPUFREQ_POLICY_PERFORMANCE) {
++ int pstate = max(cpu->pstate.min_pstate, cpu->max_perf_ratio);
++
+ /*
+ * NOHZ_FULL CPUs need this as the governor callback may not
+ * be invoked on them.
+ */
+ intel_pstate_clear_update_util_hook(policy->cpu);
+- intel_pstate_max_within_limits(cpu);
++ update_turbo_state();
++ intel_pstate_set_pstate(cpu, pstate);
+ } else {
+ intel_pstate_set_update_util_hook(policy->cpu);
+ }
+--
+2.39.5
+
--- /dev/null
+From 0613992e81ad391f9dc4473a79b0ce9781d39249 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 7 Sep 2023 11:02:07 -0700
+Subject: cpufreq: intel_pstate: Revise global turbo disable check
+
+From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+
+[ Upstream commit 37b6ddba967c601479bea418a7ac6ff16b6232b7 ]
+
+Setting global turbo flag based on CPU 0 P-state limits is problematic
+as it limits max P-state request on every CPU on the system just based
+on its P-state limits.
+
+There are two cases in which global.turbo_disabled flag is set:
+- When the MSR_IA32_MISC_ENABLE_TURBO_DISABLE bit is set to 1
+in the MSR MSR_IA32_MISC_ENABLE. This bit can be only changed by
+the system BIOS before power up.
+- When the max non turbo P-state is same as max turbo P-state for CPU 0.
+
+The second check is not a valid to decide global turbo state based on
+the CPU 0. CPU 0 max turbo P-state can be same as max non turbo P-state,
+but for other CPUs this may not be true.
+
+There is no guarantee that max P-state limits are same for every CPU. This
+is possible that during fusing max P-state for a CPU is constrained. Also
+with the Intel Speed Select performance profile, CPU 0 may not be present
+in all profiles. In this case the max non turbo and turbo P-state can be
+set to the lowest possible P-state by the hardware when switched to
+such profile. Since max non turbo and turbo P-state is same,
+global.turbo_disabled flag will be set.
+
+Once global.turbo_disabled is set, any scaling max and min frequency
+update for any CPU will result in its max P-state constrained to the max
+non turbo P-state.
+
+Hence remove the check of max non turbo P-state equal to max turbo P-state
+of CPU 0 to set global turbo disabled flag.
+
+Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+[ rjw: Subject edit ]
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Stable-dep-of: ac4e04d9e378 ("cpufreq: intel_pstate: Unchecked MSR aceess in legacy mode")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/cpufreq/intel_pstate.c | 6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
+index 8a4fdf212ce0d..7cb35842f68a1 100644
+--- a/drivers/cpufreq/intel_pstate.c
++++ b/drivers/cpufreq/intel_pstate.c
+@@ -595,13 +595,9 @@ static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu)
+ static inline void update_turbo_state(void)
+ {
+ u64 misc_en;
+- struct cpudata *cpu;
+
+- cpu = all_cpu_data[0];
+ rdmsrl(MSR_IA32_MISC_ENABLE, misc_en);
+- global.turbo_disabled =
+- (misc_en & MSR_IA32_MISC_ENABLE_TURBO_DISABLE ||
+- cpu->pstate.max_pstate == cpu->pstate.turbo_pstate);
++ global.turbo_disabled = misc_en & MSR_IA32_MISC_ENABLE_TURBO_DISABLE;
+ }
+
+ static int min_perf_pct_min(void)
+--
+2.39.5
+
--- /dev/null
+From bef81dac54cd5941e5e251289beb60e386ac0c46 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 29 Apr 2025 14:07:11 -0700
+Subject: cpufreq: intel_pstate: Unchecked MSR aceess in legacy mode
+
+From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+
+[ Upstream commit ac4e04d9e378f5aa826c2406ad7871ae1b6a6fb9 ]
+
+When turbo mode is unavailable on a Skylake-X system, executing the
+command:
+
+ # echo 1 > /sys/devices/system/cpu/intel_pstate/no_turbo
+
+results in an unchecked MSR access error:
+
+ WRMSR to 0x199 (attempted to write 0x0000000100001300).
+
+This issue was reproduced on an OEM (Original Equipment Manufacturer)
+system and is not a common problem across all Skylake-X systems.
+
+This error occurs because the MSR 0x199 Turbo Engage Bit (bit 32) is set
+when turbo mode is disabled. The issue arises when intel_pstate fails to
+detect that turbo mode is disabled. Here intel_pstate relies on
+MSR_IA32_MISC_ENABLE bit 38 to determine the status of turbo mode.
+However, on this system, bit 38 is not set even when turbo mode is
+disabled.
+
+According to the Intel Software Developer's Manual (SDM), the BIOS sets
+this bit during platform initialization to enable or disable
+opportunistic processor performance operations. Logically, this bit
+should be set in such cases. However, the SDM also specifies that "OS
+and applications must use CPUID leaf 06H to detect processors with
+opportunistic processor performance operations enabled."
+
+Therefore, in addition to checking MSR_IA32_MISC_ENABLE bit 38, verify
+that CPUID.06H:EAX[1] is 0 to accurately determine if turbo mode is
+disabled.
+
+Fixes: 4521e1a0ce17 ("cpufreq: intel_pstate: Reflect current no_turbo state correctly")
+Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+Cc: All applicable <stable@vger.kernel.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/cpufreq/intel_pstate.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
+index 255746c053b4c..a6582fb846078 100644
+--- a/drivers/cpufreq/intel_pstate.c
++++ b/drivers/cpufreq/intel_pstate.c
+@@ -594,6 +594,9 @@ static bool turbo_is_disabled(void)
+ {
+ u64 misc_en;
+
++ if (!cpu_feature_enabled(X86_FEATURE_IDA))
++ return true;
++
+ rdmsrl(MSR_IA32_MISC_ENABLE, misc_en);
+
+ return !!(misc_en & MSR_IA32_MISC_ENABLE_TURBO_DISABLE);
+--
+2.39.5
+
--- /dev/null
+From 27977bb1ae024cdd597740e261fa5027fccd8442 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 10:49:30 -0800
+Subject: drivers: base: handle module_kobject creation
+
+From: Shyam Saini <shyamsaini@linux.microsoft.com>
+
+[ Upstream commit f95bbfe18512c5c018720468959edac056a17196 ]
+
+module_add_driver() relies on module_kset list for
+/sys/module/<built-in-module>/drivers directory creation.
+
+Since,
+commit 96a1a2412acba ("kernel/params.c: defer most of param_sysfs_init() to late_initcall time")
+drivers which are initialized from subsys_initcall() or any other
+higher precedence initcall couldn't find the related kobject entry
+in the module_kset list because module_kset is not fully populated
+by the time module_add_driver() refers it. As a consequence,
+module_add_driver() returns early without calling make_driver_name().
+Therefore, /sys/module/<built-in-module>/drivers is never created.
+
+Fix this issue by letting module_add_driver() handle module_kobject
+creation itself.
+
+Fixes: 96a1a2412acb ("kernel/params.c: defer most of param_sysfs_init() to late_initcall time")
+Cc: stable@vger.kernel.org # requires all other patches from the series
+Suggested-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
+Signed-off-by: Shyam Saini <shyamsaini@linux.microsoft.com>
+Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Link: https://lore.kernel.org/r/20250227184930.34163-5-shyamsaini@linux.microsoft.com
+Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/base/module.c | 13 +++++--------
+ 1 file changed, 5 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/base/module.c b/drivers/base/module.c
+index a33663d92256d..955582b34e54a 100644
+--- a/drivers/base/module.c
++++ b/drivers/base/module.c
+@@ -42,16 +42,13 @@ int module_add_driver(struct module *mod, struct device_driver *drv)
+ if (mod)
+ mk = &mod->mkobj;
+ else if (drv->mod_name) {
+- struct kobject *mkobj;
+-
+- /* Lookup built-in module entry in /sys/modules */
+- mkobj = kset_find_obj(module_kset, drv->mod_name);
+- if (mkobj) {
+- mk = container_of(mkobj, struct module_kobject, kobj);
++ /* Lookup or create built-in module entry in /sys/modules */
++ mk = lookup_or_create_module_kobject(drv->mod_name);
++ if (mk) {
+ /* remember our module structure */
+ drv->p->mkobj = mk;
+- /* kset_find_obj took a reference */
+- kobject_put(mkobj);
++ /* lookup_or_create_module_kobject took a reference */
++ kobject_put(&mk->kobj);
+ }
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 498e1b5a4218c165a5dc6f52c479bf59d6ae8705 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Feb 2025 13:30:01 -0600
+Subject: drm/amd/display: Add scoped mutexes for amdgpu_dm_dhcp
+
+From: Mario Limonciello <mario.limonciello@amd.com>
+
+[ Upstream commit 6b675ab8efbf2bcee25be29e865455c56e246401 ]
+
+[Why]
+Guards automatically release mutex when it goes out of scope making
+code easier to follow.
+
+[How]
+Replace all use of mutex_lock()/mutex_unlock() with guard(mutex).
+
+Reviewed-by: Alex Hung <alex.hung@amd.com>
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Tom Chung <chiahsuan.chung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Stable-dep-of: be593d9d91c5 ("drm/amd/display: Fix slab-use-after-free in hdcp")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../amd/display/amdgpu_dm/amdgpu_dm_hdcp.c | 37 +++++--------------
+ 1 file changed, 10 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
+index 2ad9f900a8574..4330d37022fa3 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
+@@ -172,7 +172,7 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
+ struct mod_hdcp_display_adjustment display_adjust;
+ unsigned int conn_index = aconnector->base.index;
+
+- mutex_lock(&hdcp_w->mutex);
++ guard(mutex)(&hdcp_w->mutex);
+ hdcp_w->aconnector[conn_index] = aconnector;
+
+ memset(&link_adjust, 0, sizeof(link_adjust));
+@@ -209,7 +209,6 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
+ mod_hdcp_update_display(&hdcp_w->hdcp, conn_index, &link_adjust, &display_adjust, &hdcp_w->output);
+
+ process_output(hdcp_w);
+- mutex_unlock(&hdcp_w->mutex);
+ }
+
+ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
+@@ -220,7 +219,7 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
+ struct drm_connector_state *conn_state = aconnector->base.state;
+ unsigned int conn_index = aconnector->base.index;
+
+- mutex_lock(&hdcp_w->mutex);
++ guard(mutex)(&hdcp_w->mutex);
+ hdcp_w->aconnector[conn_index] = aconnector;
+
+ /* the removal of display will invoke auth reset -> hdcp destroy and
+@@ -239,7 +238,6 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
+ mod_hdcp_remove_display(&hdcp_w->hdcp, aconnector->base.index, &hdcp_w->output);
+
+ process_output(hdcp_w);
+- mutex_unlock(&hdcp_w->mutex);
+ }
+
+ void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index)
+@@ -247,7 +245,7 @@ void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_inde
+ struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
+ unsigned int conn_index;
+
+- mutex_lock(&hdcp_w->mutex);
++ guard(mutex)(&hdcp_w->mutex);
+
+ mod_hdcp_reset_connection(&hdcp_w->hdcp, &hdcp_w->output);
+
+@@ -259,8 +257,6 @@ void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_inde
+ }
+
+ process_output(hdcp_w);
+-
+- mutex_unlock(&hdcp_w->mutex);
+ }
+
+ void hdcp_handle_cpirq(struct hdcp_workqueue *hdcp_work, unsigned int link_index)
+@@ -277,7 +273,7 @@ static void event_callback(struct work_struct *work)
+ hdcp_work = container_of(to_delayed_work(work), struct hdcp_workqueue,
+ callback_dwork);
+
+- mutex_lock(&hdcp_work->mutex);
++ guard(mutex)(&hdcp_work->mutex);
+
+ cancel_delayed_work(&hdcp_work->callback_dwork);
+
+@@ -285,8 +281,6 @@ static void event_callback(struct work_struct *work)
+ &hdcp_work->output);
+
+ process_output(hdcp_work);
+-
+- mutex_unlock(&hdcp_work->mutex);
+ }
+
+ static void event_property_update(struct work_struct *work)
+@@ -323,7 +317,7 @@ static void event_property_update(struct work_struct *work)
+ continue;
+
+ drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+- mutex_lock(&hdcp_work->mutex);
++ guard(mutex)(&hdcp_work->mutex);
+
+ if (conn_state->commit) {
+ ret = wait_for_completion_interruptible_timeout(&conn_state->commit->hw_done,
+@@ -355,7 +349,6 @@ static void event_property_update(struct work_struct *work)
+ drm_hdcp_update_content_protection(connector,
+ DRM_MODE_CONTENT_PROTECTION_DESIRED);
+ }
+- mutex_unlock(&hdcp_work->mutex);
+ drm_modeset_unlock(&dev->mode_config.connection_mutex);
+ }
+ }
+@@ -368,7 +361,7 @@ static void event_property_validate(struct work_struct *work)
+ struct amdgpu_dm_connector *aconnector;
+ unsigned int conn_index;
+
+- mutex_lock(&hdcp_work->mutex);
++ guard(mutex)(&hdcp_work->mutex);
+
+ for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX;
+ conn_index++) {
+@@ -408,8 +401,6 @@ static void event_property_validate(struct work_struct *work)
+ schedule_work(&hdcp_work->property_update_work);
+ }
+ }
+-
+- mutex_unlock(&hdcp_work->mutex);
+ }
+
+ static void event_watchdog_timer(struct work_struct *work)
+@@ -420,7 +411,7 @@ static void event_watchdog_timer(struct work_struct *work)
+ struct hdcp_workqueue,
+ watchdog_timer_dwork);
+
+- mutex_lock(&hdcp_work->mutex);
++ guard(mutex)(&hdcp_work->mutex);
+
+ cancel_delayed_work(&hdcp_work->watchdog_timer_dwork);
+
+@@ -429,8 +420,6 @@ static void event_watchdog_timer(struct work_struct *work)
+ &hdcp_work->output);
+
+ process_output(hdcp_work);
+-
+- mutex_unlock(&hdcp_work->mutex);
+ }
+
+ static void event_cpirq(struct work_struct *work)
+@@ -439,13 +428,11 @@ static void event_cpirq(struct work_struct *work)
+
+ hdcp_work = container_of(work, struct hdcp_workqueue, cpirq_work);
+
+- mutex_lock(&hdcp_work->mutex);
++ guard(mutex)(&hdcp_work->mutex);
+
+ mod_hdcp_process_event(&hdcp_work->hdcp, MOD_HDCP_EVENT_CPIRQ, &hdcp_work->output);
+
+ process_output(hdcp_work);
+-
+- mutex_unlock(&hdcp_work->mutex);
+ }
+
+ void hdcp_destroy(struct kobject *kobj, struct hdcp_workqueue *hdcp_work)
+@@ -479,7 +466,7 @@ static bool enable_assr(void *handle, struct dc_link *link)
+
+ dtm_cmd = (struct ta_dtm_shared_memory *)psp->dtm_context.context.mem_context.shared_buf;
+
+- mutex_lock(&psp->dtm_context.mutex);
++ guard(mutex)(&psp->dtm_context.mutex);
+ memset(dtm_cmd, 0, sizeof(struct ta_dtm_shared_memory));
+
+ dtm_cmd->cmd_id = TA_DTM_COMMAND__TOPOLOGY_ASSR_ENABLE;
+@@ -494,8 +481,6 @@ static bool enable_assr(void *handle, struct dc_link *link)
+ res = false;
+ }
+
+- mutex_unlock(&psp->dtm_context.mutex);
+-
+ return res;
+ }
+
+@@ -557,13 +542,11 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
+ (!!aconnector->base.state) ?
+ aconnector->base.state->hdcp_content_type : -1);
+
+- mutex_lock(&hdcp_w->mutex);
++ guard(mutex)(&hdcp_w->mutex);
+
+ mod_hdcp_add_display(&hdcp_w->hdcp, link, display, &hdcp_w->output);
+
+ process_output(hdcp_w);
+- mutex_unlock(&hdcp_w->mutex);
+-
+ }
+
+ /**
+--
+2.39.5
+
--- /dev/null
+From 93a1cd6ca20e9d8a9cbf55c01d06a20bd878e599 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 17 Apr 2025 16:50:05 -0500
+Subject: drm/amd/display: Fix slab-use-after-free in hdcp
+
+From: Chris Bainbridge <chris.bainbridge@gmail.com>
+
+[ Upstream commit be593d9d91c5a3a363d456b9aceb71029aeb3f1d ]
+
+The HDCP code in amdgpu_dm_hdcp.c copies pointers to amdgpu_dm_connector
+objects without incrementing the kref reference counts. When using a
+USB-C dock, and the dock is unplugged, the corresponding
+amdgpu_dm_connector objects are freed, creating dangling pointers in the
+HDCP code. When the dock is plugged back, the dangling pointers are
+dereferenced, resulting in a slab-use-after-free:
+
+[ 66.775837] BUG: KASAN: slab-use-after-free in event_property_validate+0x42f/0x6c0 [amdgpu]
+[ 66.776171] Read of size 4 at addr ffff888127804120 by task kworker/0:1/10
+
+[ 66.776179] CPU: 0 UID: 0 PID: 10 Comm: kworker/0:1 Not tainted 6.14.0-rc7-00180-g54505f727a38-dirty #233
+[ 66.776183] Hardware name: HP HP Pavilion Aero Laptop 13-be0xxx/8916, BIOS F.17 12/18/2024
+[ 66.776186] Workqueue: events event_property_validate [amdgpu]
+[ 66.776494] Call Trace:
+[ 66.776496] <TASK>
+[ 66.776497] dump_stack_lvl+0x70/0xa0
+[ 66.776504] print_report+0x175/0x555
+[ 66.776507] ? __virt_addr_valid+0x243/0x450
+[ 66.776510] ? kasan_complete_mode_report_info+0x66/0x1c0
+[ 66.776515] kasan_report+0xeb/0x1c0
+[ 66.776518] ? event_property_validate+0x42f/0x6c0 [amdgpu]
+[ 66.776819] ? event_property_validate+0x42f/0x6c0 [amdgpu]
+[ 66.777121] __asan_report_load4_noabort+0x14/0x20
+[ 66.777124] event_property_validate+0x42f/0x6c0 [amdgpu]
+[ 66.777342] ? __lock_acquire+0x6b40/0x6b40
+[ 66.777347] ? enable_assr+0x250/0x250 [amdgpu]
+[ 66.777571] process_one_work+0x86b/0x1510
+[ 66.777575] ? pwq_dec_nr_in_flight+0xcf0/0xcf0
+[ 66.777578] ? assign_work+0x16b/0x280
+[ 66.777580] ? lock_is_held_type+0xa3/0x130
+[ 66.777583] worker_thread+0x5c0/0xfa0
+[ 66.777587] ? process_one_work+0x1510/0x1510
+[ 66.777588] kthread+0x3a2/0x840
+[ 66.777591] ? kthread_is_per_cpu+0xd0/0xd0
+[ 66.777594] ? trace_hardirqs_on+0x4f/0x60
+[ 66.777597] ? _raw_spin_unlock_irq+0x27/0x60
+[ 66.777599] ? calculate_sigpending+0x77/0xa0
+[ 66.777602] ? kthread_is_per_cpu+0xd0/0xd0
+[ 66.777605] ret_from_fork+0x40/0x90
+[ 66.777607] ? kthread_is_per_cpu+0xd0/0xd0
+[ 66.777609] ret_from_fork_asm+0x11/0x20
+[ 66.777614] </TASK>
+
+[ 66.777643] Allocated by task 10:
+[ 66.777646] kasan_save_stack+0x39/0x60
+[ 66.777649] kasan_save_track+0x14/0x40
+[ 66.777652] kasan_save_alloc_info+0x37/0x50
+[ 66.777655] __kasan_kmalloc+0xbb/0xc0
+[ 66.777658] __kmalloc_cache_noprof+0x1c8/0x4b0
+[ 66.777661] dm_dp_add_mst_connector+0xdd/0x5c0 [amdgpu]
+[ 66.777880] drm_dp_mst_port_add_connector+0x47e/0x770 [drm_display_helper]
+[ 66.777892] drm_dp_send_link_address+0x1554/0x2bf0 [drm_display_helper]
+[ 66.777901] drm_dp_check_and_send_link_address+0x187/0x1f0 [drm_display_helper]
+[ 66.777909] drm_dp_mst_link_probe_work+0x2b8/0x410 [drm_display_helper]
+[ 66.777917] process_one_work+0x86b/0x1510
+[ 66.777919] worker_thread+0x5c0/0xfa0
+[ 66.777922] kthread+0x3a2/0x840
+[ 66.777925] ret_from_fork+0x40/0x90
+[ 66.777927] ret_from_fork_asm+0x11/0x20
+
+[ 66.777932] Freed by task 1713:
+[ 66.777935] kasan_save_stack+0x39/0x60
+[ 66.777938] kasan_save_track+0x14/0x40
+[ 66.777940] kasan_save_free_info+0x3b/0x60
+[ 66.777944] __kasan_slab_free+0x52/0x70
+[ 66.777946] kfree+0x13f/0x4b0
+[ 66.777949] dm_dp_mst_connector_destroy+0xfa/0x150 [amdgpu]
+[ 66.778179] drm_connector_free+0x7d/0xb0
+[ 66.778184] drm_mode_object_put.part.0+0xee/0x160
+[ 66.778188] drm_mode_object_put+0x37/0x50
+[ 66.778191] drm_atomic_state_default_clear+0x220/0xd60
+[ 66.778194] __drm_atomic_state_free+0x16e/0x2a0
+[ 66.778197] drm_mode_atomic_ioctl+0x15ed/0x2ba0
+[ 66.778200] drm_ioctl_kernel+0x17a/0x310
+[ 66.778203] drm_ioctl+0x584/0xd10
+[ 66.778206] amdgpu_drm_ioctl+0xd2/0x1c0 [amdgpu]
+[ 66.778375] __x64_sys_ioctl+0x139/0x1a0
+[ 66.778378] x64_sys_call+0xee7/0xfb0
+[ 66.778381] do_syscall_64+0x87/0x140
+[ 66.778385] entry_SYSCALL_64_after_hwframe+0x4b/0x53
+
+Fix this by properly incrementing and decrementing the reference counts
+when making and deleting copies of the amdgpu_dm_connector pointers.
+
+(Mario: rebase on current code and update fixes tag)
+
+Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4006
+Signed-off-by: Chris Bainbridge <chris.bainbridge@gmail.com>
+Fixes: da3fd7ac0bcf3 ("drm/amd/display: Update CP property based on HW query")
+Reviewed-by: Alex Hung <alex.hung@amd.com>
+Link: https://lore.kernel.org/r/20250417215005.37964-1-mario.limonciello@amd.com
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit d4673f3c3b3dcb74e36e53cdfc880baa7a87b330)
+Cc: stable@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../amd/display/amdgpu_dm/amdgpu_dm_hdcp.c | 19 ++++++++++++++++---
+ 1 file changed, 16 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
+index 4330d37022fa3..a048022d9865a 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
+@@ -173,6 +173,9 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
+ unsigned int conn_index = aconnector->base.index;
+
+ guard(mutex)(&hdcp_w->mutex);
++ drm_connector_get(&aconnector->base);
++ if (hdcp_w->aconnector[conn_index])
++ drm_connector_put(&hdcp_w->aconnector[conn_index]->base);
+ hdcp_w->aconnector[conn_index] = aconnector;
+
+ memset(&link_adjust, 0, sizeof(link_adjust));
+@@ -220,7 +223,6 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
+ unsigned int conn_index = aconnector->base.index;
+
+ guard(mutex)(&hdcp_w->mutex);
+- hdcp_w->aconnector[conn_index] = aconnector;
+
+ /* the removal of display will invoke auth reset -> hdcp destroy and
+ * we'd expect the Content Protection (CP) property changed back to
+@@ -236,7 +238,10 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
+ }
+
+ mod_hdcp_remove_display(&hdcp_w->hdcp, aconnector->base.index, &hdcp_w->output);
+-
++ if (hdcp_w->aconnector[conn_index]) {
++ drm_connector_put(&hdcp_w->aconnector[conn_index]->base);
++ hdcp_w->aconnector[conn_index] = NULL;
++ }
+ process_output(hdcp_w);
+ }
+
+@@ -254,6 +259,10 @@ void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_inde
+ for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX; conn_index++) {
+ hdcp_w->encryption_status[conn_index] =
+ MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
++ if (hdcp_w->aconnector[conn_index]) {
++ drm_connector_put(&hdcp_w->aconnector[conn_index]->base);
++ hdcp_w->aconnector[conn_index] = NULL;
++ }
+ }
+
+ process_output(hdcp_w);
+@@ -489,6 +498,7 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
+ struct hdcp_workqueue *hdcp_work = handle;
+ struct amdgpu_dm_connector *aconnector = config->dm_stream_ctx;
+ int link_index = aconnector->dc_link->link_index;
++ unsigned int conn_index = aconnector->base.index;
+ struct mod_hdcp_display *display = &hdcp_work[link_index].display;
+ struct mod_hdcp_link *link = &hdcp_work[link_index].link;
+ struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
+@@ -545,7 +555,10 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
+ guard(mutex)(&hdcp_w->mutex);
+
+ mod_hdcp_add_display(&hdcp_w->hdcp, link, display, &hdcp_w->output);
+-
++ drm_connector_get(&aconnector->base);
++ if (hdcp_w->aconnector[conn_index])
++ drm_connector_put(&hdcp_w->aconnector[conn_index]->base);
++ hdcp_w->aconnector[conn_index] = aconnector;
+ process_output(hdcp_w);
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 3144d01904d30ea08a72567b68ae3d3ea80e9855 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Mar 2025 11:57:00 +0000
+Subject: firmware: arm_ffa: Skip Rx buffer ownership release if not acquired
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Sudeep Holla <sudeep.holla@arm.com>
+
+[ Upstream commit 4567bdaaaaa1744da3d7da07d9aca2f941f5b4e5 ]
+
+Completion of the FFA_PARTITION_INFO_GET ABI transfers the ownership of
+the caller’s Rx buffer from the producer(typically partition mnager) to
+the consumer(this driver/OS). FFA_RX_RELEASE transfers the ownership
+from the consumer back to the producer.
+
+However, when we set the flag to just return the count of partitions
+deployed in the system corresponding to the specified UUID while
+invoking FFA_PARTITION_INFO_GET, the Rx buffer ownership shouldn't be
+transferred to this driver. We must be able to skip transferring back
+the ownership to the partition manager when we request just to get the
+count of the partitions as the buffers are not acquired in this case.
+
+Firmware may return FFA_RET_DENIED or other error for the ffa_rx_release()
+in such cases.
+
+Fixes: bb1be7498500 ("firmware: arm_ffa: Add v1.1 get_partition_info support")
+Message-Id: <20250321115700.3525197-1-sudeep.holla@arm.com>
+Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/firmware/arm_ffa/driver.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
+index 7cd6b1564e801..7c2db3f017651 100644
+--- a/drivers/firmware/arm_ffa/driver.c
++++ b/drivers/firmware/arm_ffa/driver.c
+@@ -225,7 +225,8 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
+ memcpy(buffer + idx, drv_info->rx_buffer + idx * sz,
+ buf_sz);
+
+- ffa_rx_release();
++ if (!(flags & PARTITION_INFO_GET_RETURN_COUNT_ONLY))
++ ffa_rx_release();
+
+ mutex_unlock(&drv_info->rx_lock);
+
+--
+2.39.5
+
--- /dev/null
+From 6e7a60324564d3d7d359dce0b8eef74161449426 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Mar 2025 18:54:47 +0000
+Subject: firmware: arm_scmi: Balance device refcount when destroying devices
+
+From: Cristian Marussi <cristian.marussi@arm.com>
+
+[ Upstream commit 9ca67840c0ddf3f39407339624cef824a4f27599 ]
+
+Using device_find_child() to lookup the proper SCMI device to destroy
+causes an unbalance in device refcount, since device_find_child() calls an
+implicit get_device(): this, in turns, inhibits the call of the provided
+release methods upon devices destruction.
+
+As a consequence, one of the structures that is not freed properly upon
+destruction is the internal struct device_private dev->p populated by the
+drivers subsystem core.
+
+KMemleak detects this situation since loading/unloding some SCMI driver
+causes related devices to be created/destroyed without calling any
+device_release method.
+
+unreferenced object 0xffff00000f583800 (size 512):
+ comm "insmod", pid 227, jiffies 4294912190
+ hex dump (first 32 bytes):
+ 00 00 00 00 ad 4e ad de ff ff ff ff 00 00 00 00 .....N..........
+ ff ff ff ff ff ff ff ff 60 36 1d 8a 00 80 ff ff ........`6......
+ backtrace (crc 114e2eed):
+ kmemleak_alloc+0xbc/0xd8
+ __kmalloc_cache_noprof+0x2dc/0x398
+ device_add+0x954/0x12d0
+ device_register+0x28/0x40
+ __scmi_device_create.part.0+0x1bc/0x380
+ scmi_device_create+0x2d0/0x390
+ scmi_create_protocol_devices+0x74/0xf8
+ scmi_device_request_notifier+0x1f8/0x2a8
+ notifier_call_chain+0x110/0x3b0
+ blocking_notifier_call_chain+0x70/0xb0
+ scmi_driver_register+0x350/0x7f0
+ 0xffff80000a3b3038
+ do_one_initcall+0x12c/0x730
+ do_init_module+0x1dc/0x640
+ load_module+0x4b20/0x5b70
+ init_module_from_file+0xec/0x158
+
+$ ./scripts/faddr2line ./vmlinux device_add+0x954/0x12d0
+device_add+0x954/0x12d0:
+kmalloc_noprof at include/linux/slab.h:901
+(inlined by) kzalloc_noprof at include/linux/slab.h:1037
+(inlined by) device_private_init at drivers/base/core.c:3510
+(inlined by) device_add at drivers/base/core.c:3561
+
+Balance device refcount by issuing a put_device() on devices found via
+device_find_child().
+
+Reported-by: Alice Ryhl <aliceryhl@google.com>
+Closes: https://lore.kernel.org/linux-arm-kernel/Z8nK3uFkspy61yjP@arm.com/T/#mc1f73a0ea5e41014fa145147b7b839fc988ada8f
+CC: Sudeep Holla <sudeep.holla@arm.com>
+CC: Catalin Marinas <catalin.marinas@arm.com>
+Fixes: d4f9dddd21f3 ("firmware: arm_scmi: Add dynamic scmi devices creation")
+Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
+Tested-by: Alice Ryhl <aliceryhl@google.com>
+Message-Id: <20250306185447.2039336-1-cristian.marussi@arm.com>
+Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/firmware/arm_scmi/bus.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c
+index dcf774d3edfe4..51eeaf14367da 100644
+--- a/drivers/firmware/arm_scmi/bus.c
++++ b/drivers/firmware/arm_scmi/bus.c
+@@ -240,6 +240,9 @@ static struct scmi_device *scmi_child_dev_find(struct device *parent,
+ if (!dev)
+ return NULL;
+
++ /* Drop the refcnt bumped implicitly by device_find_child */
++ put_device(dev);
++
+ return to_scmi_dev(dev);
+ }
+
+--
+2.39.5
+
--- /dev/null
+From dfcd5bb06d22f9dbfb4679b5cb6fc688aec9f7fb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 15 Apr 2025 11:56:20 -0700
+Subject: iommu/arm-smmu-v3: Fix iommu_device_probe bug due to duplicated
+ stream ids
+
+From: Nicolin Chen <nicolinc@nvidia.com>
+
+[ Upstream commit b00d24997a11c10d3e420614f0873b83ce358a34 ]
+
+ASPEED VGA card has two built-in devices:
+ 0008:06:00.0 PCI bridge: ASPEED Technology, Inc. AST1150 PCI-to-PCI Bridge (rev 06)
+ 0008:07:00.0 VGA compatible controller: ASPEED Technology, Inc. ASPEED Graphics Family (rev 52)
+
+Its toplogy looks like this:
+ +-[0008:00]---00.0-[01-09]--+-00.0-[02-09]--+-00.0-[03]----00.0 Sandisk Corp Device 5017
+ | +-01.0-[04]--
+ | +-02.0-[05]----00.0 NVIDIA Corporation Device
+ | +-03.0-[06-07]----00.0-[07]----00.0 ASPEED Technology, Inc. ASPEED Graphics Family
+ | +-04.0-[08]----00.0 Renesas Technology Corp. uPD720201 USB 3.0 Host Controller
+ | \-05.0-[09]----00.0 Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller
+ \-00.1 PMC-Sierra Inc. Device 4028
+
+The IORT logic populaties two identical IDs into the fwspec->ids array via
+DMA aliasing in iort_pci_iommu_init() called by pci_for_each_dma_alias().
+
+Though the SMMU driver had been able to handle this situation since commit
+563b5cbe334e ("iommu/arm-smmu-v3: Cope with duplicated Stream IDs"), that
+got broken by the later commit cdf315f907d4 ("iommu/arm-smmu-v3: Maintain
+a SID->device structure"), which ended up with allocating separate streams
+with the same stuffing.
+
+On a kernel prior to v6.15-rc1, there has been an overlooked warning:
+ pci 0008:07:00.0: vgaarb: setting as boot VGA device
+ pci 0008:07:00.0: vgaarb: bridge control possible
+ pci 0008:07:00.0: vgaarb: VGA device added: decodes=io+mem,owns=none,locks=none
+ pcieport 0008:06:00.0: Adding to iommu group 14
+ ast 0008:07:00.0: stream 67328 already in tree <===== WARNING
+ ast 0008:07:00.0: enabling device (0002 -> 0003)
+ ast 0008:07:00.0: Using default configuration
+ ast 0008:07:00.0: AST 2600 detected
+ ast 0008:07:00.0: [drm] Using analog VGA
+ ast 0008:07:00.0: [drm] dram MCLK=396 Mhz type=1 bus_width=16
+ [drm] Initialized ast 0.1.0 for 0008:07:00.0 on minor 0
+ ast 0008:07:00.0: [drm] fb0: astdrmfb frame buffer device
+
+With v6.15-rc, since the commit bcb81ac6ae3c ("iommu: Get DT/ACPI parsing
+into the proper probe path"), the error returned with the warning is moved
+to the SMMU device probe flow:
+ arm_smmu_probe_device+0x15c/0x4c0
+ __iommu_probe_device+0x150/0x4f8
+ probe_iommu_group+0x44/0x80
+ bus_for_each_dev+0x7c/0x100
+ bus_iommu_probe+0x48/0x1a8
+ iommu_device_register+0xb8/0x178
+ arm_smmu_device_probe+0x1350/0x1db0
+which then fails the entire SMMU driver probe:
+ pci 0008:06:00.0: Adding to iommu group 21
+ pci 0008:07:00.0: stream 67328 already in tree
+ arm-smmu-v3 arm-smmu-v3.9.auto: Failed to register iommu
+ arm-smmu-v3 arm-smmu-v3.9.auto: probe with driver arm-smmu-v3 failed with error -22
+
+Since SMMU driver had been already expecting a potential duplicated Stream
+ID in arm_smmu_install_ste_for_dev(), change the arm_smmu_insert_master()
+routine to ignore a duplicated ID from the fwspec->sids array as well.
+
+Note: this has been failing the iommu_device_probe() since 2021, although a
+recent iommu commit in v6.15-rc1 that moves iommu_device_probe() started to
+fail the SMMU driver probe. Since nobody has cared about DMA Alias support,
+leave that as it was but fix the fundamental iommu_device_probe() breakage.
+
+Fixes: cdf315f907d4 ("iommu/arm-smmu-v3: Maintain a SID->device structure")
+Cc: stable@vger.kernel.org
+Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
+Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
+Link: https://lore.kernel.org/r/20250415185620.504299-1-nicolinc@nvidia.com
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 19 +++++++++++++++----
+ 1 file changed, 15 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+index 2cab4798e7a0d..f2260f45728e7 100644
+--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
++++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+@@ -2597,6 +2597,7 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
+ mutex_lock(&smmu->streams_mutex);
+ for (i = 0; i < fwspec->num_ids; i++) {
+ struct arm_smmu_stream *new_stream = &master->streams[i];
++ struct rb_node *existing;
+ u32 sid = fwspec->ids[i];
+
+ new_stream->id = sid;
+@@ -2607,10 +2608,20 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
+ break;
+
+ /* Insert into SID tree */
+- if (rb_find_add(&new_stream->node, &smmu->streams,
+- arm_smmu_streams_cmp_node)) {
+- dev_warn(master->dev, "stream %u already in tree\n",
+- sid);
++ existing = rb_find_add(&new_stream->node, &smmu->streams,
++ arm_smmu_streams_cmp_node);
++ if (existing) {
++ struct arm_smmu_master *existing_master =
++ rb_entry(existing, struct arm_smmu_stream, node)
++ ->master;
++
++ /* Bridged PCI devices may end up with duplicated IDs */
++ if (existing_master == master)
++ continue;
++
++ dev_warn(master->dev,
++ "stream %u already in tree from dev %s\n", sid,
++ dev_name(existing_master->dev));
+ ret = -EINVAL;
+ break;
+ }
+--
+2.39.5
+
--- /dev/null
+From c4262534abca77f4b690a5597904715dc5d3b285 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 Aug 2024 20:31:15 -0300
+Subject: iommu/arm-smmu-v3: Use the new rb tree helpers
+
+From: Jason Gunthorpe <jgg@nvidia.com>
+
+[ Upstream commit a2bb820e862d61f9ca1499e500915f9f505a2655 ]
+
+Since v5.12 the rbtree has gained some simplifying helpers aimed at making
+rb tree users write less convoluted boiler plate code. Instead the caller
+provides a single comparison function and the helpers generate the prior
+open-coded stuff.
+
+Update smmu->streams to use rb_find_add() and rb_find().
+
+Tested-by: Nicolin Chen <nicolinc@nvidia.com>
+Reviewed-by: Mostafa Saleh <smostafa@google.com>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Link: https://lore.kernel.org/r/1-v3-9fef8cdc2ff6+150d1-smmuv3_tidy_jgg@nvidia.com
+Signed-off-by: Will Deacon <will@kernel.org>
+Stable-dep-of: b00d24997a11 ("iommu/arm-smmu-v3: Fix iommu_device_probe bug due to duplicated stream ids")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 68 ++++++++++-----------
+ 1 file changed, 31 insertions(+), 37 deletions(-)
+
+diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+index 6cecbac0e6bab..2cab4798e7a0d 100644
+--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
++++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+@@ -1443,26 +1443,37 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
+ return 0;
+ }
+
++static int arm_smmu_streams_cmp_key(const void *lhs, const struct rb_node *rhs)
++{
++ struct arm_smmu_stream *stream_rhs =
++ rb_entry(rhs, struct arm_smmu_stream, node);
++ const u32 *sid_lhs = lhs;
++
++ if (*sid_lhs < stream_rhs->id)
++ return -1;
++ if (*sid_lhs > stream_rhs->id)
++ return 1;
++ return 0;
++}
++
++static int arm_smmu_streams_cmp_node(struct rb_node *lhs,
++ const struct rb_node *rhs)
++{
++ return arm_smmu_streams_cmp_key(
++ &rb_entry(lhs, struct arm_smmu_stream, node)->id, rhs);
++}
++
+ static struct arm_smmu_master *
+ arm_smmu_find_master(struct arm_smmu_device *smmu, u32 sid)
+ {
+ struct rb_node *node;
+- struct arm_smmu_stream *stream;
+
+ lockdep_assert_held(&smmu->streams_mutex);
+
+- node = smmu->streams.rb_node;
+- while (node) {
+- stream = rb_entry(node, struct arm_smmu_stream, node);
+- if (stream->id < sid)
+- node = node->rb_right;
+- else if (stream->id > sid)
+- node = node->rb_left;
+- else
+- return stream->master;
+- }
+-
+- return NULL;
++ node = rb_find(&sid, &smmu->streams, arm_smmu_streams_cmp_key);
++ if (!node)
++ return NULL;
++ return rb_entry(node, struct arm_smmu_stream, node)->master;
+ }
+
+ /* IRQ and event handlers */
+@@ -2575,8 +2586,6 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
+ {
+ int i;
+ int ret = 0;
+- struct arm_smmu_stream *new_stream, *cur_stream;
+- struct rb_node **new_node, *parent_node = NULL;
+ struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(master->dev);
+
+ master->streams = kcalloc(fwspec->num_ids, sizeof(*master->streams),
+@@ -2587,9 +2596,9 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
+
+ mutex_lock(&smmu->streams_mutex);
+ for (i = 0; i < fwspec->num_ids; i++) {
++ struct arm_smmu_stream *new_stream = &master->streams[i];
+ u32 sid = fwspec->ids[i];
+
+- new_stream = &master->streams[i];
+ new_stream->id = sid;
+ new_stream->master = master;
+
+@@ -2598,28 +2607,13 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
+ break;
+
+ /* Insert into SID tree */
+- new_node = &(smmu->streams.rb_node);
+- while (*new_node) {
+- cur_stream = rb_entry(*new_node, struct arm_smmu_stream,
+- node);
+- parent_node = *new_node;
+- if (cur_stream->id > new_stream->id) {
+- new_node = &((*new_node)->rb_left);
+- } else if (cur_stream->id < new_stream->id) {
+- new_node = &((*new_node)->rb_right);
+- } else {
+- dev_warn(master->dev,
+- "stream %u already in tree\n",
+- cur_stream->id);
+- ret = -EINVAL;
+- break;
+- }
+- }
+- if (ret)
++ if (rb_find_add(&new_stream->node, &smmu->streams,
++ arm_smmu_streams_cmp_node)) {
++ dev_warn(master->dev, "stream %u already in tree\n",
++ sid);
++ ret = -EINVAL;
+ break;
+-
+- rb_link_node(&new_stream->node, parent_node, new_node);
+- rb_insert_color(&new_stream->node, &smmu->streams);
++ }
+ }
+
+ if (ret) {
+--
+2.39.5
+
--- /dev/null
+From 704526e4387c352ceabdb1aa0839cc92151f61b1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 10:49:29 -0800
+Subject: kernel: globalize lookup_or_create_module_kobject()
+
+From: Shyam Saini <shyamsaini@linux.microsoft.com>
+
+[ Upstream commit 7c76c813cfc42a7376378a0c4b7250db2eebab81 ]
+
+lookup_or_create_module_kobject() is marked as static and __init,
+to make it global drop static keyword.
+Since this function can be called from non-init code, use __modinit
+instead of __init, __modinit marker will make it __init if
+CONFIG_MODULES is not defined.
+
+Suggested-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
+Signed-off-by: Shyam Saini <shyamsaini@linux.microsoft.com>
+Link: https://lore.kernel.org/r/20250227184930.34163-4-shyamsaini@linux.microsoft.com
+Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
+Stable-dep-of: f95bbfe18512 ("drivers: base: handle module_kobject creation")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/module.h | 2 ++
+ kernel/params.c | 2 +-
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/include/linux/module.h b/include/linux/module.h
+index a98e188cf37b8..f2a8624eef1ec 100644
+--- a/include/linux/module.h
++++ b/include/linux/module.h
+@@ -162,6 +162,8 @@ extern void cleanup_module(void);
+ #define __INITRODATA_OR_MODULE __INITRODATA
+ #endif /*CONFIG_MODULES*/
+
++struct module_kobject *lookup_or_create_module_kobject(const char *name);
++
+ /* Generic info of form tag = "info" */
+ #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
+
+diff --git a/kernel/params.c b/kernel/params.c
+index 8d48a6bfe68da..c7aed3c51cd53 100644
+--- a/kernel/params.c
++++ b/kernel/params.c
+@@ -759,7 +759,7 @@ void destroy_params(const struct kernel_param *params, unsigned num)
+ params[i].ops->free(params[i].arg);
+ }
+
+-static struct module_kobject * __init lookup_or_create_module_kobject(const char *name)
++struct module_kobject __modinit * lookup_or_create_module_kobject(const char *name)
+ {
+ struct module_kobject *mk;
+ struct kobject *kobj;
+--
+2.39.5
+
--- /dev/null
+From 64dd9801997c54c334d35d2fb7fd377c0f471a97 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 10:49:27 -0800
+Subject: kernel: param: rename locate_module_kobject
+
+From: Shyam Saini <shyamsaini@linux.microsoft.com>
+
+[ Upstream commit bbc9462f0cb0c8917a4908e856731708f0cee910 ]
+
+The locate_module_kobject() function looks up an existing
+module_kobject for a given module name. If it cannot find the
+corresponding module_kobject, it creates one for the given name.
+
+This commit renames locate_module_kobject() to
+lookup_or_create_module_kobject() to better describe its operations.
+
+This doesn't change anything functionality wise.
+
+Suggested-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
+Signed-off-by: Shyam Saini <shyamsaini@linux.microsoft.com>
+Link: https://lore.kernel.org/r/20250227184930.34163-2-shyamsaini@linux.microsoft.com
+Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
+Stable-dep-of: f95bbfe18512 ("drivers: base: handle module_kobject creation")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/params.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/kernel/params.c b/kernel/params.c
+index 2d4a0564697e8..8d48a6bfe68da 100644
+--- a/kernel/params.c
++++ b/kernel/params.c
+@@ -759,7 +759,7 @@ void destroy_params(const struct kernel_param *params, unsigned num)
+ params[i].ops->free(params[i].arg);
+ }
+
+-static struct module_kobject * __init locate_module_kobject(const char *name)
++static struct module_kobject * __init lookup_or_create_module_kobject(const char *name)
+ {
+ struct module_kobject *mk;
+ struct kobject *kobj;
+@@ -801,7 +801,7 @@ static void __init kernel_add_sysfs_param(const char *name,
+ struct module_kobject *mk;
+ int err;
+
+- mk = locate_module_kobject(name);
++ mk = lookup_or_create_module_kobject(name);
+ if (!mk)
+ return;
+
+@@ -872,7 +872,7 @@ static void __init version_sysfs_builtin(void)
+ int err;
+
+ for (vattr = __start___modver; vattr < __stop___modver; vattr++) {
+- mk = locate_module_kobject(vattr->module_name);
++ mk = lookup_or_create_module_kobject(vattr->module_name);
+ if (mk) {
+ err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr);
+ WARN_ON_ONCE(err);
+--
+2.39.5
+
--- /dev/null
+From 9c1fc2f90d2440c11a4a7b8c8940a953c427448c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Mar 2025 16:09:34 -0700
+Subject: memcg: drain obj stock on cpu hotplug teardown
+
+From: Shakeel Butt <shakeel.butt@linux.dev>
+
+[ Upstream commit 9f01b4954490d4ccdbcc2b9be34a9921ceee9cbb ]
+
+Currently on cpu hotplug teardown, only memcg stock is drained but we
+need to drain the obj stock as well otherwise we will miss the stats
+accumulated on the target cpu as well as the nr_bytes cached. The stats
+include MEMCG_KMEM, NR_SLAB_RECLAIMABLE_B & NR_SLAB_UNRECLAIMABLE_B. In
+addition we are leaking reference to struct obj_cgroup object.
+
+Link: https://lkml.kernel.org/r/20250310230934.2913113-1-shakeel.butt@linux.dev
+Fixes: bf4f059954dc ("mm: memcg/slab: obj_cgroup API")
+Signed-off-by: Shakeel Butt <shakeel.butt@linux.dev>
+Reviewed-by: Roman Gushchin <roman.gushchin@linux.dev>
+Acked-by: Johannes Weiner <hannes@cmpxchg.org>
+Cc: Michal Hocko <mhocko@kernel.org>
+Cc: Muchun Song <muchun.song@linux.dev>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ mm/memcontrol.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/mm/memcontrol.c b/mm/memcontrol.c
+index 9bf5a69e20d87..ab9afcd372a93 100644
+--- a/mm/memcontrol.c
++++ b/mm/memcontrol.c
+@@ -2378,9 +2378,18 @@ static void drain_all_stock(struct mem_cgroup *root_memcg)
+ static int memcg_hotplug_cpu_dead(unsigned int cpu)
+ {
+ struct memcg_stock_pcp *stock;
++ struct obj_cgroup *old;
++ unsigned long flags;
+
+ stock = &per_cpu(memcg_stock, cpu);
++
++ /* drain_obj_stock requires stock_lock */
++ local_lock_irqsave(&memcg_stock.stock_lock, flags);
++ old = drain_obj_stock(stock);
++ local_unlock_irqrestore(&memcg_stock.stock_lock, flags);
++
+ drain_stock(stock);
++ obj_cgroup_put(old);
+
+ return 0;
+ }
+--
+2.39.5
+
--- /dev/null
+From 8cf3d8db987b12c6e7497717f4145beb174ff190 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 21 Apr 2025 22:12:59 +0200
+Subject: Revert "drm/meson: vclk: fix calculation of 59.94 fractional rates"
+
+From: Christian Hewitt <christianshewitt@gmail.com>
+
+[ Upstream commit f37bb5486ea536c1d61df89feeaeff3f84f0b560 ]
+
+This reverts commit bfbc68e.
+
+The patch does permit the offending YUV420 @ 59.94 phy_freq and
+vclk_freq mode to match in calculations. It also results in all
+fractional rates being unavailable for use. This was unintended
+and requires the patch to be reverted.
+
+Fixes: bfbc68e4d869 ("drm/meson: vclk: fix calculation of 59.94 fractional rates")
+Cc: stable@vger.kernel.org
+Signed-off-by: Christian Hewitt <christianshewitt@gmail.com>
+Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
+Link: https://lore.kernel.org/r/20250421201300.778955-2-martin.blumenstingl@googlemail.com
+Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
+Link: https://lore.kernel.org/r/20250421201300.778955-2-martin.blumenstingl@googlemail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/meson/meson_vclk.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c
+index 2a942dc6a6dc2..2a82119eb58ed 100644
+--- a/drivers/gpu/drm/meson/meson_vclk.c
++++ b/drivers/gpu/drm/meson/meson_vclk.c
+@@ -790,13 +790,13 @@ meson_vclk_vic_supported_freq(struct meson_drm *priv, unsigned int phy_freq,
+ FREQ_1000_1001(params[i].pixel_freq));
+ DRM_DEBUG_DRIVER("i = %d phy_freq = %d alt = %d\n",
+ i, params[i].phy_freq,
+- FREQ_1000_1001(params[i].phy_freq/1000)*1000);
++ FREQ_1000_1001(params[i].phy_freq/10)*10);
+ /* Match strict frequency */
+ if (phy_freq == params[i].phy_freq &&
+ vclk_freq == params[i].vclk_freq)
+ return MODE_OK;
+ /* Match 1000/1001 variant */
+- if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/1000)*1000) &&
++ if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/10)*10) &&
+ vclk_freq == FREQ_1000_1001(params[i].vclk_freq))
+ return MODE_OK;
+ }
+@@ -1070,7 +1070,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
+
+ for (freq = 0 ; params[freq].pixel_freq ; ++freq) {
+ if ((phy_freq == params[freq].phy_freq ||
+- phy_freq == FREQ_1000_1001(params[freq].phy_freq/1000)*1000) &&
++ phy_freq == FREQ_1000_1001(params[freq].phy_freq/10)*10) &&
+ (vclk_freq == params[freq].vclk_freq ||
+ vclk_freq == FREQ_1000_1001(params[freq].vclk_freq))) {
+ if (vclk_freq != params[freq].vclk_freq)
+--
+2.39.5
+
--- /dev/null
+From 0e8d55306ed936412969e644752ba4679da22d18 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 19 Apr 2025 13:14:00 +0200
+Subject: riscv: uprobes: Add missing fence.i after building the XOL buffer
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Björn Töpel <bjorn@rivosinc.com>
+
+[ Upstream commit 7d1d19a11cfbfd8bae1d89cc010b2cc397cd0c48 ]
+
+The XOL (execute out-of-line) buffer is used to single-step the
+replaced instruction(s) for uprobes. The RISC-V port was missing a
+proper fence.i (i$ flushing) after constructing the XOL buffer, which
+can result in incorrect execution of stale/broken instructions.
+
+This was found running the BPF selftests "test_progs:
+uprobe_autoattach, attach_probe" on the Spacemit K1/X60, where the
+uprobes tests randomly blew up.
+
+Reviewed-by: Guo Ren <guoren@kernel.org>
+Fixes: 74784081aac8 ("riscv: Add uprobes supported")
+Signed-off-by: Björn Töpel <bjorn@rivosinc.com>
+Link: https://lore.kernel.org/r/20250419111402.1660267-2-bjorn@kernel.org
+Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/riscv/kernel/probes/uprobes.c | 10 ++--------
+ 1 file changed, 2 insertions(+), 8 deletions(-)
+
+diff --git a/arch/riscv/kernel/probes/uprobes.c b/arch/riscv/kernel/probes/uprobes.c
+index 4b3dc8beaf77d..cc15f7ca6cc17 100644
+--- a/arch/riscv/kernel/probes/uprobes.c
++++ b/arch/riscv/kernel/probes/uprobes.c
+@@ -167,6 +167,7 @@ void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
+ /* Initialize the slot */
+ void *kaddr = kmap_atomic(page);
+ void *dst = kaddr + (vaddr & ~PAGE_MASK);
++ unsigned long start = (unsigned long)dst;
+
+ memcpy(dst, src, len);
+
+@@ -176,13 +177,6 @@ void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
+ *(uprobe_opcode_t *)dst = __BUG_INSN_32;
+ }
+
++ flush_icache_range(start, start + len);
+ kunmap_atomic(kaddr);
+-
+- /*
+- * We probably need flush_icache_user_page() but it needs vma.
+- * This should work on most of architectures by default. If
+- * architecture needs to do something different it can define
+- * its own version of the function.
+- */
+- flush_dcache_page(page);
+ }
+--
+2.39.5
+
sch_hfsc-make-hfsc_qlen_notify-idempotent.patch
sch_qfq-make-qfq_qlen_notify-idempotent.patch
sch_ets-make-est_qlen_notify-idempotent.patch
+firmware-arm_scmi-balance-device-refcount-when-destr.patch
+firmware-arm_ffa-skip-rx-buffer-ownership-release-if.patch
+arm-dts-opos6ul-add-ksz8081-phy-properties.patch
+arm64-dts-st-adjust-interrupt-controller-for-stm32mp.patch
+arm64-dts-st-use-128kb-size-for-aliased-gic400-regis.patch
+revert-drm-meson-vclk-fix-calculation-of-59.94-fract.patch
+xhci-set-desi-bits-in-erdp-register-correctly.patch
+xhci-use-more-than-one-event-ring-segment.patch
+xhci-clean-up-stale-comment-on-erst_size-macro.patch
+xhci-split-free-interrupter-into-separate-remove-and.patch
+xhci-add-support-to-allocate-several-interrupters.patch
+xhci-add-helper-to-set-an-interrupters-interrupt-mod.patch
+usb-xhci-check-if-requested-segments-exceeds-erst-ca.patch
+xhci-support-setting-interrupt-moderation-imod-for-s.patch
+xhci-limit-time-spent-with-xhc-interrupts-disabled-d.patch
+memcg-drain-obj-stock-on-cpu-hotplug-teardown.patch
+riscv-uprobes-add-missing-fence.i-after-building-the.patch
+cpufreq-intel_pstate-revise-global-turbo-disable-che.patch
+cpufreq-intel_pstate-fold-intel_pstate_max_within_li.patch
+cpufreq-intel_pstate-do-not-update-global.turbo_disa.patch
+cpufreq-intel_pstate-unchecked-msr-aceess-in-legacy-.patch
+kernel-param-rename-locate_module_kobject.patch
+kernel-globalize-lookup_or_create_module_kobject.patch
+drivers-base-handle-module_kobject-creation.patch
+iommu-arm-smmu-v3-use-the-new-rb-tree-helpers.patch
+iommu-arm-smmu-v3-fix-iommu_device_probe-bug-due-to-.patch
+drm-amd-display-add-scoped-mutexes-for-amdgpu_dm_dhc.patch
+drm-amd-display-fix-slab-use-after-free-in-hdcp.patch
--- /dev/null
+From 7fcd3d6a290f530aac53f8b851188c6b827826b5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 29 Apr 2024 17:02:30 +0300
+Subject: usb: xhci: check if 'requested segments' exceeds ERST capacity
+
+From: Niklas Neronin <niklas.neronin@linux.intel.com>
+
+[ Upstream commit db4460b6ecf07574d580f01cd88054a62607068c ]
+
+Check if requested segments ('segs' or 'ERST_DEFAULT_SEGS') exceeds the
+maximum amount ERST supports.
+
+When 'segs' is '0', 'ERST_DEFAULT_SEGS' is used instead. But both values
+may not exceed ERST max.
+
+Macro 'ERST_MAX_SEGS' is renamed to 'ERST_DEFAULT_SEGS'. The new name
+better represents the macros, which is the number of Event Ring segments
+to allocate, when the amount is not specified.
+
+Additionally, rename and change xhci_create_secondary_interrupter()'s
+argument 'int num_segs' to 'unsigned int segs'. This makes it the same
+as its counter part in xhci_alloc_interrupter().
+
+Fixes: c99b38c41234 ("xhci: add support to allocate several interrupters")
+Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20240429140245.3955523-4-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: bea5892d0ed2 ("xhci: Limit time spent with xHC interrupts disabled during bus resume")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-mem.c | 22 +++++++++++-----------
+ drivers/usb/host/xhci.h | 6 +++---
+ 2 files changed, 14 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
+index 3ab547a6e4ce9..489f54cf9a8a2 100644
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -2275,24 +2275,24 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
+ }
+
+ static struct xhci_interrupter *
+-xhci_alloc_interrupter(struct xhci_hcd *xhci, int segs, gfp_t flags)
++xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int segs, gfp_t flags)
+ {
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
+ struct xhci_interrupter *ir;
+- unsigned int num_segs = segs;
++ unsigned int max_segs;
+ int ret;
+
++ if (!segs)
++ segs = ERST_DEFAULT_SEGS;
++
++ max_segs = BIT(HCS_ERST_MAX(xhci->hcs_params2));
++ segs = min(segs, max_segs);
++
+ ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev));
+ if (!ir)
+ return NULL;
+
+- /* number of ring segments should be greater than 0 */
+- if (segs <= 0)
+- num_segs = min_t(unsigned int, 1 << HCS_ERST_MAX(xhci->hcs_params2),
+- ERST_MAX_SEGS);
+-
+- ir->event_ring = xhci_ring_alloc(xhci, num_segs, 1, TYPE_EVENT, 0,
+- flags);
++ ir->event_ring = xhci_ring_alloc(xhci, segs, 1, TYPE_EVENT, 0, flags);
+ if (!ir->event_ring) {
+ xhci_warn(xhci, "Failed to allocate interrupter event ring\n");
+ kfree(ir);
+@@ -2353,7 +2353,7 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
+ }
+
+ struct xhci_interrupter *
+-xhci_create_secondary_interrupter(struct usb_hcd *hcd, int num_seg)
++xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs)
+ {
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct xhci_interrupter *ir;
+@@ -2363,7 +2363,7 @@ xhci_create_secondary_interrupter(struct usb_hcd *hcd, int num_seg)
+ if (!xhci->interrupters || xhci->max_interrupters <= 1)
+ return NULL;
+
+- ir = xhci_alloc_interrupter(xhci, num_seg, GFP_KERNEL);
++ ir = xhci_alloc_interrupter(xhci, segs, GFP_KERNEL);
+ if (!ir)
+ return NULL;
+
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index 9d2cf11cef846..156e43977cdd4 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1423,8 +1423,8 @@ struct urb_priv {
+ struct xhci_td td[];
+ };
+
+-/* Reasonable limit for number of Event Ring segments (spec allows 32k) */
+-#define ERST_MAX_SEGS 2
++/* Number of Event Ring segments to allocate, when amount is not specified. (spec allows 32k) */
++#define ERST_DEFAULT_SEGS 2
+ /* Poll every 60 seconds */
+ #define POLL_TIMEOUT 60
+ /* Stop endpoint command timeout (secs) for URB cancellation watchdog timer */
+@@ -1867,7 +1867,7 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
+ void xhci_free_container_ctx(struct xhci_hcd *xhci,
+ struct xhci_container_ctx *ctx);
+ struct xhci_interrupter *
+-xhci_create_secondary_interrupter(struct usb_hcd *hcd, int num_seg);
++xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs);
+ void xhci_remove_secondary_interrupter(struct usb_hcd
+ *hcd, struct xhci_interrupter *ir);
+
+--
+2.39.5
+
--- /dev/null
+From 607df2d76302cdc87ade4749e1cbab02a97820e6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 16 Feb 2024 16:09:28 -0800
+Subject: xhci: Add helper to set an interrupters interrupt moderation interval
+
+From: Mathias Nyman <mathias.nyman@linux.intel.com>
+
+[ Upstream commit ace21625878f78708b75b7a872ec7a0e2ed15ca4 ]
+
+Add a helper to set the interrupt moderation interval for an interrupter.
+Each interrupter can have its own moderation value.
+
+Hardware has a 16bit register for the moderation value, each step is 250ns.
+
+Helper function imod_interval argument is in nanoseconds.
+
+Values from 0 to 16383750 (250 x 0xffff) are accepted.
+0 means no interrupt throttling.
+
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Signed-off-by: Wesley Cheng <quic_wcheng@quicinc.com>
+Link: https://lore.kernel.org/r/20240217001017.29969-3-quic_wcheng@quicinc.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: bea5892d0ed2 ("xhci: Limit time spent with xHC interrupts disabled during bus resume")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci.c | 25 ++++++++++++++++++-------
+ 1 file changed, 18 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
+index 5c3250989047e..d6a0c79e5fada 100644
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -323,6 +323,23 @@ static int xhci_disable_interrupter(struct xhci_interrupter *ir)
+ return 0;
+ }
+
++/* interrupt moderation interval imod_interval in nanoseconds */
++static int xhci_set_interrupter_moderation(struct xhci_interrupter *ir,
++ u32 imod_interval)
++{
++ u32 imod;
++
++ if (!ir || !ir->ir_set || imod_interval > U16_MAX * 250)
++ return -EINVAL;
++
++ imod = readl(&ir->ir_set->irq_control);
++ imod &= ~ER_IRQ_INTERVAL_MASK;
++ imod |= (imod_interval / 250) & ER_IRQ_INTERVAL_MASK;
++ writel(imod, &ir->ir_set->irq_control);
++
++ return 0;
++}
++
+ static void compliance_mode_recovery(struct timer_list *t)
+ {
+ struct xhci_hcd *xhci;
+@@ -505,7 +522,6 @@ static int xhci_run_finished(struct xhci_hcd *xhci)
+ */
+ int xhci_run(struct usb_hcd *hcd)
+ {
+- u32 temp;
+ u64 temp_64;
+ int ret;
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+@@ -525,12 +541,7 @@ int xhci_run(struct usb_hcd *hcd)
+ 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(&ir->ir_set->irq_control);
+- temp &= ~ER_IRQ_INTERVAL_MASK;
+- temp |= (xhci->imod_interval / 250) & ER_IRQ_INTERVAL_MASK;
+- writel(temp, &ir->ir_set->irq_control);
++ xhci_set_interrupter_moderation(ir, xhci->imod_interval);
+
+ if (xhci->quirks & XHCI_NEC_HOST) {
+ struct xhci_command *command;
+--
+2.39.5
+
--- /dev/null
+From d0683ab97a4f20009d71afc1ba1d7751ecbb4dbd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 2 Jan 2024 13:45:09 -0800
+Subject: xhci: add support to allocate several interrupters
+
+From: Mathias Nyman <mathias.nyman@linux.intel.com>
+
+[ Upstream commit c99b38c412343053e9af187e595793c8805bb9b8 ]
+
+Modify the XHCI drivers to accommodate for handling multiple event rings in
+case there are multiple interrupters. Add the required APIs so clients are
+able to allocate/request for an interrupter ring, and pass this information
+back to the client driver. This allows for users to handle the resource
+accordingly, such as passing the event ring base address to an audio DSP.
+There is no actual support for multiple MSI/MSI-X vectors.
+
+[export xhci_initialize_ring_info() -wcheng]
+
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Signed-off-by: Wesley Cheng <quic_wcheng@quicinc.com>
+Link: https://lore.kernel.org/r/20240102214549.22498-2-quic_wcheng@quicinc.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: bea5892d0ed2 ("xhci: Limit time spent with xHC interrupts disabled during bus resume")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-debugfs.c | 2 +-
+ drivers/usb/host/xhci-mem.c | 108 ++++++++++++++++++++++++++++----
+ drivers/usb/host/xhci-ring.c | 2 +-
+ drivers/usb/host/xhci.c | 51 +++++++++------
+ drivers/usb/host/xhci.h | 6 +-
+ 5 files changed, 137 insertions(+), 32 deletions(-)
+
+diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c
+index 99baa60ef50fe..15a8402ee8a17 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->interrupter->event_ring,
++ xhci_debugfs_create_ring_dir(xhci, &xhci->interrupters[0]->event_ring,
+ "event-ring",
+ xhci->debugfs_root);
+
+diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
+index f00e96c9ca57a..3ab547a6e4ce9 100644
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -318,6 +318,7 @@ void xhci_initialize_ring_info(struct xhci_ring *ring,
+ */
+ ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1;
+ }
++EXPORT_SYMBOL_GPL(xhci_initialize_ring_info);
+
+ /* Allocate segments and link them for a ring */
+ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
+@@ -1849,6 +1850,31 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
+ kfree(ir);
+ }
+
++void xhci_remove_secondary_interrupter(struct usb_hcd *hcd, struct xhci_interrupter *ir)
++{
++ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
++ unsigned int intr_num;
++
++ /* interrupter 0 is primary interrupter, don't touch it */
++ if (!ir || !ir->intr_num || ir->intr_num >= xhci->max_interrupters)
++ xhci_dbg(xhci, "Invalid secondary interrupter, can't remove\n");
++
++ /* fixme, should we check xhci->interrupter[intr_num] == ir */
++ /* fixme locking */
++
++ spin_lock_irq(&xhci->lock);
++
++ intr_num = ir->intr_num;
++
++ xhci_remove_interrupter(xhci, ir);
++ xhci->interrupters[intr_num] = NULL;
++
++ spin_unlock_irq(&xhci->lock);
++
++ xhci_free_interrupter(xhci, ir);
++}
++EXPORT_SYMBOL_GPL(xhci_remove_secondary_interrupter);
++
+ void xhci_mem_cleanup(struct xhci_hcd *xhci)
+ {
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
+@@ -1856,10 +1882,14 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
+
+ cancel_delayed_work_sync(&xhci->cmd_timer);
+
+- xhci_remove_interrupter(xhci, xhci->interrupter);
+- xhci_free_interrupter(xhci, xhci->interrupter);
+- xhci->interrupter = NULL;
+- xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed primary event ring");
++ for (i = 0; i < xhci->max_interrupters; i++) {
++ if (xhci->interrupters[i]) {
++ xhci_remove_interrupter(xhci, xhci->interrupters[i]);
++ xhci_free_interrupter(xhci, xhci->interrupters[i]);
++ xhci->interrupters[i] = NULL;
++ }
++ }
++ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed interrupters");
+
+ if (xhci->cmd_ring)
+ xhci_ring_free(xhci, xhci->cmd_ring);
+@@ -1929,6 +1959,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
+ for (i = 0; i < xhci->num_port_caps; i++)
+ kfree(xhci->port_caps[i].psi);
+ kfree(xhci->port_caps);
++ kfree(xhci->interrupters);
+ xhci->num_port_caps = 0;
+
+ xhci->usb2_rhub.ports = NULL;
+@@ -1937,6 +1968,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
+ xhci->rh_bw = NULL;
+ xhci->ext_caps = NULL;
+ xhci->port_caps = NULL;
++ xhci->interrupters = NULL;
+
+ xhci->page_size = 0;
+ xhci->page_shift = 0;
+@@ -2243,18 +2275,20 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
+ }
+
+ static struct xhci_interrupter *
+-xhci_alloc_interrupter(struct xhci_hcd *xhci, gfp_t flags)
++xhci_alloc_interrupter(struct xhci_hcd *xhci, int segs, gfp_t flags)
+ {
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
+ struct xhci_interrupter *ir;
+- unsigned int num_segs;
++ unsigned int num_segs = segs;
+ int ret;
+
+ ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev));
+ if (!ir)
+ return NULL;
+
+- num_segs = min_t(unsigned int, 1 << HCS_ERST_MAX(xhci->hcs_params2),
++ /* number of ring segments should be greater than 0 */
++ if (segs <= 0)
++ num_segs = min_t(unsigned int, 1 << HCS_ERST_MAX(xhci->hcs_params2),
+ ERST_MAX_SEGS);
+
+ ir->event_ring = xhci_ring_alloc(xhci, num_segs, 1, TYPE_EVENT, 0,
+@@ -2289,6 +2323,13 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
+ return -EINVAL;
+ }
+
++ if (xhci->interrupters[intr_num]) {
++ xhci_warn(xhci, "Interrupter %d\n already set up", intr_num);
++ return -EINVAL;
++ }
++
++ xhci->interrupters[intr_num] = ir;
++ ir->intr_num = intr_num;
+ ir->ir_set = &xhci->run_regs->ir_set[intr_num];
+
+ /* set ERST count with the number of entries in the segment table */
+@@ -2311,10 +2352,52 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
+ return 0;
+ }
+
++struct xhci_interrupter *
++xhci_create_secondary_interrupter(struct usb_hcd *hcd, int num_seg)
++{
++ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
++ struct xhci_interrupter *ir;
++ unsigned int i;
++ int err = -ENOSPC;
++
++ if (!xhci->interrupters || xhci->max_interrupters <= 1)
++ return NULL;
++
++ ir = xhci_alloc_interrupter(xhci, num_seg, GFP_KERNEL);
++ if (!ir)
++ return NULL;
++
++ spin_lock_irq(&xhci->lock);
++
++ /* Find available secondary interrupter, interrupter 0 is reserved for primary */
++ for (i = 1; i < xhci->max_interrupters; i++) {
++ if (xhci->interrupters[i] == NULL) {
++ err = xhci_add_interrupter(xhci, ir, i);
++ break;
++ }
++ }
++
++ spin_unlock_irq(&xhci->lock);
++
++ if (err) {
++ xhci_warn(xhci, "Failed to add secondary interrupter, max interrupters %d\n",
++ xhci->max_interrupters);
++ xhci_free_interrupter(xhci, ir);
++ return NULL;
++ }
++
++ xhci_dbg(xhci, "Add secondary interrupter %d, max interrupters %d\n",
++ i, xhci->max_interrupters);
++
++ return ir;
++}
++EXPORT_SYMBOL_GPL(xhci_create_secondary_interrupter);
++
+ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
+ {
+- dma_addr_t dma;
++ struct xhci_interrupter *ir;
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
++ dma_addr_t dma;
+ unsigned int val, val2;
+ u64 val_64;
+ u32 page_size, temp;
+@@ -2439,11 +2522,14 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
+ /* Allocate and set up primary interrupter 0 with an event ring. */
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Allocating primary event ring");
+- xhci->interrupter = xhci_alloc_interrupter(xhci, flags);
+- if (!xhci->interrupter)
++ xhci->interrupters = kcalloc_node(xhci->max_interrupters, sizeof(*xhci->interrupters),
++ flags, dev_to_node(dev));
++
++ ir = xhci_alloc_interrupter(xhci, 0, flags);
++ if (!ir)
+ goto fail;
+
+- if (xhci_add_interrupter(xhci, xhci->interrupter, 0))
++ if (xhci_add_interrupter(xhci, ir, 0))
+ 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 884a668cca367..5a53280fa2edf 100644
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -3225,7 +3225,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
+ writel(status, &xhci->op_regs->status);
+
+ /* This is the handler of the primary interrupter */
+- ir = xhci->interrupter;
++ ir = xhci->interrupters[0];
+ if (!hcd->msi_enabled) {
+ u32 irq_pending;
+ irq_pending = readl(&ir->ir_set->irq_pending);
+diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
+index 70e6c240a5409..5c3250989047e 100644
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -457,7 +457,7 @@ static int xhci_init(struct usb_hcd *hcd)
+
+ static int xhci_run_finished(struct xhci_hcd *xhci)
+ {
+- struct xhci_interrupter *ir = xhci->interrupter;
++ struct xhci_interrupter *ir = xhci->interrupters[0];
+ unsigned long flags;
+ u32 temp;
+
+@@ -509,7 +509,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;
++ struct xhci_interrupter *ir = xhci->interrupters[0];
+ /* Start the xHCI host controller running only after the USB 2.0 roothub
+ * is setup.
+ */
+@@ -573,7 +573,7 @@ void xhci_stop(struct usb_hcd *hcd)
+ {
+ u32 temp;
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+- struct xhci_interrupter *ir = xhci->interrupter;
++ struct xhci_interrupter *ir = xhci->interrupters[0];
+
+ mutex_lock(&xhci->mutex);
+
+@@ -669,36 +669,51 @@ EXPORT_SYMBOL_GPL(xhci_shutdown);
+ #ifdef CONFIG_PM
+ static void xhci_save_registers(struct xhci_hcd *xhci)
+ {
+- struct xhci_interrupter *ir = xhci->interrupter;
++ struct xhci_interrupter *ir;
++ unsigned int i;
+
+ 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);
+
+- if (!ir)
+- return;
++ /* save both primary and all secondary interrupters */
++ /* fixme, shold we lock to prevent race with remove secondary interrupter? */
++ for (i = 0; i < xhci->max_interrupters; i++) {
++ ir = xhci->interrupters[i];
++ if (!ir)
++ continue;
+
+- 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);
++ 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;
++ struct xhci_interrupter *ir;
++ unsigned int i;
+
+ 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(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);
++
++ /* FIXME should we lock to protect against freeing of interrupters */
++ for (i = 0; i < xhci->max_interrupters; i++) {
++ ir = xhci->interrupters[i];
++ if (!ir)
++ continue;
++
++ 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)
+@@ -1061,7 +1076,7 @@ int xhci_resume(struct xhci_hcd *xhci, pm_message_t msg)
+ xhci_dbg(xhci, "// Disabling event ring interrupts\n");
+ temp = readl(&xhci->op_regs->status);
+ writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
+- xhci_disable_interrupter(xhci->interrupter);
++ xhci_disable_interrupter(xhci->interrupters[0]);
+
+ xhci_dbg(xhci, "cleaning up memory\n");
+ xhci_mem_cleanup(xhci);
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index a49560145d78b..9d2cf11cef846 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1549,7 +1549,7 @@ struct xhci_hcd {
+ struct reset_control *reset;
+ /* data structures */
+ struct xhci_device_context_array *dcbaa;
+- struct xhci_interrupter *interrupter;
++ struct xhci_interrupter **interrupters;
+ struct xhci_ring *cmd_ring;
+ unsigned int cmd_ring_state;
+ #define CMD_RING_STATE_RUNNING (1 << 0)
+@@ -1866,6 +1866,10 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
+ int type, gfp_t flags);
+ void xhci_free_container_ctx(struct xhci_hcd *xhci,
+ struct xhci_container_ctx *ctx);
++struct xhci_interrupter *
++xhci_create_secondary_interrupter(struct usb_hcd *hcd, int num_seg);
++void xhci_remove_secondary_interrupter(struct usb_hcd
++ *hcd, struct xhci_interrupter *ir);
+
+ /* xHCI host controller glue */
+ typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
+--
+2.39.5
+
--- /dev/null
+From a8aec2bed006c5b782322beacbf863e4e73f3b42 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 19 Oct 2023 13:29:15 +0300
+Subject: xhci: Clean up stale comment on ERST_SIZE macro
+
+From: Lukas Wunner <lukas@wunner.de>
+
+[ Upstream commit c087fada0a6180ab5b88b11c1776eef02f8d556f ]
+
+Commit ebd88cf50729 ("xhci: Remove unused defines for ERST_SIZE and
+ERST_ENTRIES") removed the ERST_SIZE macro but retained a code comment
+explaining the quantity chosen in the macro.
+
+Remove the code comment as well.
+
+Signed-off-by: Lukas Wunner <lukas@wunner.de>
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20231019102924.2797346-11-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: bea5892d0ed2 ("xhci: Limit time spent with xHC interrupts disabled during bus resume")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci.h | 7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index 76a3010b8b74a..a49560145d78b 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1423,12 +1423,7 @@ struct urb_priv {
+ struct xhci_td td[];
+ };
+
+-/*
+- * Each segment table entry is 4*32bits long. 1K seems like an ok size:
+- * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table,
+- * meaning 64 ring segments.
+- * Reasonable limit for number of Event Ring segments (spec allows 32k)
+- */
++/* Reasonable limit for number of Event Ring segments (spec allows 32k) */
+ #define ERST_MAX_SEGS 2
+ /* Poll every 60 seconds */
+ #define POLL_TIMEOUT 60
+--
+2.39.5
+
--- /dev/null
+From b825219fc4a0d3fb17f12d0b7fffeb52fba46a8e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 10 Apr 2025 18:18:27 +0300
+Subject: xhci: Limit time spent with xHC interrupts disabled during bus resume
+
+From: Mathias Nyman <mathias.nyman@linux.intel.com>
+
+[ Upstream commit bea5892d0ed274e03655223d1977cf59f9aff2f2 ]
+
+Current xhci bus resume implementation prevents xHC host from generating
+interrupts during high-speed USB 2 and super-speed USB 3 bus resume.
+
+Only reason to disable interrupts during bus resume would be to prevent
+the interrupt handler from interfering with the resume process of USB 2
+ports.
+
+Host initiated resume of USB 2 ports is done in two stages.
+
+The xhci driver first transitions the port from 'U3' to 'Resume' state,
+then wait in Resume for 20ms, and finally moves port to U0 state.
+xhci driver can't prevent interrupts by keeping the xhci spinlock
+due to this 20ms sleep.
+
+Limit interrupt disabling to the USB 2 port resume case only.
+resuming USB 2 ports in bus resume is only done in special cases where
+USB 2 ports had to be forced to suspend during bus suspend.
+
+The current way of preventing interrupts by clearing the 'Interrupt
+Enable' (INTE) bit in USBCMD register won't prevent the Interrupter
+registers 'Interrupt Pending' (IP), 'Event Handler Busy' (EHB) and
+USBSTS register Event Interrupt (EINT) bits from being set.
+
+New interrupts can't be issued before those bits are properly clered.
+
+Disable interrupts by clearing the interrupter register 'Interrupt
+Enable' (IE) bit instead. This way IP, EHB and INTE won't be set
+before IE is enabled again and a new interrupt is triggered.
+
+Reported-by: Devyn Liu <liudingyuan@huawei.com>
+Closes: https://lore.kernel.org/linux-usb/b1a9e2d51b4d4ff7a304f77c5be8164e@huawei.com/
+Cc: stable@vger.kernel.org
+Tested-by: Devyn Liu <liudingyuan@huawei.com>
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20250410151828.2868740-6-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-hub.c | 30 ++++++++++++++++--------------
+ drivers/usb/host/xhci.c | 4 ++--
+ drivers/usb/host/xhci.h | 2 ++
+ 3 files changed, 20 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
+index 0df5d807a77e8..a2b6a922077ee 100644
+--- a/drivers/usb/host/xhci-hub.c
++++ b/drivers/usb/host/xhci-hub.c
+@@ -1880,9 +1880,10 @@ int xhci_bus_resume(struct usb_hcd *hcd)
+ int slot_id;
+ int sret;
+ u32 next_state;
+- u32 temp, portsc;
++ u32 portsc;
+ struct xhci_hub *rhub;
+ struct xhci_port **ports;
++ bool disabled_irq = false;
+
+ rhub = xhci_get_rhub(hcd);
+ ports = rhub->ports;
+@@ -1898,17 +1899,20 @@ int xhci_bus_resume(struct usb_hcd *hcd)
+ return -ESHUTDOWN;
+ }
+
+- /* delay the irqs */
+- temp = readl(&xhci->op_regs->command);
+- temp &= ~CMD_EIE;
+- writel(temp, &xhci->op_regs->command);
+-
+ /* bus specific resume for ports we suspended at bus_suspend */
+- if (hcd->speed >= HCD_USB3)
++ if (hcd->speed >= HCD_USB3) {
+ next_state = XDEV_U0;
+- else
++ } else {
+ next_state = XDEV_RESUME;
+-
++ if (bus_state->bus_suspended) {
++ /*
++ * prevent port event interrupts from interfering
++ * with usb2 port resume process
++ */
++ xhci_disable_interrupter(xhci->interrupters[0]);
++ disabled_irq = true;
++ }
++ }
+ port_index = max_ports;
+ while (port_index--) {
+ portsc = readl(ports[port_index]->addr);
+@@ -1977,11 +1981,9 @@ int xhci_bus_resume(struct usb_hcd *hcd)
+ (void) readl(&xhci->op_regs->command);
+
+ bus_state->next_statechange = jiffies + msecs_to_jiffies(5);
+- /* re-enable irqs */
+- temp = readl(&xhci->op_regs->command);
+- temp |= CMD_EIE;
+- writel(temp, &xhci->op_regs->command);
+- temp = readl(&xhci->op_regs->command);
++ /* re-enable interrupter */
++ if (disabled_irq)
++ xhci_enable_interrupter(xhci->interrupters[0]);
+
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ return 0;
+diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
+index 0af298c5af65a..ce38cd2435c8c 100644
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -297,7 +297,7 @@ static void xhci_zero_64b_regs(struct xhci_hcd *xhci)
+ xhci_info(xhci, "Fault detected\n");
+ }
+
+-static int xhci_enable_interrupter(struct xhci_interrupter *ir)
++int xhci_enable_interrupter(struct xhci_interrupter *ir)
+ {
+ u32 iman;
+
+@@ -310,7 +310,7 @@ static int xhci_enable_interrupter(struct xhci_interrupter *ir)
+ return 0;
+ }
+
+-static int xhci_disable_interrupter(struct xhci_interrupter *ir)
++int xhci_disable_interrupter(struct xhci_interrupter *ir)
+ {
+ u32 iman;
+
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index 9d05a21392bb8..74bdd035d756a 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1908,6 +1908,8 @@ int xhci_alloc_tt_info(struct xhci_hcd *xhci,
+ struct usb_tt *tt, gfp_t mem_flags);
+ int xhci_set_interrupter_moderation(struct xhci_interrupter *ir,
+ u32 imod_interval);
++int xhci_enable_interrupter(struct xhci_interrupter *ir);
++int xhci_disable_interrupter(struct xhci_interrupter *ir);
+
+ /* xHCI ring, segment, TRB, and TD functions */
+ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb);
+--
+2.39.5
+
--- /dev/null
+From 80f6ce2accf243214c5936163e748097190727cb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 19 Oct 2023 13:29:09 +0300
+Subject: xhci: Set DESI bits in ERDP register correctly
+
+From: Lukas Wunner <lukas@wunner.de>
+
+[ Upstream commit 044818a6cd808b38a5d179a5fb9940417de4ba24 ]
+
+When using more than one Event Ring segment (ERSTSZ > 1), software shall
+set the DESI bits in the ERDP register to the number of the segment to
+which the upper ERDP bits are pointing. The xHC may use the DESI bits
+as a shortcut to determine whether it needs to check for an Event Ring
+Full condition: If it's enqueueing events in a different segment, it
+need not compare its internal Enqueue Pointer with the Dequeue Pointer
+in the upper bits of the ERDP register (sec 5.5.2.3.3).
+
+Not setting the DESI bits correctly can result in the xHC enqueueing
+events past the Dequeue Pointer. On Renesas uPD720201 host controllers,
+incorrect DESI bits cause an interrupt storm. For comparison, VIA VL805
+host controllers do not exhibit such problems. Perhaps they do not take
+advantage of the optimization afforded by the DESI bits.
+
+To fix the issue, assign the segment number to each struct xhci_segment
+in xhci_segment_alloc(). When advancing the Dequeue Pointer in
+xhci_update_erst_dequeue(), write the segment number to the DESI bits.
+
+On driver probe, set the DESI bits to zero in xhci_set_hc_event_deq() as
+processing starts in segment 0. Likewise on driver teardown, clear the
+DESI bits to zero in xhci_free_interrupter() when clearing the upper
+bits of the ERDP register. Previously those functions (incorrectly)
+treated the DESI bits as if they're declared RsvdP.
+
+Signed-off-by: Lukas Wunner <lukas@wunner.de>
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20231019102924.2797346-5-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: bea5892d0ed2 ("xhci: Limit time spent with xHC interrupts disabled during bus resume")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-mem.c | 25 +++++++++++--------------
+ drivers/usb/host/xhci-ring.c | 2 +-
+ drivers/usb/host/xhci.h | 1 +
+ 3 files changed, 13 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
+index fbc486546b853..f236fba5cd248 100644
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -29,6 +29,7 @@
+ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,
+ unsigned int cycle_state,
+ unsigned int max_packet,
++ unsigned int num,
+ gfp_t flags)
+ {
+ struct xhci_segment *seg;
+@@ -60,6 +61,7 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,
+ for (i = 0; i < TRBS_PER_SEGMENT; i++)
+ seg->trbs[i].link.control = cpu_to_le32(TRB_CYCLE);
+ }
++ seg->num = num;
+ seg->dma = dma;
+ seg->next = NULL;
+
+@@ -324,6 +326,7 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
+ enum xhci_ring_type type, unsigned int max_packet, gfp_t flags)
+ {
+ struct xhci_segment *prev;
++ unsigned int num = 0;
+ bool chain_links;
+
+ /* Set chain bit for 0.95 hosts, and for isoc rings on AMD 0.96 host */
+@@ -331,16 +334,17 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
+ (type == TYPE_ISOC &&
+ (xhci->quirks & XHCI_AMD_0x96_HOST)));
+
+- prev = xhci_segment_alloc(xhci, cycle_state, max_packet, flags);
++ prev = xhci_segment_alloc(xhci, cycle_state, max_packet, num, flags);
+ if (!prev)
+ return -ENOMEM;
+- num_segs--;
++ num++;
+
+ *first = prev;
+- while (num_segs > 0) {
++ while (num < num_segs) {
+ struct xhci_segment *next;
+
+- next = xhci_segment_alloc(xhci, cycle_state, max_packet, flags);
++ next = xhci_segment_alloc(xhci, cycle_state, max_packet, num,
++ flags);
+ if (!next) {
+ prev = *first;
+ while (prev) {
+@@ -353,7 +357,7 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
+ xhci_link_segments(prev, next, type, chain_links);
+
+ prev = next;
+- num_segs--;
++ num++;
+ }
+ xhci_link_segments(prev, *first, type, chain_links);
+ *last = prev;
+@@ -1803,7 +1807,6 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
+ {
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
+ size_t erst_size;
+- u64 tmp64;
+ u32 tmp;
+
+ if (!ir)
+@@ -1826,9 +1829,7 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
+ 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);
++ xhci_write_64(xhci, ERST_EHB, &ir->ir_set->erst_dequeue);
+ }
+
+ /* free interrrupter event ring */
+@@ -1935,7 +1936,6 @@ void xhci_mem_cleanup(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(ir->event_ring->deq_seg,
+@@ -1943,15 +1943,12 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter
+ 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, &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.
+ */
+- temp &= ~ERST_EHB;
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "// Write event ring dequeue pointer, preserving EHB bit");
+- xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp,
++ xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK),
+ &ir->ir_set->erst_dequeue);
+ }
+
+diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
+index cb94439629451..884a668cca367 100644
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -3167,7 +3167,7 @@ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
+ return;
+
+ /* Update HC event ring dequeue pointer */
+- temp_64 &= ERST_DESI_MASK;
++ temp_64 = ir->event_ring->deq_seg->num & ERST_DESI_MASK;
+ temp_64 |= ((u64) deq & (u64) ~ERST_PTR_MASK);
+ }
+
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index df87e8bcb7d24..0325fccfaa2a4 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1293,6 +1293,7 @@ struct xhci_segment {
+ union xhci_trb *trbs;
+ /* private to HCD */
+ struct xhci_segment *next;
++ unsigned int num;
+ dma_addr_t dma;
+ /* Max packet sized bounce buffer for td-fragmant alignment */
+ dma_addr_t bounce_dma;
+--
+2.39.5
+
--- /dev/null
+From e0c49bbfa6cb34184dfdc15d28550adfc5d56e1d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 19 Oct 2023 13:29:21 +0300
+Subject: xhci: split free interrupter into separate remove and free parts
+
+From: Mathias Nyman <mathias.nyman@linux.intel.com>
+
+[ Upstream commit 47f503cf5f799ec02e5f4b7c3b9afe145eca2aef ]
+
+The current function that both removes and frees an interrupter isn't
+optimal when using several interrupters. The array of interrupters need
+to be protected with a lock while removing interrupters, but the default
+xhci spin lock can't be used while freeing the interrupters event ring
+segment table as dma_free_coherent() should be called with IRQs enabled.
+
+There is no need to free the interrupter under the lock, so split this
+code into separate unlocked free part, and a lock protected remove part.
+
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20231019102924.2797346-17-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: bea5892d0ed2 ("xhci: Limit time spent with xHC interrupts disabled during bus resume")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-mem.c | 32 +++++++++++++++++++++-----------
+ 1 file changed, 21 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
+index 45240299fa171..f00e96c9ca57a 100644
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -1803,22 +1803,13 @@ int xhci_alloc_erst(struct xhci_hcd *xhci,
+ }
+
+ static void
+-xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
++xhci_remove_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
+ {
+- struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
+- size_t erst_size;
+ u32 tmp;
+
+ 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
+@@ -1831,10 +1822,28 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
+
+ xhci_write_64(xhci, ERST_EHB, &ir->ir_set->erst_dequeue);
+ }
++}
++
++static void
++xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
++{
++ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
++ size_t erst_size;
++
++ 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;
+
+- /* free interrrupter event ring */
++ /* free interrupter event ring */
+ if (ir->event_ring)
+ xhci_ring_free(xhci, ir->event_ring);
++
+ ir->event_ring = NULL;
+
+ kfree(ir);
+@@ -1847,6 +1856,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
+
+ cancel_delayed_work_sync(&xhci->cmd_timer);
+
++ xhci_remove_interrupter(xhci, xhci->interrupter);
+ xhci_free_interrupter(xhci, xhci->interrupter);
+ xhci->interrupter = NULL;
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed primary event ring");
+--
+2.39.5
+
--- /dev/null
+From b1b09800645a0e32d06d07d937435ff9015d44d9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 5 Sep 2024 17:33:00 +0300
+Subject: xhci: support setting interrupt moderation IMOD for secondary
+ interrupters
+
+From: Mathias Nyman <mathias.nyman@linux.intel.com>
+
+[ Upstream commit 9c0c11bb87b09a8b7cdc21ca1090e7b36abe9d09 ]
+
+Allow creators of seconday interrupters to specify the interrupt
+moderation interval value in nanoseconds when creating the interrupter.
+
+If not sure what value to use then use the xhci driver default
+xhci->imod_interval
+
+Suggested-by: Wesley Cheng <quic_wcheng@quicinc.com>
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20240905143300.1959279-13-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: bea5892d0ed2 ("xhci: Limit time spent with xHC interrupts disabled during bus resume")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-mem.c | 8 +++++++-
+ drivers/usb/host/xhci.c | 4 ++--
+ drivers/usb/host/xhci.h | 5 ++++-
+ 3 files changed, 13 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
+index 489f54cf9a8a2..2c44855be75ed 100644
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -2353,7 +2353,8 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
+ }
+
+ struct xhci_interrupter *
+-xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs)
++xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs,
++ u32 imod_interval)
+ {
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct xhci_interrupter *ir;
+@@ -2386,6 +2387,11 @@ xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs)
+ return NULL;
+ }
+
++ err = xhci_set_interrupter_moderation(ir, imod_interval);
++ if (err)
++ xhci_warn(xhci, "Failed to set interrupter %d moderation to %uns\n",
++ i, imod_interval);
++
+ xhci_dbg(xhci, "Add secondary interrupter %d, max interrupters %d\n",
+ i, xhci->max_interrupters);
+
+diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
+index d6a0c79e5fada..0af298c5af65a 100644
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -324,8 +324,8 @@ static int xhci_disable_interrupter(struct xhci_interrupter *ir)
+ }
+
+ /* interrupt moderation interval imod_interval in nanoseconds */
+-static int xhci_set_interrupter_moderation(struct xhci_interrupter *ir,
+- u32 imod_interval)
++int xhci_set_interrupter_moderation(struct xhci_interrupter *ir,
++ u32 imod_interval)
+ {
+ u32 imod;
+
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index 156e43977cdd4..9d05a21392bb8 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1867,7 +1867,8 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
+ void xhci_free_container_ctx(struct xhci_hcd *xhci,
+ struct xhci_container_ctx *ctx);
+ struct xhci_interrupter *
+-xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs);
++xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs,
++ u32 imod_interval);
+ void xhci_remove_secondary_interrupter(struct usb_hcd
+ *hcd, struct xhci_interrupter *ir);
+
+@@ -1905,6 +1906,8 @@ int xhci_alloc_tt_info(struct xhci_hcd *xhci,
+ struct xhci_virt_device *virt_dev,
+ struct usb_device *hdev,
+ struct usb_tt *tt, gfp_t mem_flags);
++int xhci_set_interrupter_moderation(struct xhci_interrupter *ir,
++ u32 imod_interval);
+
+ /* xHCI ring, segment, TRB, and TD functions */
+ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb);
+--
+2.39.5
+
--- /dev/null
+From 472d3ea2abf38ecf28b5380d6c92cf5be2de95a7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 19 Oct 2023 13:29:10 +0300
+Subject: xhci: Use more than one Event Ring segment
+
+From: Jonathan Bell <jonathan@raspberrypi.com>
+
+[ Upstream commit 28084d3fcc3c8445542917f32e382c45b5343cc2 ]
+
+Users have reported log spam created by "Event Ring Full" xHC event
+TRBs. These are caused by interrupt latency in conjunction with a very
+busy set of devices on the bus. The errors are benign, but throughput
+will suffer as the xHC will pause processing of transfers until the
+Event Ring is drained by the kernel.
+
+Commit dc0ffbea5729 ("usb: host: xhci: update event ring dequeue pointer
+on purpose") mitigated the issue by advancing the Event Ring Dequeue
+Pointer already after half a segment has been processed. Nevertheless,
+providing a larger Event Ring would be useful to cope with load peaks.
+
+Expand the number of event TRB slots available by increasing the number
+of Event Ring segments in the ERST.
+
+Controllers have a hardware-defined limit as to the number of ERST
+entries they can process, but with up to 32k it can be excessively high
+(sec 5.3.4). So cap the actual number at 2 (configurable through the
+ERST_MAX_SEGS macro), which seems like a reasonable quantity. It is
+supported by any xHC because the limit in the HCSPARAMS2 register is
+defined as a power of 2. Renesas uPD720201 and VIA VL805 controllers
+do not support more than 2 ERST entries.
+
+An alternative to increasing the number of Event Ring segments would be
+an increase of the segment size. But that requires allocating multiple
+contiguous pages, which may be impossible if memory is fragmented.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
+Signed-off-by: Lukas Wunner <lukas@wunner.de>
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20231019102924.2797346-6-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: bea5892d0ed2 ("xhci: Limit time spent with xHC interrupts disabled during bus resume")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-mem.c | 10 +++++++---
+ drivers/usb/host/xhci.h | 5 +++--
+ 2 files changed, 10 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
+index f236fba5cd248..45240299fa171 100644
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -2237,14 +2237,18 @@ xhci_alloc_interrupter(struct xhci_hcd *xhci, gfp_t flags)
+ {
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
+ struct xhci_interrupter *ir;
++ unsigned int num_segs;
+ int ret;
+
+ ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev));
+ if (!ir)
+ return NULL;
+
+- ir->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
+- 0, flags);
++ num_segs = min_t(unsigned int, 1 << HCS_ERST_MAX(xhci->hcs_params2),
++ ERST_MAX_SEGS);
++
++ ir->event_ring = xhci_ring_alloc(xhci, num_segs, 1, TYPE_EVENT, 0,
++ flags);
+ if (!ir->event_ring) {
+ xhci_warn(xhci, "Failed to allocate interrupter event ring\n");
+ kfree(ir);
+@@ -2280,7 +2284,7 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
+ /* 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;
++ erst_size |= ir->event_ring->num_segs;
+ writel(erst_size, &ir->ir_set->erst_size);
+
+ erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index 0325fccfaa2a4..76a3010b8b74a 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1427,8 +1427,9 @@ struct urb_priv {
+ * Each segment table entry is 4*32bits long. 1K seems like an ok size:
+ * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table,
+ * meaning 64 ring segments.
+- * Initial allocated size of the ERST, in number of entries */
+-#define ERST_NUM_SEGS 1
++ * Reasonable limit for number of Event Ring segments (spec allows 32k)
++ */
++#define ERST_MAX_SEGS 2
+ /* Poll every 60 seconds */
+ #define POLL_TIMEOUT 60
+ /* Stop endpoint command timeout (secs) for URB cancellation watchdog timer */
+--
+2.39.5
+