[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--