[parisc-linux-cvs] linux deller

Helge Deller deller@gmx.de
Thu, 27 Jun 2002 00:23:34 +0200


--Boundary-00=_m7jG9Ny9Z1+7wmF
Content-Type: text/plain;
  charset="iso-8859-1"
Content-Transfer-Encoding: 8bit
Content-Disposition: inline

On Thursday 27 June 2002 00:20, Helge Deller wrote:
> CVSROOT:	/var/cvs
> Module name:	linux
> Changes by:	deller	02/06/26 16:20:32
>
> Modified files:
> 	.              : Makefile
> 	arch/parisc/kernel: power.c time.c
> 	include/asm-parisc: irq.h
>
> Log message:
> 2.4.18-pa42:
> - fix a long out-standing reboot-bug:
> - added re-enabling of soft-power switch in the panic notifier chain. This
> allows us now to reboot the machine if we got a panic. This never worked
> before and helps to debug kernel-problems without pulling the power cable.
> Closes bug #94 and similiar bug reports.
> - now use tasklets for checking the soft-power switch instead of a function
> pointer - added full License


--Boundary-00=_m7jG9Ny9Z1+7wmF
Content-Type: text/plain;
  charset="iso-8859-1";
  name="diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="diff"

Index: Makefile
===================================================================
RCS file: /var/cvs/linux/Makefile,v
retrieving revision 1.312
diff -u -p -r1.312 Makefile
--- Makefile	2002/06/25 20:53:16	1.312
+++ Makefile	2002/06/26 22:14:59
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 18
-EXTRAVERSION = -pa41
+EXTRAVERSION = -pa42
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
Index: arch/parisc/kernel/power.c
===================================================================
RCS file: /var/cvs/linux/arch/parisc/kernel/power.c,v
retrieving revision 1.8
diff -u -p -r1.8 power.c
--- arch/parisc/kernel/power.c	2002/04/22 00:04:10	1.8
+++ arch/parisc/kernel/power.c	2002/06/26 22:14:59
@@ -1,28 +1,46 @@
 /*
- *  linux/arch/parisc/kernel/power.c
- *  HP PARISC soft power switch support driver
+ * linux/arch/parisc/kernel/power.c
+ * HP PARISC soft power switch support driver
  *
- *  Copyright (C) 2001-2002 Helge Deller <deller@gmx.de>
+ * Copyright (c) 2001-2002 Helge Deller <deller@gmx.de>
+ * All rights reserved.
  *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ *
+ *
  * 
  *  HINT:
  *  Support of the soft power switch button may be enabled or disabled at
  *  runtime through the "/proc/sys/kernel/power" procfs entry.
- *  
- */
+ */ 
 
-/*
- * TODO:
- * - use tasklets instead of calling it from the timer-interrupt function
- * - after a special amount of time just turn the machine off (killing init may have failed!)
- * - ....
- */
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
+#include <linux/notifier.h>
 #include <linux/reboot.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
@@ -64,9 +82,11 @@
 
 static void deferred_poweroff(void *dummy)
 {
-	extern int cad_pid;	/* kernel/sys.c */
-	kill_proc(cad_pid, SIGINT, 1);
-	/* machine_power_off(); */
+	extern int cad_pid;	/* from kernel/sys.c */
+	if (kill_proc(cad_pid, SIGINT, 1)) {
+		/* just in case killing init process failed */
+		machine_power_off();
+	}
 }
 
 /*
@@ -113,6 +133,9 @@ static void process_shutdown(void)
 }
 
 
+/* main power switch tasklet struct (scheduled from time.c) */
+DECLARE_TASKLET_DISABLED(power_tasklet, NULL, 0);
+
 /* soft power switch enabled/disabled */
 #ifdef CONFIG_PROC_FS
 static int pwrsw_enabled = 1;
@@ -120,23 +143,20 @@ static int pwrsw_enabled = 1;
 #define pwrsw_enabled (1)
 #endif
 
-/* soft power switch function ptr */
-void (*check_soft_power)(void);
-
-
 /*
  * On gecko style machines (e.g. 712/xx and 715/xx) 
  * the power switch status is stored in Bit 0 ("the highest bit")
  * of CPU diagnose register 25.
  * 
  */
-static void check_soft_power_gecko(void)
+static void gecko_tasklet_func(unsigned long unused)
 {
 	if (!pwrsw_enabled)
 		return;
 
 	if (__getDIAG(25) & 0x80000000) {
 		/* power switch button not pressed or released again */
+		/* Warning: Some machines do never reset this DIAG flag! */
 		shutdown_timer = 0;
 	} else {
 		process_shutdown();
@@ -150,9 +170,8 @@ static void check_soft_power_gecko(void)
  * real I/O location at soft_power_reg.
  * Bit 31 ("the lowest bit) is the status of the power switch.
  */
-static unsigned long soft_power_reg;
 
-static void check_soft_power_polling(void)
+static void polling_tasklet_func(unsigned long soft_power_reg)
 {
         unsigned long current_status;
 	
@@ -186,6 +205,7 @@ static void powerfail_interrupt(int code
 /* 
  * /proc filesystem support 
  */
+
 #ifdef CONFIG_SYSCTL
 static int power_proc_read(char *page, char **start, off_t off, int count, 
 	int *eof, void *data)
@@ -242,7 +262,7 @@ static struct proc_dir_entry *ent;
 
 static void __init power_create_procfs(void)
 {
-	if (!check_soft_power)
+	if (!power_tasklet.func)
 		return;
 	
 	ent = create_proc_entry(SYSCTL_FILENAME, S_IFREG|S_IRUGO|S_IWUSR, 0);
@@ -266,10 +286,29 @@ static void __exit power_remove_procfs(v
 
 
 
+/* parisc_panic_event() is called by the panic handler.
+ * As soon as a panic occurs, our tasklets above will not be
+ * executed any longer. This function then re-enables the 
+ * soft-power switch and allows the user to switch off the system
+ */
+static int parisc_panic_event(struct notifier_block *this,
+		unsigned long event, void *ptr)
+{
+	/* re-enable the soft-power switch */
+	pdc_soft_power_button(0);
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block parisc_panic_block = {
+	notifier_call: parisc_panic_event,
+	priority: INT_MAX,
+};
+
 
 static int __init power_init(void)
 {
 	unsigned long ret;
+	unsigned long soft_power_reg = 0;
 
 #if 0
 	request_irq( IRQ_FROM_REGION(CPU_IRQ_REGION)+2, &powerfail_interrupt,
@@ -281,38 +320,51 @@ static int __init power_init(void)
 	if (ret == PDC_OK)
 		ret = pdc_soft_power_button(1);
 	if (ret != PDC_OK)
-		soft_power_reg = (unsigned long) -1;
+		soft_power_reg = -1UL;
 	
-	switch ((long) soft_power_reg) {
+	switch (soft_power_reg) {
 	case 0:		printk(KERN_INFO "Gecko-style soft power switch enabled.\n");
-			check_soft_power = check_soft_power_gecko;
+			power_tasklet.func = gecko_tasklet_func;
 			break;
 			
-	case -1:	printk(KERN_INFO "Soft power switch support not available.\n");
+	case -1UL:	printk(KERN_INFO "Soft power switch support not available.\n");
 			return -ENODEV;
 	
 	default:	printk(KERN_INFO "Soft power switch enabled, polling @ 0x%08lx.\n",
 				soft_power_reg);
-			check_soft_power = check_soft_power_polling;
+			power_tasklet.data = soft_power_reg;
+			power_tasklet.func = polling_tasklet_func;
 	}
 
+	/* Register a call for panic conditions. */
+	notifier_chain_register(&panic_notifier_list, &parisc_panic_block);
+
 	power_create_procfs();
+	tasklet_enable(&power_tasklet);
 
 	return 0;
 }
 
 static void __exit power_exit(void)
 {
+	if (!power_tasklet.func)
+		return;
+
+	tasklet_disable(&power_tasklet);
+	notifier_chain_unregister(&panic_notifier_list, &parisc_panic_block);
 	power_remove_procfs();
-	check_soft_power = NULL;
+	power_tasklet.func = NULL;
+	pdc_soft_power_button(0);
 }
 
 module_init(power_init);
 module_exit(power_exit);
 
+
 MODULE_AUTHOR("Helge Deller");
 MODULE_DESCRIPTION("Soft power switch driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("Dual BSD/GPL");
+
 
 EXPORT_NO_SYMBOLS;
 
Index: arch/parisc/kernel/time.c
===================================================================
RCS file: /var/cvs/linux/arch/parisc/kernel/time.c,v
retrieving revision 1.23
diff -u -p -r1.23 time.c
--- arch/parisc/kernel/time.c	2002/05/30 16:18:15	1.23
+++ arch/parisc/kernel/time.c	2002/06/26 22:14:59
@@ -116,8 +116,8 @@ void timer_interrupt(int irq, void *dev_
 #endif
 
 	/* check soft power switch status */
-	if (check_soft_power)
-		check_soft_power();
+	if (cpu == 0 && !atomic_read(&led_tasklet.count))
+		tasklet_schedule(&power_tasklet);
 }
 
 /*** converted from ia64 ***/
Index: include/asm-parisc/irq.h
===================================================================
RCS file: /var/cvs/linux/include/asm-parisc/irq.h,v
retrieving revision 1.21
diff -u -p -r1.21 irq.h
--- include/asm-parisc/irq.h	2001/12/04 02:12:40	1.21
+++ include/asm-parisc/irq.h	2002/06/26 22:14:59
@@ -92,6 +92,6 @@ extern unsigned int txn_alloc_data(int, 
 extern unsigned long txn_alloc_addr(int);
 
 /* soft power switch support (power.c) */
-extern void (*check_soft_power)(void);
+extern struct tasklet_struct power_tasklet;
 
 #endif	/* _ASM_PARISC_IRQ_H */

--Boundary-00=_m7jG9Ny9Z1+7wmF--