]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 6.1
authorSasha Levin <sashal@kernel.org>
Wed, 7 May 2025 15:36:16 +0000 (11:36 -0400)
committerSasha Levin <sashal@kernel.org>
Wed, 7 May 2025 15:36:16 +0000 (11:36 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
25 files changed:
queue-6.1/arm-dts-opos6ul-add-ksz8081-phy-properties.patch [new file with mode: 0644]
queue-6.1/asoc-soc-core-stop-using-of_property_read_bool-for-n.patch [new file with mode: 0644]
queue-6.1/asoc-use-of_property_read_bool.patch [new file with mode: 0644]
queue-6.1/cpufreq-intel_pstate-do-not-update-global.turbo_disa.patch [new file with mode: 0644]
queue-6.1/cpufreq-intel_pstate-fold-intel_pstate_max_within_li.patch [new file with mode: 0644]
queue-6.1/cpufreq-intel_pstate-revise-global-turbo-disable-che.patch [new file with mode: 0644]
queue-6.1/cpufreq-intel_pstate-unchecked-msr-aceess-in-legacy-.patch [new file with mode: 0644]
queue-6.1/drm-amd-display-add-scoped-mutexes-for-amdgpu_dm_dhc.patch [new file with mode: 0644]
queue-6.1/drm-amd-display-change-hdcp-update-sequence-for-dm.patch [new file with mode: 0644]
queue-6.1/drm-amd-display-clean-up-style-problems-in-amdgpu_dm.patch [new file with mode: 0644]
queue-6.1/drm-amd-display-fix-slab-use-after-free-in-hdcp.patch [new file with mode: 0644]
queue-6.1/drm-amd-display-phase2-enable-mst-hdcp-multiple-disp.patch [new file with mode: 0644]
queue-6.1/firmware-arm_ffa-skip-rx-buffer-ownership-release-if.patch [new file with mode: 0644]
queue-6.1/firmware-arm_scmi-balance-device-refcount-when-destr.patch [new file with mode: 0644]
queue-6.1/iommu-arm-smmu-v3-fix-iommu_device_probe-bug-due-to-.patch [new file with mode: 0644]
queue-6.1/iommu-arm-smmu-v3-use-the-new-rb-tree-helpers.patch [new file with mode: 0644]
queue-6.1/irqchip-gic-v2m-mark-a-few-functions-__init.patch [new file with mode: 0644]
queue-6.1/irqchip-gic-v2m-prevent-use-after-free-of-gicv2m_get.patch [new file with mode: 0644]
queue-6.1/memcg-drain-obj-stock-on-cpu-hotplug-teardown.patch [new file with mode: 0644]
queue-6.1/net-phy-microchip-force-irq-polling-mode-for-lan88xx.patch [new file with mode: 0644]
queue-6.1/revert-drm-meson-vclk-fix-calculation-of-59.94-fract.patch [new file with mode: 0644]
queue-6.1/riscv-uprobes-add-missing-fence.i-after-building-the.patch [new file with mode: 0644]
queue-6.1/series
queue-6.1/spi-tegra114-don-t-fail-set_cs_timing-when-delays-ar.patch [new file with mode: 0644]
queue-6.1/spi-tegra114-remove-unnecessary-null-pointer-checks.patch [new file with mode: 0644]

diff --git a/queue-6.1/arm-dts-opos6ul-add-ksz8081-phy-properties.patch b/queue-6.1/arm-dts-opos6ul-add-ksz8081-phy-properties.patch
new file mode 100644 (file)
index 0000000..901de03
--- /dev/null
@@ -0,0 +1,44 @@
+From 503eccd1d48069fb548593d9b900b3c9181ff279 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/imx6ul-imx6ull-opos6ul.dtsi | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/arch/arm/boot/dts/imx6ul-imx6ull-opos6ul.dtsi b/arch/arm/boot/dts/imx6ul-imx6ull-opos6ul.dtsi
+index f2386dcb9ff2c..dda4fa91b2f2c 100644
+--- a/arch/arm/boot/dts/imx6ul-imx6ull-opos6ul.dtsi
++++ b/arch/arm/boot/dts/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.1/asoc-soc-core-stop-using-of_property_read_bool-for-n.patch b/queue-6.1/asoc-soc-core-stop-using-of_property_read_bool-for-n.patch
new file mode 100644 (file)
index 0000000..cd01209
--- /dev/null
@@ -0,0 +1,101 @@
+From 8a3dcc949925103d1f19b2acb48f86a5a5311af4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 22 Jan 2025 09:21:27 +0100
+Subject: ASoC: soc-core: Stop using of_property_read_bool() for non-boolean
+ properties
+
+From: Geert Uytterhoeven <geert+renesas@glider.be>
+
+[ Upstream commit 6eab7034579917f207ca6d8e3f4e11e85e0ab7d5 ]
+
+On R-Car:
+
+    OF: /sound: Read of boolean property 'simple-audio-card,bitclock-master' with a value.
+    OF: /sound: Read of boolean property 'simple-audio-card,frame-master' with a value.
+
+or:
+
+    OF: /soc/sound@ec500000/ports/port@0/endpoint: Read of boolean property 'bitclock-master' with a value.
+    OF: /soc/sound@ec500000/ports/port@0/endpoint: Read of boolean property 'frame-master' with a value.
+
+The use of of_property_read_bool() for non-boolean properties is
+deprecated in favor of of_property_present() when testing for property
+presence.
+
+Replace testing for presence before calling of_property_read_u32() by
+testing for an -EINVAL return value from the latter, to simplify the
+code.
+
+Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Link: https://patch.msgid.link/db10e96fbda121e7456d70e97a013cbfc9755f4d.1737533954.git.geert+renesas@glider.be
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/soc-core.c | 32 +++++++++++++-------------------
+ 1 file changed, 13 insertions(+), 19 deletions(-)
+
+diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
+index 58e07296144e0..b13370d2ec1d7 100644
+--- a/sound/soc/soc-core.c
++++ b/sound/soc/soc-core.c
+@@ -2837,7 +2837,7 @@ int snd_soc_of_parse_pin_switches(struct snd_soc_card *card, const char *prop)
+       unsigned int i, nb_controls;
+       int ret;
+-      if (!of_property_read_bool(dev->of_node, prop))
++      if (!of_property_present(dev->of_node, prop))
+               return 0;
+       strings = devm_kcalloc(dev, nb_controls_max,
+@@ -2911,23 +2911,17 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np,
+       if (rx_mask)
+               snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask", rx_mask);
+-      if (of_property_read_bool(np, "dai-tdm-slot-num")) {
+-              ret = of_property_read_u32(np, "dai-tdm-slot-num", &val);
+-              if (ret)
+-                      return ret;
+-
+-              if (slots)
+-                      *slots = val;
+-      }
+-
+-      if (of_property_read_bool(np, "dai-tdm-slot-width")) {
+-              ret = of_property_read_u32(np, "dai-tdm-slot-width", &val);
+-              if (ret)
+-                      return ret;
++      ret = of_property_read_u32(np, "dai-tdm-slot-num", &val);
++      if (ret && ret != -EINVAL)
++              return ret;
++      if (!ret && slots)
++              *slots = val;
+-              if (slot_width)
+-                      *slot_width = val;
+-      }
++      ret = of_property_read_u32(np, "dai-tdm-slot-width", &val);
++      if (ret && ret != -EINVAL)
++              return ret;
++      if (!ret && slot_width)
++              *slot_width = val;
+       return 0;
+ }
+@@ -3183,12 +3177,12 @@ unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np,
+        * check "[prefix]frame-master"
+        */
+       snprintf(prop, sizeof(prop), "%sbitclock-master", prefix);
+-      bit = of_property_read_bool(np, prop);
++      bit = of_property_present(np, prop);
+       if (bit && bitclkmaster)
+               *bitclkmaster = of_parse_phandle(np, prop, 0);
+       snprintf(prop, sizeof(prop), "%sframe-master", prefix);
+-      frame = of_property_read_bool(np, prop);
++      frame = of_property_present(np, prop);
+       if (frame && framemaster)
+               *framemaster = of_parse_phandle(np, prop, 0);
+-- 
+2.39.5
+
diff --git a/queue-6.1/asoc-use-of_property_read_bool.patch b/queue-6.1/asoc-use-of_property_read_bool.patch
new file mode 100644 (file)
index 0000000..14587a7
--- /dev/null
@@ -0,0 +1,81 @@
+From 4acb7b8349c6eeb995c887f03f9d39c90707270b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 31 Jul 2024 13:12:58 -0600
+Subject: ASoC: Use of_property_read_bool()
+
+From: Rob Herring (Arm) <robh@kernel.org>
+
+[ Upstream commit 69dd15a8ef0ae494179fd15023aa8172188db6b7 ]
+
+Use of_property_read_bool() to read boolean properties rather than
+of_get_property(). This is part of a larger effort to remove callers
+of of_get_property() and similar functions. of_get_property() leaks
+the DT property data pointer which is a problem for dynamically
+allocated nodes which may be freed.
+
+Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
+Link: https://patch.msgid.link/20240731191312.1710417-20-robh@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: 6eab70345799 ("ASoC: soc-core: Stop using of_property_read_bool() for non-boolean properties")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/ak4613.c | 4 ++--
+ sound/soc/soc-core.c      | 8 ++++----
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
+index f75c19ef35511..3f790d1f11a94 100644
+--- a/sound/soc/codecs/ak4613.c
++++ b/sound/soc/codecs/ak4613.c
+@@ -840,14 +840,14 @@ static void ak4613_parse_of(struct ak4613_priv *priv,
+       /* Input 1 - 2 */
+       for (i = 0; i < 2; i++) {
+               snprintf(prop, sizeof(prop), "asahi-kasei,in%d-single-end", i + 1);
+-              if (!of_get_property(np, prop, NULL))
++              if (!of_property_read_bool(np, prop))
+                       priv->ic |= 1 << i;
+       }
+       /* Output 1 - 6 */
+       for (i = 0; i < 6; i++) {
+               snprintf(prop, sizeof(prop), "asahi-kasei,out%d-single-end", i + 1);
+-              if (!of_get_property(np, prop, NULL))
++              if (!of_property_read_bool(np, prop))
+                       priv->oc |= 1 << i;
+       }
+diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
+index 6a4101dc15a54..58e07296144e0 100644
+--- a/sound/soc/soc-core.c
++++ b/sound/soc/soc-core.c
+@@ -3143,10 +3143,10 @@ unsigned int snd_soc_daifmt_parse_format(struct device_node *np,
+        * SND_SOC_DAIFMT_INV_MASK area
+        */
+       snprintf(prop, sizeof(prop), "%sbitclock-inversion", prefix);
+-      bit = !!of_get_property(np, prop, NULL);
++      bit = of_property_read_bool(np, prop);
+       snprintf(prop, sizeof(prop), "%sframe-inversion", prefix);
+-      frame = !!of_get_property(np, prop, NULL);
++      frame = of_property_read_bool(np, prop);
+       switch ((bit << 4) + frame) {
+       case 0x11:
+@@ -3183,12 +3183,12 @@ unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np,
+        * check "[prefix]frame-master"
+        */
+       snprintf(prop, sizeof(prop), "%sbitclock-master", prefix);
+-      bit = !!of_get_property(np, prop, NULL);
++      bit = of_property_read_bool(np, prop);
+       if (bit && bitclkmaster)
+               *bitclkmaster = of_parse_phandle(np, prop, 0);
+       snprintf(prop, sizeof(prop), "%sframe-master", prefix);
+-      frame = !!of_get_property(np, prop, NULL);
++      frame = of_property_read_bool(np, prop);
+       if (frame && framemaster)
+               *framemaster = of_parse_phandle(np, prop, 0);
+-- 
+2.39.5
+
diff --git a/queue-6.1/cpufreq-intel_pstate-do-not-update-global.turbo_disa.patch b/queue-6.1/cpufreq-intel_pstate-do-not-update-global.turbo_disa.patch
new file mode 100644 (file)
index 0000000..e270f90
--- /dev/null
@@ -0,0 +1,196 @@
+From 05f4584ff713d6064d7a12ded2952a58cc5c7678 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 e26c0b0096080..18d6d2a357ce1 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;
+ };
+@@ -559,12 +557,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)
+@@ -1119,40 +1118,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);
+ }
+@@ -1252,7 +1227,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
+@@ -1282,7 +1256,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);
+@@ -2253,8 +2226,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);
+@@ -2572,7 +2543,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);
+@@ -2616,7 +2586,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 ?
+@@ -2713,8 +2682,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;
+@@ -2880,8 +2847,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;
+@@ -2903,8 +2868,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);
+@@ -2922,7 +2885,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);
+@@ -3112,6 +3074,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.1/cpufreq-intel_pstate-fold-intel_pstate_max_within_li.patch b/queue-6.1/cpufreq-intel_pstate-fold-intel_pstate_max_within_li.patch
new file mode 100644 (file)
index 0000000..8225c1e
--- /dev/null
@@ -0,0 +1,61 @@
+From 5920bf68fdd391d9ca9c68a0da71b7b0e616aa22 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 faeeef4acdf70..e26c0b0096080 100644
+--- a/drivers/cpufreq/intel_pstate.c
++++ b/drivers/cpufreq/intel_pstate.c
+@@ -1984,14 +1984,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);
+@@ -2573,12 +2565,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.1/cpufreq-intel_pstate-revise-global-turbo-disable-che.patch b/queue-6.1/cpufreq-intel_pstate-revise-global-turbo-disable-che.patch
new file mode 100644 (file)
index 0000000..49443d0
--- /dev/null
@@ -0,0 +1,69 @@
+From a7b500eb867264fb33adcfc8ba370ccd893b0cd2 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 d471d74df3bbb..faeeef4acdf70 100644
+--- a/drivers/cpufreq/intel_pstate.c
++++ b/drivers/cpufreq/intel_pstate.c
+@@ -562,13 +562,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.1/cpufreq-intel_pstate-unchecked-msr-aceess-in-legacy-.patch b/queue-6.1/cpufreq-intel_pstate-unchecked-msr-aceess-in-legacy-.patch
new file mode 100644 (file)
index 0000000..0cd9080
--- /dev/null
@@ -0,0 +1,65 @@
+From eda97920501cd72b95367e79b7345efb45705636 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 18d6d2a357ce1..bc0dec57bc8e2 100644
+--- a/drivers/cpufreq/intel_pstate.c
++++ b/drivers/cpufreq/intel_pstate.c
+@@ -561,6 +561,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.1/drm-amd-display-add-scoped-mutexes-for-amdgpu_dm_dhc.patch b/queue-6.1/drm-amd-display-add-scoped-mutexes-for-amdgpu_dm_dhc.patch
new file mode 100644 (file)
index 0000000..1af24e3
--- /dev/null
@@ -0,0 +1,205 @@
+From d238016ec4e321aa99127854f07f86691d7305a0 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 7c67bb771f996..6222d5a168832 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)
+@@ -326,7 +320,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,
+@@ -358,7 +352,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);
+       }
+ }
+@@ -371,7 +364,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++) {
+@@ -415,8 +408,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)
+@@ -427,7 +418,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);
+@@ -436,8 +427,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)
+@@ -446,13 +435,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)
+@@ -486,7 +473,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;
+@@ -501,8 +488,6 @@ static bool enable_assr(void *handle, struct dc_link *link)
+               res = false;
+       }
+-      mutex_unlock(&psp->dtm_context.mutex);
+-
+       return res;
+ }
+@@ -563,13 +548,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.1/drm-amd-display-change-hdcp-update-sequence-for-dm.patch b/queue-6.1/drm-amd-display-change-hdcp-update-sequence-for-dm.patch
new file mode 100644 (file)
index 0000000..ef6ff28
--- /dev/null
@@ -0,0 +1,163 @@
+From 4f489c9cefe14311c127a2b8341ca34945a7f5a3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Jul 2023 16:32:47 -0400
+Subject: drm/amd/display: Change HDCP update sequence for DM
+
+From: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
+
+[ Upstream commit 393e83484839970e4975dfa1f0666f939a6f3e3d ]
+
+Refactor the sequence in hdcp_update_display() to use
+mod_hdcp_update_display().
+
+Previous sequence:
+       - remove()->add()
+
+This Sequence was used to update the display, (mod_hdcp_update_display
+didn't exist at the time). This meant for any hdcp updates (type changes,
+enable/disable) we would remove, reconstruct, and add. This leads to
+unnecessary calls to psp eventually
+
+New Sequence using mod_hdcp_update_display():
+       - add() once when stream is enabled
+       - use update() for all updates
+
+The update function checks for prev == new states and will not
+unnecessarily end up calling psp via add/remove.
+
+Reviewed-by: Qingqing Zhuo <qingqing.zhuo@amd.com>
+Acked-by: Tom Chung <chiahsuan.chung@amd.com>
+Signed-off-by: Bhawanpreet Lakha <bhawanpreet.lakha@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    | 80 +++++++++----------
+ 1 file changed, 38 insertions(+), 42 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 15537f554ca86..7c67bb771f996 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
+@@ -168,53 +168,45 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
+                        bool enable_encryption)
+ {
+       struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
+-      struct mod_hdcp_display *display = &hdcp_work[link_index].display;
+-      struct mod_hdcp_link *link = &hdcp_work[link_index].link;
+-      struct mod_hdcp_display_query query;
++      struct mod_hdcp_link_adjustment link_adjust;
++      struct mod_hdcp_display_adjustment display_adjust;
+       unsigned int conn_index = aconnector->base.index;
+       mutex_lock(&hdcp_w->mutex);
+       hdcp_w->aconnector[conn_index] = aconnector;
+-      query.display = NULL;
+-      mod_hdcp_query_display(&hdcp_w->hdcp, aconnector->base.index, &query);
+-
+-      if (query.display) {
+-              memcpy(display, query.display, sizeof(struct mod_hdcp_display));
+-              mod_hdcp_remove_display(&hdcp_w->hdcp, aconnector->base.index, &hdcp_w->output);
+-
+-              hdcp_w->link.adjust.hdcp2.force_type = MOD_HDCP_FORCE_TYPE_0;
+-
+-              if (enable_encryption) {
+-                      /* Explicitly set the saved SRM as sysfs call will be after
+-                       * we already enabled hdcp (s3 resume case)
+-                       */
+-                      if (hdcp_work->srm_size > 0)
+-                              psp_set_srm(hdcp_work->hdcp.config.psp.handle, hdcp_work->srm,
+-                                          hdcp_work->srm_size,
+-                                          &hdcp_work->srm_version);
+-
+-                      display->adjust.disable = MOD_HDCP_DISPLAY_NOT_DISABLE;
+-                      if (content_type == DRM_MODE_HDCP_CONTENT_TYPE0) {
+-                              hdcp_w->link.adjust.hdcp1.disable = 0;
+-                              hdcp_w->link.adjust.hdcp2.force_type = MOD_HDCP_FORCE_TYPE_0;
+-                      } else if (content_type == DRM_MODE_HDCP_CONTENT_TYPE1) {
+-                              hdcp_w->link.adjust.hdcp1.disable = 1;
+-                              hdcp_w->link.adjust.hdcp2.force_type = MOD_HDCP_FORCE_TYPE_1;
+-                      }
++      memset(&link_adjust, 0, sizeof(link_adjust));
++      memset(&display_adjust, 0, sizeof(display_adjust));
+-                      schedule_delayed_work(&hdcp_w->property_validate_dwork,
+-                                            msecs_to_jiffies(DRM_HDCP_CHECK_PERIOD_MS));
+-              } else {
+-                      display->adjust.disable = MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION;
+-                      hdcp_w->encryption_status[conn_index] = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
+-                      cancel_delayed_work(&hdcp_w->property_validate_dwork);
++      if (enable_encryption) {
++              /* Explicitly set the saved SRM as sysfs call will be after we already enabled hdcp
++               * (s3 resume case)
++               */
++              if (hdcp_work->srm_size > 0)
++                      psp_set_srm(hdcp_work->hdcp.config.psp.handle, hdcp_work->srm,
++                                  hdcp_work->srm_size,
++                                  &hdcp_work->srm_version);
++
++              display_adjust.disable = MOD_HDCP_DISPLAY_NOT_DISABLE;
++
++              link_adjust.auth_delay = 2;
++
++              if (content_type == DRM_MODE_HDCP_CONTENT_TYPE0) {
++                      link_adjust.hdcp2.force_type = MOD_HDCP_FORCE_TYPE_0;
++              } else if (content_type == DRM_MODE_HDCP_CONTENT_TYPE1) {
++                      link_adjust.hdcp1.disable = 1;
++                      link_adjust.hdcp2.force_type = MOD_HDCP_FORCE_TYPE_1;
+               }
+-              display->state = MOD_HDCP_DISPLAY_ACTIVE;
++              schedule_delayed_work(&hdcp_w->property_validate_dwork,
++                                    msecs_to_jiffies(DRM_HDCP_CHECK_PERIOD_MS));
++      } else {
++              display_adjust.disable = MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION;
++              hdcp_w->encryption_status[conn_index] = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
++              cancel_delayed_work(&hdcp_w->property_validate_dwork);
+       }
+-      mod_hdcp_add_display(&hdcp_w->hdcp, link, display, &hdcp_w->output);
++      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);
+@@ -521,7 +513,7 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
+       int link_index = aconnector->dc_link->link_index;
+       struct mod_hdcp_display *display = &hdcp_work[link_index].display;
+       struct mod_hdcp_link *link = &hdcp_work[link_index].link;
+-      struct drm_connector_state *conn_state;
++      struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
+       struct dc_sink *sink = NULL;
+       bool link_is_hdcp14 = false;
+@@ -563,7 +555,7 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
+       display->adjust.disable = MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION;
+       link->adjust.auth_delay = 3;
+       link->adjust.hdcp1.disable = 0;
+-      conn_state = aconnector->base.state;
++      hdcp_w->encryption_status[display->index] = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
+       DRM_DEBUG_DRIVER("[HDCP_DM] display %d, CP %d, type %d\n", aconnector->base.index,
+                        (!!aconnector->base.state) ?
+@@ -571,9 +563,13 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
+                        (!!aconnector->base.state) ?
+                        aconnector->base.state->hdcp_content_type : -1);
+-      if (conn_state)
+-              hdcp_update_display(hdcp_work, link_index, aconnector,
+-                                  conn_state->hdcp_content_type, false);
++      mutex_lock(&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.1/drm-amd-display-clean-up-style-problems-in-amdgpu_dm.patch b/queue-6.1/drm-amd-display-clean-up-style-problems-in-amdgpu_dm.patch
new file mode 100644 (file)
index 0000000..6056823
--- /dev/null
@@ -0,0 +1,510 @@
+From 51ee25db9428ced71fa4d874256222d611a6770f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Jul 2023 17:10:57 +0530
+Subject: drm/amd/display: Clean up style problems in amdgpu_dm_hdcp.c
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit a19de9dbb4d293c064b02cec8ef134cb9812d639 ]
+
+Conform to Linux kernel coding style.
+
+And promote sysfs entry for set/get srm to kdoc.
+
+Suggested-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Aurabindo Pillai <aurabindo.pillai@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    | 185 +++++++++---------
+ 1 file changed, 89 insertions(+), 96 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 7fc26ca30dcd6..15537f554ca86 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
+@@ -39,10 +39,10 @@
+ static bool
+ lp_write_i2c(void *handle, uint32_t address, const uint8_t *data, uint32_t size)
+ {
+-
+       struct dc_link *link = handle;
+       struct i2c_payload i2c_payloads[] = {{true, address, size, (void *)data} };
+-      struct i2c_command cmd = {i2c_payloads, 1, I2C_COMMAND_ENGINE_HW, link->dc->caps.i2c_speed_in_khz};
++      struct i2c_command cmd = {i2c_payloads, 1, I2C_COMMAND_ENGINE_HW,
++                                link->dc->caps.i2c_speed_in_khz};
+       return dm_helpers_submit_i2c(link->ctx, link, &cmd);
+ }
+@@ -52,8 +52,10 @@ lp_read_i2c(void *handle, uint32_t address, uint8_t offset, uint8_t *data, uint3
+ {
+       struct dc_link *link = handle;
+-      struct i2c_payload i2c_payloads[] = {{true, address, 1, &offset}, {false, address, size, data} };
+-      struct i2c_command cmd = {i2c_payloads, 2, I2C_COMMAND_ENGINE_HW, link->dc->caps.i2c_speed_in_khz};
++      struct i2c_payload i2c_payloads[] = {{true, address, 1, &offset},
++                                           {false, address, size, data} };
++      struct i2c_command cmd = {i2c_payloads, 2, I2C_COMMAND_ENGINE_HW,
++                                link->dc->caps.i2c_speed_in_khz};
+       return dm_helpers_submit_i2c(link->ctx, link, &cmd);
+ }
+@@ -76,7 +78,6 @@ lp_read_dpcd(void *handle, uint32_t address, uint8_t *data, uint32_t size)
+ static uint8_t *psp_get_srm(struct psp_context *psp, uint32_t *srm_version, uint32_t *srm_size)
+ {
+-
+       struct ta_hdcp_shared_memory *hdcp_cmd;
+       if (!psp->hdcp_context.context.initialized) {
+@@ -96,13 +97,12 @@ static uint8_t *psp_get_srm(struct psp_context *psp, uint32_t *srm_version, uint
+       *srm_version = hdcp_cmd->out_msg.hdcp_get_srm.srm_version;
+       *srm_size = hdcp_cmd->out_msg.hdcp_get_srm.srm_buf_size;
+-
+       return hdcp_cmd->out_msg.hdcp_get_srm.srm_buf;
+ }
+-static int psp_set_srm(struct psp_context *psp, uint8_t *srm, uint32_t srm_size, uint32_t *srm_version)
++static int psp_set_srm(struct psp_context *psp,
++                     u8 *srm, uint32_t srm_size, uint32_t *srm_version)
+ {
+-
+       struct ta_hdcp_shared_memory *hdcp_cmd;
+       if (!psp->hdcp_context.context.initialized) {
+@@ -119,7 +119,8 @@ static int psp_set_srm(struct psp_context *psp, uint8_t *srm, uint32_t srm_size,
+       psp_hdcp_invoke(psp, hdcp_cmd->cmd_id);
+-      if (hdcp_cmd->hdcp_status != TA_HDCP_STATUS__SUCCESS || hdcp_cmd->out_msg.hdcp_set_srm.valid_signature != 1 ||
++      if (hdcp_cmd->hdcp_status != TA_HDCP_STATUS__SUCCESS ||
++          hdcp_cmd->out_msg.hdcp_set_srm.valid_signature != 1 ||
+           hdcp_cmd->out_msg.hdcp_set_srm.srm_version == PSP_SRM_VERSION_MAX)
+               return -EINVAL;
+@@ -150,7 +151,6 @@ static void process_output(struct hdcp_workqueue *hdcp_work)
+ static void link_lock(struct hdcp_workqueue *work, bool lock)
+ {
+-
+       int i = 0;
+       for (i = 0; i < work->max_link; i++) {
+@@ -160,10 +160,11 @@ static void link_lock(struct hdcp_workqueue *work, bool lock)
+                       mutex_unlock(&work[i].mutex);
+       }
+ }
++
+ void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
+                        unsigned int link_index,
+                        struct amdgpu_dm_connector *aconnector,
+-                       uint8_t content_type,
++                       u8 content_type,
+                        bool enable_encryption)
+ {
+       struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
+@@ -178,18 +179,19 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
+       query.display = NULL;
+       mod_hdcp_query_display(&hdcp_w->hdcp, aconnector->base.index, &query);
+-      if (query.display != NULL) {
++      if (query.display) {
+               memcpy(display, query.display, sizeof(struct mod_hdcp_display));
+               mod_hdcp_remove_display(&hdcp_w->hdcp, aconnector->base.index, &hdcp_w->output);
+               hdcp_w->link.adjust.hdcp2.force_type = MOD_HDCP_FORCE_TYPE_0;
+               if (enable_encryption) {
+-                      /* Explicitly set the saved SRM as sysfs call will be after we already enabled hdcp
+-                       * (s3 resume case)
++                      /* Explicitly set the saved SRM as sysfs call will be after
++                       * we already enabled hdcp (s3 resume case)
+                        */
+                       if (hdcp_work->srm_size > 0)
+-                              psp_set_srm(hdcp_work->hdcp.config.psp.handle, hdcp_work->srm, hdcp_work->srm_size,
++                              psp_set_srm(hdcp_work->hdcp.config.psp.handle, hdcp_work->srm,
++                                          hdcp_work->srm_size,
+                                           &hdcp_work->srm_version);
+                       display->adjust.disable = MOD_HDCP_DISPLAY_NOT_DISABLE;
+@@ -219,7 +221,7 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
+ }
+ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
+-                       unsigned int link_index,
++                              unsigned int link_index,
+                        struct amdgpu_dm_connector *aconnector)
+ {
+       struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
+@@ -238,7 +240,8 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
+               conn_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+               DRM_DEBUG_DRIVER("[HDCP_DM] display %d, CP 2 -> 1, type %u, DPMS %u\n",
+-                       aconnector->base.index, conn_state->hdcp_content_type, aconnector->base.dpms);
++                               aconnector->base.index, conn_state->hdcp_content_type,
++                               aconnector->base.dpms);
+       }
+       mod_hdcp_remove_display(&hdcp_w->hdcp, aconnector->base.index, &hdcp_w->output);
+@@ -246,6 +249,7 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
+       process_output(hdcp_w);
+       mutex_unlock(&hdcp_w->mutex);
+ }
++
+ void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index)
+ {
+       struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
+@@ -274,15 +278,12 @@ void hdcp_handle_cpirq(struct hdcp_workqueue *hdcp_work, unsigned int link_index
+       schedule_work(&hdcp_w->cpirq_work);
+ }
+-
+-
+-
+ static void event_callback(struct work_struct *work)
+ {
+       struct hdcp_workqueue *hdcp_work;
+       hdcp_work = container_of(to_delayed_work(work), struct hdcp_workqueue,
+-                                    callback_dwork);
++                               callback_dwork);
+       mutex_lock(&hdcp_work->mutex);
+@@ -294,13 +295,12 @@ static void event_callback(struct work_struct *work)
+       process_output(hdcp_work);
+       mutex_unlock(&hdcp_work->mutex);
+-
+-
+ }
+ static void event_property_update(struct work_struct *work)
+ {
+-      struct hdcp_workqueue *hdcp_work = container_of(work, struct hdcp_workqueue, property_update_work);
++      struct hdcp_workqueue *hdcp_work = container_of(work, struct hdcp_workqueue,
++                                                      property_update_work);
+       struct amdgpu_dm_connector *aconnector = NULL;
+       struct drm_device *dev;
+       long ret;
+@@ -337,11 +337,10 @@ static void event_property_update(struct work_struct *work)
+               mutex_lock(&hdcp_work->mutex);
+               if (conn_state->commit) {
+-                      ret = wait_for_completion_interruptible_timeout(
+-                              &conn_state->commit->hw_done, 10 * HZ);
++                      ret = wait_for_completion_interruptible_timeout(&conn_state->commit->hw_done,
++                                                                      10 * HZ);
+                       if (ret == 0) {
+-                              DRM_ERROR(
+-                                      "HDCP state unknown! Setting it to DESIRED");
++                              DRM_ERROR("HDCP state unknown! Setting it to DESIRED\n");
+                               hdcp_work->encryption_status[conn_index] =
+                                       MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
+                       }
+@@ -352,24 +351,20 @@ static void event_property_update(struct work_struct *work)
+                               DRM_MODE_HDCP_CONTENT_TYPE0 &&
+                               hdcp_work->encryption_status[conn_index] <=
+                               MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON) {
+-
+                               DRM_DEBUG_DRIVER("[HDCP_DM] DRM_MODE_CONTENT_PROTECTION_ENABLED\n");
+-                              drm_hdcp_update_content_protection(
+-                                      connector,
+-                                      DRM_MODE_CONTENT_PROTECTION_ENABLED);
++                              drm_hdcp_update_content_protection(connector,
++                                                                 DRM_MODE_CONTENT_PROTECTION_ENABLED);
+                       } else if (conn_state->hdcp_content_type ==
+                                       DRM_MODE_HDCP_CONTENT_TYPE1 &&
+                                       hdcp_work->encryption_status[conn_index] ==
+                                       MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON) {
+-                              drm_hdcp_update_content_protection(
+-                                      connector,
+-                                      DRM_MODE_CONTENT_PROTECTION_ENABLED);
++                              drm_hdcp_update_content_protection(connector,
++                                                                 DRM_MODE_CONTENT_PROTECTION_ENABLED);
+                       }
+               } else {
+                       DRM_DEBUG_DRIVER("[HDCP_DM] DRM_MODE_CONTENT_PROTECTION_DESIRED\n");
+-                      drm_hdcp_update_content_protection(
+-                              connector, DRM_MODE_CONTENT_PROTECTION_DESIRED);
+-
++                      drm_hdcp_update_content_protection(connector,
++                                                         DRM_MODE_CONTENT_PROTECTION_DESIRED);
+               }
+               mutex_unlock(&hdcp_work->mutex);
+               drm_modeset_unlock(&dev->mode_config.connection_mutex);
+@@ -409,7 +404,7 @@ static void event_property_validate(struct work_struct *work)
+                                      &query);
+               DRM_DEBUG_DRIVER("[HDCP_DM] disp %d, connector->CP %u, (query, work): (%d, %d)\n",
+-                      aconnector->base.index,
++                               aconnector->base.index,
+                       aconnector->base.state->content_protection,
+                       query.encryption_status,
+                       hdcp_work->encryption_status[conn_index]);
+@@ -417,7 +412,8 @@ static void event_property_validate(struct work_struct *work)
+               if (query.encryption_status !=
+                   hdcp_work->encryption_status[conn_index]) {
+                       DRM_DEBUG_DRIVER("[HDCP_DM] encryption_status change from %x to %x\n",
+-                              hdcp_work->encryption_status[conn_index], query.encryption_status);
++                                       hdcp_work->encryption_status[conn_index],
++                                       query.encryption_status);
+                       hdcp_work->encryption_status[conn_index] =
+                               query.encryption_status;
+@@ -436,7 +432,7 @@ static void event_watchdog_timer(struct work_struct *work)
+       struct hdcp_workqueue *hdcp_work;
+       hdcp_work = container_of(to_delayed_work(work),
+-                                    struct hdcp_workqueue,
++                               struct hdcp_workqueue,
+                                     watchdog_timer_dwork);
+       mutex_lock(&hdcp_work->mutex);
+@@ -450,7 +446,6 @@ static void event_watchdog_timer(struct work_struct *work)
+       process_output(hdcp_work);
+       mutex_unlock(&hdcp_work->mutex);
+-
+ }
+ static void event_cpirq(struct work_struct *work)
+@@ -466,10 +461,8 @@ static void event_cpirq(struct work_struct *work)
+       process_output(hdcp_work);
+       mutex_unlock(&hdcp_work->mutex);
+-
+ }
+-
+ void hdcp_destroy(struct kobject *kobj, struct hdcp_workqueue *hdcp_work)
+ {
+       int i = 0;
+@@ -486,10 +479,8 @@ void hdcp_destroy(struct kobject *kobj, struct hdcp_workqueue *hdcp_work)
+       kfree(hdcp_work);
+ }
+-
+ static bool enable_assr(void *handle, struct dc_link *link)
+ {
+-
+       struct hdcp_workqueue *hdcp_work = handle;
+       struct mod_hdcp hdcp = hdcp_work->hdcp;
+       struct psp_context *psp = hdcp.config.psp.handle;
+@@ -507,7 +498,8 @@ static bool enable_assr(void *handle, struct dc_link *link)
+       memset(dtm_cmd, 0, sizeof(struct ta_dtm_shared_memory));
+       dtm_cmd->cmd_id = TA_DTM_COMMAND__TOPOLOGY_ASSR_ENABLE;
+-      dtm_cmd->dtm_in_message.topology_assr_enable.display_topology_dig_be_index = link->link_enc_hw_inst;
++      dtm_cmd->dtm_in_message.topology_assr_enable.display_topology_dig_be_index =
++              link->link_enc_hw_inst;
+       dtm_cmd->dtm_status = TA_DTM_STATUS__GENERIC_FAILURE;
+       psp_dtm_invoke(psp, dtm_cmd->cmd_id);
+@@ -549,7 +541,7 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
+       else if (aconnector->dc_em_sink)
+               sink = aconnector->dc_em_sink;
+-      if (sink != NULL)
++      if (sink)
+               link->mode = mod_hdcp_signal_type_to_operation_mode(sink->sink_signal);
+       display->controller = CONTROLLER_ID_D0 + config->otg_inst;
+@@ -574,16 +566,20 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
+       conn_state = aconnector->base.state;
+       DRM_DEBUG_DRIVER("[HDCP_DM] display %d, CP %d, type %d\n", aconnector->base.index,
+-                      (!!aconnector->base.state) ? aconnector->base.state->content_protection : -1,
+-                      (!!aconnector->base.state) ? aconnector->base.state->hdcp_content_type : -1);
++                       (!!aconnector->base.state) ?
++                       aconnector->base.state->content_protection : -1,
++                       (!!aconnector->base.state) ?
++                       aconnector->base.state->hdcp_content_type : -1);
+       if (conn_state)
+               hdcp_update_display(hdcp_work, link_index, aconnector,
+-                      conn_state->hdcp_content_type, false);
++                                  conn_state->hdcp_content_type, false);
+ }
+-
+-/* NOTE: From the usermodes prospective you only need to call write *ONCE*, the kernel
++/**
++ * DOC: Add sysfs interface for set/get srm
++ *
++ * NOTE: From the usermodes prospective you only need to call write *ONCE*, the kernel
+  *      will automatically call once or twice depending on the size
+  *
+  * call: "cat file > /sys/class/drm/card0/device/hdcp_srm" from usermode no matter what the size is
+@@ -594,23 +590,23 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
+  * sysfs interface doesn't tell us the size we will get so we are sending partial SRMs to psp and on
+  * the last call we will send the full SRM. PSP will fail on every call before the last.
+  *
+- * This means we don't know if the SRM is good until the last call. And because of this limitation we
+- * cannot throw errors early as it will stop the kernel from writing to sysfs
++ * This means we don't know if the SRM is good until the last call. And because of this
++ * limitation we cannot throw errors early as it will stop the kernel from writing to sysfs
+  *
+  * Example 1:
+- *    Good SRM size = 5096
+- *    first call to write 4096 -> PSP fails
+- *    Second call to write 1000 -> PSP Pass -> SRM is set
++ *    Good SRM size = 5096
++ *    first call to write 4096 -> PSP fails
++ *    Second call to write 1000 -> PSP Pass -> SRM is set
+  *
+  * Example 2:
+- *    Bad SRM size = 4096
+- *    first call to write 4096 -> PSP fails (This is the same as above, but we don't know if this
+- *    is the last call)
++ *    Bad SRM size = 4096
++ *    first call to write 4096 -> PSP fails (This is the same as above, but we don't know if this
++ *    is the last call)
+  *
+  * Solution?:
+- *    1: Parse the SRM? -> It is signed so we don't know the EOF
+- *    2: We can have another sysfs that passes the size before calling set. -> simpler solution
+- *    below
++ *    1: Parse the SRM? -> It is signed so we don't know the EOF
++ *    2: We can have another sysfs that passes the size before calling set. -> simpler solution
++ *    below
+  *
+  * Easy Solution:
+  * Always call get after Set to verify if set was successful.
+@@ -619,20 +615,21 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
+  * +----------------------+
+  * PSP will only update its srm if its older than the one we are trying to load.
+  * Always do set first than get.
+- *    -if we try to "1. SET" a older version PSP will reject it and we can "2. GET" the newer
+- *    version and save it
++ *    -if we try to "1. SET" a older version PSP will reject it and we can "2. GET" the newer
++ *    version and save it
+  *
+- *    -if we try to "1. SET" a newer version PSP will accept it and we can "2. GET" the
+- *    same(newer) version back and save it
++ *    -if we try to "1. SET" a newer version PSP will accept it and we can "2. GET" the
++ *    same(newer) version back and save it
+  *
+- *    -if we try to "1. SET" a newer version and PSP rejects it. That means the format is
+- *    incorrect/corrupted and we should correct our SRM by getting it from PSP
++ *    -if we try to "1. SET" a newer version and PSP rejects it. That means the format is
++ *    incorrect/corrupted and we should correct our SRM by getting it from PSP
+  */
+-static ssize_t srm_data_write(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buffer,
++static ssize_t srm_data_write(struct file *filp, struct kobject *kobj,
++                            struct bin_attribute *bin_attr, char *buffer,
+                             loff_t pos, size_t count)
+ {
+       struct hdcp_workqueue *work;
+-      uint32_t srm_version = 0;
++      u32 srm_version = 0;
+       work = container_of(bin_attr, struct hdcp_workqueue, attr);
+       link_lock(work, true);
+@@ -646,19 +643,19 @@ static ssize_t srm_data_write(struct file *filp, struct kobject *kobj, struct bi
+               work->srm_version = srm_version;
+       }
+-
+       link_lock(work, false);
+       return count;
+ }
+-static ssize_t srm_data_read(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buffer,
++static ssize_t srm_data_read(struct file *filp, struct kobject *kobj,
++                           struct bin_attribute *bin_attr, char *buffer,
+                            loff_t pos, size_t count)
+ {
+       struct hdcp_workqueue *work;
+-      uint8_t *srm = NULL;
+-      uint32_t srm_version;
+-      uint32_t srm_size;
++      u8 *srm = NULL;
++      u32 srm_version;
++      u32 srm_size;
+       size_t ret = count;
+       work = container_of(bin_attr, struct hdcp_workqueue, attr);
+@@ -691,12 +688,12 @@ static ssize_t srm_data_read(struct file *filp, struct kobject *kobj, struct bin
+ /* From the hdcp spec (5.Renewability) SRM needs to be stored in a non-volatile memory.
+  *
+  * For example,
+- *    if Application "A" sets the SRM (ver 2) and we reboot/suspend and later when Application "B"
+- *    needs to use HDCP, the version in PSP should be SRM(ver 2). So SRM should be persistent
+- *    across boot/reboots/suspend/resume/shutdown
++ *    if Application "A" sets the SRM (ver 2) and we reboot/suspend and later when Application "B"
++ *    needs to use HDCP, the version in PSP should be SRM(ver 2). So SRM should be persistent
++ *    across boot/reboots/suspend/resume/shutdown
+  *
+- * Currently when the system goes down (suspend/shutdown) the SRM is cleared from PSP. For HDCP we need
+- * to make the SRM persistent.
++ * Currently when the system goes down (suspend/shutdown) the SRM is cleared from PSP. For HDCP
++ * we need to make the SRM persistent.
+  *
+  * -PSP owns the checking of SRM but doesn't have the ability to store it in a non-volatile memory.
+  * -The kernel cannot write to the file systems.
+@@ -706,8 +703,8 @@ static ssize_t srm_data_read(struct file *filp, struct kobject *kobj, struct bin
+  *
+  * Usermode can read/write to/from PSP using the sysfs interface
+  * For example:
+- *    to save SRM from PSP to storage : cat /sys/class/drm/card0/device/hdcp_srm > srmfile
+- *    to load from storage to PSP: cat srmfile > /sys/class/drm/card0/device/hdcp_srm
++ *    to save SRM from PSP to storage : cat /sys/class/drm/card0/device/hdcp_srm > srmfile
++ *    to load from storage to PSP: cat srmfile > /sys/class/drm/card0/device/hdcp_srm
+  */
+ static const struct bin_attribute data_attr = {
+       .attr = {.name = "hdcp_srm", .mode = 0664},
+@@ -716,10 +713,9 @@ static const struct bin_attribute data_attr = {
+       .read = srm_data_read,
+ };
+-
+-struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, struct cp_psp *cp_psp, struct dc *dc)
++struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev,
++                                           struct cp_psp *cp_psp, struct dc *dc)
+ {
+-
+       int max_caps = dc->caps.max_links;
+       struct hdcp_workqueue *hdcp_work;
+       int i = 0;
+@@ -728,14 +724,16 @@ struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, struct
+       if (ZERO_OR_NULL_PTR(hdcp_work))
+               return NULL;
+-      hdcp_work->srm = kcalloc(PSP_HDCP_SRM_FIRST_GEN_MAX_SIZE, sizeof(*hdcp_work->srm), GFP_KERNEL);
++      hdcp_work->srm = kcalloc(PSP_HDCP_SRM_FIRST_GEN_MAX_SIZE,
++                               sizeof(*hdcp_work->srm), GFP_KERNEL);
+-      if (hdcp_work->srm == NULL)
++      if (!hdcp_work->srm)
+               goto fail_alloc_context;
+-      hdcp_work->srm_temp = kcalloc(PSP_HDCP_SRM_FIRST_GEN_MAX_SIZE, sizeof(*hdcp_work->srm_temp), GFP_KERNEL);
++      hdcp_work->srm_temp = kcalloc(PSP_HDCP_SRM_FIRST_GEN_MAX_SIZE,
++                                    sizeof(*hdcp_work->srm_temp), GFP_KERNEL);
+-      if (hdcp_work->srm_temp == NULL)
++      if (!hdcp_work->srm_temp)
+               goto fail_alloc_context;
+       hdcp_work->max_link = max_caps;
+@@ -788,10 +786,5 @@ struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, struct
+       kfree(hdcp_work);
+       return NULL;
+-
+-
+-
+ }
+-
+-
+-- 
+2.39.5
+
diff --git a/queue-6.1/drm-amd-display-fix-slab-use-after-free-in-hdcp.patch b/queue-6.1/drm-amd-display-fix-slab-use-after-free-in-hdcp.patch
new file mode 100644 (file)
index 0000000..bdaa6f2
--- /dev/null
@@ -0,0 +1,177 @@
+From e29a7d118e5e0feb8cda94167b19c7bdd49c58dc 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 6222d5a168832..6110d88efdbba 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);
+@@ -496,6 +505,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];
+@@ -551,7 +561,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.1/drm-amd-display-phase2-enable-mst-hdcp-multiple-disp.patch b/queue-6.1/drm-amd-display-phase2-enable-mst-hdcp-multiple-disp.patch
new file mode 100644 (file)
index 0000000..82d2ccb
--- /dev/null
@@ -0,0 +1,306 @@
+From 713c15fbc2d53a2a0b7b6689297e4d23a3d9c96b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Nov 2022 14:29:56 -0500
+Subject: drm/amd/display: phase2 enable mst hdcp multiple displays
+
+From: hersen wu <hersenxs.wu@amd.com>
+
+[ Upstream commit aa9fdd5d5add50305d2022fa072fe6f189283415 ]
+
+[why]
+For MST topology with 1 physical link and multiple connectors (>=2),
+e.g. daisy cahined MST + SST, or 1-to-multi MST hub, if userspace
+set to enable the HDCP simultaneously on all connected outputs, the
+commit tail iteratively call the hdcp_update_display() for each
+display (connector). However, the hdcp workqueue data structure for
+each link has only one DM connector and encryption status members,
+which means the work queue of property_validate/update() would only
+be triggered for the last connector within this physical link, and
+therefore the HDCP property value of other connectors would stay on
+DESIRED instead of switching to ENABLED, which is NOT as expected.
+
+[how]
+Use array of AMDGPU_DM_MAX_DISPLAY_INDEX for both aconnector and
+encryption status in hdcp workqueue data structure for each physical
+link. For property validate/update work queue, we iterates over the
+array and do similar operation/check for each connected display.
+
+Tested-by: Daniel Wheeler <Daniel.Wheeler@amd.com>
+Signed-off-by: hersen wu <hersenxs.wu@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    | 160 +++++++++++++-----
+ .../amd/display/amdgpu_dm/amdgpu_dm_hdcp.h    |   5 +-
+ 2 files changed, 122 insertions(+), 43 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 3f211c0308a2f..7fc26ca30dcd6 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
+@@ -170,9 +170,10 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
+       struct mod_hdcp_display *display = &hdcp_work[link_index].display;
+       struct mod_hdcp_link *link = &hdcp_work[link_index].link;
+       struct mod_hdcp_display_query query;
++      unsigned int conn_index = aconnector->base.index;
+       mutex_lock(&hdcp_w->mutex);
+-      hdcp_w->aconnector = aconnector;
++      hdcp_w->aconnector[conn_index] = aconnector;
+       query.display = NULL;
+       mod_hdcp_query_display(&hdcp_w->hdcp, aconnector->base.index, &query);
+@@ -204,7 +205,7 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
+                                             msecs_to_jiffies(DRM_HDCP_CHECK_PERIOD_MS));
+               } else {
+                       display->adjust.disable = MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION;
+-                      hdcp_w->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
++                      hdcp_w->encryption_status[conn_index] = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
+                       cancel_delayed_work(&hdcp_w->property_validate_dwork);
+               }
+@@ -223,9 +224,10 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
+ {
+       struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
+       struct drm_connector_state *conn_state = aconnector->base.state;
++      unsigned int conn_index = aconnector->base.index;
+       mutex_lock(&hdcp_w->mutex);
+-      hdcp_w->aconnector = aconnector;
++      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
+@@ -247,13 +249,18 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
+ void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index)
+ {
+       struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
++      unsigned int conn_index;
+       mutex_lock(&hdcp_w->mutex);
+       mod_hdcp_reset_connection(&hdcp_w->hdcp,  &hdcp_w->output);
+       cancel_delayed_work(&hdcp_w->property_validate_dwork);
+-      hdcp_w->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
++
++      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;
++      }
+       process_output(hdcp_w);
+@@ -290,49 +297,83 @@ static void event_callback(struct work_struct *work)
+ }
++
+ static void event_property_update(struct work_struct *work)
+ {
+-
+       struct hdcp_workqueue *hdcp_work = container_of(work, struct hdcp_workqueue, property_update_work);
+-      struct amdgpu_dm_connector *aconnector = hdcp_work->aconnector;
+-      struct drm_device *dev = hdcp_work->aconnector->base.dev;
++      struct amdgpu_dm_connector *aconnector = NULL;
++      struct drm_device *dev;
+       long ret;
++      unsigned int conn_index;
++      struct drm_connector *connector;
++      struct drm_connector_state *conn_state;
+-      drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+-      mutex_lock(&hdcp_work->mutex);
++      for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX; conn_index++) {
++              aconnector = hdcp_work->aconnector[conn_index];
++              if (!aconnector)
++                      continue;
+-      if (aconnector->base.state && aconnector->base.state->commit) {
+-              ret = wait_for_completion_interruptible_timeout(&aconnector->base.state->commit->hw_done, 10 * HZ);
++              if (!aconnector->base.index)
++                      continue;
+-              if (ret == 0) {
+-                      DRM_ERROR("HDCP state unknown! Setting it to DESIRED");
+-                      hdcp_work->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
+-              }
+-      }
++              connector = &aconnector->base;
++
++              /* check if display connected */
++              if (connector->status != connector_status_connected)
++                      continue;
+-      if (aconnector->base.state) {
+-              if (hdcp_work->encryption_status != MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF) {
+-                      if (aconnector->base.state->hdcp_content_type ==
++              conn_state = aconnector->base.state;
++
++              if (!conn_state)
++                      continue;
++
++              dev = connector->dev;
++
++              if (!dev)
++                      continue;
++
++              drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
++              mutex_lock(&hdcp_work->mutex);
++
++              if (conn_state->commit) {
++                      ret = wait_for_completion_interruptible_timeout(
++                              &conn_state->commit->hw_done, 10 * HZ);
++                      if (ret == 0) {
++                              DRM_ERROR(
++                                      "HDCP state unknown! Setting it to DESIRED");
++                              hdcp_work->encryption_status[conn_index] =
++                                      MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
++                      }
++              }
++              if (hdcp_work->encryption_status[conn_index] !=
++                      MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF) {
++                      if (conn_state->hdcp_content_type ==
+                               DRM_MODE_HDCP_CONTENT_TYPE0 &&
+-                      hdcp_work->encryption_status <=
+-                              MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON)
+-                              drm_hdcp_update_content_protection(&aconnector->base,
++                              hdcp_work->encryption_status[conn_index] <=
++                              MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON) {
++
++                              DRM_DEBUG_DRIVER("[HDCP_DM] DRM_MODE_CONTENT_PROTECTION_ENABLED\n");
++                              drm_hdcp_update_content_protection(
++                                      connector,
+                                       DRM_MODE_CONTENT_PROTECTION_ENABLED);
+-                      else if (aconnector->base.state->hdcp_content_type ==
++                      } else if (conn_state->hdcp_content_type ==
+                                       DRM_MODE_HDCP_CONTENT_TYPE1 &&
+-                              hdcp_work->encryption_status ==
+-                                      MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON)
+-                              drm_hdcp_update_content_protection(&aconnector->base,
++                                      hdcp_work->encryption_status[conn_index] ==
++                                      MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON) {
++                              drm_hdcp_update_content_protection(
++                                      connector,
+                                       DRM_MODE_CONTENT_PROTECTION_ENABLED);
++                      }
+               } else {
+-                      drm_hdcp_update_content_protection(&aconnector->base,
+-                              DRM_MODE_CONTENT_PROTECTION_DESIRED);
++                      DRM_DEBUG_DRIVER("[HDCP_DM] DRM_MODE_CONTENT_PROTECTION_DESIRED\n");
++                      drm_hdcp_update_content_protection(
++                              connector, DRM_MODE_CONTENT_PROTECTION_DESIRED);
++
+               }
++              mutex_unlock(&hdcp_work->mutex);
++              drm_modeset_unlock(&dev->mode_config.connection_mutex);
+       }
+-
+-      mutex_unlock(&hdcp_work->mutex);
+-      drm_modeset_unlock(&dev->mode_config.connection_mutex);
+ }
+ static void event_property_validate(struct work_struct *work)
+@@ -340,19 +381,51 @@ static void event_property_validate(struct work_struct *work)
+       struct hdcp_workqueue *hdcp_work =
+               container_of(to_delayed_work(work), struct hdcp_workqueue, property_validate_dwork);
+       struct mod_hdcp_display_query query;
+-      struct amdgpu_dm_connector *aconnector = hdcp_work->aconnector;
+-
+-      if (!aconnector)
+-              return;
++      struct amdgpu_dm_connector *aconnector;
++      unsigned int conn_index;
+       mutex_lock(&hdcp_work->mutex);
+-      query.encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
+-      mod_hdcp_query_display(&hdcp_work->hdcp, aconnector->base.index, &query);
++      for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX;
++           conn_index++) {
++              aconnector = hdcp_work->aconnector[conn_index];
++
++
++              if (!aconnector)
++                      continue;
++
++              if (!aconnector->base.index)
++                      continue;
++
++              /* check if display connected */
++              if (aconnector->base.status != connector_status_connected)
++                      continue;
+-      if (query.encryption_status != hdcp_work->encryption_status) {
+-              hdcp_work->encryption_status = query.encryption_status;
+-              schedule_work(&hdcp_work->property_update_work);
++              if (!aconnector->base.state)
++                      continue;
++
++              query.encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
++              mod_hdcp_query_display(&hdcp_work->hdcp, aconnector->base.index,
++                                     &query);
++
++              DRM_DEBUG_DRIVER("[HDCP_DM] disp %d, connector->CP %u, (query, work): (%d, %d)\n",
++                      aconnector->base.index,
++                      aconnector->base.state->content_protection,
++                      query.encryption_status,
++                      hdcp_work->encryption_status[conn_index]);
++
++              if (query.encryption_status !=
++                  hdcp_work->encryption_status[conn_index]) {
++                      DRM_DEBUG_DRIVER("[HDCP_DM] encryption_status change from %x to %x\n",
++                              hdcp_work->encryption_status[conn_index], query.encryption_status);
++
++                      hdcp_work->encryption_status[conn_index] =
++                              query.encryption_status;
++
++                      DRM_DEBUG_DRIVER("[HDCP_DM] trigger property_update_work\n");
++
++                      schedule_work(&hdcp_work->property_update_work);
++              }
+       }
+       mutex_unlock(&hdcp_work->mutex);
+@@ -687,6 +760,13 @@ struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, struct
+               hdcp_work[i].hdcp.config.ddc.funcs.read_i2c = lp_read_i2c;
+               hdcp_work[i].hdcp.config.ddc.funcs.write_dpcd = lp_write_dpcd;
+               hdcp_work[i].hdcp.config.ddc.funcs.read_dpcd = lp_read_dpcd;
++
++              memset(hdcp_work[i].aconnector, 0,
++                     sizeof(struct amdgpu_dm_connector *) *
++                             AMDGPU_DM_MAX_DISPLAY_INDEX);
++              memset(hdcp_work[i].encryption_status, 0,
++                     sizeof(enum mod_hdcp_encryption_status) *
++                             AMDGPU_DM_MAX_DISPLAY_INDEX);
+       }
+       cp_psp->funcs.update_stream_config = update_config;
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
+index bbbf7d0eff82f..69b445b011c8c 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
+@@ -43,7 +43,7 @@ struct hdcp_workqueue {
+       struct delayed_work callback_dwork;
+       struct delayed_work watchdog_timer_dwork;
+       struct delayed_work property_validate_dwork;
+-      struct amdgpu_dm_connector *aconnector;
++      struct amdgpu_dm_connector *aconnector[AMDGPU_DM_MAX_DISPLAY_INDEX];
+       struct mutex mutex;
+       struct mod_hdcp hdcp;
+@@ -51,8 +51,7 @@ struct hdcp_workqueue {
+       struct mod_hdcp_display display;
+       struct mod_hdcp_link link;
+-      enum mod_hdcp_encryption_status encryption_status;
+-
++      enum mod_hdcp_encryption_status encryption_status[AMDGPU_DM_MAX_DISPLAY_INDEX];
+       /* when display is unplugged from mst hub, connctor will be
+        * destroyed within dm_dp_mst_connector_destroy. connector
+        * hdcp perperties, like type, undesired, desired, enabled,
+-- 
+2.39.5
+
diff --git a/queue-6.1/firmware-arm_ffa-skip-rx-buffer-ownership-release-if.patch b/queue-6.1/firmware-arm_ffa-skip-rx-buffer-ownership-release-if.patch
new file mode 100644 (file)
index 0000000..9eda2f6
--- /dev/null
@@ -0,0 +1,52 @@
+From 3d1bbe519609a18914363c561cdbc3f27d88a923 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 e9f86b7573012..e1e278d431e97 100644
+--- a/drivers/firmware/arm_ffa/driver.c
++++ b/drivers/firmware/arm_ffa/driver.c
+@@ -306,7 +306,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.1/firmware-arm_scmi-balance-device-refcount-when-destr.patch b/queue-6.1/firmware-arm_scmi-balance-device-refcount-when-destr.patch
new file mode 100644 (file)
index 0000000..27cec04
--- /dev/null
@@ -0,0 +1,86 @@
+From 694e80a2b44920eb504fe9d9f510154d0e23b62b 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 35bb70724d44b..8c6f99d15f22f 100644
+--- a/drivers/firmware/arm_scmi/bus.c
++++ b/drivers/firmware/arm_scmi/bus.c
+@@ -73,6 +73,9 @@ 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.1/iommu-arm-smmu-v3-fix-iommu_device_probe-bug-due-to-.patch b/queue-6.1/iommu-arm-smmu-v3-fix-iommu_device_probe-bug-due-to-.patch
new file mode 100644 (file)
index 0000000..77e9bbd
--- /dev/null
@@ -0,0 +1,123 @@
+From d4de1adc22717fd9c0e1369a984274ec2de9f6eb 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 1ab2abab46800..6a60bad48b277 100644
+--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
++++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+@@ -2612,6 +2612,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;
+@@ -2622,10 +2623,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.1/iommu-arm-smmu-v3-use-the-new-rb-tree-helpers.patch b/queue-6.1/iommu-arm-smmu-v3-use-the-new-rb-tree-helpers.patch
new file mode 100644 (file)
index 0000000..20592fd
--- /dev/null
@@ -0,0 +1,140 @@
+From 8d69ac0bba7c2b38564e68d8c571cef24d65f101 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 96b72f3dad0d0..1ab2abab46800 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 */
+@@ -2590,8 +2601,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),
+@@ -2602,9 +2611,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;
+@@ -2613,28 +2622,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.1/irqchip-gic-v2m-mark-a-few-functions-__init.patch b/queue-6.1/irqchip-gic-v2m-mark-a-few-functions-__init.patch
new file mode 100644 (file)
index 0000000..6809985
--- /dev/null
@@ -0,0 +1,72 @@
+From 6b3dd655c1d4d29b0c1e15f6fa8f68f3be8f3c54 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 21 Nov 2022 15:39:33 +0100
+Subject: irqchip/gic-v2m: Mark a few functions __init
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+[ Upstream commit d51a15af37ce8cf59e73de51dcdce3c9f4944974 ]
+
+They are all part of the init sequence.
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Acked-by: Marc Zyngier <maz@kernel.org>
+Link: https://lore.kernel.org/r/20221121140048.534395323@linutronix.de
+Stable-dep-of: 3318dc299b07 ("irqchip/gic-v2m: Prevent use after free of gicv2m_get_fwnode()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/irqchip/irq-gic-v2m.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
+index 414cd925064f4..c2e52c9a38546 100644
+--- a/drivers/irqchip/irq-gic-v2m.c
++++ b/drivers/irqchip/irq-gic-v2m.c
+@@ -262,7 +262,7 @@ static struct msi_domain_info gicv2m_pmsi_domain_info = {
+       .chip   = &gicv2m_pmsi_irq_chip,
+ };
+-static void gicv2m_teardown(void)
++static void __init gicv2m_teardown(void)
+ {
+       struct v2m_data *v2m, *tmp;
+@@ -277,7 +277,7 @@ static void gicv2m_teardown(void)
+       }
+ }
+-static int gicv2m_allocate_domains(struct irq_domain *parent)
++static __init int gicv2m_allocate_domains(struct irq_domain *parent)
+ {
+       struct irq_domain *inner_domain, *pci_domain, *plat_domain;
+       struct v2m_data *v2m;
+@@ -404,7 +404,7 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
+       return ret;
+ }
+-static const struct of_device_id gicv2m_device_id[] = {
++static __initconst struct of_device_id gicv2m_device_id[] = {
+       {       .compatible     = "arm,gic-v2m-frame",  },
+       {},
+ };
+@@ -454,7 +454,7 @@ static int __init gicv2m_of_init(struct fwnode_handle *parent_handle,
+ #ifdef CONFIG_ACPI
+ static int acpi_num_msi;
+-static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev)
++static __init struct fwnode_handle *gicv2m_get_fwnode(struct device *dev)
+ {
+       struct v2m_data *data;
+@@ -469,7 +469,7 @@ static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev)
+       return data->fwnode;
+ }
+-static bool acpi_check_amazon_graviton_quirks(void)
++static __init bool acpi_check_amazon_graviton_quirks(void)
+ {
+       static struct acpi_table_madt *madt;
+       acpi_status status;
+-- 
+2.39.5
+
diff --git a/queue-6.1/irqchip-gic-v2m-prevent-use-after-free-of-gicv2m_get.patch b/queue-6.1/irqchip-gic-v2m-prevent-use-after-free-of-gicv2m_get.patch
new file mode 100644 (file)
index 0000000..e53193d
--- /dev/null
@@ -0,0 +1,51 @@
+From d3b764f43a2f9040bd08c4edd77873671eab55bf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 22 Apr 2025 17:16:16 +0100
+Subject: irqchip/gic-v2m: Prevent use after free of gicv2m_get_fwnode()
+
+From: Suzuki K Poulose <suzuki.poulose@arm.com>
+
+[ Upstream commit 3318dc299b072a0511d6dfd8367f3304fb6d9827 ]
+
+With ACPI in place, gicv2m_get_fwnode() is registered with the pci
+subsystem as pci_msi_get_fwnode_cb(), which may get invoked at runtime
+during a PCI host bridge probe. But, the call back is wrongly marked as
+__init, causing it to be freed, while being registered with the PCI
+subsystem and could trigger:
+
+ Unable to handle kernel paging request at virtual address ffff8000816c0400
+  gicv2m_get_fwnode+0x0/0x58 (P)
+  pci_set_bus_msi_domain+0x74/0x88
+  pci_register_host_bridge+0x194/0x548
+
+This is easily reproducible on a Juno board with ACPI boot.
+
+Retain the function for later use.
+
+Fixes: 0644b3daca28 ("irqchip/gic-v2m: acpi: Introducing GICv2m ACPI support")
+Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Reviewed-by: Marc Zyngier <maz@kernel.org>
+Cc: stable@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/irqchip/irq-gic-v2m.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
+index c2e52c9a38546..c04f2481068bb 100644
+--- a/drivers/irqchip/irq-gic-v2m.c
++++ b/drivers/irqchip/irq-gic-v2m.c
+@@ -454,7 +454,7 @@ static int __init gicv2m_of_init(struct fwnode_handle *parent_handle,
+ #ifdef CONFIG_ACPI
+ static int acpi_num_msi;
+-static __init struct fwnode_handle *gicv2m_get_fwnode(struct device *dev)
++static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev)
+ {
+       struct v2m_data *data;
+-- 
+2.39.5
+
diff --git a/queue-6.1/memcg-drain-obj-stock-on-cpu-hotplug-teardown.patch b/queue-6.1/memcg-drain-obj-stock-on-cpu-hotplug-teardown.patch
new file mode 100644 (file)
index 0000000..63b9315
--- /dev/null
@@ -0,0 +1,55 @@
+From 23250aec43b05632c5aa65fc4a8c7061677e49e2 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 3f7cab196eb62..8c586133abb7c 100644
+--- a/mm/memcontrol.c
++++ b/mm/memcontrol.c
+@@ -2368,9 +2368,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.1/net-phy-microchip-force-irq-polling-mode-for-lan88xx.patch b/queue-6.1/net-phy-microchip-force-irq-polling-mode-for-lan88xx.patch
new file mode 100644 (file)
index 0000000..e00051d
--- /dev/null
@@ -0,0 +1,111 @@
+From 57c6431bc0f9c39d8128e45de7ec69e307d696b8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 16 Apr 2025 12:24:13 +0200
+Subject: net: phy: microchip: force IRQ polling mode for lan88xx
+
+From: Fiona Klute <fiona.klute@gmx.de>
+
+[ Upstream commit 30a41ed32d3088cd0d682a13d7f30b23baed7e93 ]
+
+With lan88xx based devices the lan78xx driver can get stuck in an
+interrupt loop while bringing the device up, flooding the kernel log
+with messages like the following:
+
+lan78xx 2-3:1.0 enp1s0u3: kevent 4 may have been dropped
+
+Removing interrupt support from the lan88xx PHY driver forces the
+driver to use polling instead, which avoids the problem.
+
+The issue has been observed with Raspberry Pi devices at least since
+4.14 (see [1], bug report for their downstream kernel), as well as
+with Nvidia devices [2] in 2020, where disabling interrupts was the
+vendor-suggested workaround (together with the claim that phylib
+changes in 4.9 made the interrupt handling in lan78xx incompatible).
+
+Iperf reports well over 900Mbits/sec per direction with client in
+--dualtest mode, so there does not seem to be a significant impact on
+throughput (lan88xx device connected via switch to the peer).
+
+[1] https://github.com/raspberrypi/linux/issues/2447
+[2] https://forums.developer.nvidia.com/t/jetson-xavier-and-lan7800-problem/142134/11
+
+Link: https://lore.kernel.org/0901d90d-3f20-4a10-b680-9c978e04ddda@lunn.ch
+Fixes: 792aec47d59d ("add microchip LAN88xx phy driver")
+Signed-off-by: Fiona Klute <fiona.klute@gmx.de>
+Cc: kernel-list@raspberrypi.com
+Cc: stable@vger.kernel.org
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://patch.msgid.link/20250416102413.30654-1-fiona.klute@gmx.de
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/phy/microchip.c | 46 +++----------------------------------
+ 1 file changed, 3 insertions(+), 43 deletions(-)
+
+diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c
+index 0b88635f4fbca..623607fd2cefd 100644
+--- a/drivers/net/phy/microchip.c
++++ b/drivers/net/phy/microchip.c
+@@ -31,47 +31,6 @@ static int lan88xx_write_page(struct phy_device *phydev, int page)
+       return __phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS, page);
+ }
+-static int lan88xx_phy_config_intr(struct phy_device *phydev)
+-{
+-      int rc;
+-
+-      if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+-              /* unmask all source and clear them before enable */
+-              rc = phy_write(phydev, LAN88XX_INT_MASK, 0x7FFF);
+-              rc = phy_read(phydev, LAN88XX_INT_STS);
+-              rc = phy_write(phydev, LAN88XX_INT_MASK,
+-                             LAN88XX_INT_MASK_MDINTPIN_EN_ |
+-                             LAN88XX_INT_MASK_LINK_CHANGE_);
+-      } else {
+-              rc = phy_write(phydev, LAN88XX_INT_MASK, 0);
+-              if (rc)
+-                      return rc;
+-
+-              /* Ack interrupts after they have been disabled */
+-              rc = phy_read(phydev, LAN88XX_INT_STS);
+-      }
+-
+-      return rc < 0 ? rc : 0;
+-}
+-
+-static irqreturn_t lan88xx_handle_interrupt(struct phy_device *phydev)
+-{
+-      int irq_status;
+-
+-      irq_status = phy_read(phydev, LAN88XX_INT_STS);
+-      if (irq_status < 0) {
+-              phy_error(phydev);
+-              return IRQ_NONE;
+-      }
+-
+-      if (!(irq_status & LAN88XX_INT_STS_LINK_CHANGE_))
+-              return IRQ_NONE;
+-
+-      phy_trigger_machine(phydev);
+-
+-      return IRQ_HANDLED;
+-}
+-
+ static int lan88xx_suspend(struct phy_device *phydev)
+ {
+       struct lan88xx_priv *priv = phydev->priv;
+@@ -392,8 +351,9 @@ static struct phy_driver microchip_phy_driver[] = {
+       .config_aneg    = lan88xx_config_aneg,
+       .link_change_notify = lan88xx_link_change_notify,
+-      .config_intr    = lan88xx_phy_config_intr,
+-      .handle_interrupt = lan88xx_handle_interrupt,
++      /* Interrupt handling is broken, do not define related
++       * functions to force polling.
++       */
+       .suspend        = lan88xx_suspend,
+       .resume         = genphy_resume,
+-- 
+2.39.5
+
diff --git a/queue-6.1/revert-drm-meson-vclk-fix-calculation-of-59.94-fract.patch b/queue-6.1/revert-drm-meson-vclk-fix-calculation-of-59.94-fract.patch
new file mode 100644 (file)
index 0000000..6b014f8
--- /dev/null
@@ -0,0 +1,61 @@
+From af710f97542c389eaa50bc48fc02e7b19c1acebf 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.1/riscv-uprobes-add-missing-fence.i-after-building-the.patch b/queue-6.1/riscv-uprobes-add-missing-fence.i-after-building-the.patch
new file mode 100644 (file)
index 0000000..72882fe
--- /dev/null
@@ -0,0 +1,61 @@
+From 07d22744abb51b806341b22c08041e12965cfd8f 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 194f166b2cc40..0d18ee53fd649 100644
+--- a/arch/riscv/kernel/probes/uprobes.c
++++ b/arch/riscv/kernel/probes/uprobes.c
+@@ -161,6 +161,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);
+@@ -170,13 +171,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 f188b4822967708c6f8973a717aa65b6e8420e5e..db2390e0e80cb4a6cb39c8f669749845c66f7b30 100644 (file)
@@ -77,3 +77,27 @@ sch_hfsc-make-hfsc_qlen_notify-idempotent.patch
 sch_qfq-make-qfq_qlen_notify-idempotent.patch
 sch_ets-make-est_qlen_notify-idempotent.patch
 revert-x86-kexec-allocate-pgd-for-x86_64-transition-page-tables-separately.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
+net-phy-microchip-force-irq-polling-mode-for-lan88xx.patch
+revert-drm-meson-vclk-fix-calculation-of-59.94-fract.patch
+irqchip-gic-v2m-mark-a-few-functions-__init.patch
+irqchip-gic-v2m-prevent-use-after-free-of-gicv2m_get.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
+spi-tegra114-remove-unnecessary-null-pointer-checks.patch
+spi-tegra114-don-t-fail-set_cs_timing-when-delays-ar.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-phase2-enable-mst-hdcp-multiple-disp.patch
+drm-amd-display-clean-up-style-problems-in-amdgpu_dm.patch
+drm-amd-display-change-hdcp-update-sequence-for-dm.patch
+drm-amd-display-add-scoped-mutexes-for-amdgpu_dm_dhc.patch
+drm-amd-display-fix-slab-use-after-free-in-hdcp.patch
+asoc-use-of_property_read_bool.patch
+asoc-soc-core-stop-using-of_property_read_bool-for-n.patch
diff --git a/queue-6.1/spi-tegra114-don-t-fail-set_cs_timing-when-delays-ar.patch b/queue-6.1/spi-tegra114-don-t-fail-set_cs_timing-when-delays-ar.patch
new file mode 100644 (file)
index 0000000..820abae
--- /dev/null
@@ -0,0 +1,44 @@
+From 7cbc152533a52b99ee873db1e13646947d8ccc93 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 23 Apr 2025 21:03:03 -0500
+Subject: spi: tegra114: Don't fail set_cs_timing when delays are zero
+
+From: Aaron Kling <webgeek1234@gmail.com>
+
+[ Upstream commit 4426e6b4ecf632bb75d973051e1179b8bfac2320 ]
+
+The original code would skip null delay pointers, but when the pointers
+were converted to point within the spi_device struct, the check was not
+updated to skip delays of zero. Hence all spi devices that didn't set
+delays would fail to probe.
+
+Fixes: 04e6bb0d6bb1 ("spi: modify set_cs_timing parameter")
+Cc: stable@vger.kernel.org
+Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
+Link: https://patch.msgid.link/20250423-spi-tegra114-v1-1-2d608bcc12f9@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/spi/spi-tegra114.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
+index 6b56108308fc5..60799ab60eb45 100644
+--- a/drivers/spi/spi-tegra114.c
++++ b/drivers/spi/spi-tegra114.c
+@@ -729,9 +729,9 @@ static int tegra_spi_set_hw_cs_timing(struct spi_device *spi)
+       u32 inactive_cycles;
+       u8 cs_state;
+-      if (setup->unit != SPI_DELAY_UNIT_SCK ||
+-          hold->unit != SPI_DELAY_UNIT_SCK ||
+-          inactive->unit != SPI_DELAY_UNIT_SCK) {
++      if ((setup->unit && setup->unit != SPI_DELAY_UNIT_SCK) ||
++          (hold->unit && hold->unit != SPI_DELAY_UNIT_SCK) ||
++          (inactive->unit && inactive->unit != SPI_DELAY_UNIT_SCK)) {
+               dev_err(&spi->dev,
+                       "Invalid delay unit %d, should be SPI_DELAY_UNIT_SCK\n",
+                       SPI_DELAY_UNIT_SCK);
+-- 
+2.39.5
+
diff --git a/queue-6.1/spi-tegra114-remove-unnecessary-null-pointer-checks.patch b/queue-6.1/spi-tegra114-remove-unnecessary-null-pointer-checks.patch
new file mode 100644 (file)
index 0000000..38decc0
--- /dev/null
@@ -0,0 +1,74 @@
+From 9f6421ddc72eaeff8e254d44e7d3e650d26f0c5a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 15 Aug 2023 12:20:58 +0300
+Subject: spi: tegra114: Remove unnecessary NULL-pointer checks
+
+From: Alexander Danilenko <al.b.danilenko@gmail.com>
+
+[ Upstream commit 373c36bf7914e3198ac2654dede499f340c52950 ]
+
+cs_setup, cs_hold and cs_inactive points to fields of spi_device struct,
+so there is no sense in checking them for NULL.
+
+Found by Linux Verification Center (linuxtesting.org) with SVACE.
+
+Fixes: 04e6bb0d6bb1 ("spi: modify set_cs_timing parameter")
+Signed-off-by: Alexander Danilenko <al.b.danilenko@gmail.com>
+Link: https://lore.kernel.org/r/20230815092058.4083-1-al.b.danilenko@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: 4426e6b4ecf6 ("spi: tegra114: Don't fail set_cs_timing when delays are zero")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/spi/spi-tegra114.c | 18 +++++++-----------
+ 1 file changed, 7 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
+index d9be80e3e1bcb..6b56108308fc5 100644
+--- a/drivers/spi/spi-tegra114.c
++++ b/drivers/spi/spi-tegra114.c
+@@ -723,27 +723,23 @@ static int tegra_spi_set_hw_cs_timing(struct spi_device *spi)
+       struct spi_delay *setup = &spi->cs_setup;
+       struct spi_delay *hold = &spi->cs_hold;
+       struct spi_delay *inactive = &spi->cs_inactive;
+-      u8 setup_dly, hold_dly, inactive_dly;
++      u8 setup_dly, hold_dly;
+       u32 setup_hold;
+       u32 spi_cs_timing;
+       u32 inactive_cycles;
+       u8 cs_state;
+-      if ((setup && setup->unit != SPI_DELAY_UNIT_SCK) ||
+-          (hold && hold->unit != SPI_DELAY_UNIT_SCK) ||
+-          (inactive && inactive->unit != SPI_DELAY_UNIT_SCK)) {
++      if (setup->unit != SPI_DELAY_UNIT_SCK ||
++          hold->unit != SPI_DELAY_UNIT_SCK ||
++          inactive->unit != SPI_DELAY_UNIT_SCK) {
+               dev_err(&spi->dev,
+                       "Invalid delay unit %d, should be SPI_DELAY_UNIT_SCK\n",
+                       SPI_DELAY_UNIT_SCK);
+               return -EINVAL;
+       }
+-      setup_dly = setup ? setup->value : 0;
+-      hold_dly = hold ? hold->value : 0;
+-      inactive_dly = inactive ? inactive->value : 0;
+-
+-      setup_dly = min_t(u8, setup_dly, MAX_SETUP_HOLD_CYCLES);
+-      hold_dly = min_t(u8, hold_dly, MAX_SETUP_HOLD_CYCLES);
++      setup_dly = min_t(u8, setup->value, MAX_SETUP_HOLD_CYCLES);
++      hold_dly = min_t(u8, hold->value, MAX_SETUP_HOLD_CYCLES);
+       if (setup_dly && hold_dly) {
+               setup_hold = SPI_SETUP_HOLD(setup_dly - 1, hold_dly - 1);
+               spi_cs_timing = SPI_CS_SETUP_HOLD(tspi->spi_cs_timing1,
+@@ -755,7 +751,7 @@ static int tegra_spi_set_hw_cs_timing(struct spi_device *spi)
+               }
+       }
+-      inactive_cycles = min_t(u8, inactive_dly, MAX_INACTIVE_CYCLES);
++      inactive_cycles = min_t(u8, inactive->value, MAX_INACTIVE_CYCLES);
+       if (inactive_cycles)
+               inactive_cycles--;
+       cs_state = inactive_cycles ? 0 : 1;
+-- 
+2.39.5
+