summaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2017-04-12 16:55:03 -0400
committerThomas Gleixner <tglx@linutronix.de>2017-04-15 06:20:55 -0400
commit38f05ed04beb276f780fcd2b5c0b78c76d0b3c0c (patch)
tree2774ee6de6f56f1513e59b6c7392c7647a257e06 /drivers/cpufreq
parent8153f9ac43897f9f4786b30badc134fcc1a4fb11 (diff)
cpufreq/ia64: Replace racy task affinity logic
The get() and target() callbacks must run on the affected cpu. This is achieved by temporarily setting the affinity of the calling thread to the requested CPU and reset it to the original affinity afterwards. That's racy vs. concurrent affinity settings for that thread resulting in code executing on the wrong CPU and overwriting the new affinity setting. Replace it by work_on_cpu(). All call pathes which invoke the callbacks are already protected against CPU hotplug. 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.1704122231100.2548@nanos Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/ia64-acpi-cpufreq.c92
1 files changed, 39 insertions, 53 deletions
diff --git a/drivers/cpufreq/ia64-acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c
index e28a31a40829..a757c0a1e7b5 100644
--- a/drivers/cpufreq/ia64-acpi-cpufreq.c
+++ b/drivers/cpufreq/ia64-acpi-cpufreq.c
@@ -34,6 +34,11 @@ struct cpufreq_acpi_io {
34 unsigned int resume; 34 unsigned int resume;
35}; 35};
36 36
37struct cpufreq_acpi_req {
38 unsigned int cpu;
39 unsigned int state;
40};
41
37static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS]; 42static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS];
38 43
39static struct cpufreq_driver acpi_cpufreq_driver; 44static struct cpufreq_driver acpi_cpufreq_driver;
@@ -83,8 +88,7 @@ processor_get_pstate (
83static unsigned 88static unsigned
84extract_clock ( 89extract_clock (
85 struct cpufreq_acpi_io *data, 90 struct cpufreq_acpi_io *data,
86 unsigned value, 91 unsigned value)
87 unsigned int cpu)
88{ 92{
89 unsigned long i; 93 unsigned long i;
90 94
@@ -98,60 +102,43 @@ extract_clock (
98} 102}
99 103
100 104
101static unsigned int 105static long
102processor_get_freq ( 106processor_get_freq (
103 struct cpufreq_acpi_io *data, 107 void *arg)
104 unsigned int cpu)
105{ 108{
106 int ret = 0; 109 struct cpufreq_acpi_req *req = arg;
107 u32 value = 0; 110 unsigned int cpu = req->cpu;
108 cpumask_t saved_mask; 111 struct cpufreq_acpi_io *data = acpi_io_data[cpu];
109 unsigned long clock_freq; 112 u32 value;
113 int ret;
110 114
111 pr_debug("processor_get_freq\n"); 115 pr_debug("processor_get_freq\n");
112
113 saved_mask = current->cpus_allowed;
114 set_cpus_allowed_ptr(current, cpumask_of(cpu));
115 if (smp_processor_id() != cpu) 116 if (smp_processor_id() != cpu)
116 goto migrate_end; 117 return -EAGAIN;
117 118
118 /* processor_get_pstate gets the instantaneous frequency */ 119 /* processor_get_pstate gets the instantaneous frequency */
119 ret = processor_get_pstate(&value); 120 ret = processor_get_pstate(&value);
120
121 if (ret) { 121 if (ret) {
122 set_cpus_allowed_ptr(current, &saved_mask);
123 pr_warn("get performance failed with error %d\n", ret); 122 pr_warn("get performance failed with error %d\n", ret);
124 ret = 0; 123 return ret;
125 goto migrate_end;
126 } 124 }
127 clock_freq = extract_clock(data, value, cpu); 125 return 1000 * extract_clock(data, value);
128 ret = (clock_freq*1000);
129
130migrate_end:
131 set_cpus_allowed_ptr(current, &saved_mask);
132 return ret;
133} 126}
134 127
135 128
136static int 129static long
137processor_set_freq ( 130processor_set_freq (
138 struct cpufreq_acpi_io *data, 131 void *arg)
139 struct cpufreq_policy *policy,
140 int state)
141{ 132{
142 int ret = 0; 133 struct cpufreq_acpi_req *req = arg;
143 u32 value = 0; 134 unsigned int cpu = req->cpu;
144 cpumask_t saved_mask; 135 struct cpufreq_acpi_io *data = acpi_io_data[cpu];
145 int retval; 136 int ret, state = req->state;
137 u32 value;
146 138
147 pr_debug("processor_set_freq\n"); 139 pr_debug("processor_set_freq\n");
148 140 if (smp_processor_id() != cpu)
149 saved_mask = current->cpus_allowed; 141 return -EAGAIN;
150 set_cpus_allowed_ptr(current, cpumask_of(policy->cpu));
151 if (smp_processor_id() != policy->cpu) {
152 retval = -EAGAIN;
153 goto migrate_end;
154 }
155 142
156 if (state == data->acpi_data.state) { 143 if (state == data->acpi_data.state) {
157 if (unlikely(data->resume)) { 144 if (unlikely(data->resume)) {
@@ -159,8 +146,7 @@ processor_set_freq (
159 data->resume = 0; 146 data->resume = 0;
160 } else { 147 } else {
161 pr_debug("Already at target state (P%d)\n", state); 148 pr_debug("Already at target state (P%d)\n", state);
162 retval = 0; 149 return 0;
163 goto migrate_end;
164 } 150 }
165 } 151 }
166 152
@@ -171,7 +157,6 @@ processor_set_freq (
171 * First we write the target state's 'control' value to the 157 * First we write the target state's 'control' value to the
172 * control_register. 158 * control_register.
173 */ 159 */
174
175 value = (u32) data->acpi_data.states[state].control; 160 value = (u32) data->acpi_data.states[state].control;
176 161
177 pr_debug("Transitioning to state: 0x%08x\n", value); 162 pr_debug("Transitioning to state: 0x%08x\n", value);
@@ -179,17 +164,11 @@ processor_set_freq (
179 ret = processor_set_pstate(value); 164 ret = processor_set_pstate(value);
180 if (ret) { 165 if (ret) {
181 pr_warn("Transition failed with error %d\n", ret); 166 pr_warn("Transition failed with error %d\n", ret);
182 retval = -ENODEV; 167 return -ENODEV;
183 goto migrate_end;
184 } 168 }
185 169
186 data->acpi_data.state = state; 170 data->acpi_data.state = state;
187 171 return 0;
188 retval = 0;
189
190migrate_end:
191 set_cpus_allowed_ptr(current, &saved_mask);
192 return (retval);
193} 172}
194 173
195 174
@@ -197,11 +176,13 @@ static unsigned int
197acpi_cpufreq_get ( 176acpi_cpufreq_get (
198 unsigned int cpu) 177 unsigned int cpu)
199{ 178{
200 struct cpufreq_acpi_io *data = acpi_io_data[cpu]; 179 struct cpufreq_acpi_req req;
180 long ret;
201 181
202 pr_debug("acpi_cpufreq_get\n"); 182 req.cpu = cpu;
183 ret = work_on_cpu(cpu, processor_get_freq, &req);
203 184
204 return processor_get_freq(data, cpu); 185 return ret > 0 ? (unsigned int) ret : 0;
205} 186}
206 187
207 188
@@ -210,7 +191,12 @@ acpi_cpufreq_target (
210 struct cpufreq_policy *policy, 191 struct cpufreq_policy *policy,
211 unsigned int index) 192 unsigned int index)
212{ 193{
213 return processor_set_freq(acpi_io_data[policy->cpu], policy, index); 194 struct cpufreq_acpi_req req;
195
196 req.cpu = policy->cpu;
197 req.state = index;
198
199 return work_on_cpu(req.cpu, processor_set_freq, &req);
214} 200}
215 201
216static int 202static int