public inbox for linux-ia64@vger.kernel.org
 help / color / mirror / Atom feed
* [Linux-ia64] kernel update [relative to 2.4.0-test4]
@ 2000-07-29  7:41 David Mosberger
  2000-07-30 17:27 ` Mallick, Asit K
  2000-07-31 10:03 ` Andreas Schwab
  0 siblings, 2 replies; 4+ messages in thread
From: David Mosberger @ 2000-07-29  7:41 UTC (permalink / raw)
  To: linux-ia64

Here is the latest kernel update.  Before I go on, two major caveats:

 BIG CAVEAT
	To run this kernel on a system with a SCSI controller that
	uses the PCI DMA interface (e.g, adaptec), you'll have to
	specific boot option mem=4G to force the kernel to ignore
	memory above 4GB.  This is a temporary issue and will be fixed
	in the next version.

 BIG CAVEAT
	This kernel will work fine with the qla1280 SCSI driver, even
	if there is memory above 4GB.  However, you must make sure
	that "64 bit addressing" is enabled in the Qlogic BIOS setup
	(press "Alt-Q" during system initialization to get into the
	SCSI controller configuration menu).  If your system is unable
	to mount the root filesystem, chances are you forgot to
	do this.

OK, having said that, here are the major goodies:

 - Support for software I/O TLB is in, thanks to Goutham and Asit
   (Intel).  This support allows to DMA from 32-bit PCI devices to any
   place in the physical memory.  However, the transfer size is
   currently limited to one page and this is the reason SCSI drivers
   such as the adaptec drivers do not work yet.

 - Bumped HZ to 1024.  Yeah, I still owe you guys some performance
   measurements, but it's the right thing to do anyhow, trust me. ;-)

 - Thanks to Stephane, /proc/palinfo now sports SMP support and has
   been renamed to /proc/pal.  There are also a couple of new entries,
   such as bus_info and tr_info.

 - GENERIC build fixes from Kanoj and yours truly.  Generic kernels
   should build again.

 - IA-32 fixes from Don and Kanoj.

 - New kernel option "mem=MEMLIMIT" to tell the kernel to ignore
   memory above MEMLIMIT.  Note that this option does not set the
   memory _size_ (as is the case on x86), it sets the _limit_ (which
   was easier to implement---render me lazy).  You can use "G", "M"
   or "K" to express the memory limit as giga-, mega-, or kilobytes
   (i.e., mem=4G ignore memory above 4gig).

 - Fixed a silly typo in the ITLB handler (thanks to Asit for catching
   this!).  It didn't really hurt much as that handler gets almost
   never used.

 - Removed backwards compatibility for the old system call break
   number (0x80000).  Shame on you if you're still using binaries with
   that very old number (none of the IA-64 Linux distributions ever
   did this).

 - Support for making physical stacked PAL calls is in (also by Stephane).

 - psr.mfh bit is now maintained more accurately, which avoids a
   potential problem on SMP and also should give better performance in
   certain cases.  Dan, if you want to use the fp-based memcpy routine
   for libc, you could now check if psr.mfh is on and, if so, you know
   the fph partition is in use alrady

 - Disabled the "lost timer tick" message; that message always was
   misleading, as no ticks are actually lost; with the newer steppings
   of the CPU, the whole issue of lost timer interrupts is pretty much
   gone anyhow.

 - Some SN1 updated (Kanoj)

 - eepro100 updats to make it _really_ work with the PCI DMA api
   (Ganesh).

 - Stephane Zeisset's fix for fs/buffer.c to avoid data corruption
   when copying to vfat filesystem (this is already in Linus's test5)

 - Added missing __raw_writel (pointed out by Bill, IIRC)

That should be it.  As usual, the relative diff below shows what
changed since the last IA-64 kernel update and is for informational
purposes only.  The full kernel diff is in
linux-2.4.0-test4-ia64-000728.diff.gz at:

	ftp://ftp.kernel.org/pub/linux/kernel/ports/ia64/

Enjoy,

	--david

diff -urN linux-davidm/Documentation/DMA-mapping.txt
linux-2.4.0-test4-lia/Documentation/DMA-mapping.txt ---
linux-davidm/Documentation/DMA-mapping.txt Tue Apr 25 17:52:05 2000
+++ linux-2.4.0-test4-lia/Documentation/DMA-mapping.txt Fri Jul 28
22:51:03 2000 @@ -341,7 +341,7 @@ struct my_card_header *hp;
 
 			/* Examine the header to see if we wish
-			 * to except the data.  But synchronize
+			 * to accept the data.  But synchronize
 			 * the DMA transfer with the CPU first
 			 * so that we see updated contents.
 			 */
diff -urN linux-davidm/Makefile linux-2.4.0-test4-lia/Makefile
--- linux-davidm/Makefile	Fri Jul 28 23:48:24 2000
+++ linux-2.4.0-test4-lia/Makefile	Fri Jul 14 15:07:13 2000
@@ -365,7 +365,6 @@
 clean:	archclean
 	rm -f kernel/ksyms.lst include/linux/compile.h
 	find . -name '*.[oas]' -type f -print | grep -v lxdialog/ | xargs rm -f
-	rm -f ksym.[ch] dummy_sym.c System.map.sv map map.out
 	rm -f core `find . -type f -name 'core' -print`
 	rm -f core `find . -type f -name '.*.flags' -print`
 	rm -f vmlinux System.map
diff -urN linux-davidm/arch/ia64/config.in linux-2.4.0-test4-lia/arch/ia64/config.in
--- linux-davidm/arch/ia64/config.in	Fri Jul 28 23:48:24 2000
+++ linux-2.4.0-test4-lia/arch/ia64/config.in	Fri Jul 28 22:53:08 2000
@@ -18,6 +18,7 @@
 comment 'General setup'
 
 define_bool CONFIG_IA64 y
+define_bool CONFIG_SWIOTLB y	# for now...
 
 define_bool CONFIG_ISA n
 define_bool CONFIG_SBUS n
@@ -39,15 +40,12 @@
 	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 Itanium B0-step specific code' CONFIG_ITANIUM_B0_SPECIFIC
 	bool '  Enable use of global TLB purge instruction (ptc.g)' CONFIG_ITANIUM_PTCG
 	bool '  Enable SoftSDV hacks' CONFIG_IA64_SOFTSDV_HACKS
 	bool '  Enable AzusA hacks' CONFIG_IA64_AZUSA_HACKS
 	bool '  Emulate PAL/SAL/EFI firmware' CONFIG_IA64_FW_EMU
 	bool '  Enable IA64 Machine Check Abort' CONFIG_IA64_MCA
-fi
-
-if [ "$CONFIG_IA64_GENERIC" = "y" ]; then
-	define_bool CONFIG_IA64_SOFTSDV_HACKS y
 fi
 
 if [ "$CONFIG_IA64_SGI_SN1_SIM" = "y" ]; then
diff -urN linux-davidm/arch/ia64/dig/iosapic.c linux-2.4.0-test4-lia/arch/ia64/dig/iosapic.c
--- linux-davidm/arch/ia64/dig/iosapic.c	Thu Jun 22 07:09:44 2000
+++ linux-2.4.0-test4-lia/arch/ia64/dig/iosapic.c	Fri Jul 28 22:56:36 2000
@@ -22,12 +22,14 @@
 #include <linux/string.h>
 #include <linux/irq.h>
 
+#include <asm/acpi-ext.h>
+#include <asm/delay.h>
 #include <asm/io.h>
 #include <asm/iosapic.h>
+#include <asm/machvec.h>
+#include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/system.h>
-#include <asm/delay.h>
-#include <asm/processor.h>
 
 #undef DEBUG_IRQ_ROUTING
 
@@ -315,10 +317,6 @@
 	 */
 	outb(0xff, 0xA1);
 	outb(0xff, 0x21);
-
-#ifndef CONFIG_IA64_DIG
-	iosapic_init(IO_SAPIC_DEFAULT_ADDR);
-#endif
 }
 
 void
@@ -337,15 +335,23 @@
 			if (irq < 0 && dev->bus->parent) { /* go back to the bridge */
 				struct pci_dev * bridge = dev->bus->self;
 
-				/* do the bridge swizzle... */
-				pin = (pin + PCI_SLOT(dev->devfn)) % 4;
-				irq = iosapic_get_PCI_irq_vector(bridge->bus->number,
-								 PCI_SLOT(bridge->devfn), pin);
+				/* allow for multiple bridges on an adapter */
+				do {
+					/* do the bridge swizzle... */
+					pin = (pin + PCI_SLOT(dev->devfn)) % 4;
+					irq = iosapic_get_PCI_irq_vector(bridge->bus->number,
+									 PCI_SLOT(bridge->devfn), pin);
+				} while (irq < 0 && (bridge = bridge->bus->self));
 				if (irq >= 0)
 					printk(KERN_WARNING
 					       "PCI: using PPB(B%d,I%d,P%d) to get irq %02x\n",
 					       bridge->bus->number, PCI_SLOT(bridge->devfn),
 					       pin, irq);
+				else
+					printk(KERN_WARNING
+					       "PCI: Couldn't map irq for B%d,I%d,P%d\n",
+					       bridge->bus->number, PCI_SLOT(bridge->devfn),
+					       pin);
 			}
 			if (irq >= 0) {
 				printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %02x\n",
@@ -360,4 +366,35 @@
 		if (dev->irq >= NR_IRQS)
 			dev->irq = 15;	/* Spurious interrupts */
 	}
+}
+
+/*
+ * Register an IOSAPIC discovered via ACPI.
+ */
+void __init
+dig_register_iosapic (acpi_entry_iosapic_t *iosapic)
+{
+	unsigned int ver, v;
+	int l, max_pin;
+
+	ver = iosapic_version(iosapic->address);
+	max_pin = (ver >> 16) & 0xff;
+	
+	printk("IOSAPIC Version %x.%x: address 0x%lx IRQs 0x%x - 0x%x\n", 
+	       (ver & 0xf0) >> 4, (ver & 0x0f), iosapic->address, 
+	       iosapic->irq_base, iosapic->irq_base + max_pin);
+	
+	for (l = 0; l <= max_pin; l++) {
+		v = iosapic->irq_base + l;
+		if (v < 16)
+			v = isa_irq_to_vector(v);
+		if (v > IA64_MAX_VECTORED_IRQ) {
+			printk("    !!! bad IOSAPIC interrupt vector: %u\n", v);
+			continue;
+		}
+		/* XXX Check for IOSAPIC collisions */
+		iosapic_addr(v) = (unsigned long) ioremap(iosapic->address, 0);
+		iosapic_baseirq(v) = iosapic->irq_base;
+	}
+	iosapic_init(iosapic->address, iosapic->irq_base);
 }
diff -urN linux-davidm/arch/ia64/dig/machvec.c linux-2.4.0-test4-lia/arch/ia64/dig/machvec.c
--- linux-davidm/arch/ia64/dig/machvec.c	Sun Feb  6 18:42:40 2000
+++ linux-2.4.0-test4-lia/arch/ia64/dig/machvec.c	Fri Jul 28 22:56:47 2000
@@ -1,4 +1,2 @@
+#define MACHVEC_PLATFORM_NAME	dig
 #include <asm/machvec_init.h>
-#include <asm/machvec_dig.h>
-
-MACHVEC_DEFINE(dig)
diff -urN linux-davidm/arch/ia64/hp/hpsim_machvec.c linux-2.4.0-test4-lia/arch/ia64/hp/hpsim_machvec.c
--- linux-davidm/arch/ia64/hp/hpsim_machvec.c	Sun Feb  6 18:42:40 2000
+++ linux-2.4.0-test4-lia/arch/ia64/hp/hpsim_machvec.c	Fri Jul 28 22:56:57 2000
@@ -1,4 +1,2 @@
+#define MACHVEC_PLATFORM_NAME	hpsim
 #include <asm/machvec_init.h>
-#include <asm/machvec_hpsim.h>
-
-MACHVEC_DEFINE(hpsim)
diff -urN linux-davidm/arch/ia64/ia32/ia32_entry.S linux-2.4.0-test4-lia/arch/ia64/ia32/ia32_entry.S
--- linux-davidm/arch/ia64/ia32/ia32_entry.S	Fri Jul 28 23:48:24 2000
+++ linux-2.4.0-test4-lia/arch/ia64/ia32/ia32_entry.S	Fri Jul 28 22:57:12 2000
@@ -105,7 +105,7 @@
 	.align 8
 	.globl ia32_syscall_table
 ia32_syscall_table:	
-	data8 sys_ni_syscall	  /* 0	-  old "setup(" system call*/
+	data8 sys32_ni_syscall	  /* 0	-  old "setup(" system call*/
 	data8 sys_exit
 	data8 sys32_fork
 	data8 sys_read
@@ -122,25 +122,25 @@
 	data8 sys_mknod
 	data8 sys_chmod		  /* 15 */
 	data8 sys_lchown
-	data8 sys_ni_syscall	  /* old break syscall holder */
-	data8 sys_ni_syscall
+	data8 sys32_ni_syscall	  /* old break syscall holder */
+	data8 sys32_ni_syscall
 	data8 sys_lseek
 	data8 sys_getpid	  /* 20 */
 	data8 sys_mount
 	data8 sys_oldumount
 	data8 sys_setuid
 	data8 sys_getuid
-	data8 sys_ni_syscall /* sys_stime is not supported on IA64 */  /* 25 */
+	data8 sys32_ni_syscall /* sys_stime is not supported on IA64 */  /* 25 */
 	data8 sys32_ptrace
 	data8 sys32_alarm
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall
+	data8 sys32_ni_syscall
+	data8 sys32_ni_syscall
 	data8 ia32_utime	  /* 30 */
-	data8 sys_ni_syscall	  /* old stty syscall holder */
-	data8 sys_ni_syscall	  /* old gtty syscall holder */
+	data8 sys32_ni_syscall	  /* old stty syscall holder */
+	data8 sys32_ni_syscall	  /* old gtty syscall holder */
 	data8 sys_access
 	data8 sys_nice
-	data8 sys_ni_syscall	  /* 35 */	  /* old ftime syscall holder */
+	data8 sys32_ni_syscall	  /* 35 */	  /* old ftime syscall holder */
 	data8 sys_sync
 	data8 sys_kill
 	data8 sys_rename
@@ -149,22 +149,22 @@
 	data8 sys_dup
 	data8 sys32_pipe
 	data8 sys32_times
-	data8 sys_ni_syscall	  /* old prof syscall holder */
+	data8 sys32_ni_syscall	  /* old prof syscall holder */
 	data8 sys_brk		  /* 45 */
 	data8 sys_setgid
 	data8 sys_getgid
-	data8 sys_ni_syscall
+	data8 sys32_ni_syscall
 	data8 sys_geteuid
 	data8 sys_getegid	  /* 50 */
 	data8 sys_acct
 	data8 sys_umount	  /* recycled never used phys( */
-	data8 sys_ni_syscall	  /* old lock syscall holder */
+	data8 sys32_ni_syscall	  /* old lock syscall holder */
 	data8 ia32_ioctl
-	data8 sys_fcntl		  /* 55 */
-	data8 sys_ni_syscall	  /* old mpx syscall holder */
+	data8 sys32_fcntl	  /* 55 */
+	data8 sys32_ni_syscall	  /* old mpx syscall holder */
 	data8 sys_setpgid
-	data8 sys_ni_syscall	  /* old ulimit syscall holder */
-	data8 sys_ni_syscall
+	data8 sys32_ni_syscall	  /* old ulimit syscall holder */
+	data8 sys32_ni_syscall
 	data8 sys_umask		  /* 60 */
 	data8 sys_chroot
 	data8 sys_ustat
@@ -172,12 +172,12 @@
 	data8 sys_getppid
 	data8 sys_getpgrp	  /* 65 */
 	data8 sys_setsid
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall
+	data8 sys32_sigaction
+	data8 sys32_ni_syscall
+	data8 sys32_ni_syscall
 	data8 sys_setreuid	  /* 70 */
 	data8 sys_setregid
-	data8 sys_ni_syscall
+	data8 sys32_ni_syscall
 	data8 sys_sigpending
 	data8 sys_sethostname
 	data8 sys32_setrlimit	  /* 75 */
@@ -189,7 +189,7 @@
 	data8 sys_setgroups
 	data8 old_select
 	data8 sys_symlink
-	data8 sys_ni_syscall
+	data8 sys32_ni_syscall
 	data8 sys_readlink	  /* 85 */
 	data8 sys_uselib
 	data8 sys_swapon
@@ -203,7 +203,7 @@
 	data8 sys_fchown	  /* 95 */
 	data8 sys_getpriority
 	data8 sys_setpriority
-	data8 sys_ni_syscall	  /* old profil syscall holder */
+	data8 sys32_ni_syscall	  /* old profil syscall holder */
 	data8 sys32_statfs
 	data8 sys32_fstatfs	  /* 100 */
 	data8 sys_ioperm
@@ -214,11 +214,11 @@
 	data8 sys32_newstat
 	data8 sys32_newlstat
 	data8 sys32_newfstat
-	data8 sys_ni_syscall
+	data8 sys32_ni_syscall
 	data8 sys_iopl		  /* 110 */
 	data8 sys_vhangup
-	data8 sys_ni_syscall		// used to be sys_idle
-	data8 sys_ni_syscall
+	data8 sys32_ni_syscall		// used to be sys_idle
+	data8 sys32_ni_syscall
 	data8 sys32_wait4
 	data8 sys_swapoff	  /* 115 */
 	data8 sys_sysinfo
@@ -242,7 +242,7 @@
 	data8 sys_bdflush
 	data8 sys_sysfs		  /* 135 */
 	data8 sys_personality
-	data8 sys_ni_syscall	  /* for afs_syscall */
+	data8 sys32_ni_syscall	  /* for afs_syscall */
 	data8 sys_setfsuid
 	data8 sys_setfsgid
 	data8 sys_llseek	  /* 140 */
@@ -293,8 +293,8 @@
 	data8 sys_capset	  /* 185 */
 	data8 sys_sigaltstack
 	data8 sys_sendfile
-	data8 sys_ni_syscall		  /* streams1 */
-	data8 sys_ni_syscall		  /* streams2 */
+	data8 sys32_ni_syscall		  /* streams1 */
+	data8 sys32_ni_syscall		  /* streams2 */
 	data8 sys32_vfork	  /* 190 */
 	/*
 	 *  CAUTION: If any system calls are added beyond this point
diff -urN linux-davidm/arch/ia64/ia32/sys_ia32.c linux-2.4.0-test4-lia/arch/ia64/ia32/sys_ia32.c
--- linux-davidm/arch/ia64/ia32/sys_ia32.c	Fri Jul 28 23:48:24 2000
+++ linux-2.4.0-test4-lia/arch/ia64/ia32/sys_ia32.c	Fri Jul 28 22:57:21 2000
@@ -74,10 +74,14 @@
 
 	n = 0;
 	do {
-		if ((err = get_user(addr, (int *)A(arg))) != 0)
-			return(err);
-		if (ap)
-			*ap++ = (char *)A(addr);
+		err = get_user(addr, (int *)A(arg));
+		if (IS_ERR(err))
+			return err;
+		if (ap) {		/* no access_ok needed, we allocated */
+			err = __put_user((char *)A(addr), ap++);
+			if (IS_ERR(err))
+				return err;
+		}
 		arg += sizeof(unsigned int);
 		n++;
 	} while (addr);
@@ -101,7 +105,11 @@
 	int na, ne, r, len;
 
 	na = nargs(argv, NULL);
+	if (IS_ERR(na))
+		return(na);
 	ne = nargs(envp, NULL);
+	if (IS_ERR(ne))
+		return(ne);
 	len = (na + ne + 2) * sizeof(*av);
 	/*
 	 *  kmalloc won't work because the `sys_exec' code will attempt
@@ -121,12 +129,21 @@
 	if (IS_ERR(av))
 		return (long)av;
 	ae = av + na + 1;
-	av[na] = (char *)0;
-	ae[ne] = (char *)0;
-	(void)nargs(argv, av);
-	(void)nargs(envp, ae);
+	r = __put_user(0, (av + na));
+	if (IS_ERR(r))
+		goto out;
+	r = __put_user(0, (ae + ne));
+	if (IS_ERR(r))
+		goto out;
+	r = nargs(argv, av);
+	if (IS_ERR(r))
+		goto out;
+	r = nargs(envp, ae);
+	if (IS_ERR(r))
+		goto out;
 	r = sys_execve(filename, av, ae, regs);
 	if (IS_ERR(r))
+out:
 		sys_munmap((unsigned long) av, len);
 	return(r);
 }
@@ -959,150 +976,85 @@
 }
 
 struct iovec32 { unsigned int iov_base; int iov_len; };
+asmlinkage ssize_t sys_readv(unsigned long,const struct iovec *,unsigned long);
+asmlinkage ssize_t sys_writev(unsigned long,const struct iovec *,unsigned long);
 
-typedef ssize_t (*IO_fn_t)(struct file *, char *, size_t, loff_t *);
-
-static long
-do_readv_writev32(int type, struct file *file, const struct iovec32 *vector,
-		  u32 count)
+static struct iovec *
+get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type)
 {
-	unsigned long tot_len;
-	struct iovec iovstack[UIO_FASTIOV];
-	struct iovec *iov=iovstack, *ivp;
-	struct inode *inode;
-	long retval, i;
-	IO_fn_t fn;
+	int i;
+	u32 buf, len;
+	struct iovec *ivp, *iov;
+
+	/* Get the "struct iovec" from user memory */
 
-	/* First get the "struct iovec" from user memory and
-	 * verify all the pointers
-	 */
 	if (!count)
 		return 0;
-	if(verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count))
-		return -EFAULT;
+	if(verify_area(VERIFY_READ, iov32, sizeof(struct iovec32)*count))
+		return(struct iovec *)0;
 	if (count > UIO_MAXIOV)
-		return -EINVAL;
+		return(struct iovec *)0;
 	if (count > UIO_FASTIOV) {
 		iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
 		if (!iov)
-			return -ENOMEM;
-	}
+			return((struct iovec *)0);
+	} else
+		iov = iov_buf;
 
-	tot_len = 0;
-	i = count;
 	ivp = iov;
-	while(i > 0) {
-		u32 len;
-		u32 buf;
-
-		__get_user(len, &vector->iov_len);
-		__get_user(buf, &vector->iov_base);
-		tot_len += len;
+	for (i = 0; i < count; i++) {
+		if (__get_user(len, &iov32->iov_len) ||
+		    __get_user(buf, &iov32->iov_base)) {
+			if (iov != iov_buf)
+				kfree(iov);
+			return((struct iovec *)0);
+		}
+		if (verify_area(type, (void *)A(buf), len)) {
+			if (iov != iov_buf)
+				kfree(iov);
+			return((struct iovec *)0);
+		}
 		ivp->iov_base = (void *)A(buf);
-		ivp->iov_len = (__kernel_size_t) len;
-		vector++;
-		ivp++;
-		i--;
-	}
-
-	inode = file->f_dentry->d_inode;
-	/* VERIFY_WRITE actually means a read, as we write to user space */
-	retval = locks_verify_area((type = VERIFY_WRITE
-				    ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
-				   inode, file, file->f_pos, tot_len);
-	if (retval) {
-		if (iov != iovstack)
-			kfree(iov);
-		return retval;
-	}
-
-	/* Then do the actual IO.  Note that sockets need to be handled
-	 * specially as they have atomicity guarantees and can handle
-	 * iovec's natively
-	 */
-	if (inode->i_sock) {
-		int err;
-		err = sock_readv_writev(type, inode, file, iov, count, tot_len);
-		if (iov != iovstack)
-			kfree(iov);
-		return err;
-	}
-
-	if (!file->f_op) {
-		if (iov != iovstack)
-			kfree(iov);
-		return -EINVAL;
-	}
-	/* VERIFY_WRITE actually means a read, as we write to user space */
-	fn = file->f_op->read;
-	if (type = VERIFY_READ)
-		fn = (IO_fn_t) file->f_op->write;		
-	ivp = iov;
-	while (count > 0) {
-		void * base;
-		int len, nr;
-
-		base = ivp->iov_base;
-		len = ivp->iov_len;
+		ivp->iov_len = (__kernel_size_t)len;
+		iov32++;
 		ivp++;
-		count--;
-		nr = fn(file, base, len, &file->f_pos);
-		if (nr < 0) {
-			if (retval)
-				break;
-			retval = nr;
-			break;
-		}
-		retval += nr;
-		if (nr != len)
-			break;
 	}
-	if (iov != iovstack)
-		kfree(iov);
-	return retval;
+	return(iov);
 }
 
 asmlinkage long
 sys32_readv(int fd, struct iovec32 *vector, u32 count)
 {
-	struct file *file;
-	long ret = -EBADF;
-
-	file = fget(fd);
-	if(!file)
-		goto bad_file;
-
-	if(!(file->f_mode & 1))
-		goto out;
+	struct iovec iovstack[UIO_FASTIOV];
+	struct iovec *iov;
+	int ret;
+	mm_segment_t old_fs = get_fs();
 
-	ret = do_readv_writev32(VERIFY_WRITE, file,
-				vector, count);
-out:
-	fput(file);
-bad_file:
+	if ((iov = get_iovec32(vector, iovstack, count, VERIFY_WRITE)) = (struct iovec *)0)
+		return -EFAULT;
+	set_fs(KERNEL_DS);
+	ret = sys_readv(fd, iov, count);
+	set_fs(old_fs);
+	if (iov != iovstack)
+		kfree(iov);
 	return ret;
 }
 
 asmlinkage long
 sys32_writev(int fd, struct iovec32 *vector, u32 count)
 {
-	struct file *file;
-	int ret = -EBADF;
-
-	file = fget(fd);
-	if(!file)
-		goto bad_file;
-
-	if(!(file->f_mode & 2))
-		goto out;
+	struct iovec iovstack[UIO_FASTIOV];
+	struct iovec *iov;
+	int ret;
+	mm_segment_t old_fs = get_fs();
 
-	down(&file->f_dentry->d_inode->i_sem);
-	ret = do_readv_writev32(VERIFY_READ, file,
-				vector, count);
-	up(&file->f_dentry->d_inode->i_sem);
-out:
-	fput(file);
-bad_file:
+	if ((iov = get_iovec32(vector, iovstack, count, VERIFY_READ)) = (struct iovec *)0)
+		return -EFAULT;
+	set_fs(KERNEL_DS);
+	ret = sys_writev(fd, iov, count);
+	set_fs(old_fs);
+	if (iov != iovstack)
+		kfree(iov);
 	return ret;
 }
 
@@ -1173,21 +1125,22 @@
 static inline int
 shape_msg(struct msghdr *mp, struct msghdr32 *mp32)
 {
+	int ret;
 	unsigned int i;
 
 	if (!access_ok(VERIFY_READ, mp32, sizeof(*mp32)))
 		return(-EFAULT);
-	__get_user(i, &mp32->msg_name);
+	ret = __get_user(i, &mp32->msg_name);
 	mp->msg_name = (void *)A(i);
-	__get_user(mp->msg_namelen, &mp32->msg_namelen);
-	__get_user(i, &mp32->msg_iov);
+	ret |= __get_user(mp->msg_namelen, &mp32->msg_namelen);
+	ret |= __get_user(i, &mp32->msg_iov);
 	mp->msg_iov = (struct iovec *)A(i);
-	__get_user(mp->msg_iovlen, &mp32->msg_iovlen);
-	__get_user(i, &mp32->msg_control);
+	ret |= __get_user(mp->msg_iovlen, &mp32->msg_iovlen);
+	ret |= __get_user(i, &mp32->msg_control);
 	mp->msg_control = (void *)A(i);
-	__get_user(mp->msg_controllen, &mp32->msg_controllen);
-	__get_user(mp->msg_flags, &mp32->msg_flags);
-	return(0);
+	ret |= __get_user(mp->msg_controllen, &mp32->msg_controllen);
+	ret |= __get_user(mp->msg_flags, &mp32->msg_flags);
+	return(ret ? -EFAULT : 0);
 }
 
 /*
@@ -2341,17 +2294,17 @@
 {
 	struct switch_stack *swp;
 	struct pt_regs *ptp;
-	int i, tos;
+	int i, tos, ret;
 	int fsrlo, fsrhi;
 
 	if (!access_ok(VERIFY_READ, save, sizeof(*save)))
 		return(-EIO);
-	__get_user(tsk->thread.fcr, (unsigned int *)&save->cw);
-	__get_user(fsrlo, (unsigned int *)&save->sw);
-	__get_user(fsrhi, (unsigned int *)&save->tag);
+	ret = __get_user(tsk->thread.fcr, (unsigned int *)&save->cw);
+	ret |= __get_user(fsrlo, (unsigned int *)&save->sw);
+	ret |= __get_user(fsrhi, (unsigned int *)&save->tag);
 	tsk->thread.fsr = ((long)fsrhi << 32) | (long)fsrlo;
-	__get_user(tsk->thread.fir, (unsigned int *)&save->ipoff);
-	__get_user(tsk->thread.fdr, (unsigned int *)&save->dataoff);
+	ret |= __get_user(tsk->thread.fir, (unsigned int *)&save->ipoff);
+	ret |= __get_user(tsk->thread.fdr, (unsigned int *)&save->dataoff);
 	/*
 	 *  Stack frames start with 16-bytes of temp space
 	 */
@@ -2360,7 +2313,7 @@
 	tos = (tsk->thread.fsr >> 11) & 3;
 	for (i = 0; i < 8; i++)
 		get_fpreg(i, &save->_st[i], ptp, swp, tos);
-	return(0);
+	return(ret ? -EFAULT : 0);
 }
 
 asmlinkage long sys_ptrace(long, pid_t, unsigned long, unsigned long, long, long, long, long, long);
@@ -2492,6 +2445,105 @@
 	return ret;
 }
 
+static inline int
+get_flock32(struct flock *kfl, struct flock32 *ufl)
+{
+	int err;
+	
+	err = get_user(kfl->l_type, &ufl->l_type);
+	err |= __get_user(kfl->l_whence, &ufl->l_whence);
+	err |= __get_user(kfl->l_start, &ufl->l_start);
+	err |= __get_user(kfl->l_len, &ufl->l_len);
+	err |= __get_user(kfl->l_pid, &ufl->l_pid);
+	return err;
+}
+
+static inline int
+put_flock32(struct flock *kfl, struct flock32 *ufl)
+{
+	int err;
+	
+	err = __put_user(kfl->l_type, &ufl->l_type);
+	err |= __put_user(kfl->l_whence, &ufl->l_whence);
+	err |= __put_user(kfl->l_start, &ufl->l_start);
+	err |= __put_user(kfl->l_len, &ufl->l_len);
+	err |= __put_user(kfl->l_pid, &ufl->l_pid);
+	return err;
+}
+
+extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd,
+				 unsigned long arg);
+
+asmlinkage long
+sys32_fcntl(unsigned int fd, unsigned int cmd, int arg)
+{
+	struct flock f;
+	mm_segment_t old_fs;
+	long ret;
+
+	switch (cmd) {
+	case F_GETLK:
+	case F_SETLK:
+	case F_SETLKW:
+		if(cmd != F_GETLK && get_flock32(&f, (struct flock32 *)((long)arg)))
+			return -EFAULT;
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		ret = sys_fcntl(fd, cmd, (unsigned long)&f);
+		set_fs(old_fs);
+		if(cmd = F_GETLK && put_flock32(&f, (struct flock32 *)((long)arg)))
+			return -EFAULT;
+		return ret;
+	default:
+		/*
+		 *  `sys_fcntl' lies about arg, for the F_SETOWN
+		 *  sub-function arg can have a negative value.
+		 */
+		return sys_fcntl(fd, cmd, (unsigned long)((long)arg));
+	}
+}
+
+asmlinkage long
+sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact)
+{
+        struct k_sigaction new_ka, old_ka;
+        int ret;
+
+        if (act) {
+		old_sigset32_t mask;
+		
+		ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler);
+		ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+		ret |= __get_user(mask, &act->sa_mask);
+		if (ret)
+			return ret;
+		siginitset(&new_ka.sa.sa_mask, mask);
+        }
+
+        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) {
+		ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler);
+		ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+		ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+        }
+
+	return ret;
+}
+
+asmlinkage long sys_ni_syscall(void);
+
+asmlinkage long
+sys32_ni_syscall(int dummy0, int dummy1, int dummy2, int dummy3,
+	int dummy4, int dummy5, int dummy6, int dummy7, int stack)
+{
+	struct pt_regs *regs = (struct pt_regs *)&stack;
+
+	printk("IA32 syscall #%d issued, maybe we should implement it\n",
+		(int)regs->r1);
+	return(sys_ni_syscall());
+}
+
 #ifdef	NOTYET  /* UNTESTED FOR IA64 FROM HERE DOWN */
 
 /* In order to reduce some races, while at the same time doing additional
@@ -2545,61 +2597,6 @@
 	return sys_ioperm((unsigned long)from, (unsigned long)num, on);
 }
 
-static inline int
-get_flock(struct flock *kfl, struct flock32 *ufl)
-{
-	int err;
-	
-	err = get_user(kfl->l_type, &ufl->l_type);
-	err |= __get_user(kfl->l_whence, &ufl->l_whence);
-	err |= __get_user(kfl->l_start, &ufl->l_start);
-	err |= __get_user(kfl->l_len, &ufl->l_len);
-	err |= __get_user(kfl->l_pid, &ufl->l_pid);
-	return err;
-}
-
-static inline int
-put_flock(struct flock *kfl, struct flock32 *ufl)
-{
-	int err;
-	
-	err = __put_user(kfl->l_type, &ufl->l_type);
-	err |= __put_user(kfl->l_whence, &ufl->l_whence);
-	err |= __put_user(kfl->l_start, &ufl->l_start);
-	err |= __put_user(kfl->l_len, &ufl->l_len);
-	err |= __put_user(kfl->l_pid, &ufl->l_pid);
-	return err;
-}
-
-extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd,
-				 unsigned long arg);
-
-asmlinkage long
-sys32_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	switch (cmd) {
-	case F_GETLK:
-	case F_SETLK:
-	case F_SETLKW:
-		{
-			struct flock f;
-			mm_segment_t old_fs;
-			long ret;
-			
-			if(get_flock(&f, (struct flock32 *)arg))
-				return -EFAULT;
-			old_fs = get_fs(); set_fs (KERNEL_DS);
-			ret = sys_fcntl(fd, cmd, (unsigned long)&f);
-			set_fs (old_fs);
-			if(put_flock(&f, (struct flock32 *)arg))
-				return -EFAULT;
-			return ret;
-		}
-	default:
-		return sys_fcntl(fd, cmd, (unsigned long)arg);
-	}
-}
-
 struct dqblk32 {
     __u32 dqb_bhardlimit;
     __u32 dqb_bsoftlimit;
@@ -3861,40 +3858,6 @@
 }
 
 extern void check_pending(int signum);
-
-asmlinkage long
-sys32_sigaction (int sig, struct old_sigaction32 *act,
-		 struct old_sigaction32 *oact)
-{
-        struct k_sigaction new_ka, old_ka;
-        int ret;
-
-	if(sig < 0) {
-		current->tss.new_signal = 1;
-		sig = -sig;
-	}
-
-        if (act) {
-		old_sigset_t32 mask;
-		
-		ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler);
-		ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
-		ret |= __get_user(mask, &act->sa_mask);
-		if (ret)
-			return ret;
-		siginitset(&new_ka.sa.sa_mask, mask);
-        }
-
-        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
-	if (!ret && oact) {
-		ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler);
-		ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
-		ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
-        }
-
-	return ret;
-}
 
 #ifdef CONFIG_MODULES
 
diff -urN linux-davidm/arch/ia64/kernel/Makefile linux-2.4.0-test4-lia/arch/ia64/kernel/Makefile
--- linux-davidm/arch/ia64/kernel/Makefile	Fri Jul 28 23:48:24 2000
+++ linux-2.4.0-test4-lia/arch/ia64/kernel/Makefile	Fri Jul 28 22:58:05 2000
@@ -9,8 +9,8 @@
 
 all: kernel.o head.o init_task.o
 
-obj-y := acpi.o entry.o gate.o efi.o efi_stub.o irq.o irq_ia64.o irq_sapic.o ivt.o	\
-	 pal.o pci-dma.o process.o perfmon.o ptrace.o sal.o semaphore.o setup.o		\
+obj-y := acpi.o entry.o gate.o efi.o efi_stub.o irq.o irq_ia64.o irq_sapic.o ivt.o		\
+	 machvec.o pal.o pci-dma.o process.o perfmon.o ptrace.o sal.o semaphore.o setup.o	\
 	 signal.o sys_ia64.o traps.o time.o unaligned.o unwind.o
 
 obj-$(CONFIG_IA64_GENERIC) += machvec.o
diff -urN linux-davidm/arch/ia64/kernel/acpi.c linux-2.4.0-test4-lia/arch/ia64/kernel/acpi.c
--- linux-davidm/arch/ia64/kernel/acpi.c	Thu Jun 22 07:09:44 2000
+++ linux-2.4.0-test4-lia/arch/ia64/kernel/acpi.c	Fri Jul 28 22:58:16 2000
@@ -19,10 +19,11 @@
 #include <linux/irq.h>
 
 #include <asm/acpi-ext.h>
-#include <asm/page.h>
 #include <asm/efi.h>
 #include <asm/io.h>
 #include <asm/iosapic.h>
+#include <asm/machvec.h>
+#include <asm/page.h>
 
 #undef ACPI_DEBUG		/* Guess what this does? */
 
@@ -75,47 +76,6 @@
 }
 
 /*
- * Find all IOSAPICs and tag the iosapic_vector structure with the appropriate 
- * base addresses.
- */
-static void __init
-acpi_iosapic(char *p) 
-{
-	/*
-	 * This is not good.  ACPI is not necessarily limited to CONFIG_IA64_SV, yet
-	 * ACPI does not necessarily imply IOSAPIC either.  Perhaps there should be
-	 * a means for platform_setup() to register ACPI handlers?
-	 */
-#ifdef CONFIG_IA64_DIG
-	acpi_entry_iosapic_t *iosapic = (acpi_entry_iosapic_t *) p;
-	unsigned int ver, v;
-	int l, max_pin;
-
-	ver = iosapic_version(iosapic->address);
-	max_pin = (ver >> 16) & 0xff;
-	
-	printk("IOSAPIC Version %x.%x: address 0x%lx IRQs 0x%x - 0x%x\n", 
-	       (ver & 0xf0) >> 4, (ver & 0x0f), iosapic->address, 
-	       iosapic->irq_base, iosapic->irq_base + max_pin);
-	
-	for (l = 0; l <= max_pin; l++) {
-		v = iosapic->irq_base + l;
-		if (v < 16)
-			v = isa_irq_to_vector(v);
-		if (v > IA64_MAX_VECTORED_IRQ) {
-			printk("    !!! bad IOSAPIC interrupt vector: %u\n", v);
-			continue;
-		}
-		/* XXX Check for IOSAPIC collisions */
-		iosapic_addr(v) = (unsigned long) ioremap(iosapic->address, 0);
-		iosapic_baseirq(v) = iosapic->irq_base;
-	}
-	iosapic_init(iosapic->address, iosapic->irq_base);
-#endif
-}
-
-
-/*
  * Configure legacy IRQ information in iosapic_vector
  */
 static void __init
@@ -227,7 +187,7 @@
 			break;
 	
 		case ACPI_ENTRY_IO_SAPIC:
-			acpi_iosapic(p);
+			platform_register_iosapic((acpi_entry_iosapic_t *) p);
 			break;
 
 		case ACPI_ENTRY_INT_SRC_OVERRIDE:
diff -urN linux-davidm/arch/ia64/kernel/efi.c linux-2.4.0-test4-lia/arch/ia64/kernel/efi.c
--- linux-davidm/arch/ia64/kernel/efi.c	Thu Jun 22 07:09:44 2000
+++ linux-2.4.0-test4-lia/arch/ia64/kernel/efi.c	Fri Jul 28 22:58:24 2000
@@ -33,9 +33,10 @@
 extern efi_status_t efi_call_phys (void *, ...);
 
 struct efi efi;
-		    
 static efi_runtime_services_t *runtime;
 
+static unsigned long mem_limit = ~0UL;
+
 static efi_status_t
 phys_get_time (efi_time_t *tm, efi_time_cap_t *tc)
 {
@@ -169,15 +170,13 @@
 		      case EFI_BOOT_SERVICES_CODE:
 		      case EFI_BOOT_SERVICES_DATA:
 		      case EFI_CONVENTIONAL_MEMORY:
-			if (md->phys_addr > 1024*1024*1024UL) {
-				printk("Warning: ignoring %luMB of memory above 1GB!\n",
-				       md->num_pages >> 8);
-				md->type = EFI_UNUSABLE_MEMORY;
-				continue;
-			}
-
 			if (!(md->attribute & EFI_MEMORY_WB))
 				continue;
+			if (md->phys_addr + (md->num_pages << 12) > mem_limit) {
+				if (md->phys_addr > mem_limit)
+					continue;
+				md->num_pages = (mem_limit - md->phys_addr) >> 12;
+			}
 			if (md->num_pages = 0) {
 				printk("efi_memmap_walk: ignoring empty region at 0x%lx",
 				       md->phys_addr);
@@ -224,8 +223,8 @@
  * 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_pal_code (void)
 {
 	void *efi_map_start, *efi_map_end, *p;
 	efi_memory_desc_t *md;
@@ -240,7 +239,8 @@
 
 	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
 		md = p;
-		if (md->type != EFI_PAL_CODE) continue;
+		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",
@@ -281,9 +281,28 @@
 	efi_config_table_t *config_tables;
 	efi_char16_t *c16;
 	u64 efi_desc_size;
-	char vendor[100] = "unknown";
+	char *cp, *end, vendor[100] = "unknown";
+	extern char saved_command_line[];
 	int i;
 
+	/* it's too early to be able to use the standard kernel command line support... */
+	for (cp = saved_command_line; *cp; ) {
+		if (memcmp(cp, "mem=", 4) = 0) {
+			cp += 4;
+			mem_limit = memparse(cp, &end);
+			if (end != cp)
+				break;
+			cp = end;
+		} else {
+			while (*cp != ' ' && *cp)
+				++cp;
+			while (*cp = ' ')
+				++cp;
+		}
+	}
+	if (mem_limit != ~0UL)
+		printk("Ignoring memory above %luMB\n", mem_limit >> 20);
+
 	efi.systab = __va(ia64_boot_param.efi_systab);
 
 	/*
@@ -359,7 +378,7 @@
 	}
 #endif
 
-	map_pal_code();
+	efi_map_pal_code();
 }
 
 void
diff -urN linux-davidm/arch/ia64/kernel/entry.S linux-2.4.0-test4-lia/arch/ia64/kernel/entry.S
--- linux-davidm/arch/ia64/kernel/entry.S	Fri Jul 28 23:48:24 2000
+++ linux-2.4.0-test4-lia/arch/ia64/kernel/entry.S	Fri Jul 28 23:04:23 2000
@@ -106,29 +106,19 @@
 	alloc r16=ar.pfs,1,0,0,0
 	DO_SAVE_SWITCH_STACK
 	UNW(.body)
-	// disable interrupts to ensure atomicity for next few instructions:
-	mov r17=psr		// M-unit
-	;;
-	rsm psr.i		// M-unit
-	dep r18=-1,r0,0,61	// build mask 0x1fffffffffffffff
-	;;
-	srlz.d
-	;;
+
 	adds r22=IA64_TASK_THREAD_KSP_OFFSET,r13
+	dep r18=-1,r0,0,61	// build mask 0x1fffffffffffffff
 	adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0
 	;;
 	st8 [r22]=sp		// save kernel stack pointer of old task
 	ld8 sp=[r21]		// load kernel stack pointer of new task
 	and r20=in0,r18		// physical address of "current"
 	;;
+	mov ar.k6=r20		// copy "current" into ar.k6
 	mov r8=r13		// return pointer to previously running task
 	mov r13=in0		// set "current" pointer
-	mov ar.k6=r20		// copy "current" into ar.k6
-	;;
-	// restore interrupts
-	mov psr.l=r17
 	;;
-	srlz.d
 	DO_LOAD_SWITCH_STACK( )
 	br.ret.sptk.few rp
 END(ia64_switch_to)
diff -urN linux-davidm/arch/ia64/kernel/irq_ia64.c linux-2.4.0-test4-lia/arch/ia64/kernel/irq_ia64.c
--- linux-davidm/arch/ia64/kernel/irq_ia64.c	Thu Jun 22 07:09:44 2000
+++ linux-2.4.0-test4-lia/arch/ia64/kernel/irq_ia64.c	Fri Jul 28 23:08:34 2000
@@ -117,6 +117,13 @@
 	{
 		unsigned long bsp, sp;
 
+		/*
+		 * Note: if the interrupt happened while executing in
+		 * the context switch routine (ia64_switch_to), we may
+		 * get a spurious stack overflow here.  This is
+		 * because the register and the memory stack are not
+		 * switched atomically.
+		 */
 		asm ("mov %0=ar.bsp" : "=r"(bsp));
 		asm ("mov %0=sp" : "=r"(sp));
 
diff -urN linux-davidm/arch/ia64/kernel/ivt.S linux-2.4.0-test4-lia/arch/ia64/kernel/ivt.S
--- linux-davidm/arch/ia64/kernel/ivt.S	Fri Jul 28 23:48:24 2000
+++ linux-2.4.0-test4-lia/arch/ia64/kernel/ivt.S	Fri Jul 28 23:07:09 2000
@@ -170,33 +170,27 @@
 	 * The ITLB basically does the same as the VHPT handler except
 	 * that we always insert exactly one instruction TLB entry.
 	 */
-#if 1
 	/*
 	 * Attempt to lookup PTE through virtual linear page table.
 	 * The speculative access will fail if there is no TLB entry
 	 * for the L3 page table page we're trying to access.
 	 */
-	mov r31=pr				// save predicates
-	;;
-	thash r17=r16				// compute virtual address of L3 PTE
+	mov r16=cr.iha				// get virtual address of L3 PTE
 	;;
-	ld8.s r18=[r17]				// try to read L3 PTE
+	ld8.s r16=[r16]				// try to read L3 PTE
+	mov r31=pr				// save predicates
 	;;
-	tnat.nz p6,p0=r18			// did read succeed?
+	tnat.nz p6,p0=r16			// did read succeed?
 (p6)	br.cond.spnt.many 1f
 	;;
-	itc.i r18
+	itc.i r16
 	;;
 	mov pr=r31,-1
 	rfi
 
-1:	rsm psr.dt				// use physical addressing for data
-#else
-	mov r16=cr.ifa				// get address that caused the TLB miss
+1:	mov r16=cr.ifa				// get address that caused the TLB miss
 	;;
 	rsm psr.dt				// use physical addressing for data
-#endif
-	mov r31=pr				// save the predicate registers
 	mov r19=ar.k7				// get page table base address
 	shl r21=r16,3				// shift bit 60 into sign bit
 	shr.u r17=r16,61			// get the region number into r17
@@ -244,33 +238,27 @@
 	 * The DTLB basically does the same as the VHPT handler except
 	 * that we always insert exactly one data TLB entry.
 	 */
-	mov r16=cr.ifa				// get address that caused the TLB miss
-#if 1
 	/*
 	 * Attempt to lookup PTE through virtual linear page table.
 	 * The speculative access will fail if there is no TLB entry
 	 * for the L3 page table page we're trying to access.
 	 */
-	mov r31=pr				// save predicates
-	;;
-	thash r17=r16				// compute virtual address of L3 PTE
+	mov r16=cr.iha				// get virtual address of L3 PTE
 	;;
-	ld8.s r18=[r17]				// try to read L3 PTE
+	ld8.s r16=[r16]				// try to read L3 PTE
+	mov r31=pr				// save predicates
 	;;
-	tnat.nz p6,p0=r18			// did read succeed?
+	tnat.nz p6,p0=r16			// did read succeed?
 (p6)	br.cond.spnt.many 1f
 	;;
-	itc.d r18
+	itc.d r16
 	;;
 	mov pr=r31,-1
 	rfi
 
-1:	rsm psr.dt				// use physical addressing for data
-#else
-	rsm psr.dt				// use physical addressing for data
-	mov r31=pr				// save the predicate registers
+1:	mov r16=cr.ifa				// get address that caused the TLB miss
 	;;
-#endif
+	rsm psr.dt				// use physical addressing for data
 	mov r19=ar.k7				// get page table base address
 	shl r21=r16,3				// shift bit 60 into sign bit
 	shr.u r17=r16,61			// get the region number into r17
@@ -504,7 +492,24 @@
 	mov r29°				// save b0 in case of nested fault)
 	;;
 1:	ld8 r18=[r17]
-	;;					// avoid raw on r18
+#if defined(CONFIG_IA32_SUPPORT) && \
+    (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_B0_SPECIFIC))
+	//
+	// Erratum 85 (Access bit fault could be reported before page not present fault)
+	//   If the PTE is indicates the page is not present, then just turn this into a
+	//   page fault.
+	//
+	mov r31=pr				// save predicates
+	;;
+	tbit.nz p6,p0=r18,0			// page present bit set?
+(p6)	br.cond.sptk 1f
+	;;					// avoid WAW on p6
+	mov pr=r31,-1
+	br.cond.sptk page_fault			// page wasn't present
+1:	mov pr=r31,-1
+#else
+	;;					// avoid RAW on r18
+#endif
 	or r18=_PAGE_A,r18			// set the accessed bit
 	mov b0=r29				// restore b0
 	;;
@@ -541,14 +546,6 @@
 	;;
 	srlz.d			// ensure everyone knows psr.dt is off...
 	cmp.eq p0,p7=r16,r17	// is this a system call? (p7 <- false, if so)
-#if 1
-	// Allow syscalls via the old system call number for the time being.  This is
-	// so we can transition to the new syscall number in a relatively smooth
-	// fashion.
-	mov r17=0x80000
-	;;
-(p7)	cmp.eq.or.andcm p0,p7=r16,r17		// is this the old syscall number?
-#endif
 (p7)	br.cond.spnt.many non_syscall
 
 	SAVE_MIN				// uses r31; defines r2:
diff -urN linux-davidm/arch/ia64/kernel/machvec.c linux-2.4.0-test4-lia/arch/ia64/kernel/machvec.c
--- linux-davidm/arch/ia64/kernel/machvec.c	Tue Feb  8 12:01:59 2000
+++ linux-2.4.0-test4-lia/arch/ia64/kernel/machvec.c	Fri Jul 28 23:08:48 2000
@@ -3,12 +3,9 @@
 #include <asm/page.h>
 #include <asm/machvec.h>
 
-struct ia64_machine_vector ia64_mv;
+#ifdef CONFIG_IA64_GENERIC
 
-void
-machvec_noop (void)
-{
-}
+struct ia64_machine_vector ia64_mv;
 
 /*
  * Most platforms use this routine for mapping page frame addresses
@@ -45,4 +42,11 @@
 	}
 	ia64_mv = *mv;
 	printk("booting generic kernel on platform %s\n", name);
+}
+
+#endif /* CONFIG_IA64_GENERIC */
+
+void
+machvec_noop (void)
+{
 }
diff -urN linux-davidm/arch/ia64/kernel/pal.S linux-2.4.0-test4-lia/arch/ia64/kernel/pal.S
--- linux-davidm/arch/ia64/kernel/pal.S	Fri Jul 28 23:48:24 2000
+++ linux-2.4.0-test4-lia/arch/ia64/kernel/pal.S	Fri Jul 28 23:08:58 2000
@@ -191,3 +191,57 @@
 	srlz.d				// seralize restoration of psr.l
 	br.ret.sptk.few	b0
 END(ia64_pal_call_phys_static)
+
+/*
+ * Make a PAL call using the stacked registers in physical mode.
+ *
+ * Inputs:
+ * 	in0         Index of PAL service
+ * 	in2 - in3   Remaning PAL arguments
+ */
+GLOBAL_ENTRY(ia64_pal_call_phys_stacked)
+	UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5))
+	alloc	loc1 = ar.pfs,5,5,86,0
+	movl	loc2 = pal_entry_point
+1:	{
+	  mov r28  = in0		// copy procedure index
+	  mov loc0 = rp		// save rp
+	}
+	.body
+	;;
+	ld8 loc2 = [loc2]		// loc2 <- entry point
+	mov out0 = in0		// first argument
+	mov out1 = in1		// copy arg2
+	mov out2 = in2		// copy arg3
+	mov out3 = in3		// copy arg3
+	;;
+	mov loc3 = psr		// save psr
+	;; 
+	mov loc4=ar.rsc			// save RSE configuration
+	dep.z loc2=loc2,0,61		// convert pal entry point to physical
+	;;
+	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
+	mov b7 = loc2			// install target to branch reg
+	;;
+	andcm r16=loc3,r16		// removes bits to clear from psr
+	br.call.sptk.few rp=ia64_switch_mode
+.ret6:
+	br.call.sptk.many rp·		// now make the call
+.ret7:
+	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
+
+.ret8:	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_stacked)
+
diff -urN linux-davidm/arch/ia64/kernel/palinfo.c linux-2.4.0-test4-lia/arch/ia64/kernel/palinfo.c
--- linux-davidm/arch/ia64/kernel/palinfo.c	Thu Jun 22 07:09:44 2000
+++ linux-2.4.0-test4-lia/arch/ia64/kernel/palinfo.c	Fri Jul 28 23:09:09 2000
@@ -27,13 +27,22 @@
 #include <asm/efi.h>
 #include <asm/page.h>
 #include <asm/processor.h>
+#ifdef CONFIG_SMP
+#include <linux/smp.h>
+#endif
 
 /*
  * Hope to get rid of these in a near future
 */
 #define IA64_PAL_VERSION_BUG		1
 
-#define PALINFO_VERSION "0.1"
+#define PALINFO_VERSION "0.2"
+
+#ifdef CONFIG_SMP
+#define cpu_is_online(i) (cpu_online_map & (1UL << i))
+#else
+#define cpu_is_online(i)	1
+#endif
 
 typedef int (*palinfo_func_t)(char*);
 
@@ -43,7 +52,6 @@
 	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
@@ -95,7 +103,7 @@
 #define RSE_HINTS_COUNT (sizeof(rse_hints)/sizeof(const char *))
 
 /*
- * The current resvision of the Volume 2 of 
+ * The current revision 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:
@@ -564,7 +572,6 @@
 	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) {
@@ -577,6 +584,57 @@
 	return p - page;
 }
 
+static const char *bus_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,
+	"Request  Bus Parking",
+	"Bus Lock Mask",
+	"Enable Half Transfer",
+	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+	NULL, NULL, NULL, NULL, NULL, NULL,
+	"Disable Transaction Queuing",
+	"Disable Reponse Error Checking",
+	"Disable Bus Error Checking",
+	"Disable Bus Requester Internal Error Signalling",
+	"Disable Bus Requester Error Signalling",
+	"Disable Bus Initialization Event Checking",
+	"Disable Bus Initialization Event Signalling",
+	"Disable Bus Address Error Checking",
+	"Disable Bus Address Error Signalling",
+	"Disable Bus Data Error Checking"
+};
+
+	
+static int
+bus_info(char *page)
+{
+	char *p = page;
+	const char **v = bus_features;
+	pal_bus_features_u_t av, st, ct;
+	u64 avail, status, control;
+	int i;
+	s64 ret;
+
+	if ((ret=ia64_pal_bus_get_features(&av, &st, &ct)) != 0) return 0;
+
+	avail   = av.pal_bus_features_val;
+	status  = st.pal_bus_features_val;
+	control = ct.pal_bus_features_val;
+
+	for(i=0; i < 64; i++, v++, avail >>=1, status >>=1, control >>=1) {
+		if ( ! *v ) continue;
+		p += sprintf(p, "%-48s : %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.
@@ -613,21 +671,19 @@
 #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",
+	p += sprintf(p, "PAL_vendor : 0x%02x (min=0x%02x)\n" \
+			"PAL_A      : %02x.%02x (min=%02x.%02x)\n" \
+			"PAL_B      : %02x.%02x (min=%02x.%02x)\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,
+	     		cur_ver.pal_version_s.pv_pal_a_rev,
 	     		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,
+	     		min_ver.pal_version_s.pv_pal_a_rev,
 	     		cur_ver.pal_version_s.pv_pal_b_model,
-	     		min_ver.pal_version_s.pv_pal_b_model);
+	     		cur_ver.pal_version_s.pv_pal_b_rev,
+	     		min_ver.pal_version_s.pv_pal_b_model,
+	     		min_ver.pal_version_s.pv_pal_b_rev);
 
 	return p - page;
 }
@@ -708,30 +764,111 @@
 	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)
+tr_info(char *page)
 {
-	palinfo_func_t info = (palinfo_func_t)data;
-        int len = info(page);
+	char *p = page;
+	s64 status;
+	pal_tr_valid_u_t tr_valid;
+	u64 tr_buffer[4];
+	pal_vm_info_1_u_t vm_info_1;
+	pal_vm_info_2_u_t vm_info_2;
+	int i, j;
+	u64 max[3], pgm;
+	struct ifa_reg {
+		u64 valid:1;
+		u64 ig:11;
+		u64 vpn:52;
+	} *ifa_reg;
+	struct itir_reg {
+		u64 rv1:2;
+		u64 ps:6;
+		u64 key:24;
+		u64 rv2:32;
+	} *itir_reg;
+	struct gr_reg {
+		u64 p:1;
+		u64 rv1:1;
+		u64 ma:3;
+		u64 a:1;
+		u64 d:1;
+		u64 pl:2;
+		u64 ar:3;
+		u64 ppn:38;
+		u64 rv2:2;
+		u64 ed:1;
+		u64 ig:11;
+	} *gr_reg;
+	struct rid_reg {
+		u64 ig1:1;
+		u64 rv1:1;
+		u64 ig2:6;
+		u64 rid:24;
+		u64 rv2:32;
+	} *rid_reg;
 
-        if (len <= off+count) *eof = 1;
+	if ((status=ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) !=0) {
+		printk("ia64_pal_vm_summary=%ld\n", status);
+		return 0;
+	}
+	max[0] = vm_info_1.pal_vm_info_1_s.max_itr_entry+1;
+	max[1] = vm_info_1.pal_vm_info_1_s.max_dtr_entry+1;
 
-        *start = page + off;
-        len   -= off;
+	for (i=0; i < 2; i++ ) {
+		for (j=0; j < max[i]; j++) {
 
-        if (len>count) len = count;
-        if (len<0) len = 0;
+		status = ia64_pal_tr_read(j, i, tr_buffer, &tr_valid);
+		if (status != 0) {
+			printk(__FUNCTION__ " pal call failed on tr[%d:%d]=%ld\n", i, j, status);
+			continue;
+		}
 
-        return len;
+		ifa_reg  = (struct ifa_reg *)&tr_buffer[2];
+
+		if (ifa_reg->valid = 0) continue;
+
+		gr_reg   = (struct gr_reg *)tr_buffer;	
+		itir_reg = (struct itir_reg *)&tr_buffer[1];
+		rid_reg  = (struct rid_reg *)&tr_buffer[3];
+
+		pgm	 = -1 << (itir_reg->ps - 12);
+		p += sprintf(p, "%cTR%d: av=%d pv=%d dv=%d mv=%d\n" \
+				"\tppn  : 0x%lx\n" \
+				"\tvpn  : 0x%lx\n" \
+				"\tps   : ",
+
+				"ID"[i],
+				j,
+				tr_valid.pal_tr_valid_s.access_rights_valid,
+				tr_valid.pal_tr_valid_s.priv_level_valid,
+				tr_valid.pal_tr_valid_s.dirty_bit_valid,
+				tr_valid.pal_tr_valid_s.mem_attr_valid,
+				(gr_reg->ppn & pgm)<< 12,
+				(ifa_reg->vpn & pgm)<< 12);
+
+		p = bitvector_process(p, 1<< itir_reg->ps);
+
+		p += sprintf(p, "\n\tpl   : %d\n" \
+				"\tar   : %d\n" \
+				"\trid  : %x\n" \
+				"\tp    : %d\n" \
+				"\tma   : %d\n" \
+				"\td    : %d\n", 
+				gr_reg->pl,
+				gr_reg->ar,
+				rid_reg->rid,
+				gr_reg->p,
+				gr_reg->ma,
+				gr_reg->d);
+		}
+	}
+	return p - page;
 }
 
+
+
 /*
- * List names,function pairs for every entry in /proc/palinfo
- * Must be terminated with the NULL,NULL entry.
+ * List {name,function} pairs for every entry in /proc/palinfo/cpu*
  */
 static palinfo_entry_t palinfo_entries[]={
 	{ "version_info",	version_info, },
@@ -742,23 +879,175 @@
 	{ "processor_info",	processor_info, },
 	{ "perfmon_info",	perfmon_info, },
 	{ "frequency_info",	frequency_info, },
-	{ NULL,			NULL,}
+	{ "bus_info",		bus_info },
+	{ "tr_info",		tr_info, }
 };
 
+#define NR_PALINFO_ENTRIES	(sizeof(palinfo_entries)/sizeof(palinfo_entry_t))
+
+/*
+ * this array is used to keep track of the proc entries we create. This is 
+ * required in the module mode when we need to remove all entries. The procfs code
+ * does not do recursion of deletion
+ *
+ * Notes:
+ *	- first +1 accounts for the cpuN entry
+ *	- second +1 account for toplevel palinfo
+ * 
+ */
+#define NR_PALINFO_PROC_ENTRIES	(NR_CPUS*(NR_PALINFO_ENTRIES+1)+1)
+
+static struct proc_dir_entry *palinfo_proc_entries[NR_PALINFO_PROC_ENTRIES];
+
+/*
+ * This data structure is used to pass which cpu,function is being requested
+ * It must fit in a 64bit quantity to be passed to the proc callback routine
+ *
+ * In SMP mode, when we get a request for another CPU, we must call that
+ * other CPU using IPI and wait for the result before returning.
+ */
+typedef union {
+	u64 value;
+	struct {
+		unsigned	req_cpu: 32;	/* for which CPU this info is */
+		unsigned	func_id: 32;	/* which function is requested */
+	} pal_func_cpu;
+} pal_func_cpu_u_t;
+
+#define req_cpu	pal_func_cpu.req_cpu
+#define func_id pal_func_cpu.func_id
+
+#ifdef CONFIG_SMP
+
+/*
+ * used to hold information about final function to call 
+ */
+typedef struct {
+	palinfo_func_t	func;	/* pointer to function to call */
+	char		*page;	/* buffer to store results */
+	int		ret;	/* return value from call */
+} palinfo_smp_data_t;
+
+
+/*
+ * this function does the actual final call and he called
+ * from the smp code, i.e., this is the palinfo callback routine
+ */
+static void
+palinfo_smp_call(void *info)
+{
+	palinfo_smp_data_t *data = (palinfo_smp_data_t *)info;
+	/* printk(__FUNCTION__" called on CPU %d\n", smp_processor_id());*/
+	if (data = NULL) {
+		printk(KERN_ERR __FUNCTION__" data pointer is NULL\n");
+		data->ret = 0; /* no output */
+		return;
+	}
+	/* does this actual call */
+	data->ret = (*data->func)(data->page);
+}
+
+/*
+ * function called to trigger the IPI, we need to access a remote CPU
+ * Return:
+ *	0 : error or nothing to output
+ *	otherwise how many bytes in the "page" buffer were written
+ */
+static 
+int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page)
+{
+	palinfo_smp_data_t ptr;
+	int ret;
+
+	ptr.func = palinfo_entries[f->func_id].proc_read;
+	ptr.page = page;
+	ptr.ret  = 0; /* just in case */
+
+	/*printk(__FUNCTION__" calling CPU %d from CPU %d for function %d\n", f->req_cpu,smp_processor_id(), f->func_id);*/
+
+	/* will send IPI to other CPU and wait for completion of remote call */
+	if ((ret=smp_call_function_single(f->req_cpu, palinfo_smp_call, &ptr, 0, 1))) {
+		printk(__FUNCTION__" remote CPU call from %d to %d on function %d: error %d\n", smp_processor_id(), f->req_cpu, f->func_id, ret);
+		return 0;
+	}
+	return ptr.ret;
+}
+#else /* ! CONFIG_SMP */
+static 
+int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page)
+{
+	printk(__FUNCTION__" should not be called with non SMP kernel\n");
+	return 0;
+}
+#endif /* CONFIG_SMP */
+
+/*
+ * Entry point routine: all calls go through this function
+ */
+static int
+palinfo_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	int len=0;
+	pal_func_cpu_u_t *f = (pal_func_cpu_u_t *)&data;
+
+	/*
+	 * in SMP mode, we may need to call another CPU to get correct
+	 * information. PAL, by definition, is processor specific
+	 */
+	if (f->req_cpu = smp_processor_id()) 
+		len = (*palinfo_entries[f->func_id].proc_read)(page);
+	else
+		len = palinfo_handle_smp(f, page);
+
+        if (len <= off+count) *eof = 1;
+
+        *start = page + off;
+        len   -= off;
+
+        if (len>count) len = count;
+        if (len<0) len = 0;
+
+        return len;
+}
 
 static int __init 
 palinfo_init(void)
 {
+#	define CPUSTR	"cpu%d"
+
 	palinfo_entry_t *p;
+	pal_func_cpu_u_t f;
+	struct proc_dir_entry **pdir = palinfo_proc_entries;
+	struct proc_dir_entry *palinfo_dir, *cpu_dir;
+	int i, j;
+	char cpustr[sizeof(CPUSTR)];
 
 	printk(KERN_INFO "PAL Information Facility v%s\n", PALINFO_VERSION);
 
-	palinfo_dir = create_proc_entry("palinfo",  S_IFDIR | S_IRUGO | S_IXUGO, NULL);
+	palinfo_dir = proc_mkdir("pal", 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);
+	/*
+	 * we keep track of created entries in a depth-first order for
+	 * cleanup purposes. Each entry is stored into palinfo_proc_entries
+	 */
+	for (i=0; i < NR_CPUS; i++) {
+
+		if (!cpu_is_online(i)) continue;
+
+		sprintf(cpustr,CPUSTR, i);
+
+		cpu_dir = proc_mkdir(cpustr, palinfo_dir);
+
+		f.req_cpu = i;
+
+		for (j=0; j < NR_PALINFO_ENTRIES; j++) {
+			f.func_id = j;
+			*pdir++ = create_proc_read_entry (palinfo_entries[j].name, 0, cpu_dir, 
+						palinfo_read_entry, (void *)f.value);
+		}
+		*pdir++ = cpu_dir;
 	}
+	*pdir = palinfo_dir;
 
 	return 0;
 }
@@ -766,12 +1055,12 @@
 static int __exit
 palinfo_exit(void)
 {
-	palinfo_entry_t *p;
+	int i = 0;
 
-	for (p = palinfo_entries; p->name ; p++){
-		remove_proc_entry (p->name, palinfo_dir);
+	/* remove all nodes: depth first pass */
+	for (i=0; i< NR_PALINFO_PROC_ENTRIES ; i++) {
+		remove_proc_entry (palinfo_proc_entries[i]->name, NULL);
 	}
-	remove_proc_entry ("palinfo", 0);
 
 	return 0;
 }
diff -urN linux-davidm/arch/ia64/kernel/pci-dma.c linux-2.4.0-test4-lia/arch/ia64/kernel/pci-dma.c
--- linux-davidm/arch/ia64/kernel/pci-dma.c	Thu Jun 22 07:09:44 2000
+++ linux-2.4.0-test4-lia/arch/ia64/kernel/pci-dma.c	Fri Jul 28 23:10:22 2000
@@ -3,34 +3,424 @@
  *
  * This implementation is for IA-64 platforms that do not support
  * I/O TLBs (aka DMA address translation hardware).
- *
- * XXX This doesn't do the right thing yet.  It appears we would have
- * to add additional zones so we can implement the various address
- * mask constraints that we might encounter.  A zone for memory < 32
- * bits is obviously necessary...
+ * Goutham Rao <goutham.rao@intel.com>: Implemented the PCI DMA mapping API.
  */
 
-#include <linux/types.h>
+#include <linux/config.h>
+
 #include <linux/mm.h>
-#include <linux/string.h>
 #include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/types.h>
 
 #include <asm/io.h>
+#include <asm/pci.h>
+#include <asm/dma.h>
+
+#ifdef CONFIG_SWIOTLB
+
+#include <linux/init.h>
+#include <linux/bootmem.h>
+
+#define ALIGN(val, align) ((void *) (((unsigned long) (val) + ((align) - 1)) & ~((align) - 1)))
+
+typedef struct io_tlb_sizes {
+	size_t		size;
+	int		log_size;
+	int		n_buffers;
+	int		curr_index;
+	spinlock_t	lock;
+	char		*base;
+	unsigned long	*orig_addr;
+	unsigned int	*free_list;
+} io_tlb_sizes_t;
+
+/*
+ * List entries in order of size (low to high)
+ */
+static io_tlb_sizes_t io_tlb[] = {
+	{2048, 11, 128, 127, SPIN_LOCK_UNLOCKED, 0, 0, 0},
+	{PAGE_SIZE, PAGE_SHIFT, 128, 127, SPIN_LOCK_UNLOCKED, 0, 0, 0},
+	/*
+	 * Indicated end of entries
+	 */	
+	{0, 0, 0, 0, SPIN_LOCK_UNLOCKED, 0, 0, 0}
+};
+
+/*
+ * Used to do a quick range check in pci_unmap_single and pci_sync_single
+ */
+static char *io_tlb_start, *io_tlb_end;
+
+static unsigned long swiotlb_buf_count;
+
+static int __init
+setup_swiotlb_buf_count (char *str)
+{
+	swiotlb_buf_count = simple_strtoul(str, NULL, 0);
+	return 1;
+}
+
+__setup("swiotlb=", setup_swiotlb_buf_count);
+
+/*
+ * Statically reserve bounce buffer space and initialize bounce buffer
+ * data structures for the software IO TLB used to implement the PCI DMA API
+ */
+void
+setup_swiotlb (void)
+{
+	unsigned long entry_size, size = 0;
+	struct io_tlb_sizes *itp;
+
+	for (itp = io_tlb; itp->size; ++itp) {
+		/*
+		 * Let user override number of buffers needed
+		 */
+		if (swiotlb_buf_count)
+			itp->n_buffers = swiotlb_buf_count;
+		itp->curr_index = itp->n_buffers - 1;
+		/*
+		 * size needed for buffers + size needed for offset
+		 * table + size needed for mapping:
+		 */
+		entry_size = itp->size + sizeof(int) + sizeof(long);
+		/* the +1 makes room for the worst-case alignment... */
+		size += (itp->n_buffers + 1)*entry_size;
+	}
+
+	/*
+	 * Now get IO TLB memory from the low pages
+	 */
+	io_tlb_start = io_tlb_end = alloc_bootmem_low_pages(size);
+	if (!io_tlb_start)
+		BUG();
+
+	/*
+	 * For every io tlb size entry, allocate the required amount of memory
+	 * and initialize the free list array to mark all entries as available
+	 */
+	for (itp = io_tlb; itp->size; ++itp) {
+		int j;
+
+		/*
+		 * Reserve memory for the IO TLB buffers and the
+		 * offsets array for these size chunks
+		 */
+		itp->base = ALIGN(io_tlb_end, itp->size);
+		io_tlb_end = itp->base + itp->size * itp->n_buffers;
+
+		itp->orig_addr = ALIGN(io_tlb_end, sizeof(long));
+		io_tlb_end = ((char *)itp->orig_addr) + itp->n_buffers * sizeof(long);
+
+		itp->free_list = (unsigned int *)io_tlb_end;
+		io_tlb_end = ((char *)itp->free_list) + itp->n_buffers * sizeof(int);
+
+		/* 
+		 * Initialize free list array, marking all entries available
+		 */	
+		for (j = 0; j < itp->n_buffers; j++)
+			itp->free_list[j] = (unsigned int)(j * itp->size);
+	}
+	printk("Placing software IO TLB between 0x%p - 0x%p\n", io_tlb_start, io_tlb_end);
+}
+
+/*
+ * Allocates bounce buffer and returns its kernel virtual address.
+ */
+static void *
+__pci_map_single (struct pci_dev *hwdev, char *buffer, size_t size, int direction)
+{
+	struct io_tlb_sizes *itp;
+	char *dma_addr = 0;
+	int index;
+
+	/*
+	 * Find a IO TLB size that will fit this request and allocate a buffer
+	 * from that IO TLB pool.
+	 */
+	for (itp = io_tlb; itp->size; ++itp) {
+		if (size <= itp->size) {
+			unsigned long flags;
+
+			spin_lock_irqsave(&itp->lock, flags);
+			{
+				if (!itp->curr_index) {
+					/*
+					 * Get buffer from next IO TLB... this will
+					 * waste memory though.
+					 */
+					spin_unlock_irqrestore(&itp->lock, flags);
+					continue;
+				}
+				dma_addr = (itp->base + itp->free_list[itp->curr_index--]);
+			}
+			spin_unlock_irqrestore(&itp->lock, flags);
+			/*
+			 * Save the mapping from original address to DMA address
+			 * because the map_single API doesen't have a mapping 
+			 * like the map_sg API.
+			 */
+			index = (dma_addr - itp->base) >> itp->log_size;
+			itp->orig_addr[index] = (unsigned long) buffer;
+
+			if (direction = PCI_DMA_TODEVICE || direction = PCI_DMA_BIDIRECTIONAL)
+				memcpy(dma_addr, buffer, size);
+
+			return dma_addr;
+		}
+	}
+
+	/*
+	 * XXX What is a suitable recovery mechanism here?  We cannot 
+	 * sleep because we are called from with in interrupts!
+	 */
+	panic("__pci_map_single: could not allocate software IO TLB (%ld bytes)", size);
+}
+
+/*
+ * dma_addr is the kernel virtual address of the bounce buffer to unmap.
+ */
+static void
+__pci_unmap_single (struct pci_dev *hwdev, char *dma_addr, size_t size, int direction)
+{
+	struct io_tlb_sizes *itp;
+
+	/*
+	 * Return the buffer to the free list
+	 */
+	for (itp = io_tlb; itp->size; ++itp) {
+		if (size <= itp->size) {
+			unsigned long flags;
+			char *buffer;
+			int index;
+
+			/*
+	 	 	 * Get the mapping (IO address to original address)... 
+		 	 */
+			index = (dma_addr - itp->base) >> itp->log_size;
+			buffer = (char *) itp->orig_addr[index];
+			if ((direction = PCI_DMA_FROMDEVICE)
+			    || (direction = PCI_DMA_BIDIRECTIONAL))
+				/*
+ 	 	 		 * bounce... copy the data back into the original buffer
+	 	 		 * and delete the bounce buffer.
+ 	 	 		 */
+				memcpy(buffer, dma_addr, size);
+
+			/*
+			 * Return the entry to the list
+			 */
+			spin_lock_irqsave(&itp->lock, flags);
+			{
+				itp->free_list[++itp->curr_index] = (dma_addr - itp->base);
+			}
+			spin_unlock_irqrestore(&itp->lock, flags);
+			return;
+		}
+	}
+	BUG();
+}
+
+static void
+__pci_sync_single (struct pci_dev *hwdev, char *dma_addr, size_t size, int direction)
+{
+	struct io_tlb_sizes *itp;
+	char *buffer;
+	int index;
+
+	/*
+  	 * bounce... copy the data back into/from the original buffer
+	 * XXX How do you handle PCI_DMA_BIDIRECTIONAL here ?
+ 	 */
+	for (itp = io_tlb; itp->size; ++itp) {
+		if (size <= itp->size) {
+			/*
+	 	 	 * Get the mapping (IO address to original address)... 
+		 	 */
+			index = (dma_addr - itp->base) >> itp->log_size;
+			buffer = (char *) itp->orig_addr[index];
+			if (direction = PCI_DMA_FROMDEVICE)
+				memcpy(buffer, dma_addr, size);
+			else if (direction = PCI_DMA_TODEVICE)
+				memcpy(dma_addr, buffer, size);
+			else
+				BUG();
+			break;
+		}
+	}
+}
+
+/*
+ * Map a single buffer of the indicated size for DMA in streaming mode.
+ * The PCI address to use is returned.
+ *
+ * Once the device is given the dma address, the device owns this memory
+ * until either pci_unmap_single or pci_dma_sync_single is performed.
+ */
+dma_addr_t
+pci_map_single (struct pci_dev *hwdev, void *ptr, size_t size, int direction)
+{
+	unsigned long pci_addr = virt_to_phys(ptr);
+
+	if (direction = PCI_DMA_NONE)
+		BUG();
+	/*
+	 * Check if the PCI device can DMA to ptr... if so, just return ptr
+	 */
+	if ((pci_addr & ~hwdev->dma_mask) = 0)
+		/*
+		 * Device is bit capable of DMA'ing to the
+		 * buffer... just return the PCI address of ptr
+		 */
+		return pci_addr;
+
+	/* get a bounce buffer: */
+
+	pci_addr = virt_to_phys(__pci_map_single(hwdev, ptr, size, direction));
+	/*
+	 * Ensure that the address returned is DMA'ble:
+	 */
+	if ((pci_addr & ~hwdev->dma_mask) != 0)
+		panic("__pci_map_single: bounce buffer is not DMA'ble");
+
+	return pci_addr;
+}
+
+/*
+ * Unmap a single streaming mode DMA translation.  The dma_addr and size
+ * must match what was provided for in a previous pci_map_single call.  All
+ * other usages are undefined.
+ *
+ * After this call, reads by the cpu to the buffer are guarenteed to see
+ * whatever the device wrote there.
+ */
+void
+pci_unmap_single (struct pci_dev *hwdev, dma_addr_t pci_addr, size_t size, int direction)
+{
+	char *dma_addr = phys_to_virt(pci_addr);
+
+	if (direction = PCI_DMA_NONE)
+		BUG();
+	if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
+		__pci_unmap_single(hwdev, dma_addr, size, direction);
+}
+
+/*
+ * Make physical memory consistent for a single
+ * streaming mode DMA translation after a transfer.
+ *
+ * If you perform a pci_map_single() but wish to interrogate the
+ * buffer using the cpu, yet do not wish to teardown the PCI dma
+ * mapping, you must call this function before doing so.  At the
+ * next point you give the PCI dma address back to the card, the
+ * device again owns the buffer.
+ */
+void
+pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t pci_addr, size_t size, int direction)
+{
+	char *dma_addr = phys_to_virt(pci_addr);
+
+	if (direction = PCI_DMA_NONE)
+		BUG();
+	if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
+		__pci_sync_single(hwdev, dma_addr, size, direction);
+}
+
+/*
+ * Map a set of buffers described by scatterlist in streaming
+ * mode for DMA.  This is the scather-gather version of the
+ * above pci_map_single interface.  Here the scatter gather list
+ * elements are each tagged with the appropriate dma address
+ * and length.  They are obtained via sg_dma_{address,length}(SG).
+ *
+ * NOTE: An implementation may be able to use a smaller number of
+ *       DMA address/length pairs than there are SG table elements.
+ *       (for example via virtual mapping capabilities)
+ *       The routine returns the number of addr/length pairs actually
+ *       used, at most nents.
+ *
+ * Device ownership issues as mentioned above for pci_map_single are
+ * the same here.
+ */
+int
+pci_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
+{
+	int i;
+
+	if (direction = PCI_DMA_NONE)
+		BUG();
+
+	for (i = 0; i < nelems; i++, sg++) {
+		sg->orig_address = sg->address;
+		if ((virt_to_phys(sg->address) & ~hwdev->dma_mask) != 0) {
+			sg->address = __pci_map_single(hwdev, sg->address, sg->length, direction);
+		}
+	}
+	return nelems;
+}
+
+/*
+ * Unmap a set of streaming mode DMA translations.
+ * Again, cpu read rules concerning calls here are the same as for
+ * pci_unmap_single() above.
+ */
+void
+pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
+{
+	int i;
+
+	if (direction = PCI_DMA_NONE)
+		BUG();
+
+	for (i = 0; i < nelems; i++, sg++)
+		if (sg->orig_address != sg->address) {
+			__pci_unmap_single(hwdev, sg->address, sg->length, direction);
+			sg->address = sg->orig_address;
+		}
+}
+
+/*
+ * Make physical memory consistent for a set of streaming mode DMA
+ * translations after a transfer.
+ *
+ * The same as pci_dma_sync_single but for a scatter-gather list,
+ * same rules and usage.
+ */
+void
+pci_dma_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
+{
+	int i;
+
+	if (direction = PCI_DMA_NONE)
+		BUG();
+
+	for (i = 0; i < nelems; i++, sg++)
+		if (sg->orig_address != sg->address)
+			__pci_sync_single(hwdev, sg->address, sg->length, direction);
+}
+
+#endif /* CONFIG_SWIOTLB */
 
 void *
 pci_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
 {
-	void *ret;
+	unsigned long pci_addr;
 	int gfp = GFP_ATOMIC;
+	void *ret;
 
-	if (!hwdev || hwdev->dma_mask = 0xffffffff)
-		gfp |= GFP_DMA;	/* XXX fix me: should change this to GFP_32BIT or ZONE_32BIT */
+	if (!hwdev || hwdev->dma_mask <= 0xffffffff)
+		gfp |= GFP_DMA; /* XXX fix me: should change this to GFP_32BIT or ZONE_32BIT */
 	ret = (void *)__get_free_pages(gfp, get_order(size));
+	if (!ret)
+		return NULL;
 
-	if (ret) {
-		memset(ret, 0, size);
-		*dma_handle = virt_to_bus(ret);
-	}
+	memset(ret, 0, size);
+	pci_addr = virt_to_phys(ret);
+	if ((pci_addr & ~hwdev->dma_mask) != 0)
+		panic("pci_alloc_consistent: allocated memory is out of range for PCI device");
+	*dma_handle = pci_addr;
 	return ret;
 }
 
diff -urN linux-davidm/arch/ia64/kernel/process.c linux-2.4.0-test4-lia/arch/ia64/kernel/process.c
--- linux-davidm/arch/ia64/kernel/process.c	Fri Jul 28 23:48:24 2000
+++ linux-2.4.0-test4-lia/arch/ia64/kernel/process.c	Fri Jul 28 23:10:40 2000
@@ -532,17 +532,6 @@
 	}
 }
 
-/*
- * Free remaining state associated with DEAD_TASK.  This is called
- * after the parent of DEAD_TASK has collected the exist status of the
- * task via wait().
- */
-void
-release_thread (struct task_struct *dead_task)
-{
-	/* nothing to do */
-}
-
 unsigned long
 get_wchan (struct task_struct *p)
 {
diff -urN linux-davidm/arch/ia64/kernel/ptrace.c linux-2.4.0-test4-lia/arch/ia64/kernel/ptrace.c
--- linux-davidm/arch/ia64/kernel/ptrace.c	Fri Jul 28 23:48:24 2000
+++ linux-2.4.0-test4-lia/arch/ia64/kernel/ptrace.c	Fri Jul 28 23:10:52 2000
@@ -549,6 +549,7 @@
 ia64_sync_fph (struct task_struct *child)
 {
 	if (ia64_psr(ia64_task_regs(child))->mfh && ia64_get_fpu_owner() = child) {
+		ia64_psr(ia64_task_regs(child))->mfh = 0;
 		ia64_set_fpu_owner(0);
 		ia64_save_fpu(&child->thread.fph[0]);
 		child->thread.flags |= IA64_THREAD_FPH_VALID;
diff -urN linux-davidm/arch/ia64/kernel/setup.c linux-2.4.0-test4-lia/arch/ia64/kernel/setup.c
--- linux-davidm/arch/ia64/kernel/setup.c	Fri Jul 28 23:48:24 2000
+++ linux-2.4.0-test4-lia/arch/ia64/kernel/setup.c	Fri Jul 28 23:11:03 2000
@@ -122,6 +122,10 @@
 	 */
 	memcpy(&ia64_boot_param, (void *) ZERO_PAGE_ADDR, sizeof(ia64_boot_param));
 
+	*cmdline_p = __va(ia64_boot_param.command_line);
+	strncpy(saved_command_line, *cmdline_p, sizeof(saved_command_line));
+	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';		/* for safety */
+
 	efi_init();
 
 	max_pfn = 0;
@@ -164,27 +168,21 @@
 	/* process SAL system table: */
 	ia64_sal_init(efi.sal_systab);
 
-	*cmdline_p = __va(ia64_boot_param.command_line);
-	strncpy(saved_command_line, *cmdline_p, sizeof(saved_command_line));
-	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';		/* for safety */
-
-	printk("args to kernel: %s\n", *cmdline_p);
-
 #ifdef CONFIG_SMP
 	bootstrap_processor = hard_smp_processor_id();
 	current->processor = bootstrap_processor;
 #endif
 	cpu_init();	/* initialize the bootstrap CPU */
 
+#ifdef CONFIG_IA64_GENERIC
+	machvec_init(acpi_get_sysname());
+#endif
+
 	if (efi.acpi) {
 		/* Parse the ACPI tables */
 		acpi_parse(efi.acpi);
 	}
 
-#ifdef CONFIG_IA64_GENERIC
-	machvec_init(acpi_get_sysname());
-#endif
-
 #ifdef CONFIG_VT
 # if defined(CONFIG_VGA_CONSOLE)
 	conswitchp = &vga_con;
@@ -197,8 +195,16 @@
 	/* enable IA-64 Machine Check Abort Handling */
 	ia64_mca_init();
 #endif
+
 	paging_init();
 	platform_setup(cmdline_p);
+
+#ifdef CONFIG_SWIOTLB
+	{
+		extern void setup_swiotlb (void);
+		setup_swiotlb();
+	}
+#endif
 }
 
 /*
diff -urN linux-davidm/arch/ia64/kernel/smp.c linux-2.4.0-test4-lia/arch/ia64/kernel/smp.c
--- linux-davidm/arch/ia64/kernel/smp.c	Fri Jul 28 23:48:24 2000
+++ linux-2.4.0-test4-lia/arch/ia64/kernel/smp.c	Fri Jul 28 23:11:44 2000
@@ -320,6 +320,58 @@
 #endif	/* !CONFIG_ITANIUM_PTCG */
 
 /*
+ * Run a function on another CPU
+ *  <func>	The function to run. This must be fast and non-blocking.
+ *  <info>	An arbitrary pointer to pass to the function.
+ *  <retry>	If true, keep retrying until ready.
+ *  <wait>	If true, wait until function has completed on other CPUs.
+ *  [RETURNS]   0 on success, else a negative status code.
+ *
+ * Does not return until the remote CPU is nearly ready to execute <func>
+ * or is or has executed.
+ */
+
+int
+smp_call_function_single (int cpuid, void (*func) (void *info), void *info, int retry, int wait)
+{
+	struct smp_call_struct data;
+	long timeout;
+	int cpus = 1;
+
+	if (cpuid = smp_processor_id()) {
+		printk(__FUNCTION__" trying to call self\n");
+		return -EBUSY;
+	}
+	
+	data.func = func;
+	data.info = info;
+	data.wait = wait;
+	atomic_set(&data.unstarted_count, cpus);
+	atomic_set(&data.unfinished_count, cpus);
+
+	if (pointer_lock(&smp_call_function_data, &data, retry))
+		return -EBUSY;
+
+	/*  Send a message to all other CPUs and wait for them to respond  */
+	send_IPI_single(cpuid, IPI_CALL_FUNC);
+
+	/*  Wait for response  */
+	timeout = jiffies + HZ;
+	while ((atomic_read(&data.unstarted_count) > 0) && time_before(jiffies, timeout))
+		barrier();
+	if (atomic_read(&data.unstarted_count) > 0) {
+		smp_call_function_data = NULL;
+		return -ETIMEDOUT;
+	}
+	if (wait)
+		while (atomic_read(&data.unfinished_count) > 0)
+			barrier();
+	/* unlock pointer */
+	smp_call_function_data = NULL;
+	return 0;
+}
+
+/*
  * Run a function on all other CPUs.
  *  <func>	The function to run. This must be fast and non-blocking.
  *  <info>	An arbitrary pointer to pass to the function.
@@ -497,6 +549,8 @@
 	extern void ia64_rid_init(void);
 	extern void ia64_init_itm(void);
 	extern void ia64_cpu_local_tick(void);
+
+	efi_map_pal_code();
 
 	cpu_init();
 
diff -urN linux-davidm/arch/ia64/kernel/time.c linux-2.4.0-test4-lia/arch/ia64/kernel/time.c
--- linux-davidm/arch/ia64/kernel/time.c	Fri Jul 28 23:48:24 2000
+++ linux-2.4.0-test4-lia/arch/ia64/kernel/time.c	Fri Jul 28 23:12:00 2000
@@ -150,11 +150,13 @@
 static void
 timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	static unsigned long last_time;
-	static unsigned char count;
 	int cpu = smp_processor_id();
 	unsigned long new_itm;
+#if 0
+	static unsigned long last_time;
+	static unsigned char count;
 	int printed = 0;
+#endif
 
 	/*
 	 * Here we are in the timer irq handler. We have irqs locally
@@ -192,7 +194,7 @@
 		if (time_after(new_itm, ia64_get_itc()))
 			break;
 
-#if !(defined(CONFIG_IA64_SOFTSDV_HACKS) && defined(CONFIG_SMP))
+#if 0
 		/*
 		 * SoftSDV in SMP mode is _slow_, so we do "lose" ticks, 
 		 * but it's really OK...
diff -urN linux-davidm/arch/ia64/kernel/traps.c linux-2.4.0-test4-lia/arch/ia64/kernel/traps.c
--- linux-davidm/arch/ia64/kernel/traps.c	Thu Jun 22 07:09:44 2000
+++ linux-2.4.0-test4-lia/arch/ia64/kernel/traps.c	Fri Jul 28 23:12:31 2000
@@ -204,11 +204,13 @@
 {
 	struct task_struct *fpu_owner = ia64_get_fpu_owner();
 
+	/* first, clear psr.dfh and psr.mfh: */
 	regs->cr_ipsr &= ~(IA64_PSR_DFH | IA64_PSR_MFH);
 	if (fpu_owner != current) {
 		ia64_set_fpu_owner(current);
 
 		if (fpu_owner && ia64_psr(ia64_task_regs(fpu_owner))->mfh) {
+			ia64_psr(ia64_task_regs(fpu_owner))->mfh = 0;
 			fpu_owner->thread.flags |= IA64_THREAD_FPH_VALID;
 			__ia64_save_fpu(fpu_owner->thread.fph);
 		}
@@ -216,6 +218,11 @@
 			__ia64_load_fpu(current->thread.fph);
 		} else {
 			__ia64_init_fpu();
+			/*
+			 * Set mfh because the state in thread.fph does not match
+			 * the state in the fph partition.
+			 */
+			ia64_psr(regs)->mfh = 1;
 		}
 	}
 }
diff -urN linux-davidm/arch/ia64/mm/init.c linux-2.4.0-test4-lia/arch/ia64/mm/init.c
--- linux-davidm/arch/ia64/mm/init.c	Thu Jun 22 07:09:45 2000
+++ linux-2.4.0-test4-lia/arch/ia64/mm/init.c	Fri Jul 28 23:13:48 2000
@@ -423,5 +423,4 @@
 #ifdef CONFIG_IA32_SUPPORT
 	ia32_gdt_init();
 #endif
-	return;
 }
diff -urN linux-davidm/arch/ia64/sn/sn1/irq.c linux-2.4.0-test4-lia/arch/ia64/sn/sn1/irq.c
--- linux-davidm/arch/ia64/sn/sn1/irq.c	Tue Feb  8 12:01:59 2000
+++ linux-2.4.0-test4-lia/arch/ia64/sn/sn1/irq.c	Fri Jul 28 23:13:59 2000
@@ -1,9 +1,10 @@
 #include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/sched.h>
 
-#include <asm/irq.h>
 #include <asm/ptrace.h>
 
-static int
+static unsigned int
 sn1_startup_irq(unsigned int irq)
 {
         return(0);
@@ -24,23 +25,16 @@
 {
 }
 
-static int
-sn1_handle_irq(unsigned int irq, struct pt_regs *regs)
-{
-       return(0);
-}
-
 struct hw_interrupt_type irq_type_sn1 = {
         "sn1_irq",
         sn1_startup_irq,
         sn1_shutdown_irq,
-        sn1_handle_irq,
         sn1_enable_irq,
         sn1_disable_irq
 };
 
 void
-sn1_irq_init (struct irq_desc desc[NR_IRQS])
+sn1_irq_init (void)
 {
 	int i;
 
diff -urN linux-davidm/arch/ia64/sn/sn1/machvec.c linux-2.4.0-test4-lia/arch/ia64/sn/sn1/machvec.c
--- linux-davidm/arch/ia64/sn/sn1/machvec.c	Sun Feb  6 18:42:40 2000
+++ linux-2.4.0-test4-lia/arch/ia64/sn/sn1/machvec.c	Fri Jul 28 23:14:09 2000
@@ -1,4 +1,2 @@
+#define MACHVEC_PLATFORM_NAME	sn1
 #include <asm/machvec_init.h>
-#include <asm/machvec_sn1.h>
-
-MACHVEC_DEFINE(sn1)
diff -urN linux-davidm/arch/ia64/sn/sn1/setup.c linux-2.4.0-test4-lia/arch/ia64/sn/sn1/setup.c
--- linux-davidm/arch/ia64/sn/sn1/setup.c	Mon May  8 22:00:01 2000
+++ linux-2.4.0-test4-lia/arch/ia64/sn/sn1/setup.c	Fri Jul 28 23:25:02 2000
@@ -13,6 +13,7 @@
 #include <linux/console.h>
 #include <linux/timex.h>
 #include <linux/sched.h>
+#include <linux/ioport.h>
 
 #include <asm/io.h>
 #include <asm/machvec.h>
diff -urN linux-davidm/arch/ia64/vmlinux.lds.S linux-2.4.0-test4-lia/arch/ia64/vmlinux.lds.S
--- linux-davidm/arch/ia64/vmlinux.lds.S	Fri Jul 28 23:48:24 2000
+++ linux-2.4.0-test4-lia/arch/ia64/vmlinux.lds.S	Fri Jul 28 23:15:14 2000
@@ -46,6 +46,15 @@
 	{ *(__ex_table) }
   __stop___ex_table = .;
 
+#if defined(CONFIG_IA64_GENERIC)
+  /* Machine Vector */
+  . = ALIGN(16);
+  machvec_start = .;
+  .machvec : AT(ADDR(.machvec) - PAGE_OFFSET)
+	{ *(.machvec) }
+  machvec_end = .;
+#endif
+
   __start___ksymtab = .;	/* Kernel symbol table */
   __ksymtab : AT(ADDR(__ksymtab) - PAGE_OFFSET)
 	{ *(__ksymtab) }
diff -urN linux-davidm/drivers/net/eepro100.c linux-2.4.0-test4-lia/drivers/net/eepro100.c
--- linux-davidm/drivers/net/eepro100.c	Fri Jul 28 23:48:24 2000
+++ linux-2.4.0-test4-lia/drivers/net/eepro100.c	Fri Jul 28 23:15:43 2000
@@ -23,6 +23,8 @@
 		Convert to new PCI driver interface
 	2000 Mar 24  Dragan Stancevic <visitor@valinux.com>
 		Disabled FC and ER, to avoid lockups when when we get FCP interrupts.
+	2000 Jul 17 Goutham Rao <goutham.rao@intel.com>
+		PCI DMA API fixes, adding pci_dma_sync_single calls where neccesary
 */
 
 static const char *version @@ -524,6 +526,7 @@
 	spinlock_t lock;					/* Group with Tx control cache line. */
 	u32 tx_threshold;					/* The value for txdesc.count. */
 	struct RxFD *last_rxf;				/* Last filled RX buffer. */
+	dma_addr_t last_rxf_dma;
 	unsigned int cur_rx, dirty_rx;		/* The next free ring entry */
 	long last_rx_time;			/* Last Rx, in jiffies, to handle Rx hang. */
 	const char *product_name;
@@ -1219,19 +1222,24 @@
 		sp->rx_ring_dma[i]  			pci_map_single(sp->pdev, rxf, PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
 		skb_reserve(skb, sizeof(struct RxFD));
-		if (last_rxf)
+		if (last_rxf) {
 			last_rxf->link = cpu_to_le32(sp->rx_ring_dma[i]);
+			pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[i-1], sizeof(struct RxFD), PCI_DMA_TODEVICE);
+		}
 		last_rxf = rxf;
 		rxf->status = cpu_to_le32(0x00000001);	/* '1' is flag value only. */
 		rxf->link = 0;						/* None yet. */
 		/* This field unused by i82557. */
 		rxf->rx_buf_addr = 0xffffffff;
 		rxf->count = cpu_to_le32(PKT_BUF_SZ << 16);
+		pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[i], sizeof(struct RxFD), PCI_DMA_TODEVICE);
 	}
 	sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
 	/* Mark the last entry as end-of-list. */
 	last_rxf->status = cpu_to_le32(0xC0000002);	/* '2' is flag value only. */
+	pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[RX_RING_SIZE-1], sizeof(struct RxFD), PCI_DMA_TODEVICE);
 	sp->last_rxf = last_rxf;
+	sp->last_rxf_dma = sp->rx_ring_dma[RX_RING_SIZE-1];
 }
 
 static void speedo_purge_tx(struct net_device *dev)
@@ -1666,6 +1674,7 @@
 	skb->dev = dev;
 	skb_reserve(skb, sizeof(struct RxFD));
 	rxf->rx_buf_addr = 0xffffffff;
+	pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], sizeof(struct RxFD), PCI_DMA_TODEVICE);
 	return rxf;
 }
 
@@ -1678,7 +1687,9 @@
 	rxf->count = cpu_to_le32(PKT_BUF_SZ << 16);
 	sp->last_rxf->link = cpu_to_le32(rxf_dma);
 	sp->last_rxf->status &= cpu_to_le32(~0xC0000000);
+	pci_dma_sync_single(sp->pdev, sp->last_rxf_dma, sizeof(struct RxFD), PCI_DMA_TODEVICE);
 	sp->last_rxf = rxf;
+	sp->last_rxf_dma = rxf_dma;
 }
 
 static int speedo_refill_rx_buf(struct net_device *dev, int force)
@@ -1744,9 +1755,17 @@
 	if (speedo_debug > 4)
 		printk(KERN_DEBUG " In speedo_rx().\n");
 	/* If we own the next entry, it's a new packet. Send it up. */
-	while (sp->rx_ringp[entry] != NULL &&
-		   (status = le32_to_cpu(sp->rx_ringp[entry]->status)) & RxComplete) {
-		int pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff;
+	while (sp->rx_ringp[entry] != NULL) {
+		int pkt_len;
+
+		pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry],
+			sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
+
+		if(!((status = le32_to_cpu(sp->rx_ringp[entry]->status)) & RxComplete)) {
+			break;
+		}
+
+		pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff;
 
 		if (--rx_work_limit < 0)
 			break;
@@ -1788,7 +1807,8 @@
 				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 				/* 'skb_put()' points to the start of sk_buff data area. */
 				pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry],
-						PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
+					sizeof(struct RxFD) + pkt_len, PCI_DMA_FROMDEVICE);
+
 #if 1 || USE_IP_CSUM
 				/* Packet is in one chunk -- we can copy + cksum. */
 				eth_copy_and_sum(skb, sp->rx_skbuff[entry]->tail, pkt_len, 0);
@@ -2171,6 +2191,8 @@
 		/* Set the link in the setup frame. */
 		mc_setup_frm->link  			cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE));
+
+		pci_dma_sync_single(sp->pdev, mc_blk->frame_dma, mc_blk->len, PCI_DMA_TODEVICE);
 
 		wait_for_cmd_done(ioaddr + SCBCmd);
 		clear_suspend(last_cmd);
diff -urN linux-davidm/drivers/scsi/qla1280.c linux-2.4.0-test4-lia/drivers/scsi/qla1280.c
--- linux-davidm/drivers/scsi/qla1280.c	Mon Jun 19 13:42:40 2000
+++ linux-2.4.0-test4-lia/drivers/scsi/qla1280.c	Fri Jul 28 23:15:55 2000
@@ -809,6 +809,7 @@
 			index++, &pci_bus, &pci_devfn)) )  {
 #endif
                 /* found a adapter */
+		template->unchecked_isa_dma = 1;
 		host = scsi_register(template, sizeof(scsi_qla_host_t));
 		ha = (scsi_qla_host_t *) host->hostdata;
 		/* Clear our data area */
diff -urN linux-davidm/fs/buffer.c linux-2.4.0-test4-lia/fs/buffer.c
--- linux-davidm/fs/buffer.c	Tue Jul 11 14:29:02 2000
+++ linux-2.4.0-test4-lia/fs/buffer.c	Fri Jul 28 23:16:06 2000
@@ -1620,9 +1620,9 @@
 						PAGE_CACHE_SIZE, get_block);
 		if (status)
 			goto out_unmap;
-		kaddr = (char*)page_address(page);
+		kaddr = (char*)page_address(new_page);
 		memset(kaddr+zerofrom, 0, PAGE_CACHE_SIZE-zerofrom);
-		__block_commit_write(inode, new_page, zerofrom, to);
+		__block_commit_write(inode, new_page, zerofrom, PAGE_CACHE_SIZE);
 		kunmap(new_page);
 		UnlockPage(new_page);
 		page_cache_release(new_page);
diff -urN linux-davidm/include/asm-ia64/acpi-ext.h linux-2.4.0-test4-lia/include/asm-ia64/acpi-ext.h
--- linux-davidm/include/asm-ia64/acpi-ext.h	Tue Feb  8 12:01:59 2000
+++ linux-2.4.0-test4-lia/include/asm-ia64/acpi-ext.h	Fri Jul 28 23:16:20 2000
@@ -69,7 +69,7 @@
 	u8 eid;
 } acpi_entry_lsapic_t;
 
-typedef struct {
+typedef struct acpi_entry_iosapic {
 	u8 type;
 	u8 length;
 	u16 reserved;
diff -urN linux-davidm/include/asm-ia64/efi.h linux-2.4.0-test4-lia/include/asm-ia64/efi.h
--- linux-davidm/include/asm-ia64/efi.h	Fri Mar 10 15:24:02 2000
+++ linux-2.4.0-test4-lia/include/asm-ia64/efi.h	Fri Jul 28 23:40:25 2000
@@ -226,6 +226,7 @@
 }
 
 extern void efi_init (void);
+extern void efi_map_pal_code (void);
 extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg);
 extern void efi_gettimeofday (struct timeval *tv);
 extern void efi_enter_virtual_mode (void);	/* switch EFI to virtual mode, if possible */
diff -urN linux-davidm/include/asm-ia64/ia32.h linux-2.4.0-test4-lia/include/asm-ia64/ia32.h
--- linux-davidm/include/asm-ia64/ia32.h	Fri Jul 28 23:48:24 2000
+++ linux-2.4.0-test4-lia/include/asm-ia64/ia32.h	Fri Jul 28 23:16:34 2000
@@ -40,7 +40,6 @@
        __kernel_off_t32 l_start;
        __kernel_off_t32 l_len;
        __kernel_pid_t32 l_pid;
-       short __unused;
 };
 
 
@@ -105,11 +104,21 @@
 } sigset32_t;
 
 struct sigaction32 {
-       unsigned int  sa_handler;       /* Really a pointer, but need to deal 
-					  with 32 bits */
+       unsigned int  sa_handler;	/* Really a pointer, but need to deal 
+					     with 32 bits */
        unsigned int sa_flags;
-       unsigned int sa_restorer;       /* Another 32 bit pointer */
-       sigset32_t sa_mask;     /* A 32 bit mask */
+       unsigned int sa_restorer;	/* Another 32 bit pointer */
+       sigset32_t sa_mask;		/* A 32 bit mask */
+};
+
+typedef unsigned int old_sigset32_t;	/* at least 32 bits */
+
+struct old_sigaction32 {
+       unsigned int  sa_handler;	/* Really a pointer, but need to deal 
+					     with 32 bits */
+       old_sigset32_t sa_mask;		/* A 32 bit mask */
+       unsigned int sa_flags;
+       unsigned int sa_restorer;	/* Another 32 bit pointer */
 };
 
 typedef struct sigaltstack_ia32 {
diff -urN linux-davidm/include/asm-ia64/io.h linux-2.4.0-test4-lia/include/asm-ia64/io.h
--- linux-davidm/include/asm-ia64/io.h	Fri Apr 21 15:21:24 2000
+++ linux-2.4.0-test4-lia/include/asm-ia64/io.h	Fri Jul 28 23:37:15 2000
@@ -47,6 +47,10 @@
 	return (void *) (address + PAGE_OFFSET);
 }
 
+/*
+ * The following two macros are deprecated and scheduled for removal.
+ * Please use the PCI-DMA interface defined in <asm/pci.h> instead.
+ */
 #define bus_to_virt	phys_to_virt
 #define virt_to_bus	virt_to_phys
 
@@ -315,6 +319,7 @@
 #define writeq(v,a)	__writeq((v), (void *) (a))
 #define __raw_writeb	writeb
 #define __raw_writew	writew
+#define __raw_writel	writel
 #define __raw_writeq	writeq
 
 #ifndef inb_p
diff -urN linux-davidm/include/asm-ia64/machvec.h linux-2.4.0-test4-lia/include/asm-ia64/machvec.h
--- linux-davidm/include/asm-ia64/machvec.h	Fri Mar 10 15:24:02 2000
+++ linux-2.4.0-test4-lia/include/asm-ia64/machvec.h	Fri Jul 28 23:37:15 2000
@@ -4,8 +4,8 @@
  * Copyright (C) 1999 Silicon Graphics, Inc.
  * Copyright (C) Srinivasa Thirumalachar <sprasad@engr.sgi.com>
  * Copyright (C) Vijay Chander <vijay@engr.sgi.com>
- * Copyright (C) 1999 Hewlett-Packard Co.
- * Copyright (C) David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999-2000 Hewlett-Packard Co.
+ * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #ifndef _ASM_IA64_MACHVEC_H
 #define _ASM_IA64_MACHVEC_H
@@ -21,6 +21,7 @@
 struct task_struct;
 struct timeval;
 struct vm_area_struct;
+struct acpi_entry_iosapic;
 
 typedef void ia64_mv_setup_t (char **);
 typedef void ia64_mv_irq_init_t (void);
@@ -30,15 +31,33 @@
 typedef void ia64_mv_mca_handler_t (void);
 typedef void ia64_mv_cmci_handler_t (int, void *, struct pt_regs *);
 typedef void ia64_mv_log_print_t (void);
+typedef void ia64_mv_register_iosapic_t (struct acpi_entry_iosapic *);
+
+extern void machvec_noop (void);
 
 # if defined (CONFIG_IA64_HP_SIM)
 #  include <asm/machvec_hpsim.h>
 # elif defined (CONFIG_IA64_DIG)
 #  include <asm/machvec_dig.h>
 # elif defined (CONFIG_IA64_SGI_SN1_SIM)
-#  include <asm/machvec_sgi_sn1_SIM.h>
+#  include <asm/machvec_sgi_sn1.h>
 # elif defined (CONFIG_IA64_GENERIC)
 
+# ifdef MACHVEC_PLATFORM_HEADER
+#  include MACHVEC_PLATFORM_HEADER
+# else
+#  define platform_name		ia64_mv.name
+#  define platform_setup	ia64_mv.setup
+#  define platform_irq_init	ia64_mv.irq_init
+#  define platform_map_nr	ia64_mv.map_nr
+#  define platform_mca_init	ia64_mv.mca_init
+#  define platform_mca_handler	ia64_mv.mca_handler
+#  define platform_cmci_handler	ia64_mv.cmci_handler
+#  define platform_log_print	ia64_mv.log_print
+#  define platform_pci_fixup	ia64_mv.pci_fixup
+#  define platform_register_iosapic	ia64_mv.register_iosapic
+# endif
+
 struct ia64_machine_vector {
 	const char *name;
 	ia64_mv_setup_t *setup;
@@ -49,6 +68,7 @@
 	ia64_mv_mca_handler_t *mca_handler;
 	ia64_mv_cmci_handler_t *cmci_handler;
 	ia64_mv_log_print_t *log_print;
+	ia64_mv_register_iosapic_t *register_iosapic;
 };
 
 #define MACHVEC_INIT(name)			\
@@ -61,22 +81,12 @@
 	platform_mca_init,			\
 	platform_mca_handler,			\
 	platform_cmci_handler,			\
-	platform_log_print			\
+	platform_log_print,			\
+	platform_register_iosapic			\
 }
 
-# ifndef MACHVEC_INHIBIT_RENAMING
-#  define platform_name		ia64_mv.name
-#  define platform_setup	ia64_mv.setup
-#  define platform_irq_init	ia64_mv.irq_init
-#  define platform_map_nr	ia64_mv.map_nr
-#  define platform_mca_init	ia64_mv.mca_init
-#  define platform_mca_handler	ia64_mv.mca_handler
-#  define platform_cmci_handler	ia64_mv.cmci_handler
-#  define platform_log_print	ia64_mv.log_print
-# endif
-
 extern struct ia64_machine_vector ia64_mv;
-extern void machvec_noop (void);
+extern void machvec_init (const char *name);
 
 # else
 #  error Unknown configuration.  Update asm-ia64/machvec.h.
@@ -103,6 +113,12 @@
 #endif
 #ifndef platform_log_print
 # define platform_log_print	((ia64_mv_log_print_t *) machvec_noop)
+#endif
+#ifndef platform_pci_fixup
+# define platform_pci_fixup	((ia64_mv_pci_fixup_t *) machvec_noop)
+#endif
+#ifndef platform_register_iosapic
+# define platform_register_iosapic	((ia64_mv_register_iosapic_t *) machvec_noop)
 #endif
 
 #endif /* _ASM_IA64_MACHVEC_H */
diff -urN linux-davidm/include/asm-ia64/machvec_dig.h linux-2.4.0-test4-lia/include/asm-ia64/machvec_dig.h
--- linux-davidm/include/asm-ia64/machvec_dig.h	Sun Feb  6 18:42:40 2000
+++ linux-2.4.0-test4-lia/include/asm-ia64/machvec_dig.h	Fri Jul 28 23:16:59 2000
@@ -5,6 +5,7 @@
 extern ia64_mv_irq_init_t dig_irq_init;
 extern ia64_mv_pci_fixup_t dig_pci_fixup;
 extern ia64_mv_map_nr_t map_nr_dense;
+extern ia64_mv_register_iosapic_t dig_register_iosapic;
 
 /*
  * This stuff has dual use!
@@ -18,5 +19,6 @@
 #define platform_irq_init	dig_irq_init
 #define platform_pci_fixup	dig_pci_fixup
 #define platform_map_nr		map_nr_dense
+#define platform_register_iosapic dig_register_iosapic
 
 #endif /* _ASM_IA64_MACHVEC_DIG_h */
diff -urN linux-davidm/include/asm-ia64/machvec_hpsim.h linux-2.4.0-test4-lia/include/asm-ia64/machvec_hpsim.h
--- linux-davidm/include/asm-ia64/machvec_hpsim.h	Fri Jul 28 23:48:24 2000
+++ linux-2.4.0-test4-lia/include/asm-ia64/machvec_hpsim.h	Fri Jul 28 23:37:15 2000
@@ -15,7 +15,6 @@
 #define platform_name		"hpsim"
 #define platform_setup		hpsim_setup
 #define platform_irq_init	hpsim_irq_init
-#define platform_pci_fixup	hpsim_pci_fixup
 #define platform_map_nr		map_nr_dense
 
 #endif /* _ASM_IA64_MACHVEC_HPSIM_h */
diff -urN linux-davidm/include/asm-ia64/machvec_init.h linux-2.4.0-test4-lia/include/asm-ia64/machvec_init.h
--- linux-davidm/include/asm-ia64/machvec_init.h	Sun Feb  6 18:42:40 2000
+++ linux-2.4.0-test4-lia/include/asm-ia64/machvec_init.h	Fri Jul 28 23:17:05 2000
@@ -1,4 +1,6 @@
-#define MACHVEC_INHIBIT_RENAMING
+#define __MACHVEC_HDR(n)		<asm/machvec_##n##.h>
+#define __MACHVEC_EXPAND(n)		__MACHVEC_HDR(n)
+#define MACHVEC_PLATFORM_HEADER		__MACHVEC_EXPAND(MACHVEC_PLATFORM_NAME)
 
 #include <asm/machvec.h>
 
@@ -7,3 +9,5 @@
 	= MACHVEC_INIT(name);
 
 #define MACHVEC_DEFINE(name)	MACHVEC_HELPER(name)
+
+MACHVEC_DEFINE(MACHVEC_PLATFORM_NAME)
diff -urN linux-davidm/include/asm-ia64/page.h linux-2.4.0-test4-lia/include/asm-ia64/page.h
--- linux-davidm/include/asm-ia64/page.h	Thu Jun 22 07:09:45 2000
+++ linux-2.4.0-test4-lia/include/asm-ia64/page.h	Fri Jul 28 23:37:15 2000
@@ -100,6 +100,7 @@
 #define MAP_NR_SN1(addr)	(((unsigned long) (addr) - PAGE_OFFSET) >> PAGE_SHIFT)
 
 #ifdef CONFIG_IA64_GENERIC
+# include <asm/machvec.h>
 # define MAP_NR(addr)	platform_map_nr(addr)
 #elif defined (CONFIG_IA64_SN_SN1_SIM)
 # define MAP_NR(addr)	MAP_NR_SN1(addr)
diff -urN linux-davidm/include/asm-ia64/pal.h linux-2.4.0-test4-lia/include/asm-ia64/pal.h
--- linux-davidm/include/asm-ia64/pal.h	Thu Jun 22 07:09:45 2000
+++ linux-2.4.0-test4-lia/include/asm-ia64/pal.h	Fri Jul 28 23:17:20 2000
@@ -18,7 +18,8 @@
  * 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
+ * 00/05/25	eranian Support for stack calls, and static physical calls
+ * 00/06/18	eranian Support for stacked physical calls
  */
 
 /*
@@ -646,10 +647,12 @@
 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); 
+extern struct ia64_pal_retval ia64_pal_call_phys_stacked (u64, u64, u64, u64); 
 
 #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)
+#define PAL_CALL_PHYS_STK(iprv,a0,a1,a2,a3) iprv = ia64_pal_call_phys_stacked(a0, a1, a2, a3)
 
 typedef int (*ia64_pal_handler) (u64, ...);
 extern ia64_pal_handler ia64_pal;
@@ -951,7 +954,7 @@
 /* Return information about processor's optional power management capabilities. */
 extern inline s64 
 ia64_pal_halt_info (pal_power_mgmt_info_u_t *power_buf) 
-{
+{	
 	struct ia64_pal_retval iprv;
 	PAL_CALL_STK(iprv, PAL_HALT_INFO, (unsigned long) power_buf, 0, 0);
 	return iprv.status; 
@@ -1370,17 +1373,17 @@
 				dirty_bit_valid		: 1,
 				mem_attr_valid		: 1,
 				reserved		: 60;
-	} pal_itr_valid_s;
-} pal_itr_valid_u_t;
+	} pal_tr_valid_s;
+} pal_tr_valid_u_t;
 
 /* Read a translation register */
 extern inline s64 
-ia64_pal_vm_tr_read (u64 reg_num, u64 tr_type, u64 tr_buffer, pal_itr_valid_u_t *itr_valid) 
-{	
+ia64_pal_tr_read (u64 reg_num, u64 tr_type, u64 *tr_buffer, pal_tr_valid_u_t *tr_valid)
+{
 	struct ia64_pal_retval iprv;
-	PAL_CALL(iprv, PAL_VM_TR_READ, reg_num, tr_type, tr_buffer);
-	if (itr_valid)
-		itr_valid->piv_val = iprv.v0;
+	PAL_CALL_PHYS_STK(iprv, PAL_VM_TR_READ, reg_num, tr_type,(u64)__pa(tr_buffer));
+	if (tr_valid)
+		tr_valid->piv_val = iprv.v0;
 	return iprv.status; 
 }
 
diff -urN linux-davidm/include/asm-ia64/param.h linux-2.4.0-test4-lia/include/asm-ia64/param.h
--- linux-davidm/include/asm-ia64/param.h	Sun Feb  6 18:42:40 2000
+++ linux-2.4.0-test4-lia/include/asm-ia64/param.h	Fri Jul 28 23:37:15 2000
@@ -10,23 +10,13 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_IA64_HP_SIM
+#if defined(CONFIG_IA64_HP_SIM) || defined(CONFIG_IA64_SOFTSDV_HACKS)
 /*
  * Yeah, simulating stuff is slow, so let us catch some breath between
  * timer interrupts...
  */
 # define HZ 20
-#endif
-
-#ifdef CONFIG_IA64_DIG
-# ifdef CONFIG_IA64_SOFTSDV_HACKS
-#  define HZ 20
-# else
-#  define HZ 100
-# endif
-#endif
-
-#ifndef HZ
+#else
 # define HZ	1024
 #endif
 
diff -urN linux-davidm/include/asm-ia64/pci.h linux-2.4.0-test4-lia/include/asm-ia64/pci.h
--- linux-davidm/include/asm-ia64/pci.h	Thu Jun 22 07:17:16 2000
+++ linux-2.4.0-test4-lia/include/asm-ia64/pci.h	Fri Jul 28 23:39:07 2000
@@ -1,6 +1,15 @@
 #ifndef _ASM_IA64_PCI_H
 #define _ASM_IA64_PCI_H
 
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+
 /*
  * Can be used to override the logic in pci_scan_bus for skipping
  * already-configured bus numbers - to be used for buggy BIOSes or
@@ -11,6 +20,8 @@
 #define PCIBIOS_MIN_IO		0x1000
 #define PCIBIOS_MIN_MEM		0x10000000
 
+struct pci_dev;
+
 extern inline void pcibios_set_master(struct pci_dev *dev)
 {
 	/* No special bus mastering setup handling */
@@ -23,18 +34,8 @@
 
 /*
  * Dynamic DMA mapping API.
- * IA-64 has everything mapped statically.
  */
 
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/types.h>
-
-#include <asm/io.h>
-#include <asm/scatterlist.h>
-
-struct pci_dev;
-
 /*
  * Allocate and map kernel buffer using consistent mode DMA for a device.
  * hwdev should be valid struct pci_dev pointer for PCI devices,
@@ -64,13 +65,7 @@
  * Once the device is given the dma address, the device owns this memory
  * until either pci_unmap_single or pci_dma_sync_single is performed.
  */
-extern inline dma_addr_t
-pci_map_single (struct pci_dev *hwdev, void *ptr, size_t size, int direction)
-{
-	if (direction = PCI_DMA_NONE)
-		BUG();
-	return virt_to_bus(ptr);
-}
+extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction);
 
 /*
  * Unmap a single streaming mode DMA translation.  The dma_addr and size
@@ -80,13 +75,7 @@
  * After this call, reads by the cpu to the buffer are guarenteed to see
  * whatever the device wrote there.
  */
-extern inline void
-pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction)
-{
-	if (direction = PCI_DMA_NONE)
-		BUG();
-	/* Nothing to do */
-}
+extern void pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction);
 
 /*
  * Map a set of buffers described by scatterlist in streaming
@@ -104,26 +93,14 @@
  * Device ownership issues as mentioned above for pci_map_single are
  * the same here.
  */
-extern inline int
-pci_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
-{
-	if (direction = PCI_DMA_NONE)
-		BUG();
-	return nents;
-}
+extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction);
 
 /*
  * Unmap a set of streaming mode DMA translations.
  * Again, cpu read rules concerning calls here are the same as for
  * pci_unmap_single() above.
  */
-extern inline void
-pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
-{
-	if (direction = PCI_DMA_NONE)
-		BUG();
-	/* Nothing to do */
-}
+extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction);
 
 /*
  * Make physical memory consistent for a single
@@ -135,13 +112,7 @@
  * next point you give the PCI dma address back to the card, the
  * device again owns the buffer.
  */
-extern inline void
-pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction)
-{
-	if (direction = PCI_DMA_NONE)
-		BUG();
-	/* Nothing to do */
-}
+extern void pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction);
 
 /*
  * Make physical memory consistent for a set of streaming mode DMA
@@ -150,20 +121,15 @@
  * The same as pci_dma_sync_single but for a scatter-gather list,
  * same rules and usage.
  */
-extern inline void
-pci_dma_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
-{
-	if (direction = PCI_DMA_NONE)
-		BUG();
-	/* Nothing to do */
-}
+extern void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction);
 
 /* Return whether the given PCI device DMA address mask can
  * be supported properly.  For example, if your device can
  * only drive the low 24-bits during PCI bus mastering, then
  * you would pass 0x00ffffff as the mask to this function.
  */
-extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+extern inline int
+pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
 {
 	return 1;
 }
diff -urN linux-davidm/include/asm-ia64/processor.h linux-2.4.0-test4-lia/include/asm-ia64/processor.h
--- linux-davidm/include/asm-ia64/processor.h	Thu Jun 22 07:09:45 2000
+++ linux-2.4.0-test4-lia/include/asm-ia64/processor.h	Fri Jul 28 23:39:06 2000
@@ -338,8 +338,12 @@
 struct mm_struct;
 struct task_struct;
 
-/* Free all resources held by a thread. */
-extern void release_thread (struct task_struct *);
+/*
+ * Free all resources held by a thread. This is called after the
+ * parent of DEAD_TASK has collected the exist status of the task via
+ * wait().  This is a no-op on IA-64.
+ */
+#define release_thread(dead_task)
 
 /*
  * This is the mechanism for creating a new kernel thread.
diff -urN linux-davidm/include/asm-ia64/scatterlist.h linux-2.4.0-test4-lia/include/asm-ia64/scatterlist.h
--- linux-davidm/include/asm-ia64/scatterlist.h	Sun Feb  6 18:42:40 2000
+++ linux-2.4.0-test4-lia/include/asm-ia64/scatterlist.h	Fri Jul 28 23:18:13 2000
@@ -13,6 +13,7 @@
 	 * indirection buffer, NULL otherwise:
 	 */
 	char *alt_address;
+	char *orig_address;	/* Save away the original buffer address (used by pci-dma.c) */
 	unsigned int length;	/* buffer length */
 };
 
diff -urN linux-davidm/include/asm-ia64/smp.h linux-2.4.0-test4-lia/include/asm-ia64/smp.h
--- linux-davidm/include/asm-ia64/smp.h	Fri Apr 21 15:21:24 2000
+++ linux-2.4.0-test4-lia/include/asm-ia64/smp.h	Fri Jul 28 23:39:06 2000
@@ -99,5 +99,9 @@
 extern void __init init_smp_config (void);
 extern void smp_do_timer (struct pt_regs *regs);
 
+extern int smp_call_function_single (int cpuid, void (*func) (void *info), void *info,
+			      int retry, int wait);
+
+
 #endif /* CONFIG_SMP */
 #endif /* _ASM_IA64_SMP_H */
diff -urN linux-davidm/include/asm-ia64/system.h linux-2.4.0-test4-lia/include/asm-ia64/system.h
--- linux-davidm/include/asm-ia64/system.h	Thu Jun 22 07:09:45 2000
+++ linux-2.4.0-test4-lia/include/asm-ia64/system.h	Fri Jul 28 23:37:15 2000
@@ -445,6 +445,7 @@
    */
 # define switch_to(prev,next,last) do {							\
 	if (ia64_get_fpu_owner() = (prev) && ia64_psr(ia64_task_regs(prev))->mfh) {	\
+		ia64_psr(ia64_task_regs(prev))->mfh = 0;				\
 		(prev)->thread.flags |= IA64_THREAD_FPH_VALID;				\
 		__ia64_save_fpu((prev)->thread.fph);					\
 	}										\
diff -urN linux-davidm/lib/cmdline.c linux-2.4.0-test4-lia/lib/cmdline.c
--- linux-davidm/lib/cmdline.c	Tue Jun 20 07:52:36 2000
+++ linux-2.4.0-test4-lia/lib/cmdline.c	Fri Jul 28 23:19:54 2000
@@ -85,12 +85,12 @@
  *	@ptr: Where parse begins
  *	@retptr: (output) Pointer to next char after parse completes
  *
- *	Parses a string into a number.  The number stored
- *	at @ptr is potentially suffixed with %K (for
- *	kilobytes, or 1024 bytes) or suffixed with %M (for
- *	megabytes, or 1048576 bytes).  If the number is suffixed
- *	with K or M, then the return value is the number
- *	multiplied by one kilobyte, or one megabyte, respectively.
+ *	Parses a string into a number.  The number stored at @ptr is
+ *	potentially suffixed with %K (for kilobytes, or 1024 bytes),
+ *	%M (for megabytes, or 1048576 bytes), or %G (for gigabytes, or
+ *	1073741824).  If the number is suffixed with K, M, or G, then
+ *	the return value is the number multiplied by one kilobyte, one
+ *	megabyte, or one gigabyte, respectively.
  */
 
 unsigned long memparse (char *ptr, char **retptr)
@@ -98,6 +98,9 @@
 	unsigned long ret = simple_strtoul (ptr, retptr, 0);
 
 	switch (**retptr) {
+	case 'G':
+	case 'g':
+		ret <<= 10;
 	case 'M':
 	case 'm':
 		ret <<= 10;



^ permalink raw reply	[flat|nested] 4+ messages in thread
* [Linux-ia64] kernel update (relative to v2.4.0-test1)
@ 2000-06-01  8:54 David Mosberger
  2000-07-14 21:37 ` [Linux-ia64] kernel update (relative to 2.4.0-test4) David Mosberger
  0 siblings, 1 reply; 4+ 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] 4+ messages in thread

end of thread, other threads:[~2000-07-31 10:03 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2000-07-29  7:41 [Linux-ia64] kernel update [relative to 2.4.0-test4] David Mosberger
2000-07-30 17:27 ` Mallick, Asit K
2000-07-31 10:03 ` Andreas Schwab
  -- strict thread matches above, loose matches on Subject: below --
2000-06-01  8:54 [Linux-ia64] kernel update (relative to v2.4.0-test1) David Mosberger
2000-07-14 21:37 ` [Linux-ia64] kernel update (relative to 2.4.0-test4) David Mosberger

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