130 lines
4.1 KiB
Diff
130 lines
4.1 KiB
Diff
From: Thomas Gleixner <tglx@linutronix.de>
|
|
Date: Thu, 13 Apr 2017 10:22:43 +0200
|
|
Subject: [PATCH 12/13] cpufreq/sparc-us2e: Replace racy task affinity logic
|
|
Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/4.11/older/patches-4.11.9-rt7.tar.xz
|
|
|
|
The access to the HBIRD_ESTAR_MODE register in the cpu frequency control
|
|
functions must happen on the target CPU. This is achieved by temporarily
|
|
setting the affinity of the calling user space thread to the requested CPU
|
|
and reset it to the original affinity afterwards.
|
|
|
|
That's racy vs. CPU hotplug and concurrent affinity settings for that
|
|
thread resulting in code executing on the wrong CPU and overwriting the
|
|
new affinity setting.
|
|
|
|
Replace it by a straight forward smp function call.
|
|
|
|
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
|
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
|
|
Cc: Fenghua Yu <fenghua.yu@intel.com>
|
|
Cc: Tony Luck <tony.luck@intel.com>
|
|
Cc: Herbert Xu <herbert@gondor.apana.org.au>
|
|
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
|
|
Cc: Peter Zijlstra <peterz@infradead.org>
|
|
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
|
|
Cc: Sebastian Siewior <bigeasy@linutronix.de>
|
|
Cc: linux-pm@vger.kernel.org
|
|
Cc: Lai Jiangshan <jiangshanlai@gmail.com>
|
|
Cc: Michael Ellerman <mpe@ellerman.id.au>
|
|
Cc: Tejun Heo <tj@kernel.org>
|
|
Cc: "David S. Miller" <davem@davemloft.net>
|
|
Cc: Len Brown <lenb@kernel.org>
|
|
Link: http://lkml.kernel.org/r/alpine.DEB.2.20.1704131020280.2408@nanos
|
|
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
|
---
|
|
drivers/cpufreq/sparc-us2e-cpufreq.c | 45 ++++++++++++++++-------------------
|
|
1 file changed, 21 insertions(+), 24 deletions(-)
|
|
|
|
--- a/drivers/cpufreq/sparc-us2e-cpufreq.c
|
|
+++ b/drivers/cpufreq/sparc-us2e-cpufreq.c
|
|
@@ -118,10 +118,6 @@ static void us2e_transition(unsigned lon
|
|
unsigned long clock_tick,
|
|
unsigned long old_divisor, unsigned long divisor)
|
|
{
|
|
- unsigned long flags;
|
|
-
|
|
- local_irq_save(flags);
|
|
-
|
|
estar &= ~ESTAR_MODE_DIV_MASK;
|
|
|
|
/* This is based upon the state transition diagram in the IIe manual. */
|
|
@@ -152,8 +148,6 @@ static void us2e_transition(unsigned lon
|
|
} else {
|
|
BUG();
|
|
}
|
|
-
|
|
- local_irq_restore(flags);
|
|
}
|
|
|
|
static unsigned long index_to_estar_mode(unsigned int index)
|
|
@@ -229,48 +223,51 @@ static unsigned long estar_to_divisor(un
|
|
return ret;
|
|
}
|
|
|
|
+static void __us2e_freq_get(void *arg)
|
|
+{
|
|
+ unsigned long *estar = arg;
|
|
+
|
|
+ *estar = read_hbreg(HBIRD_ESTAR_MODE_ADDR);
|
|
+}
|
|
+
|
|
static unsigned int us2e_freq_get(unsigned int cpu)
|
|
{
|
|
- cpumask_t cpus_allowed;
|
|
unsigned long clock_tick, estar;
|
|
|
|
- cpumask_copy(&cpus_allowed, ¤t->cpus_allowed);
|
|
- set_cpus_allowed_ptr(current, cpumask_of(cpu));
|
|
-
|
|
clock_tick = sparc64_get_clock_tick(cpu) / 1000;
|
|
- estar = read_hbreg(HBIRD_ESTAR_MODE_ADDR);
|
|
-
|
|
- set_cpus_allowed_ptr(current, &cpus_allowed);
|
|
+ if (smp_call_function_single(cpu, __us2e_freq_get, &estar, 1))
|
|
+ return 0;
|
|
|
|
return clock_tick / estar_to_divisor(estar);
|
|
}
|
|
|
|
-static int us2e_freq_target(struct cpufreq_policy *policy, unsigned int index)
|
|
+static void __us2e_freq_target(void *arg)
|
|
{
|
|
- unsigned int cpu = policy->cpu;
|
|
+ unsigned int cpu = smp_processor_id();
|
|
+ unsigned int *index = arg;
|
|
unsigned long new_bits, new_freq;
|
|
unsigned long clock_tick, divisor, old_divisor, estar;
|
|
- cpumask_t cpus_allowed;
|
|
-
|
|
- cpumask_copy(&cpus_allowed, ¤t->cpus_allowed);
|
|
- set_cpus_allowed_ptr(current, cpumask_of(cpu));
|
|
|
|
new_freq = clock_tick = sparc64_get_clock_tick(cpu) / 1000;
|
|
- new_bits = index_to_estar_mode(index);
|
|
- divisor = index_to_divisor(index);
|
|
+ new_bits = index_to_estar_mode(*index);
|
|
+ divisor = index_to_divisor(*index);
|
|
new_freq /= divisor;
|
|
|
|
estar = read_hbreg(HBIRD_ESTAR_MODE_ADDR);
|
|
|
|
old_divisor = estar_to_divisor(estar);
|
|
|
|
- if (old_divisor != divisor)
|
|
+ if (old_divisor != divisor) {
|
|
us2e_transition(estar, new_bits, clock_tick * 1000,
|
|
old_divisor, divisor);
|
|
+ }
|
|
+}
|
|
|
|
- set_cpus_allowed_ptr(current, &cpus_allowed);
|
|
+static int us2e_freq_target(struct cpufreq_policy *policy, unsigned int index)
|
|
+{
|
|
+ unsigned int cpu = policy->cpu;
|
|
|
|
- return 0;
|
|
+ return smp_call_function_single(cpu, __us2e_freq_target, &index, 1);
|
|
}
|
|
|
|
static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy)
|