Skip to content

Commit 6e16d94

Browse files
hdellerKyle McMartin
authored andcommitted
[PARISC] Convert soft power switch driver to kthread
And remove it's reference in time.c. Allow lcd_print() to take a const char *. Signed-off-by: Helge Deller <deller@gmx.de> Signed-off-by: Kyle McMartin <kyle@parisc-linux.org>
1 parent 324c7e6 commit 6e16d94

File tree

4 files changed

+91
-118
lines changed

4 files changed

+91
-118
lines changed

arch/parisc/kernel/time.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,6 @@ irqreturn_t timer_interrupt(int irq, void *dev_id)
148148
write_sequnlock(&xtime_lock);
149149
}
150150

151-
/* check soft power switch status */
152-
if (cpu == 0 && !atomic_read(&power_tasklet.count))
153-
tasklet_schedule(&power_tasklet);
154-
155151
return IRQ_HANDLED;
156152
}
157153

drivers/parisc/led.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,7 @@ void __init register_led_regions(void)
631631
** avoid a race condition while writing the CMD/DATA register pair.
632632
**
633633
*/
634-
int lcd_print( char *str )
634+
int lcd_print( const char *str )
635635
{
636636
int i;
637637

drivers/parisc/power.c

Lines changed: 89 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* linux/drivers/parisc/power.c
33
* HP PARISC soft power switch support driver
44
*
5-
* Copyright (c) 2001-2005 Helge Deller <deller@gmx.de>
5+
* Copyright (c) 2001-2007 Helge Deller <deller@gmx.de>
66
* All rights reserved.
77
*
88
*
@@ -29,7 +29,6 @@
2929
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3030
*
3131
*
32-
*
3332
* HINT:
3433
* Support of the soft power switch button may be enabled or disabled at
3534
* runtime through the "/proc/sys/kernel/power" procfs entry.
@@ -38,34 +37,28 @@
3837
#include <linux/module.h>
3938
#include <linux/init.h>
4039
#include <linux/kernel.h>
41-
#include <linux/string.h>
4240
#include <linux/notifier.h>
4341
#include <linux/reboot.h>
4442
#include <linux/sched.h>
45-
#include <linux/interrupt.h>
46-
#include <linux/workqueue.h>
43+
#include <linux/kthread.h>
4744

4845
#include <asm/pdc.h>
4946
#include <asm/io.h>
5047
#include <asm/led.h>
51-
#include <asm/uaccess.h>
5248

49+
#define DRIVER_NAME "powersw"
50+
#define KTHREAD_NAME "kpowerswd"
5351

54-
#ifdef DEBUG
55-
# define DPRINTK(x...) printk(x)
56-
#else
57-
# define DPRINTK(x...)
58-
#endif
59-
60-
61-
/* filename in /proc which can be used to enable/disable the power switch */
62-
#define SYSCTL_FILENAME "sys/kernel/power"
52+
/* how often should the power button be polled ? */
53+
#define POWERSWITCH_POLL_PER_SEC 2
6354

55+
/* how long does the power button needs to be down until we react ? */
56+
#define POWERSWITCH_DOWN_SEC 2
6457

58+
/* assembly code to access special registers */
59+
/* taken from PCXL ERS page 82 */
6560
#define DIAG_CODE(code) (0x14000000 + ((code)<<5))
6661

67-
/* this will go to processor.h or any other place... */
68-
/* taken from PCXL ERS page 82 */
6962
#define MFCPU_X(rDiagReg, t_ch, t_th, code) \
7063
(DIAG_CODE(code) + ((rDiagReg)<<21) + ((t_ch)<<16) + ((t_th)<<0) )
7164

@@ -76,111 +69,95 @@
7669
#define __getDIAG(dr) ( { \
7770
register unsigned long __res asm("r28");\
7871
__asm__ __volatile__ ( \
79-
".word %1\n nop\n" : "=&r" (__res) : "i" (MFCPU_T(dr,28)) \
72+
".word %1" : "=&r" (__res) : "i" (MFCPU_T(dr,28) ) \
8073
); \
8174
__res; \
8275
} )
8376

84-
85-
static void deferred_poweroff(struct work_struct *unused)
86-
{
87-
if (kill_cad_pid(SIGINT, 1)) {
88-
/* just in case killing init process failed */
89-
machine_power_off();
90-
}
91-
}
92-
93-
/*
94-
* This function gets called from interrupt context.
95-
* As it's called within an interrupt, it wouldn't sync if we don't
96-
* use schedule_work().
97-
*/
98-
99-
static DECLARE_WORK(poweroff_work, deferred_poweroff);
100-
101-
static void poweroff(void)
102-
{
103-
static int powering_off __read_mostly;
104-
105-
if (powering_off)
106-
return;
107-
108-
powering_off++;
109-
schedule_work(&poweroff_work);
110-
}
111-
112-
113-
/* local time-counter for shutdown */
77+
/* local shutdown counter */
11478
static int shutdown_timer __read_mostly;
11579

11680
/* check, give feedback and start shutdown after one second */
11781
static void process_shutdown(void)
11882
{
11983
if (shutdown_timer == 0)
120-
DPRINTK(KERN_INFO "Shutdown requested...\n");
84+
printk(KERN_ALERT KTHREAD_NAME ": Shutdown requested...\n");
12185

12286
shutdown_timer++;
12387

12488
/* wait until the button was pressed for 1 second */
125-
if (shutdown_timer == HZ) {
126-
#if defined (DEBUG) || defined(CONFIG_CHASSIS_LCD_LED)
127-
static char msg[] = "Shutting down...";
128-
#endif
129-
DPRINTK(KERN_INFO "%s\n", msg);
89+
if (shutdown_timer == (POWERSWITCH_DOWN_SEC*POWERSWITCH_POLL_PER_SEC)) {
90+
static const char msg[] = "Shutting down...";
91+
printk(KERN_INFO KTHREAD_NAME ": %s\n", msg);
13092
lcd_print(msg);
131-
poweroff();
93+
94+
/* send kill signal */
95+
if (kill_cad_pid(SIGINT, 1)) {
96+
/* just in case killing init process failed */
97+
if (pm_power_off)
98+
pm_power_off();
99+
}
132100
}
133101
}
134102

135103

136-
/* main power switch tasklet struct (scheduled from time.c) */
137-
DECLARE_TASKLET_DISABLED(power_tasklet, NULL, 0);
104+
/* main power switch task struct */
105+
static struct task_struct *power_task;
106+
107+
/* filename in /proc which can be used to enable/disable the power switch */
108+
#define SYSCTL_FILENAME "sys/kernel/power"
138109

139110
/* soft power switch enabled/disabled */
140111
int pwrsw_enabled __read_mostly = 1;
141112

142-
/*
143-
* On gecko style machines (e.g. 712/xx and 715/xx)
144-
* the power switch status is stored in Bit 0 ("the highest bit")
145-
* of CPU diagnose register 25.
146-
*
147-
*/
148-
static void gecko_tasklet_func(unsigned long unused)
113+
/* main kernel thread worker. It polls the button state */
114+
static int kpowerswd(void *param)
149115
{
150-
if (unlikely(!pwrsw_enabled))
151-
return;
152-
153-
if (__getDIAG(25) & 0x80000000) {
154-
/* power switch button not pressed or released again */
155-
/* Warning: Some machines do never reset this DIAG flag! */
156-
shutdown_timer = 0;
157-
} else {
158-
process_shutdown();
159-
}
160-
}
161-
116+
__set_current_state(TASK_RUNNING);
117+
118+
do {
119+
int button_not_pressed;
120+
unsigned long soft_power_reg = (unsigned long) param;
121+
122+
schedule_timeout_interruptible(pwrsw_enabled ? HZ : HZ/POWERSWITCH_POLL_PER_SEC);
123+
__set_current_state(TASK_RUNNING);
124+
125+
if (unlikely(!pwrsw_enabled))
126+
continue;
127+
128+
if (soft_power_reg) {
129+
/*
130+
* Non-Gecko-style machines:
131+
* Check the power switch status which is read from the
132+
* real I/O location at soft_power_reg.
133+
* Bit 31 ("the lowest bit) is the status of the power switch.
134+
* This bit is "1" if the button is NOT pressed.
135+
*/
136+
button_not_pressed = (gsc_readl(soft_power_reg) & 0x1);
137+
} else {
138+
/*
139+
* On gecko style machines (e.g. 712/xx and 715/xx)
140+
* the power switch status is stored in Bit 0 ("the highest bit")
141+
* of CPU diagnose register 25.
142+
* Warning: Some machines never reset the DIAG flag, even if
143+
* the button has been released again.
144+
*/
145+
button_not_pressed = (__getDIAG(25) & 0x80000000);
146+
}
147+
148+
if (likely(button_not_pressed)) {
149+
if (unlikely(shutdown_timer && /* avoid writing if not necessary */
150+
shutdown_timer < (POWERSWITCH_DOWN_SEC*POWERSWITCH_POLL_PER_SEC))) {
151+
shutdown_timer = 0;
152+
printk(KERN_INFO KTHREAD_NAME ": Shutdown request aborted.\n");
153+
}
154+
} else
155+
process_shutdown();
156+
157+
158+
} while (!kthread_should_stop());
162159

163-
164-
/*
165-
* Check the power switch status which is read from the
166-
* real I/O location at soft_power_reg.
167-
* Bit 31 ("the lowest bit) is the status of the power switch.
168-
*/
169-
170-
static void polling_tasklet_func(unsigned long soft_power_reg)
171-
{
172-
unsigned long current_status;
173-
174-
if (unlikely(!pwrsw_enabled))
175-
return;
176-
177-
current_status = gsc_readl(soft_power_reg);
178-
if (current_status & 0x1) {
179-
/* power switch button not pressed */
180-
shutdown_timer = 0;
181-
} else {
182-
process_shutdown();
183-
}
160+
return 0;
184161
}
185162

186163

@@ -220,7 +197,7 @@ static struct notifier_block parisc_panic_block = {
220197
static int __init power_init(void)
221198
{
222199
unsigned long ret;
223-
unsigned long soft_power_reg = 0;
200+
unsigned long soft_power_reg;
224201

225202
#if 0
226203
request_irq( IRQ_FROM_REGION(CPU_IRQ_REGION)+2, &powerfail_interrupt,
@@ -235,44 +212,44 @@ static int __init power_init(void)
235212
soft_power_reg = -1UL;
236213

237214
switch (soft_power_reg) {
238-
case 0: printk(KERN_INFO "Gecko-style soft power switch enabled.\n");
239-
power_tasklet.func = gecko_tasklet_func;
215+
case 0: printk(KERN_INFO DRIVER_NAME ": Gecko-style soft power switch enabled.\n");
240216
break;
241217

242-
case -1UL: printk(KERN_INFO "Soft power switch support not available.\n");
218+
case -1UL: printk(KERN_INFO DRIVER_NAME ": Soft power switch support not available.\n");
243219
return -ENODEV;
244220

245-
default: printk(KERN_INFO "Soft power switch enabled, polling @ 0x%08lx.\n",
221+
default: printk(KERN_INFO DRIVER_NAME ": Soft power switch at 0x%08lx enabled.\n",
246222
soft_power_reg);
247-
power_tasklet.data = soft_power_reg;
248-
power_tasklet.func = polling_tasklet_func;
223+
}
224+
225+
power_task = kthread_run(kpowerswd, (void*)soft_power_reg, KTHREAD_NAME);
226+
if (IS_ERR(power_task)) {
227+
printk(KERN_ERR DRIVER_NAME ": thread creation failed. Driver not loaded.\n");
228+
pdc_soft_power_button(0);
229+
return -EIO;
249230
}
250231

251232
/* Register a call for panic conditions. */
252233
atomic_notifier_chain_register(&panic_notifier_list,
253234
&parisc_panic_block);
254235

255-
tasklet_enable(&power_tasklet);
256-
257236
return 0;
258237
}
259238

260239
static void __exit power_exit(void)
261240
{
262-
if (!power_tasklet.func)
263-
return;
241+
kthread_stop(power_task);
264242

265-
tasklet_disable(&power_tasklet);
266243
atomic_notifier_chain_unregister(&panic_notifier_list,
267244
&parisc_panic_block);
268-
power_tasklet.func = NULL;
245+
269246
pdc_soft_power_button(0);
270247
}
271248

272-
module_init(power_init);
249+
arch_initcall(power_init);
273250
module_exit(power_exit);
274251

275252

276-
MODULE_AUTHOR("Helge Deller");
253+
MODULE_AUTHOR("Helge Deller <deller@gmx.de>");
277254
MODULE_DESCRIPTION("Soft power switch driver");
278255
MODULE_LICENSE("Dual BSD/GPL");

include/asm-parisc/led.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ void __init register_led_regions(void);
3131

3232
#ifdef CONFIG_CHASSIS_LCD_LED
3333
/* writes a string to the LCD display (if possible on this h/w) */
34-
int lcd_print(char *str);
34+
int lcd_print(const char *str);
3535
#else
3636
#define lcd_print(str)
3737
#endif

0 commit comments

Comments
 (0)