aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Starikovskiy <alexey.y.starikovskiy@intel.com>2005-03-18 16:20:46 -0500
committerLen Brown <len.brown@intel.com>2005-07-11 23:20:49 -0400
commite2a5b420f716cd1a46674b1a90389612eced916f (patch)
tree96f363f2e402d53428c046269514a82856b0cb34
parentbe91492ca871e58f61b517cfba541095bb60001c (diff)
[ACPI] ACPI poweroff fix
Register an "acpi" system device to be notified of shutdown preparation. This depends on CONFIG_PM http://bugzilla.kernel.org/show_bug.cgi?id=4041 Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--drivers/acpi/sleep/main.c74
-rw-r--r--drivers/acpi/sleep/poweroff.c81
-rw-r--r--drivers/base/sys.c1
-rw-r--r--include/linux/pm.h2
-rw-r--r--kernel/power/main.c2
5 files changed, 107 insertions, 53 deletions
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 0a5d2a94131e..7249ba2b7a27 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -1,6 +1,7 @@
1/* 1/*
2 * sleep.c - ACPI sleep support. 2 * sleep.c - ACPI sleep support.
3 * 3 *
4 * Copyright (c) 2005 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
4 * Copyright (c) 2004 David Shaohua Li <shaohua.li@intel.com> 5 * Copyright (c) 2004 David Shaohua Li <shaohua.li@intel.com>
5 * Copyright (c) 2000-2003 Patrick Mochel 6 * Copyright (c) 2000-2003 Patrick Mochel
6 * Copyright (c) 2003 Open Source Development Lab 7 * Copyright (c) 2003 Open Source Development Lab
@@ -14,7 +15,6 @@
14#include <linux/dmi.h> 15#include <linux/dmi.h>
15#include <linux/device.h> 16#include <linux/device.h>
16#include <linux/suspend.h> 17#include <linux/suspend.h>
17#include <asm/io.h>
18#include <acpi/acpi_bus.h> 18#include <acpi/acpi_bus.h>
19#include <acpi/acpi_drivers.h> 19#include <acpi/acpi_drivers.h>
20#include "sleep.h" 20#include "sleep.h"
@@ -27,10 +27,11 @@ extern void do_suspend_lowlevel_s4bios(void);
27extern void do_suspend_lowlevel(void); 27extern void do_suspend_lowlevel(void);
28 28
29static u32 acpi_suspend_states[] = { 29static u32 acpi_suspend_states[] = {
30 [PM_SUSPEND_ON] = ACPI_STATE_S0, 30 [PM_SUSPEND_ON] = ACPI_STATE_S0,
31 [PM_SUSPEND_STANDBY] = ACPI_STATE_S1, 31 [PM_SUSPEND_STANDBY] = ACPI_STATE_S1,
32 [PM_SUSPEND_MEM] = ACPI_STATE_S3, 32 [PM_SUSPEND_MEM] = ACPI_STATE_S3,
33 [PM_SUSPEND_DISK] = ACPI_STATE_S4, 33 [PM_SUSPEND_DISK] = ACPI_STATE_S4,
34 [PM_SUSPEND_MAX] = ACPI_STATE_S5
34}; 35};
35 36
36static int init_8259A_after_S1; 37static int init_8259A_after_S1;
@@ -44,30 +45,20 @@ static int init_8259A_after_S1;
44 * wakeup code to the waking vector. 45 * wakeup code to the waking vector.
45 */ 46 */
46 47
48extern int acpi_sleep_prepare(u32 acpi_state);
49extern void acpi_power_off(void);
50
47static int acpi_pm_prepare(suspend_state_t pm_state) 51static int acpi_pm_prepare(suspend_state_t pm_state)
48{ 52{
49 u32 acpi_state = acpi_suspend_states[pm_state]; 53 u32 acpi_state = acpi_suspend_states[pm_state];
50 54
51 if (!sleep_states[acpi_state]) 55 if (!sleep_states[acpi_state]) {
56 printk("acpi_pm_prepare does not support %d \n", pm_state);
52 return -EPERM; 57 return -EPERM;
53
54 /* do we have a wakeup address for S2 and S3? */
55 /* Here, we support only S4BIOS, those we set the wakeup address */
56 /* S4OS is only supported for now via swsusp.. */
57 if (pm_state == PM_SUSPEND_MEM || pm_state == PM_SUSPEND_DISK) {
58 if (!acpi_wakeup_address)
59 return -EFAULT;
60 acpi_set_firmware_waking_vector(
61 (acpi_physical_address) virt_to_phys(
62 (void *)acpi_wakeup_address));
63 } 58 }
64 ACPI_FLUSH_CPU_CACHE(); 59 return acpi_sleep_prepare(acpi_state);
65 acpi_enable_wakeup_device_prep(acpi_state);
66 acpi_enter_sleep_state_prep(acpi_state);
67 return 0;
68} 60}
69 61
70
71/** 62/**
72 * acpi_pm_enter - Actually enter a sleep state. 63 * acpi_pm_enter - Actually enter a sleep state.
73 * @pm_state: State we're entering. 64 * @pm_state: State we're entering.
@@ -92,11 +83,9 @@ static int acpi_pm_enter(suspend_state_t pm_state)
92 return error; 83 return error;
93 } 84 }
94 85
95
96 local_irq_save(flags); 86 local_irq_save(flags);
97 acpi_enable_wakeup_device(acpi_state); 87 acpi_enable_wakeup_device(acpi_state);
98 switch (pm_state) 88 switch (pm_state) {
99 {
100 case PM_SUSPEND_STANDBY: 89 case PM_SUSPEND_STANDBY:
101 barrier(); 90 barrier();
102 status = acpi_enter_sleep_state(acpi_state); 91 status = acpi_enter_sleep_state(acpi_state);
@@ -112,6 +101,10 @@ static int acpi_pm_enter(suspend_state_t pm_state)
112 else 101 else
113 do_suspend_lowlevel_s4bios(); 102 do_suspend_lowlevel_s4bios();
114 break; 103 break;
104 case PM_SUSPEND_MAX:
105 acpi_power_off();
106 break;
107
115 default: 108 default:
116 return -EINVAL; 109 return -EINVAL;
117 } 110 }
@@ -126,11 +119,9 @@ static int acpi_pm_enter(suspend_state_t pm_state)
126 if (pm_state > PM_SUSPEND_STANDBY) 119 if (pm_state > PM_SUSPEND_STANDBY)
127 acpi_restore_state_mem(); 120 acpi_restore_state_mem();
128 121
129
130 return ACPI_SUCCESS(status) ? 0 : -EFAULT; 122 return ACPI_SUCCESS(status) ? 0 : -EFAULT;
131} 123}
132 124
133
134/** 125/**
135 * acpi_pm_finish - Finish up suspend sequence. 126 * acpi_pm_finish - Finish up suspend sequence.
136 * @pm_state: State we're coming out of. 127 * @pm_state: State we're coming out of.
@@ -156,27 +147,26 @@ static int acpi_pm_finish(suspend_state_t pm_state)
156 return 0; 147 return 0;
157} 148}
158 149
159
160int acpi_suspend(u32 acpi_state) 150int acpi_suspend(u32 acpi_state)
161{ 151{
162 suspend_state_t states[] = { 152 suspend_state_t states[] = {
163 [1] = PM_SUSPEND_STANDBY, 153 [1] = PM_SUSPEND_STANDBY,
164 [3] = PM_SUSPEND_MEM, 154 [3] = PM_SUSPEND_MEM,
165 [4] = PM_SUSPEND_DISK, 155 [4] = PM_SUSPEND_DISK,
156 [5] = PM_SUSPEND_MAX
166 }; 157 };
167 158
168 if (acpi_state <= 4 && states[acpi_state]) 159 if (acpi_state < 6 && states[acpi_state])
169 return pm_suspend(states[acpi_state]); 160 return pm_suspend(states[acpi_state]);
170 return -EINVAL; 161 return -EINVAL;
171} 162}
172 163
173static struct pm_ops acpi_pm_ops = { 164static struct pm_ops acpi_pm_ops = {
174 .prepare = acpi_pm_prepare, 165 .prepare = acpi_pm_prepare,
175 .enter = acpi_pm_enter, 166 .enter = acpi_pm_enter,
176 .finish = acpi_pm_finish, 167 .finish = acpi_pm_finish,
177}; 168};
178 169
179
180/* 170/*
181 * Toshiba fails to preserve interrupts over S1, reinitialization 171 * Toshiba fails to preserve interrupts over S1, reinitialization
182 * of 8259 is needed after S1 resume. 172 * of 8259 is needed after S1 resume.
@@ -190,16 +180,16 @@ static int __init init_ints_after_s1(struct dmi_system_id *d)
190 180
191static struct dmi_system_id __initdata acpisleep_dmi_table[] = { 181static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
192 { 182 {
193 .callback = init_ints_after_s1, 183 .callback = init_ints_after_s1,
194 .ident = "Toshiba Satellite 4030cdt", 184 .ident = "Toshiba Satellite 4030cdt",
195 .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"), }, 185 .matches = {DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),},
196 }, 186 },
197 { }, 187 {},
198}; 188};
199 189
200static int __init acpi_sleep_init(void) 190static int __init acpi_sleep_init(void)
201{ 191{
202 int i = 0; 192 int i = 0;
203 193
204 dmi_check_system(acpisleep_dmi_table); 194 dmi_check_system(acpisleep_dmi_table);
205 195
@@ -207,7 +197,7 @@ static int __init acpi_sleep_init(void)
207 return 0; 197 return 0;
208 198
209 printk(KERN_INFO PREFIX "(supports"); 199 printk(KERN_INFO PREFIX "(supports");
210 for (i=0; i < ACPI_S_STATE_COUNT; i++) { 200 for (i = 0; i < ACPI_S_STATE_COUNT; i++) {
211 acpi_status status; 201 acpi_status status;
212 u8 type_a, type_b; 202 u8 type_a, type_b;
213 status = acpi_get_sleep_type_data(i, &type_a, &type_b); 203 status = acpi_get_sleep_type_data(i, &type_a, &type_b);
diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c
index da237754ded9..1fc86e6b5ab9 100644
--- a/drivers/acpi/sleep/poweroff.c
+++ b/drivers/acpi/sleep/poweroff.c
@@ -3,35 +3,100 @@
3 * 3 *
4 * AKA S5, but it is independent of whether or not the kernel supports 4 * AKA S5, but it is independent of whether or not the kernel supports
5 * any other sleep support in the system. 5 * any other sleep support in the system.
6 *
7 * Copyright (c) 2005 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
8 *
9 * This file is released under the GPLv2.
6 */ 10 */
7 11
8#include <linux/pm.h> 12#include <linux/pm.h>
9#include <linux/init.h> 13#include <linux/init.h>
10#include <acpi/acpi_bus.h> 14#include <acpi/acpi_bus.h>
11#include <linux/sched.h> 15#include <linux/sched.h>
16#include <linux/sysdev.h>
17#include <asm/io.h>
12#include "sleep.h" 18#include "sleep.h"
13 19
14static void 20int acpi_sleep_prepare(u32 acpi_state)
15acpi_power_off (void) 21{
22 /* Flag to do not allow second time invocation for S5 state */
23 static int shutdown_prepared = 0;
24#ifdef CONFIG_ACPI_SLEEP
25 /* do we have a wakeup address for S2 and S3? */
26 /* Here, we support only S4BIOS, those we set the wakeup address */
27 /* S4OS is only supported for now via swsusp.. */
28 if (acpi_state == ACPI_STATE_S3 || acpi_state == ACPI_STATE_S4) {
29 if (!acpi_wakeup_address) {
30 return -EFAULT;
31 }
32 acpi_set_firmware_waking_vector((acpi_physical_address)
33 virt_to_phys((void *)
34 acpi_wakeup_address));
35
36 }
37 ACPI_FLUSH_CPU_CACHE();
38 acpi_enable_wakeup_device_prep(acpi_state);
39#endif
40 if (acpi_state == ACPI_STATE_S5) {
41 /* Check if we were already called */
42 if (shutdown_prepared)
43 return 0;
44 acpi_wakeup_gpe_poweroff_prepare();
45 shutdown_prepared = 1;
46 }
47 acpi_enter_sleep_state_prep(acpi_state);
48 return 0;
49}
50
51void acpi_power_off(void)
16{ 52{
17 printk("%s called\n",__FUNCTION__); 53 printk("%s called\n", __FUNCTION__);
54 acpi_sleep_prepare(ACPI_STATE_S5);
55 local_irq_disable();
18 /* Some SMP machines only can poweroff in boot CPU */ 56 /* Some SMP machines only can poweroff in boot CPU */
19 set_cpus_allowed(current, cpumask_of_cpu(0)); 57 set_cpus_allowed(current, cpumask_of_cpu(0));
20 acpi_wakeup_gpe_poweroff_prepare();
21 acpi_enter_sleep_state_prep(ACPI_STATE_S5);
22 ACPI_DISABLE_IRQS();
23 acpi_enter_sleep_state(ACPI_STATE_S5); 58 acpi_enter_sleep_state(ACPI_STATE_S5);
24} 59}
25 60
61#ifdef CONFIG_PM
62
63static int acpi_shutdown(struct sys_device *x)
64{
65 return acpi_sleep_prepare(ACPI_STATE_S5);
66}
67
68static struct sysdev_class acpi_sysclass = {
69 set_kset_name("acpi"),
70 .shutdown = acpi_shutdown
71};
72
73static struct sys_device device_acpi = {
74 .id = 0,
75 .cls = &acpi_sysclass,
76};
77
78#endif
79
26static int acpi_poweroff_init(void) 80static int acpi_poweroff_init(void)
27{ 81{
28 if (!acpi_disabled) { 82 if (!acpi_disabled) {
29 u8 type_a, type_b; 83 u8 type_a, type_b;
30 acpi_status status; 84 acpi_status status;
31 85
32 status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); 86 status =
33 if (ACPI_SUCCESS(status)) 87 acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
88 if (ACPI_SUCCESS(status)) {
34 pm_power_off = acpi_power_off; 89 pm_power_off = acpi_power_off;
90#ifdef CONFIG_PM
91 {
92 int error;
93 error = sysdev_class_register(&acpi_sysclass);
94 if (!error)
95 error = sysdev_register(&device_acpi);
96 return error;
97 }
98#endif
99 }
35 } 100 }
36 return 0; 101 return 0;
37} 102}
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index 9102e3756f95..5474bf9622d5 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -22,7 +22,6 @@
22#include <linux/string.h> 22#include <linux/string.h>
23#include <linux/pm.h> 23#include <linux/pm.h>
24 24
25
26extern struct subsystem devices_subsys; 25extern struct subsystem devices_subsys;
27 26
28#define to_sysdev(k) container_of(k, struct sys_device, kobj) 27#define to_sysdev(k) container_of(k, struct sys_device, kobj)
diff --git a/include/linux/pm.h b/include/linux/pm.h
index ed2b76e75199..da88851266b8 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -175,7 +175,7 @@ struct pm_ops {
175}; 175};
176 176
177extern void pm_set_ops(struct pm_ops *); 177extern void pm_set_ops(struct pm_ops *);
178 178extern struct pm_ops *pm_ops;
179extern int pm_suspend(suspend_state_t state); 179extern int pm_suspend(suspend_state_t state);
180 180
181 181
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 4cdebc972ff2..c7eb4a833db5 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -190,7 +190,7 @@ int software_suspend(void)
190 190
191int pm_suspend(suspend_state_t state) 191int pm_suspend(suspend_state_t state)
192{ 192{
193 if (state > PM_SUSPEND_ON && state < PM_SUSPEND_MAX) 193 if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX)
194 return enter_state(state); 194 return enter_state(state);
195 return -EINVAL; 195 return -EINVAL;
196} 196}