]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 6.6
authorSasha Levin <sashal@kernel.org>
Wed, 7 May 2025 15:36:15 +0000 (11:36 -0400)
committerSasha Levin <sashal@kernel.org>
Wed, 7 May 2025 15:36:15 +0000 (11:36 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
29 files changed:
queue-6.6/arm-dts-opos6ul-add-ksz8081-phy-properties.patch [new file with mode: 0644]
queue-6.6/arm64-dts-st-adjust-interrupt-controller-for-stm32mp.patch [new file with mode: 0644]
queue-6.6/arm64-dts-st-use-128kb-size-for-aliased-gic400-regis.patch [new file with mode: 0644]
queue-6.6/cpufreq-intel_pstate-do-not-update-global.turbo_disa.patch [new file with mode: 0644]
queue-6.6/cpufreq-intel_pstate-fold-intel_pstate_max_within_li.patch [new file with mode: 0644]
queue-6.6/cpufreq-intel_pstate-revise-global-turbo-disable-che.patch [new file with mode: 0644]
queue-6.6/cpufreq-intel_pstate-unchecked-msr-aceess-in-legacy-.patch [new file with mode: 0644]
queue-6.6/drivers-base-handle-module_kobject-creation.patch [new file with mode: 0644]
queue-6.6/drm-amd-display-add-scoped-mutexes-for-amdgpu_dm_dhc.patch [new file with mode: 0644]
queue-6.6/drm-amd-display-fix-slab-use-after-free-in-hdcp.patch [new file with mode: 0644]
queue-6.6/firmware-arm_ffa-skip-rx-buffer-ownership-release-if.patch [new file with mode: 0644]
queue-6.6/firmware-arm_scmi-balance-device-refcount-when-destr.patch [new file with mode: 0644]
queue-6.6/iommu-arm-smmu-v3-fix-iommu_device_probe-bug-due-to-.patch [new file with mode: 0644]
queue-6.6/iommu-arm-smmu-v3-use-the-new-rb-tree-helpers.patch [new file with mode: 0644]
queue-6.6/kernel-globalize-lookup_or_create_module_kobject.patch [new file with mode: 0644]
queue-6.6/kernel-param-rename-locate_module_kobject.patch [new file with mode: 0644]
queue-6.6/memcg-drain-obj-stock-on-cpu-hotplug-teardown.patch [new file with mode: 0644]
queue-6.6/revert-drm-meson-vclk-fix-calculation-of-59.94-fract.patch [new file with mode: 0644]
queue-6.6/riscv-uprobes-add-missing-fence.i-after-building-the.patch [new file with mode: 0644]
queue-6.6/series
queue-6.6/usb-xhci-check-if-requested-segments-exceeds-erst-ca.patch [new file with mode: 0644]
queue-6.6/xhci-add-helper-to-set-an-interrupters-interrupt-mod.patch [new file with mode: 0644]
queue-6.6/xhci-add-support-to-allocate-several-interrupters.patch [new file with mode: 0644]
queue-6.6/xhci-clean-up-stale-comment-on-erst_size-macro.patch [new file with mode: 0644]
queue-6.6/xhci-limit-time-spent-with-xhc-interrupts-disabled-d.patch [new file with mode: 0644]
queue-6.6/xhci-set-desi-bits-in-erdp-register-correctly.patch [new file with mode: 0644]
queue-6.6/xhci-split-free-interrupter-into-separate-remove-and.patch [new file with mode: 0644]
queue-6.6/xhci-support-setting-interrupt-moderation-imod-for-s.patch [new file with mode: 0644]
queue-6.6/xhci-use-more-than-one-event-ring-segment.patch [new file with mode: 0644]

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