aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2007-07-17 16:40:06 -0400
committerLen Brown <len.brown@intel.com>2007-07-22 04:17:38 -0400
commite9b3aba887f47f9cd64de20fec9c333a932b70dc (patch)
tree574390c4b26021d0b3c1b83fbca4545946d0452e
parentd7fff6f4d1ed1bc31577df887fefcb1541923367 (diff)
ACPI: Implement the set_target() callback from pm_ops
In the future some drivers may need to use ACPI to determine the low power states in which to place their devices, but to provide the drivers with this information the ACPI core needs to know what sleep state the system is going to enter. Namely, the device's state should not be too high power for given system sleep state and, if the device is supposed to be able to wake up the system, its state should not be too low power for the wake up to be possible). For this purpose, the ACPI core needs to implement the set_target() method in 'struct pm_ops' and store the target system sleep state passed by the PM core in a variable. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Pavel Machek <pavel@ucw.cz> Acked-by: David Brownell <david-b@pacbell.net> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--drivers/acpi/sleep/main.c84
1 files changed, 52 insertions, 32 deletions
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 42127c0d612c..19f8557c711c 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -34,34 +34,54 @@ static u32 acpi_suspend_states[] = {
34 34
35static int init_8259A_after_S1; 35static int init_8259A_after_S1;
36 36
37extern int acpi_sleep_prepare(u32 acpi_state);
38extern void acpi_power_off(void);
39
40static u32 acpi_target_sleep_state = ACPI_STATE_S0;
41
42/**
43 * acpi_pm_set_target - Set the target system sleep state to the state
44 * associated with given @pm_state, if supported.
45 */
46
47static int acpi_pm_set_target(suspend_state_t pm_state)
48{
49 u32 acpi_state = acpi_suspend_states[pm_state];
50 int error = 0;
51
52 if (sleep_states[acpi_state]) {
53 acpi_target_sleep_state = acpi_state;
54 } else {
55 printk(KERN_ERR "ACPI does not support this state: %d\n",
56 pm_state);
57 error = -ENOSYS;
58 }
59 return error;
60}
61
37/** 62/**
38 * acpi_pm_prepare - Do preliminary suspend work. 63 * acpi_pm_prepare - Do preliminary suspend work.
39 * @pm_state: suspend state we're entering. 64 * @pm_state: ignored
40 * 65 *
41 * Make sure we support the state. If we do, and we need it, set the 66 * If necessary, set the firmware waking vector and do arch-specific
42 * firmware waking vector and do arch-specific nastiness to get the 67 * nastiness to get the wakeup code to the waking vector.
43 * wakeup code to the waking vector.
44 */ 68 */
45 69
46extern int acpi_sleep_prepare(u32 acpi_state);
47extern void acpi_power_off(void);
48
49static int acpi_pm_prepare(suspend_state_t pm_state) 70static int acpi_pm_prepare(suspend_state_t pm_state)
50{ 71{
51 u32 acpi_state = acpi_suspend_states[pm_state]; 72 int error = acpi_sleep_prepare(acpi_target_sleep_state);
52 73
53 if (!sleep_states[acpi_state]) { 74 if (error)
54 printk("acpi_pm_prepare does not support %d \n", pm_state); 75 acpi_target_sleep_state = ACPI_STATE_S0;
55 return -EPERM; 76
56 } 77 return error;
57 return acpi_sleep_prepare(acpi_state);
58} 78}
59 79
60/** 80/**
61 * acpi_pm_enter - Actually enter a sleep state. 81 * acpi_pm_enter - Actually enter a sleep state.
62 * @pm_state: State we're entering. 82 * @pm_state: ignored
63 * 83 *
64 * Flush caches and go to sleep. For STR or STD, we have to call 84 * Flush caches and go to sleep. For STR or S2, we have to call
65 * arch-specific assembly, which in turn call acpi_enter_sleep_state(). 85 * arch-specific assembly, which in turn call acpi_enter_sleep_state().
66 * It's unfortunate, but it works. Please fix if you're feeling frisky. 86 * It's unfortunate, but it works. Please fix if you're feeling frisky.
67 */ 87 */
@@ -70,31 +90,32 @@ static int acpi_pm_enter(suspend_state_t pm_state)
70{ 90{
71 acpi_status status = AE_OK; 91 acpi_status status = AE_OK;
72 unsigned long flags = 0; 92 unsigned long flags = 0;
73 u32 acpi_state = acpi_suspend_states[pm_state]; 93 u32 acpi_state = acpi_target_sleep_state;
74 94
75 ACPI_FLUSH_CPU_CACHE(); 95 ACPI_FLUSH_CPU_CACHE();
76 96
77 /* Do arch specific saving of state. */ 97 /* Do arch specific saving of state. */
78 if (pm_state > PM_SUSPEND_STANDBY) { 98 if (acpi_state == ACPI_STATE_S2 || acpi_state == ACPI_STATE_S3) {
79 int error = acpi_save_state_mem(); 99 int error = acpi_save_state_mem();
80 if (error) 100
101 if (error) {
102 acpi_target_sleep_state = ACPI_STATE_S0;
81 return error; 103 return error;
104 }
82 } 105 }
83 106
84 local_irq_save(flags); 107 local_irq_save(flags);
85 acpi_enable_wakeup_device(acpi_state); 108 acpi_enable_wakeup_device(acpi_state);
86 switch (pm_state) { 109 switch (acpi_state) {
87 case PM_SUSPEND_STANDBY: 110 case ACPI_STATE_S1:
88 barrier(); 111 barrier();
89 status = acpi_enter_sleep_state(acpi_state); 112 status = acpi_enter_sleep_state(acpi_state);
90 break; 113 break;
91 114
92 case PM_SUSPEND_MEM: 115 case ACPI_STATE_S2:
116 case ACPI_STATE_S3:
93 do_suspend_lowlevel(); 117 do_suspend_lowlevel();
94 break; 118 break;
95
96 default:
97 return -EINVAL;
98 } 119 }
99 120
100 /* ACPI 3.0 specs (P62) says that it's the responsabilty 121 /* ACPI 3.0 specs (P62) says that it's the responsabilty
@@ -107,12 +128,8 @@ static int acpi_pm_enter(suspend_state_t pm_state)
107 local_irq_restore(flags); 128 local_irq_restore(flags);
108 printk(KERN_DEBUG "Back to C!\n"); 129 printk(KERN_DEBUG "Back to C!\n");
109 130
110 /* restore processor state 131 /* restore processor state */
111 * We should only be here if we're coming back from STR or STD. 132 if (acpi_state == ACPI_STATE_S2 || acpi_state == ACPI_STATE_S3)
112 * And, in the case of the latter, the memory image should have already
113 * been loaded from disk.
114 */
115 if (pm_state > PM_SUSPEND_STANDBY)
116 acpi_restore_state_mem(); 133 acpi_restore_state_mem();
117 134
118 return ACPI_SUCCESS(status) ? 0 : -EFAULT; 135 return ACPI_SUCCESS(status) ? 0 : -EFAULT;
@@ -120,7 +137,7 @@ static int acpi_pm_enter(suspend_state_t pm_state)
120 137
121/** 138/**
122 * acpi_pm_finish - Finish up suspend sequence. 139 * acpi_pm_finish - Finish up suspend sequence.
123 * @pm_state: State we're coming out of. 140 * @pm_state: ignored
124 * 141 *
125 * This is called after we wake back up (or if entering the sleep state 142 * This is called after we wake back up (or if entering the sleep state
126 * failed). 143 * failed).
@@ -128,7 +145,7 @@ static int acpi_pm_enter(suspend_state_t pm_state)
128 145
129static int acpi_pm_finish(suspend_state_t pm_state) 146static int acpi_pm_finish(suspend_state_t pm_state)
130{ 147{
131 u32 acpi_state = acpi_suspend_states[pm_state]; 148 u32 acpi_state = acpi_target_sleep_state;
132 149
133 acpi_leave_sleep_state(acpi_state); 150 acpi_leave_sleep_state(acpi_state);
134 acpi_disable_wakeup_device(acpi_state); 151 acpi_disable_wakeup_device(acpi_state);
@@ -136,6 +153,8 @@ static int acpi_pm_finish(suspend_state_t pm_state)
136 /* reset firmware waking vector */ 153 /* reset firmware waking vector */
137 acpi_set_firmware_waking_vector((acpi_physical_address) 0); 154 acpi_set_firmware_waking_vector((acpi_physical_address) 0);
138 155
156 acpi_target_sleep_state = ACPI_STATE_S0;
157
139 if (init_8259A_after_S1) { 158 if (init_8259A_after_S1) {
140 printk("Broken toshiba laptop -> kicking interrupts\n"); 159 printk("Broken toshiba laptop -> kicking interrupts\n");
141 init_8259A(0); 160 init_8259A(0);
@@ -176,6 +195,7 @@ static int acpi_pm_state_valid(suspend_state_t pm_state)
176 195
177static struct pm_ops acpi_pm_ops = { 196static struct pm_ops acpi_pm_ops = {
178 .valid = acpi_pm_state_valid, 197 .valid = acpi_pm_state_valid,
198 .set_target = acpi_pm_set_target,
179 .prepare = acpi_pm_prepare, 199 .prepare = acpi_pm_prepare,
180 .enter = acpi_pm_enter, 200 .enter = acpi_pm_enter,
181 .finish = acpi_pm_finish, 201 .finish = acpi_pm_finish,