diff options
Diffstat (limited to 'drivers/acpi/processor_driver.c')
-rw-r--r-- | drivers/acpi/processor_driver.c | 154 |
1 files changed, 114 insertions, 40 deletions
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 0034ede38710..2b805d7ef317 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,6 +459,71 @@ 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 | ||
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) | ||
471 | { | ||
472 | struct acpi_device *device = per_cpu(processor_device_array, pr->id); | ||
473 | int result = 0; | ||
474 | |||
475 | #ifdef CONFIG_CPU_FREQ | ||
476 | acpi_processor_ppc_has_changed(pr, 0); | ||
477 | #endif | ||
478 | acpi_processor_get_throttling_info(pr); | ||
479 | acpi_processor_get_limit_info(pr); | ||
480 | |||
481 | if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver) | ||
482 | acpi_processor_power_init(pr, device); | ||
483 | |||
484 | pr->cdev = thermal_cooling_device_register("Processor", device, | ||
485 | &processor_cooling_ops); | ||
486 | if (IS_ERR(pr->cdev)) { | ||
487 | result = PTR_ERR(pr->cdev); | ||
488 | goto err_power_exit; | ||
489 | } | ||
490 | |||
491 | dev_dbg(&device->dev, "registered as cooling_device%d\n", | ||
492 | pr->cdev->id); | ||
493 | |||
494 | result = sysfs_create_link(&device->dev.kobj, | ||
495 | &pr->cdev->device.kobj, | ||
496 | "thermal_cooling"); | ||
497 | if (result) { | ||
498 | printk(KERN_ERR PREFIX "Create sysfs link\n"); | ||
499 | goto err_thermal_unregister; | ||
500 | } | ||
501 | result = sysfs_create_link(&pr->cdev->device.kobj, | ||
502 | &device->dev.kobj, | ||
503 | "device"); | ||
504 | if (result) { | ||
505 | printk(KERN_ERR PREFIX "Create sysfs link\n"); | ||
506 | goto err_remove_sysfs_thermal; | ||
507 | } | ||
508 | |||
509 | return 0; | ||
510 | |||
511 | err_remove_sysfs_thermal: | ||
512 | sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); | ||
513 | err_thermal_unregister: | ||
514 | thermal_cooling_device_unregister(pr->cdev); | ||
515 | err_power_exit: | ||
516 | acpi_processor_power_exit(pr, device); | ||
517 | |||
518 | return result; | ||
519 | } | ||
520 | |||
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 | */ | ||
443 | static int __cpuinit acpi_processor_add(struct acpi_device *device) | 527 | static int __cpuinit acpi_processor_add(struct acpi_device *device) |
444 | { | 528 | { |
445 | struct acpi_processor *pr = NULL; | 529 | struct acpi_processor *pr = NULL; |
@@ -495,48 +579,27 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device) | |||
495 | goto err_free_cpumask; | 579 | goto err_free_cpumask; |
496 | } | 580 | } |
497 | 581 | ||
498 | #ifdef CONFIG_CPU_FREQ | 582 | /* |
499 | acpi_processor_ppc_has_changed(pr, 0); | 583 | * Do not start hotplugged CPUs now, but when they |
500 | #endif | 584 | * are onlined the first time |
501 | acpi_processor_get_throttling_info(pr); | 585 | */ |
502 | acpi_processor_get_limit_info(pr); | 586 | if (pr->flags.need_hotplug_init) |
503 | 587 | return 0; | |
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 | 588 | ||
514 | dev_dbg(&device->dev, "registered as cooling_device%d\n", | 589 | /* |
515 | pr->cdev->id); | 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; | ||
516 | 595 | ||
517 | result = sysfs_create_link(&device->dev.kobj, | 596 | result = acpi_processor_start(pr); |
518 | &pr->cdev->device.kobj, | 597 | if (result) |
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; | 598 | goto err_remove_sysfs; |
530 | } | ||
531 | 599 | ||
532 | return 0; | 600 | return 0; |
533 | 601 | ||
534 | err_remove_sysfs: | 602 | 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"); | 603 | sysfs_remove_link(&device->dev.kobj, "sysdev"); |
541 | err_free_cpumask: | 604 | err_free_cpumask: |
542 | free_cpumask_var(pr->throttling.shared_cpu_map); | 605 | free_cpumask_var(pr->throttling.shared_cpu_map); |
@@ -735,6 +798,17 @@ static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr) | |||
735 | return AE_ERROR; | 798 | return AE_ERROR; |
736 | } | 799 | } |
737 | 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 | |||
738 | return AE_OK; | 812 | return AE_OK; |
739 | } | 813 | } |
740 | 814 | ||