diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2009-03-11 02:02:36 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-03-18 08:50:47 -0400 |
commit | af5c820a3169e81af869c113e18ec7588836cd50 (patch) | |
tree | 6c4e08ab0c3854e418a0267cf96065b13546fa1c /arch | |
parent | 30e1e6d1af2b67558bccf322af2b3e0676b209ae (diff) |
x86: cpumask: use work_on_cpu in arch/x86/kernel/microcode_core.c
Impact: don't play with current's cpumask
Straightforward indirection through work_on_cpu(). One change is
that the error code from microcode_update_cpu() is now actually
plumbed back to microcode_init_cpu(), so now we printk if it fails
on cpu hotplug.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Dmitry Adamushko <dmitry.adamushko@gmail.com>
Cc: Peter Oruba <peter.oruba@amd.com>
LKML-Reference: <200903111632.37279.rusty@rustcorp.com.au>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/microcode_core.c | 106 |
1 files changed, 61 insertions, 45 deletions
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c index c9b721ba968c..9a8dbc000563 100644 --- a/arch/x86/kernel/microcode_core.c +++ b/arch/x86/kernel/microcode_core.c | |||
@@ -108,29 +108,40 @@ struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; | |||
108 | EXPORT_SYMBOL_GPL(ucode_cpu_info); | 108 | EXPORT_SYMBOL_GPL(ucode_cpu_info); |
109 | 109 | ||
110 | #ifdef CONFIG_MICROCODE_OLD_INTERFACE | 110 | #ifdef CONFIG_MICROCODE_OLD_INTERFACE |
111 | struct update_for_cpu { | ||
112 | const void __user *buf; | ||
113 | size_t size; | ||
114 | }; | ||
115 | |||
116 | static long update_for_cpu(void *_ufc) | ||
117 | { | ||
118 | struct update_for_cpu *ufc = _ufc; | ||
119 | int error; | ||
120 | |||
121 | error = microcode_ops->request_microcode_user(smp_processor_id(), | ||
122 | ufc->buf, ufc->size); | ||
123 | if (error < 0) | ||
124 | return error; | ||
125 | if (!error) | ||
126 | microcode_ops->apply_microcode(smp_processor_id()); | ||
127 | return error; | ||
128 | } | ||
129 | |||
111 | static int do_microcode_update(const void __user *buf, size_t size) | 130 | static int do_microcode_update(const void __user *buf, size_t size) |
112 | { | 131 | { |
113 | cpumask_t old; | ||
114 | int error = 0; | 132 | int error = 0; |
115 | int cpu; | 133 | int cpu; |
116 | 134 | struct update_for_cpu ufc = { .buf = buf, .size = size }; | |
117 | old = current->cpus_allowed; | ||
118 | 135 | ||
119 | for_each_online_cpu(cpu) { | 136 | for_each_online_cpu(cpu) { |
120 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | 137 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
121 | 138 | ||
122 | if (!uci->valid) | 139 | if (!uci->valid) |
123 | continue; | 140 | continue; |
124 | 141 | error = work_on_cpu(cpu, update_for_cpu, &ufc); | |
125 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | ||
126 | error = microcode_ops->request_microcode_user(cpu, buf, size); | ||
127 | if (error < 0) | 142 | if (error < 0) |
128 | goto out; | 143 | break; |
129 | if (!error) | ||
130 | microcode_ops->apply_microcode(cpu); | ||
131 | } | 144 | } |
132 | out: | ||
133 | set_cpus_allowed_ptr(current, &old); | ||
134 | return error; | 145 | return error; |
135 | } | 146 | } |
136 | 147 | ||
@@ -205,11 +216,26 @@ MODULE_ALIAS_MISCDEV(MICROCODE_MINOR); | |||
205 | /* fake device for request_firmware */ | 216 | /* fake device for request_firmware */ |
206 | static struct platform_device *microcode_pdev; | 217 | static struct platform_device *microcode_pdev; |
207 | 218 | ||
219 | static long reload_for_cpu(void *unused) | ||
220 | { | ||
221 | struct ucode_cpu_info *uci = ucode_cpu_info + smp_processor_id(); | ||
222 | int err = 0; | ||
223 | |||
224 | mutex_lock(µcode_mutex); | ||
225 | if (uci->valid) { | ||
226 | err = microcode_ops->request_microcode_fw(smp_processor_id(), | ||
227 | µcode_pdev->dev); | ||
228 | if (!err) | ||
229 | microcode_ops->apply_microcode(smp_processor_id()); | ||
230 | } | ||
231 | mutex_unlock(µcode_mutex); | ||
232 | return err; | ||
233 | } | ||
234 | |||
208 | static ssize_t reload_store(struct sys_device *dev, | 235 | static ssize_t reload_store(struct sys_device *dev, |
209 | struct sysdev_attribute *attr, | 236 | struct sysdev_attribute *attr, |
210 | const char *buf, size_t sz) | 237 | const char *buf, size_t sz) |
211 | { | 238 | { |
212 | struct ucode_cpu_info *uci = ucode_cpu_info + dev->id; | ||
213 | char *end; | 239 | char *end; |
214 | unsigned long val = simple_strtoul(buf, &end, 0); | 240 | unsigned long val = simple_strtoul(buf, &end, 0); |
215 | int err = 0; | 241 | int err = 0; |
@@ -218,21 +244,9 @@ static ssize_t reload_store(struct sys_device *dev, | |||
218 | if (end == buf) | 244 | if (end == buf) |
219 | return -EINVAL; | 245 | return -EINVAL; |
220 | if (val == 1) { | 246 | if (val == 1) { |
221 | cpumask_t old = current->cpus_allowed; | ||
222 | |||
223 | get_online_cpus(); | 247 | get_online_cpus(); |
224 | if (cpu_online(cpu)) { | 248 | if (cpu_online(cpu)) |
225 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | 249 | err = work_on_cpu(cpu, reload_for_cpu, NULL); |
226 | mutex_lock(µcode_mutex); | ||
227 | if (uci->valid) { | ||
228 | err = microcode_ops->request_microcode_fw(cpu, | ||
229 | µcode_pdev->dev); | ||
230 | if (!err) | ||
231 | microcode_ops->apply_microcode(cpu); | ||
232 | } | ||
233 | mutex_unlock(µcode_mutex); | ||
234 | set_cpus_allowed_ptr(current, &old); | ||
235 | } | ||
236 | put_online_cpus(); | 250 | put_online_cpus(); |
237 | } | 251 | } |
238 | if (err) | 252 | if (err) |
@@ -328,9 +342,9 @@ static int microcode_resume_cpu(int cpu) | |||
328 | return 0; | 342 | return 0; |
329 | } | 343 | } |
330 | 344 | ||
331 | static void microcode_update_cpu(int cpu) | 345 | static long microcode_update_cpu(void *unused) |
332 | { | 346 | { |
333 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | 347 | struct ucode_cpu_info *uci = ucode_cpu_info + smp_processor_id(); |
334 | int err = 0; | 348 | int err = 0; |
335 | 349 | ||
336 | /* | 350 | /* |
@@ -338,30 +352,27 @@ static void microcode_update_cpu(int cpu) | |||
338 | * otherwise just request a firmware: | 352 | * otherwise just request a firmware: |
339 | */ | 353 | */ |
340 | if (uci->valid) { | 354 | if (uci->valid) { |
341 | err = microcode_resume_cpu(cpu); | 355 | err = microcode_resume_cpu(smp_processor_id()); |
342 | } else { | 356 | } else { |
343 | collect_cpu_info(cpu); | 357 | collect_cpu_info(smp_processor_id()); |
344 | if (uci->valid && system_state == SYSTEM_RUNNING) | 358 | if (uci->valid && system_state == SYSTEM_RUNNING) |
345 | err = microcode_ops->request_microcode_fw(cpu, | 359 | err = microcode_ops->request_microcode_fw( |
360 | smp_processor_id(), | ||
346 | µcode_pdev->dev); | 361 | µcode_pdev->dev); |
347 | } | 362 | } |
348 | if (!err) | 363 | if (!err) |
349 | microcode_ops->apply_microcode(cpu); | 364 | microcode_ops->apply_microcode(smp_processor_id()); |
365 | return err; | ||
350 | } | 366 | } |
351 | 367 | ||
352 | static void microcode_init_cpu(int cpu) | 368 | static int microcode_init_cpu(int cpu) |
353 | { | 369 | { |
354 | cpumask_t old = current->cpus_allowed; | 370 | int err; |
355 | |||
356 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | ||
357 | /* We should bind the task to the CPU */ | ||
358 | BUG_ON(raw_smp_processor_id() != cpu); | ||
359 | |||
360 | mutex_lock(µcode_mutex); | 371 | mutex_lock(µcode_mutex); |
361 | microcode_update_cpu(cpu); | 372 | err = work_on_cpu(cpu, microcode_update_cpu, NULL); |
362 | mutex_unlock(µcode_mutex); | 373 | mutex_unlock(µcode_mutex); |
363 | 374 | ||
364 | set_cpus_allowed_ptr(current, &old); | 375 | return err; |
365 | } | 376 | } |
366 | 377 | ||
367 | static int mc_sysdev_add(struct sys_device *sys_dev) | 378 | static int mc_sysdev_add(struct sys_device *sys_dev) |
@@ -379,8 +390,11 @@ static int mc_sysdev_add(struct sys_device *sys_dev) | |||
379 | if (err) | 390 | if (err) |
380 | return err; | 391 | return err; |
381 | 392 | ||
382 | microcode_init_cpu(cpu); | 393 | err = microcode_init_cpu(cpu); |
383 | return 0; | 394 | if (err) |
395 | sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); | ||
396 | |||
397 | return err; | ||
384 | } | 398 | } |
385 | 399 | ||
386 | static int mc_sysdev_remove(struct sys_device *sys_dev) | 400 | static int mc_sysdev_remove(struct sys_device *sys_dev) |
@@ -404,7 +418,7 @@ static int mc_sysdev_resume(struct sys_device *dev) | |||
404 | return 0; | 418 | return 0; |
405 | 419 | ||
406 | /* only CPU 0 will apply ucode here */ | 420 | /* only CPU 0 will apply ucode here */ |
407 | microcode_update_cpu(0); | 421 | microcode_update_cpu(NULL); |
408 | return 0; | 422 | return 0; |
409 | } | 423 | } |
410 | 424 | ||
@@ -424,7 +438,9 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) | |||
424 | switch (action) { | 438 | switch (action) { |
425 | case CPU_ONLINE: | 439 | case CPU_ONLINE: |
426 | case CPU_ONLINE_FROZEN: | 440 | case CPU_ONLINE_FROZEN: |
427 | microcode_init_cpu(cpu); | 441 | if (microcode_init_cpu(cpu)) |
442 | printk(KERN_ERR "microcode: failed to init CPU%d\n", | ||
443 | cpu); | ||
428 | case CPU_DOWN_FAILED: | 444 | case CPU_DOWN_FAILED: |
429 | case CPU_DOWN_FAILED_FROZEN: | 445 | case CPU_DOWN_FAILED_FROZEN: |
430 | pr_debug("microcode: CPU%d added\n", cpu); | 446 | pr_debug("microcode: CPU%d added\n", cpu); |