public inbox for linux-ia64@vger.kernel.org
 help / color / mirror / Atom feed
* [Linux-ia64] kernel update (relative to v2.4.0-test1)
@ 2000-06-01  8:54 David Mosberger
  2000-06-03 17:32 ` Manfred Spraul
                   ` (215 more replies)
  0 siblings, 216 replies; 217+ messages in thread
From: David Mosberger @ 2000-06-01  8:54 UTC (permalink / raw)
  To: linux-ia64

Here is a quick kernel update.  I'm not sure this is distribution
material, but it should work better than last weeks patch.  Some
of the improvements:

	- "branch long" emulation by Stephan Zeisset is finally in
	  (sorry about the delay...).

	- added Stephane Eranian's /proc/palinfo "driver"; very nice
	  to find out details on your CPU...

	- SMP should work again

	- ptrace interface should work again (at least strace works...)

	- the unwind support now has a real cache and should be
          SMP-safe

	- SMP-related CPU initialization clean up; the bootstrap
	  processor now does an identify_cpu() early in the
	  bootprocess (same as in the UP case); this is necessary
	  because we now rely on PAL info stored in cpu_data[] to
	  bootstrap the system

	- some more ia-32 signal fixes from Don

	- unaligned accesses in big-endian mode now result in SIGBUS (instead
	  of sliently bogus data) (Stephane Eranian)

	- updated for 2.4.0-test1

	- remove Itanium dependencies from pgtable.h again (there is no desire
	  or need to make the kernel implementation specific)

	- speculative accesses that result in an alternate d-tlb fault are now
	  always NaTed

	- make simscsi driver SMP-safe

The full diff is available at

 ftp://ftp.kernel.org/pub/linux/kernel/ports/ia64/linux-2.4.0-test1-ia64-000531.diff*

as usual.

	--david

diff -urN linux-davidm/arch/ia64/config.in linux-2.4.0-test1-lia/arch/ia64/config.in
--- linux-davidm/arch/ia64/config.in	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/arch/ia64/config.in	Thu Jun  1 00:59:33 2000
@@ -4,7 +4,6 @@
 comment 'General setup'
 
 define_bool CONFIG_IA64 y
-define_bool CONFIG_ITANIUM y	# easy choice for now... ;-)
 
 define_bool CONFIG_ISA n
 define_bool CONFIG_SBUS n
@@ -22,6 +21,8 @@
 	 64KB			CONFIG_IA64_PAGE_SIZE_64KB" 16KB
 
 if [ "$CONFIG_IA64_DIG" = "y" ]; then
+	define_bool CONFIG_ITANIUM y
+	define_bool CONFIG_IA64_BRL_EMU y
 	bool '  Enable Itanium A-step specific code' CONFIG_ITANIUM_ASTEP_SPECIFIC
 	bool '  Enable Itanium A1-step specific code' CONFIG_ITANIUM_A1_SPECIFIC
 	bool '  Enable use of global TLB purge instruction (ptc.g)' CONFIG_ITANIUM_PTCG
@@ -44,6 +45,7 @@
 
 bool 'SMP support' CONFIG_SMP
 bool 'Performance monitor support' CONFIG_PERFMON
+bool '/proc/palinfo support' CONFIG_IA64_PALINFO
 
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
diff -urN linux-davidm/arch/ia64/hp/hpsim_irq.c linux-2.4.0-test1-lia/arch/ia64/hp/hpsim_irq.c
--- linux-davidm/arch/ia64/hp/hpsim_irq.c	Fri Mar 10 15:24:02 2000
+++ linux-2.4.0-test1-lia/arch/ia64/hp/hpsim_irq.c	Thu Jun  1 01:00:14 2000
@@ -5,7 +5,8 @@
  * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
-#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/irq.h>
 
 static unsigned int
diff -urN linux-davidm/arch/ia64/ia32/ia32_signal.c linux-2.4.0-test1-lia/arch/ia64/ia32/ia32_signal.c
--- linux-davidm/arch/ia64/ia32/ia32_signal.c	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/arch/ia64/ia32/ia32_signal.c	Thu Jun  1 01:00:27 2000
@@ -55,7 +55,7 @@
 };
 
 static int
-copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from)
+copy_siginfo_to_user32 (siginfo_t32 *to, siginfo_t *from)
 {
 	int err;
 
@@ -326,8 +326,8 @@
                           ? current->exec_domain->signal_invmap[sig]
                           : sig),
                          &frame->sig);
-       err |= __put_user(&frame->info, &frame->pinfo);
-       err |= __put_user(&frame->uc, &frame->puc);
+       err |= __put_user((long)&frame->info, &frame->pinfo);
+       err |= __put_user((long)&frame->uc, &frame->puc);
        err |= copy_siginfo_to_user32(&frame->info, info);
 
        /* Create the ucontext.  */
diff -urN linux-davidm/arch/ia64/kernel/Makefile linux-2.4.0-test1-lia/arch/ia64/kernel/Makefile
--- linux-davidm/arch/ia64/kernel/Makefile	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/Makefile	Thu Jun  1 01:00:52 2000
@@ -1,11 +1,6 @@
 #
 # Makefile for the linux kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
 .S.s:
 	$(CPP) $(AFLAGS) -o $*.s $<
@@ -24,6 +19,10 @@
 O_OBJS	+= machvec.o
 endif
 
+ifdef CONFIG_IA64_PALINFO
+O_OBJS	+= palinfo.o
+endif
+
 ifdef CONFIG_PCI
 O_OBJS	+= pci.o
 endif
@@ -34,6 +33,10 @@
 
 ifdef CONFIG_IA64_MCA
 O_OBJS	+= mca.o mca_asm.o
+endif
+
+ifdef CONFIG_IA64_BRL_EMU
+O_OBJS  += brl_emu.o
 endif
 
 clean::
diff -urN linux-davidm/arch/ia64/kernel/brl_emu.c linux-2.4.0-test1-lia/arch/ia64/kernel/brl_emu.c
--- linux-davidm/arch/ia64/kernel/brl_emu.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/brl_emu.c	Thu Jun  1 01:01:03 2000
@@ -0,0 +1,220 @@
+/*
+ *  Emulation of the "brl" instruction for IA64 processors that
+ *  don't support it in hardware. 
+ *  Author: Stephan Zeisset, Intel Corp. <Stephan.Zeisset@intel.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+
+extern char ia64_set_b1, ia64_set_b2, ia64_set_b3, ia64_set_b4, ia64_set_b5;
+
+struct illegal_op_return {
+	unsigned long fkt, arg1, arg2, arg3;
+};
+
+/*
+ *  The unimplemented bits of a virtual address must be set
+ *  to the value of the most significant implemented bit.
+ *  unimpl_va_mask includes all unimplemented bits and
+ *  the most significant implemented bit, so the result
+ *  of an and operation with the mask must be all 0's
+ *  or all 1's for the address to be valid.
+ */
+#define unimplemented_virtual_address(va) (					\
+	((va) & my_cpu_data.unimpl_va_mask) != 0 &&				\
+	((va) & my_cpu_data.unimpl_va_mask) != my_cpu_data.unimpl_va_mask	\
+)
+
+/*
+ *  The unimplemented bits of a physical address must be 0.
+ *  unimpl_pa_mask includes all unimplemented bits, so the result
+ *  of an and operation with the mask must be all 0's for the
+ *  address to be valid.
+ */
+#define unimplemented_physical_address(pa) (		\
+	((pa) & my_cpu_data.unimpl_pa_mask) != 0	\
+)
+
+/*
+ *  Handle an illegal operation fault that was caused by an 
+ *  unimplemented "brl" instruction.
+ *  If we are not successful (e.g because the illegal operation 
+ *  wasn't caused by a "brl" after all), we return -1.
+ *  If we are successful, we return either 0 or the address
+ *  of a "fixup" function for manipulating preserved register
+ *  state.
+ */
+
+struct illegal_op_return
+ia64_emulate_brl (struct pt_regs *regs, unsigned long ar_ec)
+{
+	unsigned long bundle[2];
+	unsigned long opcode, btype, qp, offset;
+	unsigned long next_ip;
+	struct siginfo siginfo;
+	struct illegal_op_return rv;
+	int tmp_taken, unimplemented_address;
+
+	rv.fkt = (unsigned long) -1;
+
+	/*
+	 *  Decode the instruction bundle.
+	 */
+
+        if (copy_from_user(bundle, (void *) (regs->cr_iip), sizeof(bundle)))
+                return rv; 
+
+	next_ip = (unsigned long) regs->cr_iip + 16;
+
+	/* "brl" must be in slot 2. */
+	if (ia64_psr(regs)->ri != 1) return rv;
+
+	/* Must be "mlx" template */
+	if ((bundle[0] & 0x1e) != 0x4) return rv;
+
+	opcode = (bundle[1] >> 60);
+	btype = ((bundle[1] >> 29) & 0x7);
+	qp = ((bundle[1] >> 23) & 0x3f);
+	offset = ((bundle[1] & 0x0800000000000000L) << 4)
+		| ((bundle[1] & 0x00fffff000000000L) >> 32) 
+		| ((bundle[1] & 0x00000000007fffffL) << 40)
+		| ((bundle[0] & 0xffff000000000000L) >> 24);
+
+	tmp_taken = regs->pr & (1L << qp);
+
+	switch(opcode) {
+		
+		case 0xC:
+			/*
+			 *  Long Branch.
+			 */
+			if (btype != 0) return rv;
+			rv.fkt = 0;
+			if (!(tmp_taken)) {
+				/*
+				 *  Qualifying predicate is 0.
+				 *  Skip instruction.
+				 */
+				regs->cr_iip = next_ip;
+				ia64_psr(regs)->ri = 0;
+				return rv;
+			}
+			break;
+
+		case 0xD:
+			/*
+			 *  Long Call.
+			 */
+			rv.fkt = 0;
+			if (!(tmp_taken)) {
+				/*
+				 *  Qualifying predicate is 0.
+				 *  Skip instruction.
+				 */
+				regs->cr_iip = next_ip;
+				ia64_psr(regs)->ri = 0;
+				return rv;
+			}
+
+			/*
+			 *  BR[btype] = IP+16
+			 */
+			switch(btype) {
+				case 0:
+					regs->b0 = next_ip;
+					break;
+				case 1:
+					rv.fkt = (unsigned long) &ia64_set_b1;
+					break;
+				case 2:
+					rv.fkt = (unsigned long) &ia64_set_b2;
+					break;
+				case 3:
+					rv.fkt = (unsigned long) &ia64_set_b3;
+					break;
+				case 4:
+					rv.fkt = (unsigned long) &ia64_set_b4;
+					break;
+				case 5:
+					rv.fkt = (unsigned long) &ia64_set_b5;
+					break;
+				case 6:
+					regs->b6 = next_ip;
+					break;
+				case 7:
+					regs->b7 = next_ip;
+					break;
+			}
+			rv.arg1 = next_ip;
+
+			/*
+			 *  AR[PFS].pfm = CFM
+			 *  AR[PFS].pec = AR[EC]
+			 *  AR[PFS].ppl = PSR.cpl
+			 */
+			regs->ar_pfs = ((regs->cr_ifs & 0x3fffffffff)
+					| (ar_ec << 52)
+					| ((unsigned long) ia64_psr(regs)->cpl << 62));
+
+			/*
+			 *  CFM.sof -= CFM.sol
+			 *  CFM.sol = 0
+			 *  CFM.sor = 0
+			 *  CFM.rrb.gr = 0
+			 *  CFM.rrb.fr = 0
+			 *  CFM.rrb.pr = 0
+			 */
+			regs->cr_ifs = ((regs->cr_ifs & 0xffffffc00000007f)
+					- ((regs->cr_ifs >> 7) & 0x7f));
+				
+			break;
+
+		default:
+			/*
+			 *  Unknown opcode.
+			 */
+			return rv;
+
+	}
+
+	regs->cr_iip += offset; 
+	ia64_psr(regs)->ri = 0;
+
+	if (ia64_psr(regs)->it = 0)
+		unimplemented_address = unimplemented_physical_address(regs->cr_iip);
+	else
+		unimplemented_address = unimplemented_virtual_address(regs->cr_iip);
+
+	if (unimplemented_address) { 
+		/*
+		 *  The target address contains unimplemented bits.
+		 */
+		printk("Woah! Unimplemented Instruction Address Trap!\n");
+		siginfo.si_signo = SIGILL;
+		siginfo.si_errno = 0;
+		siginfo.si_code = ILL_BADIADDR;
+		force_sig_info(SIGILL, &siginfo, current);
+	} else if (ia64_psr(regs)->tb) {
+		/*
+		 *  Branch Tracing is enabled.
+		 *  Force a taken branch signal.
+		 */
+		siginfo.si_signo = SIGTRAP;
+		siginfo.si_errno = 0;
+		siginfo.si_code = TRAP_BRANCH;
+		force_sig_info(SIGTRAP, &siginfo, current);
+	} else if (ia64_psr(regs)->ss) {
+		/*
+		 *  Single Step is enabled.
+		 *  Force a trace signal.
+		 */
+		siginfo.si_signo = SIGTRAP;
+		siginfo.si_errno = 0;
+		siginfo.si_code = TRAP_TRACE;
+		force_sig_info(SIGTRAP, &siginfo, current);
+	}
+	return rv;
+}
diff -urN linux-davidm/arch/ia64/kernel/efi.c linux-2.4.0-test1-lia/arch/ia64/kernel/efi.c
--- linux-davidm/arch/ia64/kernel/efi.c	Fri Apr 21 15:21:24 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/efi.c	Thu Jun  1 01:01:16 2000
@@ -5,9 +5,9 @@
  *
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
- * Copyright (C) 1999 Hewlett-Packard Co.
+ * Copyright (C) 1999-2000 Hewlett-Packard Co.
  * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
+ * Copyright (C) 1999-2000 Stephane Eranian <eranian@hpl.hp.com>
  *
  * All EFI Runtime Services are not implemented yet as EFI only
  * supports physical mode addressing on SoftSDV. This is to be fixed
@@ -22,6 +22,7 @@
 
 #include <asm/efi.h>
 #include <asm/io.h>
+#include <asm/pgtable.h>
 #include <asm/processor.h>
 
 #define EFI_DEBUG	0
@@ -207,6 +208,61 @@
 	}
 }
 
+/*
+ * Look for the PAL_CODE region reported by EFI and maps it using an
+ * ITR to enable safe PAL calls in virtual mode.  See IA-64 Processor
+ * Abstraction Layer chapter 11 in ADAG
+ */
+static void
+map_pal_code (void)
+{
+	void *efi_map_start, *efi_map_end, *p;
+	efi_memory_desc_t *md;
+	u64 efi_desc_size;
+	int pal_code_count=0;
+	u64 mask, flags;
+	u64 vaddr;
+
+	efi_map_start = __va(ia64_boot_param.efi_memmap);
+	efi_map_end   = efi_map_start + ia64_boot_param.efi_memmap_size;
+	efi_desc_size = ia64_boot_param.efi_memdesc_size;
+
+	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
+		md = p;
+		if (md->type != EFI_PAL_CODE) continue;
+
+		if (++pal_code_count > 1) {
+			printk(KERN_ERR "Too many EFI Pal Code memory ranges, dropped @ %lx\n",
+			       md->phys_addr);
+			continue;
+		} 
+		mask  = ~((1 << _PAGE_SIZE_4M)-1);	/* XXX should be dynamic? */
+		vaddr = PAGE_OFFSET + md->phys_addr;
+
+	  	printk(__FUNCTION__": mapping PAL code [0x%lx-0x%lx) into [0x%lx-0x%lx)\n",
+		       md->phys_addr, md->phys_addr + (md->num_pages << 12),
+		       vaddr & mask, (vaddr & mask) + 4*1024*1024);
+
+		/*
+		 * Cannot write to CRx with PSR.ic=1
+		 */
+		ia64_clear_ic(flags);
+
+		/*
+		 * ITR0/DTR0: used for kernel code/data
+		 * ITR1/DTR1: used by HP simulator
+		 * ITR2/DTR2: map PAL code
+		 * ITR3/DTR3: used to map PAL calls buffer
+		 */
+		ia64_itr(0x1, 2, vaddr & mask,
+			 pte_val(mk_pte_phys(md->phys_addr,
+					     __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RX))),
+			 _PAGE_SIZE_4M);
+		local_irq_restore(flags);
+		ia64_srlz_i ();
+	}
+}
+
 void __init 
 efi_init (void)
 {
@@ -291,6 +347,8 @@
 		}
 	}
 #endif
+
+	map_pal_code();
 }
 
 void
diff -urN linux-davidm/arch/ia64/kernel/efi_stub.S linux-2.4.0-test1-lia/arch/ia64/kernel/efi_stub.S
--- linux-davidm/arch/ia64/kernel/efi_stub.S	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/efi_stub.S	Thu Jun  1 01:01:29 2000
@@ -41,52 +41,6 @@
 	.text
 
 /*
- * Switch execution mode from virtual to physical or vice versa.
- *
- * Inputs:
- *	r16 = new psr to establish
- */
-ENTRY(switch_mode)
- {
-	alloc r2=ar.pfs,0,0,0,0
-	rsm psr.i | psr.ic		// disable interrupts and interrupt collection
-	mov r15=ip
- }
-	;;
- {
-	flushrs				// must be first insn in group
-	srlz.i
-	shr.u r19=r15,61		// r19 <- top 3 bits of current IP
- }
-	;;
-	mov cr.ipsr=r16			// set new PSR
-	add r3\x1f-switch_mode,r15
-	xor r15=0x7,r19			// flip the region bits
-
-	mov r17=ar.bsp
-	mov r14=rp			// get return address into a general register
-
-	// switch RSE backing store:
-	;;
-	dep r17=r15,r17,61,3		// make ar.bsp physical or virtual
-	mov r18=ar.rnat			// save ar.rnat
-	;;
-	mov ar.bspstore=r17		// this steps on ar.rnat
-	dep r3=r15,r3,61,3		// make rfi return address physical or virtual
-	;;
-	mov cr.iip=r3
-	mov cr.ifs=r0
-	dep sp=r15,sp,61,3		// make stack pointer physical or virtual
-	;;
-	mov ar.rnat=r18			// restore ar.rnat
-	dep r14=r15,r14,61,3		// make function return address physical or virtual
-	rfi				// must be last insn in group
-	;;
-1:	mov rp=r14
-	br.ret.sptk.few rp
-END(switch_mode)
-
-/*
  * Inputs:
  *	in0 = address of function descriptor of EFI routine to call
  *	in1..in7 = arguments to routine
@@ -121,7 +75,7 @@
 	;;
 	andcm r16=loc3,r16		// get psr with IT, DT, and RT bits cleared
 	mov out3=in4
-	br.call.sptk.few rp=switch_mode
+	br.call.sptk.few rp=ia64_switch_mode
 .ret0:
 	mov out4=in5
 	mov out5=in6
@@ -130,7 +84,7 @@
 .ret1:
 	mov ar.rsc=r0			// put RSE in enforced lazy, LE mode
 	mov r16=loc3
-	br.call.sptk.few rp=switch_mode	// return to virtual mode
+	br.call.sptk.few rp=ia64_switch_mode // return to virtual mode
 .ret2:
 	mov ar.rsc=loc4			// restore RSE configuration
 	mov ar.pfs=loc1
diff -urN linux-davidm/arch/ia64/kernel/entry.S linux-2.4.0-test1-lia/arch/ia64/kernel/entry.S
--- linux-davidm/arch/ia64/kernel/entry.S	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/entry.S	Thu Jun  1 01:02:14 2000
@@ -375,8 +375,6 @@
 	alloc loc1=ar.pfs,8,3,0,0
 	;;			// WAW on CFM at the br.call
 	mov loc0=rp
-	.fframe IA64_SWITCH_STACK_SIZE
-	adds sp=-IA64_SWITCH_STACK_SIZE,sp
 	br.call.sptk.many rp=save_switch_stack_with_current_frame	// must preserve b6!!
 .ret2:	mov loc2¶
 	br.call.sptk.few rp=syscall_trace
@@ -532,7 +530,7 @@
 2:
 	// check & deliver pending signals:
 (p2)	br.call.spnt.few rp=handle_signal_delivery
-#if defined(CONFIG_SMP) || defined(CONFIG_IA64_SOFTSDV_HACKS)
+#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_IA64_SOFTSDV_HACKS)
 	// Check for lost ticks
 	rsm psr.i
 	mov r2 = ar.itc
@@ -747,7 +745,7 @@
 
 #endif /* CONFIG_SMP */
 
-#if defined(CONFIG_SMP) || defined(CONFIG_IA64_SOFTSDV_HACKS)
+#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_IA64_SOFTSDV_HACKS)
 
 ENTRY(invoke_ia64_reset_itm)
 	UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8))
@@ -762,7 +760,7 @@
 	br.ret.sptk.many rp
 END(invoke_ia64_reset_itm)
 
-#endif /* defined(CONFIG_SMP) || defined(CONFIG_IA64_SOFTSDV_HACKS) */
+#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC || CONFIG_IA64_SOFTSDV_HACKS */
 
 	/*
 	 * Invoke do_softirq() while preserving in0-in7, which may be needed
@@ -847,7 +845,7 @@
 
 setup_switch_stack:
 	UNW(.prologue)
-	mov r16=loc0
+	mov r16=loc1
 	DO_SAVE_SWITCH_STACK
 	UNW(.body)
 	br.cond.sptk.many back_from_setup_switch_stack
diff -urN linux-davidm/arch/ia64/kernel/entry.h linux-2.4.0-test1-lia/arch/ia64/kernel/entry.h
--- linux-davidm/arch/ia64/kernel/entry.h	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/entry.h	Thu Jun  1 01:02:23 2000
@@ -11,8 +11,8 @@
 
 #define PT_REGS_UNWIND_INFO			\
 	UNW(.prologue);				\
-	UNW(.unwabi @svr4, 105);		\
-	UNW(.fframe IA64_PT_REGS_SIZE);		\
+	UNW(.unwabi @svr4, 'i');		\
+	UNW(.fframe IA64_PT_REGS_SIZE+16);	\
 	UNW(.spillsp rp, PT(CR_IIP));		\
 	UNW(.spillsp ar.pfs, PT(CR_IFS));	\
 	UNW(.spillsp ar.unat, PT(AR_UNAT));	\
diff -urN linux-davidm/arch/ia64/kernel/fw-emu.c linux-2.4.0-test1-lia/arch/ia64/kernel/fw-emu.c
--- linux-davidm/arch/ia64/kernel/fw-emu.c	Fri Mar 10 15:24:02 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/fw-emu.c	Thu Jun  1 01:02:33 2000
@@ -124,7 +124,18 @@
 	.proc pal_emulator_static
 pal_emulator_static:
 	mov r8=-1
-	cmp.eq p6,p7=6,r28		/* PAL_PTCE_INFO */
+
+	mov r9%6
+	;;
+	cmp.gtu p6,p7=r9,r28		/* r28 <= 255? */
+(p6)	br.cond.sptk.few static
+	;;
+	mov r9Q2
+	;;
+	cmp.gtu p6,p7=r9,r28
+(p6)	br.cond.sptk.few stacked
+	;;
+static:	cmp.eq p6,p7=6,r28		/* PAL_PTCE_INFO */
 (p7)	br.cond.sptk.few 1f
 	;;
 	mov r8=0			/* status = 0 */
@@ -157,7 +168,12 @@
 	;;
 	mov ar.lc=r9
 	mov r8=r0
-1:	br.cond.sptk.few rp
+1:
+	br.cond.sptk.few rp
+
+stacked:
+	br.ret.sptk.few rp
+
 	.endp pal_emulator_static\n");
 
 /* Macro to emulate SAL call using legacy IN and OUT calls to CF8, CFC etc.. */
diff -urN linux-davidm/arch/ia64/kernel/head.S linux-2.4.0-test1-lia/arch/ia64/kernel/head.S
--- linux-davidm/arch/ia64/kernel/head.S	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/head.S	Thu Jun  1 01:02:47 2000
@@ -633,3 +633,73 @@
 	mov      f127ð
 	br.ret.sptk.few rp
 END(__ia64_init_fpu)
+
+/*
+ * Switch execution mode from virtual to physical or vice versa.
+ *
+ * Inputs:
+ *	r16 = new psr to establish
+ *
+ * Note: RSE must already be in enforced lazy mode
+ */
+GLOBAL_ENTRY(ia64_switch_mode)
+ {
+	alloc r2=ar.pfs,0,0,0,0
+	rsm psr.i | psr.ic		// disable interrupts and interrupt collection
+	mov r15=ip
+ }
+	;;
+ {
+	flushrs				// must be first insn in group
+	srlz.i
+	shr.u r19=r15,61		// r19 <- top 3 bits of current IP
+ }
+	;;
+	mov cr.ipsr=r16			// set new PSR
+	add r3\x1f-ia64_switch_mode,r15
+	xor r15=0x7,r19			// flip the region bits
+
+	mov r17=ar.bsp
+	mov r14=rp			// get return address into a general register
+
+	// switch RSE backing store:
+	;;
+	dep r17=r15,r17,61,3		// make ar.bsp physical or virtual
+	mov r18=ar.rnat			// save ar.rnat
+	;;
+	mov ar.bspstore=r17		// this steps on ar.rnat
+	dep r3=r15,r3,61,3		// make rfi return address physical or virtual
+	;;
+	mov cr.iip=r3
+	mov cr.ifs=r0
+	dep sp=r15,sp,61,3		// make stack pointer physical or virtual
+	;;
+	mov ar.rnat=r18			// restore ar.rnat
+	dep r14=r15,r14,61,3		// make function return address physical or virtual
+	rfi				// must be last insn in group
+	;;
+1:	mov rp=r14
+	br.ret.sptk.few rp
+END(ia64_switch_mode)
+
+#ifdef CONFIG_IA64_BRL_EMU
+
+/*
+ *  Assembly routines used by brl_emu.c to set preserved register state.
+ */
+
+#define SET_REG(reg)				\
+ GLOBAL_ENTRY(ia64_set_##reg);			\
+	alloc r16=ar.pfs,1,0,0,0;		\
+	mov reg=r32;				\
+	;;					\
+	br.ret.sptk rp;				\
+ END(ia64_set_##reg)
+
+SET_REG(b1);
+SET_REG(b2);
+SET_REG(b3);
+SET_REG(b4);
+SET_REG(b5);
+
+#endif /* CONFIG_IA64_BRL_EMU */
diff -urN linux-davidm/arch/ia64/kernel/ivt.S linux-2.4.0-test1-lia/arch/ia64/kernel/ivt.S
--- linux-davidm/arch/ia64/kernel/ivt.S	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/ivt.S	Thu Jun  1 01:03:38 2000
@@ -316,7 +316,7 @@
 	movl r17=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RX
 	;;
 	shr.u r18=r16,57	// move address bit 61 to bit 4
-	dep r16=0,r16,IA64_PHYS_BITS,(64-IA64_PHYS_BITS) // clear ed, resvd, and unimpl. phys bits
+	dep r16=0,r16,IA64_MAX_PHYS_BITS,(64-IA64_MAX_PHYS_BITS)	// clear ed & reserved bits
 	;;
 	andcm r18=0x10,r18	// bit 4=~address-bit(61)
 	dep r16=r17,r16,0,12	// insert PTE control bits into r16
@@ -331,18 +331,26 @@
 // 0x1000 Entry 4 (size 64 bundles) Alt DTLB (7,46)
 	mov r16=cr.ifa		// get address that caused the TLB miss
 	movl r17=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RW
+	mov r20=cr.isr
+	mov r21=cr.ipsr
+	mov r19=pr
 	;;
+	tbit.nz p6,p7=r20,IA64_ISR_SP_BIT	// is speculation bit on?
 	shr.u r18=r16,57	// move address bit 61 to bit 4
-	dep r16=0,r16,IA64_PHYS_BITS,(64-IA64_PHYS_BITS) // clear ed, resvd, and unimpl. phys bits
+	dep r16=0,r16,IA64_MAX_PHYS_BITS,(64-IA64_MAX_PHYS_BITS) // clear ed & reserved bits
 	;;
 	andcm r18=0x10,r18	// bit 4=~address-bit(61)
 	dep r16=r17,r16,0,12	// insert PTE control bits into r16
 	;;
 	or r16=r16,r18		// set bit 4 (uncached) if the access was to region 6
+(p6)	mov cr.ipsr=r21
 	;;
-	itc.d r16		// insert the TLB entry
+(p7)	itc.d r16		// insert the TLB entry
+	mov pr=r19,-1
 	rfi
 
+	;;
+
 	//-----------------------------------------------------------------------------------
 	// call do_page_fault (predicates are in r31, psr.dt is off, r16 is faulting address)
 page_fault:
@@ -647,6 +655,50 @@
 // 0x3c00 Entry 15 (size 64 bundles) Reserved
 	FAULT(15)
 
+//
+//  Squatting in this space ...
+//
+//  This special case dispatcher for illegal operation faults
+//  allows preserved registers to be modified through a 
+//  callback function (asm only) that is handed back from
+//  the fault handler in r8. Up to three arguments can be
+//  passed to the callback function by returning an aggregate
+//  with the callback as its first element, followed by the
+//  arguments.
+//
+dispatch_illegal_op_fault:
+	SAVE_MIN_WITH_COVER
+	//
+	// The "alloc" can cause a mandatory store which could lead to
+	// an "Alt DTLB" fault which we can handle only if psr.ic is on.
+	//
+	ssm psr.ic | psr.dt
+	;;
+	srlz.i		// guarantee that interrupt collection is enabled
+	;;
+(p15)	ssm psr.i	// restore psr.i
+	adds r3=8,r2	// set up second base pointer for SAVE_REST
+	;;
+	alloc r14=ar.pfs,0,0,1,0	// must be first in insn group
+	mov out0=ar.ec
+	;;
+	SAVE_REST
+	;;
+	br.call.sptk.few rp=ia64_illegal_op_fault
+	;;
+	alloc r14=ar.pfs,0,0,3,0	// must be first in insn group
+	mov out0=r9
+	mov out1=r10
+	mov out2=r11
+	movl r15=ia64_leave_kernel
+	;;
+	mov rp=r15
+	mov b6=r8
+	;;
+	cmp.ne p6,p0=0,r8
+(p6)	br.call.dpnt b6¶		// call returns to ia64_leave_kernel
+	br.sptk ia64_leave_kernel
+
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x4000 Entry 16 (size 64 bundles) Reserved
@@ -909,7 +961,16 @@
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x5400 Entry 24 (size 16 bundles) General Exception (5,32,34,36,38,39)
-	FAULT(24)
+	mov r16=cr.isr
+	mov r31=pr
+	rsm psr.dt		// avoid nested faults due to TLB misses...
+	;;
+	srlz.d			// ensure everyone knows psr.dt is off...
+	cmp4.eq p6,p0=0,r16
+(p6)	br.sptk dispatch_illegal_op_fault
+	;;
+	mov r19$		// fault number
+	br.cond.sptk.many dispatch_to_fault_handler
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
diff -urN linux-davidm/arch/ia64/kernel/minstate.h linux-2.4.0-test1-lia/arch/ia64/kernel/minstate.h
--- linux-davidm/arch/ia64/kernel/minstate.h	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/minstate.h	Thu Jun  1 01:03:59 2000
@@ -69,7 +69,7 @@
 (p7)	mov rARBSPSTORE=ar.bspstore;			/* save ar.bspstore */			  \
 (p7)	dep rKRBS=-1,rKRBS,61,3;			/* compute kernel virtual addr of RBS */  \
 	;;											  \
-(pKern)	addl r1\x16-IA64_PT_REGS_SIZE,r1;	/* if in kernel mode, use sp (r12) */		  \
+(pKern)	addl r1=-IA64_PT_REGS_SIZE,r1;		/* if in kernel mode, use sp (r12) */		  \
 (p7)	mov ar.bspstore=rKRBS;			/* switch to kernel RBS */			  \
 	;;											  \
 (p7)	mov r18=ar.bsp;										  \
diff -urN linux-davidm/arch/ia64/kernel/pal.S linux-2.4.0-test1-lia/arch/ia64/kernel/pal.S
--- linux-davidm/arch/ia64/kernel/pal.S	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/pal.S	Thu Jun  1 01:04:13 2000
@@ -5,9 +5,14 @@
  * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
  * Copyright (C) 1999-2000 David Mosberger <davidm@hpl.hp.com>
+ * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 05/22/2000 eranian Added support for stacked register calls
+ * 05/24/2000 eranian Added support for physical mode static calls
  */
 
 #include <asm/asmmacro.h>
+#include <asm/processor.h>
 
 	.text
 	.psr abi64
@@ -83,3 +88,108 @@
 	srlz.d				// seralize restoration of psr.l
 	br.ret.sptk.few	b0
 END(ia64_pal_call_static)
+
+/*
+ * Make a PAL call using the stacked registers calling convention.
+ *
+ * Inputs:
+ * 	in0         Index of PAL service
+ * 	in2 - in3   Remaning PAL arguments
+ */
+GLOBAL_ENTRY(ia64_pal_call_stacked)
+	UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5))
+	alloc	loc1 = ar.pfs,5,4,87,0
+	movl	loc2 = pal_entry_point
+
+	mov	r28  = in0		// Index MUST be copied to r28
+	mov	out0 = in0		// AND in0 of PAL function
+	mov	loc0 = rp
+	.body
+	;;
+	ld8	loc2 = [loc2]		// loc2 <- entry point
+	mov	out1 = in1
+	mov	out2 = in2
+	mov	out3 = in3
+	mov	loc3 = psr
+	;;
+	rsm	psr.i
+	mov	b7 = loc2
+	;; 
+	br.call.sptk.many rp·		// now make the call
+.ret2:
+	mov	psr.l  = loc3
+	mov	ar.pfs = loc1
+	mov	rp = loc0
+	;;
+	srlz.d				// serialize restoration of psr.l
+	br.ret.sptk.few	b0
+END(ia64_pal_call_stacked)
+
+/*
+ * Make a physical mode PAL call using the static registers calling convention.
+ *
+ * Inputs:
+ * 	in0         Index of PAL service
+ * 	in2 - in3   Remaning PAL arguments
+ *
+ * PSR_DB, PSR_LP, PSR_TB, PSR_ID, PSR_DA are never set by the kernel.
+ * So we don't need to clear them.
+ */
+#define PAL_PSR_BITS_TO_CLEAR						\
+	(IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_RT |		\
+	 IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED |	\
+	 IA64_PSR_DFL | IA64_PSR_DFH)
+
+#define PAL_PSR_BITS_TO_SET							\
+	(IA64_PSR_BN)
+
+
+GLOBAL_ENTRY(ia64_pal_call_phys_static)
+	UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(6))
+	alloc	loc1 = ar.pfs,6,90,0,0
+	movl	loc2 = pal_entry_point
+1:	{
+	  mov	r28  = in0		// copy procedure index
+	  mov	r8   = ip		// save ip to compute branch
+	  mov	loc0 = rp		// save rp
+	}
+	.body
+	;;
+	ld8	loc2 = [loc2]		// loc2 <- entry point
+	mov	r29  = in1		// first argument
+	mov	r30  = in2		// copy arg2
+	mov	r31  = in3		// copy arg3
+	;;
+	mov	loc3 = psr		// save psr
+	adds	r8   = .ret4-1b,r8	// calculate return address for call
+	;; 
+	mov loc4=ar.rsc			// save RSE configuration
+	dep.z loc2=loc2,0,61		// convert pal entry point to physical
+	dep.z r8=r8,0,61		// convert rp to physical
+	;;
+	mov b7 = loc2			// install target to branch reg
+	mov ar.rsc=r0			// put RSE in enforced lazy, LE mode
+	movl r16=PAL_PSR_BITS_TO_CLEAR
+	movl r17=PAL_PSR_BITS_TO_SET
+	;;
+	or loc3=loc3,r17		// add in psr the bits to set
+	;;
+	andcm r16=loc3,r16		// removes bits to clear from psr
+	br.call.sptk.few rp=ia64_switch_mode
+.ret3:
+	mov rp = r8			// install return address (physical)
+	br.cond.sptk.few b7
+.ret4:
+	mov ar.rsc=r0			// put RSE in enforced lazy, LE mode
+	mov r16=loc3			// r16= original psr
+	br.call.sptk.few rp=ia64_switch_mode // return to virtual mode
+
+.ret5:	mov	psr.l = loc3		// restore init PSR
+
+	mov	ar.pfs = loc1
+	mov	rp = loc0
+	;;
+	mov ar.rsc=loc4			// restore RSE configuration
+	srlz.d				// seralize restoration of psr.l
+	br.ret.sptk.few	b0
+END(ia64_pal_call_phys_static)
diff -urN linux-davidm/arch/ia64/kernel/palinfo.c linux-2.4.0-test1-lia/arch/ia64/kernel/palinfo.c
--- linux-davidm/arch/ia64/kernel/palinfo.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/palinfo.c	Thu Jun  1 01:04:23 2000
@@ -0,0 +1,780 @@
+/*
+ * palinfo.c
+ *
+ * Prints processor specific information reported by PAL.
+ * This code is based on specification of PAL as of the
+ * Intel IA-64 Architecture Software Developer's Manual v1.0.
+ *
+ * 
+ * Copyright (C) 2000 Hewlett-Packard Co
+ * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
+ * 
+ * 05/26/2000	S.Eranian	initial release
+ *
+ * ISSUES:
+ *	- because of some PAL bugs, some calls return invalid results or
+ *	  are empty for now.
+ *	- remove hack to avoid problem with <= 256M RAM for itr.
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+
+#include <asm/pal.h>
+#include <asm/sal.h>
+#include <asm/efi.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+
+/*
+ * Hope to get rid of these in a near future
+*/
+#define IA64_PAL_VERSION_BUG		1
+
+#define PALINFO_VERSION "0.1"
+
+typedef int (*palinfo_func_t)(char*);
+
+typedef struct {
+	const char		*name;		/* name of the proc entry */
+	palinfo_func_t		proc_read;	/* function to call for reading */
+	struct proc_dir_entry	*entry;		/* registered entry (removal) */
+} palinfo_entry_t;
+
+static struct proc_dir_entry *palinfo_dir;
+
+/*
+ *  A bunch of string array to get pretty printing
+ */
+
+static char *cache_types[] = {
+	"",			/* not used */
+	"Instruction",
+	"Data",
+	"Data/Instruction"	/* unified */
+};
+
+static const char *cache_mattrib[]={
+	"WriteThrough",
+	"WriteBack",
+	"",		/* reserved */
+	""		/* reserved */
+};
+
+static const char *cache_st_hints[]={
+	"Temporal, level 1",
+	"Reserved",
+	"Reserved",
+	"Non-temporal, all levels",
+	"Reserved",
+	"Reserved",
+	"Reserved",	
+	"Reserved"
+};
+
+static const char *cache_ld_hints[]={
+	"Temporal, level 1",
+	"Non-temporal, level 1",
+	"Reserved",
+	"Non-temporal, all levels",
+	"Reserved",
+	"Reserved",
+	"Reserved",	
+	"Reserved"
+};
+
+static const char *rse_hints[]={
+	"enforced lazy",
+	"eager stores",
+	"eager loads",
+	"eager loads and stores"
+};
+
+#define RSE_HINTS_COUNT (sizeof(rse_hints)/sizeof(const char *))
+
+/*
+ * The current resvision of the Volume 2 of 
+ * IA-64 Architecture Software Developer's Manual is wrong.
+ * Table 4-10 has invalid information concerning the ma field:
+ * Correct table is:
+ *      bit 0 - 001 - UC
+ *      bit 4 - 100 - UC
+ *      bit 5 - 101 - UCE
+ *      bit 6 - 110 - WC
+ *      bit 7 - 111 - NatPage 
+ */
+static const char *mem_attrib[]={
+	"Write Back (WB)",		/* 000 */
+	"Uncacheable (UC)",		/* 001 */
+	"Reserved",			/* 010 */
+	"Reserved",			/* 011 */
+	"Uncacheable (UC)",		/* 100 */
+	"Uncacheable Exported (UCE)",	/* 101 */
+	"Write Coalescing (WC)",	/* 110 */
+	"NaTPage"			/* 111 */
+};
+
+
+
+/*
+ * Allocate a buffer suitable for calling PAL code in Virtual mode
+ *
+ * The documentation (PAL2.6) requires thius buffer to have a pinned
+ * translation to avoid any DTLB faults. For this reason we allocate
+ * a page (large enough to hold any possible reply) and use a DTC
+ * to hold the translation during the call. A call the free_palbuffer()
+ * is required to release ALL resources (page + translation).
+ *
+ * The size of the page allocated is based on the PAGE_SIZE defined
+ * at compile time for the kernel, i.e.  >= 4Kb.
+ *
+ * Return: a pointer to the newly allocated page (virtual address)
+ */
+static void *
+get_palcall_buffer(void)
+{
+	void *tmp;
+
+	tmp = (void *)__get_free_page(GFP_KERNEL);
+	if (tmp = 0) {
+		printk(KERN_ERR "%s: can't get a buffer page\n", __FUNCTION__);
+	} else if ( ((u64)tmp - PAGE_OFFSET) > (1<<_PAGE_SIZE_256M) )  { /* XXX: temporary hack */
+		unsigned long flags;
+
+		/* PSR.ic must be zero to insert new DTR */
+		ia64_clear_ic(flags);
+
+		/*
+		 * we  only insert of DTR
+		 *
+		 * XXX: we need to figure out a way to "allocate" TR(s) to avoid
+		 * conflicts. Maybe something in an include file like pgtable.h
+		 * page.h or processor.h
+		 *
+		 * ITR0/DTR0: used for kernel code/data
+		 * ITR1/DTR1: used by HP simulator
+		 * ITR2/DTR2: used to map PAL code
+		 */
+		ia64_itr(0x2, 3, (u64)tmp,
+			 pte_val(mk_pte_phys(__pa(tmp), __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RW))), PAGE_SHIFT);
+
+		ia64_srlz_d ();
+
+		__restore_flags(flags);	
+	}
+
+	return tmp;
+}
+
+/*
+ * Free a palcall buffer allocated with the previous call
+ *
+ * The translation is also purged.
+ */
+static void
+free_palcall_buffer(void *addr)
+{
+	__free_page(addr);
+	ia64_ptr(0x2, (u64)addr, PAGE_SHIFT);
+	ia64_srlz_d ();
+}
+
+/*
+ * Take a 64bit vector and produces a string such that
+ * if bit n is set then 2^n in clear text is generated. The adjustment
+ * to the right unit is also done.
+ *
+ * Input:
+ *	- a pointer to a buffer to hold the string
+ * 	- a 64-bit vector
+ * Ouput:
+ *	- a pointer to the end of the buffer
+ *
+ */
+static char *
+bitvector_process(char *p, u64 vector)
+{
+	int i,j;
+	const char *units[]={ "", "K", "M", "G", "T" };
+
+	for (i=0, j=0; i < 64; i++ , j=i/10) {
+		if (vector & 0x1) {
+			p += sprintf(p, "%d%s ", 1 << (i-j*10), units[j]);
+		}
+		vector >>= 1;
+	}
+	return p;
+}
+
+/*
+ * Take a 64bit vector and produces a string such that
+ * if bit n is set then register n is present. The function
+ * takes into account consecutive registers and prints out ranges.
+ *
+ * Input:
+ *	- a pointer to a buffer to hold the string
+ * 	- a 64-bit vector
+ * Ouput:
+ *	- a pointer to the end of the buffer
+ *
+ */
+static char *
+bitregister_process(char *p, u64 *reg_info, int max)
+{
+	int i, begin, skip = 0;
+	u64 value = reg_info[0];
+
+	value >>= i = begin = ffs(value) - 1;
+
+	for(; i < max; i++ ) {
+
+		if (i != 0 && (i%64) = 0) value = *++reg_info;
+
+		if ((value & 0x1) = 0 && skip = 0) {
+			if (begin  <= i - 2) 
+				p += sprintf(p, "%d-%d ", begin, i-1);
+			else
+				p += sprintf(p, "%d ", i-1);
+			skip  = 1;
+			begin = -1;
+		} else if ((value & 0x1) && skip = 1) {
+			skip = 0;
+			begin = i;
+		}
+		value >>=1;
+	}
+	if (begin > -1) {
+		if (begin < 127) 
+			p += sprintf(p, "%d-127", begin);
+		else
+			p += sprintf(p, "127");
+	}
+
+	return p;
+}
+
+static int
+power_info(char *page)
+{
+	s64 status;
+	char *p = page;
+	pal_power_mgmt_info_u_t *halt_info;
+	int i;
+
+	halt_info = get_palcall_buffer();
+	if (halt_info = 0) return 0;
+
+	status = ia64_pal_halt_info(halt_info);
+	if (status != 0) {
+		free_palcall_buffer(halt_info);
+		return 0;
+	}
+
+	for (i=0; i < 8 ; i++ ) {
+		if (halt_info[i].pal_power_mgmt_info_s.im = 1) {
+			p += sprintf(p,	"Power level %d:\n" \
+					"\tentry_latency       : %d cycles\n" \
+				 	"\texit_latency        : %d cycles\n" \
+					"\tpower consumption   : %d mW\n" \
+					"\tCache+TLB coherency : %s\n", i,
+				halt_info[i].pal_power_mgmt_info_s.entry_latency,
+				halt_info[i].pal_power_mgmt_info_s.exit_latency,
+				halt_info[i].pal_power_mgmt_info_s.power_consumption,
+				halt_info[i].pal_power_mgmt_info_s.co ? "Yes" : "No");
+		} else {
+			p += sprintf(p,"Power level %d: not implemented\n",i);
+		}
+	}
+
+	free_palcall_buffer(halt_info);
+
+	return p - page;
+}
+
+static int 
+cache_info(char *page)
+{
+	char *p = page;
+	u64 levels, unique_caches;
+	pal_cache_config_info_t cci;
+	int i,j, k;
+	s64 status;
+
+	if ((status=ia64_pal_cache_summary(&levels, &unique_caches)) != 0) {
+			printk("ia64_pal_cache_summary=%ld\n", status);
+			return 0;
+	}
+
+	p += sprintf(p, "Cache levels  : %ld\n" \
+			"Unique caches : %ld\n\n",
+			levels,
+			unique_caches);
+
+	for (i=0; i < levels; i++) {
+
+		for (j=2; j >0 ; j--) {
+
+			/* even without unification some level may not be present */
+			if ((status=ia64_pal_cache_config_info(i,j, &cci)) != 0) {
+				continue;
+			}
+			p += sprintf(p, "%s Cache level %d:\n" \
+					"\tSize           : %ld bytes\n" \
+					"\tAttributes     : ",
+					cache_types[j+cci.pcci_unified], i+1,
+					cci.pcci_cache_size);
+
+			if (cci.pcci_unified) p += sprintf(p, "Unified ");
+
+			p += sprintf(p, "%s\n", cache_mattrib[cci.pcci_cache_attr]);
+
+			p += sprintf(p, "\tAssociativity  : %d\n" \
+					"\tLine size      : %d bytes\n" \
+					"\tStride         : %d bytes\n",
+					cci.pcci_assoc,
+					1<<cci.pcci_line_size,
+					1<<cci.pcci_stride);
+			if (j = 1)
+				p += sprintf(p, "\tStore latency  : N/A\n");
+			else
+				p += sprintf(p, "\tStore latency  : %d cycle(s)\n",
+						cci.pcci_st_latency);
+
+			p += sprintf(p, "\tLoad latency   : %d cycle(s)\n" \
+					"\tStore hints    : ",
+					cci.pcci_ld_latency);
+
+			for(k=0; k < 8; k++ ) {
+				if ( cci.pcci_st_hints & 0x1) p += sprintf(p, "[%s]", cache_st_hints[k]);
+				cci.pcci_st_hints >>=1; 
+			}
+			p += sprintf(p, "\n\tLoad hints     : ");
+
+			for(k=0; k < 8; k++ ) {
+				if ( cci.pcci_ld_hints & 0x1) p += sprintf(p, "[%s]", cache_ld_hints[k]);
+				cci.pcci_ld_hints >>=1; 
+			}
+			p += sprintf(p, "\n\tAlias boundary : %d byte(s)\n" \
+					"\tTag LSB        : %d\n" \
+					"\tTag MSB        : %d\n",
+					1<<cci.pcci_alias_boundary,
+					cci.pcci_tag_lsb,
+					cci.pcci_tag_msb);
+
+			/* when unified, data(j=2) is enough */
+			if (cci.pcci_unified) break;
+		}
+	}
+	return p - page;
+}
+
+
+static int
+vm_info(char *page)
+{
+	char *p = page;
+	u64 tr_pages =0, vw_pages=0, tc_pages;
+	u64 attrib;
+	pal_vm_info_1_u_t vm_info_1;
+	pal_vm_info_2_u_t vm_info_2;
+	pal_tc_info_u_t	tc_info;
+	ia64_ptce_info_t ptce;
+	int i, j;
+	s64 status;
+
+	if ((status=ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) !=0) {
+		printk("ia64_pal_vm_summary=%ld\n", status);
+		return 0;
+	}
+
+
+	p += sprintf(p, "Physical Address Space         : %d bits\n" \
+			"Virtual Address Space          : %d bits\n" \
+			"Protection Key Registers(PKR)  : %d\n" \
+			"Implemented bits in PKR.key    : %d\n" \
+			"Hash Tag ID                    : 0x%x\n" \
+			"Size of RR.rid                 : %d\n",
+			vm_info_1.pal_vm_info_1_s.phys_add_size,
+			vm_info_2.pal_vm_info_2_s.impl_va_msb+1,
+			vm_info_1.pal_vm_info_1_s.max_pkr+1,
+			vm_info_1.pal_vm_info_1_s.key_size,
+			vm_info_1.pal_vm_info_1_s.hash_tag_id,
+			vm_info_2.pal_vm_info_2_s.rid_size);
+
+	if (ia64_pal_mem_attrib(&attrib) != 0) return 0;
+
+	p += sprintf(p, "Supported memory attributes    : %s\n", mem_attrib[attrib&0x7]);
+
+	if ((status=ia64_pal_vm_page_size(&tr_pages, &vw_pages)) !=0) {
+		printk("ia64_pal_vm_page_size=%ld\n", status);
+		return 0;
+	}
+
+	p += sprintf(p, "\nTLB walker                     : %s implemented\n" \
+			"Number of DTR                  : %d\n" \
+			"Number of ITR                  : %d\n" \
+			"TLB insertable page sizes      : ",
+			vm_info_1.pal_vm_info_1_s.vw ? "\b":"not",
+			vm_info_1.pal_vm_info_1_s.max_dtr_entry+1,
+			vm_info_1.pal_vm_info_1_s.max_itr_entry+1);
+
+
+	p = bitvector_process(p, tr_pages);
+
+	p += sprintf(p, "\nTLB purgeable page sizes       : ");
+
+	p = bitvector_process(p, vw_pages);
+
+	if ((status=ia64_get_ptce(&ptce)) != 0) {
+		printk("ia64_get_ptce=%ld\n",status);
+		return 0;
+	}
+
+	p += sprintf(p, "\nPurge base address             : 0x%016lx\n" \
+			"Purge outer loop count         : %d\n" \
+			"Purge inner loop count         : %d\n" \
+			"Purge outer loop stride        : %d\n" \
+			"Purge inner loop stride        : %d\n",
+			ptce.base,
+			ptce.count[0],
+			ptce.count[1],
+			ptce.stride[0],
+			ptce.stride[1]);
+
+	p += sprintf(p, "TC Levels                      : %d\n" \
+			"Unique TC(s)                   : %d\n", 
+			vm_info_1.pal_vm_info_1_s.num_tc_levels,
+			vm_info_1.pal_vm_info_1_s.max_unique_tcs);
+
+	for(i=0; i < vm_info_1.pal_vm_info_1_s.num_tc_levels; i++) {
+		for (j=2; j>0 ; j--) {
+			tc_pages = 0; /* just in case */
+
+		
+			/* even without unification, some levels may not be present */
+			if ((status=ia64_pal_vm_info(i,j, &tc_info, &tc_pages)) != 0) {
+				continue;
+			}
+
+			p += sprintf(p, "\n%s Translation Cache Level %d:\n" \
+					"\tHash sets           : %d\n" \
+					"\tAssociativity       : %d\n" \
+					"\tNumber of entries   : %d\n" \
+					"\tFlags               : ",
+					cache_types[j+tc_info.tc_unified], i+1,
+					tc_info.tc_num_sets,
+					tc_info.tc_associativity,
+					tc_info.tc_num_entries);
+
+			if (tc_info.tc_pf) p += sprintf(p, "PreferredPageSizeOptimized ");
+			if (tc_info.tc_unified) p += sprintf(p, "Unified ");
+			if (tc_info.tc_reduce_tr) p += sprintf(p, "TCReduction");
+
+			p += sprintf(p, "\n\tSupported page sizes: ");
+
+			p = bitvector_process(p, tc_pages);
+
+			/* when unified date (j=2) is enough */
+			if (tc_info.tc_unified) break;
+		}
+	}
+	p += sprintf(p, "\n");
+
+	return p - page;	
+}
+
+
+static int
+register_info(char *page)
+{
+	char *p = page;
+	u64 reg_info[2];
+	u64 info;
+	u64 phys_stacked;
+	pal_hints_u_t hints;
+	u64 iregs, dregs;
+	char *info_type[]={
+		"Implemented AR(s)",
+		"AR(s) with read side-effects",
+		"Implemented CR(s)",
+		"CR(s) with read side-effects",
+	};
+
+	for(info=0; info < 4; info++) {
+
+		if (ia64_pal_register_info(info, &reg_info[0], &reg_info[1]) != 0) return 0;
+
+	 	p += sprintf(p, "%-32s : ", info_type[info]);
+
+		p = bitregister_process(p, reg_info, 128);
+
+		p += sprintf(p, "\n");
+	}
+
+	if (ia64_pal_rse_info(&phys_stacked, &hints) != 0) return 0;
+
+	p += sprintf(p, "RSE stacked physical registers   : %ld\n" \
+			"RSE load/store hints             : %ld (%s)\n",
+			phys_stacked,
+			hints.ph_data, 
+		     	hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(??)");
+
+	if (ia64_pal_debug_info(&iregs, &dregs)) return 0;
+
+	p += sprintf(p, "Instruction debug register pairs : %ld\n" \
+			"Data debug register pairs        : %ld\n",
+			iregs, dregs);
+
+	return p - page;
+}
+
+static const char *proc_features[]={
+	NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+	NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,
+	NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+	NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,
+	NULL,NULL,NULL,NULL,NULL,
+	"XIP,XPSR,XFS implemented",
+	"XR1-XR3 implemented",
+	"Disable dynamic predicate prediction",
+	"Disable processor physical number",
+	"Disable dynamic data cache prefetch",
+	"Disable dynamic inst cache prefetch",
+	"Disable dynamic branch prediction",
+	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+	"Disable BINIT on processor time-out",
+	"Disable dynamic power management (DPM)",
+	"Disable coherency", 
+	"Disable cache", 
+	"Enable CMCI promotion",
+	"Enable MCA to BINIT promotion",
+	"Enable MCA promotion",
+	"Enable BEER promotion"
+};
+
+	
+static int
+processor_info(char *page)
+{
+	char *p = page;
+	const char **v = proc_features;
+	u64 avail=1, status=1, control=1;
+	int i;
+	s64 ret;
+
+	/* must be in physical mode */
+	if ((ret=ia64_pal_proc_get_features(&avail, &status, &control)) != 0) return 0;
+
+	for(i=0; i < 64; i++, v++,avail >>=1, status >>=1, control >>=1) {
+		if ( ! *v ) continue;
+		p += sprintf(p, "%-40s : %s%s %s\n", *v, 
+				avail & 0x1 ? "" : "NotImpl",
+				avail & 0x1 ? (status & 0x1 ? "On" : "Off"): "",
+				avail & 0x1 ? (control & 0x1 ? "Ctrl" : "NoCtrl"): "");
+	}
+	return p - page;
+}
+
+/*
+ * physical mode call for PAL_VERSION is working fine.
+ * This function is meant to go away once PAL get fixed.
+ */
+static inline s64 
+ia64_pal_version_phys(pal_version_u_t *pal_min_version, pal_version_u_t *pal_cur_version) 
+{	
+	struct ia64_pal_retval iprv;
+	PAL_CALL_PHYS(iprv, PAL_VERSION, 0, 0, 0);
+	if (pal_min_version)
+		pal_min_version->pal_version_val = iprv.v0;
+	if (pal_cur_version)
+		pal_cur_version->pal_version_val = iprv.v1;
+	return iprv.status; 
+}
+
+static int
+version_info(char *page)
+{
+	s64 status;
+	pal_version_u_t min_ver, cur_ver;
+	char *p = page;
+
+#ifdef IA64_PAL_VERSION_BUG
+	/* The virtual mode call is buggy. But the physical mode call seems
+	 * to be ok. Until they fix virtual mode, we do physical.
+	 */
+	status = ia64_pal_version_phys(&min_ver, &cur_ver);
+#else
+	/* The system crashes if you enable this code with the wrong PAL 
+	 * code
+	 */
+	status = ia64_pal_version(&min_ver, &cur_ver);
+#endif
+	if (status != 0) return 0;
+
+	p += sprintf(p, "PAL_vendor     : 0x%x (min=0x%x)\n" \
+			"PAL_A revision : 0x%x (min=0x%x)\n" \
+			"PAL_A model    : 0x%x (min=0x%x)\n" \
+			"PAL_B mode     : 0x%x (min=0x%x)\n" \
+			"PAL_B revision : 0x%x (min=0x%x)\n",
+	     		cur_ver.pal_version_s.pv_pal_vendor,
+	     		min_ver.pal_version_s.pv_pal_vendor,
+	     		cur_ver.pal_version_s.pv_pal_a_rev,
+	     		cur_ver.pal_version_s.pv_pal_a_rev,
+	     		cur_ver.pal_version_s.pv_pal_a_model,
+	     		min_ver.pal_version_s.pv_pal_a_model,
+	     		cur_ver.pal_version_s.pv_pal_b_rev,
+	     		min_ver.pal_version_s.pv_pal_b_rev,
+	     		cur_ver.pal_version_s.pv_pal_b_model,
+	     		min_ver.pal_version_s.pv_pal_b_model);
+
+	return p - page;
+}
+
+static int
+perfmon_info(char *page)
+{
+	char *p = page;
+	u64 *pm_buffer;
+	pal_perf_mon_info_u_t pm_info;
+
+	pm_buffer = (u64 *)get_palcall_buffer();
+	if (pm_buffer = 0) return 0;
+
+	if (ia64_pal_perf_mon_info(pm_buffer, &pm_info) != 0) {
+		free_palcall_buffer(pm_buffer);
+		return 0;
+	}
+
+#ifdef IA64_PAL_PERF_MON_INFO_BUG
+	pm_buffer[5]=0x3;
+	pm_info.pal_perf_mon_info_s.cycles  = 0x12;
+	pm_info.pal_perf_mon_info_s.retired = 0x08;
+#endif
+
+	p += sprintf(p, "PMC/PMD pairs                 : %d\n" \
+			"Counter width                 : %d bits\n" \
+			"Cycle event number            : %d\n" \
+			"Retired event number          : %d\n" \
+			"Implemented PMC               : ", 
+			pm_info.pal_perf_mon_info_s.generic,
+			pm_info.pal_perf_mon_info_s.width,
+			pm_info.pal_perf_mon_info_s.cycles,
+			pm_info.pal_perf_mon_info_s.retired);
+
+	p = bitregister_process(p, pm_buffer, 256);
+
+	p += sprintf(p, "\nImplemented PMD               : ");
+	
+	p = bitregister_process(p, pm_buffer+4, 256);
+
+	p += sprintf(p, "\nCycles count capable          : ");
+	
+	p = bitregister_process(p, pm_buffer+8, 256);
+
+	p += sprintf(p, "\nRetired bundles count capable : ");
+	
+	p = bitregister_process(p, pm_buffer+12, 256);
+
+	p += sprintf(p, "\n");
+
+	free_palcall_buffer(pm_buffer);
+
+	return p - page;
+}
+
+static int
+frequency_info(char *page)
+{
+	char *p = page;
+	struct pal_freq_ratio proc, itc, bus;
+	u64 base;
+
+	if (ia64_pal_freq_base(&base) = -1)
+		p += sprintf(p, "Output clock            : not implemented\n"); 
+	else
+		p += sprintf(p, "Output clock            : %ld ticks/s\n", base);
+
+	if (ia64_pal_freq_ratios(&proc, &bus, &itc) != 0) return 0;
+
+	p += sprintf(p, "Processor/Clock ratio   : %ld/%ld\n" \
+			"Bus/Clock ratio         : %ld/%ld\n" \
+			"ITC/Clock ratio         : %ld/%ld\n",
+			proc.num, proc.den,
+			bus.num, bus.den,
+			itc.num, itc.den);
+
+	return p - page;
+}
+
+
+/*
+ * Entry point routine: all calls go trhough this function
+ */
+static int
+palinfo_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	palinfo_func_t info = (palinfo_func_t)data;
+        int len = info(page);
+
+        if (len <= off+count) *eof = 1;
+
+        *start = page + off;
+        len   -= off;
+
+        if (len>count) len = count;
+        if (len<0) len = 0;
+
+        return len;
+}
+
+/*
+ * List names,function pairs for every entry in /proc/palinfo
+ * Must be terminated with the NULL,NULL entry.
+ */
+static palinfo_entry_t palinfo_entries[]={
+	{ "version_info",	version_info, },
+	{ "vm_info", 		vm_info, },
+	{ "cache_info",		cache_info, },
+	{ "power_info",		power_info, },
+	{ "register_info",	register_info, },
+	{ "processor_info",	processor_info, },
+	{ "perfmon_info",	perfmon_info, },
+	{ "frequency_info",	frequency_info, },
+	{ NULL,			NULL,}
+};
+
+
+static int __init 
+palinfo_init(void)
+{
+	palinfo_entry_t *p;
+
+	printk(KERN_INFO "PAL Information Facility v%s\n", PALINFO_VERSION);
+
+	palinfo_dir = create_proc_entry("palinfo",  S_IFDIR | S_IRUGO | S_IXUGO, NULL);
+
+	for (p = palinfo_entries; p->name ; p++){
+		p->entry = create_proc_read_entry (p->name, 0, palinfo_dir, 
+						   palinfo_read_entry, p->proc_read);
+	}
+
+	return 0;
+}
+
+static int __exit
+palinfo_exit(void)
+{
+	palinfo_entry_t *p;
+
+	for (p = palinfo_entries; p->name ; p++){
+		remove_proc_entry (p->name, palinfo_dir);
+	}
+	remove_proc_entry ("palinfo", 0);
+
+	return 0;
+}
+
+module_init(palinfo_init);
+module_exit(palinfo_exit);
diff -urN linux-davidm/arch/ia64/kernel/setup.c linux-2.4.0-test1-lia/arch/ia64/kernel/setup.c
--- linux-davidm/arch/ia64/kernel/setup.c	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/setup.c	Thu Jun  1 01:04:49 2000
@@ -108,6 +108,8 @@
 {
 	unsigned long max_pfn, bootmap_start, bootmap_size;
 
+	unw_init();
+
 	/*
 	 * The secondary bootstrap loader passes us the boot
 	 * parameters at the beginning of the ZERO_PAGE, so let's
@@ -155,10 +157,8 @@
 #ifdef CONFIG_SMP
 	bootstrap_processor = hard_smp_processor_id();
 	current->processor = bootstrap_processor;
-#else
-	cpu_init();
-	identify_cpu(&cpu_data[0]);
 #endif
+	cpu_init();	/* initialize the bootstrap CPU */
 
 	if (efi.acpi) {
 		/* Parse the ACPI tables */
@@ -270,11 +270,14 @@
 			u64 features;
 		} field;
 	} cpuid;
+	pal_vm_info_1_u_t vm1;
+	pal_vm_info_2_u_t vm2;
+	pal_status_t status;
+	unsigned long impl_va_msb = 50, phys_addr_size = 44;	/* Itanium defaults */
 	int i;
 
-	for (i = 0; i < 5; ++i) {
+	for (i = 0; i < 5; ++i)
 		cpuid.bits[i] = ia64_get_cpuid(i);
-	}
 
 	memset(c, 0, sizeof(struct cpuinfo_ia64));
 
@@ -287,6 +290,24 @@
 	c->archrev = cpuid.field.archrev;
 	c->features = cpuid.field.features;
 
+	status = ia64_pal_vm_summary(&vm1, &vm2);
+	if (status = PAL_STATUS_SUCCESS) {
+#if 1
+		/*
+		 * XXX the current PAL code returns IMPL_VA_MSB=60, which is dead-wrong.
+		 * --davidm 00/05/26
+		 s*/
+		impl_va_msb = 50;
+#else
+		impl_va_msb = vm2.pal_vm_info_2_s.impl_va_msb;
+#endif
+		phys_addr_size = vm1.pal_vm_info_1_s.phys_add_size;
+	}
+	printk("processor implements %lu virtual and %lu physical address bits\n",
+	       impl_va_msb + 1, phys_addr_size);
+	c->unimpl_va_mask = ~((7L<<61) | ((1L << (impl_va_msb + 1)) - 1));
+	c->unimpl_pa_mask = ~((1L<<63) | ((1L << phys_addr_size) - 1));
+
 #ifdef CONFIG_IA64_SOFTSDV_HACKS
 	/* BUG: SoftSDV doesn't support the cpuid registers. */
 	if (c->vendor[0] = '\0') 
@@ -301,6 +322,11 @@
 void
 cpu_init (void)
 {
+	extern void __init ia64_rid_init (void);
+	extern void __init ia64_tlb_init (void);
+
+	identify_cpu(&my_cpu_data);
+
 	/* Clear the stack memory reserved for pt_regs: */
 	memset(ia64_task_regs(current), 0, sizeof(struct pt_regs));
 
@@ -314,6 +340,14 @@
 	 */
 	ia64_set_dcr(IA64_DCR_DR | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_PP);
 	ia64_set_fpu_owner(0);		/* initialize ar.k5 */
+
 	atomic_inc(&init_mm.mm_count);
 	current->active_mm = &init_mm;
+
+	ia64_rid_init();
+	ia64_tlb_init();
+
+#ifdef CONFIG_SMP
+	normal_xtp();
+#endif
 }
diff -urN linux-davidm/arch/ia64/kernel/signal.c linux-2.4.0-test1-lia/arch/ia64/kernel/signal.c
--- linux-davidm/arch/ia64/kernel/signal.c	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/signal.c	Thu Jun  1 01:05:04 2000
@@ -71,8 +71,15 @@
 	 * pre-set the correct error code here to ensure that the right values
 	 * get saved in sigcontext by ia64_do_signal.
 	 */
-	pt->r8 = EINTR;
-	pt->r10 = -1;
+#ifdef CONFIG_IA32_SUPPORT
+        if (IS_IA32_PROCESS(pt)) {
+                pt->r8 = -EINTR;
+        } else
+#endif
+	{
+		pt->r8 = EINTR;
+		pt->r10 = -1;
+	}
 	while (1) {
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule();
@@ -138,7 +145,8 @@
 	return err;
 }
 
-int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+int
+copy_siginfo_to_user (siginfo_t *to, siginfo_t *from)
 {
 	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
 		return -EFAULT;
@@ -147,29 +155,32 @@
 	else {
 		int err;
 
-		/* If you change siginfo_t structure, please be sure
-		   this code is fixed accordingly.
-		   It should never copy any pad contained in the structure
-		   to avoid security leaks, but must copy the generic
-		   3 ints plus the relevant union member.  */
+		/*
+		 * If you change siginfo_t structure, please be sure
+		 * this code is fixed accordingly.  It should never
+		 * copy any pad contained in the structure to avoid
+		 * security leaks, but must copy the generic 3 ints
+		 * plus the relevant union member.
+		 */
 		err = __put_user(from->si_signo, &to->si_signo);
 		err |= __put_user(from->si_errno, &to->si_errno);
 		err |= __put_user((short)from->si_code, &to->si_code);
 		switch (from->si_code >> 16) {
-		case __SI_FAULT >> 16:
-		case __SI_POLL >> 16:
+		      case __SI_FAULT >> 16:
+			err |= __put_user(from->si_isr, &to->si_isr);
+		      case __SI_POLL >> 16:
 			err |= __put_user(from->si_addr, &to->si_addr);
 			err |= __put_user(from->si_imm, &to->si_imm);
 			break;
-		case __SI_CHLD >> 16:
+		      case __SI_CHLD >> 16:
 			err |= __put_user(from->si_utime, &to->si_utime);
 			err |= __put_user(from->si_stime, &to->si_stime);
 			err |= __put_user(from->si_status, &to->si_status);
-		default:
+		      default:
 			err |= __put_user(from->si_uid, &to->si_uid);
 			err |= __put_user(from->si_pid, &to->si_pid);
 			break;
-		/* case __SI_RT: This is not generated by the kernel as of now.  */
+		      /* case __SI_RT: This is not generated by the kernel as of now.  */
 		}
 		return err;
 	}
@@ -563,6 +574,11 @@
 			      case ERESTARTSYS:
 				if ((ka->sa.sa_flags & SA_RESTART) = 0) {
 			      case ERESTARTNOHAND:
+#ifdef CONFIG_IA32_SUPPORT
+					if (IS_IA32_PROCESS(pt))
+						pt->r8 = -EINTR;
+					else
+#endif
 					pt->r8 = EINTR;
 					/* note: pt->r10 is already -1 */
 					break;
diff -urN linux-davidm/arch/ia64/kernel/smp.c linux-2.4.0-test1-lia/arch/ia64/kernel/smp.c
--- linux-davidm/arch/ia64/kernel/smp.c	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/smp.c	Thu Jun  1 01:06:05 2000
@@ -81,6 +81,7 @@
 #ifndef CONFIG_ITANIUM_PTCG
 # define IPI_FLUSH_TLB		3
 #endif	/*!CONFIG_ITANIUM_PTCG */
+#define IPI_KDB_INTERRUPT	4
 
 /*
  *	Setup routine for controlling SMP activation
@@ -245,6 +246,9 @@
 				start += (1UL << nbits);
 			} while (start < end);
 
+			ia64_insn_group_barrier();
+			ia64_srlz_i();			/* srlz.i implies srlz.d */
+
 			if (saved_rid != flush_rid) {
 				ia64_set_rr(flush_start, saved_rid);
 				ia64_srlz_d();
@@ -440,19 +444,6 @@
 	}
 }
 
-
-/*
- * Called by both boot and secondaries to move global data into
- * per-processor storage.
- */
-static inline void __init
-smp_store_cpu_info(int cpuid)
-{
-	struct cpuinfo_ia64 *c = &cpu_data[cpuid];
-
-	identify_cpu(c);
-}
-
 static inline void __init
 smp_calibrate_delay(int cpuid)
 {
@@ -521,16 +512,8 @@
 	extern void ia64_init_itm(void);
 	extern void ia64_cpu_local_tick(void);
 
-	ia64_set_dcr(IA64_DCR_DR | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_PP);
-	ia64_set_fpu_owner(0);	       
-	ia64_rid_init();		/* initialize region ids */
-
 	cpu_init();
-	__flush_tlb_all();
-
-	normal_xtp();
 
-	smp_store_cpu_info(smp_processor_id());
 	smp_setup_percpu_timer(smp_processor_id());
 
 	/* setup the CPU local timer tick */
@@ -658,16 +641,7 @@
 	/* Setup BSP mappings */
 	__cpu_number_map[bootstrap_processor] = 0;
 	__cpu_logical_map[0] = bootstrap_processor;
-	current->processor = bootstrap_processor;
 
-	/* Mark BSP booted and get active_mm context */
-	cpu_init();
-
-	/* reset XTP for interrupt routing */
-	normal_xtp();
-
-	/* And generate an entry in cpu_data */
-	smp_store_cpu_info(bootstrap_processor);
 	smp_calibrate_delay(smp_processor_id());
 #if 0
 	smp_tune_scheduling();
@@ -785,4 +759,3 @@
 	}
 
 }
-
diff -urN linux-davidm/arch/ia64/kernel/traps.c linux-2.4.0-test1-lia/arch/ia64/kernel/traps.c
--- linux-davidm/arch/ia64/kernel/traps.c	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/traps.c	Thu Jun  1 01:07:02 2000
@@ -36,6 +36,10 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 
+#ifdef CONFIG_KDB
+#include <linux/kdb.h>
+#endif
+
 #include <asm/ia32.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
@@ -89,6 +93,13 @@
 
 	printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err);
 
+#ifdef CONFIG_KDB
+	while (1) {
+                kdb(KDB_REASON_PANIC, 0, regs);
+                printk("Cant go anywhere from Panic!\n");
+	}
+#endif
+
 	show_regs(regs);
 
 	if (current->thread.flags & IA64_KERNEL_DEATH) {
@@ -361,6 +372,42 @@
 		}
 	}
 	return 0;
+}
+
+struct illegal_op_return {
+	unsigned long fkt, arg1, arg2, arg3;
+};
+
+struct illegal_op_return
+ia64_illegal_op_fault (unsigned long ec, unsigned long arg1, unsigned long arg2,
+		       unsigned long arg3, unsigned long arg4, unsigned long arg5,
+		       unsigned long arg6, unsigned long arg7, unsigned long stack)
+{
+	struct pt_regs *regs = (struct pt_regs *) &stack;
+	struct illegal_op_return rv;
+	struct siginfo si;
+	char buf[128];
+
+#ifdef CONFIG_IA64_BRL_EMU	
+	{
+		extern struct illegal_op_return ia64_emulate_brl (struct pt_regs *, unsigned long);
+
+		rv = ia64_emulate_brl(regs, ec);
+		if (rv.fkt != (unsigned long) -1)
+			return rv;
+	}
+#endif
+
+	sprintf(buf, "IA-64 Illegal operation fault");
+	die_if_kernel(buf, regs, 0);
+
+	memset(&si, 0, sizeof(si));
+	si.si_signo = SIGILL;
+	si.si_code = ILL_ILLOPC;
+	si.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
+	force_sig_info(SIGILL, &si, current);
+	rv.fkt = 0;
+	return rv;
 }
 
 void
diff -urN linux-davidm/arch/ia64/kernel/unaligned.c linux-2.4.0-test1-lia/arch/ia64/kernel/unaligned.c
--- linux-davidm/arch/ia64/kernel/unaligned.c	Fri Apr 21 15:21:24 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/unaligned.c	Thu Jun  1 01:07:40 2000
@@ -1,8 +1,8 @@
 /*
  * Architecture-specific unaligned trap handling.
  *
- * Copyright (C) 1999 Hewlett-Packard Co
- * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
+ * Copyright (C) 1999-2000 Hewlett-Packard Co
+ * Copyright (C) 1999-2000 Stephane Eranian <eranian@hpl.hp.com>
  */
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -1410,6 +1410,25 @@
 		die_if_kernel("Unaligned reference while in kernel\n", regs, 30);
 		/* NOT_REACHED */
 	}
+	/*
+	 * For now, we don't support user processes running big-endian
+	 * which do unaligned accesses
+	 */
+	if (ia64_psr(regs)->be) {
+		struct siginfo si;
+
+		printk(KERN_ERR "%s(%d): big-endian unaligned access %016lx (ip=%016lx) not "
+		       "yet supported\n",
+		       current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri);
+
+		si.si_signo = SIGBUS;
+		si.si_errno = 0;
+		si.si_code = BUS_ADRALN;
+		si.si_addr = (void *) ifa;
+		send_sig_info(SIGBUS, &si, current);
+		return;
+	}
+
 	if (current->thread.flags & IA64_THREAD_UAC_SIGBUS) {
 		struct siginfo si;
 
@@ -1417,7 +1436,7 @@
 		si.si_errno = 0;
 		si.si_code = BUS_ADRALN;
 		si.si_addr = (void *) ifa;
-		send_sig_info (SIGBUS, &si, current);
+		send_sig_info(SIGBUS, &si, current);
 		return;
 	}
 
diff -urN linux-davidm/arch/ia64/kernel/unwind.c linux-2.4.0-test1-lia/arch/ia64/kernel/unwind.c
--- linux-davidm/arch/ia64/kernel/unwind.c	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/unwind.c	Thu Jun  1 01:07:55 2000
@@ -2,6 +2,16 @@
  * Copyright (C) 1999-2000 Hewlett-Packard Co
  * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
  */
+/*
+ * SMP conventions:
+ *	o updates to the global unwind data (in structure "unw") are serialized
+ *	  by the unw.lock spinlock
+ *	o each unwind script has its own read-write lock; a thread must acquire
+ *	  a read lock before executing a script and must acquire a write lock
+ *	  before modifying a script
+ *	o if both the unw.lock spinlock and a script's read-write lock must be
+ *	  acquired, then the read-write lock must be acquired first.
+ */
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -11,6 +21,7 @@
 
 #ifdef CONFIG_IA64_NEW_UNWIND
 
+#include <asm/delay.h>
 #include <asm/ptrace.h>
 #include <asm/ptrace_offsets.h>
 #include <asm/rse.h>
@@ -32,202 +43,517 @@
  */
 #define UNWIND_TABLE_SORT_BUG
 
-#define UNW_DEBUG	1
+#define UNW_LOG_CACHE_SIZE	7	/* each unw_script is ~256 bytes in size */
+#define UNW_CACHE_SIZE		(1 << UNW_LOG_CACHE_SIZE)
+
+#define UNW_LOG_HASH_SIZE	(UNW_LOG_CACHE_SIZE + 1)
+#define UNW_HASH_SIZE		(1 << UNW_LOG_HASH_SIZE)
+
+#define UNW_DEBUG	0
+#define UNW_STATS	0	/* WARNING: this disabled interrupts for long time-spans!! */
 
 #if UNW_DEBUG
 # define dprintk(format...)	printk(format)
+# define inline
 #else
 # define dprintk(format...)
 #endif
 
+#if UNW_STATS
+# define STAT(x...)	x
+#else
+# define STAT(x...)
+#endif
+
 #define alloc_reg_state()	kmalloc(sizeof(struct unw_state_record), GFP_ATOMIC)
 #define free_reg_state(usr)	kfree(usr)
 
 typedef unsigned long unw_word;
-
-static const enum unw_register_index save_order[] = {
-	UNW_REG_RP, UNW_REG_PFS, UNW_REG_PSP, UNW_REG_PR,
-	UNW_REG_UNAT, UNW_REG_LC, UNW_REG_FPSR, UNW_REG_PRI_UNAT_GR
-};
+typedef unsigned char unw_hash_index_t;
 
 #define struct_offset(str,fld)	((char *)&((str *)NULL)->fld - (char *) 0)
 
-static unsigned short preg_index[UNW_NUM_REGS] = {
-	struct_offset(struct unw_frame_info, pri_unat)/8,	/* PRI_UNAT_GR */
-	struct_offset(struct unw_frame_info, pri_unat)/8,	/* PRI_UNAT_MEM */
-	struct_offset(struct unw_frame_info, pbsp)/8,
-	struct_offset(struct unw_frame_info, bspstore)/8,
-	struct_offset(struct unw_frame_info, pfs)/8,
-	struct_offset(struct unw_frame_info, rnat)/8,
-	struct_offset(struct unw_frame_info, psp)/8,
-	struct_offset(struct unw_frame_info, rp)/8,
-	struct_offset(struct unw_frame_info, r4)/8,
-	struct_offset(struct unw_frame_info, r5)/8,
-	struct_offset(struct unw_frame_info, r6)/8,
-	struct_offset(struct unw_frame_info, r7)/8,
-	struct_offset(struct unw_frame_info, unat)/8,
-	struct_offset(struct unw_frame_info, pr)/8,
-	struct_offset(struct unw_frame_info, lc)/8,
-	struct_offset(struct unw_frame_info, fpsr)/8,
-	struct_offset(struct unw_frame_info, b1)/8,
-	struct_offset(struct unw_frame_info, b2)/8,
-	struct_offset(struct unw_frame_info, b3)/8,
-	struct_offset(struct unw_frame_info, b4)/8,
-	struct_offset(struct unw_frame_info, b5)/8,
-	struct_offset(struct unw_frame_info, f2)/8,
-	struct_offset(struct unw_frame_info, f3)/8,
-	struct_offset(struct unw_frame_info, f4)/8,
-	struct_offset(struct unw_frame_info, f5)/8,
-	struct_offset(struct unw_frame_info, fr[16])/8,
-	struct_offset(struct unw_frame_info, fr[17])/8,
-	struct_offset(struct unw_frame_info, fr[18])/8,
-	struct_offset(struct unw_frame_info, fr[19])/8,
-	struct_offset(struct unw_frame_info, fr[20])/8,
-	struct_offset(struct unw_frame_info, fr[21])/8,
-	struct_offset(struct unw_frame_info, fr[22])/8,
-	struct_offset(struct unw_frame_info, fr[23])/8,
-	struct_offset(struct unw_frame_info, fr[24])/8,
-	struct_offset(struct unw_frame_info, fr[25])/8,
-	struct_offset(struct unw_frame_info, fr[26])/8,
-	struct_offset(struct unw_frame_info, fr[27])/8,
-	struct_offset(struct unw_frame_info, fr[28])/8,
-	struct_offset(struct unw_frame_info, fr[29])/8,
-	struct_offset(struct unw_frame_info, fr[30])/8,
-	struct_offset(struct unw_frame_info, fr[31])/8,
-};
+static struct {
+	struct unw_table *tables;
 
+	const unsigned char save_order[8];
+	/* Maps a preserved register index (preg_index) to corresponding switch_stack offset: */
+	unsigned short sw_off[sizeof(struct unw_frame_info) / 8];
+
+	unsigned short lru_head;
+	unsigned short lru_tail;
+	unsigned short preg_index[UNW_NUM_REGS];
+	struct unw_table kernel_table;
+
+	spinlock_t lock;
+	unw_hash_index_t hash[UNW_HASH_SIZE];
+	struct unw_script cache[UNW_CACHE_SIZE];
+
+# if UNW_DEBUG
+	const char *preg_name[UNW_NUM_REGS];
+# endif
+# if UNW_STATS
+	struct {
+		struct {
+			int lookups;
+			int hinted_hits;
+			int normal_hits;
+			int collision_chain_traversals;
+		} cache;
+		struct {
+			unsigned long build_time;
+			unsigned long run_time;
+			unsigned long parse_time;
+			int builds;
+			int news;
+			int collisions;
+			int runs;
+		} script;
+		struct {
+			unsigned long init_time;
+			unsigned long unwind_time;
+			int inits;
+			int unwinds;
+		} api;
+	} stat;
+# endif
+} unw = {
+	tables: &unw.kernel_table,
+	lock: SPIN_LOCK_UNLOCKED,
+	save_order: {
+		UNW_REG_RP, UNW_REG_PFS, UNW_REG_PSP, UNW_REG_PR,
+		UNW_REG_UNAT, UNW_REG_LC, UNW_REG_FPSR, UNW_REG_PRI_UNAT_GR
+	},
+	preg_index: {
+		struct_offset(struct unw_frame_info, pri_unat)/8,	/* PRI_UNAT_GR */
+		struct_offset(struct unw_frame_info, pri_unat)/8,	/* PRI_UNAT_MEM */
+		struct_offset(struct unw_frame_info, pbsp)/8,
+		struct_offset(struct unw_frame_info, bspstore)/8,
+		struct_offset(struct unw_frame_info, pfs)/8,
+		struct_offset(struct unw_frame_info, rnat)/8,
+		struct_offset(struct unw_frame_info, psp)/8,
+		struct_offset(struct unw_frame_info, rp)/8,
+		struct_offset(struct unw_frame_info, r4)/8,
+		struct_offset(struct unw_frame_info, r5)/8,
+		struct_offset(struct unw_frame_info, r6)/8,
+		struct_offset(struct unw_frame_info, r7)/8,
+		struct_offset(struct unw_frame_info, unat)/8,
+		struct_offset(struct unw_frame_info, pr)/8,
+		struct_offset(struct unw_frame_info, lc)/8,
+		struct_offset(struct unw_frame_info, fpsr)/8,
+		struct_offset(struct unw_frame_info, b1)/8,
+		struct_offset(struct unw_frame_info, b2)/8,
+		struct_offset(struct unw_frame_info, b3)/8,
+		struct_offset(struct unw_frame_info, b4)/8,
+		struct_offset(struct unw_frame_info, b5)/8,
+		struct_offset(struct unw_frame_info, f2)/8,
+		struct_offset(struct unw_frame_info, f3)/8,
+		struct_offset(struct unw_frame_info, f4)/8,
+		struct_offset(struct unw_frame_info, f5)/8,
+		struct_offset(struct unw_frame_info, fr[16 - 16])/8,
+		struct_offset(struct unw_frame_info, fr[17 - 16])/8,
+		struct_offset(struct unw_frame_info, fr[18 - 16])/8,
+		struct_offset(struct unw_frame_info, fr[19 - 16])/8,
+		struct_offset(struct unw_frame_info, fr[20 - 16])/8,
+		struct_offset(struct unw_frame_info, fr[21 - 16])/8,
+		struct_offset(struct unw_frame_info, fr[22 - 16])/8,
+		struct_offset(struct unw_frame_info, fr[23 - 16])/8,
+		struct_offset(struct unw_frame_info, fr[24 - 16])/8,
+		struct_offset(struct unw_frame_info, fr[25 - 16])/8,
+		struct_offset(struct unw_frame_info, fr[26 - 16])/8,
+		struct_offset(struct unw_frame_info, fr[27 - 16])/8,
+		struct_offset(struct unw_frame_info, fr[28 - 16])/8,
+		struct_offset(struct unw_frame_info, fr[29 - 16])/8,
+		struct_offset(struct unw_frame_info, fr[30 - 16])/8,
+		struct_offset(struct unw_frame_info, fr[31 - 16])/8,
+	},
+	hash : { [0 ... UNW_HASH_SIZE - 1] = -1 },
 #if UNW_DEBUG
-
-static const char *preg_name[UNW_NUM_REGS] = {
-	"pri_unat_gr", "pri_unat_mem", "bsp", "bspstore", "ar.pfs", "ar.rnat", "psp", "rp",
-	"r4", "r5", "r6", "r7",
-	"ar.unat", "pr", "ar.lc", "ar.fpsr",
-	"b1", "b2", "b3", "b4", "b5",
-	"f2", "f3", "f4", "f5",
-	"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
-	"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"
+	preg_name: {
+		"pri_unat_gr", "pri_unat_mem", "bsp", "bspstore", "ar.pfs", "ar.rnat", "psp", "rp",
+		"r4", "r5", "r6", "r7",
+		"ar.unat", "pr", "ar.lc", "ar.fpsr",
+		"b1", "b2", "b3", "b4", "b5",
+		"f2", "f3", "f4", "f5",
+		"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+		"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"
+	}
+#endif
 };
 
-#endif /* UNW_DEBUG */
-
-/* Maps a preserved register index (preg_index) into the corresponding switch_stack offset: */
-static unsigned short sw_offset[sizeof (struct unw_frame_info) / 8];
+\f
+/* Unwind accessors.  */
 
-static struct unw_table *unw_tables;
-
-static void
-push (struct unw_state_record *sr)
+int
+unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char *nat, int write)
 {
-	struct unw_reg_state *rs;
+	unsigned long *addr, *nat_addr, nat_mask = 0, dummy_nat;
+	struct unw_ireg *ireg;
+	struct pt_regs *pt;
 
-	rs = alloc_reg_state();
-	memcpy(rs, &sr->curr, sizeof(*rs));
-	rs->next = sr->stack;
-	sr->stack = rs;
-}
+	if ((unsigned) regnum - 1 >= 127)
+		return -1;
 
-static void
-pop (struct unw_state_record *sr)
-{
-	struct unw_reg_state *rs;
+	if (regnum < 32) {
+		if (regnum >= 4 && regnum <= 7) {
+			/* access a preserved register */
+			ireg = &info->r4 + (regnum - 4);
+			addr = ireg->loc;
+			if (addr) {
+				nat_addr = addr + ireg->nat.off;
+				switch (ireg->nat.type) {
+				      case UNW_NAT_VAL:
+					/* simulate getf.sig/setf.sig */
+					if (write) {
+						if (*nat) {
+							/* write NaTVal and be done with it */
+							addr[0] = 0;
+							addr[1] = 0x1fffe;
+							return 0;
+						}
+						addr[1] = 0x1003e;
+					} else {
+						if (addr[0] = 0 && addr[1] = 0x1ffe) {
+							/* return NaT and be done with it */
+							*val = 0;
+							*nat = 1;
+							return 0;
+						}
+					}
+					/* fall through */
+				      case UNW_NAT_NONE:
+					nat_addr = &dummy_nat;
+					break;
 
-	if (!sr->stack) {
-		printk ("unwind: stack underflow!\n");
-		return;
+				      case UNW_NAT_SCRATCH:
+					if (info->unat)
+						nat_addr = info->unat;
+					else
+						nat_addr = &info->sw->caller_unat;
+				      case UNW_NAT_PRI_UNAT:
+					nat_mask = (1UL << ((long) addr & 0x1f8)/8);
+					break;
+
+				      case UNW_NAT_STACKED:
+					nat_addr = ia64_rse_rnat_addr(addr);
+					if ((unsigned long) addr < info->regstk.limit
+					    || (unsigned long) addr >= info->regstk.top)
+						return -1;
+					if ((unsigned long) nat_addr >= info->regstk.top)
+						nat_addr = &info->sw->ar_rnat;
+					nat_mask = (1UL << ia64_rse_slot_num(addr));
+					break;
+				}
+			} else {
+				addr = &info->sw->r4 + (regnum - 4);
+				nat_addr = &info->sw->ar_unat;
+				nat_mask = (1UL << ((long) addr & 0x1f8)/8);
+			}
+		} else {
+			/* access a scratch register */
+			pt = (struct pt_regs *) info->sp - 1;
+			if (regnum <= 3)
+				addr = &pt->r1 + (regnum - 1);
+			else if (regnum <= 11)
+				addr = &pt->r8 + (regnum - 8);
+			else if (regnum <= 15)
+				addr = &pt->r12 + (regnum - 12);
+			else
+				addr = &pt->r16 + (regnum - 16);
+			if (info->unat)
+				nat_addr = info->unat;
+			else
+				nat_addr = &info->sw->caller_unat;
+			nat_mask = (1UL << ((long) addr & 0x1f8)/8);
+		}
+	} else {
+		/* access a stacked register */
+		addr = ia64_rse_skip_regs((unsigned long *) info->bsp, regnum);
+		nat_addr = ia64_rse_rnat_addr(addr);
+		if ((unsigned long) addr < info->regstk.limit
+		    || (unsigned long) addr >= info->regstk.top)
+		{
+			dprintk("unwind: ignoring attempt to access register outside of rbs\n");
+			return -1;
+		}
+		if ((unsigned long) nat_addr >= info->regstk.top)
+			nat_addr = &info->sw->ar_rnat;
+		nat_mask = (1UL << ia64_rse_slot_num(addr));
 	}
-	rs = sr->stack;
-	sr->stack = rs->next;
-	free_reg_state(rs);
-}
 
-static enum unw_register_index __attribute__((const))
-decode_abreg (unsigned char abreg, int memory)
-{
-	switch (abreg) {
-	      case 0x04 ... 0x07: return UNW_REG_R4 + (abreg - 0x04);
-	      case 0x22 ... 0x25: return UNW_REG_F2 + (abreg - 0x22);
-	      case 0x30 ... 0x3f: return UNW_REG_F16 + (abreg - 0x30);
-	      case 0x41 ... 0x45: return UNW_REG_B1 + (abreg - 0x41);
-	      case 0x60: return UNW_REG_PR;
-	      case 0x61: return UNW_REG_PSP;
-	      case 0x62: return memory ? UNW_REG_PRI_UNAT_MEM : UNW_REG_PRI_UNAT_GR;
-	      case 0x63: return UNW_REG_RP;
-	      case 0x64: return UNW_REG_BSP;
-	      case 0x65: return UNW_REG_BSPSTORE;
-	      case 0x66: return UNW_REG_RNAT;
-	      case 0x67: return UNW_REG_UNAT;
-	      case 0x68: return UNW_REG_FPSR;
-	      case 0x69: return UNW_REG_PFS;
-	      case 0x6a: return UNW_REG_LC;
-	      default:
-		break;
+	if (write) {
+		*addr = *val;
+		*nat_addr = (*nat_addr & ~nat_mask) | nat_mask;
+	} else {
+		*val = *addr;
+		*nat = (*nat_addr & nat_mask) != 0;
 	}
-	dprintk("unwind: bad abreg=0x%x\n", abreg);
-	return UNW_REG_LC;
+	return 0;
 }
 
-static void
-set_reg (struct unw_reg_info *reg, enum unw_where where, int when, unsigned long val)
+int
+unw_access_br (struct unw_frame_info *info, int regnum, unsigned long *val, int write)
 {
-	reg->val = val;
-	reg->where = where;
-	if (reg->when = UNW_WHEN_NEVER)
-		reg->when = when;
-}
+	unsigned long *addr;
+	struct pt_regs *pt;
 
-static void
-alloc_spill_area (unsigned long *offp, unsigned long regsize,
-		  struct unw_reg_info *lo, struct unw_reg_info *hi)
-{
-	struct unw_reg_info *reg;
+	pt = (struct pt_regs *) info->sp - 1;
+	switch (regnum) {
+		/* scratch: */
+	      case 0: addr = &pt->b0; break;
+	      case 6: addr = &pt->b6; break;
+	      case 7: addr = &pt->b7; break;
 
-	for (reg = hi; reg >= lo; --reg) {
-		if (reg->where = UNW_WHERE_SPILL_HOME) {
-			reg->where = UNW_WHERE_PSPREL;
-			reg->val = *offp;
-			*offp += regsize;
-		}
+		/* preserved: */
+	      case 1: case 2: case 3: case 4: case 5:
+		addr = *(&info->b1 + (regnum - 1));
+		break;
+
+	      default:
+		return -1;
 	}
+	if (write)
+		*addr = *val;
+	else
+		*val = *addr;
+	return 0;
 }
 
-static void
-spill_next_when (struct unw_reg_info **regp, struct unw_reg_info *lim, unw_word t)
+int
+unw_access_fr (struct unw_frame_info *info, int regnum, struct ia64_fpreg *val, int write)
 {
-	struct unw_reg_info *reg;
+	struct ia64_fpreg *addr = 0;
+	struct pt_regs *pt;
 
-	for (reg = *regp; reg <= lim; ++reg) {
-		if (reg->where = UNW_WHERE_SPILL_HOME) {
-			reg->when = t;
-			*regp = reg + 1;
-			return;
-		}
+	if ((unsigned) (regnum - 2) >= 30)
+		return -1;
+
+	pt = (struct pt_regs *) info->sp - 1;
+
+	if (regnum <= 5) {
+		addr = *(&info->f2 + (regnum - 2));
+		if (!addr)
+			addr = &info->sw->f2 + (regnum - 2);
+	} else if (regnum <= 15) {
+		if (regnum <= 9)
+			addr = &pt->f6  + (regnum - 6);
+		else
+			addr = &info->sw->f10 + (regnum - 10);
+	} else if (regnum <= 31) {
+		addr = *(&info->fr[regnum - 16]);
+		if (!addr)
+			addr = &info->sw->f16 + (regnum - 16);
 	}
-	dprintk("unwind: excess spill!\n");
+
+	if (write)
+		*addr = *val;
+	else
+		*val = *addr;
+	return 0;
 }
 
-static void
-finish_prologue (struct unw_state_record *sr)
+int
+unw_access_ar (struct unw_frame_info *info, int regnum, unsigned long *val, int write)
 {
-	struct unw_reg_info *reg;
-	unsigned long off;
-	int i;
+	unsigned long *addr;
+	struct pt_regs *pt;
 
-	/*
-	 * First, resolve implicit register save locations
-	 * (see Section "11.4.2.3 Rules for Using Unwind
-	 * Descriptors", rule 3):
-	 */
-	for (i = 0; i < (int) sizeof(save_order)/sizeof(save_order[0]); ++i) {
-		reg = sr->curr.reg + save_order[i];
-		if (reg->where = UNW_WHERE_GR_SAVE) {
-			reg->where = UNW_WHERE_GR;
-			reg->val = sr->gr_save_loc++;
-		}
-	}
+	pt = (struct pt_regs *) info->sp - 1;
 
-	/*
-	 * Next, compute when the fp, general, and branch registers get
-	 * saved.  This must come before alloc_spill_area() because
+	switch (regnum) {
+	      case UNW_AR_BSP:
+		addr = info->pbsp;
+		if (!addr)
+			addr = &info->sw->ar_bspstore;
+		break;
+
+	      case UNW_AR_BSPSTORE:
+		addr = info->bspstore;
+		if (!addr)
+			addr = &info->sw->ar_bspstore;
+		break;
+
+	      case UNW_AR_PFS:
+		addr = info->pfs;
+		if (!addr)
+			addr = &info->sw->ar_pfs;
+		break;
+
+	      case UNW_AR_RNAT:
+		addr = info->rnat;
+		if (!addr)
+			addr = &info->sw->ar_rnat;
+		break;
+
+	      case UNW_AR_UNAT:
+		addr = info->unat;
+		if (!addr)
+			addr = &info->sw->ar_unat;
+		break;
+
+	      case UNW_AR_LC:
+		addr = info->lc;
+		if (!addr)
+			addr = &info->sw->ar_lc;
+		break;
+
+	      case UNW_AR_FPSR:
+		addr = info->fpsr;
+		if (!addr)
+			addr = &info->sw->ar_fpsr;
+		break;
+
+	      case UNW_AR_RSC:
+		addr = &pt->ar_rsc;
+		break;
+
+	      case UNW_AR_CCV:
+		addr = &pt->ar_ccv;
+		break;
+
+	      default:
+		return -1;
+	}
+
+	if (write)
+		*addr = *val;
+	else
+		*val = *addr;
+	return 0;
+}
+
+inline int
+unw_access_pr (struct unw_frame_info *info, unsigned long *val, int write)
+{
+	unsigned long *addr;
+
+	addr = info->pr;
+	if (!addr)
+		addr = &info->sw->pr;
+
+	if (write)
+		*addr = *val;
+	else
+		*val = *addr;
+	return 0;
+}
+
+\f
+/* Unwind decoder routines */
+
+static inline void
+push (struct unw_state_record *sr)
+{
+	struct unw_reg_state *rs;
+
+	rs = alloc_reg_state();
+	memcpy(rs, &sr->curr, sizeof(*rs));
+	rs->next = sr->stack;
+	sr->stack = rs;
+}
+
+static void
+pop (struct unw_state_record *sr)
+{
+	struct unw_reg_state *rs;
+
+	if (!sr->stack) {
+		printk ("unwind: stack underflow!\n");
+		return;
+	}
+	rs = sr->stack;
+	sr->stack = rs->next;
+	free_reg_state(rs);
+}
+
+static enum unw_register_index __attribute__((const))
+decode_abreg (unsigned char abreg, int memory)
+{
+	switch (abreg) {
+	      case 0x04 ... 0x07: return UNW_REG_R4 + (abreg - 0x04);
+	      case 0x22 ... 0x25: return UNW_REG_F2 + (abreg - 0x22);
+	      case 0x30 ... 0x3f: return UNW_REG_F16 + (abreg - 0x30);
+	      case 0x41 ... 0x45: return UNW_REG_B1 + (abreg - 0x41);
+	      case 0x60: return UNW_REG_PR;
+	      case 0x61: return UNW_REG_PSP;
+	      case 0x62: return memory ? UNW_REG_PRI_UNAT_MEM : UNW_REG_PRI_UNAT_GR;
+	      case 0x63: return UNW_REG_RP;
+	      case 0x64: return UNW_REG_BSP;
+	      case 0x65: return UNW_REG_BSPSTORE;
+	      case 0x66: return UNW_REG_RNAT;
+	      case 0x67: return UNW_REG_UNAT;
+	      case 0x68: return UNW_REG_FPSR;
+	      case 0x69: return UNW_REG_PFS;
+	      case 0x6a: return UNW_REG_LC;
+	      default:
+		break;
+	}
+	dprintk("unwind: bad abreg=0x%x\n", abreg);
+	return UNW_REG_LC;
+}
+
+static void
+set_reg (struct unw_reg_info *reg, enum unw_where where, int when, unsigned long val)
+{
+	reg->val = val;
+	reg->where = where;
+	if (reg->when = UNW_WHEN_NEVER)
+		reg->when = when;
+}
+
+static void
+alloc_spill_area (unsigned long *offp, unsigned long regsize,
+		  struct unw_reg_info *lo, struct unw_reg_info *hi)
+{
+	struct unw_reg_info *reg;
+
+	for (reg = hi; reg >= lo; --reg) {
+		if (reg->where = UNW_WHERE_SPILL_HOME) {
+			reg->where = UNW_WHERE_PSPREL;
+			reg->val = *offp;
+			*offp += regsize;
+		}
+	}
+}
+
+static inline void
+spill_next_when (struct unw_reg_info **regp, struct unw_reg_info *lim, unw_word t)
+{
+	struct unw_reg_info *reg;
+
+	for (reg = *regp; reg <= lim; ++reg) {
+		if (reg->where = UNW_WHERE_SPILL_HOME) {
+			reg->when = t;
+			*regp = reg + 1;
+			return;
+		}
+	}
+	dprintk("unwind: excess spill!\n");
+}
+
+static inline void
+finish_prologue (struct unw_state_record *sr)
+{
+	struct unw_reg_info *reg;
+	unsigned long off;
+	int i;
+
+	/*
+	 * First, resolve implicit register save locations
+	 * (see Section "11.4.2.3 Rules for Using Unwind
+	 * Descriptors", rule 3):
+	 */
+	for (i = 0; i < (int) sizeof(unw.save_order)/sizeof(unw.save_order[0]); ++i) {
+		reg = sr->curr.reg + unw.save_order[i];
+		if (reg->where = UNW_WHERE_GR_SAVE) {
+			reg->where = UNW_WHERE_GR;
+			reg->val = sr->gr_save_loc++;
+		}
+	}
+
+	/*
+	 * Next, compute when the fp, general, and branch registers get
+	 * saved.  This must come before alloc_spill_area() because
 	 * we need to know which registers are spilled to their home
 	 * locations.
 	 */
@@ -267,7 +593,7 @@
  * Region header descriptors.
  */
 
-static inline void
+static void
 desc_prologue (int body, unw_word rlen, unsigned char mask, unsigned char grsave,
 	       struct unw_state_record *sr)
 {
@@ -298,7 +624,7 @@
 	if (!body) {
 		for (i = 0; i < 4; ++i) {
 			if (mask & 0x8)
-				set_reg(sr->curr.reg + save_order[i], UNW_WHERE_GR,
+				set_reg(sr->curr.reg + unw.save_order[i], UNW_WHERE_GR,
 					sr->region_start + sr->region_len - 1, grsave++);
 			mask <<= 1;
 		}
@@ -316,8 +642,10 @@
 static inline void
 desc_abi (unsigned char abi, unsigned char context, struct unw_state_record *sr)
 {
-	dprintk("unwind: ignoring unwabi(abi=0x%x,context=0x%x)\n", abi, context);
-	sr->flags |= UNW_FLAG_INTERRUPT_FRAME;
+	if (abi = 0 && context = 'i')
+		sr->flags |= UNW_FLAG_INTERRUPT_FRAME;
+	else
+		dprintk("unwind: ignoring unwabi(abi=0x%x,context=0x%x)\n", abi, context);
 }
 
 static inline void
@@ -645,44 +973,126 @@
 
 #include "unwind_decoder.c"
 
-static struct unw_table_entry *
-lookup (struct unw_table *table, unsigned long rel_ip)
+\f
+/* Unwind scripts. */
+
+static inline unw_hash_index_t
+hash (unsigned long ip)
 {
-	struct unw_table_entry *e = 0;
-	unsigned long lo, hi, mid;
+#	define magic	0x9e3779b97f4a7c16	/* (sqrt(5)/2-1)*2^64 */
 
-	/* do a binary search for right entry: */
-	for (lo = 0, hi = table->length; lo < hi; ) {
-		mid = (lo + hi) / 2;
-		e = &table->array[mid];
-		if (rel_ip < e->start_offset)
-			hi = mid;
-		else if (rel_ip >= e->end_offset)
-			lo = mid + 1;
-		else
-			break;
-	}
-	return e;
+	return (ip >> 4)*magic >> (64 - UNW_LOG_HASH_SIZE);
 }
 
-static struct unw_script *
-script_new (void)
+static inline long
+cache_match (struct unw_script *script, unsigned long ip, unsigned long pr_val)
 {
-	struct unw_script *script;
+	read_lock(&script->lock);
+	if ((ip) = (script)->ip && (((pr_val) ^ (script)->pr_val) & (script)->pr_mask) = 0)
+		/* keep the read lock... */
+		return 1;
+	read_unlock(&script->lock);
+	return 0;
+}
 
-	script = kmalloc(sizeof(*script), GFP_ATOMIC);	/* XXX fix me */
-	memset(script, 0, sizeof(*script));
-	return script;
+static inline struct unw_script *
+script_lookup (struct unw_frame_info *info)
+{
+	struct unw_script *script = unw.cache + info->hint;
+	unsigned long ip, pr_val;
+
+	STAT(++unw.stat.cache.lookups);
+
+	ip = info->ip;
+	pr_val = info->pr_val;
+
+	if (cache_match(script, ip, pr_val)) {
+		STAT(++unw.stat.cache.hinted_hits);
+		return script;
+	}
+
+	script = unw.cache + unw.hash[hash(ip)];
+	while (1) {
+		if (cache_match(script, ip, pr_val)) {
+			/* update hint; no locking required as single-word writes are atomic */
+			STAT(++unw.stat.cache.normal_hits);
+			unw.cache[info->prev_script].hint = script - unw.cache;
+			return script;
+		}
+		if (script->coll_chain >= UNW_HASH_SIZE)
+			return 0;
+		script = unw.cache + script->coll_chain;
+		STAT(++unw.stat.cache.collision_chain_traversals);
+	}
 }
 
-static void
-script_emit (struct unw_script *script, struct unw_insn insn)
+/*
+ * On returning, a write lock for the SCRIPT is still being held.
+ */
+static inline struct unw_script *
+script_new (unsigned long ip)
 {
-	if (script->count >= UNW_MAX_SCRIPT_LEN) {
-		dprintk("unwind: script exceeds maximum size of %u instructions!\n",
-			UNW_MAX_SCRIPT_LEN);
+	struct unw_script *script, *prev, *tmp;
+	unsigned short head;
+	unsigned long flags;
+	unsigned char index;
+
+	STAT(++unw.stat.script.news);
+
+	/*
+	 * Atomically fetch the least recently used script.  We can't
+	 * do this via unw.lock because we also need to acquire the
+	 * script's lock and to avoid deadlock, we must acquire the
+	 * latter before the former.
+	 */
+	do {
+		head = unw.lru_head;
+	} while (cmpxchg(&unw.lru_head, head, unw.cache[head].lru_chain) != head);
+
+	script = unw.cache + head;
+
+	write_lock(&script->lock);
+
+	spin_lock_irqsave(&unw.lock, flags);
+	{
+		/* re-insert script at the tail of the LRU chain: */
+		unw.cache[unw.lru_tail].lru_chain = head;
+		unw.lru_tail = head;
+
+		/* remove the old script from the hash table (if it's there): */
+		index = hash(script->ip);
+		tmp = unw.cache + unw.hash[index];
+		prev = 0;
+		while (1) {
+			if (tmp = script) {
+				if (prev)
+					prev->coll_chain = tmp->coll_chain;
+				else
+					unw.hash[index] = tmp->coll_chain;
+				break;
+			} else
+				prev = tmp;
+			if (tmp->coll_chain >= UNW_CACHE_SIZE)
+				/* old script wasn't in the hash-table */
+				break;
+			tmp = unw.cache + tmp->coll_chain;
+		}
+
+		/* enter new script in the hash table */
+		index = hash(ip);
+		script->coll_chain = unw.hash[index];
+		unw.hash[index] = script - unw.cache;
+
+		script->ip = ip;	/* set new IP while we're holding the locks */
+
+		STAT(if (script->coll_chain < UNW_CACHE_SIZE) ++unw.stat.script.collisions);
 	}
-	script->insn[script->count++] = insn;
+	spin_unlock_irqrestore(&unw.lock, flags);
+
+	script->flags = 0;
+	script->hint = 0;
+	script->count = 0;
+	return script;
 }
 
 static void
@@ -690,17 +1100,34 @@
 {
 	script->pr_mask = sr->pr_mask;
 	script->pr_val = sr->pr_val;
+	/*
+	 * We could down-grade our write-lock on script->lock here but
+	 * the rwlock API doesn't offer atomic lock downgrading, so
+	 * we'll just keep the write-lock and release it later when
+	 * we're done using the script.
+	 */
 }
 
 static inline void
-emit_nat_info (struct unw_state_record *sr, int i, struct unw_script *script)
+script_emit (struct unw_script *script, struct unw_insn insn)
 {
-	struct unw_reg_info *r = sr->curr.reg + i;
-	enum unw_insn_opcode opc;
-	struct unw_insn insn;
-	unsigned long val;
-
-	switch (r->where) {
+	if (script->count >= UNW_MAX_SCRIPT_LEN) {
+		dprintk("unwind: script exceeds maximum size of %u instructions!\n",
+			UNW_MAX_SCRIPT_LEN);
+		return;
+	}
+	script->insn[script->count++] = insn;
+}
+
+static inline void
+emit_nat_info (struct unw_state_record *sr, int i, struct unw_script *script)
+{
+	struct unw_reg_info *r = sr->curr.reg + i;
+	enum unw_insn_opcode opc;
+	struct unw_insn insn;
+	unsigned long val;
+
+	switch (r->where) {
 	      case UNW_WHERE_GR:
 		if (r->val >= 32) {
 			/* register got spilled to a stacked register */
@@ -734,7 +1161,7 @@
 		return;
 	}
 	insn.opc = opc;
-	insn.dst = preg_index[i];
+	insn.dst = unw.preg_index[i];
 	insn.val = val;
 	script_emit(script, insn);
 }
@@ -765,10 +1192,10 @@
 				opc = UNW_INSN_MOVE2;
 				need_nat_info = 0;
 			}
-			val = preg_index[UNW_REG_R4 + (rval - 4)];
+			val = unw.preg_index[UNW_REG_R4 + (rval - 4)];
 		} else {
 			opc = UNW_INSN_LOAD_SPREL;
-			val = 0x10 - sizeof(struct pt_regs); 
+			val = -sizeof(struct pt_regs); 
 			if (rval >= 1 && rval <= 3)
 				val += struct_offset(struct pt_regs, r1) + 8*(rval - 1);
 			else if (rval <= 11)
@@ -784,12 +1211,12 @@
 
 	      case UNW_WHERE_FR:
 		if (rval <= 5)
-			val = preg_index[UNW_REG_F2  + (rval -  1)];
+			val = unw.preg_index[UNW_REG_F2  + (rval -  1)];
 		else if (rval >= 16 && rval <= 31)
-			val = preg_index[UNW_REG_F16 + (rval - 16)];
+			val = unw.preg_index[UNW_REG_F16 + (rval - 16)];
 		else {
 			opc = UNW_INSN_LOAD_SPREL;
-			val = 0x10 - sizeof(struct pt_regs);
+			val = -sizeof(struct pt_regs);
 			if (rval <= 9)
 				val += struct_offset(struct pt_regs, f6) + 16*(rval - 6);
 			else
@@ -799,10 +1226,10 @@
 
 	      case UNW_WHERE_BR:
 		if (rval >= 1 && rval <= 5)
-			val = preg_index[UNW_REG_B1 + (rval - 1)];
+			val = unw.preg_index[UNW_REG_B1 + (rval - 1)];
 		else {
 			opc = UNW_INSN_LOAD_SPREL;
-			val = 0x10 - sizeof(struct pt_regs);
+			val = -sizeof(struct pt_regs);
 			if (rval = 0)
 				val += struct_offset(struct pt_regs, b0);
 			else if (rval = 6)
@@ -825,412 +1252,191 @@
 		break;
 	}
 	insn.opc = opc;
-	insn.dst = preg_index[i];
+	insn.dst = unw.preg_index[i];
 	insn.val = val;
 	script_emit(script, insn);
 	if (need_nat_info)
 		emit_nat_info(sr, i, script);
 }
 
+static inline struct unw_table_entry *
+lookup (struct unw_table *table, unsigned long rel_ip)
+{
+	struct unw_table_entry *e = 0;
+	unsigned long lo, hi, mid;
+
+	/* do a binary search for right entry: */
+	for (lo = 0, hi = table->length; lo < hi; ) {
+		mid = (lo + hi) / 2;
+		e = &table->array[mid];
+		if (rel_ip < e->start_offset)
+			hi = mid;
+		else if (rel_ip >= e->end_offset)
+			lo = mid + 1;
+		else
+			break;
+	}
+	return e;
+}
+
 /*
  * Build an unwind script that unwinds from state OLD_STATE to the
  * entrypoint of the function that called OLD_STATE.
  */
-static struct unw_script *
+static inline struct unw_script *
 build_script (struct unw_frame_info *info)
 {
 	struct unw_reg_state *rs, *next;
 	struct unw_table_entry *e = 0;
 	struct unw_script *script = 0;
+	unsigned long ip = info->ip;
 	struct unw_state_record sr;
 	struct unw_table *table;
 	struct unw_reg_info *r;
 	struct unw_insn insn;
 	u8 *dp, *desc_end;
-	unsigned long ip;
 	u64 hdr;
 	int i;
+	STAT(unsigned long start, parse_start;)
+
+	STAT(++unw.stat.script.builds; start = ia64_get_itc());
 
 	/* build state record */
 	memset(&sr, 0, sizeof(sr));
 	for (r = sr.curr.reg; r < sr.curr.reg + UNW_NUM_REGS; ++r)
 		r->when = UNW_WHEN_NEVER;
-	sr.pr_val = info->pr_val;
-
-	script = script_new ();
-	if (!script) {
-		dprintk("unwind: failed to create unwind script\n");
-		return 0;
-	}
-	ip = script->ip = info->ip;
-
-	/* search the kernels and the modules' unwind tables for IP: */
-
-	for (table = unw_tables; table; table = table->next) {
-		if (ip >= table->start && ip < table->end) {
-			e = lookup(table, ip - table->segment_base);
-			break;
-		}
-	}
-	if (!e) {
-		/* no info, return default unwinder (leaf proc, no mem stack, no saved regs)  */
-		dprintk("unwind: no unwind info for ip=%lx\n", ip);
-		sr.curr.reg[UNW_REG_RP].where = UNW_WHERE_BR;
-		sr.curr.reg[UNW_REG_RP].when = -1;
-		sr.curr.reg[UNW_REG_RP].val = 0;
-		compile_reg(&sr, UNW_REG_RP, script);
-		script_finalize(script, &sr);
-		return script;
-	}
-
-	sr.when_target = (3*((ip & ~0xfUL) - (table->segment_base + e->start_offset))
-			  + (ip & 0xfUL));
-	hdr = *(u64 *) (table->segment_base + e->info_offset);
-	dp =   (u8 *)  (table->segment_base + e->info_offset + 8);
-	desc_end = dp + 8*UNW_LENGTH(hdr);
-
-	while (!sr.done && dp < desc_end)
-		dp = unw_decode(dp, sr.in_body, &sr);
-
-	if (sr.when_target > sr.epilogue_start) {
-		/*
-		 * sp has been restored and all values on the memory stack below
-		 * psp also have been restored.
-		 */
-		sr.curr.reg[UNW_REG_PSP].where = UNW_WHERE_NONE;
-		sr.curr.reg[UNW_REG_PSP].val = 0;
-		for (r = sr.curr.reg; r < sr.curr.reg + UNW_NUM_REGS; ++r)
-			if ((r->where = UNW_WHERE_PSPREL && r->val <= 0x10)
-			    || r->where = UNW_WHERE_SPREL)
-				r->where = UNW_WHERE_NONE;
-	}
-
-	script->flags = sr.flags;
-
-	/*
-	 * If RP did't get saved, generate entry for the return link
-	 * register.
-	 */
-	if (sr.curr.reg[UNW_REG_RP].when >= sr.when_target) {
-		sr.curr.reg[UNW_REG_RP].where = UNW_WHERE_BR;
-		sr.curr.reg[UNW_REG_RP].when = -1;
-		sr.curr.reg[UNW_REG_RP].val = sr.return_link_reg;
-	}
-
-#if UNW_DEBUG
-	printk ("unwind: state record for func 0x%lx, t=%u:\n",
-		table->segment_base + e->start_offset, sr.when_target);
-	for (r = sr.curr.reg; r < sr.curr.reg + UNW_NUM_REGS; ++r) {
-		if (r->where != UNW_WHERE_NONE || r->when != UNW_WHEN_NEVER) {
-			printk("  %s <- ", preg_name[r - sr.curr.reg]);
-			switch (r->where) {
-			      case UNW_WHERE_GR:     printk("r%lu", r->val); break;
-			      case UNW_WHERE_FR:     printk("f%lu", r->val); break;
-			      case UNW_WHERE_BR:     printk("b%lu", r->val); break;
-			      case UNW_WHERE_SPREL:  printk("[sp+0x%lx]", r->val); break;
-			      case UNW_WHERE_PSPREL: printk("[psp+0x%lx]", 0x10 - r->val); break;
-			      case UNW_WHERE_NONE:
-				printk("%s+0x%lx", preg_name[r - sr.curr.reg], r->val);
-				break; 
-			      default:		     printk("BADWHERE(%d)", r->where); break;
-			}
-			printk ("\t\t%d\n", r->when);
-		}
-	}
-#endif
-
-	/* translate state record into unwinder instructions: */
-
-	if (sr.curr.reg[UNW_REG_PSP].where = UNW_WHERE_NONE
-	    && sr.when_target > sr.curr.reg[UNW_REG_PSP].when && sr.curr.reg[UNW_REG_PSP].val != 0)
-	{
-		/* new psp is sp plus frame size */
-		insn.opc = UNW_INSN_ADD;
-		insn.dst = preg_index[UNW_REG_PSP];
-		insn.val = sr.curr.reg[UNW_REG_PSP].val;
-		script_emit(script, insn);
-	}
-
-	/* determine where the primary UNaT is: */
-	if (sr.when_target < sr.curr.reg[UNW_REG_PRI_UNAT_GR].when)
-		i = UNW_REG_PRI_UNAT_MEM;
-	else if (sr.when_target < sr.curr.reg[UNW_REG_PRI_UNAT_MEM].when)
-		i = UNW_REG_PRI_UNAT_GR;
-	else if (sr.curr.reg[UNW_REG_PRI_UNAT_MEM].when > sr.curr.reg[UNW_REG_PRI_UNAT_GR].when)
-		i = UNW_REG_PRI_UNAT_MEM;
-	else
-		i = UNW_REG_PRI_UNAT_GR;
-
-	compile_reg(&sr, i, script);
-
-	for (i = UNW_REG_BSP; i < UNW_NUM_REGS; ++i)
-		compile_reg(&sr, i, script);
-
-	/* free labelled register states & stack: */
-
-	for (rs = sr.reg_state_list; rs; rs = next) {
-		next = rs->next;
-		free_reg_state(rs);
-	}
-	while (sr.stack)
-		pop(&sr);
-
-	script_finalize(script, &sr);
-	return script;
-}
-
-int
-unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char *nat, int write)
-{
-	unsigned long *addr, *nat_addr, nat_mask = 0, dummy_nat;
-	struct unw_ireg *ireg;
-	struct pt_regs *pt;
-
-	if ((unsigned) regnum - 1 >= 127)
-		return -1;
-
-	if (regnum < 32) {
-		if (regnum >= 4 && regnum <= 7) {
-			/* access a preserved register */
-			ireg = &info->r4 + (regnum - 4);
-			addr = ireg->loc;
-			if (addr) {
-				nat_addr = addr + ireg->nat.off;
-				switch (ireg->nat.type) {
-				      case UNW_NAT_VAL:
-					/* simulate getf.sig/setf.sig */
-					if (write) {
-						if (*nat) {
-							/* write NaTVal and be done with it */
-							addr[0] = 0;
-							addr[1] = 0x1fffe;
-							return 0;
-						}
-						addr[1] = 0x1003e;
-					} else {
-						if (addr[0] = 0 && addr[1] = 0x1ffe) {
-							/* return NaT and be done with it */
-							*val = 0;
-							*nat = 1;
-							return 0;
-						}
-					}
-					/* fall through */
-				      case UNW_NAT_NONE:
-					nat_addr = &dummy_nat;
-					break;
-
-				      case UNW_NAT_SCRATCH:
-					if (info->unat)
-						nat_addr = info->unat;
-					else
-						nat_addr = &info->sw->caller_unat;
-				      case UNW_NAT_PRI_UNAT:
-					nat_mask = (1UL << ((long) addr & 0x1f8)/8);
-					break;
-
-				      case UNW_NAT_STACKED:
-					nat_addr = ia64_rse_rnat_addr(addr);
-					if ((unsigned long) addr < info->regstk.limit
-					    || (unsigned long) addr >= info->regstk.top)
-						return -1;
-					if ((unsigned long) nat_addr >= info->regstk.top)
-						nat_addr = &info->sw->ar_rnat;
-					nat_mask = (1UL << ia64_rse_slot_num(addr));
-					break;
-				}
-			} else {
-				addr = &info->sw->r4 + (regnum - 4);
-				nat_addr = &info->sw->ar_unat;
-				nat_mask = (1UL << ((long) addr & 0x1f8)/8);
-			}
-		} else {
-			/* access a scratch register */
-			pt = (struct pt_regs *) info->sp - 1;
-			if (regnum <= 3)
-				addr = &pt->r1 + (regnum - 1);
-			else if (regnum <= 11)
-				addr = &pt->r8 + (regnum - 8);
-			else if (regnum <= 15)
-				addr = &pt->r12 + (regnum - 12);
-			else
-				addr = &pt->r16 + (regnum - 16);
-			if (info->unat)
-				nat_addr = info->unat;
-			else
-				nat_addr = &info->sw->caller_unat;
-			nat_mask = (1UL << ((long) addr & 0x1f8)/8);
-		}
-	} else {
-		/* access a stacked register */
-		addr = ia64_rse_skip_regs((unsigned long *) info->bsp, regnum);
-		nat_addr = ia64_rse_rnat_addr(addr);
-		if ((unsigned long) addr < info->regstk.limit
-		    || (unsigned long) addr >= info->regstk.top)
-		{
-			dprintk("unwind: ignoring attempt to access register outside of rbs\n");
-			return -1;
-		}
-		if ((unsigned long) nat_addr >= info->regstk.top)
-			nat_addr = &info->sw->ar_rnat;
-		nat_mask = (1UL << ia64_rse_slot_num(addr));
-	}
-
-	if (write) {
-		*addr = *val;
-		*nat_addr = (*nat_addr & ~nat_mask) | nat_mask;
-	} else {
-		*val = *addr;
-		*nat = (*nat_addr & nat_mask) != 0;
-	}
-	return 0;
-}
-
-int
-unw_access_br (struct unw_frame_info *info, int regnum, unsigned long *val, int write)
-{
-	unsigned long *addr;
-	struct pt_regs *pt;
-
-	pt = (struct pt_regs *) info->sp - 1;
-	switch (regnum) {
-		/* scratch: */
-	      case 0: addr = &pt->b0; break;
-	      case 6: addr = &pt->b6; break;
-	      case 7: addr = &pt->b7; break;
-
-		/* preserved: */
-	      case 1: case 2: case 3: case 4: case 5:
-		addr = *(&info->b1 + (regnum - 1));
-		break;
-
-	      default:
-		return -1;
-	}
-	if (write)
-		*addr = *val;
-	else
-		*val = *addr;
-	return 0;
-}
-
-int
-unw_access_fr (struct unw_frame_info *info, int regnum, struct ia64_fpreg *val, int write)
-{
-	struct ia64_fpreg *addr = 0;
-	struct pt_regs *pt;
-
-	if ((unsigned) (regnum - 2) >= 30)
-		return -1;
-
-	pt = (struct pt_regs *) info->sp - 1;
+	sr.pr_val = info->pr_val;
 
-	if (regnum <= 5) {
-		addr = *(&info->f2 + (regnum - 2));
-		if (!addr)
-			addr = &info->sw->f2 + (regnum - 2);
-	} else if (regnum <= 15) {
-		if (regnum <= 9)
-			addr = &pt->f6  + (regnum - 6);
-		else
-			addr = &info->sw->f10 + (regnum - 10);
-	} else if (regnum <= 31) {
-		addr = *(&info->fr[regnum - 16]);
-		if (!addr)
-			addr = &info->sw->f16 + (regnum - 16);
+	script = script_new(ip);
+	if (!script) {
+		dprintk("unwind: failed to create unwind script\n");
+		STAT(unw.stat.script.build_time += ia64_get_itc() - start);
+		return 0;
 	}
+	unw.cache[info->prev_script].hint = script - unw.cache;
 
-	if (write)
-		*addr = *val;
-	else
-		*val = *addr;
-	return 0;
-}
-
-int
-unw_access_ar (struct unw_frame_info *info, int regnum, unsigned long *val, int write)
-{
-	unsigned long *addr;
-	struct pt_regs *pt;
+	/* search the kernels and the modules' unwind tables for IP: */
 
-	pt = (struct pt_regs *) info->sp - 1;
+	STAT(parse_start = ia64_get_itc());
 
-	switch (regnum) {
-	      case UNW_AR_BSP:
-		addr = info->pbsp;
-		if (!addr)
-			addr = &info->sw->ar_bspstore;
-		break;
+	for (table = unw.tables; table; table = table->next) {
+		if (ip >= table->start && ip < table->end) {
+			e = lookup(table, ip - table->segment_base);
+			break;
+		}
+	}
+	if (!e) {
+		/* no info, return default unwinder (leaf proc, no mem stack, no saved regs)  */
+		dprintk("unwind: no unwind info for ip=0x%lx\n", ip);
+		sr.curr.reg[UNW_REG_RP].where = UNW_WHERE_BR;
+		sr.curr.reg[UNW_REG_RP].when = -1;
+		sr.curr.reg[UNW_REG_RP].val = 0;
+		compile_reg(&sr, UNW_REG_RP, script);
+		script_finalize(script, &sr);
+		STAT(unw.stat.script.parse_time += ia64_get_itc() - parse_start);
+		STAT(unw.stat.script.build_time += ia64_get_itc() - start);
+		return script;
+	}
 
-	      case UNW_AR_BSPSTORE:
-		addr = info->bspstore;
-		if (!addr)
-			addr = &info->sw->ar_bspstore;
-		break;
+	sr.when_target = (3*((ip & ~0xfUL) - (table->segment_base + e->start_offset))
+			  + (ip & 0xfUL));
+	hdr = *(u64 *) (table->segment_base + e->info_offset);
+	dp =   (u8 *)  (table->segment_base + e->info_offset + 8);
+	desc_end = dp + 8*UNW_LENGTH(hdr);
 
-	      case UNW_AR_PFS:
-		addr = info->pfs;
-		if (!addr)
-			addr = &info->sw->ar_pfs;
-		break;
+	while (!sr.done && dp < desc_end)
+		dp = unw_decode(dp, sr.in_body, &sr);
 
-	      case UNW_AR_RNAT:
-		addr = info->rnat;
-		if (!addr)
-			addr = &info->sw->ar_rnat;
-		break;
+	if (sr.when_target > sr.epilogue_start) {
+		/*
+		 * sp has been restored and all values on the memory stack below
+		 * psp also have been restored.
+		 */
+		sr.curr.reg[UNW_REG_PSP].where = UNW_WHERE_NONE;
+		sr.curr.reg[UNW_REG_PSP].val = 0;
+		for (r = sr.curr.reg; r < sr.curr.reg + UNW_NUM_REGS; ++r)
+			if ((r->where = UNW_WHERE_PSPREL && r->val <= 0x10)
+			    || r->where = UNW_WHERE_SPREL)
+				r->where = UNW_WHERE_NONE;
+	}
 
-	      case UNW_AR_UNAT:
-		addr = info->unat;
-		if (!addr)
-			addr = &info->sw->ar_unat;
-		break;
+	script->flags = sr.flags;
 
-	      case UNW_AR_LC:
-		addr = info->lc;
-		if (!addr)
-			addr = &info->sw->ar_lc;
-		break;
+	/*
+	 * If RP did't get saved, generate entry for the return link
+	 * register.
+	 */
+	if (sr.curr.reg[UNW_REG_RP].when >= sr.when_target) {
+		sr.curr.reg[UNW_REG_RP].where = UNW_WHERE_BR;
+		sr.curr.reg[UNW_REG_RP].when = -1;
+		sr.curr.reg[UNW_REG_RP].val = sr.return_link_reg;
+	}
 
-	      case UNW_AR_FPSR:
-		addr = info->fpsr;
-		if (!addr)
-			addr = &info->sw->ar_fpsr;
-		break;
+#if UNW_DEBUG
+	printk ("unwind: state record for func 0x%lx, t=%u:\n",
+		table->segment_base + e->start_offset, sr.when_target);
+	for (r = sr.curr.reg; r < sr.curr.reg + UNW_NUM_REGS; ++r) {
+		if (r->where != UNW_WHERE_NONE || r->when != UNW_WHEN_NEVER) {
+			printk("  %s <- ", unw.preg_name[r - sr.curr.reg]);
+			switch (r->where) {
+			      case UNW_WHERE_GR:     printk("r%lu", r->val); break;
+			      case UNW_WHERE_FR:     printk("f%lu", r->val); break;
+			      case UNW_WHERE_BR:     printk("b%lu", r->val); break;
+			      case UNW_WHERE_SPREL:  printk("[sp+0x%lx]", r->val); break;
+			      case UNW_WHERE_PSPREL: printk("[psp+0x%lx]", 0x10 - r->val); break;
+			      case UNW_WHERE_NONE:
+				printk("%s+0x%lx", unw.preg_name[r - sr.curr.reg], r->val);
+				break; 
+			      default:		     printk("BADWHERE(%d)", r->where); break;
+			}
+			printk ("\t\t%d\n", r->when);
+		}
+	}
+#endif
 
-	      case UNW_AR_RSC:
-		addr = &pt->ar_rsc;
-		break;
+	STAT(unw.stat.script.parse_time += ia64_get_itc() - parse_start);
 
-	      case UNW_AR_CCV:
-		addr = &pt->ar_ccv;
-		break;
+	/* translate state record into unwinder instructions: */
 
-	      default:
-		return -1;
+	if (sr.curr.reg[UNW_REG_PSP].where = UNW_WHERE_NONE
+	    && sr.when_target > sr.curr.reg[UNW_REG_PSP].when && sr.curr.reg[UNW_REG_PSP].val != 0)
+	{
+		/* new psp is sp plus frame size */
+		insn.opc = UNW_INSN_ADD;
+		insn.dst = unw.preg_index[UNW_REG_PSP];
+		insn.val = sr.curr.reg[UNW_REG_PSP].val;
+		script_emit(script, insn);
 	}
 
-	if (write)
-		*addr = *val;
+	/* determine where the primary UNaT is: */
+	if (sr.when_target < sr.curr.reg[UNW_REG_PRI_UNAT_GR].when)
+		i = UNW_REG_PRI_UNAT_MEM;
+	else if (sr.when_target < sr.curr.reg[UNW_REG_PRI_UNAT_MEM].when)
+		i = UNW_REG_PRI_UNAT_GR;
+	else if (sr.curr.reg[UNW_REG_PRI_UNAT_MEM].when > sr.curr.reg[UNW_REG_PRI_UNAT_GR].when)
+		i = UNW_REG_PRI_UNAT_MEM;
 	else
-		*val = *addr;
-	return 0;
-}
+		i = UNW_REG_PRI_UNAT_GR;
 
-inline int
-unw_access_pr (struct unw_frame_info *info, unsigned long *val, int write)
-{
-	unsigned long *addr;
+	compile_reg(&sr, i, script);
 
-	addr = info->pr;
-	if (!addr)
-		addr = &info->sw->pr;
+	for (i = UNW_REG_BSP; i < UNW_NUM_REGS; ++i)
+		compile_reg(&sr, i, script);
 
-	if (write)
-		*addr = *val;
-	else
-		*val = *addr;
-	return 0;
+	/* free labelled register states & stack: */
+
+	STAT(parse_start = ia64_get_itc());
+	for (rs = sr.reg_state_list; rs; rs = next) {
+		next = rs->next;
+		free_reg_state(rs);
+	}
+	while (sr.stack)
+		pop(&sr);
+	STAT(unw.stat.script.parse_time += ia64_get_itc() - parse_start);
+
+	script_finalize(script, &sr);
+	STAT(unw.stat.script.build_time += ia64_get_itc() - start);
+	return script;
 }
 
 /*
@@ -1238,13 +1444,15 @@
  * reflect the state that existed upon entry to the function that this
  * unwinder represents.
  */
-static void
+static inline void
 run_script (struct unw_script *script, struct unw_frame_info *state)
 {
 	struct unw_insn *ip, *limit, next_insn;
 	unsigned long opc, dst, val, off;
 	unsigned long *s = (unsigned long *) state;
+	STAT(unsigned long start;)
 
+	STAT(++unw.stat.script.runs; start = ia64_get_itc());
 	state->flags = script->flags;
 	ip = script->insn;
 	limit = script->insn + script->count;
@@ -1299,10 +1507,11 @@
 			break;
 		}
 	}
+	STAT(unw.stat.script.run_time += ia64_get_itc() - start);
 	return;
 
   lazy_init:
-	off = sw_offset[val];
+	off = unw.sw_off[val];
 	s[val] = (unsigned long) state->sw + off;
 	if (off >= struct_offset (struct unw_frame_info, r4)
 	    && off <= struct_offset (struct unw_frame_info, r7))
@@ -1314,61 +1523,71 @@
 	goto redo;
 }
 
-static void
+static int
 find_save_locs (struct unw_frame_info *info)
 {
-	static struct unw_script *script_cache;
+	int have_write_lock = 0;
 	struct unw_script *scr;
 
-	/* XXX BIG FIXME---need hash table here... */
-	scr = script_cache;
-	if (scr) {
-		while (scr->ip != info->ip || ((info->pr_val ^ scr->pr_val) & scr->pr_mask) != 0) {
-			if (scr->hint = -1) {
-				scr = 0;
-				break;
-			}
-			scr = (struct unw_script *) ((int *) scr + scr->hint);
-		}
+	if (info->ip & (my_cpu_data.unimpl_va_mask | 0xf)) {
+		/* don't let obviously bad addresses pollute the cache */
+		info->rp = 0;
+		return -1;
 	}
 
+	scr = script_lookup(info);
 	if (!scr) {
 		scr = build_script(info);
-		if (scr) {
-			if (script_cache)
-				scr->hint = (int *) script_cache - (int *) scr;
-			else
-				scr->hint = -1;
-			script_cache = scr;
+		if (!scr) {
+			dprintk("unwind: failed to locate/build unwind script for ip %lx\n",
+				info->ip);
+			return -1;
 		}
+		have_write_lock = 1;
 	}
+	info->hint = scr->hint;
+	info->prev_script = scr - unw.cache;
 
-	if (!scr) {
-		dprintk("unwind: failed to locate/build unwind script for ip %lx\n", info->ip);
-		return;
-	}
 	run_script(scr, info);
+
+	if (have_write_lock)
+		write_unlock(&scr->lock);
+	else
+		read_unlock(&scr->lock);
+	return 0;
 }
 
 int
 unw_unwind (struct unw_frame_info *info)
 {
+	unsigned long prev_ip, prev_sp, prev_bsp;
 	unsigned long ip, pr, num_regs;
+	STAT(unsigned long start, flags;)
+	int retval;
 	
+	STAT(local_irq_save(flags); ++unw.stat.api.unwinds; start = ia64_get_itc());
+
+	prev_ip = info->ip;
+	prev_sp = info->sp;
+	prev_bsp = info->bsp;
+
 	/* restore the ip */
 	if (!info->rp) {
-		dprintk("unwind: failed to locate return link!\n");
+		dprintk("unwind: failed to locate return link (ip=0x%lx)!\n", info->ip);
+		STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));
 		return -1;
 	}
 	ip = info->ip = *info->rp;
 	if (ip <= TASK_SIZE) {
-		dprintk("unwind: reached user-space (ip=%lx)\n", ip);
+		dprintk("unwind: reached user-space (ip=0x%lx)\n", ip);
+		STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));
 		return -1;
 	}
 
 	/* restore the cfm: */
 	if (!info->pfs) {
 		dprintk("unwind: failed to locate ar.pfs!\n");
+		STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));
 		return -1;
 	}
 	info->cfm = *info->pfs;
@@ -1387,6 +1606,7 @@
 	if (info->bsp < info->regstk.limit || info->bsp > info->regstk.top) {
 		dprintk("unwind: bsp (0x%lx) out of range [0x%lx-0x%lx]\n",
 			info->bsp, info->regstk.limit, info->regstk.top);
+		STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));
 		return -1;
 	}
 
@@ -1395,20 +1615,31 @@
 	if (info->sp < info->memstk.top || info->sp > info->memstk.limit) {
 		dprintk("unwind: sp (0x%lx) out of range [0x%lx-0x%lx]\n",
 			info->sp, info->regstk.top, info->regstk.limit);
+		STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));
+		return -1;
+	}
+
+	if (info->ip = prev_ip && info->sp = prev_sp && info->bsp = prev_bsp) {
+		dprintk("unwind: ip, sp, bsp remain unchanged; stopping here (ip=0x%lx)\n", ip);
+		STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));
 		return -1;
 	}
 
 	/* finally, restore the predicates: */
 	unw_get_pr(info, &info->pr_val);
 
-	find_save_locs(info);
-	return 0;
+	retval = find_save_locs(info);
+	STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));
+	return retval;
 }
 
 static void
 unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t, struct switch_stack *sw)
 {
 	unsigned long rbslimit, rbstop, stklimit, stktop, sol;
+	STAT(unsigned long start, flags;)
+
+	STAT(local_irq_save(flags); ++unw.stat.api.inits; start = ia64_get_itc());
 
 	/*
 	 * Subtle stuff here: we _could_ unwind through the
@@ -1445,6 +1676,7 @@
 	info->pr_val = sw->pr;
 
 	find_save_locs(info);
+	STAT(unw.stat.api.init_time += ia64_get_itc() - start; local_irq_restore(flags));
 }
 
 #endif /* CONFIG_IA64_NEW_UNWIND */
@@ -1563,7 +1795,8 @@
 		return -1;
 
 	info->ip = read_reg(info, sol - 2, &is_nat);
-	if (is_nat)
+	if (is_nat || (info->ip & (my_cpu_data.unimpl_va_mask | 0xf)))
+		/* don't let obviously bad addresses pollute the cache */
 		return -1;
 
 	cfm = read_reg(info, sol - 1, &is_nat);
@@ -1580,18 +1813,12 @@
 
 #ifdef CONFIG_IA64_NEW_UNWIND
 
-void *
-unw_add_unwind_table (const char *name, unsigned long segment_base, unsigned long gp,
-		      void *table_start, void *table_end)
+static void
+init_unwind_table (struct unw_table *table, const char *name, unsigned long segment_base,
+		   unsigned long gp, void *table_start, void *table_end)
 {
-	struct unw_table *table;
 	struct unw_table_entry *start = table_start, *end = table_end;
 
-	if (end - start <= 0) {
-		dprintk("unwind: ignoring attempt to insert empty unwind table\n");
-		return 0;
-	}
-
 #ifdef UNWIND_TABLE_SORT_BUG
 	{
 		struct unw_table_entry *e1, *e2, tmp;
@@ -1609,8 +1836,6 @@
 		}
 	}
 #endif
-
-	table = kmalloc(sizeof(*table), GFP_USER);
 	table->name = name;
 	table->segment_base = segment_base;
 	table->gp = gp;
@@ -1618,9 +1843,34 @@
 	table->end = segment_base + end[-1].end_offset;
 	table->array = start;
 	table->length = end - start;
+}
+
+void *
+unw_add_unwind_table (const char *name, unsigned long segment_base, unsigned long gp,
+		      void *table_start, void *table_end)
+{
+	struct unw_table_entry *start = table_start, *end = table_end;
+	struct unw_table *table;
+	unsigned long flags;
+
+	if (end - start <= 0) {
+		dprintk("unwind: ignoring attempt to insert empty unwind table\n");
+		return 0;
+	}
+	
+	table = kmalloc(sizeof(*table), GFP_USER);
+	if (!table)
+		return 0;
 
-	table->next = unw_tables;
-	unw_tables = table;
+	init_unwind_table(table, name, segment_base, gp, table_start, table_end);
+
+	spin_lock_irqsave(&unw.lock, flags);
+	{
+		/* keep kernel unwind table at the front (it's searched most commonly): */
+		table->next = unw.tables->next;
+		unw.tables->next = table;
+	}
+	spin_unlock_irqrestore(&unw.lock, flags);
 
 	return table;
 }
@@ -1628,7 +1878,10 @@
 void
 unw_remove_unwind_table (void *handle)
 {
-	struct unw_table *table, *prev;
+	struct unw_table *table, *prevt;
+	struct unw_script *tmp, *prev;
+	unsigned long flags;
+	long index;
 
 	if (!handle) {
 		dprintk("unwind: ignoring attempt to remove non-existent unwind table\n");
@@ -1636,18 +1889,52 @@
 	}
 
 	table = handle;
-	for (prev = (struct unw_table *) &unw_tables; prev; prev = prev->next)
-		if (prev->next = table)
-			break;
-	if (!prev) {
-		dprintk("unwind: failed to find unwind table %p\n", table);
+	if (table = &unw.kernel_table) {
+		dprintk("unwind: sorry, freeing the kernel's unwind table is a no-can-do!\n");
 		return;
 	}
-	prev->next = table->next;
-	kfree(table);
 
-	/* XXX need to implement this... */
-	dprintk("unwind: don't forget to clear cache entries for this module!\n");
+	spin_lock_irqsave(&unw.lock, flags);
+	{
+		/* first, delete the table: */
+
+		for (prevt = (struct unw_table *) &unw.tables; prevt; prevt = prevt->next)
+			if (prevt->next = table)
+				break;
+		if (!prevt) {
+			dprintk("unwind: failed to find unwind table %p\n", table);
+			spin_unlock_irqrestore(&unw.lock, flags);
+			return;
+		}
+		prevt->next = table->next;
+
+		/* next, remove hash table entries for this table */
+
+		for (index = 0; index <= UNW_HASH_SIZE; ++index) {
+			if (unw.hash[index] >= UNW_CACHE_SIZE)
+				continue;
+
+			tmp = unw.cache + unw.hash[index];
+			prev = 0;
+			while (1) {
+				write_lock(&tmp->lock);
+				{
+					if (tmp->ip >= table->start && tmp->ip < table->end) {
+						if (prev)
+							prev->coll_chain = tmp->coll_chain;
+						else
+							unw.hash[index] = -1;
+						tmp->ip = 0;
+					} else
+						prev = tmp;
+				}
+				write_unlock(&tmp->lock);
+			}
+		}
+	}
+	spin_unlock_irqrestore(&unw.lock, flags);
+
+	kfree(table);
 }
 #endif /* CONFIG_IA64_NEW_UNWIND */
 
@@ -1656,27 +1943,39 @@
 {
 #ifdef CONFIG_IA64_NEW_UNWIND
 	extern int ia64_unw_start, ia64_unw_end, __gp;
+	extern void unw_hash_index_t_is_too_narrow (void);
 	long i, off;
-#	define SW(f)	struct_offset(struct switch_stack, f)
 
-	sw_offset[preg_index[UNW_REG_PRI_UNAT_GR]] = SW(ar_unat);
-	sw_offset[preg_index[UNW_REG_BSPSTORE]] = SW(ar_bspstore);
-	sw_offset[preg_index[UNW_REG_PFS]] = SW(ar_unat);
-	sw_offset[preg_index[UNW_REG_RP]] = SW(b0);
-	sw_offset[preg_index[UNW_REG_UNAT]] = SW(ar_unat);
-	sw_offset[preg_index[UNW_REG_PR]] = SW(pr);
-	sw_offset[preg_index[UNW_REG_LC]] = SW(ar_lc);
-	sw_offset[preg_index[UNW_REG_FPSR]] = SW(ar_fpsr);
-	for (i = UNW_REG_R4, off = SW(r4); i <= UNW_REG_R7; ++i, off += 8)
-		sw_offset[preg_index[i]] = off;
-	for (i = UNW_REG_B1, off = SW(b1); i <= UNW_REG_B5; ++i, off += 8)
-		sw_offset[preg_index[i]] = off;
-	for (i = UNW_REG_F2, off = SW(f2); i <= UNW_REG_F5; ++i, off += 16)
-		sw_offset[preg_index[i]] = off;
-	for (i = UNW_REG_F16, off = SW(f16); i <= UNW_REG_F31; ++i, off += 16)
-		sw_offset[preg_index[i]] = off;
+	if (8*sizeof (unw_hash_index_t) < UNW_LOG_HASH_SIZE)
+		unw_hash_index_t_is_too_narrow();
+
+	unw.sw_off[unw.preg_index[UNW_REG_PRI_UNAT_GR]] = SW(AR_UNAT);
+	unw.sw_off[unw.preg_index[UNW_REG_BSPSTORE]] = SW(AR_BSPSTORE);
+	unw.sw_off[unw.preg_index[UNW_REG_PFS]] = SW(AR_UNAT);
+	unw.sw_off[unw.preg_index[UNW_REG_RP]] = SW(B0);
+	unw.sw_off[unw.preg_index[UNW_REG_UNAT]] = SW(AR_UNAT);
+	unw.sw_off[unw.preg_index[UNW_REG_PR]] = SW(PR);
+	unw.sw_off[unw.preg_index[UNW_REG_LC]] = SW(AR_LC);
+	unw.sw_off[unw.preg_index[UNW_REG_FPSR]] = SW(AR_FPSR);
+	for (i = UNW_REG_R4, off = SW(R4); i <= UNW_REG_R7; ++i, off += 8)
+		unw.sw_off[unw.preg_index[i]] = off;
+	for (i = UNW_REG_B1, off = SW(B1); i <= UNW_REG_B5; ++i, off += 8)
+		unw.sw_off[unw.preg_index[i]] = off;
+	for (i = UNW_REG_F2, off = SW(F2); i <= UNW_REG_F5; ++i, off += 16)
+		unw.sw_off[unw.preg_index[i]] = off;
+	for (i = UNW_REG_F16, off = SW(F16); i <= UNW_REG_F31; ++i, off += 16)
+		unw.sw_off[unw.preg_index[i]] = off;
+
+	unw.cache[0].coll_chain = -1;
+	for (i = 1; i < UNW_CACHE_SIZE; ++i) {
+		unw.cache[i].lru_chain = (i - 1);
+		unw.cache[i].coll_chain = -1;
+		unw.cache[i].lock = RW_LOCK_UNLOCKED;
+	}
+	unw.lru_head = UNW_CACHE_SIZE - 1;
+	unw.lru_tail = 0;
 
-	unw_add_unwind_table("kernel", KERNEL_START, (unsigned long) &__gp,
-			     &ia64_unw_start, &ia64_unw_end);
+	init_unwind_table(&unw.kernel_table, "kernel", KERNEL_START, (unsigned long) &__gp,
+			  &ia64_unw_start, &ia64_unw_end);
 #endif /* CONFIG_IA64_NEW_UNWIND */
 }
diff -urN linux-davidm/arch/ia64/kernel/unwind_i.h linux-2.4.0-test1-lia/arch/ia64/kernel/unwind_i.h
--- linux-davidm/arch/ia64/kernel/unwind_i.h	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/unwind_i.h	Thu Jun  1 01:08:05 2000
@@ -138,14 +138,23 @@
 	signed int val		: 19;
 };
 
-#define UNW_MAX_SCRIPT_LEN	(2*UNW_NUM_REGS)
+/*
+ * Preserved general static registers (r2-r5) give rise to two script
+ * instructions; everything else yields at most one instruction; at
+ * the end of the script, the psp gets popped, accounting for one more
+ * instruction.
+ */
+#define UNW_MAX_SCRIPT_LEN	(UNW_NUM_REGS + 5)
 
 struct unw_script {
 	unsigned long ip;		/* ip this script is for */
 	unsigned long pr_mask;		/* mask of predicates script depends on */
 	unsigned long pr_val;		/* predicate values this script is for */
-	unsigned long flags;		/* see UNW_FLAG_* in unwind.h */
-	unsigned int count;		/* number of instructions in script */
-	int hint;			/* hint for next script to try */
+	rwlock_t lock;
+	unsigned int flags;		/* see UNW_FLAG_* in unwind.h */
+	unsigned short lru_chain;	/* used for least-recently-used chain */
+	unsigned short coll_chain;	/* used for hash collisions */
+	unsigned short hint;		/* hint for next script to try (or -1) */
+	unsigned short count;		/* number of instructions in script */
 	struct unw_insn insn[UNW_MAX_SCRIPT_LEN];
 };
diff -urN linux-davidm/arch/ia64/mm/fault.c linux-2.4.0-test1-lia/arch/ia64/mm/fault.c
--- linux-davidm/arch/ia64/mm/fault.c	Mon Apr 24 15:52:23 2000
+++ linux-2.4.0-test1-lia/arch/ia64/mm/fault.c	Thu Jun  1 01:09:50 2000
@@ -1,8 +1,8 @@
 /*
  * MMU fault handling support.
  *
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -94,7 +94,14 @@
 	 * sure we exit gracefully rather than endlessly redo the
 	 * fault.
 	 */
-	if (!handle_mm_fault(mm, vma, address, (isr & IA64_ISR_W) != 0)) {
+	switch (handle_mm_fault(mm, vma, address, (mask & VM_WRITE) != 0)) {
+	      case 1:
+		++current->min_flt;
+		break;
+	      case 2:
+		++current->maj_flt;
+		break;
+	      case 0:
 		/*
 		 * We ran out of memory, or some other thing happened
 		 * to us that made us unable to handle the page fault
@@ -102,6 +109,8 @@
 		 */
 		signal = SIGBUS;
 		goto bad_area;
+	      default:
+		goto out_of_memory;
 	}
 	up(&mm->mmap_sem);
 	return;
@@ -128,15 +137,11 @@
 		return;
 	}
 	if (user_mode(regs)) {
-#if 0
-printk("%s(%d): segfault accessing %lx\n", current->comm, current->pid, address);
-show_regs(regs);
-#endif
 		si.si_signo = signal;
 		si.si_errno = 0;
 		si.si_code = SI_KERNEL;
 		si.si_addr = (void *) address;
-		force_sig_info(SIGSEGV, &si, current);
+		force_sig_info(signal, &si, current);
 		return;
 	}
 
@@ -161,4 +166,11 @@
 	die_if_kernel("Oops", regs, isr);
 	do_exit(SIGKILL);
 	return;
+
+  out_of_memory:
+	up(&mm->mmap_sem);
+	printk("VM: killing process %s\n", current->comm);
+	if (user_mode(regs))
+		do_exit(SIGKILL);
+	goto no_context;
 }
diff -urN linux-davidm/arch/ia64/mm/init.c linux-2.4.0-test1-lia/arch/ia64/mm/init.c
--- linux-davidm/arch/ia64/mm/init.c	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/arch/ia64/mm/init.c	Thu Jun  1 01:10:02 2000
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/swap.h>
 
+#include <asm/bitops.h>
 #include <asm/dma.h>
 #include <asm/efi.h>
 #include <asm/ia32.h>
@@ -265,7 +266,7 @@
 void __init
 ia64_rid_init (void)
 {
-	unsigned long flags, rid, pta;
+	unsigned long flags, rid, pta, impl_va_msb;
 
 	/* Set up the kernel identity mappings (regions 6 & 7) and the vmalloc area (region 5): */
 	ia64_clear_ic(flags);
@@ -300,11 +301,15 @@
 #	define ld_max_addr_space_size	(ld_max_addr_space_pages + PAGE_SHIFT)
 #	define ld_max_vpt_size		(ld_max_addr_space_pages + ld_pte_size)
 #	define POW2(n)			(1ULL << (n))
-#	define IMPL_VA_MSB		50
-	if (POW2(ld_max_addr_space_size - 1) + POW2(ld_max_vpt_size) > POW2(IMPL_VA_MSB))
+	impl_va_msb = ffz(~my_cpu_data.unimpl_va_mask) - 1;
+
+	if (impl_va_msb < 50 || impl_va_msb > 60)
+		panic("Bogus impl_va_msb value of %lu!\n", impl_va_msb);
+
+	if (POW2(ld_max_addr_space_size - 1) + POW2(ld_max_vpt_size) > POW2(impl_va_msb))
 		panic("mm/init: overlap between virtually mapped linear page table and "
 		      "mapped kernel space!");
-	pta = POW2(61) - POW2(IMPL_VA_MSB);
+	pta = POW2(61) - POW2(impl_va_msb);
 	/*
 	 * Set the (virtually mapped linear) page table address.  Bit
 	 * 8 selects between the short and long format, bits 2-7 the
@@ -324,9 +329,6 @@
 
 	clear_page((void *) ZERO_PAGE_ADDR);
 
-	ia64_rid_init();
-	__flush_tlb_all();
-
 	/* initialize mem_map[] */
 
 	memset(zones_size, 0, sizeof(zones_size));
@@ -378,8 +380,6 @@
 
 	max_mapnr = max_low_pfn;
 	high_memory = __va(max_low_pfn * PAGE_SIZE);
-
-	ia64_tlb_init();
 
 	totalram_pages += free_all_bootmem();
 
diff -urN linux-davidm/arch/ia64/mm/tlb.c linux-2.4.0-test1-lia/arch/ia64/mm/tlb.c
--- linux-davidm/arch/ia64/mm/tlb.c	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/arch/ia64/mm/tlb.c	Thu Jun  1 01:10:24 2000
@@ -53,10 +53,11 @@
  * flush_tlb_no_ptcg is called with ptcg_lock locked
  */
 static inline void
-flush_tlb_no_ptcg (__u64 start, __u64 end, __u64 nbits)
+flush_tlb_no_ptcg (unsigned long start, unsigned long end, unsigned long nbits)
 {
-	__u64 flags;
-	__u64 saved_tpr;
+	extern void smp_send_flush_tlb (void);
+	unsigned long saved_tpr = 0;
+	unsigned long flags;
 
 	/*
 	 * Some times this is called with interrupts disabled and causes
@@ -83,10 +84,12 @@
 	 * Purge local TLB entries. ALAT invalidation is done in ia64_leave_kernel.
 	 */
 	do {
-		__asm__ __volatile__ ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory");
+		asm volatile ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory");
 		start += (1UL << nbits);
 	} while (start < end);
 
+	ia64_srlz_i();			/* srlz.i implies srlz.d */
+
 	/*
 	 * Wait for other CPUs to finish purging entries.
 	 */
@@ -157,7 +160,7 @@
 	stride0 = ia64_ptce_info.stride[0];
 	stride1 = ia64_ptce_info.stride[1];
 
-	__save_and_cli(flags);
+	local_irq_save(flags);
 	for (i = 0; i < count0; ++i) {
 		for (j = 0; j < count1; ++j) {
 			asm volatile ("ptc.e %0" :: "r"(addr));
@@ -165,7 +168,7 @@
 		}
 		addr += stride0;
 	}
-	__restore_flags(flags);
+	local_irq_restore(flags);
 	ia64_insn_group_barrier();
 	ia64_srlz_i();			/* srlz.i implies srlz.d */
 	ia64_insn_group_barrier();
@@ -211,21 +214,20 @@
 		/*
 		 * Flush ALAT entries also.
 		 */
-		__asm__ __volatile__ ("ptc.ga %0,%1;;srlz.i;;"
-				      :: "r"(start), "r"(nbits<<2) : "memory");
+		asm volatile ("ptc.ga %0,%1;;srlz.i;;" :: "r"(start), "r"(nbits<<2) : "memory");
 # else
-		__asm__ __volatile__ ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory");
+		asm volatile ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory");
 # endif
 		start += (1UL << nbits);
 	} while (start < end);
-#endif /* CONFIG_SMP && !defined(CONFIG_ITANIUM_PTCG)
+#endif /* CONFIG_SMP && !defined(CONFIG_ITANIUM_PTCG) */
 	spin_unlock(&ptcg_lock);
 	ia64_insn_group_barrier();
 	ia64_srlz_i();			/* srlz.i implies srlz.d */
 	ia64_insn_group_barrier();
 }
 
-void
+void __init
 ia64_tlb_init (void)
 {
 	ia64_get_ptce(&ia64_ptce_info);
diff -urN linux-davidm/drivers/ide/piix.c linux-2.4.0-test1-lia/drivers/ide/piix.c
--- linux-davidm/drivers/ide/piix.c	Thu Jun  1 01:20:27 2000
+++ linux-2.4.0-test1-lia/drivers/ide/piix.c	Thu Jun  1 01:11:08 2000
@@ -423,7 +423,7 @@
 
 void __init ide_init_piix (ide_hwif_t *hwif)
 {
-#if 0
+#ifndef CONFIG_IA64
 	/* autoprobe instead... --davidm 00/04/20 */
 	if (!hwif->irq)
 		hwif->irq = hwif->channel ? 15 : 14;
diff -urN linux-davidm/drivers/scsi/simscsi.c linux-2.4.0-test1-lia/drivers/scsi/simscsi.c
--- linux-davidm/drivers/scsi/simscsi.c	Thu May 25 23:22:10 2000
+++ linux-2.4.0-test1-lia/drivers/scsi/simscsi.c	Thu Jun  1 01:11:28 2000
@@ -85,17 +85,22 @@
 static void
 simscsi_interrupt (unsigned long val)
 {
+	unsigned long flags;
 	Scsi_Cmnd *sc;
 
-	while ((sc = queue[rd].sc) != 0) {
-		atomic_dec(&num_reqs);
-		queue[rd].sc = 0;
+	spin_lock_irqsave(&io_request_lock, flags);
+	{
+		while ((sc = queue[rd].sc) != 0) {
+			atomic_dec(&num_reqs);
+			queue[rd].sc = 0;
 #if DEBUG_SIMSCSI
-		printk("simscsi_interrupt: done with %ld\n", sc->serial_number);
+			printk("simscsi_interrupt: done with %ld\n", sc->serial_number);
 #endif
-		(*sc->scsi_done)(sc);
-		rd = (rd + 1) % SIMSCSI_REQ_QUEUE_LEN;
+			(*sc->scsi_done)(sc);
+			rd = (rd + 1) % SIMSCSI_REQ_QUEUE_LEN;
+		}
 	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 int
diff -urN linux-davidm/drivers/sound/emu10k1/main.c linux-2.4.0-test1-lia/drivers/sound/emu10k1/main.c
--- linux-davidm/drivers/sound/emu10k1/main.c	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/drivers/sound/emu10k1/main.c	Thu Jun  1 01:12:11 2000
@@ -532,7 +532,7 @@
 	return CTSTATUS_SUCCESS;
 }
 
-static void audio_exit(struct emu10k1_card *card)
+static void __devexit audio_exit(struct emu10k1_card *card)
 {
 	kfree(card->waveout);
 	kfree(card->wavein);
@@ -550,7 +550,7 @@
 	return;
 }
 
-static void emu10k1_exit(struct emu10k1_card *card)
+static void __devexit emu10k1_exit(struct emu10k1_card *card)
 {
 	int ch;
 
diff -urN linux-davidm/fs/binfmt_elf.c linux-2.4.0-test1-lia/fs/binfmt_elf.c
--- linux-davidm/fs/binfmt_elf.c	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/fs/binfmt_elf.c	Thu Jun  1 01:12:21 2000
@@ -288,12 +288,14 @@
 	    } else
 		    map_addr = -EINVAL;
 #else /* !CONFIG_BINFMT_ELF32 */
+	    down(&current->mm->mmap_sem);
 	    map_addr = do_mmap(interpreter,
 			    load_addr + ELF_PAGESTART(vaddr),
 			    eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr),
 			    elf_prot,
 			    elf_type,
 			    eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
+	    up(&current->mm->mmap_sem);
 #endif /* !CONFIG_BINFMT_ELF32 */
 
 	    if (!load_addr_set && interp_elf_ex->e_type = ET_DYN) {
@@ -663,11 +665,13 @@
 		} else
 			error = EINVAL;
 #else /* CONFIG_BINFMT_ELF32 */
+		down(&current->mm->mmap_sem);
 		error = do_mmap(bprm->file, ELF_PAGESTART(load_bias + vaddr),
 		                (elf_ppnt->p_filesz +
 		                ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
 		                elf_prot, elf_flags, (elf_ppnt->p_offset -
 		                ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
+		up(&current->mm->mmap_sem);
 #endif /* CONFIG_BINFMT_ELF32 */
 
 		if (!load_addr_set) {
diff -urN linux-davidm/fs/lockd/xdr.c linux-2.4.0-test1-lia/fs/lockd/xdr.c
--- linux-davidm/fs/lockd/xdr.c	Sun Apr  2 15:31:32 2000
+++ linux-2.4.0-test1-lia/fs/lockd/xdr.c	Thu Jun  1 01:12:30 2000
@@ -86,7 +86,7 @@
 
 	if ((len = ntohl(*p++)) != NFS2_FHSIZE) {
 		printk(KERN_NOTICE
-			"lockd: bad fhandle size %x (should be %Zu)\n",
+			"lockd: bad fhandle size %x (should be %u)\n",
 			len, NFS2_FHSIZE);
 		return NULL;
 	}
diff -urN linux-davidm/fs/nfsd/nfscache.c linux-2.4.0-test1-lia/fs/nfsd/nfscache.c
--- linux-davidm/fs/nfsd/nfscache.c	Thu Jun  1 01:20:28 2000
+++ linux-2.4.0-test1-lia/fs/nfsd/nfscache.c	Thu Jun  1 01:12:41 2000
@@ -60,7 +60,7 @@
 	nfscache = (struct svc_cacherep *)
 		__get_free_pages(GFP_KERNEL, order);
 	if (!nfscache) {
-		printk (KERN_ERR "nfsd: cannot allocate %d bytes for reply cache\n", i);
+		printk (KERN_ERR "nfsd: cannot allocate %Zu bytes for reply cache\n", i);
 		return;
 	}
 	memset(nfscache, 0, i);
@@ -70,7 +70,7 @@
 	if (!hash_list) {
 		free_pages ((unsigned long)nfscache, order);
 		nfscache = NULL;
-		printk (KERN_ERR "nfsd: cannot allocate %d bytes for hash list\n", i);
+		printk (KERN_ERR "nfsd: cannot allocate %Zu bytes for hash list\n", i);
 		return;
 	}
 
diff -urN linux-davidm/fs/readdir.c linux-2.4.0-test1-lia/fs/readdir.c
--- linux-davidm/fs/readdir.c	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/fs/readdir.c	Thu Jun  1 01:30:33 2000
@@ -79,10 +79,6 @@
 	return 0;
 }
 
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
-#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
-
-#if !defined(__ia64__)
 /*
  * Traditional linux readdir() handling..
  *
@@ -91,6 +87,10 @@
  * anyway. Thus the special "fillonedir()" function for that
  * case (the low-level handlers don't need to care about this).
  */
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
+
+#ifndef __ia64__
 
 struct old_linux_dirent {
 	unsigned long	d_ino;
@@ -146,7 +146,7 @@
 	return error;
 }
 
-#endif /* !defined(__ia64__) */
+#endif /* !__ia64__ */
 
 /*
  * New, all-improved, singing, dancing, iBCS2-compliant getdents()
diff -urN linux-davidm/include/asm-ia64/pal.h linux-2.4.0-test1-lia/include/asm-ia64/pal.h
--- linux-davidm/include/asm-ia64/pal.h	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/include/asm-ia64/pal.h	Thu Jun  1 01:13:03 2000
@@ -4,11 +4,12 @@
 /*
  * Processor Abstraction Layer definitions.
  *
- * This is based on version 2.4 of the manual "Enhanced Mode Processor
- * Abstraction Layer".
+ * This is based on Intel IA-64 Architecture Software Developer's Manual rev 1.0
+ * chapter 11 IA-64 Processor Abstraction Layer
  *
  * Copyright (C) 1998-2000 Hewlett-Packard Co
  * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
  * Copyright (C) 1999 Srinivasa Prasad Thirumalachar <sprasad@sprasad.engr.sgi.com>
@@ -16,6 +17,8 @@
  * 99/10/01	davidm	Make sure we pass zero for reserved parameters.
  * 00/03/07	davidm	Updated pal_cache_flush() to be in sync with PAL v2.6.
  * 00/03/23     cfleck  Modified processor min-state save area to match updated PAL & SAL info
+ * 00/05/24     eranian Updated to latest PAL spec, fix structures bugs, added 
+ * 00/05/25	eranian Support for stack calls, and statis physical calls
  */
 
 /*
@@ -127,8 +130,8 @@
 typedef	union  pal_cache_config_info_1_s {
 	struct {
 		u64		u		: 1,	/* 0 Unified cache ? */
-				reserved	: 5,	/* 7-3 Reserved */
 				at		: 2,	/* 2-1 Cache mem attr*/
+				reserved	: 5,	/* 7-3 Reserved */
 				associativity	: 8,	/* 16-8 Associativity*/
 				line_size	: 8,	/* 23-17 Line size */
 				stride		: 8,	/* 31-24 Stride */
@@ -164,8 +167,8 @@
 	u64				pcci_reserved;
 } pal_cache_config_info_t;
 
-#define pcci_ld_hint		pcci_info_1.pcci1.load_hints
-#define pcci_st_hint		pcci_info_1.pcci1_bits.store_hints
+#define pcci_ld_hints		pcci_info_1.pcci1_bits.load_hints
+#define pcci_st_hints		pcci_info_1.pcci1_bits.store_hints
 #define pcci_ld_latency		pcci_info_1.pcci1_bits.load_latency
 #define pcci_st_latency		pcci_info_1.pcci1_bits.store_latency
 #define pcci_stride		pcci_info_1.pcci1_bits.stride
@@ -641,8 +644,12 @@
  * parameters.
  */
 extern struct ia64_pal_retval ia64_pal_call_static (u64, u64, u64, u64); 
+extern struct ia64_pal_retval ia64_pal_call_stacked (u64, u64, u64, u64); 
+extern struct ia64_pal_retval ia64_pal_call_phys_static (u64, u64, u64, u64); 
 
-#define PAL_CALL(iprv,a0,a1,a2,a3)	iprv = ia64_pal_call_static(a0,a1, a2, a3)
+#define PAL_CALL(iprv,a0,a1,a2,a3)	iprv = ia64_pal_call_static(a0, a1, a2, a3)
+#define PAL_CALL_STK(iprv,a0,a1,a2,a3)	iprv = ia64_pal_call_stacked(a0, a1, a2, a3)
+#define PAL_CALL_PHYS(iprv,a0,a1,a2,a3) iprv = ia64_pal_call_phys_static(a0, a1, a2, a3)
 
 typedef int (*ia64_pal_handler) (u64, ...);
 extern ia64_pal_handler ia64_pal;
@@ -702,7 +709,7 @@
 			   pal_bus_features_u_t *features_control)
 {
 	struct ia64_pal_retval iprv;
-	PAL_CALL(iprv, PAL_BUS_GET_FEATURES, 0, 0, 0);
+	PAL_CALL_PHYS(iprv, PAL_BUS_GET_FEATURES, 0, 0, 0);
 	if (features_avail)
 		features_avail->pal_bus_features_val = iprv.v0;
 	if (features_status)
@@ -711,15 +718,54 @@
 		features_control->pal_bus_features_val = iprv.v2;
 	return iprv.status;	
 }
+
 /* Enables/disables specific processor bus features */
 extern inline s64 
 ia64_pal_bus_set_features (pal_bus_features_u_t feature_select) 
 {	
 	struct ia64_pal_retval iprv;
-	PAL_CALL(iprv, PAL_BUS_SET_FEATURES, feature_select.pal_bus_features_val, 0, 0);
+	PAL_CALL_PHYS(iprv, PAL_BUS_SET_FEATURES, feature_select.pal_bus_features_val, 0, 0);
 	return iprv.status;
 }
 
+/* Get detailed cache information */
+extern inline s64
+ia64_pal_cache_config_info (u64 cache_level, u64 cache_type, pal_cache_config_info_t *conf)
+{
+	struct ia64_pal_retval iprv;
+
+	PAL_CALL(iprv, PAL_CACHE_INFO, cache_level, cache_type, 0); 
+
+	if (iprv.status = 0) {
+		conf->pcci_status                 = iprv.status;
+		conf->pcci_info_1.pcci1_data      = iprv.v0;
+		conf->pcci_info_2.pcci2_data      = iprv.v1;
+		conf->pcci_reserved               = iprv.v2;
+	}
+	return iprv.status; 
+
+}
+
+/* Get detailed cche protection information */
+extern inline s64
+ia64_pal_cache_prot_info (u64 cache_level, u64 cache_type, pal_cache_protection_info_t *prot)
+{
+	struct ia64_pal_retval iprv;
+
+	PAL_CALL(iprv, PAL_CACHE_PROT_INFO, cache_level, cache_type, 0); 
+
+	if (iprv.status = 0) {
+		prot->pcpi_status           = iprv.status;
+		prot->pcp_info[0].pcpi_data = iprv.v0 & 0xffffffff;
+		prot->pcp_info[1].pcpi_data = iprv.v0 >> 32;
+		prot->pcp_info[2].pcpi_data = iprv.v1 & 0xffffffff;
+		prot->pcp_info[3].pcpi_data = iprv.v1 >> 32;
+		prot->pcp_info[4].pcpi_data = iprv.v2 & 0xffffffff;
+		prot->pcp_info[5].pcpi_data = iprv.v2 >> 32;
+	}
+	return iprv.status; 
+}
+ 
 /*
  * Flush the processor instruction or data caches.  *PROGRESS must be
  * initialized to zero before calling this for the first time..
@@ -895,7 +941,10 @@
 	struct {
 	       u64		exit_latency		: 16,
 				entry_latency		: 16,
-				power_consumption	: 32;
+				power_consumption	: 28,
+				im			: 1,
+				co			: 1,
+				reserved		: 2;
 	} pal_power_mgmt_info_s;
 } pal_power_mgmt_info_u_t;
 
@@ -904,7 +953,7 @@
 ia64_pal_halt_info (pal_power_mgmt_info_u_t *power_buf) 
 {	
 	struct ia64_pal_retval iprv;
-	PAL_CALL(iprv, PAL_HALT_INFO, (unsigned long) power_buf, 0, 0);
+	PAL_CALL_STK(iprv, PAL_HALT_INFO, (unsigned long) power_buf, 0, 0);
 	return iprv.status; 
 }
 
@@ -1013,7 +1062,7 @@
 	struct ia64_pal_retval iprv;
 	PAL_CALL(iprv, PAL_MEM_ATTRIB, 0, 0, 0);
 	if (mem_attrib)
-		*mem_attrib = iprv.v0;
+		*mem_attrib = iprv.v0 & 0xff;
 	return iprv.status; 
 }
 
@@ -1076,28 +1125,32 @@
 	return iprv.status; 
 }
 
-#ifdef TBD
 struct pal_features_s;
 /* Provide information about configurable processor features */
 extern inline s64 
-ia64_pal_proc_get_features (struct pal_features_s *features_avail, 
-			    struct pal_features_s *features_status, 
-			    struct pal_features_s *features_control)
+ia64_pal_proc_get_features (u64 *features_avail, 
+			    u64 *features_status, 
+			    u64 *features_control)
 {	
 	struct ia64_pal_retval iprv;
-	PAL_CALL(iprv, PAL_PROC_GET_FEATURES, 0, 0, 0);
+	PAL_CALL_PHYS(iprv, PAL_PROC_GET_FEATURES, 0, 0, 0);
+	if (iprv.status = 0) {
+		*features_avail   = iprv.v0;
+		*features_status  = iprv.v1;
+		*features_control = iprv.v2;
+	}
 	return iprv.status; 
 }
+
 /* Enable/disable processor dependent features */
 extern inline s64 
-ia64_pal_proc_set_features (feature_select) 
+ia64_pal_proc_set_features (u64 feature_select) 
 {	
 	struct ia64_pal_retval iprv;
-	PAL_CALL(iprv, PAL_PROC_SET_FEATURES, feature_select, 0, 0);
+	PAL_CALL_PHYS(iprv, PAL_PROC_SET_FEATURES, feature_select, 0, 0);
 	return iprv.status; 
 }
 
-#endif 
 /*
  * Put everything in a struct so we avoid the global offset table whenever
  * possible.
@@ -1206,12 +1259,16 @@
 
 /* Return PAL version information */
 extern inline s64 
-ia64_pal_version (pal_version_u_t *pal_version) 
+ia64_pal_version (pal_version_u_t *pal_min_version, pal_version_u_t *pal_cur_version) 
 {	
 	struct ia64_pal_retval iprv;
 	PAL_CALL(iprv, PAL_VERSION, 0, 0, 0);
-	if (pal_version)
-		pal_version->pal_version_val = iprv.v0;
+	if (pal_min_version)
+		pal_min_version->pal_version_val = iprv.v0;
+
+	if (pal_cur_version)
+		pal_cur_version->pal_version_val = iprv.v1;
+
 	return iprv.status; 
 }
 
@@ -1228,7 +1285,14 @@
 	} pal_tc_info_s;
 } pal_tc_info_u_t;				
 				
-	       
+#define tc_reduce_tr		pal_tc_info_s.reduce_tr
+#define tc_unified		pal_tc_info_s.unified
+#define tc_pf			pal_tc_info_s.pf
+#define tc_num_entries		pal_tc_info_s.num_entries
+#define tc_associativity	pal_tc_info_s.associativity
+#define tc_num_sets		pal_tc_info_s.num_sets
+
+
 /* Return information about the virtual memory characteristics of the processor 
  * implementation.
  */
@@ -1264,7 +1328,7 @@
 	struct {
 		u64		vw		: 1,
 				phys_add_size	: 7,
-				key_size	: 16,
+				key_size	: 8,
 				max_pkr		: 8,
 				hash_tag_id	: 8,
 				max_dtr_entry	: 8,
diff -urN linux-davidm/include/asm-ia64/pgtable.h linux-2.4.0-test1-lia/include/asm-ia64/pgtable.h
--- linux-davidm/include/asm-ia64/pgtable.h	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/include/asm-ia64/pgtable.h	Thu Jun  1 01:14:01 2000
@@ -16,23 +16,16 @@
 
 #include <asm/mman.h>
 #include <asm/page.h>
+#include <asm/processor.h>
 #include <asm/types.h>
 
-/* Size of virtuaql and physical address spaces: */
-#ifdef CONFIG_ITANIUM
-# define IA64_IMPL_VA_MSB	50
-# define IA64_PHYS_BITS		44		/* Itanium PRM defines 44 bits of ppn */
-#else
-# define IA64_IMPL_VA_MSB	60		/* maximum value (bits 61-63 are region bits) */
-# define IA64_PHYS_BITS		50		/* EAS2.6 allows up to 50 bits of ppn */
-#endif
-#define IA64_PHYS_SIZE		(__IA64_UL(1) << IA64_PHYS_BITS)
+#define IA64_MAX_PHYS_BITS	50	/* max. number of physical address bits (architected) */
 
 /* Is ADDR a valid kernel address? */
 #define kern_addr_valid(addr)	((addr) >= TASK_SIZE)
 
 /* Is ADDR a valid physical address? */
-#define phys_addr_valid(addr)	((addr) < IA64_PHYS_SIZE)
+#define phys_addr_valid(addr)	(((addr) & my_cpu_data.unimpl_pa_mask) = 0)
 
 /*
  * First, define the various bits in a PTE.  Note that the PTE format
@@ -63,7 +56,7 @@
 #define _PAGE_AR_SHIFT		9
 #define _PAGE_A			(1 <<  5)	/* page accessed bit */
 #define _PAGE_D			(1 <<  6)	/* page dirty bit */
-#define _PAGE_PPN_MASK		((IA64_PHYS_SIZE - 1) & ~0xfffUL)
+#define _PAGE_PPN_MASK		(((__IA64_UL(1) << IA64_MAX_PHYS_BITS) - 1) & ~0xfffUL)
 #define _PAGE_ED		(__IA64_UL(1) << 52)	/* exception deferral */
 #define _PAGE_PROTNONE		(__IA64_UL(1) << 63)
 
diff -urN linux-davidm/include/asm-ia64/processor.h linux-2.4.0-test1-lia/include/asm-ia64/processor.h
--- linux-davidm/include/asm-ia64/processor.h	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/include/asm-ia64/processor.h	Thu Jun  1 01:14:12 2000
@@ -237,6 +237,8 @@
 	__u64 proc_freq;	/* frequency of processor */
 	__u64 cyc_per_usec;	/* itc_freq/1000000 */
 	__u64 usec_per_cyc;	/* 2^IA64_USEC_PER_CYC_SHIFT*1000000/itc_freq */
+	__u64 unimpl_va_mask;	/* mask of unimplemented virtual address bits (from PAL) */
+	__u64 unimpl_pa_mask;	/* mask of unimplemented physical address bits (from PAL) */
 #ifdef CONFIG_SMP
 	__u64 loops_per_sec;
 	__u64 ipi_count;
diff -urN linux-davidm/include/asm-ia64/string.h linux-2.4.0-test1-lia/include/asm-ia64/string.h
--- linux-davidm/include/asm-ia64/string.h	Sun Feb  6 18:42:40 2000
+++ linux-2.4.0-test1-lia/include/asm-ia64/string.h	Thu Jun  1 01:14:24 2000
@@ -12,4 +12,7 @@
 #define __HAVE_ARCH_STRLEN	1 /* see arch/ia64/lib/strlen.S */
 #define __HAVE_ARCH_MEMSET	1 /* see arch/ia64/lib/memset.S */
 
+extern __kernel_size_t strlen (const char *);
+extern void *memset (void *,int,__kernel_size_t);
+
 #endif /* _ASM_IA64_STRING_H */
diff -urN linux-davidm/include/asm-ia64/system.h linux-2.4.0-test1-lia/include/asm-ia64/system.h
--- linux-davidm/include/asm-ia64/system.h	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/include/asm-ia64/system.h	Thu Jun  1 01:14:34 2000
@@ -135,7 +135,7 @@
 do {									 \
 	unsigned long ip, old_psr, psr = (x);				 \
 									 \
-	__asm__ __volatile__ ("mov %0=psr; mov psr.l=%1;; srlz.d"	 \
+	__asm__ __volatile__ (";;mov %0=psr; mov psr.l=%1;; srlz.d"	 \
 			      : "=&r" (old_psr) : "r" (psr) : "memory"); \
 	if ((old_psr & (1UL << 14)) && !(psr & (1UL << 14))) {		 \
 		__asm__ ("mov %0=ip" : "=r"(ip));			 \
@@ -149,7 +149,7 @@
 						      : "=r" (x) :: "memory")
 # define local_irq_disable()	__asm__ __volatile__ (";; rsm psr.i;;" ::: "memory")
 /* (potentially) setting psr.i requires data serialization: */
-# define local_irq_restore(x)	__asm__ __volatile__ ("mov psr.l=%0;; srlz.d"		\
+# define local_irq_restore(x)	__asm__ __volatile__ (";; mov psr.l=%0;; srlz.d"	\
 						      :: "r" (x) : "memory")
 #endif /* !CONFIG_IA64_DEBUG_IRQ */
 
diff -urN linux-davidm/include/asm-ia64/unwind.h linux-2.4.0-test1-lia/include/asm-ia64/unwind.h
--- linux-davidm/include/asm-ia64/unwind.h	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/include/asm-ia64/unwind.h	Thu Jun  1 01:14:42 2000
@@ -48,7 +48,9 @@
 struct unw_frame_info {
 	struct unw_stack regstk;
 	struct unw_stack memstk;
-	unsigned long flags;
+	unsigned int flags;
+	short hint;
+	short prev_script;
 	unsigned long bsp;
 	unsigned long sp;		/* stack pointer */
 	unsigned long psp;		/* previous sp */
diff -urN linux-davidm/init/main.c linux-2.4.0-test1-lia/init/main.c
--- linux-davidm/init/main.c	Thu Jun  1 01:38:40 2000
+++ linux-2.4.0-test1-lia/init/main.c	Thu Jun  1 01:15:49 2000
@@ -572,7 +572,6 @@
 #endif
 	mem_init();
 	kmem_cache_sizes_init();
-	unw_init();		/* XXX remove reliance on kmalloc and move to setup_arch() */
 #ifdef CONFIG_PERFMON
 	perfmon_init();
 #endif



^ permalink raw reply	[flat|nested] 217+ messages in thread

end of thread, other threads:[~2003-04-15 22:27 UTC | newest]

Thread overview: 217+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2000-06-01  8:54 [Linux-ia64] kernel update (relative to v2.4.0-test1) David Mosberger
2000-06-03 17:32 ` Manfred Spraul
2000-06-10  1:07 ` David Mosberger
2000-06-10  1:11 ` David Mosberger
2000-07-14 21:37 ` [Linux-ia64] kernel update (relative to 2.4.0-test4) David Mosberger
2000-08-12  5:02 ` [Linux-ia64] kernel update (relative to v2.4.0-test6) David Mosberger
2000-08-14 11:35 ` Andreas Schwab
2000-08-14 17:00 ` David Mosberger
2000-09-09  6:51 ` [Linux-ia64] kernel update (relative to v2.4.0-test8) David Mosberger
2000-09-09 19:07 ` H . J . Lu
2000-09-09 20:49 ` David Mosberger
2000-09-09 21:25 ` Uros Prestor
2000-09-09 21:33 ` H . J . Lu
2000-09-09 21:45 ` David Mosberger
2000-09-09 21:49 ` H . J . Lu
2000-09-10  0:17 ` David Mosberger
2000-09-10  0:24 ` Uros Prestor
2000-09-10  0:39 ` H . J . Lu
2000-09-10  0:57 ` H . J . Lu
2000-09-10 15:47 ` H . J . Lu
2000-09-14  1:50 ` David Mosberger
2000-10-05 19:01 ` [Linux-ia64] kernel update (relative to v2.4.0-test9) David Mosberger
2000-10-05 22:08 ` Keith Owens
2000-10-05 22:15 ` David Mosberger
2000-10-31  8:55 ` [Linux-ia64] kernel update (relative to 2.4.0-test9) David Mosberger
2000-11-02  8:50 ` [Linux-ia64] kernel update (relative to 2.4.0-test10) David Mosberger
2000-11-02 10:39 ` Pimenov, Sergei
2000-11-16  7:59 ` David Mosberger
2000-12-07  8:26 ` [Linux-ia64] kernel update (relative to 2.4.0-test11) David Mosberger
2000-12-07 21:57 ` David Mosberger
2000-12-15  5:00 ` [Linux-ia64] kernel update (relative to 2.4.0-test12) David Mosberger
2000-12-15 22:43 ` Nathan Straz
2001-01-09  9:48 ` [Linux-ia64] kernel update (relative to 2.4.0) David Mosberger
2001-01-09 11:05 ` Sapariya Manish.j
2001-01-10  3:26 ` [Linux-ia64] kernel update (relative to 2.4.0) - copy_user fi Mallick, Asit K
2001-01-12  2:30 ` [Linux-ia64] kernel update (relative to 2.4.0) Jim Wilson
2001-01-26  4:53 ` David Mosberger
2001-01-31 20:32 ` [Linux-ia64] kernel update (relative to 2.4.1) David Mosberger
2001-03-01  7:12 ` [Linux-ia64] kernel update (relative to 2.4.2) David Mosberger
2001-03-01 10:17 ` Andreas Schwab
2001-03-01 10:27 ` Andreas Schwab
2001-03-01 15:29 ` David Mosberger
2001-03-02 12:26 ` Keith Owens
2001-05-09  4:52 ` [Linux-ia64] kernel update (relative to 2.4.4) Keith Owens
2001-05-09  5:07 ` David Mosberger
2001-05-09 11:45 ` Keith Owens
2001-05-09 13:38 ` Jack Steiner
2001-05-09 14:06 ` David Mosberger
2001-05-09 14:21 ` Jack Steiner
2001-05-10  4:14 ` David Mosberger
2001-05-31  7:37 ` [Linux-ia64] kernel update (relative to 2.4.5) David Mosberger
2001-06-27  7:09 ` David Mosberger
2001-06-27 17:24 ` Richard Hirst
2001-06-27 18:10 ` Martin Wilck
2001-07-23 23:49 ` [Linux-ia64] kernel update (relative to 2.4.7) David Mosberger
2001-07-24  1:50 ` Keith Owens
2001-07-24  3:02 ` Keith Owens
2001-07-24 16:37 ` Andreas Schwab
2001-07-24 18:42 ` David Mosberger
2001-08-14  8:15 ` [Linux-ia64] kernel update (relative to 2.4.8) Chris Ahna
2001-08-14  8:19 ` David Mosberger
2001-08-14  8:51 ` Keith Owens
2001-08-14 15:48 ` David Mosberger
2001-08-14 16:23 ` Don Dugger
2001-08-14 17:06 ` David Mosberger
2001-08-15  0:22 ` Keith Owens
2001-08-21  3:55 ` [Linux-ia64] kernel update (relative to 2.4.9) David Mosberger
2001-08-22 10:00 ` Andreas Schwab
2001-08-22 17:42 ` Chris Ahna
2001-09-25  7:13 ` [Linux-ia64] kernel update (relative to 2.4.10) David Mosberger
2001-09-25  7:17 ` David Mosberger
2001-09-25 12:17 ` Andreas Schwab
2001-09-25 15:14 ` Andreas Schwab
2001-09-25 15:45 ` Andreas Schwab
2001-09-26 22:49 ` David Mosberger
2001-09-26 22:51 ` David Mosberger
2001-09-27  4:57 ` Keith Owens
2001-09-27 17:48 ` David Mosberger
2001-10-02  5:20 ` Keith Owens
2001-10-02  5:50 ` Keith Owens
2001-10-11  2:47 ` [Linux-ia64] kernel update (relative to 2.4.11) David Mosberger
2001-10-11  4:39 ` Keith Owens
2001-10-25  4:27 ` [Linux-ia64] kernel update (relative to 2.4.13) David Mosberger
2001-10-25  4:30 ` David Mosberger
2001-10-25  5:26 ` Keith Owens
2001-10-25  6:21 ` Keith Owens
2001-10-25  6:44 ` Christoph Hellwig
2001-10-25 19:55 ` Luck, Tony
2001-10-25 20:20 ` David Mosberger
2001-10-26 14:36 ` Andreas Schwab
2001-10-30  2:20 ` David Mosberger
2001-11-02  1:35 ` William Lee Irwin III
2001-11-06  1:23 ` David Mosberger
2001-11-06  6:59 ` [Linux-ia64] kernel update (relative to 2.4.14) David Mosberger
2001-11-07  1:48 ` Keith Owens
2001-11-07  2:47 ` David Mosberger
2001-11-27  5:24 ` [Linux-ia64] kernel update (relative to 2.4.16) David Mosberger
2001-11-27 13:04 ` Andreas Schwab
2001-11-27 17:02 ` John Hesterberg
2001-11-27 22:03 ` John Hesterberg
2001-11-29  0:41 ` David Mosberger
2001-12-05 15:25 ` [Linux-ia64] kernel update (relative to 2.4.10) n0ano
2001-12-15  5:13 ` [Linux-ia64] kernel update (relative to 2.4.16) David Mosberger
2001-12-15  8:12 ` Keith Owens
2001-12-16 12:21 ` [Linux-ia64] kernel update (relative to 2.4.10) Zach, Yoav
2001-12-17 17:11 ` n0ano
2001-12-26 21:15 ` [Linux-ia64] kernel update (relative to 2.4.16) David Mosberger
2001-12-27  6:38 ` [Linux-ia64] kernel update (relative to v2.4.17) David Mosberger
2001-12-27  8:09 ` j-nomura
2001-12-27 21:59 ` Christian Groessler
2001-12-31  3:13 ` Matt_Domsch
2002-01-07 11:30 ` j-nomura
2002-02-08  7:02 ` [Linux-ia64] kernel update (relative to 2.5.3) David Mosberger
2002-02-27  1:47 ` [Linux-ia64] kernel update (relative to 2.4.18) David Mosberger
2002-02-28  4:40 ` Peter Chubb
2002-02-28 19:19 ` David Mosberger
2002-03-06 22:33 ` Peter Chubb
2002-03-08  6:38 ` [Linux-ia64] kernel update (relative to 2.5.5) David Mosberger
2002-03-09 11:08 ` Keith Owens
2002-04-26  7:15 ` [Linux-ia64] kernel update (relative to v2.5.10) David Mosberger
2002-05-31  6:08 ` [Linux-ia64] kernel update (relative to v2.5.18) David Mosberger
2002-06-06  2:01 ` Peter Chubb
2002-06-06  3:16 ` David Mosberger
2002-06-07 21:54 ` Bjorn Helgaas
2002-06-07 22:07 ` Bjorn Helgaas
2002-06-09 10:34 ` Steffen Persvold
2002-06-14  3:12 ` Peter Chubb
2002-06-22  8:57 ` [Linux-ia64] kernel update (relative to 2.4.18) David Mosberger
2002-06-22  9:25 ` David Mosberger
2002-06-22 10:05 ` Steffen Persvold
2002-06-22 19:03 ` David Mosberger
2002-06-22 19:33 ` Andreas Schwab
2002-07-08 22:08 ` Kimio Suganuma
2002-07-08 22:14 ` David Mosberger
2002-07-20  7:08 ` [Linux-ia64] kernel update (relative to v2.4.18) David Mosberger
2002-07-22 11:54 ` Andreas Schwab
2002-07-22 12:31 ` Keith Owens
2002-07-22 12:34 ` Andreas Schwab
2002-07-22 12:54 ` Keith Owens
2002-07-22 18:05 ` David Mosberger
2002-07-22 23:54 ` Kimio Suganuma
2002-07-23  1:00 ` Keith Owens
2002-07-23  1:10 ` David Mosberger
2002-07-23  1:21 ` Matthew Wilcox
2002-07-23  1:28 ` David Mosberger
2002-07-23  1:35 ` Grant Grundler
2002-07-23  3:09 ` Keith Owens
2002-07-23  5:04 ` David Mosberger
2002-07-23  5:58 ` Keith Owens
2002-07-23  6:15 ` David Mosberger
2002-07-23 12:09 ` Andreas Schwab
2002-07-23 15:38 ` Wichmann, Mats D
2002-07-23 16:17 ` David Mosberger
2002-07-23 16:28 ` David Mosberger
2002-07-23 16:30 ` David Mosberger
2002-07-23 18:08 ` KOCHI, Takayoshi
2002-07-23 19:17 ` Andreas Schwab
2002-07-24  4:30 ` KOCHI, Takayoshi
2002-08-22 13:42 ` [Linux-ia64] kernel update (relative to 2.4.19) Bjorn Helgaas
2002-08-22 14:22 ` Wichmann, Mats D
2002-08-22 15:29 ` Bjorn Helgaas
2002-08-23  4:52 ` KOCHI, Takayoshi
2002-08-23 10:10 ` Andreas Schwab
2002-08-30  5:42 ` [Linux-ia64] kernel update (relative to v2.5.32) David Mosberger
2002-08-30 17:26 ` KOCHI, Takayoshi
2002-08-30 19:00 ` David Mosberger
2002-09-18  3:25 ` Peter Chubb
2002-09-18  3:32 ` David Mosberger
2002-09-18  6:54 ` [Linux-ia64] kernel update (relative to 2.5.35) David Mosberger
2002-09-28 21:48 ` [Linux-ia64] kernel update (relative to 2.5.39) David Mosberger
2002-09-30 23:28 ` Peter Chubb
2002-09-30 23:49 ` David Mosberger
2002-10-01  4:26 ` Peter Chubb
2002-10-01  5:19 ` David Mosberger
2002-10-03  2:33 ` Jes Sorensen
2002-10-03  2:46 ` KOCHI, Takayoshi
2002-10-13 23:39 ` Peter Chubb
2002-10-17 11:46 ` Jes Sorensen
2002-11-01  6:18 ` [Linux-ia64] kernel update (relative to 2.5.45) David Mosberger
2002-12-11  4:44 ` [Linux-ia64] kernel update (relative to 2.4.20) Bjorn Helgaas
2002-12-12  2:00 ` Matthew Wilcox
2002-12-13 17:36 ` Bjorn Helgaas
2002-12-21  9:00 ` [Linux-ia64] kernel update (relative to 2.5.52) David Mosberger
2002-12-26  6:07 ` Kimio Suganuma
2003-01-02 21:27 ` David Mosberger
2003-01-25  5:02 ` [Linux-ia64] kernel update (relative to 2.5.59) David Mosberger
2003-01-25 20:19 ` Sam Ravnborg
2003-01-27 18:47 ` David Mosberger
2003-01-28 19:44 ` Arun Sharma
2003-01-28 19:55 ` David Mosberger
2003-01-28 21:34 ` Arun Sharma
2003-01-28 23:09 ` David Mosberger
2003-01-29  4:27 ` Peter Chubb
2003-01-29  6:07 ` David Mosberger
2003-01-29 14:06 ` Erich Focht
2003-01-29 17:10 ` Luck, Tony
2003-01-29 17:48 ` Paul Bame
2003-01-29 19:08 ` David Mosberger
2003-02-12 23:26 ` [Linux-ia64] kernel update (relative to 2.5.60) David Mosberger
2003-02-13  5:52 ` j-nomura
2003-02-13 17:53 ` Grant Grundler
2003-02-13 18:36 ` David Mosberger
2003-02-13 19:17 ` Grant Grundler
2003-02-13 20:00 ` David Mosberger
2003-02-13 20:11 ` Grant Grundler
2003-02-18 19:52 ` Jesse Barnes
2003-03-07  8:19 ` [Linux-ia64] kernel update (relative to v2.5.64) David Mosberger
2003-04-12  4:28 ` [Linux-ia64] kernel update (relative to v2.5.67) David Mosberger
2003-04-14 12:55 ` Takayoshi Kochi
2003-04-14 17:00 ` Howell, David P
2003-04-14 18:45 ` David Mosberger
2003-04-14 20:56 ` Alex Williamson
2003-04-14 22:13 ` Howell, David P
2003-04-15  9:01 ` Takayoshi Kochi
2003-04-15 22:03 ` David Mosberger
2003-04-15 22:12 ` Alex Williamson
2003-04-15 22:27 ` David Mosberger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox