diff options
author | Thomas Renninger <trenn@suse.de> | 2012-01-19 12:18:43 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2012-01-19 21:26:32 -0500 |
commit | 99b725084450bbc6f8e1ab20a0df4cc291c342b5 (patch) | |
tree | 74d4dd48ff460cc92cf55c19aef8b5c52448e825 | |
parent | 54d5dcc45af7adbb907072d042bbece4c2b4de6e (diff) |
ACPI processor hotplug: Delay acpi_processor_start() call for hotplugged cores
Delay the setting up of features (cpuidle, throttling by calling
acpi_processor_start()) to the time when the hotplugged
core got onlined the first time and got fully
initialized.
Signed-off-by: Thomas Renninger <trenn@suse.de>
Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r-- | drivers/acpi/processor_driver.c | 72 | ||||
-rw-r--r-- | drivers/idle/intel_idle.c | 2 | ||||
-rw-r--r-- | include/acpi/processor.h | 1 |
3 files changed, 67 insertions, 8 deletions
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index bec55937cf1..2b805d7ef31 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c | |||
@@ -84,7 +84,7 @@ static int acpi_processor_remove(struct acpi_device *device, int type); | |||
84 | static void acpi_processor_notify(struct acpi_device *device, u32 event); | 84 | static void acpi_processor_notify(struct acpi_device *device, u32 event); |
85 | static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr); | 85 | static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr); |
86 | static int acpi_processor_handle_eject(struct acpi_processor *pr); | 86 | static int acpi_processor_handle_eject(struct acpi_processor *pr); |
87 | 87 | static int acpi_processor_start(struct acpi_processor *pr); | |
88 | 88 | ||
89 | static const struct acpi_device_id processor_device_ids[] = { | 89 | static const struct acpi_device_id processor_device_ids[] = { |
90 | {ACPI_PROCESSOR_OBJECT_HID, 0}, | 90 | {ACPI_PROCESSOR_OBJECT_HID, 0}, |
@@ -423,10 +423,29 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb, | |||
423 | struct acpi_processor *pr = per_cpu(processors, cpu); | 423 | struct acpi_processor *pr = per_cpu(processors, cpu); |
424 | 424 | ||
425 | if (action == CPU_ONLINE && pr) { | 425 | if (action == CPU_ONLINE && pr) { |
426 | acpi_processor_ppc_has_changed(pr, 0); | 426 | /* CPU got physically hotplugged and onlined the first time: |
427 | acpi_processor_hotplug(pr); | 427 | * Initialize missing things |
428 | acpi_processor_reevaluate_tstate(pr, action); | 428 | */ |
429 | acpi_processor_tstate_has_changed(pr); | 429 | if (pr->flags.need_hotplug_init) { |
430 | struct cpuidle_driver *idle_driver = | ||
431 | cpuidle_get_driver(); | ||
432 | |||
433 | printk(KERN_INFO "Will online and init hotplugged " | ||
434 | "CPU: %d\n", pr->id); | ||
435 | WARN(acpi_processor_start(pr), "Failed to start CPU:" | ||
436 | " %d\n", pr->id); | ||
437 | pr->flags.need_hotplug_init = 0; | ||
438 | if (idle_driver && !strcmp(idle_driver->name, | ||
439 | "intel_idle")) { | ||
440 | intel_idle_cpu_init(pr->id); | ||
441 | } | ||
442 | /* Normal CPU soft online event */ | ||
443 | } else { | ||
444 | acpi_processor_ppc_has_changed(pr, 0); | ||
445 | acpi_processor_cst_has_changed(pr); | ||
446 | acpi_processor_reevaluate_tstate(pr, action); | ||
447 | acpi_processor_tstate_has_changed(pr); | ||
448 | } | ||
430 | } | 449 | } |
431 | if (action == CPU_DEAD && pr) { | 450 | if (action == CPU_DEAD && pr) { |
432 | /* invalidate the flag.throttling after one CPU is offline */ | 451 | /* invalidate the flag.throttling after one CPU is offline */ |
@@ -440,7 +459,15 @@ static struct notifier_block acpi_cpu_notifier = | |||
440 | .notifier_call = acpi_cpu_soft_notify, | 459 | .notifier_call = acpi_cpu_soft_notify, |
441 | }; | 460 | }; |
442 | 461 | ||
443 | static int __cpuinit acpi_processor_start(struct acpi_processor *pr) | 462 | /* |
463 | * acpi_processor_start() is called by the cpu_hotplug_notifier func: | ||
464 | * acpi_cpu_soft_notify(). Getting it __cpuinit{data} is difficult, the | ||
465 | * root cause seem to be that acpi_processor_uninstall_hotplug_notify() | ||
466 | * is in the module_exit (__exit) func. Allowing acpi_processor_start() | ||
467 | * to not be in __cpuinit section, but being called from __cpuinit funcs | ||
468 | * via __ref looks like the right thing to do here. | ||
469 | */ | ||
470 | static __ref int acpi_processor_start(struct acpi_processor *pr) | ||
444 | { | 471 | { |
445 | struct acpi_device *device = per_cpu(processor_device_array, pr->id); | 472 | struct acpi_device *device = per_cpu(processor_device_array, pr->id); |
446 | int result = 0; | 473 | int result = 0; |
@@ -491,7 +518,12 @@ err_power_exit: | |||
491 | return result; | 518 | return result; |
492 | } | 519 | } |
493 | 520 | ||
494 | 521 | /* | |
522 | * Do not put anything in here which needs the core to be online. | ||
523 | * For example MSR access or setting up things which check for cpuinfo_x86 | ||
524 | * (cpu_data(cpu)) values, like CPU feature flags, family, model, etc. | ||
525 | * Such things have to be put in and set up above in acpi_processor_start() | ||
526 | */ | ||
495 | static int __cpuinit acpi_processor_add(struct acpi_device *device) | 527 | static int __cpuinit acpi_processor_add(struct acpi_device *device) |
496 | { | 528 | { |
497 | struct acpi_processor *pr = NULL; | 529 | struct acpi_processor *pr = NULL; |
@@ -546,6 +578,21 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device) | |||
546 | result = -EFAULT; | 578 | result = -EFAULT; |
547 | goto err_free_cpumask; | 579 | goto err_free_cpumask; |
548 | } | 580 | } |
581 | |||
582 | /* | ||
583 | * Do not start hotplugged CPUs now, but when they | ||
584 | * are onlined the first time | ||
585 | */ | ||
586 | if (pr->flags.need_hotplug_init) | ||
587 | return 0; | ||
588 | |||
589 | /* | ||
590 | * Do not start hotplugged CPUs now, but when they | ||
591 | * are onlined the first time | ||
592 | */ | ||
593 | if (pr->flags.need_hotplug_init) | ||
594 | return 0; | ||
595 | |||
549 | result = acpi_processor_start(pr); | 596 | result = acpi_processor_start(pr); |
550 | if (result) | 597 | if (result) |
551 | goto err_remove_sysfs; | 598 | goto err_remove_sysfs; |
@@ -751,6 +798,17 @@ static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr) | |||
751 | return AE_ERROR; | 798 | return AE_ERROR; |
752 | } | 799 | } |
753 | 800 | ||
801 | /* CPU got hot-plugged, but cpu_data is not initialized yet | ||
802 | * Set flag to delay cpu_idle/throttling initialization | ||
803 | * in: | ||
804 | * acpi_processor_add() | ||
805 | * acpi_processor_get_info() | ||
806 | * and do it when the CPU gets online the first time | ||
807 | * TBD: Cleanup above functions and try to do this more elegant. | ||
808 | */ | ||
809 | printk(KERN_INFO "CPU %d got hotplugged\n", pr->id); | ||
810 | pr->flags.need_hotplug_init = 1; | ||
811 | |||
754 | return AE_OK; | 812 | return AE_OK; |
755 | } | 813 | } |
756 | 814 | ||
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 20bce51c2e8..54ab97bae04 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c | |||
@@ -527,7 +527,7 @@ int intel_idle_cpu_init(int cpu) | |||
527 | 527 | ||
528 | return 0; | 528 | return 0; |
529 | } | 529 | } |
530 | 530 | EXPORT_SYMBOL_GPL(intel_idle_cpu_init); | |
531 | 531 | ||
532 | static int __init intel_idle_init(void) | 532 | static int __init intel_idle_init(void) |
533 | { | 533 | { |
diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 610f6fb1bbc..8cf7e98a2c7 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h | |||
@@ -195,6 +195,7 @@ struct acpi_processor_flags { | |||
195 | u8 has_cst:1; | 195 | u8 has_cst:1; |
196 | u8 power_setup_done:1; | 196 | u8 power_setup_done:1; |
197 | u8 bm_rld_set:1; | 197 | u8 bm_rld_set:1; |
198 | u8 need_hotplug_init:1; | ||
198 | }; | 199 | }; |
199 | 200 | ||
200 | struct acpi_processor { | 201 | struct acpi_processor { |