diff options
author | Thomas Renninger <trenn@suse.de> | 2012-01-19 12:18:42 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2012-01-19 21:24:34 -0500 |
commit | 54d5dcc45af7adbb907072d042bbece4c2b4de6e (patch) | |
tree | a76ad45025545902b48aa6b58da630d7c87681a4 /drivers/acpi | |
parent | dcd6c92267155e70a94b3927bce681ce74b80d1f (diff) |
ACPI processor hotplug: Split up acpi_processor_add
No functional change.
This is needed because:
When a CPU gets hotplugged, it's totally uninitialized
and offline. cpuinfo_x86 struct (cpu_data(cpu)) is mostly
zero (CPU feature flags, model, family,..).
When a CPU gets hotplugged, struct processor is alloc'd,
some sysfs files are set up but acpi_processor_add()
must not try to access a MSR on this CPU or try to read
out CPU feature,family, etc.
This must be done in acpi_processor_start().
The next patch will delay the call of acpi_processor_start()
for physically hotpluggedcores, to the time when they are onlined
the first time. There it is safe then to access cpu_data(cpu)
cpuinfo_x86 struct or access MSRs which is needed to
set up cpuidle, throttling and other features.
Tested and
Signed-off-by: Thomas Renninger <trenn@suse.de>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/processor_driver.c | 92 |
1 files changed, 54 insertions, 38 deletions
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 0034ede38710..bec55937cf10 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c | |||
@@ -440,6 +440,58 @@ static struct notifier_block acpi_cpu_notifier = | |||
440 | .notifier_call = acpi_cpu_soft_notify, | 440 | .notifier_call = acpi_cpu_soft_notify, |
441 | }; | 441 | }; |
442 | 442 | ||
443 | static int __cpuinit acpi_processor_start(struct acpi_processor *pr) | ||
444 | { | ||
445 | struct acpi_device *device = per_cpu(processor_device_array, pr->id); | ||
446 | int result = 0; | ||
447 | |||
448 | #ifdef CONFIG_CPU_FREQ | ||
449 | acpi_processor_ppc_has_changed(pr, 0); | ||
450 | #endif | ||
451 | acpi_processor_get_throttling_info(pr); | ||
452 | acpi_processor_get_limit_info(pr); | ||
453 | |||
454 | if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver) | ||
455 | acpi_processor_power_init(pr, device); | ||
456 | |||
457 | pr->cdev = thermal_cooling_device_register("Processor", device, | ||
458 | &processor_cooling_ops); | ||
459 | if (IS_ERR(pr->cdev)) { | ||
460 | result = PTR_ERR(pr->cdev); | ||
461 | goto err_power_exit; | ||
462 | } | ||
463 | |||
464 | dev_dbg(&device->dev, "registered as cooling_device%d\n", | ||
465 | pr->cdev->id); | ||
466 | |||
467 | result = sysfs_create_link(&device->dev.kobj, | ||
468 | &pr->cdev->device.kobj, | ||
469 | "thermal_cooling"); | ||
470 | if (result) { | ||
471 | printk(KERN_ERR PREFIX "Create sysfs link\n"); | ||
472 | goto err_thermal_unregister; | ||
473 | } | ||
474 | result = sysfs_create_link(&pr->cdev->device.kobj, | ||
475 | &device->dev.kobj, | ||
476 | "device"); | ||
477 | if (result) { | ||
478 | printk(KERN_ERR PREFIX "Create sysfs link\n"); | ||
479 | goto err_remove_sysfs_thermal; | ||
480 | } | ||
481 | |||
482 | return 0; | ||
483 | |||
484 | err_remove_sysfs_thermal: | ||
485 | sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); | ||
486 | err_thermal_unregister: | ||
487 | thermal_cooling_device_unregister(pr->cdev); | ||
488 | err_power_exit: | ||
489 | acpi_processor_power_exit(pr, device); | ||
490 | |||
491 | return result; | ||
492 | } | ||
493 | |||
494 | |||
443 | static int __cpuinit acpi_processor_add(struct acpi_device *device) | 495 | static int __cpuinit acpi_processor_add(struct acpi_device *device) |
444 | { | 496 | { |
445 | struct acpi_processor *pr = NULL; | 497 | struct acpi_processor *pr = NULL; |
@@ -494,49 +546,13 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device) | |||
494 | result = -EFAULT; | 546 | result = -EFAULT; |
495 | goto err_free_cpumask; | 547 | goto err_free_cpumask; |
496 | } | 548 | } |
497 | 549 | result = acpi_processor_start(pr); | |
498 | #ifdef CONFIG_CPU_FREQ | 550 | if (result) |
499 | acpi_processor_ppc_has_changed(pr, 0); | ||
500 | #endif | ||
501 | acpi_processor_get_throttling_info(pr); | ||
502 | acpi_processor_get_limit_info(pr); | ||
503 | |||
504 | if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver) | ||
505 | acpi_processor_power_init(pr, device); | ||
506 | |||
507 | pr->cdev = thermal_cooling_device_register("Processor", device, | ||
508 | &processor_cooling_ops); | ||
509 | if (IS_ERR(pr->cdev)) { | ||
510 | result = PTR_ERR(pr->cdev); | ||
511 | goto err_power_exit; | ||
512 | } | ||
513 | |||
514 | dev_dbg(&device->dev, "registered as cooling_device%d\n", | ||
515 | pr->cdev->id); | ||
516 | |||
517 | result = sysfs_create_link(&device->dev.kobj, | ||
518 | &pr->cdev->device.kobj, | ||
519 | "thermal_cooling"); | ||
520 | if (result) { | ||
521 | printk(KERN_ERR PREFIX "Create sysfs link\n"); | ||
522 | goto err_thermal_unregister; | ||
523 | } | ||
524 | result = sysfs_create_link(&pr->cdev->device.kobj, | ||
525 | &device->dev.kobj, | ||
526 | "device"); | ||
527 | if (result) { | ||
528 | printk(KERN_ERR PREFIX "Create sysfs link\n"); | ||
529 | goto err_remove_sysfs; | 551 | goto err_remove_sysfs; |
530 | } | ||
531 | 552 | ||
532 | return 0; | 553 | return 0; |
533 | 554 | ||
534 | err_remove_sysfs: | 555 | err_remove_sysfs: |
535 | sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); | ||
536 | err_thermal_unregister: | ||
537 | thermal_cooling_device_unregister(pr->cdev); | ||
538 | err_power_exit: | ||
539 | acpi_processor_power_exit(pr, device); | ||
540 | sysfs_remove_link(&device->dev.kobj, "sysdev"); | 556 | sysfs_remove_link(&device->dev.kobj, "sysdev"); |
541 | err_free_cpumask: | 557 | err_free_cpumask: |
542 | free_cpumask_var(pr->throttling.shared_cpu_map); | 558 | free_cpumask_var(pr->throttling.shared_cpu_map); |