From: Sasha Levin Date: Wed, 7 May 2025 15:36:15 +0000 (-0400) Subject: Fixes for 6.6 X-Git-Tag: v5.15.182~24 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e6fd124f3646f1d4a483d866f627a8c9c5943a69;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 6.6 Signed-off-by: Sasha Levin --- diff --git a/queue-6.6/arm-dts-opos6ul-add-ksz8081-phy-properties.patch b/queue-6.6/arm-dts-opos6ul-add-ksz8081-phy-properties.patch new file mode 100644 index 0000000000..a7be7e796b --- /dev/null +++ b/queue-6.6/arm-dts-opos6ul-add-ksz8081-phy-properties.patch @@ -0,0 +1,44 @@ +From 1aadaa1217609ff4e1723af15d1b7014e86866a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Oleksij Rempel +Signed-off-by: Shawn Guo +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/arm64-dts-st-adjust-interrupt-controller-for-stm32mp.patch b/queue-6.6/arm64-dts-st-adjust-interrupt-controller-for-stm32mp.patch new file mode 100644 index 0000000000..60b213a5fa --- /dev/null +++ b/queue-6.6/arm64-dts-st-adjust-interrupt-controller-for-stm32mp.patch @@ -0,0 +1,39 @@ +From f6eb25904b67b34ecfa7420a1d11a5ce303d5213 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 28 Apr 2025 14:06:58 +0200 +Subject: arm64: dts: st: Adjust interrupt-controller for stm32mp25 SoCs + +From: Christian Bruel + +[ 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 +Link: https://lore.kernel.org/r/20250415111654.2103767-2-christian.bruel@foss.st.com +Signed-off-by: Alexandre Torgue +Signed-off-by: Arnd Bergmann +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/arm64-dts-st-use-128kb-size-for-aliased-gic400-regis.patch b/queue-6.6/arm64-dts-st-use-128kb-size-for-aliased-gic400-regis.patch new file mode 100644 index 0000000000..3db380d2d2 --- /dev/null +++ b/queue-6.6/arm64-dts-st-use-128kb-size-for-aliased-gic400-regis.patch @@ -0,0 +1,48 @@ +From 452e47e89885b1a6c3c5927670273bf9ebc7cbee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Christian Bruel +Acked-by: Marc Zyngier +Link: https://lore.kernel.org/r/20250415111654.2103767-3-christian.bruel@foss.st.com +Signed-off-by: Alexandre Torgue +Signed-off-by: Arnd Bergmann +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/cpufreq-intel_pstate-do-not-update-global.turbo_disa.patch b/queue-6.6/cpufreq-intel_pstate-do-not-update-global.turbo_disa.patch new file mode 100644 index 0000000000..f4e52e0460 --- /dev/null +++ b/queue-6.6/cpufreq-intel_pstate-do-not-update-global.turbo_disa.patch @@ -0,0 +1,196 @@ +From 4629e907d1ba9d61016ecf1db2f068f697337979 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Acked-by: Srinivas Pandruvada +Stable-dep-of: ac4e04d9e378 ("cpufreq: intel_pstate: Unchecked MSR aceess in legacy mode") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/cpufreq-intel_pstate-fold-intel_pstate_max_within_li.patch b/queue-6.6/cpufreq-intel_pstate-fold-intel_pstate_max_within_li.patch new file mode 100644 index 0000000000..7f1747484c --- /dev/null +++ b/queue-6.6/cpufreq-intel_pstate-fold-intel_pstate_max_within_li.patch @@ -0,0 +1,61 @@ +From dc370f49bc51fd5519a1e4805969faf0fc904cdf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ Upstream commit 032c5565eb80edb6f2faeb31939540c897987119 ] + +Fold intel_pstate_max_within_limits() into its only caller. + +No functional impact. + +Signed-off-by: Rafael J. Wysocki +Acked-by: Srinivas Pandruvada +Stable-dep-of: ac4e04d9e378 ("cpufreq: intel_pstate: Unchecked MSR aceess in legacy mode") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/cpufreq-intel_pstate-revise-global-turbo-disable-che.patch b/queue-6.6/cpufreq-intel_pstate-revise-global-turbo-disable-che.patch new file mode 100644 index 0000000000..01018f84b1 --- /dev/null +++ b/queue-6.6/cpufreq-intel_pstate-revise-global-turbo-disable-che.patch @@ -0,0 +1,69 @@ +From 0613992e81ad391f9dc4473a79b0ce9781d39249 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 Sep 2023 11:02:07 -0700 +Subject: cpufreq: intel_pstate: Revise global turbo disable check + +From: Srinivas Pandruvada + +[ 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 +[ rjw: Subject edit ] +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: ac4e04d9e378 ("cpufreq: intel_pstate: Unchecked MSR aceess in legacy mode") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/cpufreq-intel_pstate-unchecked-msr-aceess-in-legacy-.patch b/queue-6.6/cpufreq-intel_pstate-unchecked-msr-aceess-in-legacy-.patch new file mode 100644 index 0000000000..a4cb0110dc --- /dev/null +++ b/queue-6.6/cpufreq-intel_pstate-unchecked-msr-aceess-in-legacy-.patch @@ -0,0 +1,65 @@ +From bef81dac54cd5941e5e251289beb60e386ac0c46 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 29 Apr 2025 14:07:11 -0700 +Subject: cpufreq: intel_pstate: Unchecked MSR aceess in legacy mode + +From: Srinivas Pandruvada + +[ 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 +Cc: All applicable +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/drivers-base-handle-module_kobject-creation.patch b/queue-6.6/drivers-base-handle-module_kobject-creation.patch new file mode 100644 index 0000000000..beb8b0d7e4 --- /dev/null +++ b/queue-6.6/drivers-base-handle-module_kobject-creation.patch @@ -0,0 +1,65 @@ +From 27977bb1ae024cdd597740e261fa5027fccd8442 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Feb 2025 10:49:30 -0800 +Subject: drivers: base: handle module_kobject creation + +From: Shyam Saini + +[ Upstream commit f95bbfe18512c5c018720468959edac056a17196 ] + +module_add_driver() relies on module_kset list for +/sys/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//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 +Signed-off-by: Shyam Saini +Acked-by: Greg Kroah-Hartman +Link: https://lore.kernel.org/r/20250227184930.34163-5-shyamsaini@linux.microsoft.com +Signed-off-by: Petr Pavlu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/drm-amd-display-add-scoped-mutexes-for-amdgpu_dm_dhc.patch b/queue-6.6/drm-amd-display-add-scoped-mutexes-for-amdgpu_dm_dhc.patch new file mode 100644 index 0000000000..3a2d3406e9 --- /dev/null +++ b/queue-6.6/drm-amd-display-add-scoped-mutexes-for-amdgpu_dm_dhc.patch @@ -0,0 +1,205 @@ +From 498e1b5a4218c165a5dc6f52c479bf59d6ae8705 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Feb 2025 13:30:01 -0600 +Subject: drm/amd/display: Add scoped mutexes for amdgpu_dm_dhcp + +From: Mario Limonciello + +[ 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 +Signed-off-by: Mario Limonciello +Signed-off-by: Tom Chung +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +Stable-dep-of: be593d9d91c5 ("drm/amd/display: Fix slab-use-after-free in hdcp") +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.6/drm-amd-display-fix-slab-use-after-free-in-hdcp.patch b/queue-6.6/drm-amd-display-fix-slab-use-after-free-in-hdcp.patch new file mode 100644 index 0000000000..38aa005480 --- /dev/null +++ b/queue-6.6/drm-amd-display-fix-slab-use-after-free-in-hdcp.patch @@ -0,0 +1,177 @@ +From 93a1cd6ca20e9d8a9cbf55c01d06a20bd878e599 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 17 Apr 2025 16:50:05 -0500 +Subject: drm/amd/display: Fix slab-use-after-free in hdcp + +From: Chris Bainbridge + +[ 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] +[ 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] + +[ 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 +Fixes: da3fd7ac0bcf3 ("drm/amd/display: Update CP property based on HW query") +Reviewed-by: Alex Hung +Link: https://lore.kernel.org/r/20250417215005.37964-1-mario.limonciello@amd.com +Signed-off-by: Mario Limonciello +Signed-off-by: Alex Deucher +(cherry picked from commit d4673f3c3b3dcb74e36e53cdfc880baa7a87b330) +Cc: stable@vger.kernel.org +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.6/firmware-arm_ffa-skip-rx-buffer-ownership-release-if.patch b/queue-6.6/firmware-arm_ffa-skip-rx-buffer-ownership-release-if.patch new file mode 100644 index 0000000000..d46842e75f --- /dev/null +++ b/queue-6.6/firmware-arm_ffa-skip-rx-buffer-ownership-release-if.patch @@ -0,0 +1,52 @@ +From 3144d01904d30ea08a72567b68ae3d3ea80e9855 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/firmware-arm_scmi-balance-device-refcount-when-destr.patch b/queue-6.6/firmware-arm_scmi-balance-device-refcount-when-destr.patch new file mode 100644 index 0000000000..eaf831eae3 --- /dev/null +++ b/queue-6.6/firmware-arm_scmi-balance-device-refcount-when-destr.patch @@ -0,0 +1,86 @@ +From 6e7a60324564d3d7d359dce0b8eef74161449426 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Mar 2025 18:54:47 +0000 +Subject: firmware: arm_scmi: Balance device refcount when destroying devices + +From: Cristian Marussi + +[ 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 +Closes: https://lore.kernel.org/linux-arm-kernel/Z8nK3uFkspy61yjP@arm.com/T/#mc1f73a0ea5e41014fa145147b7b839fc988ada8f +CC: Sudeep Holla +CC: Catalin Marinas +Fixes: d4f9dddd21f3 ("firmware: arm_scmi: Add dynamic scmi devices creation") +Signed-off-by: Cristian Marussi +Tested-by: Alice Ryhl +Message-Id: <20250306185447.2039336-1-cristian.marussi@arm.com> +Signed-off-by: Sudeep Holla +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/iommu-arm-smmu-v3-fix-iommu_device_probe-bug-due-to-.patch b/queue-6.6/iommu-arm-smmu-v3-fix-iommu_device_probe-bug-due-to-.patch new file mode 100644 index 0000000000..1e01fa9e1d --- /dev/null +++ b/queue-6.6/iommu-arm-smmu-v3-fix-iommu_device_probe-bug-due-to-.patch @@ -0,0 +1,123 @@ +From dfcd5bb06d22f9dbfb4679b5cb6fc688aec9f7fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Jason Gunthorpe +Signed-off-by: Nicolin Chen +Link: https://lore.kernel.org/r/20250415185620.504299-1-nicolinc@nvidia.com +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/iommu-arm-smmu-v3-use-the-new-rb-tree-helpers.patch b/queue-6.6/iommu-arm-smmu-v3-use-the-new-rb-tree-helpers.patch new file mode 100644 index 0000000000..3745d28547 --- /dev/null +++ b/queue-6.6/iommu-arm-smmu-v3-use-the-new-rb-tree-helpers.patch @@ -0,0 +1,140 @@ +From c4262534abca77f4b690a5597904715dc5d3b285 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Aug 2024 20:31:15 -0300 +Subject: iommu/arm-smmu-v3: Use the new rb tree helpers + +From: Jason Gunthorpe + +[ 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 +Reviewed-by: Mostafa Saleh +Signed-off-by: Jason Gunthorpe +Link: https://lore.kernel.org/r/1-v3-9fef8cdc2ff6+150d1-smmuv3_tidy_jgg@nvidia.com +Signed-off-by: Will Deacon +Stable-dep-of: b00d24997a11 ("iommu/arm-smmu-v3: Fix iommu_device_probe bug due to duplicated stream ids") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/kernel-globalize-lookup_or_create_module_kobject.patch b/queue-6.6/kernel-globalize-lookup_or_create_module_kobject.patch new file mode 100644 index 0000000000..9f7f1942c5 --- /dev/null +++ b/queue-6.6/kernel-globalize-lookup_or_create_module_kobject.patch @@ -0,0 +1,55 @@ +From 704526e4387c352ceabdb1aa0839cc92151f61b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Feb 2025 10:49:29 -0800 +Subject: kernel: globalize lookup_or_create_module_kobject() + +From: Shyam Saini + +[ 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 +Signed-off-by: Shyam Saini +Link: https://lore.kernel.org/r/20250227184930.34163-4-shyamsaini@linux.microsoft.com +Signed-off-by: Petr Pavlu +Stable-dep-of: f95bbfe18512 ("drivers: base: handle module_kobject creation") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/kernel-param-rename-locate_module_kobject.patch b/queue-6.6/kernel-param-rename-locate_module_kobject.patch new file mode 100644 index 0000000000..7c21739bc2 --- /dev/null +++ b/queue-6.6/kernel-param-rename-locate_module_kobject.patch @@ -0,0 +1,62 @@ +From 64dd9801997c54c334d35d2fb7fd377c0f471a97 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Feb 2025 10:49:27 -0800 +Subject: kernel: param: rename locate_module_kobject + +From: Shyam Saini + +[ 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 +Signed-off-by: Shyam Saini +Link: https://lore.kernel.org/r/20250227184930.34163-2-shyamsaini@linux.microsoft.com +Signed-off-by: Petr Pavlu +Stable-dep-of: f95bbfe18512 ("drivers: base: handle module_kobject creation") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/memcg-drain-obj-stock-on-cpu-hotplug-teardown.patch b/queue-6.6/memcg-drain-obj-stock-on-cpu-hotplug-teardown.patch new file mode 100644 index 0000000000..77734e42ee --- /dev/null +++ b/queue-6.6/memcg-drain-obj-stock-on-cpu-hotplug-teardown.patch @@ -0,0 +1,55 @@ +From 9c1fc2f90d2440c11a4a7b8c8940a953c427448c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 10 Mar 2025 16:09:34 -0700 +Subject: memcg: drain obj stock on cpu hotplug teardown + +From: Shakeel Butt + +[ 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 +Reviewed-by: Roman Gushchin +Acked-by: Johannes Weiner +Cc: Michal Hocko +Cc: Muchun Song +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/revert-drm-meson-vclk-fix-calculation-of-59.94-fract.patch b/queue-6.6/revert-drm-meson-vclk-fix-calculation-of-59.94-fract.patch new file mode 100644 index 0000000000..7426fadcfd --- /dev/null +++ b/queue-6.6/revert-drm-meson-vclk-fix-calculation-of-59.94-fract.patch @@ -0,0 +1,61 @@ +From 8cf3d8db987b12c6e7497717f4145beb174ff190 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 21 Apr 2025 22:12:59 +0200 +Subject: Revert "drm/meson: vclk: fix calculation of 59.94 fractional rates" + +From: Christian Hewitt + +[ 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 +Signed-off-by: Martin Blumenstingl +Reviewed-by: Neil Armstrong +Link: https://lore.kernel.org/r/20250421201300.778955-2-martin.blumenstingl@googlemail.com +Signed-off-by: Neil Armstrong +Link: https://lore.kernel.org/r/20250421201300.778955-2-martin.blumenstingl@googlemail.com +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/riscv-uprobes-add-missing-fence.i-after-building-the.patch b/queue-6.6/riscv-uprobes-add-missing-fence.i-after-building-the.patch new file mode 100644 index 0000000000..e66f0bf6aa --- /dev/null +++ b/queue-6.6/riscv-uprobes-add-missing-fence.i-after-building-the.patch @@ -0,0 +1,61 @@ +From 0e8d55306ed936412969e644752ba4679da22d18 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Fixes: 74784081aac8 ("riscv: Add uprobes supported") +Signed-off-by: Björn Töpel +Link: https://lore.kernel.org/r/20250419111402.1660267-2-bjorn@kernel.org +Signed-off-by: Palmer Dabbelt +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/series b/queue-6.6/series index d7b46f12f0..cc4411a7bd 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -101,3 +101,31 @@ sch_drr-make-drr_qlen_notify-idempotent.patch 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 diff --git a/queue-6.6/usb-xhci-check-if-requested-segments-exceeds-erst-ca.patch b/queue-6.6/usb-xhci-check-if-requested-segments-exceeds-erst-ca.patch new file mode 100644 index 0000000000..f6f9106493 --- /dev/null +++ b/queue-6.6/usb-xhci-check-if-requested-segments-exceeds-erst-ca.patch @@ -0,0 +1,118 @@ +From 7fcd3d6a290f530aac53f8b851188c6b827826b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Apr 2024 17:02:30 +0300 +Subject: usb: xhci: check if 'requested segments' exceeds ERST capacity + +From: Niklas Neronin + +[ 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 +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20240429140245.3955523-4-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: bea5892d0ed2 ("xhci: Limit time spent with xHC interrupts disabled during bus resume") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/xhci-add-helper-to-set-an-interrupters-interrupt-mod.patch b/queue-6.6/xhci-add-helper-to-set-an-interrupters-interrupt-mod.patch new file mode 100644 index 0000000000..e0819ab53c --- /dev/null +++ b/queue-6.6/xhci-add-helper-to-set-an-interrupters-interrupt-mod.patch @@ -0,0 +1,82 @@ +From 607df2d76302cdc87ade4749e1cbab02a97820e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Feb 2024 16:09:28 -0800 +Subject: xhci: Add helper to set an interrupters interrupt moderation interval + +From: Mathias Nyman + +[ 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 +Signed-off-by: Wesley Cheng +Link: https://lore.kernel.org/r/20240217001017.29969-3-quic_wcheng@quicinc.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: bea5892d0ed2 ("xhci: Limit time spent with xHC interrupts disabled during bus resume") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/xhci-add-support-to-allocate-several-interrupters.patch b/queue-6.6/xhci-add-support-to-allocate-several-interrupters.patch new file mode 100644 index 0000000000..bca068ccbc --- /dev/null +++ b/queue-6.6/xhci-add-support-to-allocate-several-interrupters.patch @@ -0,0 +1,380 @@ +From d0683ab97a4f20009d71afc1ba1d7751ecbb4dbd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jan 2024 13:45:09 -0800 +Subject: xhci: add support to allocate several interrupters + +From: Mathias Nyman + +[ 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 +Signed-off-by: Wesley Cheng +Link: https://lore.kernel.org/r/20240102214549.22498-2-quic_wcheng@quicinc.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: bea5892d0ed2 ("xhci: Limit time spent with xHC interrupts disabled during bus resume") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/xhci-clean-up-stale-comment-on-erst_size-macro.patch b/queue-6.6/xhci-clean-up-stale-comment-on-erst_size-macro.patch new file mode 100644 index 0000000000..6b4588103f --- /dev/null +++ b/queue-6.6/xhci-clean-up-stale-comment-on-erst_size-macro.patch @@ -0,0 +1,46 @@ +From a8aec2bed006c5b782322beacbf863e4e73f3b42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Oct 2023 13:29:15 +0300 +Subject: xhci: Clean up stale comment on ERST_SIZE macro + +From: Lukas Wunner + +[ 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 +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20231019102924.2797346-11-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: bea5892d0ed2 ("xhci: Limit time spent with xHC interrupts disabled during bus resume") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/xhci-limit-time-spent-with-xhc-interrupts-disabled-d.patch b/queue-6.6/xhci-limit-time-spent-with-xhc-interrupts-disabled-d.patch new file mode 100644 index 0000000000..733b3a9d13 --- /dev/null +++ b/queue-6.6/xhci-limit-time-spent-with-xhc-interrupts-disabled-d.patch @@ -0,0 +1,150 @@ +From b825219fc4a0d3fb17f12d0b7fffeb52fba46a8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 10 Apr 2025 18:18:27 +0300 +Subject: xhci: Limit time spent with xHC interrupts disabled during bus resume + +From: Mathias Nyman + +[ 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 +Closes: https://lore.kernel.org/linux-usb/b1a9e2d51b4d4ff7a304f77c5be8164e@huawei.com/ +Cc: stable@vger.kernel.org +Tested-by: Devyn Liu +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20250410151828.2868740-6-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/xhci-set-desi-bits-in-erdp-register-correctly.patch b/queue-6.6/xhci-set-desi-bits-in-erdp-register-correctly.patch new file mode 100644 index 0000000000..d1a4dbbd66 --- /dev/null +++ b/queue-6.6/xhci-set-desi-bits-in-erdp-register-correctly.patch @@ -0,0 +1,176 @@ +From 80f6ce2accf243214c5936163e748097190727cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Oct 2023 13:29:09 +0300 +Subject: xhci: Set DESI bits in ERDP register correctly + +From: Lukas Wunner + +[ 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 +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20231019102924.2797346-5-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: bea5892d0ed2 ("xhci: Limit time spent with xHC interrupts disabled during bus resume") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/xhci-split-free-interrupter-into-separate-remove-and.patch b/queue-6.6/xhci-split-free-interrupter-into-separate-remove-and.patch new file mode 100644 index 0000000000..55dcb0ef30 --- /dev/null +++ b/queue-6.6/xhci-split-free-interrupter-into-separate-remove-and.patch @@ -0,0 +1,96 @@ +From e0c49bbfa6cb34184dfdc15d28550adfc5d56e1d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Oct 2023 13:29:21 +0300 +Subject: xhci: split free interrupter into separate remove and free parts + +From: Mathias Nyman + +[ 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 +Link: https://lore.kernel.org/r/20231019102924.2797346-17-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: bea5892d0ed2 ("xhci: Limit time spent with xHC interrupts disabled during bus resume") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/xhci-support-setting-interrupt-moderation-imod-for-s.patch b/queue-6.6/xhci-support-setting-interrupt-moderation-imod-for-s.patch new file mode 100644 index 0000000000..1eef269854 --- /dev/null +++ b/queue-6.6/xhci-support-setting-interrupt-moderation-imod-for-s.patch @@ -0,0 +1,95 @@ +From b1b09800645a0e32d06d07d937435ff9015d44d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Sep 2024 17:33:00 +0300 +Subject: xhci: support setting interrupt moderation IMOD for secondary + interrupters + +From: Mathias Nyman + +[ 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 +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20240905143300.1959279-13-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: bea5892d0ed2 ("xhci: Limit time spent with xHC interrupts disabled during bus resume") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/xhci-use-more-than-one-event-ring-segment.patch b/queue-6.6/xhci-use-more-than-one-event-ring-segment.patch new file mode 100644 index 0000000000..1b197746e1 --- /dev/null +++ b/queue-6.6/xhci-use-more-than-one-event-ring-segment.patch @@ -0,0 +1,100 @@ +From 472d3ea2abf38ecf28b5380d6c92cf5be2de95a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Oct 2023 13:29:10 +0300 +Subject: xhci: Use more than one Event Ring segment + +From: Jonathan Bell + +[ 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 +Signed-off-by: Lukas Wunner +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20231019102924.2797346-6-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: bea5892d0ed2 ("xhci: Limit time spent with xHC interrupts disabled during bus resume") +Signed-off-by: Sasha Levin +--- + 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 +