diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2007-07-11 21:18:04 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-07-16 07:04:16 -0400 |
commit | 13077d80286205e02eebe1c2786a914a4bbd2588 (patch) | |
tree | 837b11e18353eaf6550ec9f831adedcada1986ef /arch/sparc64/kernel/power.c | |
parent | 2c4f4ecb7a421e0be6632d3366f0bc7cdf1e38b1 (diff) |
[SPARC64]: Export powerd facilities for external entities.
Besides the existing usage for power-button interrupts, we'll
want to make use of this code for domain-services where the
LDOM manager can send reboot requests to the guest node.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/power.c')
-rw-r--r-- | arch/sparc64/kernel/power.c | 54 |
1 files changed, 31 insertions, 23 deletions
diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c index 5d6adea3967f..8dd4294ad21e 100644 --- a/arch/sparc64/kernel/power.c +++ b/arch/sparc64/kernel/power.c | |||
@@ -1,7 +1,6 @@ | |||
1 | /* $Id: power.c,v 1.10 2001/12/11 01:57:16 davem Exp $ | 1 | /* power.c: Power management driver. |
2 | * power.c: Power management driver. | ||
3 | * | 2 | * |
4 | * Copyright (C) 1999 David S. Miller (davem@redhat.com) | 3 | * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net) |
5 | */ | 4 | */ |
6 | 5 | ||
7 | #include <linux/kernel.h> | 6 | #include <linux/kernel.h> |
@@ -19,6 +18,7 @@ | |||
19 | #include <asm/prom.h> | 18 | #include <asm/prom.h> |
20 | #include <asm/of_device.h> | 19 | #include <asm/of_device.h> |
21 | #include <asm/io.h> | 20 | #include <asm/io.h> |
21 | #include <asm/power.h> | ||
22 | #include <asm/sstate.h> | 22 | #include <asm/sstate.h> |
23 | 23 | ||
24 | #include <linux/unistd.h> | 24 | #include <linux/unistd.h> |
@@ -29,24 +29,26 @@ | |||
29 | */ | 29 | */ |
30 | int scons_pwroff = 1; | 30 | int scons_pwroff = 1; |
31 | 31 | ||
32 | #ifdef CONFIG_PCI | ||
33 | #include <linux/pci.h> | ||
34 | static void __iomem *power_reg; | 32 | static void __iomem *power_reg; |
35 | 33 | ||
36 | static DECLARE_WAIT_QUEUE_HEAD(powerd_wait); | 34 | static DECLARE_WAIT_QUEUE_HEAD(powerd_wait); |
37 | static int button_pressed; | 35 | static int button_pressed; |
38 | 36 | ||
39 | static irqreturn_t power_handler(int irq, void *dev_id) | 37 | void wake_up_powerd(void) |
40 | { | 38 | { |
41 | if (button_pressed == 0) { | 39 | if (button_pressed == 0) { |
42 | button_pressed = 1; | 40 | button_pressed = 1; |
43 | wake_up(&powerd_wait); | 41 | wake_up(&powerd_wait); |
44 | } | 42 | } |
43 | } | ||
44 | |||
45 | static irqreturn_t power_handler(int irq, void *dev_id) | ||
46 | { | ||
47 | wake_up_powerd(); | ||
45 | 48 | ||
46 | /* FIXME: Check registers for status... */ | 49 | /* FIXME: Check registers for status... */ |
47 | return IRQ_HANDLED; | 50 | return IRQ_HANDLED; |
48 | } | 51 | } |
49 | #endif /* CONFIG_PCI */ | ||
50 | 52 | ||
51 | extern void machine_halt(void); | 53 | extern void machine_halt(void); |
52 | extern void machine_alt_power_off(void); | 54 | extern void machine_alt_power_off(void); |
@@ -56,19 +58,18 @@ void machine_power_off(void) | |||
56 | { | 58 | { |
57 | sstate_poweroff(); | 59 | sstate_poweroff(); |
58 | if (!serial_console || scons_pwroff) { | 60 | if (!serial_console || scons_pwroff) { |
59 | #ifdef CONFIG_PCI | ||
60 | if (power_reg) { | 61 | if (power_reg) { |
61 | /* Both register bits seem to have the | 62 | /* Both register bits seem to have the |
62 | * same effect, so until I figure out | 63 | * same effect, so until I figure out |
63 | * what the difference is... | 64 | * what the difference is... |
64 | */ | 65 | */ |
65 | writel(AUXIO_PCIO_CPWR_OFF | AUXIO_PCIO_SPWR_OFF, power_reg); | 66 | writel(AUXIO_PCIO_CPWR_OFF | AUXIO_PCIO_SPWR_OFF, power_reg); |
66 | } else | 67 | } else { |
67 | #endif /* CONFIG_PCI */ | ||
68 | if (poweroff_method != NULL) { | 68 | if (poweroff_method != NULL) { |
69 | poweroff_method(); | 69 | poweroff_method(); |
70 | /* not reached */ | 70 | /* not reached */ |
71 | } | 71 | } |
72 | } | ||
72 | } | 73 | } |
73 | machine_halt(); | 74 | machine_halt(); |
74 | } | 75 | } |
@@ -76,7 +77,6 @@ void machine_power_off(void) | |||
76 | void (*pm_power_off)(void) = machine_power_off; | 77 | void (*pm_power_off)(void) = machine_power_off; |
77 | EXPORT_SYMBOL(pm_power_off); | 78 | EXPORT_SYMBOL(pm_power_off); |
78 | 79 | ||
79 | #ifdef CONFIG_PCI | ||
80 | static int powerd(void *__unused) | 80 | static int powerd(void *__unused) |
81 | { | 81 | { |
82 | static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; | 82 | static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; |
@@ -86,7 +86,7 @@ static int powerd(void *__unused) | |||
86 | daemonize("powerd"); | 86 | daemonize("powerd"); |
87 | 87 | ||
88 | add_wait_queue(&powerd_wait, &wait); | 88 | add_wait_queue(&powerd_wait, &wait); |
89 | again: | 89 | |
90 | for (;;) { | 90 | for (;;) { |
91 | set_task_state(current, TASK_INTERRUPTIBLE); | 91 | set_task_state(current, TASK_INTERRUPTIBLE); |
92 | if (button_pressed) | 92 | if (button_pressed) |
@@ -100,16 +100,28 @@ again: | |||
100 | /* Ok, down we go... */ | 100 | /* Ok, down we go... */ |
101 | button_pressed = 0; | 101 | button_pressed = 0; |
102 | if (kernel_execve("/sbin/shutdown", argv, envp) < 0) { | 102 | if (kernel_execve("/sbin/shutdown", argv, envp) < 0) { |
103 | printk("powerd: shutdown execution failed\n"); | 103 | printk(KERN_ERR "powerd: shutdown execution failed\n"); |
104 | add_wait_queue(&powerd_wait, &wait); | 104 | machine_power_off(); |
105 | goto again; | ||
106 | } | 105 | } |
107 | return 0; | 106 | return 0; |
108 | } | 107 | } |
109 | 108 | ||
109 | int start_powerd(void) | ||
110 | { | ||
111 | int err; | ||
112 | |||
113 | err = kernel_thread(powerd, NULL, CLONE_FS); | ||
114 | if (err < 0) | ||
115 | printk(KERN_ERR "power: Failed to start power daemon.\n"); | ||
116 | else | ||
117 | printk(KERN_INFO "power: powerd running.\n"); | ||
118 | |||
119 | return err; | ||
120 | } | ||
121 | |||
110 | static int __init has_button_interrupt(unsigned int irq, struct device_node *dp) | 122 | static int __init has_button_interrupt(unsigned int irq, struct device_node *dp) |
111 | { | 123 | { |
112 | if (irq == PCI_IRQ_NONE) | 124 | if (irq == 0xffffffff) |
113 | return 0; | 125 | return 0; |
114 | if (!of_find_property(dp, "button", NULL)) | 126 | if (!of_find_property(dp, "button", NULL)) |
115 | return 0; | 127 | return 0; |
@@ -130,17 +142,14 @@ static int __devinit power_probe(struct of_device *op, const struct of_device_id | |||
130 | poweroff_method = machine_halt; /* able to use the standard halt */ | 142 | poweroff_method = machine_halt; /* able to use the standard halt */ |
131 | 143 | ||
132 | if (has_button_interrupt(irq, op->node)) { | 144 | if (has_button_interrupt(irq, op->node)) { |
133 | if (kernel_thread(powerd, NULL, CLONE_FS) < 0) { | 145 | if (start_powerd() < 0) |
134 | printk("Failed to start power daemon.\n"); | ||
135 | return 0; | 146 | return 0; |
136 | } | ||
137 | printk("powerd running.\n"); | ||
138 | 147 | ||
139 | if (request_irq(irq, | 148 | if (request_irq(irq, |
140 | power_handler, 0, "power", NULL) < 0) | 149 | power_handler, 0, "power", NULL) < 0) |
141 | printk("power: Error, cannot register IRQ handler.\n"); | 150 | printk(KERN_ERR "power: Cannot setup IRQ handler.\n"); |
142 | } else { | 151 | } else { |
143 | printk("not using powerd.\n"); | 152 | printk(KERN_INFO "power: Not using powerd.\n"); |
144 | } | 153 | } |
145 | 154 | ||
146 | return 0; | 155 | return 0; |
@@ -164,4 +173,3 @@ void __init power_init(void) | |||
164 | of_register_driver(&power_driver, &of_bus_type); | 173 | of_register_driver(&power_driver, &of_bus_type); |
165 | return; | 174 | return; |
166 | } | 175 | } |
167 | #endif /* CONFIG_PCI */ | ||