From: Sasha Levin Date: Wed, 7 May 2025 15:36:16 +0000 (-0400) Subject: Fixes for 5.15 X-Git-Tag: v5.15.182~22 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5acc27dbba7bcdfc45f5023d58504677e0fc4dbe;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 5.15 Signed-off-by: Sasha Levin --- diff --git a/queue-5.15/arm-dts-opos6ul-add-ksz8081-phy-properties.patch b/queue-5.15/arm-dts-opos6ul-add-ksz8081-phy-properties.patch new file mode 100644 index 0000000000..bdddc1b306 --- /dev/null +++ b/queue-5.15/arm-dts-opos6ul-add-ksz8081-phy-properties.patch @@ -0,0 +1,44 @@ +From ecd209e97dcf5523048b9b06998629601b012d6d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 Mar 2025 17:20:38 +0100 +Subject: ARM: dts: opos6ul: add ksz8081 phy properties +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sébastien Szymanski + +[ Upstream commit 6e1a7bc8382b0d4208258f7d2a4474fae788dd90 ] + +Commit c7e73b5051d6 ("ARM: imx: mach-imx6ul: remove 14x14 EVK specific +PHY fixup") removed a PHY fixup that setted the clock mode and the LED +mode. +Make the Ethernet interface work again by doing as advised in the +commit's log, set clock mode and the LED mode in the device tree. + +Fixes: c7e73b5051d6 ("ARM: imx: mach-imx6ul: remove 14x14 EVK specific PHY fixup") +Signed-off-by: Sébastien Szymanski +Reviewed-by: Oleksij Rempel +Signed-off-by: Shawn Guo +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/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-5.15/cpufreq-intel_pstate-do-not-update-global.turbo_disa.patch b/queue-5.15/cpufreq-intel_pstate-do-not-update-global.turbo_disa.patch new file mode 100644 index 0000000000..f92f25f3e2 --- /dev/null +++ b/queue-5.15/cpufreq-intel_pstate-do-not-update-global.turbo_disa.patch @@ -0,0 +1,196 @@ +From f8932eb7f77838e33fa7d95510c125f26c98a4dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Mar 2024 18:02:42 +0100 +Subject: cpufreq: intel_pstate: Do not update global.turbo_disabled after + initialization + +From: Rafael J. Wysocki + +[ Upstream commit 0940f1a8011fd69be5082015068e0dc31c800c20 ] + +The global.turbo_disabled is updated quite often, especially in the +passive mode in which case it is updated every time the scheduler calls +into the driver. However, this is generally not necessary and it adds +MSR read overhead to scheduler code paths (and that particular MSR is +slow to read). + +For this reason, make the driver read MSR_IA32_MISC_ENABLE_TURBO_DISABLE +just once at the cpufreq driver registration time and remove all of the +in-flight updates of global.turbo_disabled. + +Signed-off-by: Rafael J. Wysocki +Acked-by: Srinivas Pandruvada +Stable-dep-of: ac4e04d9e378 ("cpufreq: intel_pstate: Unchecked MSR aceess in legacy mode") +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/intel_pstate.c | 51 ++++++---------------------------- + 1 file changed, 8 insertions(+), 43 deletions(-) + +diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c +index bcfde997f445d..a26d28c437699 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; + }; +@@ -560,12 +558,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) +@@ -1110,40 +1109,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); + } +@@ -1243,7 +1218,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 +@@ -1273,7 +1247,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); +@@ -2205,8 +2178,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); +@@ -2523,7 +2494,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); +@@ -2562,7 +2532,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 ? +@@ -2659,8 +2628,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; + +@@ -2826,8 +2793,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; + +@@ -2849,8 +2814,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); +@@ -2868,7 +2831,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); + +@@ -3058,6 +3020,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-5.15/cpufreq-intel_pstate-fold-intel_pstate_max_within_li.patch b/queue-5.15/cpufreq-intel_pstate-fold-intel_pstate_max_within_li.patch new file mode 100644 index 0000000000..83f49809cb --- /dev/null +++ b/queue-5.15/cpufreq-intel_pstate-fold-intel_pstate_max_within_li.patch @@ -0,0 +1,61 @@ +From 84097c4bb28e934fd60bcf17878f9d97822c7a17 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Mar 2024 18:01:58 +0100 +Subject: cpufreq: intel_pstate: Fold intel_pstate_max_within_limits() into + caller + +From: Rafael J. Wysocki + +[ Upstream commit 032c5565eb80edb6f2faeb31939540c897987119 ] + +Fold intel_pstate_max_within_limits() into its only caller. + +No functional impact. + +Signed-off-by: Rafael J. Wysocki +Acked-by: Srinivas Pandruvada +Stable-dep-of: ac4e04d9e378 ("cpufreq: intel_pstate: Unchecked MSR aceess in legacy mode") +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/intel_pstate.c | 13 ++++--------- + 1 file changed, 4 insertions(+), 9 deletions(-) + +diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c +index 6f69e396ce8c8..bcfde997f445d 100644 +--- a/drivers/cpufreq/intel_pstate.c ++++ b/drivers/cpufreq/intel_pstate.c +@@ -1936,14 +1936,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); +@@ -2524,12 +2516,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-5.15/cpufreq-intel_pstate-process-hwp-guaranteed-change-n.patch b/queue-5.15/cpufreq-intel_pstate-process-hwp-guaranteed-change-n.patch new file mode 100644 index 0000000000..a7e3cb18a3 --- /dev/null +++ b/queue-5.15/cpufreq-intel_pstate-process-hwp-guaranteed-change-n.patch @@ -0,0 +1,261 @@ +From aa88dc777754b1557313c1cbf447c1720dcfbc7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Sep 2021 09:42:17 -0700 +Subject: cpufreq: intel_pstate: Process HWP Guaranteed change notification + +From: Srinivas Pandruvada + +[ Upstream commit 57577c996d731ce1e5a4a488e64e6e201b360847 ] + +It is possible that HWP guaranteed ratio is changed in response to +change in power and thermal limits. For example when Intel Speed Select +performance profile is changed or there is change in TDP, hardware can +send notifications. It is possible that the guaranteed ratio is +increased. This creates an issue when turbo is disabled, as the old +limits set in MSR_HWP_REQUEST are still lower and hardware will clip +to older limits. + +This change enables HWP interrupt and process HWP interrupts. When +guaranteed is changed, calls cpufreq_update_policy() so that driver +callbacks are called to update to new HWP limits. This callback +is called from a delayed workqueue of 10ms to avoid frequent updates. + +Although the scope of IA32_HWP_INTERRUPT is per logical cpu, on some +plaforms interrupt is generated on all CPUs. This is particularly a +problem during initialization, when the driver didn't allocated +data for other CPUs. So this change uses a cpumask of enabled CPUs and +process interrupts on those CPUs only. + +When the cpufreq offline() or suspend() callback is called, HWP interrupt +is disabled on those CPUs and also cancels any pending work item. + +Spin lock is used to protect data and processing shared with interrupt +handler. Here READ_ONCE(), WRITE_ONCE() macros are used to designate +shared data, even though spin lock act as an optimization barrier here. + +Signed-off-by: Srinivas Pandruvada +Tested-by: pablomh@gmail.com +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: ac4e04d9e378 ("cpufreq: intel_pstate: Unchecked MSR aceess in legacy mode") +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/intel_pstate.c | 117 +++++++++++++++++++++++++++++++-- + 1 file changed, 111 insertions(+), 6 deletions(-) + +diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c +index 4de71e772f514..2a1d21438a468 100644 +--- a/drivers/cpufreq/intel_pstate.c ++++ b/drivers/cpufreq/intel_pstate.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include "../drivers/thermal/intel/thermal_interrupt.h" + + #define INTEL_PSTATE_SAMPLING_INTERVAL (10 * NSEC_PER_MSEC) + +@@ -220,6 +221,7 @@ struct global_params { + * @sched_flags: Store scheduler flags for possible cross CPU update + * @hwp_boost_min: Last HWP boosted min performance + * @suspended: Whether or not the driver has been suspended. ++ * @hwp_notify_work: workqueue for HWP notifications. + * + * This structure stores per CPU instance data for all CPUs. + */ +@@ -258,6 +260,7 @@ struct cpudata { + unsigned int sched_flags; + u32 hwp_boost_min; + bool suspended; ++ struct delayed_work hwp_notify_work; + }; + + static struct cpudata **all_cpu_data; +@@ -983,11 +986,15 @@ static void intel_pstate_hwp_set(unsigned int cpu) + wrmsrl_on_cpu(cpu, MSR_HWP_REQUEST, value); + } + ++static void intel_pstate_disable_hwp_interrupt(struct cpudata *cpudata); ++ + static void intel_pstate_hwp_offline(struct cpudata *cpu) + { + u64 value = READ_ONCE(cpu->hwp_req_cached); + int min_perf; + ++ intel_pstate_disable_hwp_interrupt(cpu); ++ + if (boot_cpu_has(X86_FEATURE_HWP_EPP)) { + /* + * In case the EPP has been set to "performance" by the +@@ -1064,6 +1071,9 @@ static int intel_pstate_suspend(struct cpufreq_policy *policy) + + cpu->suspended = true; + ++ /* disable HWP interrupt and cancel any pending work */ ++ intel_pstate_disable_hwp_interrupt(cpu); ++ + return 0; + } + +@@ -1557,15 +1567,105 @@ static void intel_pstate_sysfs_hide_hwp_dynamic_boost(void) + + /************************** sysfs end ************************/ + ++static void intel_pstate_notify_work(struct work_struct *work) ++{ ++ struct cpudata *cpudata = ++ container_of(to_delayed_work(work), struct cpudata, hwp_notify_work); ++ ++ cpufreq_update_policy(cpudata->cpu); ++ wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_STATUS, 0); ++} ++ ++static DEFINE_SPINLOCK(hwp_notify_lock); ++static cpumask_t hwp_intr_enable_mask; ++ ++void notify_hwp_interrupt(void) ++{ ++ unsigned int this_cpu = smp_processor_id(); ++ struct cpudata *cpudata; ++ unsigned long flags; ++ u64 value; ++ ++ if (!READ_ONCE(hwp_active) || !boot_cpu_has(X86_FEATURE_HWP_NOTIFY)) ++ return; ++ ++ rdmsrl_safe(MSR_HWP_STATUS, &value); ++ if (!(value & 0x01)) ++ return; ++ ++ spin_lock_irqsave(&hwp_notify_lock, flags); ++ ++ if (!cpumask_test_cpu(this_cpu, &hwp_intr_enable_mask)) ++ goto ack_intr; ++ ++ /* ++ * Currently we never free all_cpu_data. And we can't reach here ++ * without this allocated. But for safety for future changes, added ++ * check. ++ */ ++ if (unlikely(!READ_ONCE(all_cpu_data))) ++ goto ack_intr; ++ ++ /* ++ * The free is done during cleanup, when cpufreq registry is failed. ++ * We wouldn't be here if it fails on init or switch status. But for ++ * future changes, added check. ++ */ ++ cpudata = READ_ONCE(all_cpu_data[this_cpu]); ++ if (unlikely(!cpudata)) ++ goto ack_intr; ++ ++ schedule_delayed_work(&cpudata->hwp_notify_work, msecs_to_jiffies(10)); ++ ++ spin_unlock_irqrestore(&hwp_notify_lock, flags); ++ ++ return; ++ ++ack_intr: ++ wrmsrl_safe(MSR_HWP_STATUS, 0); ++ spin_unlock_irqrestore(&hwp_notify_lock, flags); ++} ++ ++static void intel_pstate_disable_hwp_interrupt(struct cpudata *cpudata) ++{ ++ unsigned long flags; ++ ++ /* wrmsrl_on_cpu has to be outside spinlock as this can result in IPC */ ++ wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_INTERRUPT, 0x00); ++ ++ spin_lock_irqsave(&hwp_notify_lock, flags); ++ if (cpumask_test_and_clear_cpu(cpudata->cpu, &hwp_intr_enable_mask)) ++ cancel_delayed_work(&cpudata->hwp_notify_work); ++ spin_unlock_irqrestore(&hwp_notify_lock, flags); ++} ++ ++static void intel_pstate_enable_hwp_interrupt(struct cpudata *cpudata) ++{ ++ /* Enable HWP notification interrupt for guaranteed performance change */ ++ if (boot_cpu_has(X86_FEATURE_HWP_NOTIFY)) { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&hwp_notify_lock, flags); ++ INIT_DELAYED_WORK(&cpudata->hwp_notify_work, intel_pstate_notify_work); ++ cpumask_set_cpu(cpudata->cpu, &hwp_intr_enable_mask); ++ spin_unlock_irqrestore(&hwp_notify_lock, flags); ++ ++ /* wrmsrl_on_cpu has to be outside spinlock as this can result in IPC */ ++ wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_INTERRUPT, 0x01); ++ } ++} ++ + static void intel_pstate_hwp_enable(struct cpudata *cpudata) + { +- /* First disable HWP notification interrupt as we don't process them */ ++ /* First disable HWP notification interrupt till we activate again */ + if (boot_cpu_has(X86_FEATURE_HWP_NOTIFY)) + wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_INTERRUPT, 0x00); + + wrmsrl_on_cpu(cpudata->cpu, MSR_PM_ENABLE, 0x1); + if (cpudata->epp_default == -EINVAL) + cpudata->epp_default = intel_pstate_get_epp(cpudata, 0); ++ ++ intel_pstate_enable_hwp_interrupt(cpudata); + } + + static int atom_get_min_pstate(int not_used) +@@ -2266,7 +2366,7 @@ static int intel_pstate_init_cpu(unsigned int cpunum) + if (!cpu) + return -ENOMEM; + +- all_cpu_data[cpunum] = cpu; ++ WRITE_ONCE(all_cpu_data[cpunum], cpu); + + cpu->cpu = cpunum; + +@@ -2937,8 +3037,10 @@ static void intel_pstate_driver_cleanup(void) + if (intel_pstate_driver == &intel_pstate) + intel_pstate_clear_update_util_hook(cpu); + ++ spin_lock(&hwp_notify_lock); + kfree(all_cpu_data[cpu]); +- all_cpu_data[cpu] = NULL; ++ WRITE_ONCE(all_cpu_data[cpu], NULL); ++ spin_unlock(&hwp_notify_lock); + } + } + cpus_read_unlock(); +@@ -3207,6 +3309,7 @@ static bool intel_pstate_hwp_is_enabled(void) + + static int __init intel_pstate_init(void) + { ++ static struct cpudata **_all_cpu_data; + const struct x86_cpu_id *id; + int rc; + +@@ -3232,7 +3335,7 @@ static int __init intel_pstate_init(void) + * deal with it. + */ + if ((!no_hwp && boot_cpu_has(X86_FEATURE_HWP_EPP)) || hwp_forced) { +- hwp_active++; ++ WRITE_ONCE(hwp_active, 1); + hwp_mode_bdw = id->driver_data; + intel_pstate.attr = hwp_cpufreq_attrs; + intel_cpufreq.attr = hwp_cpufreq_attrs; +@@ -3283,10 +3386,12 @@ static int __init intel_pstate_init(void) + + pr_info("Intel P-state driver initializing\n"); + +- all_cpu_data = vzalloc(array_size(sizeof(void *), num_possible_cpus())); +- if (!all_cpu_data) ++ _all_cpu_data = vzalloc(array_size(sizeof(void *), num_possible_cpus())); ++ if (!_all_cpu_data) + return -ENOMEM; + ++ WRITE_ONCE(all_cpu_data, _all_cpu_data); ++ + intel_pstate_request_control_from_smm(); + + intel_pstate_sysfs_expose_params(); +-- +2.39.5 + diff --git a/queue-5.15/cpufreq-intel_pstate-revise-global-turbo-disable-che.patch b/queue-5.15/cpufreq-intel_pstate-revise-global-turbo-disable-che.patch new file mode 100644 index 0000000000..d7d12d5be7 --- /dev/null +++ b/queue-5.15/cpufreq-intel_pstate-revise-global-turbo-disable-che.patch @@ -0,0 +1,69 @@ +From c954aeeeadc7694c41fb563942cbabf72fe2e1e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 Sep 2023 11:02:07 -0700 +Subject: cpufreq: intel_pstate: Revise global turbo disable check + +From: Srinivas Pandruvada + +[ Upstream commit 37b6ddba967c601479bea418a7ac6ff16b6232b7 ] + +Setting global turbo flag based on CPU 0 P-state limits is problematic +as it limits max P-state request on every CPU on the system just based +on its P-state limits. + +There are two cases in which global.turbo_disabled flag is set: +- When the MSR_IA32_MISC_ENABLE_TURBO_DISABLE bit is set to 1 +in the MSR MSR_IA32_MISC_ENABLE. This bit can be only changed by +the system BIOS before power up. +- When the max non turbo P-state is same as max turbo P-state for CPU 0. + +The second check is not a valid to decide global turbo state based on +the CPU 0. CPU 0 max turbo P-state can be same as max non turbo P-state, +but for other CPUs this may not be true. + +There is no guarantee that max P-state limits are same for every CPU. This +is possible that during fusing max P-state for a CPU is constrained. Also +with the Intel Speed Select performance profile, CPU 0 may not be present +in all profiles. In this case the max non turbo and turbo P-state can be +set to the lowest possible P-state by the hardware when switched to +such profile. Since max non turbo and turbo P-state is same, +global.turbo_disabled flag will be set. + +Once global.turbo_disabled is set, any scaling max and min frequency +update for any CPU will result in its max P-state constrained to the max +non turbo P-state. + +Hence remove the check of max non turbo P-state equal to max turbo P-state +of CPU 0 to set global turbo disabled flag. + +Signed-off-by: Srinivas Pandruvada +[ rjw: Subject edit ] +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: ac4e04d9e378 ("cpufreq: intel_pstate: Unchecked MSR aceess in legacy mode") +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/intel_pstate.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c +index cb6fb9cdba0b8..6f69e396ce8c8 100644 +--- a/drivers/cpufreq/intel_pstate.c ++++ b/drivers/cpufreq/intel_pstate.c +@@ -563,13 +563,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-5.15/cpufreq-intel_pstate-unchecked-msr-aceess-in-legacy-.patch b/queue-5.15/cpufreq-intel_pstate-unchecked-msr-aceess-in-legacy-.patch new file mode 100644 index 0000000000..9fe71ac06d --- /dev/null +++ b/queue-5.15/cpufreq-intel_pstate-unchecked-msr-aceess-in-legacy-.patch @@ -0,0 +1,65 @@ +From 440d08e6e32a6192de35b667bd2b69f71d972009 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 29 Apr 2025 14:07:11 -0700 +Subject: cpufreq: intel_pstate: Unchecked MSR aceess in legacy mode + +From: Srinivas Pandruvada + +[ Upstream commit ac4e04d9e378f5aa826c2406ad7871ae1b6a6fb9 ] + +When turbo mode is unavailable on a Skylake-X system, executing the +command: + + # echo 1 > /sys/devices/system/cpu/intel_pstate/no_turbo + +results in an unchecked MSR access error: + + WRMSR to 0x199 (attempted to write 0x0000000100001300). + +This issue was reproduced on an OEM (Original Equipment Manufacturer) +system and is not a common problem across all Skylake-X systems. + +This error occurs because the MSR 0x199 Turbo Engage Bit (bit 32) is set +when turbo mode is disabled. The issue arises when intel_pstate fails to +detect that turbo mode is disabled. Here intel_pstate relies on +MSR_IA32_MISC_ENABLE bit 38 to determine the status of turbo mode. +However, on this system, bit 38 is not set even when turbo mode is +disabled. + +According to the Intel Software Developer's Manual (SDM), the BIOS sets +this bit during platform initialization to enable or disable +opportunistic processor performance operations. Logically, this bit +should be set in such cases. However, the SDM also specifies that "OS +and applications must use CPUID leaf 06H to detect processors with +opportunistic processor performance operations enabled." + +Therefore, in addition to checking MSR_IA32_MISC_ENABLE bit 38, verify +that CPUID.06H:EAX[1] is 0 to accurately determine if turbo mode is +disabled. + +Fixes: 4521e1a0ce17 ("cpufreq: intel_pstate: Reflect current no_turbo state correctly") +Signed-off-by: Srinivas Pandruvada +Cc: All applicable +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/intel_pstate.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c +index a26d28c437699..875c8cdaddda1 100644 +--- a/drivers/cpufreq/intel_pstate.c ++++ b/drivers/cpufreq/intel_pstate.c +@@ -562,6 +562,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-5.15/cpufreq-intel_pstate-update-cpuinfo.max_freq-on-hwp_.patch b/queue-5.15/cpufreq-intel_pstate-update-cpuinfo.max_freq-on-hwp_.patch new file mode 100644 index 0000000000..ca30ec4d9e --- /dev/null +++ b/queue-5.15/cpufreq-intel_pstate-update-cpuinfo.max_freq-on-hwp_.patch @@ -0,0 +1,89 @@ +From f9f9bd456c7f1a49b58ecb484e5d2509c0e340b2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Dec 2021 20:06:08 +0100 +Subject: cpufreq: intel_pstate: Update cpuinfo.max_freq on HWP_CAP changes + +From: Rafael J. Wysocki + +[ Upstream commit dfeeedc1bf5772226bddf51ed3f853e5a6707bf1 ] + +With HWP enabled, when the turbo range of performance levels is +disabled by the platform firmware, the CPU capacity is given by +the "guaranteed performance" field in MSR_HWP_CAPABILITIES which +is generally dynamic. When it changes, the kernel receives an HWP +notification interrupt handled by notify_hwp_interrupt(). + +When the "guaranteed performance" value changes in the above +configuration, the CPU performance scaling needs to be adjusted so +as to use the new CPU capacity in computations, which means that +the cpuinfo.max_freq value needs to be updated for that CPU. + +Accordingly, modify intel_pstate_notify_work() to read +MSR_HWP_CAPABILITIES and update cpuinfo.max_freq to reflect the +new configuration (this update can be carried out even if the +configuration doesn't actually change, because it simply doesn't +matter then and it takes less time to update it than to do extra +checks to decide whether or not a change has really occurred). + +Reported-by: Srinivas Pandruvada +Tested-by: Srinivas Pandruvada +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: ac4e04d9e378 ("cpufreq: intel_pstate: Unchecked MSR aceess in legacy mode") +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/intel_pstate.c | 24 +++++++++++++++++------- + 1 file changed, 17 insertions(+), 7 deletions(-) + +diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c +index 2a1d21438a468..cb6fb9cdba0b8 100644 +--- a/drivers/cpufreq/intel_pstate.c ++++ b/drivers/cpufreq/intel_pstate.c +@@ -1111,19 +1111,22 @@ static void intel_pstate_update_policies(void) + cpufreq_update_policy(cpu); + } + ++static void __intel_pstate_update_max_freq(struct cpudata *cpudata, ++ struct cpufreq_policy *policy) ++{ ++ policy->cpuinfo.max_freq = global.turbo_disabled_mf ? ++ 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); +- struct cpudata *cpudata; + + if (!policy) + return; + +- cpudata = all_cpu_data[cpu]; +- policy->cpuinfo.max_freq = global.turbo_disabled_mf ? +- cpudata->pstate.max_freq : cpudata->pstate.turbo_freq; +- +- refresh_frequency_limits(policy); ++ __intel_pstate_update_max_freq(all_cpu_data[cpu], policy); + + cpufreq_cpu_release(policy); + } +@@ -1571,8 +1574,15 @@ static void intel_pstate_notify_work(struct work_struct *work) + { + struct cpudata *cpudata = + container_of(to_delayed_work(work), struct cpudata, hwp_notify_work); ++ struct cpufreq_policy *policy = cpufreq_cpu_acquire(cpudata->cpu); ++ ++ if (policy) { ++ intel_pstate_get_hwp_cap(cpudata); ++ __intel_pstate_update_max_freq(cpudata, policy); ++ ++ cpufreq_cpu_release(policy); ++ } + +- cpufreq_update_policy(cpudata->cpu); + wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_STATUS, 0); + } + +-- +2.39.5 + diff --git a/queue-5.15/firmware-arm_scmi-balance-device-refcount-when-destr.patch b/queue-5.15/firmware-arm_scmi-balance-device-refcount-when-destr.patch new file mode 100644 index 0000000000..bf8e160d64 --- /dev/null +++ b/queue-5.15/firmware-arm_scmi-balance-device-refcount-when-destr.patch @@ -0,0 +1,86 @@ +From 03f6a515d22b7b74dec567c6ce37dfc47d8d3033 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Mar 2025 18:54:47 +0000 +Subject: firmware: arm_scmi: Balance device refcount when destroying devices + +From: Cristian Marussi + +[ Upstream commit 9ca67840c0ddf3f39407339624cef824a4f27599 ] + +Using device_find_child() to lookup the proper SCMI device to destroy +causes an unbalance in device refcount, since device_find_child() calls an +implicit get_device(): this, in turns, inhibits the call of the provided +release methods upon devices destruction. + +As a consequence, one of the structures that is not freed properly upon +destruction is the internal struct device_private dev->p populated by the +drivers subsystem core. + +KMemleak detects this situation since loading/unloding some SCMI driver +causes related devices to be created/destroyed without calling any +device_release method. + +unreferenced object 0xffff00000f583800 (size 512): + comm "insmod", pid 227, jiffies 4294912190 + hex dump (first 32 bytes): + 00 00 00 00 ad 4e ad de ff ff ff ff 00 00 00 00 .....N.......... + ff ff ff ff ff ff ff ff 60 36 1d 8a 00 80 ff ff ........`6...... + backtrace (crc 114e2eed): + kmemleak_alloc+0xbc/0xd8 + __kmalloc_cache_noprof+0x2dc/0x398 + device_add+0x954/0x12d0 + device_register+0x28/0x40 + __scmi_device_create.part.0+0x1bc/0x380 + scmi_device_create+0x2d0/0x390 + scmi_create_protocol_devices+0x74/0xf8 + scmi_device_request_notifier+0x1f8/0x2a8 + notifier_call_chain+0x110/0x3b0 + blocking_notifier_call_chain+0x70/0xb0 + scmi_driver_register+0x350/0x7f0 + 0xffff80000a3b3038 + do_one_initcall+0x12c/0x730 + do_init_module+0x1dc/0x640 + load_module+0x4b20/0x5b70 + init_module_from_file+0xec/0x158 + +$ ./scripts/faddr2line ./vmlinux device_add+0x954/0x12d0 +device_add+0x954/0x12d0: +kmalloc_noprof at include/linux/slab.h:901 +(inlined by) kzalloc_noprof at include/linux/slab.h:1037 +(inlined by) device_private_init at drivers/base/core.c:3510 +(inlined by) device_add at drivers/base/core.c:3561 + +Balance device refcount by issuing a put_device() on devices found via +device_find_child(). + +Reported-by: Alice Ryhl +Closes: https://lore.kernel.org/linux-arm-kernel/Z8nK3uFkspy61yjP@arm.com/T/#mc1f73a0ea5e41014fa145147b7b839fc988ada8f +CC: Sudeep Holla +CC: Catalin Marinas +Fixes: d4f9dddd21f3 ("firmware: arm_scmi: Add dynamic scmi devices creation") +Signed-off-by: Cristian Marussi +Tested-by: Alice Ryhl +Message-Id: <20250306185447.2039336-1-cristian.marussi@arm.com> +Signed-off-by: Sudeep Holla +Signed-off-by: Sasha Levin +--- + drivers/firmware/arm_scmi/bus.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c +index 7c1c0951e562d..758ced6a8cc4e 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-5.15/iommu-arm-smmu-v3-fix-iommu_device_probe-bug-due-to-.patch b/queue-5.15/iommu-arm-smmu-v3-fix-iommu_device_probe-bug-due-to-.patch new file mode 100644 index 0000000000..521e53bc5f --- /dev/null +++ b/queue-5.15/iommu-arm-smmu-v3-fix-iommu_device_probe-bug-due-to-.patch @@ -0,0 +1,123 @@ +From 4466804dfcd58d18f1a062683e4713379f65f30e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 15 Apr 2025 11:56:20 -0700 +Subject: iommu/arm-smmu-v3: Fix iommu_device_probe bug due to duplicated + stream ids + +From: Nicolin Chen + +[ Upstream commit b00d24997a11c10d3e420614f0873b83ce358a34 ] + +ASPEED VGA card has two built-in devices: + 0008:06:00.0 PCI bridge: ASPEED Technology, Inc. AST1150 PCI-to-PCI Bridge (rev 06) + 0008:07:00.0 VGA compatible controller: ASPEED Technology, Inc. ASPEED Graphics Family (rev 52) + +Its toplogy looks like this: + +-[0008:00]---00.0-[01-09]--+-00.0-[02-09]--+-00.0-[03]----00.0 Sandisk Corp Device 5017 + | +-01.0-[04]-- + | +-02.0-[05]----00.0 NVIDIA Corporation Device + | +-03.0-[06-07]----00.0-[07]----00.0 ASPEED Technology, Inc. ASPEED Graphics Family + | +-04.0-[08]----00.0 Renesas Technology Corp. uPD720201 USB 3.0 Host Controller + | \-05.0-[09]----00.0 Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller + \-00.1 PMC-Sierra Inc. Device 4028 + +The IORT logic populaties two identical IDs into the fwspec->ids array via +DMA aliasing in iort_pci_iommu_init() called by pci_for_each_dma_alias(). + +Though the SMMU driver had been able to handle this situation since commit +563b5cbe334e ("iommu/arm-smmu-v3: Cope with duplicated Stream IDs"), that +got broken by the later commit cdf315f907d4 ("iommu/arm-smmu-v3: Maintain +a SID->device structure"), which ended up with allocating separate streams +with the same stuffing. + +On a kernel prior to v6.15-rc1, there has been an overlooked warning: + pci 0008:07:00.0: vgaarb: setting as boot VGA device + pci 0008:07:00.0: vgaarb: bridge control possible + pci 0008:07:00.0: vgaarb: VGA device added: decodes=io+mem,owns=none,locks=none + pcieport 0008:06:00.0: Adding to iommu group 14 + ast 0008:07:00.0: stream 67328 already in tree <===== WARNING + ast 0008:07:00.0: enabling device (0002 -> 0003) + ast 0008:07:00.0: Using default configuration + ast 0008:07:00.0: AST 2600 detected + ast 0008:07:00.0: [drm] Using analog VGA + ast 0008:07:00.0: [drm] dram MCLK=396 Mhz type=1 bus_width=16 + [drm] Initialized ast 0.1.0 for 0008:07:00.0 on minor 0 + ast 0008:07:00.0: [drm] fb0: astdrmfb frame buffer device + +With v6.15-rc, since the commit bcb81ac6ae3c ("iommu: Get DT/ACPI parsing +into the proper probe path"), the error returned with the warning is moved +to the SMMU device probe flow: + arm_smmu_probe_device+0x15c/0x4c0 + __iommu_probe_device+0x150/0x4f8 + probe_iommu_group+0x44/0x80 + bus_for_each_dev+0x7c/0x100 + bus_iommu_probe+0x48/0x1a8 + iommu_device_register+0xb8/0x178 + arm_smmu_device_probe+0x1350/0x1db0 +which then fails the entire SMMU driver probe: + pci 0008:06:00.0: Adding to iommu group 21 + pci 0008:07:00.0: stream 67328 already in tree + arm-smmu-v3 arm-smmu-v3.9.auto: Failed to register iommu + arm-smmu-v3 arm-smmu-v3.9.auto: probe with driver arm-smmu-v3 failed with error -22 + +Since SMMU driver had been already expecting a potential duplicated Stream +ID in arm_smmu_install_ste_for_dev(), change the arm_smmu_insert_master() +routine to ignore a duplicated ID from the fwspec->sids array as well. + +Note: this has been failing the iommu_device_probe() since 2021, although a +recent iommu commit in v6.15-rc1 that moves iommu_device_probe() started to +fail the SMMU driver probe. Since nobody has cared about DMA Alias support, +leave that as it was but fix the fundamental iommu_device_probe() breakage. + +Fixes: cdf315f907d4 ("iommu/arm-smmu-v3: Maintain a SID->device structure") +Cc: stable@vger.kernel.org +Suggested-by: Jason Gunthorpe +Reviewed-by: Jason Gunthorpe +Signed-off-by: Nicolin Chen +Link: https://lore.kernel.org/r/20250415185620.504299-1-nicolinc@nvidia.com +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +index fc07ecce426ef..bc65e7b4f0045 100644 +--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c ++++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +@@ -2582,6 +2582,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; +@@ -2603,10 +2604,20 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu, + } + + /* 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-5.15/iommu-arm-smmu-v3-use-the-new-rb-tree-helpers.patch b/queue-5.15/iommu-arm-smmu-v3-use-the-new-rb-tree-helpers.patch new file mode 100644 index 0000000000..5cfad76057 --- /dev/null +++ b/queue-5.15/iommu-arm-smmu-v3-use-the-new-rb-tree-helpers.patch @@ -0,0 +1,140 @@ +From 088020d89aca9ab4a1dca05b88a8775c88a21286 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Aug 2024 20:31:15 -0300 +Subject: iommu/arm-smmu-v3: Use the new rb tree helpers + +From: Jason Gunthorpe + +[ Upstream commit a2bb820e862d61f9ca1499e500915f9f505a2655 ] + +Since v5.12 the rbtree has gained some simplifying helpers aimed at making +rb tree users write less convoluted boiler plate code. Instead the caller +provides a single comparison function and the helpers generate the prior +open-coded stuff. + +Update smmu->streams to use rb_find_add() and rb_find(). + +Tested-by: Nicolin Chen +Reviewed-by: Mostafa Saleh +Signed-off-by: Jason Gunthorpe +Link: https://lore.kernel.org/r/1-v3-9fef8cdc2ff6+150d1-smmuv3_tidy_jgg@nvidia.com +Signed-off-by: Will Deacon +Stable-dep-of: b00d24997a11 ("iommu/arm-smmu-v3: Fix iommu_device_probe bug due to duplicated stream ids") +Signed-off-by: Sasha Levin +--- + drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 68 ++++++++++----------- + 1 file changed, 31 insertions(+), 37 deletions(-) + +diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +index ec4c87095c6cd..fc07ecce426ef 100644 +--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c ++++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +@@ -1430,26 +1430,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 */ +@@ -2560,8 +2571,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), +@@ -2572,9 +2581,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; + +@@ -2594,28 +2603,13 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu, + } + + /* 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-5.15/irqchip-gic-v2m-add-const-to-of_device_id.patch b/queue-5.15/irqchip-gic-v2m-add-const-to-of_device_id.patch new file mode 100644 index 0000000000..5a3bdd44a1 --- /dev/null +++ b/queue-5.15/irqchip-gic-v2m-add-const-to-of_device_id.patch @@ -0,0 +1,36 @@ +From 008c2b91aea386652fac6390c4bc1c509bfc1f64 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Dec 2021 21:24:53 +0800 +Subject: irqchip/gic-v2m: Add const to of_device_id + +From: Xiang wangx + +[ Upstream commit c10f2f8b5d8027c1ea77f777f2d16cb9043a6c09 ] + +struct of_device_id should normally be const. + +Signed-off-by: Xiang wangx +Signed-off-by: Marc Zyngier +Link: https://lore.kernel.org/r/20211209132453.25623-1-wangxiang@cdjrlc.com +Stable-dep-of: 3318dc299b07 ("irqchip/gic-v2m: Prevent use after free of gicv2m_get_fwnode()") +Signed-off-by: Sasha Levin +--- + 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 0e57c60681aab..48e2eed33f8fa 100644 +--- a/drivers/irqchip/irq-gic-v2m.c ++++ b/drivers/irqchip/irq-gic-v2m.c +@@ -405,7 +405,7 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode, + return ret; + } + +-static struct of_device_id gicv2m_device_id[] = { ++static const struct of_device_id gicv2m_device_id[] = { + { .compatible = "arm,gic-v2m-frame", }, + {}, + }; +-- +2.39.5 + diff --git a/queue-5.15/irqchip-gic-v2m-mark-a-few-functions-__init.patch b/queue-5.15/irqchip-gic-v2m-mark-a-few-functions-__init.patch new file mode 100644 index 0000000000..214a9e162e --- /dev/null +++ b/queue-5.15/irqchip-gic-v2m-mark-a-few-functions-__init.patch @@ -0,0 +1,72 @@ +From 0896b5f7e2d73af58cc009091bb4d13998633322 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 21 Nov 2022 15:39:33 +0100 +Subject: irqchip/gic-v2m: Mark a few functions __init + +From: Thomas Gleixner + +[ Upstream commit d51a15af37ce8cf59e73de51dcdce3c9f4944974 ] + +They are all part of the init sequence. + +Signed-off-by: Thomas Gleixner +Acked-by: Marc Zyngier +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 +--- + 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 48e2eed33f8fa..6790a621a9324 100644 +--- a/drivers/irqchip/irq-gic-v2m.c ++++ b/drivers/irqchip/irq-gic-v2m.c +@@ -263,7 +263,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; + +@@ -278,7 +278,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; +@@ -405,7 +405,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", }, + {}, + }; +@@ -455,7 +455,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; + +@@ -470,7 +470,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-5.15/irqchip-gic-v2m-prevent-use-after-free-of-gicv2m_get.patch b/queue-5.15/irqchip-gic-v2m-prevent-use-after-free-of-gicv2m_get.patch new file mode 100644 index 0000000000..217cf07be7 --- /dev/null +++ b/queue-5.15/irqchip-gic-v2m-prevent-use-after-free-of-gicv2m_get.patch @@ -0,0 +1,51 @@ +From 85ce65866dc9f70c0e585e324fa0e7eb5524d241 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Thomas Gleixner +Signed-off-by: Ingo Molnar +Reviewed-by: Marc Zyngier +Cc: stable@vger.kernel.org +Signed-off-by: Sasha Levin +--- + 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 6790a621a9324..9d99b19cd21b6 100644 +--- a/drivers/irqchip/irq-gic-v2m.c ++++ b/drivers/irqchip/irq-gic-v2m.c +@@ -455,7 +455,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-5.15/net-phy-microchip-force-irq-polling-mode-for-lan88xx.patch b/queue-5.15/net-phy-microchip-force-irq-polling-mode-for-lan88xx.patch new file mode 100644 index 0000000000..da942baa0d --- /dev/null +++ b/queue-5.15/net-phy-microchip-force-irq-polling-mode-for-lan88xx.patch @@ -0,0 +1,111 @@ +From 6c5d5144b5ad7be45a8bb814f928dfa603805af5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Apr 2025 12:24:13 +0200 +Subject: net: phy: microchip: force IRQ polling mode for lan88xx + +From: Fiona Klute + +[ 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 +Cc: kernel-list@raspberrypi.com +Cc: stable@vger.kernel.org +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250416102413.30654-1-fiona.klute@gmx.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 230f2fcf9c46a..7c8bcec0a8fab 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; +@@ -388,8 +347,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-5.15/revert-drm-meson-vclk-fix-calculation-of-59.94-fract.patch b/queue-5.15/revert-drm-meson-vclk-fix-calculation-of-59.94-fract.patch new file mode 100644 index 0000000000..b71cdc9993 --- /dev/null +++ b/queue-5.15/revert-drm-meson-vclk-fix-calculation-of-59.94-fract.patch @@ -0,0 +1,61 @@ +From fab9fd871d60ae99aae98d129645fdfcd3977a8c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 21 Apr 2025 22:12:59 +0200 +Subject: Revert "drm/meson: vclk: fix calculation of 59.94 fractional rates" + +From: Christian Hewitt + +[ Upstream commit f37bb5486ea536c1d61df89feeaeff3f84f0b560 ] + +This reverts commit bfbc68e. + +The patch does permit the offending YUV420 @ 59.94 phy_freq and +vclk_freq mode to match in calculations. It also results in all +fractional rates being unavailable for use. This was unintended +and requires the patch to be reverted. + +Fixes: bfbc68e4d869 ("drm/meson: vclk: fix calculation of 59.94 fractional rates") +Cc: stable@vger.kernel.org +Signed-off-by: Christian Hewitt +Signed-off-by: Martin Blumenstingl +Reviewed-by: Neil Armstrong +Link: https://lore.kernel.org/r/20250421201300.778955-2-martin.blumenstingl@googlemail.com +Signed-off-by: Neil Armstrong +Link: https://lore.kernel.org/r/20250421201300.778955-2-martin.blumenstingl@googlemail.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/meson/meson_vclk.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c +index 2a942dc6a6dc2..2a82119eb58ed 100644 +--- a/drivers/gpu/drm/meson/meson_vclk.c ++++ b/drivers/gpu/drm/meson/meson_vclk.c +@@ -790,13 +790,13 @@ meson_vclk_vic_supported_freq(struct meson_drm *priv, unsigned int phy_freq, + FREQ_1000_1001(params[i].pixel_freq)); + DRM_DEBUG_DRIVER("i = %d phy_freq = %d alt = %d\n", + i, params[i].phy_freq, +- FREQ_1000_1001(params[i].phy_freq/1000)*1000); ++ FREQ_1000_1001(params[i].phy_freq/10)*10); + /* Match strict frequency */ + if (phy_freq == params[i].phy_freq && + vclk_freq == params[i].vclk_freq) + return MODE_OK; + /* Match 1000/1001 variant */ +- if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/1000)*1000) && ++ if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/10)*10) && + vclk_freq == FREQ_1000_1001(params[i].vclk_freq)) + return MODE_OK; + } +@@ -1070,7 +1070,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, + + for (freq = 0 ; params[freq].pixel_freq ; ++freq) { + if ((phy_freq == params[freq].phy_freq || +- phy_freq == FREQ_1000_1001(params[freq].phy_freq/1000)*1000) && ++ phy_freq == FREQ_1000_1001(params[freq].phy_freq/10)*10) && + (vclk_freq == params[freq].vclk_freq || + vclk_freq == FREQ_1000_1001(params[freq].vclk_freq))) { + if (vclk_freq != params[freq].vclk_freq) +-- +2.39.5 + diff --git a/queue-5.15/riscv-uprobes-add-missing-fence.i-after-building-the.patch b/queue-5.15/riscv-uprobes-add-missing-fence.i-after-building-the.patch new file mode 100644 index 0000000000..f1e4edaf8c --- /dev/null +++ b/queue-5.15/riscv-uprobes-add-missing-fence.i-after-building-the.patch @@ -0,0 +1,61 @@ +From de23949570352bbe4c66024ff9ce06e6f9199761 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 19 Apr 2025 13:14:00 +0200 +Subject: riscv: uprobes: Add missing fence.i after building the XOL buffer +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Björn Töpel + +[ Upstream commit 7d1d19a11cfbfd8bae1d89cc010b2cc397cd0c48 ] + +The XOL (execute out-of-line) buffer is used to single-step the +replaced instruction(s) for uprobes. The RISC-V port was missing a +proper fence.i (i$ flushing) after constructing the XOL buffer, which +can result in incorrect execution of stale/broken instructions. + +This was found running the BPF selftests "test_progs: +uprobe_autoattach, attach_probe" on the Spacemit K1/X60, where the +uprobes tests randomly blew up. + +Reviewed-by: Guo Ren +Fixes: 74784081aac8 ("riscv: Add uprobes supported") +Signed-off-by: Björn Töpel +Link: https://lore.kernel.org/r/20250419111402.1660267-2-bjorn@kernel.org +Signed-off-by: Palmer Dabbelt +Signed-off-by: Sasha Levin +--- + arch/riscv/kernel/probes/uprobes.c | 10 ++-------- + 1 file changed, 2 insertions(+), 8 deletions(-) + +diff --git a/arch/riscv/kernel/probes/uprobes.c b/arch/riscv/kernel/probes/uprobes.c +index 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 + diff --git a/queue-5.15/serial-msm-configure-correct-working-mode-before-sta.patch b/queue-5.15/serial-msm-configure-correct-working-mode-before-sta.patch new file mode 100644 index 0000000000..f7dfdfed8a --- /dev/null +++ b/queue-5.15/serial-msm-configure-correct-working-mode-before-sta.patch @@ -0,0 +1,60 @@ +From 7ca7c5e6908c8a1e9ce3c1d33577705f99f017bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 8 Apr 2025 19:22:47 +0200 +Subject: serial: msm: Configure correct working mode before starting earlycon + +From: Stephan Gerhold + +[ Upstream commit 7094832b5ac861b0bd7ed8866c93cb15ef619996 ] + +The MSM UART DM controller supports different working modes, e.g. DMA or +the "single-character mode", where all reads/writes operate on a single +character rather than 4 chars (32-bit) at once. When using earlycon, +__msm_console_write() always writes 4 characters at a time, but we don't +know which mode the bootloader was using and we don't set the mode either. + +This causes garbled output if the bootloader was using the single-character +mode, because only every 4th character appears in the serial console, e.g. + + "[ 00oni pi 000xf0[ 00i s 5rm9(l)l s 1 1 SPMTA 7:C 5[ 00A ade k d[ + 00ano:ameoi .Q1B[ 00ac _idaM00080oo'" + +If the bootloader was using the DMA ("DM") mode, output would likely fail +entirely. Later, when the full serial driver probes, the port is +re-initialized and output works as expected. + +Fix this also for earlycon by clearing the DMEN register and +reset+re-enable the transmitter to apply the change. This ensures the +transmitter is in the expected state before writing any output. + +Cc: stable +Fixes: 0efe72963409 ("tty: serial: msm: Add earlycon support") +Signed-off-by: Stephan Gerhold +Reviewed-by: Neil Armstrong +Link: https://lore.kernel.org/r/20250408-msm-serial-earlycon-v1-1-429080127530@linaro.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/msm_serial.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c +index 03ff63438e772..9740bc301cc27 100644 +--- a/drivers/tty/serial/msm_serial.c ++++ b/drivers/tty/serial/msm_serial.c +@@ -1732,6 +1732,12 @@ msm_serial_early_console_setup_dm(struct earlycon_device *device, + if (!device->port.membase) + return -ENODEV; + ++ /* Disable DM / single-character modes */ ++ msm_write(&device->port, 0, UARTDM_DMEN); ++ msm_write(&device->port, MSM_UART_CR_CMD_RESET_RX, MSM_UART_CR); ++ msm_write(&device->port, MSM_UART_CR_CMD_RESET_TX, MSM_UART_CR); ++ msm_write(&device->port, MSM_UART_CR_TX_ENABLE, MSM_UART_CR); ++ + device->con->write = msm_serial_early_write_dm; + return 0; + } +-- +2.39.5 + diff --git a/queue-5.15/series b/queue-5.15/series index 036ebd5295..537d35b987 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -42,3 +42,22 @@ net-hns3-defer-calling-ptp_clock_register.patch pci-imx6-skip-controller_id-generation-logic-for-i.mx7d.patch of-module-add-buffer-overflow-check-in-of_modalias.patch net-hns3-fix-deadlock-issue-when-externel_lb-and-reset-are-executed-together.patch +firmware-arm_scmi-balance-device-refcount-when-destr.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-add-const-to-of_device_id.patch +irqchip-gic-v2m-mark-a-few-functions-__init.patch +irqchip-gic-v2m-prevent-use-after-free-of-gicv2m_get.patch +serial-msm-configure-correct-working-mode-before-sta.patch +riscv-uprobes-add-missing-fence.i-after-building-the.patch +cpufreq-intel_pstate-process-hwp-guaranteed-change-n.patch +cpufreq-intel_pstate-update-cpuinfo.max_freq-on-hwp_.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 diff --git a/queue-5.15/spi-tegra114-don-t-fail-set_cs_timing-when-delays-ar.patch b/queue-5.15/spi-tegra114-don-t-fail-set_cs_timing-when-delays-ar.patch new file mode 100644 index 0000000000..e8228c51e1 --- /dev/null +++ b/queue-5.15/spi-tegra114-don-t-fail-set_cs_timing-when-delays-ar.patch @@ -0,0 +1,44 @@ +From 781aebf1222acd569312d0568eb700bcfaef90f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://patch.msgid.link/20250423-spi-tegra114-v1-1-2d608bcc12f9@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + 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 b6f081227cbd4..af9ed52445fe6 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-5.15/spi-tegra114-remove-unnecessary-null-pointer-checks.patch b/queue-5.15/spi-tegra114-remove-unnecessary-null-pointer-checks.patch new file mode 100644 index 0000000000..c456c1074b --- /dev/null +++ b/queue-5.15/spi-tegra114-remove-unnecessary-null-pointer-checks.patch @@ -0,0 +1,74 @@ +From c47743b1dc5476f8cec47629183a425586b25a69 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 15 Aug 2023 12:20:58 +0300 +Subject: spi: tegra114: Remove unnecessary NULL-pointer checks + +From: Alexander Danilenko + +[ 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 +Link: https://lore.kernel.org/r/20230815092058.4083-1-al.b.danilenko@gmail.com +Signed-off-by: Mark Brown +Stable-dep-of: 4426e6b4ecf6 ("spi: tegra114: Don't fail set_cs_timing when delays are zero") +Signed-off-by: Sasha Levin +--- + 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 8f345247a8c32..b6f081227cbd4 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 +