diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-26 00:25:17 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-26 00:25:17 -0500 |
commit | c41b3810c09e60664433548c5218cc6ece6a8903 (patch) | |
tree | cf9d822e3216d57a0ba3a184e9d586ad7bdf370c | |
parent | 556f12f602ac0a18a82ca83e9f8e8547688fc633 (diff) | |
parent | 4383822020c54c21eb2eb939a3233b44a51e8ca0 (diff) |
Merge tag 'pm+acpi-fixes-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull ACPI and power management fixes from Rafael Wysocki:
- Fixes for blackfin and microblaze build problems introduced by the
removal of global pm_idle. From Lars-Peter Clausen.
- OPP core build fix from Shawn Guo.
- Error condition check fix for the new imx6q-cpufreq driver from Wei
Yongjun.
- Fix for an AER driver crash related to the lack of APEI
initialization for acpi=off. From Rafael J Wysocki.
- Fix for a USB breakage on Thinkpad T430 related to ACPI power
resources and PCI wakeup from Rafael J. Wysocki.
* tag 'pm+acpi-fixes-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
ACPI / PM: Take unusual configurations of power resources into account
imx6q-cpufreq: fix return value check in imx6q_cpufreq_probe()
PM / OPP: fix condition for empty of_init_opp_table()
ACPI / APEI: Fix crash in apei_hest_parse() for acpi=off
microblaze idle: Fix compile error
blackfin idle: Fix compile error
-rw-r--r-- | arch/blackfin/kernel/process.c | 4 | ||||
-rw-r--r-- | arch/microblaze/kernel/process.c | 5 | ||||
-rw-r--r-- | drivers/acpi/apei/hest.c | 5 | ||||
-rw-r--r-- | drivers/acpi/internal.h | 2 | ||||
-rw-r--r-- | drivers/acpi/power.c | 112 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 9 | ||||
-rw-r--r-- | drivers/cpufreq/imx6q-cpufreq.c | 2 | ||||
-rw-r--r-- | include/linux/opp.h | 18 |
8 files changed, 107 insertions, 50 deletions
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c index 8061426b7df5..9782c0329c14 100644 --- a/arch/blackfin/kernel/process.c +++ b/arch/blackfin/kernel/process.c | |||
@@ -80,12 +80,10 @@ void cpu_idle(void) | |||
80 | if (cpu_is_offline(smp_processor_id())) | 80 | if (cpu_is_offline(smp_processor_id())) |
81 | cpu_die(); | 81 | cpu_die(); |
82 | #endif | 82 | #endif |
83 | if (!idle) | ||
84 | idle = default_idle; | ||
85 | tick_nohz_idle_enter(); | 83 | tick_nohz_idle_enter(); |
86 | rcu_idle_enter(); | 84 | rcu_idle_enter(); |
87 | while (!need_resched()) | 85 | while (!need_resched()) |
88 | idle(); | 86 | default_idle(); |
89 | rcu_idle_exit(); | 87 | rcu_idle_exit(); |
90 | tick_nohz_idle_exit(); | 88 | tick_nohz_idle_exit(); |
91 | preempt_enable_no_resched(); | 89 | preempt_enable_no_resched(); |
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c index 6ff2dcff3410..08f87343f8d0 100644 --- a/arch/microblaze/kernel/process.c +++ b/arch/microblaze/kernel/process.c | |||
@@ -97,13 +97,10 @@ void cpu_idle(void) | |||
97 | 97 | ||
98 | /* endless idle loop with no priority at all */ | 98 | /* endless idle loop with no priority at all */ |
99 | while (1) { | 99 | while (1) { |
100 | if (!idle) | ||
101 | idle = default_idle; | ||
102 | |||
103 | tick_nohz_idle_enter(); | 100 | tick_nohz_idle_enter(); |
104 | rcu_idle_enter(); | 101 | rcu_idle_enter(); |
105 | while (!need_resched()) | 102 | while (!need_resched()) |
106 | idle(); | 103 | default_idle(); |
107 | rcu_idle_exit(); | 104 | rcu_idle_exit(); |
108 | tick_nohz_idle_exit(); | 105 | tick_nohz_idle_exit(); |
109 | 106 | ||
diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index 7f00cf38098f..f5ef5d54e4ac 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c | |||
@@ -89,7 +89,7 @@ int apei_hest_parse(apei_hest_func_t func, void *data) | |||
89 | struct acpi_hest_header *hest_hdr; | 89 | struct acpi_hest_header *hest_hdr; |
90 | int i, rc, len; | 90 | int i, rc, len; |
91 | 91 | ||
92 | if (hest_disable) | 92 | if (hest_disable || !hest_tab) |
93 | return -EINVAL; | 93 | return -EINVAL; |
94 | 94 | ||
95 | hest_hdr = (struct acpi_hest_header *)(hest_tab + 1); | 95 | hest_hdr = (struct acpi_hest_header *)(hest_tab + 1); |
@@ -216,9 +216,6 @@ void __init acpi_hest_init(void) | |||
216 | return; | 216 | return; |
217 | } | 217 | } |
218 | 218 | ||
219 | if (acpi_disabled) | ||
220 | goto err; | ||
221 | |||
222 | status = acpi_get_table(ACPI_SIG_HEST, 0, | 219 | status = acpi_get_table(ACPI_SIG_HEST, 0, |
223 | (struct acpi_table_header **)&hest_tab); | 220 | (struct acpi_table_header **)&hest_tab); |
224 | if (status == AE_NOT_FOUND) | 221 | if (status == AE_NOT_FOUND) |
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index c8b70b5b2814..3c94a732b4b3 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h | |||
@@ -71,7 +71,7 @@ int acpi_extract_power_resources(union acpi_object *package, unsigned int start, | |||
71 | struct list_head *list); | 71 | struct list_head *list); |
72 | int acpi_add_power_resource(acpi_handle handle); | 72 | int acpi_add_power_resource(acpi_handle handle); |
73 | void acpi_power_add_remove_device(struct acpi_device *adev, bool add); | 73 | void acpi_power_add_remove_device(struct acpi_device *adev, bool add); |
74 | int acpi_power_min_system_level(struct list_head *list); | 74 | int acpi_power_wakeup_list_init(struct list_head *list, int *system_level); |
75 | int acpi_device_sleep_wake(struct acpi_device *dev, | 75 | int acpi_device_sleep_wake(struct acpi_device *dev, |
76 | int enable, int sleep_state, int dev_state); | 76 | int enable, int sleep_state, int dev_state); |
77 | int acpi_power_get_inferred_state(struct acpi_device *device, int *state); | 77 | int acpi_power_get_inferred_state(struct acpi_device *device, int *state); |
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index b820528a5fa3..34f5ef11d427 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c | |||
@@ -73,6 +73,7 @@ struct acpi_power_resource { | |||
73 | u32 system_level; | 73 | u32 system_level; |
74 | u32 order; | 74 | u32 order; |
75 | unsigned int ref_count; | 75 | unsigned int ref_count; |
76 | bool wakeup_enabled; | ||
76 | struct mutex resource_lock; | 77 | struct mutex resource_lock; |
77 | }; | 78 | }; |
78 | 79 | ||
@@ -272,11 +273,9 @@ static int __acpi_power_on(struct acpi_power_resource *resource) | |||
272 | return 0; | 273 | return 0; |
273 | } | 274 | } |
274 | 275 | ||
275 | static int acpi_power_on(struct acpi_power_resource *resource) | 276 | static int acpi_power_on_unlocked(struct acpi_power_resource *resource) |
276 | { | 277 | { |
277 | int result = 0;; | 278 | int result = 0; |
278 | |||
279 | mutex_lock(&resource->resource_lock); | ||
280 | 279 | ||
281 | if (resource->ref_count++) { | 280 | if (resource->ref_count++) { |
282 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 281 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
@@ -293,9 +292,16 @@ static int acpi_power_on(struct acpi_power_resource *resource) | |||
293 | schedule_work(&dep->work); | 292 | schedule_work(&dep->work); |
294 | } | 293 | } |
295 | } | 294 | } |
295 | return result; | ||
296 | } | ||
296 | 297 | ||
297 | mutex_unlock(&resource->resource_lock); | 298 | static int acpi_power_on(struct acpi_power_resource *resource) |
299 | { | ||
300 | int result; | ||
298 | 301 | ||
302 | mutex_lock(&resource->resource_lock); | ||
303 | result = acpi_power_on_unlocked(resource); | ||
304 | mutex_unlock(&resource->resource_lock); | ||
299 | return result; | 305 | return result; |
300 | } | 306 | } |
301 | 307 | ||
@@ -313,17 +319,15 @@ static int __acpi_power_off(struct acpi_power_resource *resource) | |||
313 | return 0; | 319 | return 0; |
314 | } | 320 | } |
315 | 321 | ||
316 | static int acpi_power_off(struct acpi_power_resource *resource) | 322 | static int acpi_power_off_unlocked(struct acpi_power_resource *resource) |
317 | { | 323 | { |
318 | int result = 0; | 324 | int result = 0; |
319 | 325 | ||
320 | mutex_lock(&resource->resource_lock); | ||
321 | |||
322 | if (!resource->ref_count) { | 326 | if (!resource->ref_count) { |
323 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 327 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
324 | "Power resource [%s] already off", | 328 | "Power resource [%s] already off", |
325 | resource->name)); | 329 | resource->name)); |
326 | goto unlock; | 330 | return 0; |
327 | } | 331 | } |
328 | 332 | ||
329 | if (--resource->ref_count) { | 333 | if (--resource->ref_count) { |
@@ -335,10 +339,16 @@ static int acpi_power_off(struct acpi_power_resource *resource) | |||
335 | if (result) | 339 | if (result) |
336 | resource->ref_count++; | 340 | resource->ref_count++; |
337 | } | 341 | } |
342 | return result; | ||
343 | } | ||
338 | 344 | ||
339 | unlock: | 345 | static int acpi_power_off(struct acpi_power_resource *resource) |
340 | mutex_unlock(&resource->resource_lock); | 346 | { |
347 | int result; | ||
341 | 348 | ||
349 | mutex_lock(&resource->resource_lock); | ||
350 | result = acpi_power_off_unlocked(resource); | ||
351 | mutex_unlock(&resource->resource_lock); | ||
342 | return result; | 352 | return result; |
343 | } | 353 | } |
344 | 354 | ||
@@ -521,18 +531,35 @@ void acpi_power_add_remove_device(struct acpi_device *adev, bool add) | |||
521 | } | 531 | } |
522 | } | 532 | } |
523 | 533 | ||
524 | int acpi_power_min_system_level(struct list_head *list) | 534 | int acpi_power_wakeup_list_init(struct list_head *list, int *system_level_p) |
525 | { | 535 | { |
526 | struct acpi_power_resource_entry *entry; | 536 | struct acpi_power_resource_entry *entry; |
527 | int system_level = 5; | 537 | int system_level = 5; |
528 | 538 | ||
529 | list_for_each_entry(entry, list, node) { | 539 | list_for_each_entry(entry, list, node) { |
530 | struct acpi_power_resource *resource = entry->resource; | 540 | struct acpi_power_resource *resource = entry->resource; |
541 | acpi_handle handle = resource->device.handle; | ||
542 | int result; | ||
543 | int state; | ||
531 | 544 | ||
545 | mutex_lock(&resource->resource_lock); | ||
546 | |||
547 | result = acpi_power_get_state(handle, &state); | ||
548 | if (result) { | ||
549 | mutex_unlock(&resource->resource_lock); | ||
550 | return result; | ||
551 | } | ||
552 | if (state == ACPI_POWER_RESOURCE_STATE_ON) { | ||
553 | resource->ref_count++; | ||
554 | resource->wakeup_enabled = true; | ||
555 | } | ||
532 | if (system_level > resource->system_level) | 556 | if (system_level > resource->system_level) |
533 | system_level = resource->system_level; | 557 | system_level = resource->system_level; |
558 | |||
559 | mutex_unlock(&resource->resource_lock); | ||
534 | } | 560 | } |
535 | return system_level; | 561 | *system_level_p = system_level; |
562 | return 0; | ||
536 | } | 563 | } |
537 | 564 | ||
538 | /* -------------------------------------------------------------------------- | 565 | /* -------------------------------------------------------------------------- |
@@ -610,6 +637,7 @@ int acpi_device_sleep_wake(struct acpi_device *dev, | |||
610 | */ | 637 | */ |
611 | int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state) | 638 | int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state) |
612 | { | 639 | { |
640 | struct acpi_power_resource_entry *entry; | ||
613 | int err = 0; | 641 | int err = 0; |
614 | 642 | ||
615 | if (!dev || !dev->wakeup.flags.valid) | 643 | if (!dev || !dev->wakeup.flags.valid) |
@@ -620,17 +648,31 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state) | |||
620 | if (dev->wakeup.prepare_count++) | 648 | if (dev->wakeup.prepare_count++) |
621 | goto out; | 649 | goto out; |
622 | 650 | ||
623 | err = acpi_power_on_list(&dev->wakeup.resources); | 651 | list_for_each_entry(entry, &dev->wakeup.resources, node) { |
624 | if (err) { | 652 | struct acpi_power_resource *resource = entry->resource; |
625 | dev_err(&dev->dev, "Cannot turn wakeup power resources on\n"); | 653 | |
626 | dev->wakeup.flags.valid = 0; | 654 | mutex_lock(&resource->resource_lock); |
627 | } else { | 655 | |
628 | /* | 656 | if (!resource->wakeup_enabled) { |
629 | * Passing 3 as the third argument below means the device may be | 657 | err = acpi_power_on_unlocked(resource); |
630 | * put into arbitrary power state afterward. | 658 | if (!err) |
631 | */ | 659 | resource->wakeup_enabled = true; |
632 | err = acpi_device_sleep_wake(dev, 1, sleep_state, 3); | 660 | } |
661 | |||
662 | mutex_unlock(&resource->resource_lock); | ||
663 | |||
664 | if (err) { | ||
665 | dev_err(&dev->dev, | ||
666 | "Cannot turn wakeup power resources on\n"); | ||
667 | dev->wakeup.flags.valid = 0; | ||
668 | goto out; | ||
669 | } | ||
633 | } | 670 | } |
671 | /* | ||
672 | * Passing 3 as the third argument below means the device may be | ||
673 | * put into arbitrary power state afterward. | ||
674 | */ | ||
675 | err = acpi_device_sleep_wake(dev, 1, sleep_state, 3); | ||
634 | if (err) | 676 | if (err) |
635 | dev->wakeup.prepare_count = 0; | 677 | dev->wakeup.prepare_count = 0; |
636 | 678 | ||
@@ -647,6 +689,7 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state) | |||
647 | */ | 689 | */ |
648 | int acpi_disable_wakeup_device_power(struct acpi_device *dev) | 690 | int acpi_disable_wakeup_device_power(struct acpi_device *dev) |
649 | { | 691 | { |
692 | struct acpi_power_resource_entry *entry; | ||
650 | int err = 0; | 693 | int err = 0; |
651 | 694 | ||
652 | if (!dev || !dev->wakeup.flags.valid) | 695 | if (!dev || !dev->wakeup.flags.valid) |
@@ -668,10 +711,25 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev) | |||
668 | if (err) | 711 | if (err) |
669 | goto out; | 712 | goto out; |
670 | 713 | ||
671 | err = acpi_power_off_list(&dev->wakeup.resources); | 714 | list_for_each_entry(entry, &dev->wakeup.resources, node) { |
672 | if (err) { | 715 | struct acpi_power_resource *resource = entry->resource; |
673 | dev_err(&dev->dev, "Cannot turn wakeup power resources off\n"); | 716 | |
674 | dev->wakeup.flags.valid = 0; | 717 | mutex_lock(&resource->resource_lock); |
718 | |||
719 | if (resource->wakeup_enabled) { | ||
720 | err = acpi_power_off_unlocked(resource); | ||
721 | if (!err) | ||
722 | resource->wakeup_enabled = false; | ||
723 | } | ||
724 | |||
725 | mutex_unlock(&resource->resource_lock); | ||
726 | |||
727 | if (err) { | ||
728 | dev_err(&dev->dev, | ||
729 | "Cannot turn wakeup power resources off\n"); | ||
730 | dev->wakeup.flags.valid = 0; | ||
731 | break; | ||
732 | } | ||
675 | } | 733 | } |
676 | 734 | ||
677 | out: | 735 | out: |
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 4be408756adc..5e7e991717d7 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -1002,7 +1002,14 @@ static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, | |||
1002 | if (!list_empty(&wakeup->resources)) { | 1002 | if (!list_empty(&wakeup->resources)) { |
1003 | int sleep_state; | 1003 | int sleep_state; |
1004 | 1004 | ||
1005 | sleep_state = acpi_power_min_system_level(&wakeup->resources); | 1005 | err = acpi_power_wakeup_list_init(&wakeup->resources, |
1006 | &sleep_state); | ||
1007 | if (err) { | ||
1008 | acpi_handle_warn(handle, "Retrieving current states " | ||
1009 | "of wakeup power resources failed\n"); | ||
1010 | acpi_power_resources_list_free(&wakeup->resources); | ||
1011 | goto out; | ||
1012 | } | ||
1006 | if (sleep_state < wakeup->sleep_state) { | 1013 | if (sleep_state < wakeup->sleep_state) { |
1007 | acpi_handle_warn(handle, "Overriding _PRW sleep state " | 1014 | acpi_handle_warn(handle, "Overriding _PRW sleep state " |
1008 | "(S%d) by S%d from power resources\n", | 1015 | "(S%d) by S%d from power resources\n", |
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index d6b6ef350cb6..54e336de373b 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c | |||
@@ -245,7 +245,7 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) | |||
245 | arm_reg = devm_regulator_get(cpu_dev, "arm"); | 245 | arm_reg = devm_regulator_get(cpu_dev, "arm"); |
246 | pu_reg = devm_regulator_get(cpu_dev, "pu"); | 246 | pu_reg = devm_regulator_get(cpu_dev, "pu"); |
247 | soc_reg = devm_regulator_get(cpu_dev, "soc"); | 247 | soc_reg = devm_regulator_get(cpu_dev, "soc"); |
248 | if (!arm_reg || !pu_reg || !soc_reg) { | 248 | if (IS_ERR(arm_reg) || IS_ERR(pu_reg) || IS_ERR(soc_reg)) { |
249 | dev_err(cpu_dev, "failed to get regulators\n"); | 249 | dev_err(cpu_dev, "failed to get regulators\n"); |
250 | ret = -ENOENT; | 250 | ret = -ENOENT; |
251 | goto put_node; | 251 | goto put_node; |
diff --git a/include/linux/opp.h b/include/linux/opp.h index 214e0ebcb84d..3aca2b8def33 100644 --- a/include/linux/opp.h +++ b/include/linux/opp.h | |||
@@ -47,15 +47,6 @@ int opp_enable(struct device *dev, unsigned long freq); | |||
47 | int opp_disable(struct device *dev, unsigned long freq); | 47 | int opp_disable(struct device *dev, unsigned long freq); |
48 | 48 | ||
49 | struct srcu_notifier_head *opp_get_notifier(struct device *dev); | 49 | struct srcu_notifier_head *opp_get_notifier(struct device *dev); |
50 | |||
51 | #ifdef CONFIG_OF | ||
52 | int of_init_opp_table(struct device *dev); | ||
53 | #else | ||
54 | static inline int of_init_opp_table(struct device *dev) | ||
55 | { | ||
56 | return -EINVAL; | ||
57 | } | ||
58 | #endif /* CONFIG_OF */ | ||
59 | #else | 50 | #else |
60 | static inline unsigned long opp_get_voltage(struct opp *opp) | 51 | static inline unsigned long opp_get_voltage(struct opp *opp) |
61 | { | 52 | { |
@@ -112,6 +103,15 @@ static inline struct srcu_notifier_head *opp_get_notifier(struct device *dev) | |||
112 | } | 103 | } |
113 | #endif /* CONFIG_PM_OPP */ | 104 | #endif /* CONFIG_PM_OPP */ |
114 | 105 | ||
106 | #if defined(CONFIG_PM_OPP) && defined(CONFIG_OF) | ||
107 | int of_init_opp_table(struct device *dev); | ||
108 | #else | ||
109 | static inline int of_init_opp_table(struct device *dev) | ||
110 | { | ||
111 | return -EINVAL; | ||
112 | } | ||
113 | #endif | ||
114 | |||
115 | #if defined(CONFIG_CPU_FREQ) && defined(CONFIG_PM_OPP) | 115 | #if defined(CONFIG_CPU_FREQ) && defined(CONFIG_PM_OPP) |
116 | int opp_init_cpufreq_table(struct device *dev, | 116 | int opp_init_cpufreq_table(struct device *dev, |
117 | struct cpufreq_frequency_table **table); | 117 | struct cpufreq_frequency_table **table); |