Merge master.kernel.org:/pub/scm/linux/kernel/git/kyle/parisc-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/kyle/parisc-2.6: (23 commits)
  [PARISC] Move os_id_to_string() inside #ifndef __ASSEMBLY__
  [PARISC] Fix do_gettimeofday() hang
  [PARISC] Fix PCREL22F relocation problem for most modules
  [PARISC] Refactor show_regs in traps.c
  [PARISC] Add os_id_to_string helper
  [PARISC] OS_ID_LINUX == 0x0006
  [PARISC] Ensure Space ID hashing is turned off
  [PARISC] Match show_cache_info with reality
  [PARISC] Remove unused macro fixup_branch in syscall.S
  [PARISC] Add is_compat_task() helper
  [PARISC] Update Thibaut Varene's CREDITS entry
  [PARISC] Reduce data footprint in pdc_stable.c
  [PARISC] pdc_stable version 0.30
  [PARISC] Work around machines which do not support chassis warnings
  [PARISC] PDC_CHASSIS is implemented on all machines
  [PARISC] Remove unconditional #define PIC in syscall macros
  [PARISC] Use MFIA in current_text_addr on pa2.0 processors
  [PARISC] Remove dead function pc_in_user_space
  [PARISC] Test ioc_needs_fdc variable instead of open coding
  [PARISC] Fix gcc 4.1 warnings in sba_iommu.c
  ...
diff --git a/CREDITS b/CREDITS
index 85c7c70b7..66b9e7a 100644
--- a/CREDITS
+++ b/CREDITS
@@ -3401,10 +3401,10 @@
 
 N: Thibaut Varene
 E: T-Bone@parisc-linux.org
-W: http://www.parisc-linux.org/
+W: http://www.parisc-linux.org/~varenet/
 P: 1024D/B7D2F063 E67C 0D43 A75E 12A5 BB1C  FA2F 1E32 C3DA B7D2 F063
 D: PA-RISC port minion, PDC and GSCPS2 drivers, debuglocks and other bits
-D: Some bits in an ARM port, S1D13XXX FB driver, random patches here and there
+D: Some ARM at91rm9200 bits, S1D13XXX FB driver, random patches here and there
 D: AD1889 sound driver
 S: Paris, France
 
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index c057ad7..bc7c4a4 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -97,15 +97,17 @@
 void
 show_cache_info(struct seq_file *m)
 {
+	char buf[32];
+
 	seq_printf(m, "I-cache\t\t: %ld KB\n", 
 		cache_info.ic_size/1024 );
-	seq_printf(m, "D-cache\t\t: %ld KB (%s%s, %d-way associative)\n", 
+	if (cache_info.dc_loop == 1)
+		snprintf(buf, 32, "%lu-way associative", cache_info.dc_loop);
+	seq_printf(m, "D-cache\t\t: %ld KB (%s%s, %s)\n",
 		cache_info.dc_size/1024,
 		(cache_info.dc_conf.cc_wt ? "WT":"WB"),
 		(cache_info.dc_conf.cc_sh ? ", shared I/D":""),
-		(cache_info.dc_conf.cc_assoc)
-	);
-
+		((cache_info.dc_loop == 1) ? "direct mapped" : buf));
 	seq_printf(m, "ITLB entries\t: %ld\n" "DTLB entries\t: %ld%s\n",
 		cache_info.it_size,
 		cache_info.dt_size,
@@ -158,11 +160,11 @@
 		cache_info.dc_conf.cc_block,
 		cache_info.dc_conf.cc_line,
 		cache_info.dc_conf.cc_shift);
-	printk("	wt %d sh %d cst %d assoc %d\n",
+	printk("	wt %d sh %d cst %d hv %d\n",
 		cache_info.dc_conf.cc_wt,
 		cache_info.dc_conf.cc_sh,
 		cache_info.dc_conf.cc_cst,
-		cache_info.dc_conf.cc_assoc);
+		cache_info.dc_conf.cc_hv);
 
 	printk("IC  base 0x%lx stride 0x%lx count 0x%lx loop 0x%lx\n",
 		cache_info.ic_base,
@@ -176,11 +178,11 @@
 		cache_info.ic_conf.cc_block,
 		cache_info.ic_conf.cc_line,
 		cache_info.ic_conf.cc_shift);
-	printk("	wt %d sh %d cst %d assoc %d\n",
+	printk("	wt %d sh %d cst %d hv %d\n",
 		cache_info.ic_conf.cc_wt,
 		cache_info.ic_conf.cc_sh,
 		cache_info.ic_conf.cc_cst,
-		cache_info.ic_conf.cc_assoc);
+		cache_info.ic_conf.cc_hv);
 
 	printk("D-TLB conf: sh %d page %d cst %d aid %d pad1 %d \n",
 		cache_info.dt_conf.tc_sh,
@@ -234,7 +236,8 @@
 
 void disable_sr_hashing(void)
 {
-	int srhash_type;
+	int srhash_type, retval;
+	unsigned long space_bits;
 
 	switch (boot_cpu_data.cpu_type) {
 	case pcx: /* We shouldn't get this far.  setup.c should prevent it. */
@@ -260,6 +263,13 @@
 	}
 
 	disable_sr_hashing_asm(srhash_type);
+
+	retval = pdc_spaceid_bits(&space_bits);
+	/* If this procedure isn't implemented, don't panic. */
+	if (retval < 0 && retval != PDC_BAD_OPTION)
+		panic("pdc_spaceid_bits call failed.\n");
+	if (space_bits != 0)
+		panic("SpaceID hashing is still on!\n");
 }
 
 void flush_dcache_page(struct page *page)
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index d9e53cf..630730c 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -1638,7 +1638,7 @@
 	load32		PA(pa_dbit_lock),t0
 
 dbit_spin_20w:
-	ldcw            0(t0),t1
+	LDCW		0(t0),t1
 	cmpib,=         0,t1,dbit_spin_20w
 	nop
 
@@ -1674,7 +1674,7 @@
 	load32		PA(pa_dbit_lock),t0
 
 dbit_spin_11:
-	ldcw            0(t0),t1
+	LDCW		0(t0),t1
 	cmpib,=         0,t1,dbit_spin_11
 	nop
 
@@ -1714,7 +1714,7 @@
 	load32		PA(pa_dbit_lock),t0
 
 dbit_spin_20:
-	ldcw            0(t0),t1
+	LDCW		0(t0),t1
 	cmpib,=         0,t1,dbit_spin_20
 	nop
 
diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c
index 2dc06b8..4398d2a 100644
--- a/arch/parisc/kernel/firmware.c
+++ b/arch/parisc/kernel/firmware.c
@@ -11,7 +11,7 @@
  * Copyright 1999 The Puffin Group, (Alex deVries, David Kennedy)
  * Copyright 2003 Grant Grundler <grundler parisc-linux org>
  * Copyright 2003,2004 Ryan Bradetich <rbrad@parisc-linux.org>
- * Copyright 2004 Thibaut VARENE <varenet@parisc-linux.org>
+ * Copyright 2004,2006 Thibaut VARENE <varenet@parisc-linux.org>
  *
  *    This program is free software; you can redistribute it and/or modify
  *    it under the terms of the GNU General Public License as published by
@@ -252,10 +252,8 @@
 #endif
 
 /**
- * pdc_chassis_disp - Updates display
+ * pdc_chassis_disp - Updates chassis code
  * @retval: -1 on error, 0 on success
- *
- * Works on old PDC only (E class, others?)
  */
 int pdc_chassis_disp(unsigned long disp)
 {
@@ -269,6 +267,22 @@
 }
 
 /**
+ * pdc_chassis_warn - Fetches chassis warnings
+ * @retval: -1 on error, 0 on success
+ */
+int pdc_chassis_warn(unsigned long *warn)
+{
+	int retval = 0;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_WARN, __pa(pdc_result));
+	*warn = pdc_result[0];
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+/**
  * pdc_coproc_cfg - To identify coprocessors attached to the processor.
  * @pdc_coproc_info: Return buffer address.
  *
@@ -393,7 +407,9 @@
  * pdc_model_sysmodel - Get the system model name.
  * @name: A char array of at least 81 characters.
  *
- * Get system model name from PDC ROM (e.g. 9000/715 or 9000/778/B160L)
+ * Get system model name from PDC ROM (e.g. 9000/715 or 9000/778/B160L).
+ * Using OS_ID_HPUX will return the equivalent of the 'modelname' command
+ * on HP/UX.
  */
 int pdc_model_sysmodel(char *name)
 {
@@ -498,6 +514,26 @@
         return retval;
 }
 
+/**
+ * pdc_spaceid_bits - Return whether Space ID hashing is turned on.
+ * @space_bits: Should be 0, if not, bad mojo!
+ *
+ * Returns information about Space ID hashing.
+ */
+int pdc_spaceid_bits(unsigned long *space_bits)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	pdc_result[0] = 0;
+	retval = mem_pdc_call(PDC_CACHE, PDC_CACHE_RET_SPID, __pa(pdc_result), 0);
+	convert_to_wide(pdc_result);
+	*space_bits = pdc_result[0];
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
 #ifndef CONFIG_PA20
 /**
  * pdc_btlb_info - Return block TLB information.
diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c
index f27cfe4..aee3118 100644
--- a/arch/parisc/kernel/module.c
+++ b/arch/parisc/kernel/module.c
@@ -89,6 +89,12 @@
 	return is_init(me, loc) || is_core(me, loc);
 }
 
+static inline int is_local_section(struct module *me, void *loc, void *dot)
+{
+	return (is_init(me, loc) && is_init(me, dot)) ||
+		(is_core(me, loc) && is_core(me, dot));
+}
+
 
 #ifndef __LP64__
 struct got_entry {
@@ -364,8 +370,14 @@
 }
 #endif /* __LP64__ */
 
+enum elf_stub_type {
+	ELF_STUB_GOT,
+	ELF_STUB_MILLI,
+	ELF_STUB_DIRECT,
+};
+
 static Elf_Addr get_stub(struct module *me, unsigned long value, long addend,
-	int millicode, int init_section)
+	enum elf_stub_type stub_type, int init_section)
 {
 	unsigned long i;
 	struct stub_entry *stub;
@@ -396,7 +408,7 @@
 	stub->insns[1] |= reassemble_17(rrsel(value, addend) / 4);
 
 #else
-/* for 64-bit we have two kinds of stubs:
+/* for 64-bit we have three kinds of stubs:
  * for normal function calls:
  * 	ldd 0(%dp),%dp
  * 	ldd 10(%dp), %r1
@@ -408,18 +420,23 @@
  * 	ldo 0(%r1), %r1
  * 	ldd 10(%r1), %r1
  * 	bve,n (%r1)
+ *
+ * for direct branches (jumps between different section of the
+ * same module):
+ *	ldil 0, %r1
+ *	ldo 0(%r1), %r1
+ *	bve,n (%r1)
  */
-	if (!millicode)
-	{
+	switch (stub_type) {
+	case ELF_STUB_GOT:
 		stub->insns[0] = 0x537b0000;	/* ldd 0(%dp),%dp	*/
 		stub->insns[1] = 0x53610020;	/* ldd 10(%dp),%r1	*/
 		stub->insns[2] = 0xe820d000;	/* bve (%r1)		*/
 		stub->insns[3] = 0x537b0030;	/* ldd 18(%dp),%dp	*/
 
 		stub->insns[0] |= reassemble_14(get_got(me, value, addend) & 0x3fff);
-	}
-	else
-	{
+		break;
+	case ELF_STUB_MILLI:
 		stub->insns[0] = 0x20200000;	/* ldil 0,%r1		*/
 		stub->insns[1] = 0x34210000;	/* ldo 0(%r1), %r1	*/
 		stub->insns[2] = 0x50210020;	/* ldd 10(%r1),%r1	*/
@@ -427,7 +444,17 @@
 
 		stub->insns[0] |= reassemble_21(lrsel(value, addend));
 		stub->insns[1] |= reassemble_14(rrsel(value, addend));
+		break;
+	case ELF_STUB_DIRECT:
+		stub->insns[0] = 0x20200000;    /* ldil 0,%r1           */
+		stub->insns[1] = 0x34210000;    /* ldo 0(%r1), %r1      */
+		stub->insns[2] = 0xe820d002;    /* bve,n (%r1)          */
+
+		stub->insns[0] |= reassemble_21(lrsel(value, addend));
+		stub->insns[1] |= reassemble_14(rrsel(value, addend));
+		break;
 	}
+
 #endif
 
 	return (Elf_Addr)stub;
@@ -539,14 +566,14 @@
 			break;
 		case R_PARISC_PCREL17F:
 			/* 17-bit PC relative address */
-			val = get_stub(me, val, addend, 0, is_init(me, loc));
+			val = get_stub(me, val, addend, ELF_STUB_GOT, is_init(me, loc));
 			val = (val - dot - 8)/4;
 			CHECK_RELOC(val, 17)
 			*loc = (*loc & ~0x1f1ffd) | reassemble_17(val);
 			break;
 		case R_PARISC_PCREL22F:
 			/* 22-bit PC relative address; only defined for pa20 */
-			val = get_stub(me, val, addend, 0, is_init(me, loc));
+			val = get_stub(me, val, addend, ELF_STUB_GOT, is_init(me, loc));
 			DEBUGP("STUB FOR %s loc %lx+%lx at %lx\n", 
 			       strtab + sym->st_name, (unsigned long)loc, addend, 
 			       val)
@@ -643,13 +670,23 @@
 			       strtab + sym->st_name,
 			       loc, val);
 			/* can we reach it locally? */
-			if(!is_local(me, (void *)val)) {
-				if (strncmp(strtab + sym->st_name, "$$", 2)
+			if(!is_local_section(me, (void *)val, (void *)dot)) {
+
+				if (is_local(me, (void *)val))
+					/* this is the case where the
+					 * symbol is local to the
+					 * module, but in a different
+					 * section, so stub the jump
+					 * in case it's more than 22
+					 * bits away */
+					val = get_stub(me, val, addend, ELF_STUB_DIRECT,
+						       is_init(me, loc));
+				else if (strncmp(strtab + sym->st_name, "$$", 2)
 				    == 0)
-					val = get_stub(me, val, addend, 1,
+					val = get_stub(me, val, addend, ELF_STUB_MILLI,
 						       is_init(me, loc));
 				else
-					val = get_stub(me, val, addend, 0,
+					val = get_stub(me, val, addend, ELF_STUB_GOT,
 						       is_init(me, loc));
 			}
 			DEBUGP("STUB FOR %s loc %lx, val %lx+%lx at %lx\n", 
diff --git a/arch/parisc/kernel/pdc_chassis.c b/arch/parisc/kernel/pdc_chassis.c
index a45e2e2..d47ba1a 100644
--- a/arch/parisc/kernel/pdc_chassis.c
+++ b/arch/parisc/kernel/pdc_chassis.c
@@ -1,8 +1,8 @@
 /* 
- *    interfaces to log Chassis Codes via PDC (firmware)
+ *    interfaces to Chassis Codes via PDC (firmware)
  *
  *    Copyright (C) 2002 Laurent Canet <canetl@esiee.fr>
- *    Copyright (C) 2002-2004 Thibaut VARENE <varenet@parisc-linux.org>
+ *    Copyright (C) 2002-2006 Thibaut VARENE <varenet@parisc-linux.org>
  *
  *    This program is free software; you can redistribute it and/or modify
  *    it under the terms of the GNU General Public License, version 2, as
@@ -16,6 +16,10 @@
  *    You should have received a copy of the GNU General Public License
  *    along with this program; if not, write to the Free Software
  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *    TODO: poll chassis warns, trigger (configurable) machine shutdown when
+ *    		needed.
+ *    	    Find out how to get Chassis warnings out of PAT boxes?
  */
 
 #undef PDC_CHASSIS_DEBUG
@@ -30,15 +34,16 @@
 #include <linux/reboot.h>
 #include <linux/notifier.h>
 #include <linux/cache.h>
+#include <linux/proc_fs.h>
 
 #include <asm/pdc_chassis.h>
 #include <asm/processor.h>
 #include <asm/pdc.h>
 #include <asm/pdcpat.h>
 
+#define PDC_CHASSIS_VER	"0.05"
 
 #ifdef CONFIG_PDC_CHASSIS
-static int pdc_chassis_old __read_mostly = 0;	
 static unsigned int pdc_chassis_enabled __read_mostly = 1;
 
 
@@ -64,7 +69,7 @@
  * Currently, only E class and A180 are known to work with this.
  * Inspired by Christoph Plattner
  */
-
+#if 0
 static void __init pdc_chassis_checkold(void)
 {
 	switch(CPU_HVERSION) {
@@ -73,7 +78,6 @@
 		case 0x482:		/* E45 */
 		case 0x483:		/* E55 */
 		case 0x516:		/* A180 */
-			pdc_chassis_old = 1;
 			break;
 
 		default:
@@ -81,7 +85,7 @@
 	}
 	DPRINTK(KERN_DEBUG "%s: pdc_chassis_checkold(); pdc_chassis_old = %d\n", __FILE__, pdc_chassis_old);
 }
-
+#endif
 
 /**
  * pdc_chassis_panic_event() - Called by the panic handler.
@@ -131,30 +135,20 @@
 void __init parisc_pdc_chassis_init(void)
 {
 #ifdef CONFIG_PDC_CHASSIS
-	int handle = 0;
 	if (likely(pdc_chassis_enabled)) {
 		DPRINTK(KERN_DEBUG "%s: parisc_pdc_chassis_init()\n", __FILE__);
 
 		/* Let see if we have something to handle... */
-		/* Check for PDC_PAT or old LED Panel */
-		pdc_chassis_checkold();
-		if (is_pdc_pat()) {
-			printk(KERN_INFO "Enabling PDC_PAT chassis codes support.\n");
-			handle = 1;
-		}
-		else if (unlikely(pdc_chassis_old)) {
-			printk(KERN_INFO "Enabling old style chassis LED panel support.\n");
-			handle = 1;
-		}
+		printk(KERN_INFO "Enabling %s chassis codes support v%s\n",
+				is_pdc_pat() ? "PDC_PAT" : "regular",
+				PDC_CHASSIS_VER);
 
-		if (handle) {
-			/* initialize panic notifier chain */
-			atomic_notifier_chain_register(&panic_notifier_list,
-					&pdc_chassis_panic_block);
+		/* initialize panic notifier chain */
+		atomic_notifier_chain_register(&panic_notifier_list,
+				&pdc_chassis_panic_block);
 
-			/* initialize reboot notifier chain */
-			register_reboot_notifier(&pdc_chassis_reboot_block);
-		}
+		/* initialize reboot notifier chain */
+		register_reboot_notifier(&pdc_chassis_reboot_block);
 	}
 #endif /* CONFIG_PDC_CHASSIS */
 }
@@ -215,9 +209,12 @@
 			}
 		} else retval = -1;
 #else
-		if (unlikely(pdc_chassis_old)) {
+		if (1) {
 			switch (message) {
 				case PDC_CHASSIS_DIRECT_BSTART:
+					retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_INIT));
+					break;
+
 				case PDC_CHASSIS_DIRECT_BCOMPLETE:
 					retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_RUN));
 					break;
@@ -244,3 +241,61 @@
 #endif /* CONFIG_PDC_CHASSIS */
 	return retval;
 }
+
+#ifdef CONFIG_PDC_CHASSIS_WARN
+#ifdef CONFIG_PROC_FS
+static int pdc_chassis_warn_pread(char *page, char **start, off_t off,
+		int count, int *eof, void *data)
+{
+	char *out = page;
+	int len, ret;
+	unsigned long warn;
+	u32 warnreg;
+
+	ret = pdc_chassis_warn(&warn);
+	if (ret != PDC_OK)
+		return -EIO;
+
+	warnreg = (warn & 0xFFFFFFFF);
+
+	if ((warnreg >> 24) & 0xFF)
+		out += sprintf(out, "Chassis component failure! (eg fan or PSU): 0x%.2x\n", ((warnreg >> 24) & 0xFF));
+
+	out += sprintf(out, "Battery: %s\n", (warnreg & 0x04) ? "Low!" : "OK");
+	out += sprintf(out, "Temp low: %s\n", (warnreg & 0x02) ? "Exceeded!" : "OK");
+	out += sprintf(out, "Temp mid: %s\n", (warnreg & 0x01) ? "Exceeded!" : "OK");
+
+	len = out - page - off;
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0) return 0;
+	} else {
+		len = count;
+	}
+	*start = page + off;
+	return len;
+}
+
+static int __init pdc_chassis_create_procfs(void)
+{
+	unsigned long test;
+	int ret;
+
+	ret = pdc_chassis_warn(&test);
+	if ((ret == PDC_BAD_PROC) || (ret == PDC_BAD_OPTION)) {
+		/* seems that some boxes (eg L1000) do not implement this */
+		printk(KERN_INFO "Chassis warnings not supported.\n");
+		return 0;
+	}
+
+	printk(KERN_INFO "Enabling PDC chassis warnings support v%s\n",
+			PDC_CHASSIS_VER);
+	create_proc_read_entry("chassis", 0400, NULL, pdc_chassis_warn_pread,
+				NULL);
+	return 0;
+}
+
+__initcall(pdc_chassis_create_procfs);
+
+#endif /* CONFIG_PROC_FS */
+#endif /* CONFIG_PDC_CHASSIS_WARN */
diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c
index 413292f..3f28de9 100644
--- a/arch/parisc/kernel/ptrace.c
+++ b/arch/parisc/kernel/ptrace.c
@@ -91,7 +91,7 @@
 		int copied;
 
 #ifdef __LP64__
-		if (personality(child->personality) == PER_LINUX32) {
+		if (__is_compat_task(child)) {
 			unsigned int tmp;
 
 			addr &= 0xffffffffL;
@@ -123,7 +123,7 @@
 	case PTRACE_POKEDATA:
 		ret = 0;
 #ifdef __LP64__
-		if (personality(child->personality) == PER_LINUX32) {
+		if (__is_compat_task(child)) {
 			unsigned int tmp = (unsigned int)data;
 			DBG("sys_ptrace(POKE%s, %d, %lx, %lx)\n",
 				request == PTRACE_POKETEXT ? "TEXT" : "DATA",
@@ -146,7 +146,7 @@
 	case PTRACE_PEEKUSR: {
 		ret = -EIO;
 #ifdef __LP64__
-		if (personality(child->personality) == PER_LINUX32) {
+		if (__is_compat_task(child)) {
 			unsigned int tmp;
 
 			if (addr & (sizeof(int)-1))
@@ -205,7 +205,7 @@
 			goto out_tsk;
 		}
 #ifdef __LP64__
-		if (personality(child->personality) == PER_LINUX32) {
+		if (__is_compat_task(child)) {
 			if (addr & (sizeof(int)-1))
 				goto out_tsk;
 			if ((addr = translate_usr_offset(addr)) < 0)
diff --git a/arch/parisc/kernel/real2.S b/arch/parisc/kernel/real2.S
index 8c2859c..453d01a 100644
--- a/arch/parisc/kernel/real2.S
+++ b/arch/parisc/kernel/real2.S
@@ -276,15 +276,6 @@
 
 #endif
 
-	.export pc_in_user_space
-	.text
-	/* Doesn't belong here but I couldn't find a nicer spot. */
-	/* Should never get called, only used by profile stuff in time.c */
-pc_in_user_space:
-	bv,n	0(%rp)
-	nop
-
-
 	.export __canonicalize_funcptr_for_compare
 	.text
 	/* http://lists.parisc-linux.org/hypermail/parisc-linux/10916.html
diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c
index 4a36ec3..278f4b9 100644
--- a/arch/parisc/kernel/setup.c
+++ b/arch/parisc/kernel/setup.c
@@ -303,6 +303,8 @@
 
 static int __init parisc_init(void)
 {
+	u32 osid = (OS_ID_LINUX << 16);
+
 	parisc_proc_mkdir();
 	parisc_init_resources();
 	do_device_inventory();                  /* probe for hardware */
@@ -311,6 +313,9 @@
 	
 	/* set up a new led state on systems shipped LED State panel */
 	pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BSTART);
+
+	/* tell PDC we're Linux. Nevermind failure. */
+	pdc_stable_write(0x40, &osid, sizeof(osid));
 	
 	processor_init();
 	printk(KERN_INFO "CPU(s): %d x %s at %d.%06d MHz\n",
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index cc38edf..bb83880 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -76,7 +76,7 @@
 #ifdef __LP64__
 	compat_sigset_t newset32;
 
-	if(personality(current->personality) == PER_LINUX32){
+	if (is_compat_task()) {
 		/* XXX: Don't preclude handling different sized sigset_t's.  */
 		if (sigsetsize != sizeof(compat_sigset_t))
 			return -EINVAL;
@@ -153,7 +153,7 @@
 	compat_sigset_t compat_set;
 	struct compat_rt_sigframe __user * compat_frame;
 	
-	if(personality(current->personality) == PER_LINUX32)
+	if (is_compat_task())
 		sigframe_size = PARISC_RT_SIGFRAME_SIZE32;
 #endif
 
@@ -166,7 +166,7 @@
 #ifdef __LP64__
 	compat_frame = (struct compat_rt_sigframe __user *)frame;
 	
-	if(personality(current->personality) == PER_LINUX32){
+	if (is_compat_task()) {
 		DBG(2,"sys_rt_sigreturn: ELF32 process.\n");
 		if (__copy_from_user(&compat_set, &compat_frame->uc.uc_sigmask, sizeof(compat_set)))
 			goto give_sigsegv;
@@ -186,7 +186,7 @@
 
 	/* Good thing we saved the old gr[30], eh? */
 #ifdef __LP64__
-	if(personality(current->personality) == PER_LINUX32){
+	if (is_compat_task()) {
 		DBG(1,"sys_rt_sigreturn: compat_frame->uc.uc_mcontext 0x%p\n",
 				&compat_frame->uc.uc_mcontext);
 // FIXME: Load upper half from register file
@@ -315,7 +315,7 @@
 
 	compat_frame = (struct compat_rt_sigframe __user *)frame;
 	
-	if(personality(current->personality) == PER_LINUX32) {
+	if (is_compat_task()) {
 		DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &compat_frame->info);
 		err |= copy_siginfo_to_user32(&compat_frame->info, info);
 		DBG(1,"SETUP_RT_FRAME: 1\n");
@@ -392,7 +392,7 @@
 	haddr = A(ka->sa.sa_handler);
 	/* The sa_handler may be a pointer to a function descriptor */
 #ifdef __LP64__
-	if(personality(current->personality) == PER_LINUX32) {
+	if (is_compat_task()) {
 #endif
 		if (haddr & PA_PLABEL_FDESC) {
 			Elf32_Fdesc fdesc;
@@ -427,19 +427,19 @@
 	 */
 	sigframe_size = PARISC_RT_SIGFRAME_SIZE;
 #ifdef __LP64__
-	if(personality(current->personality) == PER_LINUX32)
+	if (is_compat_task())
 		sigframe_size = PARISC_RT_SIGFRAME_SIZE32;
 #endif
 	if (in_syscall) {
 		regs->gr[31] = haddr;
 #ifdef __LP64__
-		if(personality(current->personality) == PER_LINUX)
+		if (personality(current->personality) == PER_LINUX)
 			sigframe_size |= 1;
 #endif
 	} else {
 		unsigned long psw = USER_PSW;
 #ifdef __LP64__
-		if(personality(current->personality) == PER_LINUX)
+		if (personality(current->personality) == PER_LINUX)
 			psw |= PSW_W;
 #endif
 
@@ -464,7 +464,7 @@
 	regs->gr[26] = sig;               /* signal number */
 	
 #ifdef __LP64__
-	if(personality(current->personality) == PER_LINUX32){
+	if (is_compat_task()) {
 		regs->gr[25] = A(&compat_frame->info); /* siginfo pointer */
 		regs->gr[24] = A(&compat_frame->uc);   /* ucontext pointer */
 	} else
diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S
index 479d9a0..9670a89 100644
--- a/arch/parisc/kernel/syscall.S
+++ b/arch/parisc/kernel/syscall.S
@@ -29,18 +29,6 @@
 	.level		1.1
 #endif
 
-#ifndef CONFIG_64BIT
-	.macro fixup_branch,lbl
-	b	    \lbl
-	.endm
-#else
-	.macro fixup_branch,lbl
-	ldil	    L%\lbl, %r1
-	ldo	    R%\lbl(%r1), %r1
-	bv,n        %r0(%r1)
-	.endm
-#endif
-
 	.text
 
 	.import syscall_exit,code
@@ -541,7 +529,7 @@
 # endif
 /* ENABLE_LWS_DEBUG */
 
-	ldcw	0(%sr2,%r20), %r28			/* Try to acquire the lock */
+	LDCW	0(%sr2,%r20), %r28			/* Try to acquire the lock */
 	cmpb,<>,n	%r0, %r28, cas_action		/* Did we get it? */
 cas_wouldblock:
 	ldo	2(%r0), %r28				/* 2nd case */
diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c
index 594930b..eb35e1c 100644
--- a/arch/parisc/kernel/time.c
+++ b/arch/parisc/kernel/time.c
@@ -157,8 +157,22 @@
 		usec += (xtime.tv_nsec / 1000);
 	} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
 
-	while (usec >= 1000000) {
-		usec -= 1000000;
+	if (unlikely(usec > LONG_MAX)) {
+		/* This can happen if the gettimeoffset adjustment is
+		 * negative and xtime.tv_nsec is smaller than the
+		 * adjustment */
+		printk(KERN_ERR "do_gettimeofday() spurious xtime.tv_nsec of %ld\n", usec);
+		usec += USEC_PER_SEC;
+		--sec;
+		/* This should never happen, it means the negative
+		 * time adjustment was more than a second, so there's
+		 * something seriously wrong */
+		BUG_ON(usec > LONG_MAX);
+	}
+
+
+	while (usec >= USEC_PER_SEC) {
+		usec -= USEC_PER_SEC;
 		++sec;
 	}
 
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index ff20060..348344a 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -66,57 +66,42 @@
 #else
 #define RFMT "%08lx"
 #endif
+#define FFMT "%016llx"	/* fpregs are 64-bit always */
 
-void show_regs(struct pt_regs *regs)
+#define PRINTREGS(lvl,r,f,fmt,x)	\
+	printk("%s%s%02d-%02d  " fmt " " fmt " " fmt " " fmt "\n",	\
+		lvl, f, (x), (x+3), (r)[(x)+0], (r)[(x)+1],		\
+		(r)[(x)+2], (r)[(x)+3])
+
+static void print_gr(char *level, struct pt_regs *regs)
 {
 	int i;
-	char buf[128], *p;
-	char *level;
-	unsigned long cr30;
-	unsigned long cr31;
-	/* carlos says that gcc understands better memory in a struct,
-	 * and it makes our life easier with fpregs -- T-Bone */
-	struct { u32 sw[2]; } s;
-	
-	level = user_mode(regs) ? KERN_DEBUG : KERN_CRIT;
+	char buf[64];
 
-	printk("%s\n", level); /* don't want to have that pretty register dump messed up */
-
+	printk("%s\n", level);
 	printk("%s     YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI\n", level);
 	printbinary(buf, regs->gr[0], 32);
 	printk("%sPSW: %s %s\n", level, buf, print_tainted());
 
-	for (i = 0; i < 32; i += 4) {
-		int j;
-		p = buf;
-		p += sprintf(p, "%sr%02d-%02d ", level, i, i + 3);
-		for (j = 0; j < 4; j++) {
-			p += sprintf(p, " " RFMT, (i+j) == 0 ? 0 : regs->gr[i + j]);
-		}
-		printk("%s\n", buf);
-	}
+	for (i = 0; i < 32; i += 4)
+		PRINTREGS(level, regs->gr, "r", RFMT, i);
+}
 
-	for (i = 0; i < 8; i += 4) {
-		int j;
-		p = buf;
-		p += sprintf(p, "%ssr%d-%d  ", level, i, i + 3);
-		for (j = 0; j < 4; j++) {
-			p += sprintf(p, " " RFMT, regs->sr[i + j]);
-		}
-		printk("%s\n", buf);
-	}
+static void print_fr(char *level, struct pt_regs *regs)
+{
+	int i;
+	char buf[64];
+	struct { u32 sw[2]; } s;
 
 	/* FR are 64bit everywhere. Need to use asm to get the content
 	 * of fpsr/fper1, and we assume that we won't have a FP Identify
 	 * in our way, otherwise we're screwed.
 	 * The fldd is used to restore the T-bit if there was one, as the
 	 * store clears it anyway.
-	 * BTW, PA2.0 book says "thou shall not use fstw on FPSR/FPERs". */ 
-	__asm__ (
-		"fstd %%fr0,0(%1)	\n\t"
-		"fldd 0(%1),%%fr0	\n\t"
-		: "=m" (s) : "r" (&s) : "%r0"
-		);
+	 * PA2.0 book says "thou shall not use fstw on FPSR/FPERs" - T-Bone */
+	asm volatile ("fstd %%fr0,0(%1)	\n\t"
+		      "fldd 0(%1),%%fr0	\n\t"
+		      : "=m" (s) : "r" (&s) : "r0");
 
 	printk("%s\n", level);
 	printk("%s      VZOUICununcqcqcqcqcqcrmunTDVZOUI\n", level);
@@ -125,14 +110,25 @@
 	printk("%sFPER1: %08x\n", level, s.sw[1]);
 
 	/* here we'll print fr0 again, tho it'll be meaningless */
-	for (i = 0; i < 32; i += 4) {
-		int j;
-		p = buf;
-		p += sprintf(p, "%sfr%02d-%02d ", level, i, i + 3);
-		for (j = 0; j < 4; j++)
-			p += sprintf(p, " %016llx", (i+j) == 0 ? 0 : regs->fr[i+j]);
-		printk("%s\n", buf);
-	}
+	for (i = 0; i < 32; i += 4)
+		PRINTREGS(level, regs->fr, "fr", FFMT, i);
+}
+
+void show_regs(struct pt_regs *regs)
+{
+	int i;
+	char *level;
+	unsigned long cr30, cr31;
+
+	level = user_mode(regs) ? KERN_DEBUG : KERN_CRIT;
+
+	print_gr(level, regs);
+
+	for (i = 0; i < 8; i += 4)
+		PRINTREGS(level, regs->sr, "sr", RFMT, i);
+
+	if (user_mode(regs))
+		print_fr(level, regs);
 
 	cr30 = mfctl(30);
 	cr31 = mfctl(31);
diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c
index de0a1b2..92328fb 100644
--- a/arch/parisc/kernel/unaligned.c
+++ b/arch/parisc/kernel/unaligned.c
@@ -43,6 +43,8 @@
 	"\tldil L%%" #lbl ", %%r1\n"			\
 	"\tldo R%%" #lbl "(%%r1), %%r1\n"		\
 	"\tbv,n %%r0(%%r1)\n"
+/* If you use FIXUP_BRANCH, then you must list this clobber */
+#define FIXUP_BRANCH_CLOBBER "r1"
 
 /* 1111 1100 0000 0000 0001 0011 1100 0000 */
 #define OPCODE1(a,b,c)	((a)<<26|(b)<<12|(c)<<6) 
@@ -157,7 +159,7 @@
 "	.previous\n"
 	: "=r" (val), "=r" (ret)
 	: "0" (val), "r" (saddr), "r" (regs->isr)
-	: "r20" );
+	: "r20", FIXUP_BRANCH_CLOBBER );
 
 	DPRINTF("val = 0x" RFMT "\n", val);
 
@@ -202,7 +204,7 @@
 "	.previous\n"
 	: "=r" (val), "=r" (ret)
 	: "0" (val), "r" (saddr), "r" (regs->isr)
-	: "r19", "r20" );
+	: "r19", "r20", FIXUP_BRANCH_CLOBBER );
 
 	DPRINTF("val = 0x" RFMT "\n", val);
 
@@ -253,7 +255,7 @@
 "	.previous\n"
 	: "=r" (val), "=r" (ret)
 	: "0" (val), "r" (saddr), "r" (regs->isr)
-	: "r19", "r20" );
+	: "r19", "r20", FIXUP_BRANCH_CLOBBER );
 #else
     {
 	unsigned long valh=0,vall=0;
@@ -287,7 +289,7 @@
 "	.previous\n"
 	: "=r" (valh), "=r" (vall), "=r" (ret)
 	: "0" (valh), "1" (vall), "r" (saddr), "r" (regs->isr)
-	: "r19", "r20" );
+	: "r19", "r20", FIXUP_BRANCH_CLOBBER );
 	val=((__u64)valh<<32)|(__u64)vall;
     }
 #endif
@@ -335,7 +337,7 @@
 "	.previous\n"
 	: "=r" (ret)
 	: "r" (val), "r" (regs->ior), "r" (regs->isr)
-	: "r19" );
+	: "r19", FIXUP_BRANCH_CLOBBER );
 
 	return ret;
 }
@@ -389,7 +391,7 @@
 "	.previous\n"
 	: "=r" (ret)
 	: "r" (val), "r" (regs->ior), "r" (regs->isr)
-	: "r19", "r20", "r21", "r22", "r1" );
+	: "r19", "r20", "r21", "r22", "r1", FIXUP_BRANCH_CLOBBER );
 
 	return 0;
 }
@@ -450,7 +452,7 @@
 "	.previous\n"
 	: "=r" (ret)
 	: "r" (val), "r" (regs->ior), "r" (regs->isr)
-	: "r19", "r20", "r21", "r22", "r1" );
+	: "r19", "r20", "r21", "r22", "r1", FIXUP_BRANCH_CLOBBER );
 #else
     {
 	unsigned long valh=(val>>32),vall=(val&0xffffffffl);
@@ -495,7 +497,7 @@
 "	.previous\n"
 	: "=r" (ret)
 	: "r" (valh), "r" (vall), "r" (regs->ior), "r" (regs->isr)
-	: "r19", "r20", "r21", "r1" );
+	: "r19", "r20", "r21", "r1", FIXUP_BRANCH_CLOBBER );
     }
 #endif
 
diff --git a/drivers/parisc/Kconfig b/drivers/parisc/Kconfig
index 3f5de86..1d3b84b 100644
--- a/drivers/parisc/Kconfig
+++ b/drivers/parisc/Kconfig
@@ -140,18 +140,37 @@
 	  If unsure, say Y.
 
 config PDC_CHASSIS
-	bool "PDC chassis State Panel support"
+	bool "PDC chassis state codes support"
 	default y
 	help
-	  Say Y here if you want to enable support for the LED State front
-	  panel as found on E class, and support for the GSP Virtual Front
-	  Panel (LED State and message logging)  as found on high end
-	  servers such as A, L and N-class.
-	  
-	  This has nothing to do with Chassis LCD and LED support.
+	  Say Y here if you want to enable support for Chassis codes.
+	  That includes support for LED State front panel as found on E
+	  class, and support for the GSP Virtual Front Panel (LED State and
+	  message logging)  as found on high end servers such as A, L and
+	  N-class.
+	  This driver will also display progress messages on LCD display,
+	  such as "INI", "RUN" and "FLT", and might thus clobber messages
+	  shown by the LED/LCD driver.
+	  This driver updates the state panel (LED and/or LCD) upon system
+	  state change (eg: boot, shutdown or panic).
 	  
 	  If unsure, say Y.
 
+
+config PDC_CHASSIS_WARN
+	bool "PDC chassis warnings support"
+	depends on PROC_FS
+	default y
+	help
+	  Say Y here if you want to enable support for Chassis warnings.
+	  This will add a proc entry '/proc/chassis' giving some information
+	  about the overall health state of the system.
+	  This includes NVRAM battery level, overtemp or failures such as
+	  fans or power units.
+
+	  If unsure, say Y.
+
+
 config PDC_STABLE
 	tristate "PDC Stable Storage support"
 	depends on SYSFS
diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c
index bbeabe3..ea1b7a6 100644
--- a/drivers/parisc/pdc_stable.c
+++ b/drivers/parisc/pdc_stable.c
@@ -28,8 +28,15 @@
  *    following code can deal with just 96 bytes of Stable Storage, and all
  *    sizes between 96 and 192 bytes (provided they are multiple of struct
  *    device_path size, eg: 128, 160 and 192) to provide full information.
- *    The code makes no use of data above 192 bytes. One last word: there's one
- *    path we can always count on: the primary path.
+ *    One last word: there's one path we can always count on: the primary path.
+ *    Anything above 224 bytes is used for 'osdep2' OS-dependent storage area.
+ *
+ *    The first OS-dependent area should always be available. Obviously, this is
+ *    not true for the other one. Also bear in mind that reading/writing from/to
+ *    osdep2 is much more expensive than from/to osdep1.
+ *    NOTE: We do not handle the 2 bytes OS-dep area at 0x5D, nor the first
+ *    2 bytes of storage available right after OSID. That's a total of 4 bytes
+ *    sacrificed: -ETOOLAZY :P
  *
  *    The current policy wrt file permissions is:
  *	- write: root only
@@ -64,15 +71,18 @@
 #include <asm/uaccess.h>
 #include <asm/hardware.h>
 
-#define PDCS_VERSION	"0.22"
+#define PDCS_VERSION	"0.30"
 #define PDCS_PREFIX	"PDC Stable Storage"
 
 #define PDCS_ADDR_PPRI	0x00
 #define PDCS_ADDR_OSID	0x40
+#define PDCS_ADDR_OSD1	0x48
+#define PDCS_ADDR_DIAG	0x58
 #define PDCS_ADDR_FSIZ	0x5C
 #define PDCS_ADDR_PCON	0x60
 #define PDCS_ADDR_PALT	0x80
 #define PDCS_ADDR_PKBD	0xA0
+#define PDCS_ADDR_OSD2	0xE0
 
 MODULE_AUTHOR("Thibaut VARENE <varenet@parisc-linux.org>");
 MODULE_DESCRIPTION("sysfs interface to HP PDC Stable Storage data");
@@ -82,6 +92,9 @@
 /* holds Stable Storage size. Initialized once and for all, no lock needed */
 static unsigned long pdcs_size __read_mostly;
 
+/* holds OS ID. Initialized once and for all, hopefully to 0x0006 */
+static u16 pdcs_osid __read_mostly;
+
 /* This struct defines what we need to deal with a parisc pdc path entry */
 struct pdcspath_entry {
 	rwlock_t rw_lock;		/* to protect path entry access */
@@ -609,27 +622,64 @@
 pdcs_osid_read(struct subsystem *entry, char *buf)
 {
 	char *out = buf;
-	__u32 result;
-	char *tmpstr = NULL;
 
 	if (!entry || !buf)
 		return -EINVAL;
 
-	/* get OSID */
-	if (pdc_stable_read(PDCS_ADDR_OSID, &result, sizeof(result)) != PDC_OK)
+	out += sprintf(out, "%s dependent data (0x%.4x)\n",
+		os_id_to_string(pdcs_osid), pdcs_osid);
+
+	return out - buf;
+}
+
+/**
+ * pdcs_osdep1_read - Stable Storage OS-Dependent data area 1 output.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The output buffer to write to.
+ *
+ * This can hold 16 bytes of OS-Dependent data.
+ */
+static ssize_t
+pdcs_osdep1_read(struct subsystem *entry, char *buf)
+{
+	char *out = buf;
+	u32 result[4];
+
+	if (!entry || !buf)
+		return -EINVAL;
+
+	if (pdc_stable_read(PDCS_ADDR_OSD1, &result, sizeof(result)) != PDC_OK)
 		return -EIO;
 
-	/* the actual result is 16 bits away */
-	switch (result >> 16) {
-		case 0x0000:	tmpstr = "No OS-dependent data"; break;
-		case 0x0001:	tmpstr = "HP-UX dependent data"; break;
-		case 0x0002:	tmpstr = "MPE-iX dependent data"; break;
-		case 0x0003:	tmpstr = "OSF dependent data"; break;
-		case 0x0004:	tmpstr = "HP-RT dependent data"; break;
-		case 0x0005:	tmpstr = "Novell Netware dependent data"; break;
-		default:	tmpstr = "Unknown"; break;
-	}
-	out += sprintf(out, "%s (0x%.4x)\n", tmpstr, (result >> 16));
+	out += sprintf(out, "0x%.8x\n", result[0]);
+	out += sprintf(out, "0x%.8x\n", result[1]);
+	out += sprintf(out, "0x%.8x\n", result[2]);
+	out += sprintf(out, "0x%.8x\n", result[3]);
+
+	return out - buf;
+}
+
+/**
+ * pdcs_diagnostic_read - Stable Storage Diagnostic register output.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The output buffer to write to.
+ *
+ * I have NFC how to interpret the content of that register ;-).
+ */
+static ssize_t
+pdcs_diagnostic_read(struct subsystem *entry, char *buf)
+{
+	char *out = buf;
+	u32 result;
+
+	if (!entry || !buf)
+		return -EINVAL;
+
+	/* get diagnostic */
+	if (pdc_stable_read(PDCS_ADDR_DIAG, &result, sizeof(result)) != PDC_OK)
+		return -EIO;
+
+	out += sprintf(out, "0x%.4x\n", (result >> 16));
 
 	return out - buf;
 }
@@ -645,7 +695,7 @@
 pdcs_fastsize_read(struct subsystem *entry, char *buf)
 {
 	char *out = buf;
-	__u32 result;
+	u32 result;
 
 	if (!entry || !buf)
 		return -EINVAL;
@@ -664,6 +714,39 @@
 }
 
 /**
+ * pdcs_osdep2_read - Stable Storage OS-Dependent data area 2 output.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The output buffer to write to.
+ *
+ * This can hold pdcs_size - 224 bytes of OS-Dependent data, when available.
+ */
+static ssize_t
+pdcs_osdep2_read(struct subsystem *entry, char *buf)
+{
+	char *out = buf;
+	unsigned long size;
+	unsigned short i;
+	u32 result;
+
+	if (unlikely(pdcs_size <= 224))
+		return -ENODATA;
+
+	size = pdcs_size - 224;
+
+	if (!entry || !buf)
+		return -EINVAL;
+
+	for (i=0; i<size; i+=4) {
+		if (unlikely(pdc_stable_read(PDCS_ADDR_OSD2 + i, &result,
+					sizeof(result)) != PDC_OK))
+			return -EIO;
+		out += sprintf(out, "0x%.8x\n", result);
+	}
+
+	return out - buf;
+}
+
+/**
  * pdcs_auto_write - This function handles autoboot/search flag modifying.
  * @entry: An allocated and populated subsytem struct. We don't use it tho.
  * @buf: The input buffer to read from.
@@ -770,13 +853,100 @@
 	return pdcs_auto_write(entry, buf, count, PF_AUTOSEARCH);
 }
 
+/**
+ * pdcs_osdep1_write - Stable Storage OS-Dependent data area 1 input.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The input buffer to read from.
+ * @count: The number of bytes to be read.
+ *
+ * This can store 16 bytes of OS-Dependent data. We use a byte-by-byte
+ * write approach. It's up to userspace to deal with it when constructing
+ * its input buffer.
+ */
+static ssize_t
+pdcs_osdep1_write(struct subsystem *entry, const char *buf, size_t count)
+{
+	u8 in[16];
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	if (!entry || !buf || !count)
+		return -EINVAL;
+
+	if (unlikely(pdcs_osid != OS_ID_LINUX))
+		return -EPERM;
+
+	if (count > 16)
+		return -EMSGSIZE;
+
+	/* We'll use a local copy of buf */
+	memset(in, 0, 16);
+	memcpy(in, buf, count);
+
+	if (pdc_stable_write(PDCS_ADDR_OSD1, &in, sizeof(in)) != PDC_OK)
+		return -EIO;
+
+	return count;
+}
+
+/**
+ * pdcs_osdep2_write - Stable Storage OS-Dependent data area 2 input.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The input buffer to read from.
+ * @count: The number of bytes to be read.
+ *
+ * This can store pdcs_size - 224 bytes of OS-Dependent data. We use a
+ * byte-by-byte write approach. It's up to userspace to deal with it when
+ * constructing its input buffer.
+ */
+static ssize_t
+pdcs_osdep2_write(struct subsystem *entry, const char *buf, size_t count)
+{
+	unsigned long size;
+	unsigned short i;
+	u8 in[4];
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	if (!entry || !buf || !count)
+		return -EINVAL;
+
+	if (unlikely(pdcs_size <= 224))
+		return -ENOSYS;
+
+	if (unlikely(pdcs_osid != OS_ID_LINUX))
+		return -EPERM;
+
+	size = pdcs_size - 224;
+
+	if (count > size)
+		return -EMSGSIZE;
+
+	/* We'll use a local copy of buf */
+
+	for (i=0; i<count; i+=4) {
+		memset(in, 0, 4);
+		memcpy(in, buf+i, (count-i < 4) ? count-i : 4);
+		if (unlikely(pdc_stable_write(PDCS_ADDR_OSD2 + i, &in,
+					sizeof(in)) != PDC_OK))
+			return -EIO;
+	}
+
+	return count;
+}
+
 /* The remaining attributes. */
 static PDCS_ATTR(size, 0444, pdcs_size_read, NULL);
 static PDCS_ATTR(autoboot, 0644, pdcs_autoboot_read, pdcs_autoboot_write);
 static PDCS_ATTR(autosearch, 0644, pdcs_autosearch_read, pdcs_autosearch_write);
 static PDCS_ATTR(timer, 0444, pdcs_timer_read, NULL);
-static PDCS_ATTR(osid, 0400, pdcs_osid_read, NULL);
+static PDCS_ATTR(osid, 0444, pdcs_osid_read, NULL);
+static PDCS_ATTR(osdep1, 0600, pdcs_osdep1_read, pdcs_osdep1_write);
+static PDCS_ATTR(diagnostic, 0400, pdcs_diagnostic_read, NULL);
 static PDCS_ATTR(fastsize, 0400, pdcs_fastsize_read, NULL);
+static PDCS_ATTR(osdep2, 0600, pdcs_osdep2_read, pdcs_osdep2_write);
 
 static struct subsys_attribute *pdcs_subsys_attrs[] = {
 	&pdcs_attr_size,
@@ -784,7 +954,10 @@
 	&pdcs_attr_autosearch,
 	&pdcs_attr_timer,
 	&pdcs_attr_osid,
+	&pdcs_attr_osdep1,
+	&pdcs_attr_diagnostic,
 	&pdcs_attr_fastsize,
+	&pdcs_attr_osdep2,
 	NULL,
 };
 
@@ -865,6 +1038,7 @@
 {
 	struct subsys_attribute *attr;
 	int i, rc = 0, error = 0;
+	u32 result;
 
 	/* find the size of the stable storage */
 	if (pdc_stable_get_size(&pdcs_size) != PDC_OK) 
@@ -876,6 +1050,13 @@
 
 	printk(KERN_INFO PDCS_PREFIX " facility v%s\n", PDCS_VERSION);
 
+	/* get OSID */
+	if (pdc_stable_read(PDCS_ADDR_OSID, &result, sizeof(result)) != PDC_OK)
+		return -EIO;
+
+	/* the actual result is 16 bits away */
+	pdcs_osid = (u16)(result >> 16);
+
 	/* For now we'll register the stable subsys within this driver */
 	if ((rc = firmware_register(&stable_subsys)))
 		goto fail_firmreg;
@@ -887,7 +1068,7 @@
 	
 	/* register the paths subsys as a subsystem of stable subsys */
 	kset_set_kset_s(&paths_subsys, stable_subsys);
-	if ((rc= subsystem_register(&paths_subsys)))
+	if ((rc = subsystem_register(&paths_subsys)))
 		goto fail_subsysreg;
 
 	/* now we create all "files" for the paths subsys */
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
index 278f325..d09e39e 100644
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -316,10 +316,10 @@
 **
 ** Superdome (in particular, REO) allows only 64-bit CSR accesses.
 */
-#define READ_REG32(addr)	 le32_to_cpu(__raw_readl(addr))
-#define READ_REG64(addr)	 le64_to_cpu(__raw_readq(addr))
-#define WRITE_REG32(val, addr) __raw_writel(cpu_to_le32(val), addr)
-#define WRITE_REG64(val, addr) __raw_writeq(cpu_to_le64(val), addr)
+#define READ_REG32(addr)	readl(addr)
+#define READ_REG64(addr)	readq(addr)
+#define WRITE_REG32(val, addr)	writel((val), (addr))
+#define WRITE_REG64(val, addr)	writeq((val), (addr))
 
 #ifdef CONFIG_64BIT
 #define READ_REG(addr)		READ_REG64(addr)
@@ -1427,7 +1427,7 @@
 	iov_order = get_order(iova_space_size >> (IOVP_SHIFT - PAGE_SHIFT));
 	ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64);
 
-	DBG_INIT("%s() hpa 0x%lx IOV %dMB (%d bits)\n",
+	DBG_INIT("%s() hpa 0x%p IOV %dMB (%d bits)\n",
 		__FUNCTION__, ioc->ioc_hpa, iova_space_size >> 20,
 		iov_order + PAGE_SHIFT);
 
@@ -1764,7 +1764,7 @@
 
 	sba_dev->num_ioc = num_ioc;
 	for (i = 0; i < num_ioc; i++) {
-		unsigned long ioc_hpa = sba_dev->ioc[i].ioc_hpa;
+		void __iomem *ioc_hpa = sba_dev->ioc[i].ioc_hpa;
 		unsigned int j;
 
 		for (j=0; j < sizeof(u64) * ROPES_PER_IOC; j+=sizeof(u64)) {
@@ -1776,7 +1776,8 @@
 			 * Improves netperf UDP_STREAM by ~10% for bcm5701.
 			 */
 			if (IS_PLUTO(sba_dev->iodc)) {
-				unsigned long rope_cfg, cfg_val;
+				void __iomem *rope_cfg;
+				unsigned long cfg_val;
 
 				rope_cfg = ioc_hpa + IOC_ROPE0_CFG + j;
 				cfg_val = READ_REG(rope_cfg);
@@ -1902,7 +1903,7 @@
 	 * (bit #61, big endian), we have to flush and sync every time
 	 * IO-PDIR is changed in Ike/Astro.
 	 */
-	if (boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC) {
+	if (ioc_needs_fdc) {
 		printk(KERN_INFO MODULE_NAME " FDC/SYNC required.\n");
 	} else {
 		printk(KERN_INFO MODULE_NAME " IOC has cache coherent PDIR.\n");
diff --git a/include/asm-parisc/assembly.h b/include/asm-parisc/assembly.h
index 3ce3440..1a7bfe6 100644
--- a/include/asm-parisc/assembly.h
+++ b/include/asm-parisc/assembly.h
@@ -48,6 +48,7 @@
 #define CALLEE_SAVE_FRAME_SIZE (CALLEE_REG_FRAME_SIZE + CALLEE_FLOAT_FRAME_SIZE)
 
 #ifdef CONFIG_PA20
+#define LDCW		ldcw,co
 #define BL		b,l
 # ifdef CONFIG_64BIT
 #  define LEVEL		2.0w
@@ -55,6 +56,7 @@
 #  define LEVEL		2.0
 # endif
 #else
+#define LDCW		ldcw
 #define BL		bl
 #define LEVEL		1.1
 #endif
diff --git a/include/asm-parisc/compat.h b/include/asm-parisc/compat.h
index 289624d..71b4eee 100644
--- a/include/asm-parisc/compat.h
+++ b/include/asm-parisc/compat.h
@@ -5,6 +5,7 @@
  */
 #include <linux/types.h>
 #include <linux/sched.h>
+#include <linux/personality.h>
 
 #define COMPAT_USER_HZ 100
 
@@ -149,4 +150,14 @@
 	return (void __user *)regs->gr[30];
 }
 
+static inline int __is_compat_task(struct task_struct *t)
+{
+	return personality(t->personality) == PER_LINUX32;
+}
+
+static inline int is_compat_task(void)
+{
+	return __is_compat_task(current);
+}
+
 #endif /* _ASM_PARISC_COMPAT_H */
diff --git a/include/asm-parisc/pdc.h b/include/asm-parisc/pdc.h
index 08364f9..c9b2e35 100644
--- a/include/asm-parisc/pdc.h
+++ b/include/asm-parisc/pdc.h
@@ -278,12 +278,11 @@
 /* constants for OS (NVM...) */
 #define OS_ID_NONE		0	/* Undefined OS ID	*/
 #define OS_ID_HPUX		1	/* HP-UX OS		*/
-#define OS_ID_LINUX		OS_ID_HPUX /* just use the same value as hpux */
 #define OS_ID_MPEXL		2	/* MPE XL OS		*/
 #define OS_ID_OSF		3	/* OSF OS		*/
 #define OS_ID_HPRT		4	/* HP-RT OS		*/
 #define OS_ID_NOVEL		5	/* NOVELL OS		*/
-#define OS_ID_NT		6	/* NT OS		*/
+#define OS_ID_LINUX		6	/* Linux		*/
 
 
 /* constants for PDC_CHASSIS */
@@ -352,8 +351,8 @@
 		cc_wt	: 1,	/* 0 = WT-Dcache, 1 = WB-Dcache */
 		cc_sh	: 2,	/* 0 = separate I/D-cache, else shared I/D-cache */
 		cc_cst  : 3,	/* 0 = incoherent D-cache, 1=coherent D-cache */
-		cc_pad1 : 5,	/* reserved */
-		cc_assoc: 8;	/* associativity of I/D-cache */
+		cc_pad1 : 10,	/* reserved */
+		cc_hv   : 3;	/* hversion dependent */
 };
 
 struct pdc_tlb_cf {		/* for PDC_CACHE (I/D-TLB's) */
@@ -719,6 +718,7 @@
 int pdc_add_valid(unsigned long address);
 int pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsigned long len);
 int pdc_chassis_disp(unsigned long disp);
+int pdc_chassis_warn(unsigned long *warn);
 int pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info);
 int pdc_iodc_read(unsigned long *actcnt, unsigned long hpa, unsigned int index,
 		  void *iodc_data, unsigned int iodc_data_size);
@@ -732,6 +732,7 @@
 int pdc_model_versions(unsigned long *versions, int id);
 int pdc_model_capabilities(unsigned long *capabilities);
 int pdc_cache_info(struct pdc_cache_info *cache);
+int pdc_spaceid_bits(unsigned long *space_bits);
 #ifndef CONFIG_PA20
 int pdc_btlb_info(struct pdc_btlb_info *btlb);
 int pdc_mem_map_hpa(struct pdc_memory_map *r_addr, struct pdc_module_path *mod_path);
@@ -775,6 +776,18 @@
 
 extern void pdc_init(void);
 
+static inline char * os_id_to_string(u16 os_id) {
+	switch(os_id) {
+	case OS_ID_NONE:	return "No OS";
+	case OS_ID_HPUX:	return "HP-UX";
+	case OS_ID_MPEXL:	return "MPE-iX";
+	case OS_ID_OSF:		return "OSF";
+	case OS_ID_HPRT:	return "HP-RT";
+	case OS_ID_NOVEL:	return "Novell Netware";
+	case OS_ID_LINUX:	return "Linux";
+	default:	return "Unknown";
+	}
+}
 #endif /* __ASSEMBLY__ */
 
 #endif /* _PARISC_PDC_H */
diff --git a/include/asm-parisc/pgtable.h b/include/asm-parisc/pgtable.h
index b6bcc67..5066c54 100644
--- a/include/asm-parisc/pgtable.h
+++ b/include/asm-parisc/pgtable.h
@@ -506,13 +506,13 @@
 
 /* TLB page size encoding - see table 3-1 in parisc20.pdf */
 #define _PAGE_SIZE_ENCODING_4K		0
-#define _PAGE_SIZE_ENCODING_16K	1
-#define _PAGE_SIZE_ENCODING_64K	2
+#define _PAGE_SIZE_ENCODING_16K		1
+#define _PAGE_SIZE_ENCODING_64K		2
 #define _PAGE_SIZE_ENCODING_256K	3
 #define _PAGE_SIZE_ENCODING_1M		4
 #define _PAGE_SIZE_ENCODING_4M		5
-#define _PAGE_SIZE_ENCODING_16M	6
-#define _PAGE_SIZE_ENCODING_64M	7
+#define _PAGE_SIZE_ENCODING_16M		6
+#define _PAGE_SIZE_ENCODING_64M		7
 
 #if defined(CONFIG_PARISC_PAGE_SIZE_4KB)
 # define _PAGE_SIZE_ENCODING_DEFAULT _PAGE_SIZE_ENCODING_4K
diff --git a/include/asm-parisc/processor.h b/include/asm-parisc/processor.h
index ca49dc9..b73626f 100644
--- a/include/asm-parisc/processor.h
+++ b/include/asm-parisc/processor.h
@@ -26,14 +26,12 @@
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
  */
-
-/* We cannot use MFIA as it was added for PA2.0 - prumpf
-
-   At one point there were no "0f/0b" type local symbols in gas for
-   PA-RISC.  This is no longer true, but this still seems like the
-   nicest way to implement this. */
-
-#define current_text_addr() ({ void *pc; __asm__("\n\tblr 0,%0\n\tnop":"=r" (pc)); pc; })
+#ifdef CONFIG_PA20
+#define current_ia(x)	__asm__("mfia %0" : "=r"(x))
+#else /* mfia added in pa2.0 */
+#define current_ia(x)	__asm__("blr 0,%0\n\tnop" : "=r"(x))
+#endif
+#define current_text_addr() ({ void *pc; current_ia(pc); pc; })
 
 #define TASK_SIZE               (current->thread.task_size)
 #define TASK_UNMAPPED_BASE      (current->thread.map_base)
diff --git a/include/asm-parisc/system.h b/include/asm-parisc/system.h
index 8638761..5fe2d23 100644
--- a/include/asm-parisc/system.h
+++ b/include/asm-parisc/system.h
@@ -155,13 +155,14 @@
    type and dynamically select the 16-byte aligned int from the array
    for the semaphore.  */
 
-#define __PA_LDCW_ALIGNMENT 16
-#define __ldcw_align(a) ({ \
-  unsigned long __ret = (unsigned long) &(a)->lock[0];        		\
-  __ret = (__ret + __PA_LDCW_ALIGNMENT - 1) & ~(__PA_LDCW_ALIGNMENT - 1); \
-  (volatile unsigned int *) __ret;                                      \
+#define __PA_LDCW_ALIGNMENT	16
+#define __ldcw_align(a) ({					\
+	unsigned long __ret = (unsigned long) &(a)->lock[0];	\
+	__ret = (__ret + __PA_LDCW_ALIGNMENT - 1)		\
+		& ~(__PA_LDCW_ALIGNMENT - 1);			\
+	(volatile unsigned int *) __ret;			\
 })
-#define LDCW	"ldcw"
+#define __LDCW	"ldcw"
 
 #else /*CONFIG_PA20*/
 /* From: "Jim Hull" <jim.hull of hp.com>
@@ -171,17 +172,18 @@
    they only require "natural" alignment (4-byte for ldcw, 8-byte for
    ldcd). */
 
-#define __PA_LDCW_ALIGNMENT 4
+#define __PA_LDCW_ALIGNMENT	4
 #define __ldcw_align(a) ((volatile unsigned int *)a)
-#define LDCW	"ldcw,co"
+#define __LDCW	"ldcw,co"
 
 #endif /*!CONFIG_PA20*/
 
 /* LDCW, the only atomic read-write operation PA-RISC has. *sigh*.  */
-#define __ldcw(a) ({ \
-	unsigned __ret; \
-	__asm__ __volatile__(LDCW " 0(%1),%0" : "=r" (__ret) : "r" (a)); \
-	__ret; \
+#define __ldcw(a) ({						\
+	unsigned __ret;						\
+	__asm__ __volatile__(__LDCW " 0(%1),%0"			\
+		: "=r" (__ret) : "r" (a));			\
+	__ret;							\
 })
 
 #ifdef CONFIG_SMP
diff --git a/include/asm-parisc/uaccess.h b/include/asm-parisc/uaccess.h
index f6c417c..d973e8b 100644
--- a/include/asm-parisc/uaccess.h
+++ b/include/asm-parisc/uaccess.h
@@ -172,7 +172,11 @@
 /*
  * The "__put_user/kernel_asm()" macros tell gcc they read from memory
  * instead of writing. This is because they do not write to any memory
- * gcc knows about, so there are no aliasing issues.
+ * gcc knows about, so there are no aliasing issues. These macros must
+ * also be aware that "fixup_put_user_skip_[12]" are executed in the
+ * context of the fault, and any registers used there must be listed
+ * as clobbers. In this case only "r1" is used by the current routines.
+ * r8/r9 are already listed as err/val.
  */
 
 #ifdef __LP64__
@@ -183,7 +187,8 @@
 		"\t.dword\t1b,fixup_put_user_skip_1\n"	    \
 		"\t.previous"                               \
 		: "=r"(__pu_err)                            \
-		: "r"(ptr), "r"(x), "0"(__pu_err))
+		: "r"(ptr), "r"(x), "0"(__pu_err)	    \
+	    	: "r1")
 
 #define __put_user_asm(stx,x,ptr)                           \
 	__asm__ __volatile__ (                              \
diff --git a/include/asm-parisc/unistd.h b/include/asm-parisc/unistd.h
index 12b8672..27bcfad 100644
--- a/include/asm-parisc/unistd.h
+++ b/include/asm-parisc/unistd.h
@@ -797,11 +797,6 @@
 
 #define SYS_ify(syscall_name)   __NR_##syscall_name
 
-/* Assume all syscalls are done from PIC code just to be
- * safe. The worst case scenario is that you lose a register
- * and save/restore r19 across the syscall. */
-#define PIC
-
 #ifndef ASM_LINE_SEP
 # define ASM_LINE_SEP ;
 #endif