From: Qiuxu Zhuo <[email protected]> There is already stop_core_cpuslocked() for hardware core-level testing features, which requires near-simultaneous execution of the WRMSR instruction on all threads of a core to initiate a test. However, some hardware requires this simultaneous execution of WRMSR at the cluster level.
Add stop_cluster_cpuslocked(), a customized version of stop_machine_cpuslocked() for operating solely on the threads of a single cluster. Suggested-by: Tony Luck <[email protected]> Signed-off-by: Qiuxu Zhuo <[email protected]> Signed-off-by: Ehab Ababneh <[email protected]> --- include/linux/stop_machine.h | 15 +++++++++++++++ kernel/stop_machine.c | 35 ++++++++++++++++++++++------------- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/include/linux/stop_machine.h b/include/linux/stop_machine.h index 84e7fb627ba4..a189f405a4f2 100644 --- a/include/linux/stop_machine.h +++ b/include/linux/stop_machine.h @@ -157,6 +157,21 @@ int stop_machine_cpuslocked(cpu_stop_fn_t fn, void *data, const struct cpumask * */ int stop_core_cpuslocked(unsigned int cpu, cpu_stop_fn_t fn, void *data); +/** + * stop_cluster_cpuslocked: - stop all threads on a CPU cluster + * @cpu: any CPU in the targeted cluster + * @fn: the function to run + * @data: the data ptr for @fn() + * + * Same as above, only the CPUs associated with a single CPU cluster are affected. + * + * Context: Must be called from within a cpus_read_lock() protected region. + * + * Return: 0 if all executions of @fn returned 0, any non zero return + * value if any returned non zero. + */ +int stop_cluster_cpuslocked(unsigned int cpu, cpu_stop_fn_t fn, void *data); + int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus); #else /* CONFIG_SMP || CONFIG_HOTPLUG_CPU */ diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index d085ba1f4b44..1afda0ddfb90 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c @@ -630,32 +630,41 @@ int stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus) } EXPORT_SYMBOL_GPL(stop_machine); -#ifdef CONFIG_SCHED_SMT -/* - * INTEL_IFS is the only user of this API. That selftest can - * only be compiled if SMP=y. On x86 it selects SCHED_SMT. - * Keep the ifdefs for now. - */ -int stop_core_cpuslocked(unsigned int cpu, cpu_stop_fn_t fn, void *data) +static int stop_cpus_cpuslocked(const struct cpumask *cpus, cpu_stop_fn_t fn, void *data) { - const struct cpumask *smt_mask = cpu_smt_mask(cpu); - struct multi_stop_data msdata = { .fn = fn, .data = data, - .num_threads = cpumask_weight(smt_mask), - .active_cpus = smt_mask, + .num_threads = cpumask_weight(cpus), + .active_cpus = cpus, }; lockdep_assert_cpus_held(); - /* Set the initial state and stop all online cpus. */ + /* Set the initial state and stop all online @cpus. */ set_state(&msdata, MULTI_STOP_PREPARE); - return stop_cpus(smt_mask, multi_cpu_stop, &msdata); + return stop_cpus(cpus, multi_cpu_stop, &msdata); +} + +#ifdef CONFIG_SCHED_SMT +/* + * INTEL_IFS is the only user of this API. That selftest can + * only be compiled if SMP=y. On x86 it selects SCHED_SMT. + * Keep the ifdefs for now. + */ +int stop_core_cpuslocked(unsigned int cpu, cpu_stop_fn_t fn, void *data) +{ + return stop_cpus_cpuslocked(cpu_smt_mask(cpu), fn, data); } EXPORT_SYMBOL_GPL(stop_core_cpuslocked); #endif +int stop_cluster_cpuslocked(unsigned int cpu, cpu_stop_fn_t fn, void *data) +{ + return stop_cpus_cpuslocked(topology_cluster_cpumask(cpu), fn, data); +} +EXPORT_SYMBOL_GPL(stop_cluster_cpuslocked); + /** * stop_machine_from_inactive_cpu - stop_machine() from inactive CPU * @fn: the function to run -- 2.43.0
