[parisc-linux-cvs] 2.4.16-pa1, soft-power-switch support

Helge Deller deller@gmx.de
Thu, 29 Nov 2001 21:03:31 +0100


--------------Boundary-00=_VPVKY4B95VRMIG490EK1
Content-Type: text/plain;
  charset="iso-8859-1"
Content-Transfer-Encoding: 8bit

> Modified files:
> 	.              : Makefile
> 	arch/parisc/kernel: Makefile firmware.c processor.c time.c
> 	                    traps.c
> 	include/asm-parisc: irq.h
>
> Log message:
> - 2.4.16-pa1
> - added first atempt to support the soft-power-switch
> (works on c3000 but not yet on a 715/64 machine)
> - some small other cleanups



--------------Boundary-00=_VPVKY4B95VRMIG490EK1
Content-Type: text/plain;
  charset="iso-8859-1";
  name="diff2"
Content-Transfer-Encoding: 8bit
Content-Disposition: attachment; filename="diff2"

Index: Makefile
===================================================================
RCS file: /var/cvs/linux/Makefile,v
retrieving revision 1.205
diff -u -p -r1.205 Makefile
--- Makefile	2001/11/29 15:49:10	1.205
+++ Makefile	2001/11/29 19:47:31
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 16
-EXTRAVERSION = -pa0
+EXTRAVERSION = -pa1
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
Index: arch/parisc/kernel/Makefile
===================================================================
RCS file: /var/cvs/linux/arch/parisc/kernel/Makefile,v
retrieving revision 1.39
diff -u -p -r1.39 Makefile
--- arch/parisc/kernel/Makefile	2001/11/13 17:31:52	1.39
+++ arch/parisc/kernel/Makefile	2001/11/29 19:47:34
@@ -24,7 +24,7 @@ obj-y           += cache.o pacache.o set
 		pa7300lc.o pci-dma.o syscall.o entry.o sys_parisc.o \
 		firmware.o ptrace.o hardware.o inventory.o drivers.o \
 		semaphore.o signal.o hpmc.o real2.o parisc_ksyms.o \
-		unaligned.o processor.o
+		unaligned.o processor.o power.o
 
 export-objs	:= parisc_ksyms.o superio.o
 
Index: arch/parisc/kernel/firmware.c
===================================================================
RCS file: /var/cvs/linux/arch/parisc/kernel/firmware.c,v
retrieving revision 1.37
diff -u -p -r1.37 firmware.c
--- arch/parisc/kernel/firmware.c	2001/11/29 08:30:08	1.37
+++ arch/parisc/kernel/firmware.c	2001/11/29 19:47:37
@@ -44,6 +44,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/spinlock.h>
+#include <linux/init.h>
 
 #include <asm/page.h>
 #include <asm/pdc.h>
@@ -143,7 +144,7 @@ int pdc_add_valid(unsigned long address)
  *
  * An HVERSION dependent call for returning the chassis information.
  */
-int pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsigned long len)
+int __init pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsigned long len)
 {
         int retval;
 
@@ -166,7 +167,7 @@ int pdc_chassis_info(struct pdc_chassis_
  * This PDC call returns the presence and status of all the coprocessors
  * attached to the processor.
  */
-int pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info)
+int __init pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info)
 {
         int retval;
 
@@ -601,7 +602,7 @@ int pdc_do_reset()
  * Enable the soft power switch and return the absolute address 
  * of the soft power switch register
  */
-int pdc_soft_power_info(unsigned long *power_reg)
+int __init pdc_soft_power_info(unsigned long *power_reg)
 {
 	int retval;
 
Index: arch/parisc/kernel/power.c
===================================================================
RCS file: power.c
diff -N power.c
--- /dev/null	Thu Nov 30 14:01:38 2000
+++ power.c	Thu Nov 29 12:47:37 2001
@@ -0,0 +1,160 @@
+/*
+ *  linux/arch/parisc/kernel/power.c
+ *  HP PARISC powerfail and soft power switch support
+ *
+ *  Copyright (C) 2001 Helge Deller <deller@gmx.de>
+ *
+ */
+
+/*
+ * Status: EXPERIMENTAL
+ *  
+ * TODO:
+ * - make it work on my 715/64 (Gecko-style) machine,
+ * - use tasklets instead of calling it from the timer-interrupt function
+ * - ....
+ */
+
+#include <asm/irq.h>
+#include <asm/pdc.h>
+#include <asm/gsc.h>
+#include <asm/io.h>
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/reboot.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+
+/* For kernel debugging purposes it's sometimes better to have
+ * the soft-power switch killing the power at once.
+ * This may be reached by uncommenting the following line: */
+
+//#define POWERSWITCH_DISABLED
+
+
+
+static void deferred_poweroff(void *dummy)
+{
+	kill_proc(1, SIGINT, 0);
+	/* machine_power_off(); */
+}
+
+/*
+ * This function gets called from interrupt context.
+ * As it's called within an interrupt, it wouldn't sync if we don't
+ * use schedule_task().
+ */
+
+static void poweroff(void)
+{
+	static int powering_off;
+	static struct tq_struct poweroff_tq = {
+		routine: deferred_poweroff,
+	};
+
+	if (powering_off)
+		return;
+
+	powering_off++;
+	schedule_task(&poweroff_tq);
+}
+
+
+/* soft power switch function ptr */
+void (*check_soft_power)(struct pt_regs *regs);
+
+
+/*
+ * 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.
+ * 
+ * FIXME: doesn't work yet,
+ * I assume HPUX does some strange things (e.g. copy cr23 to cr25 ?)
+ */
+static void check_soft_power_gecko(struct pt_regs *regs)
+{
+#if 0
+	static int x;
+
+	x++;
+	/* reduce the amount of stupid printk()s */
+	if (x & 0x3f)
+		return;
+
+	if (mfctl(23) & 0x80000000) 
+		printk("SWITCH_ON\n") ;
+	else
+		printk("SWITCH_OFF!!\n");
+#endif
+}
+
+
+
+/*
+ * Check the power switch status which is read from the
+ * 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(struct pt_regs *regs)
+{
+        unsigned long current_status;
+	static int timer;
+
+	current_status = gsc_readl(soft_power_reg);
+	if (current_status & 0x1) {
+		/* power switch button not pressed */
+		timer = 0;
+	} else {
+		gsc_writel(soft_power_reg, current_status & ~0x1);
+		timer++;
+		/* wait until the button was pressed for 1 second */
+		if (timer == HZ)
+			poweroff();
+	}
+}
+
+
+/*
+ * powerfail interruption handler (irq IRQ_FROM_REGION(CPU_IRQ_REGION)+2) 
+ */
+static void powerfail_interrupt(int code, void *x, struct pt_regs *regs)
+{
+	printk(KERN_CRIT "POWERFAIL INTERRUPTION !\n");
+	poweroff();
+}
+
+
+
+void __init power_init(void)
+{
+	unsigned long ret;
+
+	request_irq( IRQ_FROM_REGION(CPU_IRQ_REGION)+2, &powerfail_interrupt,
+		0, "powerfail", NULL);
+
+#if !defined(POWERSWITCH_DISABLED)
+	/* enable the soft power switch if possible */
+	ret = pdc_soft_power_info(&soft_power_reg);
+	if (ret != PDC_OK)
+		return;
+	
+	switch ((long) soft_power_reg) {
+	case 0:		printk(KERN_INFO "Enabled gecko-style soft power switch.\n");
+			check_soft_power = check_soft_power_gecko;
+			break;
+			
+	case -1:	printk(KERN_INFO "No soft power switch support.\n");
+			break;
+	
+	default:	printk(KERN_INFO "Enabled soft power switch (polling mode, io=0x%08lx).\n",
+				soft_power_reg);
+			check_soft_power = check_soft_power_polling;
+	}
+#endif
+}
Index: arch/parisc/kernel/processor.c
===================================================================
RCS file: /var/cvs/linux/arch/parisc/kernel/processor.c,v
retrieving revision 1.7
diff -u -p -r1.7 processor.c
--- arch/parisc/kernel/processor.c	2001/11/29 15:49:18	1.7
+++ arch/parisc/kernel/processor.c	2001/11/29 19:47:37
@@ -107,7 +107,7 @@ static int __init processor_probe(struct
 
 		ASSERT(PDC_OK == status);
 
-		if(cpu_info.cpu_num >= NR_CPUS) {
+		if (cpu_info.cpu_num >= NR_CPUS) {
 			printk(KERN_WARNING "IGNORING CPU at 0x%x,"
 				" cpu_slot_id > NR_CPUS"
 				" (%ld > %d)\n",
@@ -164,32 +164,30 @@ static int __init processor_probe(struct
  */
 void __init collect_boot_cpu_data(void)
 {
-	memset(&boot_cpu_data,0,sizeof(boot_cpu_data));
+	memset(&boot_cpu_data, 0, sizeof(boot_cpu_data));
 
 	boot_cpu_data.cpu_hz = 100 * PAGE0->mem_10msec; /* Hz of this PARISC */
 
 	/* get CPU-Model Information... */
 #define p ((unsigned long *)&boot_cpu_data.pdc.model)
-	if(pdc_model_info(&boot_cpu_data.pdc.model)==0)
+	if (pdc_model_info(&boot_cpu_data.pdc.model) == PDC_OK)
 		printk(KERN_INFO 
-			"model	%08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+			"model %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
 			p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8]);
 #undef p
 
-	if(pdc_model_versions(&boot_cpu_data.pdc.versions, 0)==0)
-		printk(KERN_INFO "vers\t%08lx\n", 
+	if (pdc_model_versions(&boot_cpu_data.pdc.versions, 0) == PDC_OK)
+		printk(KERN_INFO "vers  %08lx\n", 
 			boot_cpu_data.pdc.versions);
 
-	if(pdc_model_cpuid(&boot_cpu_data.pdc.cpuid)==0)
-		printk(KERN_INFO "cpuid\t%08lx\n",
+	if (pdc_model_cpuid(&boot_cpu_data.pdc.cpuid) == PDC_OK)
+		printk(KERN_INFO "CPUID vers %ld rev %ld (0x%08lx)\n",
+			(boot_cpu_data.pdc.cpuid >> 5) & 127,
+			boot_cpu_data.pdc.cpuid & 31,
 			boot_cpu_data.pdc.cpuid);
 
-	printk(KERN_INFO "CPUID\tvers %ld rev %ld\n",
-		(boot_cpu_data.pdc.cpuid >> 5) & 127,
-		boot_cpu_data.pdc.cpuid & 31);
-
-	if (pdc_model_sysmodel(boot_cpu_data.pdc.sys_model_name)==0)
-		printk(KERN_INFO "model\t%s\n",
+	if (pdc_model_sysmodel(boot_cpu_data.pdc.sys_model_name) == PDC_OK)
+		printk(KERN_INFO "model %s\n",
 			boot_cpu_data.pdc.sys_model_name);
 
 	boot_cpu_data.hversion =  boot_cpu_data.pdc.model.hversion;
Index: arch/parisc/kernel/time.c
===================================================================
RCS file: /var/cvs/linux/arch/parisc/kernel/time.c,v
retrieving revision 1.18
diff -u -p -r1.18 time.c
--- arch/parisc/kernel/time.c	2001/11/25 23:36:47	1.18
+++ arch/parisc/kernel/time.c	2001/11/29 19:47:37
@@ -87,6 +87,10 @@ void timer_interrupt(int irq, void *dev_
 	if (cpu == 0 && !atomic_read(&led_tasklet.count))
 		tasklet_schedule(&led_tasklet);
 #endif
+
+	/* check soft power switch status */
+	if (check_soft_power)
+		check_soft_power(regs);
 }
 
 /*** converted from ia64 ***/
@@ -204,5 +208,7 @@ void __init time_init(void)
 	        xtime.tv_sec = 0;
 		xtime.tv_usec = 0;
 	}
+
+	power_init();
 }
 
Index: arch/parisc/kernel/traps.c
===================================================================
RCS file: /var/cvs/linux/arch/parisc/kernel/traps.c,v
retrieving revision 1.56
diff -u -p -r1.56 traps.c
--- arch/parisc/kernel/traps.c	2001/11/29 15:49:18	1.56
+++ arch/parisc/kernel/traps.c	2001/11/29 19:47:38
@@ -241,6 +241,7 @@ void handle_break(unsigned iir, struct p
 
 int handle_toc(void)
 {
+	printk(KERN_CRIT "TOC call.\n");
 	return 0;
 }
 
@@ -288,6 +289,11 @@ void handle_interruption(int code, struc
 	case  1:
 		parisc_terminate("High Priority Machine Check (HPMC)",regs,code,0);
 		/* NOT REACHED */
+		
+	case  2: /* power failure interrupt */
+		printk(KERN_CRIT "Power failure interrupt !\n");
+		return;
+
 	case  3: /* Recovery counter trap */
 		regs->gr[0] &= ~PSW_R;
 		if (regs->iasq[0])
@@ -324,7 +330,6 @@ void handle_interruption(int code, struc
 		parisc_terminate("Non access data tlb fault!",regs,code,fault_address);
 
 	case 18:
-
 		/* PCXS only -- later cpu's split this into types 26,27 & 28 */
 
 		/* Check for unaligned access */
Index: include/asm-parisc/irq.h
===================================================================
RCS file: /var/cvs/linux/include/asm-parisc/irq.h,v
retrieving revision 1.19
diff -u -p -r1.19 irq.h
--- include/asm-parisc/irq.h	2001/11/25 22:41:29	1.19
+++ include/asm-parisc/irq.h	2001/11/29 19:48:07
@@ -90,4 +90,8 @@ extern int txn_claim_irq(int);
 extern unsigned int txn_alloc_data(int, unsigned int);
 extern unsigned long txn_alloc_addr(int);
 
+/* soft power switch support */
+extern void (*check_soft_power)(struct pt_regs *regs);
+extern void power_init(void);
+
 #endif	/* _ASM_PARISC_IRQ_H */

--------------Boundary-00=_VPVKY4B95VRMIG490EK1--