All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Mosberger <davidm@hpl.hp.com>
To: linux-ia64@vger.kernel.org
Subject: [Linux-ia64] kernel update (relative to 2.4.13)
Date: Thu, 25 Oct 2001 04:27:42 +0000	[thread overview]
Message-ID: <marc-linux-ia64-105590698805620@msgid-missing> (raw)
In-Reply-To: <marc-linux-ia64-105590678205111@msgid-missing>

An updated ia64 patch for 2.4.13 is now available at
ftp://ftp.kernel.org/pub/linux/kernel/ports/ia64/ in file:

        linux-2.4.11-ia64-011010.diff*

change log:

	- support readahead() syscall added by 2.4.13 (both for ia64 and ia32)
	- console log level fix by Jesper Juhl
	- half-hearted attempt add supporting reading of "default LDT entry" in ia32
	  modify_ldt() syscall; someone who understands what this is supposed to do
	  should take a look at this...
	- palinfo update by Stephane Eranian
	- die() fix by Keith Owens
	- unaligned handler fix for rotating fp regs by Tony Luck
	- ACPI fix to get AGP bus scanned again by Chris Ahna
	- implementation ia64 version of wbinvd() for ACPI; this hasn't been tested
	  and may not work; shouldn't be an issue at the moment as this is needed only
	  for ACPI functionality that is not supported on Itanium; still someone who
	  knows ACPI better may want to take a look at this
	- update PCI DMA interface to support page-based mapping/unmapping and
	  the optional DAC interface

This kernel has been tested with gcc-3.0 on Big Sur, Lion, and HP
simulator.  Both UP and MP seem to compile fine.  As usual, your
mileage may vary.

Enjoy,

	--david

diff -urN linux-2.4.13/Documentation/Configure.help linux-2.4.13-lia/Documentation/Configure.help
--- linux-2.4.13/Documentation/Configure.help	Wed Oct 24 10:17:38 2001
+++ linux-2.4.13-lia/Documentation/Configure.help	Wed Oct 24 10:21:05 2001
@@ -2632,6 +2632,16 @@
   the GLX component for XFree86 3.3.6, which can be downloaded from
   http://utah-glx.sourceforge.net/ .
 
+Intel 460GX support
+CONFIG_AGP_I460
+  This option gives you AGP support for the Intel 460GX chipset.  This
+  chipset, the first to support Intel Itanium processors, is new and
+  this option is correspondingly a little experimental.
+
+  If you don't have a 460GX based machine (such as BigSur) with an AGP 
+  slot then this option isn't going to do you much good.  If you're
+  dying to do Direct Rendering on IA-64, this is what you're looking for.
+
 Intel I810/I810 DC100/I810e support
 CONFIG_AGP_I810
   This option gives you AGP support for the Xserver on the Intel 810,
@@ -12846,6 +12856,18 @@
   Say Y here if you would like to be able to read the hard disk
   partition table format used by SGI machines.
 
+Intel EFI GUID partition support
+CONFIG_EFI_PARTITION
+  Say Y here if you would like to use hard disks under Linux which
+  were partitioned using EFI GPT.  Presently only useful on the
+  IA-64 platform.
+
+/dev/guid support (EXPERIMENTAL)
+CONFIG_DEVFS_GUID
+  Say Y here if you would like to access disks and partitions by
+  their Globally Unique Identifiers (GUIDs) which will appear as
+  symbolic links in /dev/guid.
+
 Ultrix partition support
 CONFIG_ULTRIX_PARTITION
   Say Y here if you would like to be able to read the hard disk
@@ -18964,11 +18986,22 @@
   so the "DIG-compliant" option is usually the right choice.
 
   HP-simulator   For the HP simulator (http://software.hp.com/ia64linux/).
-  SN1-simulator  For the SGI SN1 simulator.
+  SGI-SN1	 For SGI SN1 Platforms.
+  SGI-SN2	 For SGI SN2 Platforms.
   DIG-compliant  For DIG ("Developer's Interface Guide") compliant system.
 
   If you don't know what to do, choose "generic".
 
+CONFIG_IA64_SGI_SN_SIM
+  Build a kernel that runs on both the SGI simulator AND on hardware.
+  There is a very slight performance penalty on hardware for including this
+  option.
+
+CONFIG_IA64_SGI_SN_DEBUG
+  This enables addition debug code that helps isolate
+  platform/kernel bugs. There is a small but measurable performance
+  degradation when this option is enabled.
+
 Kernel page size
 CONFIG_IA64_PAGE_SIZE_4KB
 
@@ -18986,56 +19019,13 @@
 
   If you don't know what to do, choose 8KB.
 
-Enable Itanium A-step specific code
-CONFIG_ITANIUM_ASTEP_SPECIFIC
-  Select this option to build a kernel for an Itanium prototype system
-  with an A-step CPU.  You have an A-step CPU if the "revision" field in
-  /proc/cpuinfo is 0.
-
 Enable Itanium B-step specific code
 CONFIG_ITANIUM_BSTEP_SPECIFIC
   Select this option to build a kernel for an Itanium prototype system
-  with a B-step CPU.  You have a B-step CPU if the "revision" field in
-  /proc/cpuinfo has a value in the range from 1 to 4.
-
-Enable Itanium B0-step specific code
-CONFIG_ITANIUM_B0_SPECIFIC
-  Select this option to bild a kernel for an Itanium prototype system
-  with a B0-step CPU.  You have a B0-step CPU if the "revision" field in
-  /proc/cpuinfo is 1.
-
-Force interrupt redirection
-CONFIG_IA64_HAVE_IRQREDIR
-  Select this option if you know that your system has the ability to
-  redirect interrupts to different CPUs.  Select N here if you're
-  unsure.
-
-Enable use of global TLB purge instruction (ptc.g)
-CONFIG_ITANIUM_PTCG
-  Say Y here if you want the kernel to use the IA-64 "ptc.g"
-  instruction to flush the TLB on all CPUs.  Select N here if
-  you're unsure.
-
-Enable SoftSDV hacks
-CONFIG_IA64_SOFTSDV_HACKS
-  Say Y here to enable hacks to make the kernel work on the Intel
-  SoftSDV simulator.  Select N here if you're unsure.
-
-Enable AzusA hacks
-CONFIG_IA64_AZUSA_HACKS
-  Say Y here to enable hacks to make the kernel work on the NEC
-  AzusA platform.  Select N here if you're unsure.
-
-Force socket buffers below 4GB?
-CONFIG_SKB_BELOW_4GB
-  Most of today's network interface cards (NICs) support DMA to
-  the low 32 bits of the address space only.  On machines with
-  more then 4GB of memory, this can cause the system to slow
-  down if there is no I/O TLB hardware.  Turning this option on
-  avoids the slow-down by forcing socket buffers to be allocated
-  from memory below 4GB.  The downside is that your system could
-  run out of memory below 4GB before all memory has been used up.
-  If you're unsure how to answer this question, answer Y.
+  with a B-step CPU.  Only B3 step CPUs are supported.  You have a B3-step
+  CPU if the "revision" field in /proc/cpuinfo is equal to 4.  If the
+  "revision" field shows a number bigger than 4, you do not have to turn
+  on this option.
 
 Enable IA-64 Machine Check Abort
 CONFIG_IA64_MCA
@@ -19055,6 +19045,15 @@
   Layer) information in /proc/pal.  This contains useful information
   about the processors in your systems, such as cache and TLB sizes
   and the PAL firmware version in use.
+
+  To use this option, you have to check that the "/proc file system
+  support" (CONFIG_PROC_FS) is enabled, too.
+
+/proc/efi/vars support
+CONFIG_EFI_VARS
+  If you say Y here, you are able to get EFI (Extensible Firmware
+  Interface) variable information in /proc/efi/vars.  You may read,
+  write, create, and destroy EFI variables through this interface.
 
   To use this option, you have to check that the "/proc file system
   support" (CONFIG_PROC_FS) is enabled, too.
diff -urN linux-2.4.13/Documentation/kernel-parameters.txt linux-2.4.13-lia/Documentation/kernel-parameters.txt
--- linux-2.4.13/Documentation/kernel-parameters.txt	Wed Jun 20 11:21:33 2001
+++ linux-2.4.13-lia/Documentation/kernel-parameters.txt	Wed Oct 10 17:33:26 2001
@@ -17,6 +17,7 @@
 	CD	Appropriate CD support is enabled.
 	DEVFS   devfs support is enabled. 
 	DRM	Direct Rendering Management support is enabled. 
+	EFI	EFI Partitioning (GPT) is enabled
 	EIDE	EIDE/ATAPI support is enabled.
 	FB	The frame buffer device is enabled.
 	HW	Appropriate hardware is enabled.
@@ -211,6 +212,9 @@
 	gc_3=		[HW,JOY]
  
 	gdth=		[HW,SCSI]
+
+	gpt             [EFI] Forces disk with valid GPT signature but
+			invalid Protective MBR to be treated as GPT.
 
 	gscd=		[HW,CD]
 
diff -urN linux-2.4.13/Makefile linux-2.4.13-lia/Makefile
--- linux-2.4.13/Makefile	Wed Oct 24 10:17:41 2001
+++ linux-2.4.13-lia/Makefile	Wed Oct 24 10:21:05 2001
@@ -88,7 +88,7 @@
 
 CPPFLAGS := -D__KERNEL__ -I$(HPATH)
 
-CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \
+CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -g -O2 \
 	  -fomit-frame-pointer -fno-strict-aliasing -fno-common
 AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS)
 
@@ -137,7 +137,8 @@
 	drivers/net/net.o \
 	drivers/media/media.o
 DRIVERS-$(CONFIG_AGP) += drivers/char/agp/agp.o
-DRIVERS-$(CONFIG_DRM) += drivers/char/drm/drm.o
+DRIVERS-$(CONFIG_DRM_NEW) += drivers/char/drm/drm.o
+DRIVERS-$(CONFIG_DRM_OLD) += drivers/char/drm-4.0/drm.o
 DRIVERS-$(CONFIG_NUBUS) += drivers/nubus/nubus.a
 DRIVERS-$(CONFIG_ISDN) += drivers/isdn/isdn.a
 DRIVERS-$(CONFIG_NET_FC) += drivers/net/fc/fc.o
@@ -241,14 +242,14 @@
 
 include arch/$(ARCH)/Makefile
 
-export	CPPFLAGS CFLAGS AFLAGS
+export	CPPFLAGS CFLAGS CFLAGS_KERNEL AFLAGS AFLAGS_KERNEL
 
 export	NETWORKS DRIVERS LIBS HEAD LDFLAGS LINKFLAGS MAKEBOOT ASFLAGS
 
 .S.s:
-	$(CPP) $(AFLAGS) -traditional -o $*.s $<
+	$(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -traditional -o $*.s $<
 .S.o:
-	$(CC) $(AFLAGS) -traditional -c -o $*.o $<
+	$(CC) $(AFLAGS) $(AFLAGS_KERNEL) -traditional -c -o $*.o $<
 
 Version: dummy
 	@rm -f include/linux/compile.h
diff -urN linux-2.4.13/arch/i386/lib/usercopy.c linux-2.4.13-lia/arch/i386/lib/usercopy.c
--- linux-2.4.13/arch/i386/lib/usercopy.c	Mon Sep 24 15:06:13 2001
+++ linux-2.4.13-lia/arch/i386/lib/usercopy.c	Thu Oct  4 00:21:39 2001
@@ -14,6 +14,7 @@
 unsigned long
 __generic_copy_to_user(void *to, const void *from, unsigned long n)
 {
+	prefetch(from);
 	if (access_ok(VERIFY_WRITE, to, n))
 	{
 		if(n<512)
@@ -27,6 +28,7 @@
 unsigned long
 __generic_copy_from_user(void *to, const void *from, unsigned long n)
 {
+	prefetchw(to);
 	if (access_ok(VERIFY_READ, from, n))
 	{
 		if(n<512)
diff -urN linux-2.4.13/arch/i386/mm/fault.c linux-2.4.13-lia/arch/i386/mm/fault.c
--- linux-2.4.13/arch/i386/mm/fault.c	Wed Oct 10 16:31:44 2001
+++ linux-2.4.13-lia/arch/i386/mm/fault.c	Wed Oct 24 18:11:25 2001
@@ -27,8 +27,6 @@
 
 extern void die(const char *,struct pt_regs *,long);
 
-extern int console_loglevel;
-
 /*
  * Ugly, ugly, but the goto's result in better assembly..
  */
diff -urN linux-2.4.13/arch/ia64/Makefile linux-2.4.13-lia/arch/ia64/Makefile
--- linux-2.4.13/arch/ia64/Makefile	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/Makefile	Thu Oct  4 00:21:52 2001
@@ -17,13 +17,15 @@
 AFLAGS_KERNEL := -mconstant-gp
 EXTRA	 
-CFLAGS := $(CFLAGS) -pipe $(EXTRA) -ffixed-r13 -mfixed-rangeñ0-f15,f32-f127 -falign-functions2
+CFLAGS := $(CFLAGS) -pipe $(EXTRA) -ffixed-r13 -mfixed-rangeñ0-f15,f32-f127 \
+	  -falign-functions2
+# -ffunction-sections
 CFLAGS_KERNEL := -mconstant-gp
 
 GCC_VERSION=$(shell $(CROSS_COMPILE)$(HOSTCC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.')
 
 ifneq ($(GCC_VERSION),2)
-	CFLAGS += -frename-registers
+	CFLAGS += -frename-registers --param max-inline-insns@0
 endif
 
 ifeq ($(CONFIG_ITANIUM_BSTEP_SPECIFIC),y)
@@ -32,7 +34,7 @@
 
 ifdef CONFIG_IA64_GENERIC
 	CORE_FILES      :=      arch/$(ARCH)/hp/hp.a	\
-				arch/$(ARCH)/sn/sn.a	\
+				arch/$(ARCH)/sn/sn.o	\
 				arch/$(ARCH)/dig/dig.a	\
 				arch/$(ARCH)/sn/io/sgiio.o \
 				$(CORE_FILES)
@@ -52,15 +54,14 @@
                                 $(CORE_FILES)
 endif
 
-ifdef CONFIG_IA64_SGI_SN1
+ifdef CONFIG_IA64_SGI_SN
 	CFLAGS		+= -DBRINGUP
-        SUBDIRS         :=      arch/$(ARCH)/sn/sn1	\
-				arch/$(ARCH)/sn		\
+        SUBDIRS         :=      arch/$(ARCH)/sn/kernel	\
 				arch/$(ARCH)/sn/io	\
 				arch/$(ARCH)/sn/fprom	\
 				$(SUBDIRS)
-        CORE_FILES      :=      arch/$(ARCH)/sn/sn.a	\
-				arch/$(ARCH)/sn/io/sgiio.o\
+        CORE_FILES      :=      arch/$(ARCH)/sn/kernel/sn.o	\
+				arch/$(ARCH)/sn/io/sgiio.o	\
 				$(CORE_FILES)
 endif
 
@@ -105,7 +106,7 @@
 
 compressed: vmlinux
 	$(OBJCOPY) --strip-all vmlinux vmlinux-tmp
-	gzip -9 vmlinux-tmp
+	gzip vmlinux-tmp
 	mv vmlinux-tmp.gz vmlinux.gz
 
 rawboot:
diff -urN linux-2.4.13/arch/ia64/config.in linux-2.4.13-lia/arch/ia64/config.in
--- linux-2.4.13/arch/ia64/config.in	Wed Oct 24 10:17:42 2001
+++ linux-2.4.13-lia/arch/ia64/config.in	Wed Oct 24 10:21:06 2001
@@ -28,6 +28,7 @@
 
 if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then
   define_bool CONFIG_ACPI y
+  define_bool CONFIG_ACPI_EFI y
   define_bool CONFIG_ACPI_INTERPRETER y
   define_bool CONFIG_ACPI_KERNEL_CONFIG y
 fi
@@ -40,7 +41,8 @@
 	"generic		CONFIG_IA64_GENERIC		\
 	 DIG-compliant		CONFIG_IA64_DIG			\
 	 HP-simulator		CONFIG_IA64_HP_SIM		\
-	 SGI-SN1		CONFIG_IA64_SGI_SN1" generic
+	 SGI-SN1		CONFIG_IA64_SGI_SN1		\
+	 SGI-SN2		CONFIG_IA64_SGI_SN2" generic
 
 choice 'Kernel page size'						\
 	"4KB			CONFIG_IA64_PAGE_SIZE_4KB		\
@@ -51,25 +53,6 @@
 if [ "$CONFIG_ITANIUM" = "y" ]; then
 	define_bool CONFIG_IA64_BRL_EMU y
 	bool '  Enable Itanium B-step specific code' CONFIG_ITANIUM_BSTEP_SPECIFIC
-	if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then
-	  bool '   Enable Itanium B0-step specific code' CONFIG_ITANIUM_B0_SPECIFIC
-        fi
-	if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then
-	  bool '   Enable Itanium B1-step specific code' CONFIG_ITANIUM_B1_SPECIFIC
-	fi
-	if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then
-	  bool '   Enable Itanium B2-step specific code' CONFIG_ITANIUM_B2_SPECIFIC
-	fi
-	bool '  Enable Itanium C-step specific code' CONFIG_ITANIUM_CSTEP_SPECIFIC
-	if [ "$CONFIG_ITANIUM_CSTEP_SPECIFIC" = "y" ]; then
-	  bool '   Enable Itanium C0-step specific code' CONFIG_ITANIUM_C0_SPECIFIC
-	fi
-	if [ "$CONFIG_ITANIUM_B0_SPECIFIC" = "y" \
-	     -o "$CONFIG_ITANIUM_B1_SPECIFIC" = "y" -o "$CONFIG_ITANIUM_B2_SPECIFIC" = "y" ]; then
-	  define_bool CONFIG_ITANIUM_PTCG n
-	else
-	  define_bool CONFIG_ITANIUM_PTCG y
-	fi
 	if [ "$CONFIG_IA64_SGI_SN1" = "y" ]; then
 	  define_int CONFIG_IA64_L1_CACHE_SHIFT 7 # align cache-sensitive data to 128 bytes
 	else
@@ -78,7 +61,6 @@
 fi
 
 if [ "$CONFIG_MCKINLEY" = "y" ]; then
-	define_bool CONFIG_ITANIUM_PTCG y
 	define_int CONFIG_IA64_L1_CACHE_SHIFT 7
 	bool '  Enable McKinley A-step specific code' CONFIG_MCKINLEY_ASTEP_SPECIFIC
 	if [ "$CONFIG_MCKINLEY_ASTEP_SPECIFIC" = "y" ]; then
@@ -87,28 +69,32 @@
 fi
 
 if [ "$CONFIG_IA64_DIG" = "y" ]; then
-	bool '  Force interrupt redirection' CONFIG_IA64_HAVE_IRQREDIR
 	bool '  Enable IA-64 Machine Check Abort' CONFIG_IA64_MCA
 	define_bool CONFIG_PM y
 fi
 
-if [ "$CONFIG_IA64_SGI_SN1" = "y" ]; then
-	bool '  Enable SGI Medusa Simulator Support' CONFIG_IA64_SGI_SN1_SIM
-	define_bool CONFIG_DEVFS_DEBUG y
+if [ "$CONFIG_IA64_SGI_SN1" = "y" ] || [ "$CONFIG_IA64_SGI_SN2" = "y" ]; then
+	define_bool CONFIG_IA64_SGI_SN y
+	bool '  Enable extra debugging code' CONFIG_IA64_SGI_SN_DEBUG n
+	bool '  Enable SGI Medusa Simulator Support' CONFIG_IA64_SGI_SN_SIM
+	bool '  Enable autotest (llsc). Option to run cache test instead of booting' \
+			CONFIG_IA64_SGI_AUTOTEST n
 	define_bool CONFIG_DEVFS_FS y
-	define_bool CONFIG_IA64_BRL_EMU y
+	if [ "$CONFIG_DEVFS_FS" = "y" ]; then
+	  bool '    Enable DEVFS Debug Code' CONFIG_DEVFS_DEBUG n
+	fi
+	bool '  Enable protocol mode for the L1 console' CONFIG_SERIAL_SGI_L1_PROTOCOL y
+	define_bool CONFIG_DISCONTIGMEM y
 	define_bool CONFIG_IA64_MCA y
-	define_bool CONFIG_ITANIUM y
-	define_bool CONFIG_SGI_IOC3_ETH y
+	define_bool CONFIG_NUMA y
 	define_bool CONFIG_PERCPU_IRQ y
-	define_int  CONFIG_CACHE_LINE_SHIFT 7
-	bool '  Enable DISCONTIGMEM support' CONFIG_DISCONTIGMEM
-	bool '	Enable NUMA support' CONFIG_NUMA
+	tristate '  PCIBA support' CONFIG_PCIBA
 fi
 
 define_bool CONFIG_KCORE_ELF y	# On IA-64, we always want an ELF /proc/kcore.
 
 bool 'SMP support' CONFIG_SMP
+tristate 'Support running of Linux/x86 binaries' CONFIG_IA32_SUPPORT
 bool 'Performance monitor support' CONFIG_PERFMON
 tristate '/proc/pal support' CONFIG_IA64_PALINFO
 tristate '/proc/efi/vars support' CONFIG_EFI_VARS
@@ -270,19 +256,19 @@
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
-#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Kernel support for IA-32 emulation' CONFIG_IA32_SUPPORT
-  tristate 'Kernel FP software completion' CONFIG_MATHEMU
-else
-  define_bool CONFIG_MATHEMU y
+bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
+if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
+   bool '  Print possible IA64 hazards to console' CONFIG_IA64_PRINT_HAZARDS
+   bool '  Disable VHPT' CONFIG_DISABLE_VHPT
+   bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ
+
+# early printk is currently broken for SMP: the secondary processors get stuck...
+#   bool '  Early printk support (requires VGA!)' CONFIG_IA64_EARLY_PRINTK
+
+   bool '  Debug memory allocations' CONFIG_DEBUG_SLAB
+   bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
+   bool '  Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG
+   bool '  Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ
 fi
-
-bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
-bool 'Early printk support (requires VGA!)' CONFIG_IA64_EARLY_PRINTK
-bool 'Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG
-bool 'Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ
-bool 'Print possible IA64 hazards to console' CONFIG_IA64_PRINT_HAZARDS
-bool 'Disable VHPT' CONFIG_DISABLE_VHPT
 
 endmenu
diff -urN linux-2.4.13/arch/ia64/defconfig linux-2.4.13-lia/arch/ia64/defconfig
--- linux-2.4.13/arch/ia64/defconfig	Thu Jun 22 07:09:44 2000
+++ linux-2.4.13-lia/arch/ia64/defconfig	Thu Oct  4 00:21:39 2001
@@ -3,53 +3,131 @@
 #
 
 #
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+# CONFIG_KMOD is not set
+
+#
 # General setup
 #
 CONFIG_IA64=y
 # CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
 # CONFIG_SBUS is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_ACPI=y
+CONFIG_ACPI_EFI=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_KERNEL_CONFIG=y
+CONFIG_ITANIUM=y
+# CONFIG_MCKINLEY is not set
 # CONFIG_IA64_GENERIC is not set
-CONFIG_IA64_HP_SIM=y
-# CONFIG_IA64_SGI_SN1_SIM is not set
-# CONFIG_IA64_DIG is not set
+CONFIG_IA64_DIG=y
+# CONFIG_IA64_HP_SIM is not set
+# CONFIG_IA64_SGI_SN1 is not set
+# CONFIG_IA64_SGI_SN2 is not set
 # CONFIG_IA64_PAGE_SIZE_4KB is not set
 # CONFIG_IA64_PAGE_SIZE_8KB is not set
 CONFIG_IA64_PAGE_SIZE_16KB=y
 # CONFIG_IA64_PAGE_SIZE_64KB is not set
+CONFIG_IA64_BRL_EMU=y
+CONFIG_ITANIUM_BSTEP_SPECIFIC=y
+CONFIG_IA64_L1_CACHE_SHIFT=6
+CONFIG_IA64_MCA=y
+CONFIG_PM=y
 CONFIG_KCORE_ELF=y
-# CONFIG_SMP is not set
-# CONFIG_PERFMON is not set
-# CONFIG_NET is not set
-# CONFIG_SYSVIPC is not set
+CONFIG_SMP=y
+CONFIG_IA32_SUPPORT=y
+CONFIG_PERFMON=y
+CONFIG_IA64_PALINFO=y
+CONFIG_EFI_VARS=y
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-# CONFIG_BINFMT_ELF is not set
+CONFIG_SYSCTL=y
+CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ACPI_DEBUG is not set
+# CONFIG_ACPI_BUSMGR is not set
+# CONFIG_ACPI_SYS is not set
+# CONFIG_ACPI_CPU is not set
+# CONFIG_ACPI_BUTTON is not set
+# CONFIG_ACPI_AC is not set
+# CONFIG_ACPI_EC is not set
+# CONFIG_ACPI_CMBATT is not set
+# CONFIG_ACPI_THERMAL is not set
 CONFIG_PCI=y
 CONFIG_PCI_NAMES=y
 # CONFIG_HOTPLUG is not set
 # CONFIG_PCMCIA is not set
 
 #
-# Code maturity level options
+# Parallel port support
 #
-CONFIG_EXPERIMENTAL=y
+# CONFIG_PARPORT is not set
 
 #
-# Loadable module support
+# Networking options
 #
-# CONFIG_MODULES is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK is not set
+# CONFIG_NETFILTER is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
-# Parallel port support
+# QoS and/or fair queueing
 #
-# CONFIG_PARPORT is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
 
 #
 # Plug and Play configuration
 #
 # CONFIG_PNP is not set
 # CONFIG_ISAPNP is not set
+# CONFIG_PNPBIOS is not set
 
 #
 # Block devices
@@ -58,14 +136,12 @@
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
-
-#
-# Additional Block Devices
-#
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
 
 #
 # I2O device support
@@ -73,10 +149,23 @@
 # CONFIG_I2O is not set
 # CONFIG_I2O_PCI is not set
 # CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
 # CONFIG_I2O_SCSI is not set
 # CONFIG_I2O_PROC is not set
 
 #
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 CONFIG_IDE=y
@@ -92,12 +181,21 @@
 # CONFIG_BLK_DEV_HD_IDE is not set
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_IDEDISK_MULTI_MODE=y
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
+CONFIG_BLK_DEV_IDEFLOPPY=y
+CONFIG_BLK_DEV_IDESCSI=y
 
 #
 # IDE chipset support/bugfixes
@@ -109,45 +207,209 @@
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
+CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
-CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_PCI_AUTO is not set
 CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
 # CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
-# CONFIG_BLK_DEV_AEC6210 is not set
-# CONFIG_AEC6210_TUNING is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD7409 is not set
-# CONFIG_AMD7409_OVERRIDE is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_CMD64X_RAID is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_HPT366_FIP is not set
-# CONFIG_HPT366_MODE3 is not set
 CONFIG_BLK_DEV_PIIX=y
-CONFIG_PIIX_TUNING=y
+# CONFIG_PIIX_TUNING is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
 # CONFIG_BLK_DEV_PDC202XX is not set
 # CONFIG_PDC202XX_BURST is not set
-# CONFIG_PDC202XX_MASTER is not set
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_SVWKS is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
 # CONFIG_IDE_CHIPSETS is not set
-CONFIG_IDEDMA_AUTO=y
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_DMA_NONPCI is not set
 CONFIG_BLK_DEV_IDE_MODES=y
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
 
 #
 # SCSI support
 #
-# CONFIG_SCSI is not set
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS@
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_DEBUG_QUEUES=y
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR_D700 is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_SYM53C8XX is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+CONFIG_SCSI_QLOGIC_1280=y
+# CONFIG_SCSI_QLOGIC_QLA2100 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_TULIP is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+CONFIG_EEPRO100=y
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_LAN_SAA9730 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
 
 #
 # Amateur Radio support
@@ -165,13 +427,27 @@
 # CONFIG_CD_NO_IDESCSI is not set
 
 #
+# Input core support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_KEYBDEV=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X\x1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Yv8
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+
+#
 # Character devices
 #
-# CONFIG_VT is not set
-# CONFIG_SERIAL is not set
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_UNIX98_PTYS is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT%6
 
 #
 # I2C support
@@ -182,97 +458,382 @@
 # Mice
 #
 # CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+CONFIG_INPUT_SERIO=y
+CONFIG_INPUT_SERPORT=y
 
 #
 # Joysticks
 #
-# CONFIG_JOYSTICK is not set
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
 # CONFIG_QIC02_TAPE is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 CONFIG_EFI_RTC=y
-
-#
-# Video For Linux
-#
-# CONFIG_VIDEO_DEV is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
+# CONFIG_SONYPI is not set
 
 #
 # Ftape, the floppy tape device driver
 #
 # CONFIG_FTAPE is not set
-# CONFIG_DRM is not set
-# CONFIG_DRM_TDFX is not set
-# CONFIG_AGP is not set
+CONFIG_AGP=y
+# CONFIG_AGP_INTEL is not set
+CONFIG_AGP_I460=y
+# CONFIG_AGP_I810 is not set
+# CONFIG_AGP_VIA is not set
+# CONFIG_AGP_AMD is not set
+# CONFIG_AGP_SIS is not set
+# CONFIG_AGP_ALI is not set
+# CONFIG_AGP_SWORKS is not set
+CONFIG_DRM=y
+# CONFIG_DRM_NEW is not set
+CONFIG_DRM_OLD=y
+CONFIG_DRM40_TDFX=y
+# CONFIG_DRM40_GAMMA is not set
+# CONFIG_DRM40_R128 is not set
+# CONFIG_DRM40_RADEON is not set
+# CONFIG_DRM40_I810 is not set
+# CONFIG_DRM40_MGA is not set
 
 #
-# USB support
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+
+#
+# Video For Linux
 #
-# CONFIG_USB is not set
+CONFIG_VIDEO_PROC_FS=y
+# CONFIG_I2C_PARPORT is not set
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_CADET is not set
+# CONFIG_RADIO_RTRACK is not set
+# CONFIG_RADIO_RTRACK2 is not set
+# CONFIG_RADIO_AZTECH is not set
+# CONFIG_RADIO_GEMTEK is not set
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+# CONFIG_RADIO_MIROPCM20_RDS is not set
+# CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_TERRATEC is not set
+# CONFIG_RADIO_TRUST is not set
+# CONFIG_RADIO_TYPHOON is not set
+# CONFIG_RADIO_ZOLTRIX is not set
 
 #
 # File systems
 #
 # CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS_FS=y
 # CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
 # CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
 # CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_VFAT_FS=y
 # CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
 # CONFIG_CRAMFS is not set
-# CONFIG_ISO9660_FS is not set
+# CONFIG_TMPFS is not set
+# CONFIG_RAMFS is not set
+CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
-# CONFIG_PROC_FS is not set
+CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS is not set
+CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
 # CONFIG_ROMFS_FS is not set
-# CONFIG_EXT2_FS is not set
+CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
 
 #
 # Partition Types
 #
-# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
 CONFIG_MSDOS_PARTITION=y
-# CONFIG_NLS is not set
-# CONFIG_NLS is not set
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_DEVFS_GUID is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Console drivers
+#
+CONFIG_VGA_CONSOLE=y
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
 
 #
 # Sound
 #
-# CONFIG_SOUND is not set
+CONFIG_SOUND=y
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+CONFIG_SOUND_CS4281=y
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+
+#
+# USB Controllers
+#
+CONFIG_USB_UHCI_ALT=y
+CONFIG_USB_OHCI=y
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+# CONFIG_USB_HID is not set
+CONFIG_USB_KBD=y
+CONFIG_USB_MOUSE=y
+# CONFIG_USB_WACOM is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Multimedia devices
+#
+CONFIG_USB_IBMCAM=y
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB misc drivers
+#
+# CONFIG_USB_RIO500 is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
 
 #
 # Kernel hacking
 #
-# CONFIG_IA32_SUPPORT is not set
-# CONFIG_MATHEMU is not set
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_IA64_EARLY_PRINTK is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_IA64_PRINT_HAZARDS=y
+# CONFIG_DISABLE_VHPT is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_IA64_DEBUG_CMPXCHG is not set
 # CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_IA64_PRINT_HAZARDS is not set
-# CONFIG_KDB is not set
diff -urN linux-2.4.13/arch/ia64/ia32/binfmt_elf32.c linux-2.4.13-lia/arch/ia64/ia32/binfmt_elf32.c
--- linux-2.4.13/arch/ia64/ia32/binfmt_elf32.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/ia32/binfmt_elf32.c	Thu Oct  4 00:21:52 2001
@@ -3,10 +3,11 @@
  *
  * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
  * Copyright (C) 2001 Hewlett-Packard Co
- * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * 06/16/00	A. Mallick	initialize csd/ssd/tssd/cflg for ia32_load_state
  * 04/13/01	D. Mosberger	dropped saving tssd in ar.k1---it's not needed
+ * 09/14/01	D. Mosberger	fixed memory management for gdt/tss page
  */
 #include <linux/config.h>
 
@@ -41,65 +42,59 @@
 extern void ia64_elf32_init (struct pt_regs *regs);
 extern void put_dirty_page (struct task_struct * tsk, struct page *page, unsigned long address);
 
+static void elf32_set_personality (void);
+
 #define ELF_PLAT_INIT(_r)		ia64_elf32_init(_r)
 #define setup_arg_pages(bprm)		ia32_setup_arg_pages(bprm)
-#define elf_map				elf_map32
+#define elf_map				elf32_map
+#define SET_PERSONALITY(ex, ibcs2)	elf32_set_personality()
 
 /* Ugly but avoids duplication */
 #include "../../../fs/binfmt_elf.c"
 
-/* Global descriptor table */
-unsigned long *ia32_gdt_table, *ia32_tss;
+extern struct page *ia32_shared_page[];
+extern unsigned long *ia32_gdt;
 
 struct page *
-put_shared_page (struct task_struct * tsk, struct page *page, unsigned long address)
+ia32_install_shared_page (struct vm_area_struct *vma, unsigned long address, int no_share)
 {
-	pgd_t * pgd;
-	pmd_t * pmd;
-	pte_t * pte;
-
-	if (page_count(page) != 1)
-		printk("mem_map disagrees with %p at %08lx\n", (void *) page, address);
+	struct page *pg = ia32_shared_page[(address - vma->vm_start)/PAGE_SIZE];
 
-	pgd = pgd_offset(tsk->mm, address);
-
-	spin_lock(&tsk->mm->page_table_lock);
-	{
-		pmd = pmd_alloc(tsk->mm, pgd, address);
-		if (!pmd)
-			goto out;
-		pte = pte_alloc(tsk->mm, pmd, address);
-		if (!pte)
-			goto out;
-		if (!pte_none(*pte))
-			goto out;
-		flush_page_to_ram(page);
-		set_pte(pte, pte_mkwrite(mk_pte(page, PAGE_SHARED)));
-	}
-	spin_unlock(&tsk->mm->page_table_lock);
-	/* no need for flush_tlb */
-	return page;
-
-  out:
-	spin_unlock(&tsk->mm->page_table_lock);
-	__free_page(page);
-	return 0;
+	get_page(pg);
+	return pg;
 }
 
+static struct vm_operations_struct ia32_shared_page_vm_ops = {
+	nopage:	ia32_install_shared_page
+};
+
 void
 ia64_elf32_init (struct pt_regs *regs)
 {
 	struct vm_area_struct *vma;
-	int nr;
 
 	/*
 	 * Map GDT and TSS below 4GB, where the processor can find them.  We need to map
 	 * it with privilege level 3 because the IVE uses non-privileged accesses to these
 	 * tables.  IA-32 segmentation is used to protect against IA-32 accesses to them.
 	 */
-	put_shared_page(current, virt_to_page(ia32_gdt_table), IA32_GDT_OFFSET);
-	if (PAGE_SHIFT <= IA32_PAGE_SHIFT)
-		put_shared_page(current, virt_to_page(ia32_tss), IA32_TSS_OFFSET);
+	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+	if (vma) {
+		vma->vm_mm = current->mm;
+		vma->vm_start = IA32_GDT_OFFSET;
+		vma->vm_end = vma->vm_start + max(PAGE_SIZE, 2*IA32_PAGE_SIZE);
+		vma->vm_page_prot = PAGE_SHARED;
+		vma->vm_flags = VM_READ|VM_MAYREAD;
+		vma->vm_ops = &ia32_shared_page_vm_ops;
+		vma->vm_pgoff = 0;
+		vma->vm_file = NULL;
+		vma->vm_private_data = NULL;
+		down_write(&current->mm->mmap_sem);
+		{
+			insert_vm_struct(current->mm, vma);
+		}
+		up_write(&current->mm->mmap_sem);
+	}
 
 	/*
 	 * Install LDT as anonymous memory.  This gives us all-zero segment descriptors
@@ -116,34 +111,13 @@
 		vma->vm_pgoff = 0;
 		vma->vm_file = NULL;
 		vma->vm_private_data = NULL;
-		insert_vm_struct(current->mm, vma);
+		down_write(&current->mm->mmap_sem);
+		{
+			insert_vm_struct(current->mm, vma);
+		}
+		up_write(&current->mm->mmap_sem);
 	}
 
-	nr = smp_processor_id();
-
-	current->thread.map_base  = IA32_PAGE_OFFSET/3;
-	current->thread.task_size = IA32_PAGE_OFFSET;	/* use what Linux/x86 uses... */
-	set_fs(USER_DS);				/* set addr limit for new TASK_SIZE */
-
-	/* Setup the segment selectors */
-	regs->r16 = (__USER_DS << 16) | __USER_DS; /* ES = DS, GS, FS are zero */
-	regs->r17 = (__USER_DS << 16) | __USER_CS; /* SS, CS; ia32_load_state() sets TSS and LDT */
-
-	/* Setup the segment descriptors */
-	regs->r24 = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_DS >> 3]);	/* ESD */
-	regs->r27 = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_DS >> 3]);	/* DSD */
-	regs->r28 = 0;								/* FSD (null) */
-	regs->r29 = 0;								/* GSD (null) */
-	regs->r30 = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[_LDT(nr)]);		/* LDTD */
-
-	/*
-	 * Setup GDTD.  Note: GDTD is the descrambled version of the pseudo-descriptor
-	 * format defined by Figure 3-11 "Pseudo-Descriptor Format" in the IA-32
-	 * architecture manual.
-	 */
-	regs->r31 = IA32_SEG_UNSCRAMBLE(IA32_SEG_DESCRIPTOR(IA32_GDT_OFFSET, IA32_PAGE_SIZE - 1, 0,
-							    0, 0, 0, 0, 0, 0));
-
 	ia64_psr(regs)->ac = 0;		/* turn off alignment checking */
 	regs->loadrs = 0;
 	/*
@@ -164,10 +138,19 @@
 	current->thread.fcr = IA32_FCR_DEFAULT;
 	current->thread.fir = 0;
 	current->thread.fdr = 0;
-	current->thread.csd = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_CS >> 3]);
-	current->thread.ssd = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_DS >> 3]);
-	current->thread.tssd = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[_TSS(nr)]);
 
+	/*
+	 * Setup GDTD.  Note: GDTD is the descrambled version of the pseudo-descriptor
+	 * format defined by Figure 3-11 "Pseudo-Descriptor Format" in the IA-32
+	 * architecture manual.
+	 */
+	regs->r31 = IA32_SEG_UNSCRAMBLE(IA32_SEG_DESCRIPTOR(IA32_GDT_OFFSET, IA32_PAGE_SIZE - 1, 0,
+							    0, 0, 0, 0, 0, 0));
+	/* Setup the segment selectors */
+	regs->r16 = (__USER_DS << 16) | __USER_DS; /* ES = DS, GS, FS are zero */
+	regs->r17 = (__USER_DS << 16) | __USER_CS; /* SS, CS; ia32_load_state() sets TSS and LDT */
+
+	ia32_load_segment_descriptors(current);
 	ia32_load_state(current);
 }
 
@@ -189,6 +172,7 @@
 	if (!mpnt)
 		return -ENOMEM;
 
+	down_write(&current->mm->mmap_sem);
 	{
 		mpnt->vm_mm = current->mm;
 		mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
@@ -204,54 +188,32 @@
 	}
 
 	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-		if (bprm->page[i]) {
-			put_dirty_page(current,bprm->page[i],stack_base);
+		struct page *page = bprm->page[i];
+		if (page) {
+			bprm->page[i] = NULL;
+			put_dirty_page(current, page, stack_base);
 		}
 		stack_base += PAGE_SIZE;
 	}
+	up_write(&current->mm->mmap_sem);
 
 	return 0;
 }
 
-static unsigned long
-ia32_mm_addr (unsigned long addr)
+static void
+elf32_set_personality (void)
 {
-	struct vm_area_struct *vma;
-
-	if ((vma = find_vma(current->mm, addr)) = NULL)
-		return ELF_PAGESTART(addr);
-	if (vma->vm_start > addr)
-		return ELF_PAGESTART(addr);
-	return ELF_PAGEALIGN(addr);
+	set_personality(PER_LINUX32);
+	current->thread.map_base  = IA32_PAGE_OFFSET/3;
+	current->thread.task_size = IA32_PAGE_OFFSET;	/* use what Linux/x86 uses... */
+	set_fs(USER_DS);				/* set addr limit for new TASK_SIZE */
 }
 
-/*
- *  Normally we would do an `mmap' to map in the process's text section.
- *  This doesn't work with IA32 processes as the ELF file might specify
- *  a non page size aligned address.  Instead we will just allocate
- *  memory and read the data in from the file.  Slightly less efficient
- *  but it works.
- */
-extern long ia32_do_mmap (struct file *filep, unsigned int len, unsigned int prot,
-			  unsigned int flags, unsigned int fd, unsigned int offset);
-
 static unsigned long
-elf_map32 (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type)
+elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type)
 {
-	unsigned long retval;
+	unsigned long pgoff = (eppnt->p_vaddr) & ~IA32_PAGE_MASK;
 
-	if (eppnt->p_memsz >= (1UL<<32) || addr > (1UL<<32) - eppnt->p_memsz)
-		return -EINVAL;
-
-	/*
-	 *  Make sure the elf interpreter doesn't get loaded at location 0
-	 *    so that NULL pointers correctly cause segfaults.
-	 */
-	if (addr = 0)
-		addr += PAGE_SIZE;
-	set_brk(ia32_mm_addr(addr), addr + eppnt->p_memsz);
-	memset((char *) addr + eppnt->p_filesz, 0, eppnt->p_memsz - eppnt->p_filesz);
-	kernel_read(filep, eppnt->p_offset, (char *) addr, eppnt->p_filesz);
-	retval = (unsigned long) addr;
-	return retval;
+	return ia32_do_mmap(filep, (addr & IA32_PAGE_MASK), eppnt->p_filesz + pgoff, prot, type,
+			    eppnt->p_offset - pgoff);
 }
diff -urN linux-2.4.13/arch/ia64/ia32/ia32_entry.S linux-2.4.13-lia/arch/ia64/ia32/ia32_entry.S
--- linux-2.4.13/arch/ia64/ia32/ia32_entry.S	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/ia32/ia32_entry.S	Wed Oct 24 18:11:48 2001
@@ -2,7 +2,7 @@
 #include <asm/offsets.h>
 #include <asm/signal.h>
 
-#include "../kernel/entry.h"
+#include "../kernel/minstate.h"
 
 	/*
 	 * execve() is special because in case of success, we need to
@@ -14,13 +14,13 @@
 	alloc loc1=ar.pfs,3,2,4,0
 	mov loc0=rp
 	.body
-	mov out0=in0			// filename
+	zxt4 out0=in0			// filename
 	;;				// stop bit between alloc and call
-	mov out1=in1			// argv
-	mov out2=in2			// envp
+	zxt4 out1=in1			// argv
+	zxt4 out2=in2			// envp
 	add out3\x16,sp			// regs
 	br.call.sptk.few rp=sys32_execve
-1:	cmp4.ge p6,p0=r8,r0
+1:	cmp.ge p6,p0=r8,r0
 	mov ar.pfs=loc1			// restore ar.pfs
 	;;
 (p6)	mov ar.pfs=r0			// clear ar.pfs in case of success
@@ -29,31 +29,80 @@
 	br.ret.sptk.few rp
 END(ia32_execve)
 
-	//
-	// Get possibly unaligned sigmask argument into an aligned
-	//   kernel buffer
-GLOBAL_ENTRY(ia32_rt_sigsuspend)
-	// We'll cheat and not do an alloc here since we are ultimately
-	// going to do a simple branch to the IA64 sys_rt_sigsuspend.
-	// r32 is still the first argument which is the signal mask.
-	// We copy this 4-byte aligned value to an 8-byte aligned buffer
-	// in the task structure and then jump to the IA64 code.
+ENTRY(ia32_clone)
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)
+	alloc r16=ar.pfs,2,2,4,0
+	DO_SAVE_SWITCH_STACK
+	mov loc0=rp
+	mov loc1=r16				// save ar.pfs across do_fork
+	.body
+	zxt4 out1=in1				// newsp
+	mov out3=0				// stacksize
+	adds out2=IA64_SWITCH_STACK_SIZE+16,sp	// out2 = &regs
+	zxt4 out0=in0				// out0 = clone_flags
+	br.call.sptk.many rp=do_fork
+.ret0:	.restore sp
+	adds sp=IA64_SWITCH_STACK_SIZE,sp	// pop the switch stack
+	mov ar.pfs=loc1
+	mov rp=loc0
+	br.ret.sptk.many rp
+END(ia32_clone)
 
-	EX(.Lfail, ld4 r2=[r32],4)		// load low part of sigmask
-	;;
-	EX(.Lfail, ld4 r3=[r32])		// load high part of sigmask
-	adds r32=IA64_TASK_THREAD_SIGMASK_OFFSET,r13
-	;;
-	st8 [r32]=r2
-	adds r10=IA64_TASK_THREAD_SIGMASK_OFFSET+4,r13
+ENTRY(sys32_rt_sigsuspend)
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
+	alloc loc1=ar.pfs,8,2,3,0		// preserve all eight input regs
+	mov loc0=rp
+	mov out0=in0				// mask
+	mov out1=in1				// sigsetsize
+	mov out2=sp				// out2 = &sigscratch
+	.fframe 16
+	adds sp=-16,sp				// allocate dummy "sigscratch"
 	;;
+	.body
+	br.call.sptk.many rp=ia32_rt_sigsuspend
+1:	.restore sp
+	adds sp\x16,sp
+	mov rp=loc0
+	mov ar.pfs=loc1
+	br.ret.sptk.many rp
+END(sys32_rt_sigsuspend)
 
-	st4 [r10]=r3
-	br.cond.sptk.many sys_rt_sigsuspend
-
-.Lfail:	br.ret.sptk.many rp	// failed to read sigmask
-END(ia32_rt_sigsuspend)
+ENTRY(sys32_sigsuspend)
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
+	alloc loc1=ar.pfs,8,2,3,0		// preserve all eight input regs
+	mov loc0=rp
+	mov out0=in2				// mask (first two args are ignored)
+	;;
+	mov out1=sp				// out1 = &sigscratch
+	.fframe 16
+	adds sp=-16,sp				// allocate dummy "sigscratch"
+	.body
+	br.call.sptk.many rp=ia32_sigsuspend
+1:	.restore sp
+	adds sp\x16,sp
+	mov rp=loc0
+	mov ar.pfs=loc1
+	br.ret.sptk.many rp
+END(sys32_sigsuspend)
 
+GLOBAL_ENTRY(ia32_ret_from_clone)
+	PT_REGS_UNWIND_INFO(0)
+	/*
+	 * We need to call schedule_tail() to complete the scheduling process.
+	 * Called by ia64_switch_to after do_fork()->copy_thread().  r8 contains the
+	 * address of the previously executing task.
+	 */
+	br.call.sptk.many rp=ia64_invoke_schedule_tail
+.ret1:	adds r2=IA64_TASK_PTRACE_OFFSET,r13
+	;;
+	ld8 r2=[r2]
+	;;
+	mov r8=0
+	tbit.nz p6,p0=r2,PT_TRACESYS_BIT
+(p6)	br.cond.spnt .ia32_strace_check_retval
+	;;					// prevent RAW on r8
+END(ia32_ret_from_clone)
+	// fall thrugh
 GLOBAL_ENTRY(ia32_ret_from_syscall)
 	PT_REGS_UNWIND_INFO(0)
 
@@ -72,20 +121,25 @@
 	// manipulate ar.pfs.
 	//
 	// Input:
-	//	r15 = syscall number
-	//	b6  = syscall entry point
+	//	r8 = syscall number
+	//	b6 = syscall entry point
 	//
 GLOBAL_ENTRY(ia32_trace_syscall)
 	PT_REGS_UNWIND_INFO(0)
+	mov r3=-38
+	adds r2=IA64_PT_REGS_R8_OFFSET+16,sp
+	;;
+	st8 [r2]=r3				// initialize return code to -ENOSYS
 	br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch syscall args
-.ret0:	br.call.sptk.few rp¶			// do the syscall
-.ret1:	cmp.lt p6,p0=r8,r0			// syscall failed?
+.ret2:	br.call.sptk.few rp¶			// do the syscall
+.ia32_strace_check_retval:
+	cmp.lt p6,p0=r8,r0			// syscall failed?
 	adds r2=IA64_PT_REGS_R8_OFFSET+16,sp	// r2 = &pt_regs.r8
 	;;
 	st8.spill [r2]=r8			// store return value in slot for r8
 	br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch return value
-.ret2:	alloc r2=ar.pfs,0,0,0,0			// drop the syscall argument frame
-	br.cond.sptk.many ia64_leave_kernel	// rp MUST be != ia64_leave_kernel!
+.ret4:	alloc r2=ar.pfs,0,0,0,0			// drop the syscall argument frame
+	br.cond.sptk.many ia64_leave_kernel
 END(ia32_trace_syscall)
 
 GLOBAL_ENTRY(sys32_vfork)
@@ -110,7 +164,7 @@
 	mov out3=0
 	adds out2=IA64_SWITCH_STACK_SIZE+16,sp	// out2 = &regs
 	br.call.sptk.few rp=do_fork
-.ret3:	mov ar.pfs=loc1
+.ret5:	mov ar.pfs=loc1
 	.restore sp
 	adds sp=IA64_SWITCH_STACK_SIZE,sp	// pop the switch stack
 	mov rp=loc0
@@ -137,21 +191,21 @@
 	data8 sys32_time
 	data8 sys_mknod
 	data8 sys_chmod		  /* 15 */
-	data8 sys_lchown
+	data8 sys_lchown	/* 16-bit version */
 	data8 sys32_ni_syscall	  /* old break syscall holder */
 	data8 sys32_ni_syscall
 	data8 sys32_lseek
 	data8 sys_getpid	  /* 20 */
 	data8 sys_mount
 	data8 sys_oldumount
-	data8 sys_setuid
-	data8 sys_getuid
+	data8 sys_setuid	/* 16-bit version */
+	data8 sys_getuid	/* 16-bit version */
 	data8 sys32_ni_syscall /* sys_stime is not supported on IA64 */  /* 25 */
 	data8 sys32_ptrace
 	data8 sys32_alarm
 	data8 sys32_ni_syscall
-	data8 sys_pause
-	data8 ia32_utime	  /* 30 */
+	data8 sys32_pause
+	data8 sys32_utime	  /* 30 */
 	data8 sys32_ni_syscall	  /* old stty syscall holder */
 	data8 sys32_ni_syscall	  /* old gtty syscall holder */
 	data8 sys_access
@@ -167,15 +221,15 @@
 	data8 sys32_times
 	data8 sys32_ni_syscall	  /* old prof syscall holder */
 	data8 sys_brk		  /* 45 */
-	data8 sys_setgid
-	data8 sys_getgid
+	data8 sys_setgid	/* 16-bit version */
+	data8 sys_getgid	/* 16-bit version */
 	data8 sys32_signal
-	data8 sys_geteuid
-	data8 sys_getegid	  /* 50 */
+	data8 sys_geteuid	/* 16-bit version */
+	data8 sys_getegid	/* 16-bit version */	  /* 50 */
 	data8 sys_acct
 	data8 sys_umount	  /* recycled never used phys( */
 	data8 sys32_ni_syscall	  /* old lock syscall holder */
-	data8 ia32_ioctl
+	data8 sys32_ioctl
 	data8 sys32_fcntl	  /* 55 */
 	data8 sys32_ni_syscall	  /* old mpx syscall holder */
 	data8 sys_setpgid
@@ -191,19 +245,19 @@
 	data8 sys32_sigaction
 	data8 sys32_ni_syscall
 	data8 sys32_ni_syscall
-	data8 sys_setreuid	  /* 70 */
-	data8 sys_setregid
-	data8 sys32_ni_syscall
-	data8 sys_sigpending
+	data8 sys_setreuid	/* 16-bit version */	  /* 70 */
+	data8 sys_setregid	/* 16-bit version */
+	data8 sys32_sigsuspend
+	data8 sys32_sigpending
 	data8 sys_sethostname
 	data8 sys32_setrlimit	  /* 75 */
-	data8 sys32_getrlimit
+	data8 sys32_old_getrlimit
 	data8 sys32_getrusage
 	data8 sys32_gettimeofday
 	data8 sys32_settimeofday
-	data8 sys_getgroups	  /* 80 */
-	data8 sys_setgroups
-	data8 old_select
+	data8 sys32_getgroups16	  /* 80 */
+	data8 sys32_setgroups16
+	data8 sys32_old_select
 	data8 sys_symlink
 	data8 sys32_ni_syscall
 	data8 sys_readlink	  /* 85 */
@@ -212,17 +266,17 @@
 	data8 sys_reboot
 	data8 sys32_readdir
 	data8 sys32_mmap	  /* 90 */
-	data8 sys_munmap
+	data8 sys32_munmap
 	data8 sys_truncate
 	data8 sys_ftruncate
 	data8 sys_fchmod
-	data8 sys_fchown	  /* 95 */
+	data8 sys_fchown	/* 16-bit version */	  /* 95 */
 	data8 sys_getpriority
 	data8 sys_setpriority
 	data8 sys32_ni_syscall	  /* old profil syscall holder */
 	data8 sys32_statfs
 	data8 sys32_fstatfs	  /* 100 */
-	data8 sys_ioperm
+	data8 sys32_ioperm
 	data8 sys32_socketcall
 	data8 sys_syslog
 	data8 sys32_setitimer
@@ -231,36 +285,36 @@
 	data8 sys32_newlstat
 	data8 sys32_newfstat
 	data8 sys32_ni_syscall
-	data8 sys_iopl		  /* 110 */
+	data8 sys32_iopl		  /* 110 */
 	data8 sys_vhangup
 	data8 sys32_ni_syscall		/* used to be sys_idle */
 	data8 sys32_ni_syscall
 	data8 sys32_wait4
 	data8 sys_swapoff	  /* 115 */
-	data8 sys_sysinfo
+	data8 sys32_sysinfo
 	data8 sys32_ipc
 	data8 sys_fsync
 	data8 sys32_sigreturn
-	data8 sys_clone		  /* 120 */
+	data8 ia32_clone	  /* 120 */
 	data8 sys_setdomainname
 	data8 sys32_newuname
 	data8 sys32_modify_ldt
-	data8 sys_adjtimex
+	data8 sys32_ni_syscall	/* adjtimex */
 	data8 sys32_mprotect	  /* 125 */
-	data8 sys_sigprocmask
-	data8 sys_create_module
-	data8 sys_init_module
-	data8 sys_delete_module
-	data8 sys_get_kernel_syms  /* 130 */
-	data8 sys_quotactl
+	data8 sys32_sigprocmask
+	data8 sys32_ni_syscall	/* create_module */
+	data8 sys32_ni_syscall	/* init_module */
+	data8 sys32_ni_syscall	/* delete_module */
+	data8 sys32_ni_syscall	/* get_kernel_syms */  /* 130 */
+	data8 sys32_quotactl
 	data8 sys_getpgid
 	data8 sys_fchdir
-	data8 sys_bdflush
-	data8 sys_sysfs		  /* 135 */
-	data8 sys_personality
+	data8 sys32_ni_syscall	/* sys_bdflush */
+	data8 sys_sysfs		/* 135 */
+	data8 sys32_personality
 	data8 sys32_ni_syscall	  /* for afs_syscall */
-	data8 sys_setfsuid
-	data8 sys_setfsgid
+	data8 sys_setfsuid	/* 16-bit version */
+	data8 sys_setfsgid	/* 16-bit version */
 	data8 sys_llseek	  /* 140 */
 	data8 sys32_getdents
 	data8 sys32_select
@@ -282,66 +336,73 @@
 	data8 sys_sched_yield
 	data8 sys_sched_get_priority_max
 	data8 sys_sched_get_priority_min	 /* 160 */
-	data8 sys_sched_rr_get_interval
+	data8 sys32_sched_rr_get_interval
 	data8 sys32_nanosleep
 	data8 sys_mremap
-	data8 sys_setresuid
-	data8 sys32_getresuid	  /* 165 */
-	data8 sys_vm86
-	data8 sys_query_module
+	data8 sys_setresuid	/* 16-bit version */
+	data8 sys32_getresuid16	/* 16-bit version */	  /* 165 */
+	data8 sys32_ni_syscall	/* vm86 */
+	data8 sys32_ni_syscall	/* sys_query_module */
 	data8 sys_poll
-	data8 sys_nfsservctl
+	data8 sys32_ni_syscall	/* nfsservctl */
 	data8 sys_setresgid	  /* 170 */
-	data8 sys32_getresgid
+	data8 sys32_getresgid16
 	data8 sys_prctl
 	data8 sys32_rt_sigreturn
 	data8 sys32_rt_sigaction
 	data8 sys32_rt_sigprocmask /* 175 */
 	data8 sys_rt_sigpending
-	data8 sys_rt_sigtimedwait
-	data8 sys_rt_sigqueueinfo
-	data8 ia32_rt_sigsuspend
-	data8 sys_pread		  /* 180 */
-	data8 sys_pwrite
-	data8 sys_chown
+	data8 sys32_rt_sigtimedwait
+	data8 sys32_rt_sigqueueinfo
+	data8 sys32_rt_sigsuspend
+	data8 sys32_pread	  /* 180 */
+	data8 sys32_pwrite
+	data8 sys_chown	/* 16-bit version */
 	data8 sys_getcwd
 	data8 sys_capget
 	data8 sys_capset	  /* 185 */
 	data8 sys32_sigaltstack
-	data8 sys_sendfile
+	data8 sys32_sendfile
 	data8 sys32_ni_syscall		  /* streams1 */
 	data8 sys32_ni_syscall		  /* streams2 */
 	data8 sys32_vfork	  /* 190 */
+	data8 sys32_getrlimit
+	data8 sys32_mmap2
+	data8 sys32_truncate64
+	data8 sys32_ftruncate64
+	data8 sys32_stat64	  /* 195 */
+	data8 sys32_lstat64
+	data8 sys32_fstat64
+	data8 sys_lchown
+	data8 sys_getuid
+	data8 sys_getgid	  /* 200 */
+	data8 sys_geteuid
+	data8 sys_getegid
+	data8 sys_setreuid
+	data8 sys_setregid
+	data8 sys_getgroups	  /* 205 */
+	data8 sys_setgroups
+	data8 sys_fchown
+	data8 sys_setresuid
+	data8 sys_getresuid
+	data8 sys_setresgid	  /* 210 */
+	data8 sys_getresgid
+	data8 sys_chown
+	data8 sys_setuid
+	data8 sys_setgid
+	data8 sys_setfsuid	  /* 215 */
+	data8 sys_setfsgid
+	data8 sys_pivot_root
+	data8 sys_mincore
+	data8 sys_madvise
+	data8 sys_getdents64	  /* 220 */
+	data8 sys32_fcntl64
+	data8 sys_ni_syscall		/* reserved for TUX */
+	data8 sys_ni_syscall		/* reserved for Security */
+	data8 sys_gettid
+	data8 sys_readahead	  /* 225 */
 	data8 sys_ni_syscall
 	data8 sys_ni_syscall
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall	  /* 195 */
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall	  /* 200 */
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall	  /* 205 */
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall	  /* 210 */
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall	  /* 215 */
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall	  /* 220 */
 	data8 sys_ni_syscall
 	data8 sys_ni_syscall
 	/*
diff -urN linux-2.4.13/arch/ia64/ia32/ia32_ioctl.c linux-2.4.13-lia/arch/ia64/ia32/ia32_ioctl.c
--- linux-2.4.13/arch/ia64/ia32/ia32_ioctl.c	Thu Jan  4 12:50:17 2001
+++ linux-2.4.13-lia/arch/ia64/ia32/ia32_ioctl.c	Thu Oct  4 00:21:52 2001
@@ -3,6 +3,8 @@
  *
  * Copyright (C) 2000 VA Linux Co
  * Copyright (C) 2000 Don Dugger <n0ano@valinux.com>
+ * Copyright (C) 2001 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #include <linux/types.h>
@@ -22,8 +24,12 @@
 #include <linux/if_ppp.h>
 #include <linux/ixjuser.h>
 #include <linux/i2o-dev.h>
+
+#include <asm/ia32.h>
+
 #include <../drivers/char/drm/drm.h>
 
+
 #define IOCTL_NR(a)	((a) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT))
 
 #define DO_IOCTL(fd, cmd, arg) ({			\
@@ -36,179 +42,200 @@
 	_ret;						\
 })
 
-#define P(i)	((void *)(long)(i))
-
+#define P(i)	((void *)(unsigned long)(i))
 
 asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
 
-asmlinkage long ia32_ioctl(unsigned int fd, unsigned int cmd, unsigned int arg)
+static long
+put_dirent32 (struct dirent *d, struct linux32_dirent *d32)
+{
+	size_t namelen = strlen(d->d_name);
+
+	return (put_user(d->d_ino, &d32->d_ino)
+		|| put_user(d->d_off, &d32->d_off)
+		|| put_user(d->d_reclen, &d32->d_reclen)
+		|| copy_to_user(d32->d_name, d->d_name, namelen + 1));
+}
+
+asmlinkage long
+sys32_ioctl (unsigned int fd, unsigned int cmd, unsigned int arg)
 {
 	long ret;
 
 	switch (IOCTL_NR(cmd)) {
-
-	case IOCTL_NR(DRM_IOCTL_VERSION):
-		{
-			drm_version_t ver;
-			struct {
-				int	version_major;
-				int	version_minor;
-				int	version_patchlevel;
-				unsigned int name_len;
-				unsigned int name; /* pointer */
-				unsigned int date_len;
-				unsigned int date; /* pointer */
-				unsigned int desc_len;
-				unsigned int desc; /* pointer */
-			} ver32;
-
-			if (copy_from_user(&ver32, P(arg), sizeof(ver32)))
-				return -EFAULT;
-			ver.name_len = ver32.name_len;
-			ver.name = P(ver32.name);
-			ver.date_len = ver32.date_len;
-			ver.date = P(ver32.date);
-			ver.desc_len = ver32.desc_len;
-			ver.desc = P(ver32.desc);
-			ret = DO_IOCTL(fd, cmd, &ver);
-			if (ret >= 0) {
-				ver32.version_major = ver.version_major;
-				ver32.version_minor = ver.version_minor;
-				ver32.version_patchlevel = ver.version_patchlevel;
-				ver32.name_len = ver.name_len;
-				ver32.date_len = ver.date_len;
-				ver32.desc_len = ver.desc_len;
-				if (copy_to_user(P(arg), &ver32, sizeof(ver32)))
-					return -EFAULT;
-			}
-			return(ret);
-		}
-
-	case IOCTL_NR(DRM_IOCTL_GET_UNIQUE):
-		{
-			drm_unique_t un;
-			struct {
-				unsigned int unique_len;
-				unsigned int unique;
-			} un32;
-
-			if (copy_from_user(&un32, P(arg), sizeof(un32)))
-				return -EFAULT;
-			un.unique_len = un32.unique_len;
-			un.unique = P(un32.unique);
-			ret = DO_IOCTL(fd, cmd, &un);
-			if (ret >= 0) {
-				un32.unique_len = un.unique_len;
-				if (copy_to_user(P(arg), &un32, sizeof(un32)))
-					return -EFAULT;
-			}
-			return(ret);
-		}
-	case IOCTL_NR(DRM_IOCTL_SET_UNIQUE):
-	case IOCTL_NR(DRM_IOCTL_ADD_MAP):
-	case IOCTL_NR(DRM_IOCTL_ADD_BUFS):
-	case IOCTL_NR(DRM_IOCTL_MARK_BUFS):
-	case IOCTL_NR(DRM_IOCTL_INFO_BUFS):
-	case IOCTL_NR(DRM_IOCTL_MAP_BUFS):
-	case IOCTL_NR(DRM_IOCTL_FREE_BUFS):
-	case IOCTL_NR(DRM_IOCTL_ADD_CTX):
-	case IOCTL_NR(DRM_IOCTL_RM_CTX):
-	case IOCTL_NR(DRM_IOCTL_MOD_CTX):
-	case IOCTL_NR(DRM_IOCTL_GET_CTX):
-	case IOCTL_NR(DRM_IOCTL_SWITCH_CTX):
-	case IOCTL_NR(DRM_IOCTL_NEW_CTX):
-	case IOCTL_NR(DRM_IOCTL_RES_CTX):
-
-	case IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE):
-	case IOCTL_NR(DRM_IOCTL_AGP_RELEASE):
-	case IOCTL_NR(DRM_IOCTL_AGP_ENABLE):
-	case IOCTL_NR(DRM_IOCTL_AGP_INFO):
-	case IOCTL_NR(DRM_IOCTL_AGP_ALLOC):
-	case IOCTL_NR(DRM_IOCTL_AGP_FREE):
-	case IOCTL_NR(DRM_IOCTL_AGP_BIND):
-	case IOCTL_NR(DRM_IOCTL_AGP_UNBIND):
-
-	/* Mga specific ioctls */
-
-	case IOCTL_NR(DRM_IOCTL_MGA_INIT):
-
-	/* I810 specific ioctls */
-
-	case IOCTL_NR(DRM_IOCTL_I810_GETBUF):
-	case IOCTL_NR(DRM_IOCTL_I810_COPY):
-
-	/* Rage 128 specific ioctls */
-
-	case IOCTL_NR(DRM_IOCTL_R128_PACKET):
-
-	case IOCTL_NR(VFAT_IOCTL_READDIR_BOTH):
-	case IOCTL_NR(VFAT_IOCTL_READDIR_SHORT):
-	case IOCTL_NR(MTIOCGET):
-	case IOCTL_NR(MTIOCPOS):
-	case IOCTL_NR(MTIOCGETCONFIG):
-	case IOCTL_NR(MTIOCSETCONFIG):
-	case IOCTL_NR(PPPIOCSCOMPRESS):
-	case IOCTL_NR(PPPIOCGIDLE):
-	case IOCTL_NR(NCP_IOC_GET_FS_INFO_V2):
-	case IOCTL_NR(NCP_IOC_GETOBJECTNAME):
-	case IOCTL_NR(NCP_IOC_SETOBJECTNAME):
-	case IOCTL_NR(NCP_IOC_GETPRIVATEDATA):
-	case IOCTL_NR(NCP_IOC_SETPRIVATEDATA):
-	case IOCTL_NR(NCP_IOC_GETMOUNTUID2):
-	case IOCTL_NR(CAPI_MANUFACTURER_CMD):
-	case IOCTL_NR(VIDIOCGTUNER):
-	case IOCTL_NR(VIDIOCSTUNER):
-	case IOCTL_NR(VIDIOCGWIN):
-	case IOCTL_NR(VIDIOCSWIN):
-	case IOCTL_NR(VIDIOCGFBUF):
-	case IOCTL_NR(VIDIOCSFBUF):
-	case IOCTL_NR(MGSL_IOCSPARAMS):
-	case IOCTL_NR(MGSL_IOCGPARAMS):
-	case IOCTL_NR(ATM_GETNAMES):
-	case IOCTL_NR(ATM_GETLINKRATE):
-	case IOCTL_NR(ATM_GETTYPE):
-	case IOCTL_NR(ATM_GETESI):
-	case IOCTL_NR(ATM_GETADDR):
-	case IOCTL_NR(ATM_RSTADDR):
-	case IOCTL_NR(ATM_ADDADDR):
-	case IOCTL_NR(ATM_DELADDR):
-	case IOCTL_NR(ATM_GETCIRANGE):
-	case IOCTL_NR(ATM_SETCIRANGE):
-	case IOCTL_NR(ATM_SETESI):
-	case IOCTL_NR(ATM_SETESIF):
-	case IOCTL_NR(ATM_GETSTAT):
-	case IOCTL_NR(ATM_GETSTATZ):
-	case IOCTL_NR(ATM_GETLOOP):
-	case IOCTL_NR(ATM_SETLOOP):
-	case IOCTL_NR(ATM_QUERYLOOP):
-	case IOCTL_NR(ENI_SETMULT):
-	case IOCTL_NR(NS_GETPSTAT):
-	/* case IOCTL_NR(NS_SETBUFLEV): This is a duplicate case with ZATM_GETPOOLZ */
-	case IOCTL_NR(ZATM_GETPOOLZ):
-	case IOCTL_NR(ZATM_GETPOOL):
-	case IOCTL_NR(ZATM_SETPOOL):
-	case IOCTL_NR(ZATM_GETTHIST):
-	case IOCTL_NR(IDT77105_GETSTAT):
-	case IOCTL_NR(IDT77105_GETSTATZ):
-	case IOCTL_NR(IXJCTL_TONE_CADENCE):
-	case IOCTL_NR(IXJCTL_FRAMES_READ):
-	case IOCTL_NR(IXJCTL_FRAMES_WRITTEN):
-	case IOCTL_NR(IXJCTL_READ_WAIT):
-	case IOCTL_NR(IXJCTL_WRITE_WAIT):
-	case IOCTL_NR(IXJCTL_DRYBUFFER_READ):
-	case IOCTL_NR(I2OHRTGET):
-	case IOCTL_NR(I2OLCTGET):
-	case IOCTL_NR(I2OPARMSET):
-	case IOCTL_NR(I2OPARMGET):
-	case IOCTL_NR(I2OSWDL):
-	case IOCTL_NR(I2OSWUL):
-	case IOCTL_NR(I2OSWDEL):
-	case IOCTL_NR(I2OHTML):
+	      case IOCTL_NR(VFAT_IOCTL_READDIR_SHORT):
+	      case IOCTL_NR(VFAT_IOCTL_READDIR_BOTH): {
+		      struct linux32_dirent *d32 = P(arg);
+		      struct dirent d[2];
+
+		      ret = DO_IOCTL(fd, _IOR('r', _IOC_NR(cmd),
+					      struct dirent [2]),
+				     (unsigned long) d);
+		      if (ret < 0)
+			  return ret;
+
+		      if (put_dirent32(d, d32) || put_dirent32(d + 1, d32 + 1))
+			  return -EFAULT;
+
+		      return ret;
+	      }
+
+	      case IOCTL_NR(DRM_IOCTL_VERSION):
+	      {
+		      drm_version_t ver;
+		      struct {
+			      int	version_major;
+			      int	version_minor;
+			      int	version_patchlevel;
+			      unsigned int name_len;
+			      unsigned int name; /* pointer */
+			      unsigned int date_len;
+			      unsigned int date; /* pointer */
+			      unsigned int desc_len;
+			      unsigned int desc; /* pointer */
+		      } ver32;
+
+		      if (copy_from_user(&ver32, P(arg), sizeof(ver32)))
+			      return -EFAULT;
+		      ver.name_len = ver32.name_len;
+		      ver.name = P(ver32.name);
+		      ver.date_len = ver32.date_len;
+		      ver.date = P(ver32.date);
+		      ver.desc_len = ver32.desc_len;
+		      ver.desc = P(ver32.desc);
+		      ret = DO_IOCTL(fd, DRM_IOCTL_VERSION, &ver);
+		      if (ret >= 0) {
+			      ver32.version_major = ver.version_major;
+			      ver32.version_minor = ver.version_minor;
+			      ver32.version_patchlevel = ver.version_patchlevel;
+			      ver32.name_len = ver.name_len;
+			      ver32.date_len = ver.date_len;
+			      ver32.desc_len = ver.desc_len;
+			      if (copy_to_user(P(arg), &ver32, sizeof(ver32)))
+				      return -EFAULT;
+		      }
+		      return ret;
+	      }
+
+	      case IOCTL_NR(DRM_IOCTL_GET_UNIQUE):
+	      {
+		      drm_unique_t un;
+		      struct {
+			      unsigned int unique_len;
+			      unsigned int unique;
+		      } un32;
+
+		      if (copy_from_user(&un32, P(arg), sizeof(un32)))
+			      return -EFAULT;
+		      un.unique_len = un32.unique_len;
+		      un.unique = P(un32.unique);
+		      ret = DO_IOCTL(fd, DRM_IOCTL_GET_UNIQUE, &un);
+		      if (ret >= 0) {
+			      un32.unique_len = un.unique_len;
+			      if (copy_to_user(P(arg), &un32, sizeof(un32)))
+				      return -EFAULT;
+		      }
+		      return ret;
+	      }
+	      case IOCTL_NR(DRM_IOCTL_SET_UNIQUE):
+	      case IOCTL_NR(DRM_IOCTL_ADD_MAP):
+	      case IOCTL_NR(DRM_IOCTL_ADD_BUFS):
+	      case IOCTL_NR(DRM_IOCTL_MARK_BUFS):
+	      case IOCTL_NR(DRM_IOCTL_INFO_BUFS):
+	      case IOCTL_NR(DRM_IOCTL_MAP_BUFS):
+	      case IOCTL_NR(DRM_IOCTL_FREE_BUFS):
+	      case IOCTL_NR(DRM_IOCTL_ADD_CTX):
+	      case IOCTL_NR(DRM_IOCTL_RM_CTX):
+	      case IOCTL_NR(DRM_IOCTL_MOD_CTX):
+	      case IOCTL_NR(DRM_IOCTL_GET_CTX):
+	      case IOCTL_NR(DRM_IOCTL_SWITCH_CTX):
+	      case IOCTL_NR(DRM_IOCTL_NEW_CTX):
+	      case IOCTL_NR(DRM_IOCTL_RES_CTX):
+
+	      case IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE):
+	      case IOCTL_NR(DRM_IOCTL_AGP_RELEASE):
+	      case IOCTL_NR(DRM_IOCTL_AGP_ENABLE):
+	      case IOCTL_NR(DRM_IOCTL_AGP_INFO):
+	      case IOCTL_NR(DRM_IOCTL_AGP_ALLOC):
+	      case IOCTL_NR(DRM_IOCTL_AGP_FREE):
+	      case IOCTL_NR(DRM_IOCTL_AGP_BIND):
+	      case IOCTL_NR(DRM_IOCTL_AGP_UNBIND):
+
+		/* Mga specific ioctls */
+
+	      case IOCTL_NR(DRM_IOCTL_MGA_INIT):
+
+		/* I810 specific ioctls */
+
+	      case IOCTL_NR(DRM_IOCTL_I810_GETBUF):
+	      case IOCTL_NR(DRM_IOCTL_I810_COPY):
+
+	      case IOCTL_NR(MTIOCGET):
+	      case IOCTL_NR(MTIOCPOS):
+	      case IOCTL_NR(MTIOCGETCONFIG):
+	      case IOCTL_NR(MTIOCSETCONFIG):
+	      case IOCTL_NR(PPPIOCSCOMPRESS):
+	      case IOCTL_NR(PPPIOCGIDLE):
+	      case IOCTL_NR(NCP_IOC_GET_FS_INFO_V2):
+	      case IOCTL_NR(NCP_IOC_GETOBJECTNAME):
+	      case IOCTL_NR(NCP_IOC_SETOBJECTNAME):
+	      case IOCTL_NR(NCP_IOC_GETPRIVATEDATA):
+	      case IOCTL_NR(NCP_IOC_SETPRIVATEDATA):
+	      case IOCTL_NR(NCP_IOC_GETMOUNTUID2):
+	      case IOCTL_NR(CAPI_MANUFACTURER_CMD):
+	      case IOCTL_NR(VIDIOCGTUNER):
+	      case IOCTL_NR(VIDIOCSTUNER):
+	      case IOCTL_NR(VIDIOCGWIN):
+	      case IOCTL_NR(VIDIOCSWIN):
+	      case IOCTL_NR(VIDIOCGFBUF):
+	      case IOCTL_NR(VIDIOCSFBUF):
+	      case IOCTL_NR(MGSL_IOCSPARAMS):
+	      case IOCTL_NR(MGSL_IOCGPARAMS):
+	      case IOCTL_NR(ATM_GETNAMES):
+	      case IOCTL_NR(ATM_GETLINKRATE):
+	      case IOCTL_NR(ATM_GETTYPE):
+	      case IOCTL_NR(ATM_GETESI):
+	      case IOCTL_NR(ATM_GETADDR):
+	      case IOCTL_NR(ATM_RSTADDR):
+	      case IOCTL_NR(ATM_ADDADDR):
+	      case IOCTL_NR(ATM_DELADDR):
+	      case IOCTL_NR(ATM_GETCIRANGE):
+	      case IOCTL_NR(ATM_SETCIRANGE):
+	      case IOCTL_NR(ATM_SETESI):
+	      case IOCTL_NR(ATM_SETESIF):
+	      case IOCTL_NR(ATM_GETSTAT):
+	      case IOCTL_NR(ATM_GETSTATZ):
+	      case IOCTL_NR(ATM_GETLOOP):
+	      case IOCTL_NR(ATM_SETLOOP):
+	      case IOCTL_NR(ATM_QUERYLOOP):
+	      case IOCTL_NR(ENI_SETMULT):
+	      case IOCTL_NR(NS_GETPSTAT):
+		/* case IOCTL_NR(NS_SETBUFLEV): This is a duplicate case with ZATM_GETPOOLZ */
+	      case IOCTL_NR(ZATM_GETPOOLZ):
+	      case IOCTL_NR(ZATM_GETPOOL):
+	      case IOCTL_NR(ZATM_SETPOOL):
+	      case IOCTL_NR(ZATM_GETTHIST):
+	      case IOCTL_NR(IDT77105_GETSTAT):
+	      case IOCTL_NR(IDT77105_GETSTATZ):
+	      case IOCTL_NR(IXJCTL_TONE_CADENCE):
+	      case IOCTL_NR(IXJCTL_FRAMES_READ):
+	      case IOCTL_NR(IXJCTL_FRAMES_WRITTEN):
+	      case IOCTL_NR(IXJCTL_READ_WAIT):
+	      case IOCTL_NR(IXJCTL_WRITE_WAIT):
+	      case IOCTL_NR(IXJCTL_DRYBUFFER_READ):
+	      case IOCTL_NR(I2OHRTGET):
+	      case IOCTL_NR(I2OLCTGET):
+	      case IOCTL_NR(I2OPARMSET):
+	      case IOCTL_NR(I2OPARMGET):
+	      case IOCTL_NR(I2OSWDL):
+	      case IOCTL_NR(I2OSWUL):
+	      case IOCTL_NR(I2OSWDEL):
+	      case IOCTL_NR(I2OHTML):
 		break;
-	default:
-		return(sys_ioctl(fd, cmd, (unsigned long)arg));
+	      default:
+		return sys_ioctl(fd, cmd, (unsigned long)arg);
 
 	}
 	printk("%x:unimplemented IA32 ioctl system call\n", cmd);
-	return(-EINVAL);
+	return -EINVAL;
 }
diff -urN linux-2.4.13/arch/ia64/ia32/ia32_ldt.c linux-2.4.13-lia/arch/ia64/ia32/ia32_ldt.c
--- linux-2.4.13/arch/ia64/ia32/ia32_ldt.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/ia32/ia32_ldt.c	Wed Oct 24 18:12:38 2001
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001 Hewlett-Packard Co
- * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * Adapted from arch/i386/kernel/ldt.c
  */
@@ -16,6 +16,8 @@
 #include <asm/uaccess.h>
 #include <asm/ia32.h>
 
+#define P(p)	((void *) (unsigned long) (p))
+
 /*
  * read_ldt() is not really atomic - this is not a problem since synchronization of reads
  * and writes done to the LDT has to be assured by user-space anyway. Writes are atomic,
@@ -58,10 +60,30 @@
 }
 
 static int
+read_default_ldt (void * ptr, unsigned long bytecount)
+{
+	unsigned long size;
+	int err;
+
+	/* XXX fix me: should return equivalent of default_ldt[0] */
+	err = 0;
+	size = 8;
+	if (size > bytecount)
+		size = bytecount;
+
+	err = size;
+	if (clear_user(ptr, size))
+		err = -EFAULT;
+
+	return err;
+}
+
+static int
 write_ldt (void * ptr, unsigned long bytecount, int oldmode)
 {
 	struct ia32_modify_ldt_ldt_s ldt_info;
 	__u64 entry;
+	int ret;
 
 	if (bytecount != sizeof(ldt_info))
 		return -EINVAL;
@@ -97,23 +119,28 @@
 	 * memory, but we still need to guard against out-of-memory, hence we must use
 	 * put_user().
 	 */
-	return __put_user(entry, (__u64 *) IA32_LDT_OFFSET + ldt_info.entry_number);
+	ret = __put_user(entry, (__u64 *) IA32_LDT_OFFSET + ldt_info.entry_number);
+	ia32_load_segment_descriptors(current);
+	return ret;
 }
 
 asmlinkage int
-sys32_modify_ldt (int func, void *ptr, unsigned int bytecount)
+sys32_modify_ldt (int func, unsigned int ptr, unsigned int bytecount)
 {
 	int ret = -ENOSYS;
 
 	switch (func) {
 	      case 0:
-		ret = read_ldt(ptr, bytecount);
+		ret = read_ldt(P(ptr), bytecount);
 		break;
 	      case 1:
-		ret = write_ldt(ptr, bytecount, 1);
+		ret = write_ldt(P(ptr), bytecount, 1);
+		break;
+	      case 2:
+		ret = read_default_ldt(P(ptr), bytecount);
 		break;
 	      case 0x11:
-		ret = write_ldt(ptr, bytecount, 0);
+		ret = write_ldt(P(ptr), bytecount, 0);
 		break;
 	}
 	return ret;
diff -urN linux-2.4.13/arch/ia64/ia32/ia32_signal.c linux-2.4.13-lia/arch/ia64/ia32/ia32_signal.c
--- linux-2.4.13/arch/ia64/ia32/ia32_signal.c	Mon Oct  9 17:54:53 2000
+++ linux-2.4.13-lia/arch/ia64/ia32/ia32_signal.c	Wed Oct 10 17:38:49 2001
@@ -1,8 +1,8 @@
 /*
  * IA32 Architecture-specific signal handling support.
  *
- * Copyright (C) 1999 Hewlett-Packard Co
- * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999, 2001 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
  * Copyright (C) 2000 VA Linux Co
  * Copyright (C) 2000 Don Dugger <n0ano@valinux.com>
@@ -13,6 +13,7 @@
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/personality.h>
 #include <linux/ptrace.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
@@ -28,9 +29,15 @@
 #include <asm/segment.h>
 #include <asm/ia32.h>
 
+#include "../kernel/sigframe.h"
+
+#define A(__x)		((unsigned long)(__x))
+
 #define DEBUG_SIG	0
 #define _BLOCKABLE	(~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
+#define __IA32_NR_sigreturn            119
+#define __IA32_NR_rt_sigreturn         173
 
 struct sigframe_ia32
 {
@@ -54,12 +61,51 @@
        char retcode[8];
 };
 
-static int
+int
+copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 *from)
+{
+	unsigned long tmp;
+	int err;
+
+	if (!access_ok(VERIFY_READ, from, sizeof(siginfo_t32)))
+		return -EFAULT;
+
+	err = __get_user(to->si_signo, &from->si_signo);
+	err |= __get_user(to->si_errno, &from->si_errno);
+	err |= __get_user(to->si_code, &from->si_code);
+
+	if (from->si_code < 0)
+		err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
+	else {
+		switch (from->si_code >> 16) {
+		      case __SI_CHLD >> 16:
+			err |= __get_user(to->si_utime, &from->si_utime);
+			err |= __get_user(to->si_stime, &from->si_stime);
+			err |= __get_user(to->si_status, &from->si_status);
+		      default:
+			err |= __get_user(to->si_pid, &from->si_pid);
+			err |= __get_user(to->si_uid, &from->si_uid);
+			break;
+		      case __SI_FAULT >> 16:
+			err |= __get_user(tmp, &from->si_addr);
+			to->si_addr = (void *) tmp;
+			break;
+		      case __SI_POLL >> 16:
+			err |= __get_user(to->si_band, &from->si_band);
+			err |= __get_user(to->si_fd, &from->si_fd);
+			break;
+			/* case __SI_RT: This is not generated by the kernel as of now.  */
+		}
+	}
+	return err;
+}
+
+int
 copy_siginfo_to_user32 (siginfo_t32 *to, siginfo_t *from)
 {
 	int err;
 
-	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t32)))
+	if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t32)))
 		return -EFAULT;
 
 	/* If you change siginfo_t structure, please be sure
@@ -97,110 +143,329 @@
 	return err;
 }
 
+static inline void
+sigact_set_handler (struct k_sigaction *sa, unsigned int handler, unsigned int restorer)
+{
+	if (handler + 1 <= 2)
+		/* SIG_DFL, SIG_IGN, or SIG_ERR: must sign-extend to 64-bits */
+		sa->sa.sa_handler = (__sighandler_t) A((int) handler);
+	else
+		sa->sa.sa_handler = (__sighandler_t) (((unsigned long) restorer << 32) | handler);
+}
 
+asmlinkage long
+ia32_rt_sigsuspend (sigset32_t *uset, unsigned int sigsetsize, struct sigscratch *scr)
+{
+	extern long ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall);
+	sigset_t oldset, set;
 
-static int
-setup_sigcontext_ia32(struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate,
-                struct pt_regs *regs, unsigned long mask)
+	scr->scratch_unat = 0;	/* avoid leaking kernel bits to user level */
+	memset(&set, 0, sizeof(&set));
+
+	if (sigsetsize > sizeof(sigset_t))
+		return -EINVAL;
+
+	if (copy_from_user(&set.sig, &uset->sig, sigsetsize))
+		return -EFAULT;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+
+	spin_lock_irq(&current->sigmask_lock);
+	{
+		oldset = current->blocked;
+		current->blocked = set;
+		recalc_sigpending(current);
+	}
+	spin_unlock_irq(&current->sigmask_lock);
+
+	/*
+	 * The return below usually returns to the signal handler.  We need to pre-set the
+	 * correct error code here to ensure that the right values get saved in sigcontext
+	 * by ia64_do_signal.
+	 */
+	scr->pt.r8 = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (ia64_do_signal(&oldset, scr, 1))
+			return -EINTR;
+	}
+}
+
+asmlinkage long
+ia32_sigsuspend (unsigned int mask, struct sigscratch *scr)
+{
+	return ia32_rt_sigsuspend((sigset32_t *)&mask, sizeof(mask), scr);
+}
+
+asmlinkage long
+sys32_signal (int sig, unsigned int handler)
+{
+	struct k_sigaction new_sa, old_sa;
+	int ret;
+
+	sigact_set_handler(&new_sa, handler, 0);
+	new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK;
+
+	ret = do_sigaction(sig, &new_sa, &old_sa);
+
+	return ret ? ret : IA32_SA_HANDLER(&old_sa);
+}
+
+asmlinkage long
+sys32_rt_sigaction (int sig, struct sigaction32 *act,
+		    struct sigaction32 *oact, unsigned int sigsetsize)
+{
+	struct k_sigaction new_ka, old_ka;
+	unsigned int handler, restorer;
+	int ret;
+
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
+	if (sigsetsize != sizeof(sigset32_t))
+		return -EINVAL;
+
+	if (act) {
+		ret = get_user(handler, &act->sa_handler);
+		ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags);
+		ret |= get_user(restorer, &act->sa_restorer);
+		ret |= copy_from_user(&new_ka.sa.sa_mask, &act->sa_mask, sizeof(sigset32_t));
+		if (ret)
+			return -EFAULT;
+
+		sigact_set_handler(&new_ka, handler, restorer);
+	}
+
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) {
+		ret = put_user(IA32_SA_HANDLER(&old_ka), &oact->sa_handler);
+		ret |= put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+		ret |= put_user(IA32_SA_RESTORER(&old_ka), &oact->sa_restorer);
+		ret |= copy_to_user(&oact->sa_mask, &old_ka.sa.sa_mask, sizeof(sigset32_t));
+	}
+	return ret;
+}
+
+
+extern asmlinkage long sys_rt_sigprocmask (int how, sigset_t *set, sigset_t *oset,
+					   size_t sigsetsize);
+
+asmlinkage long
+sys32_rt_sigprocmask (int how, sigset32_t *set, sigset32_t *oset, unsigned int sigsetsize)
+{
+	mm_segment_t old_fs = get_fs();
+	sigset_t s;
+	long ret;
+
+	if (sigsetsize > sizeof(s))
+		return -EINVAL;
+
+	if (set) {
+		memset(&s, 0, sizeof(s));
+		if (copy_from_user(&s.sig, set, sigsetsize))
+			return -EFAULT;
+	}
+	set_fs(KERNEL_DS);
+	ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL, sizeof(s));
+	set_fs(old_fs);
+	if (ret)
+		return ret;
+	if (oset) {
+		if (copy_to_user(oset, &s.sig, sigsetsize))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+asmlinkage long
+sys32_sigprocmask (int how, unsigned int *set, unsigned int *oset)
 {
-       int  err = 0;
-       unsigned long flag;
+	return sys32_rt_sigprocmask(how, (sigset32_t *) set, (sigset32_t *) oset, sizeof(*set));
+}
 
-       err |= __put_user((regs->r16 >> 32) & 0xffff , (unsigned int *)&sc->fs);
-       err |= __put_user((regs->r16 >> 48) & 0xffff , (unsigned int *)&sc->gs);
+asmlinkage long
+sys32_rt_sigtimedwait (sigset32_t *uthese, siginfo_t32 *uinfo, struct timespec32 *uts,
+		       unsigned int sigsetsize)
+{
+	extern asmlinkage long sys_rt_sigtimedwait (const sigset_t *, siginfo_t *,
+						    const struct timespec *, size_t);
+	extern int copy_siginfo_to_user32 (siginfo_t32 *, siginfo_t *);
+	mm_segment_t old_fs = get_fs();
+	struct timespec t;
+	siginfo_t info;
+	sigset_t s;
+	int ret;
 
-       err |= __put_user((regs->r16 >> 56) & 0xffff, (unsigned int *)&sc->es);
-       err |= __put_user(regs->r16 & 0xffff, (unsigned int *)&sc->ds);
-       err |= __put_user(regs->r15, &sc->edi);
-       err |= __put_user(regs->r14, &sc->esi);
-       err |= __put_user(regs->r13, &sc->ebp);
-       err |= __put_user(regs->r12, &sc->esp);
-       err |= __put_user(regs->r11, &sc->ebx);
-       err |= __put_user(regs->r10, &sc->edx);
-       err |= __put_user(regs->r9, &sc->ecx);
-       err |= __put_user(regs->r8, &sc->eax);
+	if (copy_from_user(&s.sig, uthese, sizeof(sigset32_t)))
+		return -EFAULT;
+	if (uts) {
+		ret = get_user(t.tv_sec, &uts->tv_sec);
+		ret |= get_user(t.tv_nsec, &uts->tv_nsec);
+		if (ret)
+			return -EFAULT;
+	}
+	set_fs(KERNEL_DS);
+	ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize);
+	set_fs(old_fs);
+	if (ret >= 0 && uinfo) {
+		if (copy_siginfo_to_user32(uinfo, &info))
+			return -EFAULT;
+	}
+	return ret;
+}
+
+asmlinkage long
+sys32_rt_sigqueueinfo (int pid, int sig, siginfo_t32 *uinfo)
+{
+	extern asmlinkage long sys_rt_sigqueueinfo (int, int, siginfo_t *);
+	extern int copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 *from);
+	mm_segment_t old_fs = get_fs();
+	siginfo_t info;
+	int ret;
+
+	if (copy_siginfo_from_user32(&info, uinfo))
+		return -EFAULT;
+	set_fs(KERNEL_DS);
+	ret = sys_rt_sigqueueinfo(pid, sig, &info);
+	set_fs(old_fs);
+	return ret;
+}
+
+asmlinkage long
+sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact)
+{
+	struct k_sigaction new_ka, old_ka;
+	unsigned int handler, restorer;
+	int ret;
+
+	if (act) {
+		old_sigset32_t mask;
+
+		ret = get_user(handler, &act->sa_handler);
+		ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags);
+		ret |= get_user(restorer, &act->sa_restorer);
+		ret |= get_user(mask, &act->sa_mask);
+		if (ret)
+			return ret;
+
+		sigact_set_handler(&new_ka, handler, restorer);
+		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(IA32_SA_HANDLER(&old_ka), &oact->sa_handler);
+		ret |= put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+		ret |= put_user(IA32_SA_RESTORER(&old_ka), &oact->sa_restorer);
+		ret |= put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+	}
+
+	return ret;
+}
+
+static int
+setup_sigcontext_ia32 (struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate,
+		       struct pt_regs *regs, unsigned long mask)
+{
+	int  err = 0;
+	unsigned long flag;
+
+	err |= __put_user((regs->r16 >> 32) & 0xffff, (unsigned int *)&sc->fs);
+	err |= __put_user((regs->r16 >> 48) & 0xffff, (unsigned int *)&sc->gs);
+	err |= __put_user((regs->r16 >> 16) & 0xffff, (unsigned int *)&sc->es);
+	err |= __put_user(regs->r16 & 0xffff, (unsigned int *)&sc->ds);
+	err |= __put_user(regs->r15, &sc->edi);
+	err |= __put_user(regs->r14, &sc->esi);
+	err |= __put_user(regs->r13, &sc->ebp);
+	err |= __put_user(regs->r12, &sc->esp);
+	err |= __put_user(regs->r11, &sc->ebx);
+	err |= __put_user(regs->r10, &sc->edx);
+	err |= __put_user(regs->r9, &sc->ecx);
+	err |= __put_user(regs->r8, &sc->eax);
 #if 0
-       err |= __put_user(current->tss.trap_no, &sc->trapno);
-       err |= __put_user(current->tss.error_code, &sc->err);
+	err |= __put_user(current->tss.trap_no, &sc->trapno);
+	err |= __put_user(current->tss.error_code, &sc->err);
 #endif
-       err |= __put_user(regs->cr_iip, &sc->eip);
-       err |= __put_user(regs->r17 & 0xffff, (unsigned int *)&sc->cs);
-       /*
-	*  `eflags' is in an ar register for this context
-	*/
-       asm volatile ("mov %0=ar.eflag ;;" : "=r"(flag));
-       err |= __put_user((unsigned int)flag, &sc->eflags);
-       
-       err |= __put_user(regs->r12, &sc->esp_at_signal);
-       err |= __put_user((regs->r17 >> 16) & 0xffff, (unsigned int *)&sc->ss);
+	err |= __put_user(regs->cr_iip, &sc->eip);
+	err |= __put_user(regs->r17 & 0xffff, (unsigned int *)&sc->cs);
+	/*
+	 *  `eflags' is in an ar register for this context
+	 */
+	asm volatile ("mov %0=ar.eflag ;;" : "=r"(flag));
+	err |= __put_user((unsigned int)flag, &sc->eflags);
+	err |= __put_user(regs->r12, &sc->esp_at_signal);
+	err |= __put_user((regs->r17 >> 16) & 0xffff, (unsigned int *)&sc->ss);
 
 #if 0
-       tmp = save_i387(fpstate);
-       if (tmp < 0)
-         err = 1;
-       else
-         err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate);
+	tmp = save_i387(fpstate);
+	if (tmp < 0)
+		err = 1;
+	else
+		err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate);
 
-       /* non-iBCS2 extensions.. */
+	/* non-iBCS2 extensions.. */
 #endif
-       err |= __put_user(mask, &sc->oldmask);
+	err |= __put_user(mask, &sc->oldmask);
 #if 0
-       err |= __put_user(current->tss.cr2, &sc->cr2);
+	err |= __put_user(current->tss.cr2, &sc->cr2);
 #endif
-       
-       return err;
+	return err;
 }
 
 static int
-restore_sigcontext_ia32(struct pt_regs *regs, struct sigcontext_ia32 *sc, int *peax)
+restore_sigcontext_ia32 (struct pt_regs *regs, struct sigcontext_ia32 *sc, int *peax)
 {
-       unsigned int err = 0;
+	unsigned int err = 0;
+
+#define COPY(ia64x, ia32x)	err |= __get_user(regs->ia64x, &sc->ia32x)
 
-#define COPY(ia64x, ia32x)             err |= __get_user(regs->ia64x, &sc->ia32x)
+#define copyseg_gs(tmp)		(regs->r16 |= (unsigned long) tmp << 48)
+#define copyseg_fs(tmp)		(regs->r16 |= (unsigned long) tmp << 32)
+#define copyseg_cs(tmp)		(regs->r17 |= tmp)
+#define copyseg_ss(tmp)		(regs->r17 |= (unsigned long) tmp << 16)
+#define copyseg_es(tmp)		(regs->r16 |= (unsigned long) tmp << 16)
+#define copyseg_ds(tmp)		(regs->r16 |= tmp)
+
+#define COPY_SEG(seg)					\
+	{						\
+		unsigned short tmp;			\
+		err |= __get_user(tmp, &sc->seg);	\
+		copyseg_##seg(tmp);			\
+	}
+#define COPY_SEG_STRICT(seg)				\
+	{						\
+		unsigned short tmp;			\
+		err |= __get_user(tmp, &sc->seg);	\
+		copyseg_##seg(tmp|3);			\
+	}
 
-#define copyseg_gs(tmp)        (regs->r16 |= (unsigned long) tmp << 48)
-#define copyseg_fs(tmp)        (regs->r16 |= (unsigned long) tmp << 32)
-#define copyseg_cs(tmp)        (regs->r17 |= tmp)
-#define copyseg_ss(tmp)        (regs->r17 |= (unsigned long) tmp << 16)
-#define copyseg_es(tmp)        (regs->r16 |= (unsigned long) tmp << 16)
-#define copyseg_ds(tmp)        (regs->r16 |= tmp)
-
-#define COPY_SEG(seg)                                          \
-       { unsigned short tmp;                                   \
-         err |= __get_user(tmp, &sc->seg);                             \
-         copyseg_##seg(tmp); }
-
-#define COPY_SEG_STRICT(seg)                                   \
-       { unsigned short tmp;                                   \
-         err |= __get_user(tmp, &sc->seg);                             \
-         copyseg_##seg(tmp|3); }
-
-       /* To make COPY_SEGs easier, we zero r16, r17 */
-       regs->r16 = 0;
-       regs->r17 = 0;
-
-       COPY_SEG(gs);
-       COPY_SEG(fs);
-       COPY_SEG(es);
-       COPY_SEG(ds);
-       COPY(r15, edi);
-       COPY(r14, esi);
-       COPY(r13, ebp);
-       COPY(r12, esp);
-       COPY(r11, ebx);
-       COPY(r10, edx);
-       COPY(r9, ecx);
-       COPY(cr_iip, eip);
-       COPY_SEG_STRICT(cs);
-       COPY_SEG_STRICT(ss);
-       {
+	/* To make COPY_SEGs easier, we zero r16, r17 */
+	regs->r16 = 0;
+	regs->r17 = 0;
+
+	COPY_SEG(gs);
+	COPY_SEG(fs);
+	COPY_SEG(es);
+	COPY_SEG(ds);
+	COPY(r15, edi);
+	COPY(r14, esi);
+	COPY(r13, ebp);
+	COPY(r12, esp);
+	COPY(r11, ebx);
+	COPY(r10, edx);
+	COPY(r9, ecx);
+	COPY(cr_iip, eip);
+	COPY_SEG_STRICT(cs);
+	COPY_SEG_STRICT(ss);
+	ia32_load_segment_descriptors(current);
+	{
 		unsigned int tmpflags;
 		unsigned long flag;
 
 		/*
-		 *  IA32 `eflags' is not part of `pt_regs', it's
-		 *  in an ar register which is part of the thread
-		 *  context.  Fortunately, we are executing in the
+		 *  IA32 `eflags' is not part of `pt_regs', it's in an ar register which
+		 *  is part of the thread context.  Fortunately, we are executing in the
 		 *  IA32 process's context.
 		 */
 		err |= __get_user(tmpflags, &sc->eflags);
@@ -210,186 +475,191 @@
 		asm volatile ("mov ar.eflag=%0 ;;" :: "r"(flag));
 
 		regs->r1 = -1;	/* disable syscall checks, r1 is orig_eax */
-       }
+	}
 
 #if 0
-       {
-               struct _fpstate * buf;
-               err |= __get_user(buf, &sc->fpstate);
-               if (buf) {
-                       if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
-                               goto badframe;
-                       err |= restore_i387(buf);
-               }
-       }
+	{
+		struct _fpstate * buf;
+		err |= __get_user(buf, &sc->fpstate);
+		if (buf) {
+			if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
+				goto badframe;
+			err |= restore_i387(buf);
+		}
+	}
 #endif
 
-       err |= __get_user(*peax, &sc->eax);
-       return err;
+	err |= __get_user(*peax, &sc->eax);
+	return err;
 
-#if 0       
-badframe:
-       return 1;
+#if 0
+  badframe:
+	return 1;
 #endif
-
 }
 
 /*
  * Determine which stack to use..
  */
 static inline void *
-get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
+get_sigframe (struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
 {
-       unsigned long esp;
-       unsigned int xss;
+	unsigned long esp;
 
-       /* Default to using normal stack */
-       esp = regs->r12;
-       xss = regs->r16 >> 16;
-
-       /* This is the X/Open sanctioned signal stack switching.  */
-       if (ka->sa.sa_flags & SA_ONSTACK) {
-               if (! on_sig_stack(esp))
-                       esp = current->sas_ss_sp + current->sas_ss_size;
-       }
-       /* Legacy stack switching not supported */
-       
-       return (void *)((esp - frame_size) & -8ul);
+	/* Default to using normal stack (truncate off sign-extension of bit 31: */
+	esp = (unsigned int) regs->r12;
+
+	/* This is the X/Open sanctioned signal stack switching.  */
+	if (ka->sa.sa_flags & SA_ONSTACK) {
+		if (!on_sig_stack(esp))
+			esp = current->sas_ss_sp + current->sas_ss_size;
+	}
+	/* Legacy stack switching not supported */
+
+	return (void *)((esp - frame_size) & -8ul);
 }
 
 static int
-setup_frame_ia32(int sig, struct k_sigaction *ka, sigset_t *set,
-           struct pt_regs * regs) 
-{      
-       struct sigframe_ia32 *frame;
-       int err = 0;
-
-       frame = get_sigframe(ka, regs, sizeof(*frame));
-
-       if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-               goto give_sigsegv;
-
-       err |= __put_user((current->exec_domain
-                          && current->exec_domain->signal_invmap
-                          && sig < 32
-                          ? (int)(current->exec_domain->signal_invmap[sig])
-                          : sig),
-                         &frame->sig);
-
-       err |= setup_sigcontext_ia32(&frame->sc, &frame->fpstate, regs, set->sig[0]);
-
-       if (_IA32_NSIG_WORDS > 1) {
-               err |= __copy_to_user(frame->extramask, &set->sig[1],
-                                     sizeof(frame->extramask));
-       }
-
-       /* Set up to return from userspace.  If provided, use a stub
-          already in userspace.  */
-       err |= __put_user((long)frame->retcode, &frame->pretcode);
-       /* This is popl %eax ; movl $,%eax ; int $0x80 */
-       err |= __put_user(0xb858, (short *)(frame->retcode+0));
-#define __IA32_NR_sigreturn            119
-       err |= __put_user(__IA32_NR_sigreturn & 0xffff, (short *)(frame->retcode+2));
-       err |= __put_user(__IA32_NR_sigreturn >> 16, (short *)(frame->retcode+4));
-       err |= __put_user(0x80cd, (short *)(frame->retcode+6));
-
-       if (err)
-               goto give_sigsegv;
-
-       /* Set up registers for signal handler */
-       regs->r12 = (unsigned long) frame;
-       regs->cr_iip = (unsigned long) ka->sa.sa_handler;
-
-       set_fs(USER_DS);
-       regs->r16 = (__USER_DS << 16) |  (__USER_DS); /* ES = DS, GS, FS are zero */
-       regs->r17 = (__USER_DS << 16) | __USER_CS;
+setup_frame_ia32 (int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs)
+{
+	struct sigframe_ia32 *frame;
+	int err = 0;
+
+	frame = get_sigframe(ka, regs, sizeof(*frame));
+
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+		goto give_sigsegv;
+
+	err |= __put_user((current->exec_domain
+			   && current->exec_domain->signal_invmap
+			   && sig < 32
+			   ? (int)(current->exec_domain->signal_invmap[sig])
+			   : sig),
+			  &frame->sig);
+
+	err |= setup_sigcontext_ia32(&frame->sc, &frame->fpstate, regs, set->sig[0]);
+
+	if (_IA32_NSIG_WORDS > 1)
+		err |= __copy_to_user(frame->extramask, (char *) &set->sig + 4,
+				      sizeof(frame->extramask));
+
+	/* Set up to return from userspace.  If provided, use a stub
+	   already in userspace.  */
+	if (ka->sa.sa_flags & SA_RESTORER) {
+		unsigned int restorer = IA32_SA_RESTORER(ka);
+		err |= __put_user(restorer, &frame->pretcode);
+	} else {
+		err |= __put_user((long)frame->retcode, &frame->pretcode);
+		/* This is popl %eax ; movl $,%eax ; int $0x80 */
+		err |= __put_user(0xb858, (short *)(frame->retcode+0));
+		err |= __put_user(__IA32_NR_sigreturn & 0xffff, (short *)(frame->retcode+2));
+		err |= __put_user(__IA32_NR_sigreturn >> 16, (short *)(frame->retcode+4));
+		err |= __put_user(0x80cd, (short *)(frame->retcode+6));
+	}
+
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up registers for signal handler */
+	regs->r12 = (unsigned long) frame;
+	regs->cr_iip = IA32_SA_HANDLER(ka);
+
+	set_fs(USER_DS);
+	regs->r16 = (__USER_DS << 16) |  (__USER_DS); /* ES = DS, GS, FS are zero */
+	regs->r17 = (__USER_DS << 16) | __USER_CS;
 
 #if 0
-       regs->eflags &= ~TF_MASK;
+	regs->eflags &= ~TF_MASK;
 #endif
 
 #if 0
-       printk("SIG deliver (%s:%d): sig=%d sp=%p pc=%lx ra=%x\n",
+	printk("SIG deliver (%s:%d): sig=%d sp=%p pc=%lx ra=%x\n",
                current->comm, current->pid, sig, (void *) frame, regs->cr_iip, frame->pretcode);
 #endif
 
-       return 1;
+	return 1;
 
-give_sigsegv:
-       if (sig = SIGSEGV)
-               ka->sa.sa_handler = SIG_DFL;
-       force_sig(SIGSEGV, current);
-       return 0;
+  give_sigsegv:
+	if (sig = SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
+	return 0;
 }
 
 static int
-setup_rt_frame_ia32(int sig, struct k_sigaction *ka, siginfo_t *info,
-              sigset_t *set, struct pt_regs * regs)
+setup_rt_frame_ia32 (int sig, struct k_sigaction *ka, siginfo_t *info,
+		     sigset_t *set, struct pt_regs * regs)
 {
-       struct rt_sigframe_ia32 *frame;
-       int err = 0;
+	struct rt_sigframe_ia32 *frame;
+	int err = 0;
 
-       frame = get_sigframe(ka, regs, sizeof(*frame));
+	frame = get_sigframe(ka, regs, sizeof(*frame));
 
-       if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-               goto give_sigsegv;
-
-       err |= __put_user((current->exec_domain
-                          && current->exec_domain->signal_invmap
-                          && sig < 32
-                          ? current->exec_domain->signal_invmap[sig]
-                          : sig),
-                         &frame->sig);
-       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.  */
-       err |= __put_user(0, &frame->uc.uc_flags);
-       err |= __put_user(0, &frame->uc.uc_link);
-       err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
-       err |= __put_user(sas_ss_flags(regs->r12),
-                         &frame->uc.uc_stack.ss_flags);
-       err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-       err |= setup_sigcontext_ia32(&frame->uc.uc_mcontext, &frame->fpstate,
-                               regs, set->sig[0]);
-       err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
-       
-       err |= __put_user((long)frame->retcode, &frame->pretcode);
-       /* This is movl $,%eax ; int $0x80 */
-       err |= __put_user(0xb8, (char *)(frame->retcode+0));
-#define __IA32_NR_rt_sigreturn         173
-       err |= __put_user(__IA32_NR_rt_sigreturn, (int *)(frame->retcode+1));
-       err |= __put_user(0x80cd, (short *)(frame->retcode+5));
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+		goto give_sigsegv;
+
+	err |= __put_user((current->exec_domain
+			   && current->exec_domain->signal_invmap
+			   && sig < 32
+			   ? current->exec_domain->signal_invmap[sig]
+			   : sig),
+			  &frame->sig);
+	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.  */
+	err |= __put_user(0, &frame->uc.uc_flags);
+	err |= __put_user(0, &frame->uc.uc_link);
+	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+	err |= __put_user(sas_ss_flags(regs->r12), &frame->uc.uc_stack.ss_flags);
+	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+	err |= setup_sigcontext_ia32(&frame->uc.uc_mcontext, &frame->fpstate, regs, set->sig[0]);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up to return from userspace.  If provided, use a stub
+	   already in userspace.  */
+	if (ka->sa.sa_flags & SA_RESTORER) {
+		unsigned int restorer = IA32_SA_RESTORER(ka);
+		err |= __put_user(restorer, &frame->pretcode);
+	} else {
+		err |= __put_user((long)frame->retcode, &frame->pretcode);
+		/* This is movl $,%eax ; int $0x80 */
+		err |= __put_user(0xb8, (char *)(frame->retcode+0));
+		err |= __put_user(__IA32_NR_rt_sigreturn, (int *)(frame->retcode+1));
+		err |= __put_user(0x80cd, (short *)(frame->retcode+5));
+	}
 
-       if (err)
-               goto give_sigsegv;
+	if (err)
+		goto give_sigsegv;
 
-       /* Set up registers for signal handler */
-       regs->r12 = (unsigned long) frame;
-       regs->cr_iip = (unsigned long) ka->sa.sa_handler;
+	/* Set up registers for signal handler */
+	regs->r12 = (unsigned long) frame;
+	regs->cr_iip = IA32_SA_HANDLER(ka);
 
-       set_fs(USER_DS);
+	set_fs(USER_DS);
 
-       regs->r16 = (__USER_DS << 16) |  (__USER_DS); /* ES = DS, GS, FS are zero */
-       regs->r17 = (__USER_DS << 16) | __USER_CS;
+	regs->r16 = (__USER_DS << 16) |  (__USER_DS); /* ES = DS, GS, FS are zero */
+	regs->r17 = (__USER_DS << 16) | __USER_CS;
 
 #if 0
-       regs->eflags &= ~TF_MASK;
+	regs->eflags &= ~TF_MASK;
 #endif
 
 #if 0
-       printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%x\n",
+	printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%x\n",
                current->comm, current->pid, (void *) frame, regs->cr_iip, frame->pretcode);
 #endif
 
-       return 1;
+	return 1;
 
 give_sigsegv:
-       if (sig = SIGSEGV)
-               ka->sa.sa_handler = SIG_DFL;
-       force_sig(SIGSEGV, current);
-       return 0;
+	if (sig = SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
+	return 0;
 }
 
 int
@@ -398,95 +668,78 @@
 {
        /* Set up the stack frame */
        if (ka->sa.sa_flags & SA_SIGINFO)
-               return(setup_rt_frame_ia32(sig, ka, info, set, regs));
+               return setup_rt_frame_ia32(sig, ka, info, set, regs);
        else
-               return(setup_frame_ia32(sig, ka, set, regs));
+               return setup_frame_ia32(sig, ka, set, regs);
 }
 
-asmlinkage int
-sys32_sigreturn(
-int arg0,
-int arg1,
-int arg2,
-int arg3,
-int arg4,
-int arg5,
-int arg6,
-int arg7,
-unsigned long stack)
-{
-       struct pt_regs *regs = (struct pt_regs *) &stack;
-       struct sigframe_ia32 *frame = (struct sigframe_ia32 *)(regs->r12- 8);
-       sigset_t set;
-       int eax;
-
-       if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
-               goto badframe;
-
-       if (__get_user(set.sig[0], &frame->sc.oldmask)
-           || (_IA32_NSIG_WORDS > 1
-               && __copy_from_user((((char *) &set.sig) + 4),
-                                   &frame->extramask,
-                                   sizeof(frame->extramask))))
-               goto badframe;
-
-       sigdelsetmask(&set, ~_BLOCKABLE);
-       spin_lock_irq(&current->sigmask_lock);
-       current->blocked = (sigset_t) set;
-       recalc_sigpending(current);
-       spin_unlock_irq(&current->sigmask_lock);
-       
-       if (restore_sigcontext_ia32(regs, &frame->sc, &eax))
-               goto badframe;
-       return eax;
-
-badframe:
-       force_sig(SIGSEGV, current);
-       return 0;
-}      
-
-asmlinkage int
-sys32_rt_sigreturn(
-int arg0,
-int arg1,
-int arg2,
-int arg3,
-int arg4,
-int arg5,
-int arg6,
-int arg7,
-unsigned long stack)
-{
-       struct pt_regs *regs = (struct pt_regs *) &stack;
-       struct rt_sigframe_ia32 *frame = (struct rt_sigframe_ia32 *)(regs->r12 - 4);
-       sigset_t set;
-       stack_t st;
-       int eax;
-
-       if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
-               goto badframe;
-       if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
-               goto badframe;
-
-       sigdelsetmask(&set, ~_BLOCKABLE);
-       spin_lock_irq(&current->sigmask_lock);
-       current->blocked =  set;
-       recalc_sigpending(current);
-       spin_unlock_irq(&current->sigmask_lock);
-       
-       if (restore_sigcontext_ia32(regs, &frame->uc.uc_mcontext, &eax))
-               goto badframe;
-
-       if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
-               goto badframe;
-       /* It is more difficult to avoid calling this function than to
-          call it and ignore errors.  */
-       do_sigaltstack(&st, NULL, regs->r12);
-
-       return eax;
-
-badframe:
-       force_sig(SIGSEGV, current);
-       return 0;
-}      
+asmlinkage long
+sys32_sigreturn (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7,
+		 unsigned long stack)
+{
+	struct pt_regs *regs = (struct pt_regs *) &stack;
+	unsigned long esp = (unsigned int) regs->r12;
+	struct sigframe_ia32 *frame = (struct sigframe_ia32 *)(esp - 8);
+	sigset_t set;
+	int eax;
+
+	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+
+	if (__get_user(set.sig[0], &frame->sc.oldmask)
+	    || (_IA32_NSIG_WORDS > 1 && __copy_from_user((char *) &set.sig + 4, &frame->extramask,
+							 sizeof(frame->extramask))))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sigmask_lock);
+	current->blocked = (sigset_t) set;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	if (restore_sigcontext_ia32(regs, &frame->sc, &eax))
+		goto badframe;
+	return eax;
+
+  badframe:
+	force_sig(SIGSEGV, current);
+	return 0;
+}
 
+asmlinkage long
+sys32_rt_sigreturn (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7,
+		    unsigned long stack)
+{
+	struct pt_regs *regs = (struct pt_regs *) &stack;
+	unsigned long esp = (unsigned int) regs->r12;
+	struct rt_sigframe_ia32 *frame = (struct rt_sigframe_ia32 *)(esp - 4);
+	sigset_t set;
+	stack_t st;
+	int eax;
+
+	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sigmask_lock);
+	current->blocked =  set;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	if (restore_sigcontext_ia32(regs, &frame->uc.uc_mcontext, &eax))
+		goto badframe;
+
+	if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
+		goto badframe;
+	/* It is more difficult to avoid calling this function than to
+	   call it and ignore errors.  */
+	do_sigaltstack(&st, NULL, esp);
+
+	return eax;
+
+  badframe:
+	force_sig(SIGSEGV, current);
+	return 0;
+}
diff -urN linux-2.4.13/arch/ia64/ia32/ia32_support.c linux-2.4.13-lia/arch/ia64/ia32/ia32_support.c
--- linux-2.4.13/arch/ia64/ia32/ia32_support.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/ia32/ia32_support.c	Wed Oct 10 17:39:02 2001
@@ -4,15 +4,18 @@
  * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
  * Copyright (C) 2000 Asit K. Mallick <asit.k.mallick@intel.com>
  * Copyright (C) 2001 Hewlett-Packard Co
- * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * 06/16/00	A. Mallick	added csd/ssd/tssd for ia32 thread context
  * 02/19/01	D. Mosberger	dropped tssd; it's not needed
+ * 09/14/01	D. Mosberger	fixed memory management for gdt/tss page
+ * 09/29/01	D. Mosberger	added ia32_load_segment_descriptors()
  */
 
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/mm.h>
+#include <linux/personality.h>
 #include <linux/sched.h>
 
 #include <asm/page.h>
@@ -21,10 +24,46 @@
 #include <asm/processor.h>
 #include <asm/ia32.h>
 
-extern unsigned long *ia32_gdt_table, *ia32_tss;
-
 extern void die_if_kernel (char *str, struct pt_regs *regs, long err);
 
+struct exec_domain ia32_exec_domain;
+struct page *ia32_shared_page[(2*IA32_PAGE_SIZE + PAGE_SIZE - 1)/PAGE_SIZE];
+unsigned long *ia32_gdt;
+
+static unsigned long
+load_desc (u16 selector)
+{
+	unsigned long *table, limit, index;
+
+	if (!selector)
+		return 0;
+	if (selector & IA32_SEGSEL_TI) {
+		table = (unsigned long *) IA32_LDT_OFFSET;
+		limit = IA32_LDT_ENTRIES;
+	} else {
+		table = ia32_gdt;
+		limit = IA32_PAGE_SIZE / sizeof(ia32_gdt[0]);
+	}
+	index = selector >> IA32_SEGSEL_INDEX_SHIFT;
+	if (index >= limit)
+		return 0;
+	return IA32_SEG_UNSCRAMBLE(table[index]);
+}
+
+void
+ia32_load_segment_descriptors (struct task_struct *task)
+{
+	struct pt_regs *regs = ia64_task_regs(task);
+
+	/* Setup the segment descriptors */
+	regs->r24 = load_desc(regs->r16 >> 16);		/* ESD */
+	regs->r27 = load_desc(regs->r16 >>  0);		/* DSD */
+	regs->r28 = load_desc(regs->r16 >> 32);		/* FSD */
+	regs->r29 = load_desc(regs->r16 >> 48);		/* GSD */
+	task->thread.csd = load_desc(regs->r17 >>  0);	/* CSD */
+	task->thread.ssd = load_desc(regs->r17 >> 16);	/* SSD */
+}
+
 void
 ia32_save_state (struct task_struct *t)
 {
@@ -46,14 +85,17 @@
 	t->thread.csd = csd;
 	t->thread.ssd = ssd;
 	ia64_set_kr(IA64_KR_IO_BASE, t->thread.old_iob);
+	ia64_set_kr(IA64_KR_TSSD, t->thread.old_k1);
 }
 
 void
 ia32_load_state (struct task_struct *t)
 {
-	unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd;
+	unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd, tssd;
 	struct pt_regs *regs = ia64_task_regs(t);
-	int nr;
+	int nr = smp_processor_id();	/* LDT and TSS depend on CPU number: */
+
+	nr = smp_processor_id();
 
 	eflag = t->thread.eflag;
 	fsr = t->thread.fsr;
@@ -62,6 +104,7 @@
 	fdr = t->thread.fdr;
 	csd = t->thread.csd;
 	ssd = t->thread.ssd;
+	tssd = load_desc(_TSS(nr));					/* TSSD */
 
 	asm volatile ("mov ar.eflag=%0;"
 		      "mov ar.fsr=%1;"
@@ -72,11 +115,12 @@
 		      "mov ar.ssd=%6;"
 		      :: "r"(eflag), "r"(fsr), "r"(fcr), "r"(fir), "r"(fdr), "r"(csd), "r"(ssd));
 	current->thread.old_iob = ia64_get_kr(IA64_KR_IO_BASE);
+	current->thread.old_k1 = ia64_get_kr(IA64_KR_TSSD);
 	ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE);
+	ia64_set_kr(IA64_KR_TSSD, tssd);
 
-	/* load TSS and LDT while preserving SS and CS: */
-	nr = smp_processor_id();
 	regs->r17 = (_TSS(nr) << 48) | (_LDT(nr) << 32) | (__u32) regs->r17;
+	regs->r30 = load_desc(_LDT(nr));				/* LDTD */
 }
 
 /*
@@ -85,36 +129,34 @@
 void
 ia32_gdt_init (void)
 {
-	unsigned long gdt_and_tss_page, ldt_size;
+	unsigned long *tss;
+	unsigned long ldt_size;
 	int nr;
 
-	/* allocate two IA-32 pages of memory: */
-	gdt_and_tss_page = __get_free_pages(GFP_KERNEL,
-					    (IA32_PAGE_SHIFT < PAGE_SHIFT)
-					    ? 0 : (IA32_PAGE_SHIFT + 1) - PAGE_SHIFT);
-	ia32_gdt_table = (unsigned long *) gdt_and_tss_page;
-	ia32_tss = (unsigned long *) (gdt_and_tss_page + IA32_PAGE_SIZE);
-
-	/* Zero the gdt and tss */
-	memset((void *) gdt_and_tss_page, 0, 2*IA32_PAGE_SIZE);
+	ia32_shared_page[0] = alloc_page(GFP_KERNEL);
+	ia32_gdt = page_address(ia32_shared_page[0]);
+	tss = ia32_gdt + IA32_PAGE_SIZE/sizeof(ia32_gdt[0]);
+
+	if (IA32_PAGE_SIZE = PAGE_SIZE) {
+		ia32_shared_page[1] = alloc_page(GFP_KERNEL);
+		tss = page_address(ia32_shared_page[1]);
+	}
 
 	/* CS descriptor in IA-32 (scrambled) format */
-	ia32_gdt_table[__USER_CS >> 3] -		IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET - 1) >> IA32_PAGE_SHIFT,
-				    0xb, 1, 3, 1, 1, 1, 1);
+	ia32_gdt[__USER_CS >> 3] = IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET-1) >> IA32_PAGE_SHIFT,
+						       0xb, 1, 3, 1, 1, 1, 1);
 
 	/* DS descriptor in IA-32 (scrambled) format */
-	ia32_gdt_table[__USER_DS >> 3] -		IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET - 1) >> IA32_PAGE_SHIFT,
-				    0x3, 1, 3, 1, 1, 1, 1);
+	ia32_gdt[__USER_DS >> 3] = IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET-1) >> IA32_PAGE_SHIFT,
+						       0x3, 1, 3, 1, 1, 1, 1);
 
 	/* We never change the TSS and LDT descriptors, so we can share them across all CPUs.  */
 	ldt_size = PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE);
 	for (nr = 0; nr < NR_CPUS; ++nr) {
-		ia32_gdt_table[_TSS(nr)] = IA32_SEG_DESCRIPTOR(IA32_TSS_OFFSET, 235,
-							       0xb, 0, 3, 1, 1, 1, 0);
-		ia32_gdt_table[_LDT(nr)] = IA32_SEG_DESCRIPTOR(IA32_LDT_OFFSET, ldt_size - 1,
-							       0x2, 0, 3, 1, 1, 1, 0);
+		ia32_gdt[_TSS(nr)] = IA32_SEG_DESCRIPTOR(IA32_TSS_OFFSET, 235,
+							 0xb, 0, 3, 1, 1, 1, 0);
+		ia32_gdt[_LDT(nr)] = IA32_SEG_DESCRIPTOR(IA32_LDT_OFFSET, ldt_size - 1,
+							 0x2, 0, 3, 1, 1, 1, 0);
 	}
 }
 
@@ -133,3 +175,18 @@
 	siginfo.si_code = TRAP_BRKPT;
 	force_sig_info(SIGTRAP, &siginfo, current);
 }
+
+static int __init
+ia32_init (void)
+{
+	ia32_exec_domain.name = "Linux/x86";
+	ia32_exec_domain.handler = NULL;
+	ia32_exec_domain.pers_low = PER_LINUX32;
+	ia32_exec_domain.pers_high = PER_LINUX32;
+	ia32_exec_domain.signal_map = default_exec_domain.signal_map;
+	ia32_exec_domain.signal_invmap = default_exec_domain.signal_invmap;
+	register_exec_domain(&ia32_exec_domain);
+	return 0;
+}
+
+__initcall(ia32_init);
diff -urN linux-2.4.13/arch/ia64/ia32/ia32_traps.c linux-2.4.13-lia/arch/ia64/ia32/ia32_traps.c
--- linux-2.4.13/arch/ia64/ia32/ia32_traps.c	Thu Jan  4 12:50:17 2001
+++ linux-2.4.13-lia/arch/ia64/ia32/ia32_traps.c	Thu Oct  4 00:21:52 2001
@@ -1,7 +1,12 @@
 /*
- * IA32 exceptions handler
+ * IA-32 exception handlers
  *
+ * Copyright (C) 2000 Asit K. Mallick <asit.k.mallick@intel.com>
+ * Copyright (C) 2001 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+/*
  * 06/16/00	A. Mallick	added siginfo for most cases (close to IA32)
+ * 09/29/00	D. Mosberger	added ia32_intercept()
  */
 
 #include <linux/kernel.h>
@@ -9,6 +14,26 @@
 
 #include <asm/ia32.h>
 #include <asm/ptrace.h>
+
+int
+ia32_intercept (struct pt_regs *regs, unsigned long isr)
+{
+	switch ((isr >> 16) & 0xff) {
+	      case 0:	/* Instruction intercept fault */
+	      case 3:	/* Locked Data reference fault */
+	      case 1:	/* Gate intercept trap */
+		return -1;
+
+	      case 2:	/* System flag trap */
+		if (((isr >> 14) & 0x3) >= 2) {
+			/* MOV SS, POP SS instructions */
+			ia64_psr(regs)->id = 1;
+			return 0;
+		} else
+			return -1;
+	}
+	return -1;
+}
 
 int
 ia32_exception (struct pt_regs *regs, unsigned long isr)
diff -urN linux-2.4.13/arch/ia64/ia32/sys_ia32.c linux-2.4.13-lia/arch/ia64/ia32/sys_ia32.c
--- linux-2.4.13/arch/ia64/ia32/sys_ia32.c	Mon Aug 20 10:18:26 2001
+++ linux-2.4.13-lia/arch/ia64/ia32/sys_ia32.c	Wed Oct 10 17:39:17 2001
@@ -1,14 +1,13 @@
 /*
- * sys_ia32.c: Conversion between 32bit and 64bit native syscalls. Based on
- *             sys_sparc32
+ * sys_ia32.c: Conversion between 32bit and 64bit native syscalls. Derived from sys_sparc32.c.
  *
  * Copyright (C) 2000		VA Linux Co
  * Copyright (C) 2000		Don Dugger <n0ano@valinux.com>
  * Copyright (C) 1999		Arun Sharma <arun.sharma@intel.com>
  * Copyright (C) 1997,1998	Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  * Copyright (C) 1997		David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 2000		Hewlett-Packard Co.
- * Copyright (C) 2000		David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 2000-2001 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * These routines maintain argument size conversion between 32bit and 64bit
  * environment.
@@ -53,31 +52,56 @@
 #include <asm/types.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
-#include <asm/ipc.h>
 
 #include <net/scm.h>
 #include <net/sock.h>
 #include <asm/ia32.h>
 
+#define DEBUG	0
+
+#if DEBUG
+# define DBG(fmt...)	printk(KERN_DEBUG fmt)
+#else
+# define DBG(fmt...)
+#endif
+
 #define A(__x)		((unsigned long)(__x))
 #define AA(__x)		((unsigned long)(__x))
 #define ROUND_UP(x,a)	((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1)))
 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
 
+#define OFFSET4K(a)		((a) & 0xfff)
+#define PAGE_START(addr)	((addr) & PAGE_MASK)
+#define PAGE_OFF(addr)		((addr) & ~PAGE_MASK)
+
 extern asmlinkage long sys_execve (char *, char **, char **, struct pt_regs *);
 extern asmlinkage long sys_mprotect (unsigned long, size_t, unsigned long);
+extern asmlinkage long sys_munmap (unsigned long, size_t);
+extern unsigned long arch_get_unmapped_area (struct file *, unsigned long, unsigned long,
+					     unsigned long, unsigned long);
+
+/* forward declaration: */
+asmlinkage long sys32_mprotect (unsigned int, unsigned int, int);
+
+/*
+ * Anything that modifies or inspects ia32 user virtual memory must hold this semaphore
+ * while doing so.
+ */
+/* XXX make per-mm: */
+static DECLARE_MUTEX(ia32_mmap_sem);
 
 static int
 nargs (unsigned int arg, char **ap)
 {
-	int n, err, addr;
+	unsigned int addr;
+	int n, err;
 
 	if (!arg)
 		return 0;
 
 	n = 0;
 	do {
-		err = get_user(addr, (int *)A(arg));
+		err = get_user(addr, (unsigned int *)A(arg));
 		if (err)
 			return err;
 		if (ap)
@@ -94,7 +118,7 @@
 	      int stack)
 {
 	struct pt_regs *regs = (struct pt_regs *)&stack;
-	unsigned long old_map_base, old_task_size;
+	unsigned long old_map_base, old_task_size, tssd;
 	char **av, **ae;
 	int na, ne, len;
 	long r;
@@ -123,15 +147,20 @@
 
 	old_map_base  = current->thread.map_base;
 	old_task_size = current->thread.task_size;
+	tssd = ia64_get_kr(IA64_KR_TSSD);
 
-	/* we may be exec'ing a 64-bit process: reset map base & task-size: */
+	/* we may be exec'ing a 64-bit process: reset map base, task-size, and io-base: */
 	current->thread.map_base  = DEFAULT_MAP_BASE;
 	current->thread.task_size = DEFAULT_TASK_SIZE;
+	ia64_set_kr(IA64_KR_IO_BASE, current->thread.old_iob);
+	ia64_set_kr(IA64_KR_TSSD, current->thread.old_k1);
 
 	set_fs(KERNEL_DS);
 	r = sys_execve(filename, av, ae, regs);
 	if (r < 0) {
-		/* oops, execve failed, switch back to old map base & task-size: */
+		/* oops, execve failed, switch back to old values... */
+		ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE);
+		ia64_set_kr(IA64_KR_TSSD, tssd);
 		current->thread.map_base  = old_map_base;
 		current->thread.task_size = old_task_size;
 		set_fs(USER_DS);	/* establish new task-size as the address-limit */
@@ -142,30 +171,33 @@
 }
 
 static inline int
-putstat(struct stat32 *ubuf, struct stat *kbuf)
+putstat (struct stat32 *ubuf, struct stat *kbuf)
 {
 	int err;
 
-	err = put_user (kbuf->st_dev, &ubuf->st_dev);
-	err |= __put_user (kbuf->st_ino, &ubuf->st_ino);
-	err |= __put_user (kbuf->st_mode, &ubuf->st_mode);
-	err |= __put_user (kbuf->st_nlink, &ubuf->st_nlink);
-	err |= __put_user (kbuf->st_uid, &ubuf->st_uid);
-	err |= __put_user (kbuf->st_gid, &ubuf->st_gid);
-	err |= __put_user (kbuf->st_rdev, &ubuf->st_rdev);
-	err |= __put_user (kbuf->st_size, &ubuf->st_size);
-	err |= __put_user (kbuf->st_atime, &ubuf->st_atime);
-	err |= __put_user (kbuf->st_mtime, &ubuf->st_mtime);
-	err |= __put_user (kbuf->st_ctime, &ubuf->st_ctime);
-	err |= __put_user (kbuf->st_blksize, &ubuf->st_blksize);
-	err |= __put_user (kbuf->st_blocks, &ubuf->st_blocks);
+	if (clear_user(ubuf, sizeof(*ubuf)))
+		return 1;
+
+	err  = __put_user(kbuf->st_dev, &ubuf->st_dev);
+	err |= __put_user(kbuf->st_ino, &ubuf->st_ino);
+	err |= __put_user(kbuf->st_mode, &ubuf->st_mode);
+	err |= __put_user(kbuf->st_nlink, &ubuf->st_nlink);
+	err |= __put_user(kbuf->st_uid, &ubuf->st_uid);
+	err |= __put_user(kbuf->st_gid, &ubuf->st_gid);
+	err |= __put_user(kbuf->st_rdev, &ubuf->st_rdev);
+	err |= __put_user(kbuf->st_size, &ubuf->st_size);
+	err |= __put_user(kbuf->st_atime, &ubuf->st_atime);
+	err |= __put_user(kbuf->st_mtime, &ubuf->st_mtime);
+	err |= __put_user(kbuf->st_ctime, &ubuf->st_ctime);
+	err |= __put_user(kbuf->st_blksize, &ubuf->st_blksize);
+	err |= __put_user(kbuf->st_blocks, &ubuf->st_blocks);
 	return err;
 }
 
-extern asmlinkage long sys_newstat(char * filename, struct stat * statbuf);
+extern asmlinkage long sys_newstat (char * filename, struct stat * statbuf);
 
 asmlinkage long
-sys32_newstat(char * filename, struct stat32 *statbuf)
+sys32_newstat (char *filename, struct stat32 *statbuf)
 {
 	int ret;
 	struct stat s;
@@ -173,8 +205,8 @@
 
 	set_fs(KERNEL_DS);
 	ret = sys_newstat(filename, &s);
-	set_fs (old_fs);
-	if (putstat (statbuf, &s))
+	set_fs(old_fs);
+	if (putstat(statbuf, &s))
 		return -EFAULT;
 	return ret;
 }
@@ -182,16 +214,16 @@
 extern asmlinkage long sys_newlstat(char * filename, struct stat * statbuf);
 
 asmlinkage long
-sys32_newlstat(char * filename, struct stat32 *statbuf)
+sys32_newlstat (char *filename, struct stat32 *statbuf)
 {
-	int ret;
-	struct stat s;
 	mm_segment_t old_fs = get_fs();
+	struct stat s;
+	int ret;
 
-	set_fs (KERNEL_DS);
+	set_fs(KERNEL_DS);
 	ret = sys_newlstat(filename, &s);
-	set_fs (old_fs);
-	if (putstat (statbuf, &s))
+	set_fs(old_fs);
+	if (putstat(statbuf, &s))
 		return -EFAULT;
 	return ret;
 }
@@ -199,112 +231,249 @@
 extern asmlinkage long sys_newfstat(unsigned int fd, struct stat * statbuf);
 
 asmlinkage long
-sys32_newfstat(unsigned int fd, struct stat32 *statbuf)
+sys32_newfstat (unsigned int fd, struct stat32 *statbuf)
 {
-	int ret;
-	struct stat s;
 	mm_segment_t old_fs = get_fs();
+	struct stat s;
+	int ret;
 
-	set_fs (KERNEL_DS);
+	set_fs(KERNEL_DS);
 	ret = sys_newfstat(fd, &s);
-	set_fs (old_fs);
-	if (putstat (statbuf, &s))
+	set_fs(old_fs);
+	if (putstat(statbuf, &s))
 		return -EFAULT;
 	return ret;
 }
 
-#define OFFSET4K(a)	((a) & 0xfff)
+#if PAGE_SHIFT > IA32_PAGE_SHIFT
 
-unsigned long
-do_mmap_fake(struct file *file, unsigned long addr, unsigned long len,
-	unsigned long prot, unsigned long flags, loff_t off)
+
+static int
+get_page_prot (unsigned long addr)
+{
+	struct vm_area_struct *vma = find_vma(current->mm, addr);
+	int prot = 0;
+
+	if (!vma || vma->vm_start > addr)
+		return 0;
+
+	if (vma->vm_flags & VM_READ)
+		prot |= PROT_READ;
+	if (vma->vm_flags & VM_WRITE)
+		prot |= PROT_WRITE;
+	if (vma->vm_flags & VM_EXEC)
+		prot |= PROT_EXEC;
+	return prot;
+}
+
+/*
+ * Map a subpage by creating an anonymous page that contains the union of the old page and
+ * the subpage.
+ */
+static unsigned long
+mmap_subpage (struct file *file, unsigned long start, unsigned long end, int prot, int flags,
+	      loff_t off)
 {
+	void *page = (void *) get_zeroed_page(GFP_KERNEL);
 	struct inode *inode;
-	void *front, *back;
-	unsigned long baddr;
-	int r;
-	char c;
+	unsigned long ret;
+	int old_prot = get_page_prot(start);
 
-	if (OFFSET4K(addr) || OFFSET4K(off))
-		return -EINVAL;
-	prot |= PROT_WRITE;
-	front = NULL;
-	back = NULL;
-	if ((baddr = (addr & PAGE_MASK)) != addr && get_user(c, (char *)baddr) = 0) {
-		front = kmalloc(addr - baddr, GFP_KERNEL);
-		if (!front)
-			return -ENOMEM;
-		__copy_user(front, (void *)baddr, addr - baddr);
+	DBG("mmap_subpage(file=%p,start=0x%lx,end=0x%lx,prot=%x,flags=%x,off=0x%llx)\n",
+	    file, start, end, prot, flags, off);
+
+	if (!page)
+		return -ENOMEM;
+
+	if (old_prot)
+		copy_from_user(page, (void *) PAGE_START(start), PAGE_SIZE);
+
+	down_write(&current->mm->mmap_sem);
+	{
+		ret = do_mmap(0, PAGE_START(start), PAGE_SIZE, prot | PROT_WRITE,
+			      flags | MAP_FIXED | MAP_ANONYMOUS, 0);
 	}
-	if (addr && ((addr + len) & ~PAGE_MASK) && get_user(c, (char *)(addr + len)) = 0) {
-		back = kmalloc(PAGE_SIZE - ((addr + len) & ~PAGE_MASK), GFP_KERNEL);
-		if (!back) {
-			if (front)
-				kfree(front);
-			return -ENOMEM;
+	up_write(&current->mm->mmap_sem);
+
+	if (IS_ERR((void *) ret))
+		goto out;
+
+	if (old_prot) {
+		/* copy back the old page contents.  */
+		if (PAGE_OFF(start))
+			copy_to_user((void *) PAGE_START(start), page, PAGE_OFF(start));
+		if (PAGE_OFF(end))
+			copy_to_user((void *) end, page + PAGE_OFF(end),
+				     PAGE_SIZE - PAGE_OFF(end));
+	}
+	if (!(flags & MAP_ANONYMOUS)) {
+		/* read the file contents */
+		inode = file->f_dentry->d_inode;
+		if (!inode->i_fop || !file->f_op->read
+		    || ((*file->f_op->read)(file, (char *) start, end - start, &off) < 0))
+		{
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+	if (!(prot & PROT_WRITE))
+		ret = sys_mprotect(PAGE_START(start), PAGE_SIZE, prot | old_prot);
+  out:
+	free_page((unsigned long) page);
+	return ret;
+}
+
+static unsigned long
+emulate_mmap (struct file *file, unsigned long start, unsigned long len, int prot, int flags,
+	      loff_t off)
+{
+	unsigned long tmp, end, pend, pstart, ret, is_congruent, fudge = 0;
+	struct inode *inode;
+	loff_t poff;
+
+	end = start + len;
+	pstart = PAGE_START(start);
+	pend = PAGE_ALIGN(end);
+
+	if (flags & MAP_FIXED) {
+		if (start > pstart) {
+			if (flags & MAP_SHARED)
+				printk(KERN_INFO
+				       "%s(%d): emulate_mmap() can't share head (addr=0x%lx)\n",
+				       current->comm, current->pid, start);
+			ret = mmap_subpage(file, start, min(PAGE_ALIGN(start), end), prot, flags,
+					   off);
+			if (IS_ERR((void *) ret))
+				return ret;
+			pstart += PAGE_SIZE;
+			if (pstart >= pend)
+				return start;	/* done */
+		}
+		if (end < pend) {
+			if (flags & MAP_SHARED)
+				printk(KERN_INFO
+				       "%s(%d): emulate_mmap() can't share tail (end=0x%lx)\n",
+				       current->comm, current->pid, end);
+			ret = mmap_subpage(file, max(start, PAGE_START(end)), end, prot, flags,
+					   (off + len) - PAGE_OFF(end));
+			if (IS_ERR((void *) ret))
+				return ret;
+			pend -= PAGE_SIZE;
+			if (pstart >= pend)
+				return start;	/* done */
+		}
+	} else {
+		/*
+		 * If a start address was specified, use it if the entire rounded out area
+		 * is available.
+		 */
+		if (start && !pstart)
+			fudge = 1;	/* handle case of mapping to range (0,PAGE_SIZE) */
+		tmp = arch_get_unmapped_area(file, pstart - fudge, pend - pstart, 0, flags);
+		if (tmp != pstart) {
+			pstart = tmp;
+			start = pstart + PAGE_OFF(off);	/* make start congruent with off */
+			end = start + len;
+			pend = PAGE_ALIGN(end);
 		}
-		__copy_user(back, (char *)addr + len, PAGE_SIZE - ((addr + len) & ~PAGE_MASK));
 	}
+
+	poff = off + (pstart - start);	/* note: (pstart - start) may be negative */
+	is_congruent = (flags & MAP_ANONYMOUS) || (PAGE_OFF(poff) = 0);
+
+	if ((flags & MAP_SHARED) && !is_congruent)
+		printk(KERN_INFO "%s(%d): emulate_mmap() can't share contents of incongruent mmap "
+		       "(addr=0x%lx,off=0x%llx)\n", current->comm, current->pid, start, off);
+
+	DBG("mmap_body: mapping [0x%lx-0x%lx) %s with poff 0x%llx\n", pstart, pend,
+	    is_congruent ? "congruent" : "not congruent", poff);
+
 	down_write(&current->mm->mmap_sem);
-	r = do_mmap(0, baddr, len + (addr - baddr), prot, flags | MAP_ANONYMOUS, 0);
+	{
+		if (!(flags & MAP_ANONYMOUS) && is_congruent)
+			ret = do_mmap(file, pstart, pend - pstart, prot, flags | MAP_FIXED, poff);
+		else
+			ret = do_mmap(0, pstart, pend - pstart,
+				      prot | ((flags & MAP_ANONYMOUS) ? 0 : PROT_WRITE),
+				      flags | MAP_FIXED | MAP_ANONYMOUS, 0);
+	}
 	up_write(&current->mm->mmap_sem);
-	if (r < 0)
-		return(r);
-	if (addr = 0)
-		addr = r;
-	if (back) {
-		__copy_user((char *)addr + len, back, PAGE_SIZE - ((addr + len) & ~PAGE_MASK));
-		kfree(back);
-	}
-	if (front) {
-		__copy_user((void *)baddr, front, addr - baddr);
-		kfree(front);
-	}
-	if (flags & MAP_ANONYMOUS) {
-		clear_user((char *)addr, len);
-		return(addr);
+
+	if (IS_ERR((void *) ret))
+		return ret;
+
+	if (!is_congruent) {
+		/* read the file contents */
+		inode = file->f_dentry->d_inode;
+		if (!inode->i_fop || !file->f_op->read
+		    || ((*file->f_op->read)(file, (char *) pstart, pend - pstart, &poff) < 0))
+		{
+			sys_munmap(pstart, pend - pstart);
+			return -EINVAL;
+		}
+		if (!(prot & PROT_WRITE) && sys_mprotect(pstart, pend - pstart, prot) < 0)
+			return EINVAL;
 	}
-	if (!file)
-		return -EINVAL;
-	inode = file->f_dentry->d_inode;
-	if (!inode->i_fop)
-		return -EINVAL;
-	if (!file->f_op->read)
-		return -EINVAL;
-	r = file->f_op->read(file, (char *)addr, len, &off);
-	return (r < 0) ? -EINVAL : addr;
+	return start;
 }
 
-long
-ia32_do_mmap (struct file *file, unsigned int addr, unsigned int len, unsigned int prot,
-	      unsigned int flags, unsigned int fd, unsigned int offset)
+#endif /* PAGE_SHIFT > IA32_PAGE_SHIFT */
+
+static inline unsigned int
+get_prot32 (unsigned int prot)
 {
-	long error = -EFAULT;
-	unsigned int poff;
+	if (prot & PROT_WRITE)
+		/* on x86, PROT_WRITE implies PROT_READ which implies PROT_EEC */
+		prot |= PROT_READ | PROT_WRITE | PROT_EXEC;
+	else if (prot & (PROT_READ | PROT_EXEC))
+		/* on x86, there is no distinction between PROT_READ and PROT_EXEC */
+		prot |= (PROT_READ | PROT_EXEC);
 
-	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-	prot |= PROT_EXEC;
+	return prot;
+}
 
-	if ((flags & MAP_FIXED) && ((addr & ~PAGE_MASK) || (offset & ~PAGE_MASK)))
-		error = do_mmap_fake(file, addr, len, prot, flags, (loff_t)offset);
-	else {
-		poff = offset & PAGE_MASK;
-		len += offset - poff;
+unsigned long
+ia32_do_mmap (struct file *file, unsigned long addr, unsigned long len, int prot, int flags,
+	      loff_t offset)
+{
+	DBG("ia32_do_mmap(file=%p,addr=0x%lx,len=0x%lx,prot=%x,flags=%x,offset=0x%llx)\n",
+	    file, addr, len, prot, flags, offset);
+
+	if (file && (!file->f_op || !file->f_op->mmap))
+		return -ENODEV;
+
+	len = IA32_PAGE_ALIGN(len);
+	if (len = 0)
+		return addr;
+
+	if (len > IA32_PAGE_OFFSET || addr > IA32_PAGE_OFFSET - len)
+		return -EINVAL;
+
+	if (OFFSET4K(offset))
+		return -EINVAL;
 
-		down_write(&current->mm->mmap_sem);
-		error = do_mmap_pgoff(file, addr, len, prot, flags, poff >> PAGE_SHIFT);
-		up_write(&current->mm->mmap_sem);
+	prot = get_prot32(prot);
 
-		if (!IS_ERR((void *) error))
-			error += offset - poff;
+#if PAGE_SHIFT > IA32_PAGE_SHIFT
+	down(&ia32_mmap_sem);
+	{
+		addr = emulate_mmap(file, addr, len, prot, flags, offset);
 	}
-	return error;
+	up(&ia32_mmap_sem);
+#else
+	down_write(&current->mm->mmap_sem);
+	{
+		addr = do_mmap(file, addr, len, prot, flags, offset);
+	}
+	up_write(&current->mm->mmap_sem);
+#endif
+	DBG("ia32_do_mmap: returning 0x%lx\n", addr);
+	return addr;
 }
 
 /*
- * Linux/i386 didn't use to be able to handle more than
- * 4 system call parameters, so these system calls used a memory
- * block for parameter passing..
+ * Linux/i386 didn't use to be able to handle more than 4 system call parameters, so these
+ * system calls used a memory block for parameter passing..
  */
 
 struct mmap_arg_struct {
@@ -317,180 +486,166 @@
 };
 
 asmlinkage long
-sys32_mmap(struct mmap_arg_struct *arg)
+sys32_mmap (struct mmap_arg_struct *arg)
 {
 	struct mmap_arg_struct a;
 	struct file *file = NULL;
-	long retval;
+	unsigned long addr;
+	int flags;
 
 	if (copy_from_user(&a, arg, sizeof(a)))
 		return -EFAULT;
 
-	if (PAGE_ALIGN(a.len) = 0)
-		return a.addr;
+	if (OFFSET4K(a.offset))
+		return -EINVAL;
+
+	flags = a.flags;
 
-	if (!(a.flags & MAP_ANONYMOUS)) {
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+	if (!(flags & MAP_ANONYMOUS)) {
 		file = fget(a.fd);
 		if (!file)
 			return -EBADF;
 	}
-#ifdef	CONFIG_IA64_PAGE_SIZE_4KB
-	if ((a.offset & ~PAGE_MASK) != 0)
-		return -EINVAL;
 
-	down_write(&current->mm->mmap_sem);
-	retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, a.offset >> PAGE_SHIFT);
-	up_write(&current->mm->mmap_sem);
-#else
-	retval = ia32_do_mmap(file, a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
-#endif
+	addr = ia32_do_mmap(file, a.addr, a.len, a.prot, flags, a.offset);
+
 	if (file)
 		fput(file);
-	return retval;
+	return addr;
 }
 
 asmlinkage long
-sys32_mprotect(unsigned long start, size_t len, unsigned long prot)
+sys32_mmap2 (unsigned int addr, unsigned int len, unsigned int prot, unsigned int flags,
+	     unsigned int fd, unsigned int pgoff)
 {
+	struct file *file = NULL;
+	unsigned long retval;
 
-#ifdef	CONFIG_IA64_PAGE_SIZE_4KB
-	return(sys_mprotect(start, len, prot));
-#else	// CONFIG_IA64_PAGE_SIZE_4KB
-	if (prot = 0)
-		return(0);
-	len += start & ~PAGE_MASK;
-	if ((start & ~PAGE_MASK) && (prot & PROT_WRITE))
-		prot |= PROT_EXEC;
-	return(sys_mprotect(start & PAGE_MASK, len & PAGE_MASK, prot));
-#endif	// CONFIG_IA64_PAGE_SIZE_4KB
-}
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+	if (!(flags & MAP_ANONYMOUS)) {
+		file = fget(fd);
+		if (!file)
+			return -EBADF;
+	}
 
-asmlinkage long
-sys32_pipe(int *fd)
-{
-	int retval;
-	int fds[2];
+	retval = ia32_do_mmap(file, addr, len, prot, flags,
+			      (unsigned long) pgoff << IA32_PAGE_SHIFT);
 
-	retval = do_pipe(fds);
-	if (retval)
-		goto out;
-	if (copy_to_user(fd, fds, sizeof(fds)))
-		retval = -EFAULT;
-  out:
+	if (file)
+		fput(file);
 	return retval;
 }
 
 asmlinkage long
-sys32_signal (int sig, unsigned int handler)
+sys32_munmap (unsigned int start, unsigned int len)
 {
-	struct k_sigaction new_sa, old_sa;
-	int ret;
+	unsigned int end = start + len;
+	long ret;
+
+#if PAGE_SHIFT <= IA32_PAGE_SHIFT
+	ret = sys_munmap(start, end - start);
+#else
+	if (start > end)
+		return -EINVAL;
+
+	start = PAGE_ALIGN(start);
+	end = PAGE_START(end);
+
+	if (start >= end)
+		return 0;
+
+	down(&ia32_mmap_sem);
+	{
+		ret = sys_munmap(start, end - start);
+	}
+	up(&ia32_mmap_sem);
+#endif
+	return ret;
+}
 
-	new_sa.sa.sa_handler = (__sighandler_t) A(handler);
-	new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK;
+#if PAGE_SHIFT > IA32_PAGE_SHIFT
+
+/*
+ * When mprotect()ing a partial page, we set the permission to the union of the old
+ * settings and the new settings.  In other words, it's only possible to make access to a
+ * partial page less restrictive.
+ */
+static long
+mprotect_subpage (unsigned long address, int new_prot)
+{
+	int old_prot;
 
-	ret = do_sigaction(sig, &new_sa, &old_sa);
+	if (new_prot = PROT_NONE)
+		return 0;		/* optimize case where nothing changes... */
 
-	return ret ? ret : (unsigned long)old_sa.sa.sa_handler;
+	old_prot = get_page_prot(address);
+	return sys_mprotect(address, PAGE_SIZE, new_prot | old_prot);
 }
 
+#endif /* PAGE_SHIFT > IA32_PAGE_SHIFT */
+
 asmlinkage long
-sys32_rt_sigaction(int sig, struct sigaction32 *act,
-		   struct sigaction32 *oact,  unsigned int sigsetsize)
+sys32_mprotect (unsigned int start, unsigned int len, int prot)
 {
-	struct k_sigaction new_ka, old_ka;
-	int ret;
-	sigset32_t set32;
+	unsigned long end = start + len;
+#if PAGE_SHIFT > IA32_PAGE_SHIFT
+	long retval = 0;
+#endif
+
+	prot = get_prot32(prot);
 
-	/* XXX: Don't preclude handling different sized sigset_t's.  */
-	if (sigsetsize != sizeof(sigset32_t))
+#if PAGE_SHIFT <= IA32_PAGE_SHIFT
+	return sys_mprotect(start, end - start, prot);
+#else
+	if (OFFSET4K(start))
 		return -EINVAL;
 
-	if (act) {
-		ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler);
-		ret |= __copy_from_user(&set32, &act->sa_mask,
-					sizeof(sigset32_t));
-		switch (_NSIG_WORDS) {
-		case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6]
-				| (((long)set32.sig[7]) << 32);
-		case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4]
-				| (((long)set32.sig[5]) << 32);
-		case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2]
-				| (((long)set32.sig[3]) << 32);
-		case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0]
-				| (((long)set32.sig[1]) << 32);
-		}
-		ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+	end = IA32_PAGE_ALIGN(end);
+	if (end < start)
+		return -EINVAL;
 
-		if (ret)
-			return -EFAULT;
-	}
+	down(&ia32_mmap_sem);
+	{
+		if (PAGE_OFF(start)) {
+			/* start address is 4KB aligned but not page aligned. */
+			retval = mprotect_subpage(PAGE_START(start), prot);
+			if (retval < 0)
+				goto out;
 
-	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+			start = PAGE_ALIGN(start);
+			if (start >= end)
+				goto out;	/* retval is already zero... */
+		}
 
-	if (!ret && oact) {
-		switch (_NSIG_WORDS) {
-		case 4:
-			set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32);
-			set32.sig[6] = old_ka.sa.sa_mask.sig[3];
-		case 3:
-			set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32);
-			set32.sig[4] = old_ka.sa.sa_mask.sig[2];
-		case 2:
-			set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32);
-			set32.sig[2] = old_ka.sa.sa_mask.sig[1];
-		case 1:
-			set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32);
-			set32.sig[0] = old_ka.sa.sa_mask.sig[0];
+		if (PAGE_OFF(end)) {
+			/* end address is 4KB aligned but not page aligned. */
+			retval = mprotect_subpage(PAGE_START(end), prot);
+			if (retval < 0)
+				return retval;
+			end = PAGE_START(end);
 		}
-		ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler);
-		ret |= __copy_to_user(&oact->sa_mask, &set32,
-				      sizeof(sigset32_t));
-		ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+		retval = sys_mprotect(start, end - start, prot);
 	}
-
-	return ret;
+  out:
+	up(&ia32_mmap_sem);
+	return retval;
+#endif
 }
 
-
-extern asmlinkage long sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset,
-					  size_t sigsetsize);
-
 asmlinkage long
-sys32_rt_sigprocmask(int how, sigset32_t *set, sigset32_t *oset,
-		     unsigned int sigsetsize)
+sys32_pipe (int *fd)
 {
-	sigset_t s;
-	sigset32_t s32;
-	int ret;
-	mm_segment_t old_fs = get_fs();
+	int retval;
+	int fds[2];
 
-	if (set) {
-		if (copy_from_user (&s32, set, sizeof(sigset32_t)))
-			return -EFAULT;
-		switch (_NSIG_WORDS) {
-		case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
-		case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
-		case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
-		case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
-		}
-	}
-	set_fs (KERNEL_DS);
-	ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL,
-				 sigsetsize);
-	set_fs (old_fs);
-	if (ret) return ret;
-	if (oset) {
-		switch (_NSIG_WORDS) {
-		case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
-		case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
-		case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
-		case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
-		}
-		if (copy_to_user (oset, &s32, sizeof(sigset32_t)))
-			return -EFAULT;
-	}
-	return 0;
+	retval = do_pipe(fds);
+	if (retval)
+		goto out;
+	if (copy_to_user(fd, fds, sizeof(fds)))
+		retval = -EFAULT;
+  out:
+	return retval;
 }
 
 static inline int
@@ -498,31 +653,34 @@
 {
 	int err;
 
-	err = put_user (kbuf->f_type, &ubuf->f_type);
-	err |= __put_user (kbuf->f_bsize, &ubuf->f_bsize);
-	err |= __put_user (kbuf->f_blocks, &ubuf->f_blocks);
-	err |= __put_user (kbuf->f_bfree, &ubuf->f_bfree);
-	err |= __put_user (kbuf->f_bavail, &ubuf->f_bavail);
-	err |= __put_user (kbuf->f_files, &ubuf->f_files);
-	err |= __put_user (kbuf->f_ffree, &ubuf->f_ffree);
-	err |= __put_user (kbuf->f_namelen, &ubuf->f_namelen);
-	err |= __put_user (kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]);
-	err |= __put_user (kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]);
+	if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)))
+		return -EFAULT;
+
+	err = __put_user(kbuf->f_type, &ubuf->f_type);
+	err |= __put_user(kbuf->f_bsize, &ubuf->f_bsize);
+	err |= __put_user(kbuf->f_blocks, &ubuf->f_blocks);
+	err |= __put_user(kbuf->f_bfree, &ubuf->f_bfree);
+	err |= __put_user(kbuf->f_bavail, &ubuf->f_bavail);
+	err |= __put_user(kbuf->f_files, &ubuf->f_files);
+	err |= __put_user(kbuf->f_ffree, &ubuf->f_ffree);
+	err |= __put_user(kbuf->f_namelen, &ubuf->f_namelen);
+	err |= __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]);
+	err |= __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]);
 	return err;
 }
 
 extern asmlinkage long sys_statfs(const char * path, struct statfs * buf);
 
 asmlinkage long
-sys32_statfs(const char * path, struct statfs32 *buf)
+sys32_statfs (const char *path, struct statfs32 *buf)
 {
 	int ret;
 	struct statfs s;
 	mm_segment_t old_fs = get_fs();
 
-	set_fs (KERNEL_DS);
-	ret = sys_statfs((const char *)path, &s);
-	set_fs (old_fs);
+	set_fs(KERNEL_DS);
+	ret = sys_statfs(path, &s);
+	set_fs(old_fs);
 	if (put_statfs(buf, &s))
 		return -EFAULT;
 	return ret;
@@ -531,15 +689,15 @@
 extern asmlinkage long sys_fstatfs(unsigned int fd, struct statfs * buf);
 
 asmlinkage long
-sys32_fstatfs(unsigned int fd, struct statfs32 *buf)
+sys32_fstatfs (unsigned int fd, struct statfs32 *buf)
 {
 	int ret;
 	struct statfs s;
 	mm_segment_t old_fs = get_fs();
 
-	set_fs (KERNEL_DS);
+	set_fs(KERNEL_DS);
 	ret = sys_fstatfs(fd, &s);
-	set_fs (old_fs);
+	set_fs(old_fs);
 	if (put_statfs(buf, &s))
 		return -EFAULT;
 	return ret;
@@ -557,23 +715,21 @@
 };
 
 static inline long
-get_tv32(struct timeval *o, struct timeval32 *i)
+get_tv32 (struct timeval *o, struct timeval32 *i)
 {
 	return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
-		(__get_user(o->tv_sec, &i->tv_sec) |
-		 __get_user(o->tv_usec, &i->tv_usec)));
+		(__get_user(o->tv_sec, &i->tv_sec) | __get_user(o->tv_usec, &i->tv_usec)));
 }
 
 static inline long
-put_tv32(struct timeval32 *o, struct timeval *i)
+put_tv32 (struct timeval32 *o, struct timeval *i)
 {
 	return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
-		(__put_user(i->tv_sec, &o->tv_sec) |
-		 __put_user(i->tv_usec, &o->tv_usec)));
+		(__put_user(i->tv_sec, &o->tv_sec) | __put_user(i->tv_usec, &o->tv_usec)));
 }
 
 static inline long
-get_it32(struct itimerval *o, struct itimerval32 *i)
+get_it32 (struct itimerval *o, struct itimerval32 *i)
 {
 	return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
 		(__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) |
@@ -583,7 +739,7 @@
 }
 
 static inline long
-put_it32(struct itimerval32 *o, struct itimerval *i)
+put_it32 (struct itimerval32 *o, struct itimerval *i)
 {
 	return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
 		(__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
@@ -592,10 +748,10 @@
 		 __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
 }
 
-extern int do_getitimer(int which, struct itimerval *value);
+extern int do_getitimer (int which, struct itimerval *value);
 
 asmlinkage long
-sys32_getitimer(int which, struct itimerval32 *it)
+sys32_getitimer (int which, struct itimerval32 *it)
 {
 	struct itimerval kit;
 	int error;
@@ -607,10 +763,10 @@
 	return error;
 }
 
-extern int do_setitimer(int which, struct itimerval *, struct itimerval *);
+extern int do_setitimer (int which, struct itimerval *, struct itimerval *);
 
 asmlinkage long
-sys32_setitimer(int which, struct itimerval32 *in, struct itimerval32 *out)
+sys32_setitimer (int which, struct itimerval32 *in, struct itimerval32 *out)
 {
 	struct itimerval kin, kout;
 	int error;
@@ -630,8 +786,9 @@
 	return 0;
 
 }
+
 asmlinkage unsigned long
-sys32_alarm(unsigned int seconds)
+sys32_alarm (unsigned int seconds)
 {
 	struct itimerval it_new, it_old;
 	unsigned int oldalarm;
@@ -660,7 +817,7 @@
 extern asmlinkage long sys_gettimeofday (struct timeval *tv, struct timezone *tz);
 
 asmlinkage long
-ia32_utime(char * filename, struct utimbuf_32 *times32)
+sys32_utime (char *filename, struct utimbuf_32 *times32)
 {
 	mm_segment_t old_fs = get_fs();
 	struct timeval tv[2], *tvp;
@@ -673,20 +830,20 @@
 		if (get_user(tv[1].tv_sec, &times32->mtime))
 			return -EFAULT;
 		tv[1].tv_usec = 0;
-		set_fs (KERNEL_DS);
+		set_fs(KERNEL_DS);
 		tvp = tv;
 	} else
 		tvp = NULL;
 	ret = sys_utimes(filename, tvp);
-	set_fs (old_fs);
+	set_fs(old_fs);
 	return ret;
 }
 
 extern struct timezone sys_tz;
-extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz);
+extern int do_sys_settimeofday (struct timeval *tv, struct timezone *tz);
 
 asmlinkage long
-sys32_gettimeofday(struct timeval32 *tv, struct timezone *tz)
+sys32_gettimeofday (struct timeval32 *tv, struct timezone *tz)
 {
 	if (tv) {
 		struct timeval ktv;
@@ -702,7 +859,7 @@
 }
 
 asmlinkage long
-sys32_settimeofday(struct timeval32 *tv, struct timezone *tz)
+sys32_settimeofday (struct timeval32 *tv, struct timezone *tz)
 {
 	struct timeval ktv;
 	struct timezone ktz;
@@ -719,20 +876,6 @@
 	return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL);
 }
 
-struct linux32_dirent {
-	u32	d_ino;
-	u32	d_off;
-	u16	d_reclen;
-	char	d_name[1];
-};
-
-struct old_linux32_dirent {
-	u32	d_ino;
-	u32	d_offset;
-	u16	d_namlen;
-	char	d_name[1];
-};
-
 struct getdents32_callback {
 	struct linux32_dirent * current_dir;
 	struct linux32_dirent * previous;
@@ -775,7 +918,7 @@
 }
 
 asmlinkage long
-sys32_getdents (unsigned int fd, void * dirent, unsigned int count)
+sys32_getdents (unsigned int fd, struct linux32_dirent *dirent, unsigned int count)
 {
 	struct file * file;
 	struct linux32_dirent * lastdirent;
@@ -787,7 +930,7 @@
 	if (!file)
 		goto out;
 
-	buf.current_dir = (struct linux32_dirent *) dirent;
+	buf.current_dir = dirent;
 	buf.previous = NULL;
 	buf.count = count;
 	buf.error = 0;
@@ -831,7 +974,7 @@
 }
 
 asmlinkage long
-sys32_readdir (unsigned int fd, void * dirent, unsigned int count)
+sys32_readdir (unsigned int fd, void *dirent, unsigned int count)
 {
 	int error;
 	struct file * file;
@@ -866,7 +1009,7 @@
 #define ROUND_UP_TIME(x,y) (((x)+(y)-1)/(y))
 
 asmlinkage long
-sys32_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval32 *tvp32)
+sys32_select (int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval32 *tvp32)
 {
 	fd_set_bits fds;
 	char *bits;
@@ -878,8 +1021,7 @@
 		time_t sec, usec;
 
 		ret = -EFAULT;
-		if (get_user(sec, &tvp32->tv_sec)
-		    || get_user(usec, &tvp32->tv_usec))
+		if (get_user(sec, &tvp32->tv_sec) || get_user(usec, &tvp32->tv_usec))
 			goto out_nofds;
 
 		ret = -EINVAL;
@@ -933,9 +1075,7 @@
 			usec = timeout % HZ;
 			usec *= (1000000/HZ);
 		}
-		if (put_user(sec, (int *)&tvp32->tv_sec)
-		    || put_user(usec, (int *)&tvp32->tv_usec))
-		{
+		if (put_user(sec, &tvp32->tv_sec) || put_user(usec, &tvp32->tv_usec)) {
 			ret = -EFAULT;
 			goto out;
 		}
@@ -969,50 +1109,43 @@
 };
 
 asmlinkage long
-old_select(struct sel_arg_struct *arg)
+sys32_old_select (struct sel_arg_struct *arg)
 {
 	struct sel_arg_struct a;
 
 	if (copy_from_user(&a, arg, sizeof(a)))
 		return -EFAULT;
-	return sys32_select(a.n, (fd_set *)A(a.inp), (fd_set *)A(a.outp), (fd_set *)A(a.exp),
-			    (struct timeval32 *)A(a.tvp));
+	return sys32_select(a.n, (fd_set *) A(a.inp), (fd_set *) A(a.outp), (fd_set *) A(a.exp),
+			    (struct timeval32 *) A(a.tvp));
 }
 
-struct timespec32 {
-	int	tv_sec;
-	int	tv_nsec;
-};
-
-extern asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp);
+extern asmlinkage long sys_nanosleep (struct timespec *rqtp, struct timespec *rmtp);
 
 asmlinkage long
-sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp)
+sys32_nanosleep (struct timespec32 *rqtp, struct timespec32 *rmtp)
 {
 	struct timespec t;
 	int ret;
-	mm_segment_t old_fs = get_fs ();
+	mm_segment_t old_fs = get_fs();
 
-	if (get_user (t.tv_sec, &rqtp->tv_sec) ||
-	    __get_user (t.tv_nsec, &rqtp->tv_nsec))
+	if (get_user (t.tv_sec, &rqtp->tv_sec) || get_user (t.tv_nsec, &rqtp->tv_nsec))
 		return -EFAULT;
-	set_fs (KERNEL_DS);
+	set_fs(KERNEL_DS);
 	ret = sys_nanosleep(&t, rmtp ? &t : NULL);
-	set_fs (old_fs);
+	set_fs(old_fs);
 	if (rmtp && ret = -EINTR) {
-		if (__put_user (t.tv_sec, &rmtp->tv_sec) ||
-		    __put_user (t.tv_nsec, &rmtp->tv_nsec))
+		if (put_user(t.tv_sec, &rmtp->tv_sec) || put_user(t.tv_nsec, &rmtp->tv_nsec))
 			return -EFAULT;
 	}
 	return ret;
 }
 
 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);
+asmlinkage ssize_t sys_readv (unsigned long,const struct iovec *,unsigned long);
+asmlinkage ssize_t sys_writev (unsigned long,const struct iovec *,unsigned long);
 
 static struct iovec *
-get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type)
+get_iovec32 (struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type)
 {
 	int i;
 	u32 buf, len;
@@ -1022,24 +1155,23 @@
 
 	if (!count)
 		return 0;
-	if(verify_area(VERIFY_READ, iov32, sizeof(struct iovec32)*count))
-		return(struct iovec *)0;
+	if (verify_area(VERIFY_READ, iov32, sizeof(struct iovec32)*count))
+		return NULL;
 	if (count > UIO_MAXIOV)
-		return(struct iovec *)0;
+		return NULL;
 	if (count > UIO_FASTIOV) {
 		iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
 		if (!iov)
-			return((struct iovec *)0);
+			return NULL;
 	} else
 		iov = iov_buf;
 
 	ivp = iov;
 	for (i = 0; i < count; i++) {
-		if (__get_user(len, &iov32->iov_len) ||
-		    __get_user(buf, &iov32->iov_base)) {
+		if (__get_user(len, &iov32->iov_len) || __get_user(buf, &iov32->iov_base)) {
 			if (iov != iov_buf)
 				kfree(iov);
-			return((struct iovec *)0);
+			return NULL;
 		}
 		if (verify_area(type, (void *)A(buf), len)) {
 			if (iov != iov_buf)
@@ -1047,22 +1179,23 @@
 			return((struct iovec *)0);
 		}
 		ivp->iov_base = (void *)A(buf);
-		ivp->iov_len = (__kernel_size_t)len;
+		ivp->iov_len = (__kernel_size_t) len;
 		iov32++;
 		ivp++;
 	}
-	return(iov);
+	return iov;
 }
 
 asmlinkage long
-sys32_readv(int fd, struct iovec32 *vector, u32 count)
+sys32_readv (int fd, struct iovec32 *vector, u32 count)
 {
 	struct iovec iovstack[UIO_FASTIOV];
 	struct iovec *iov;
-	int ret;
+	long ret;
 	mm_segment_t old_fs = get_fs();
 
-	if ((iov = get_iovec32(vector, iovstack, count, VERIFY_WRITE)) = (struct iovec *)0)
+	iov = get_iovec32(vector, iovstack, count, VERIFY_WRITE);
+	if (!iov)
 		return -EFAULT;
 	set_fs(KERNEL_DS);
 	ret = sys_readv(fd, iov, count);
@@ -1073,14 +1206,15 @@
 }
 
 asmlinkage long
-sys32_writev(int fd, struct iovec32 *vector, u32 count)
+sys32_writev (int fd, struct iovec32 *vector, u32 count)
 {
 	struct iovec iovstack[UIO_FASTIOV];
 	struct iovec *iov;
-	int ret;
+	long ret;
 	mm_segment_t old_fs = get_fs();
 
-	if ((iov = get_iovec32(vector, iovstack, count, VERIFY_READ)) = (struct iovec *)0)
+	iov = get_iovec32(vector, iovstack, count, VERIFY_READ);
+	if (!iov)
 		return -EFAULT;
 	set_fs(KERNEL_DS);
 	ret = sys_writev(fd, iov, count);
@@ -1098,45 +1232,66 @@
 	int	rlim_max;
 };
 
-extern asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit *rlim);
+extern asmlinkage long sys_getrlimit (unsigned int resource, struct rlimit *rlim);
 
 asmlinkage long
-sys32_getrlimit(unsigned int resource, struct rlimit32 *rlim)
+sys32_old_getrlimit (unsigned int resource, struct rlimit32 *rlim)
 {
+	mm_segment_t old_fs = get_fs();
+	struct rlimit r;
+	int ret;
+
+	set_fs(KERNEL_DS);
+	ret = sys_getrlimit(resource, &r);
+	set_fs(old_fs);
+	if (!ret) {
+		ret = put_user(RESOURCE32(r.rlim_cur), &rlim->rlim_cur);
+		ret |= put_user(RESOURCE32(r.rlim_max), &rlim->rlim_max);
+	}
+	return ret;
+}
+
+asmlinkage long
+sys32_getrlimit (unsigned int resource, struct rlimit32 *rlim)
+{
+	mm_segment_t old_fs = get_fs();
 	struct rlimit r;
 	int ret;
-	mm_segment_t old_fs = get_fs ();
 
-	set_fs (KERNEL_DS);
+	set_fs(KERNEL_DS);
 	ret = sys_getrlimit(resource, &r);
-	set_fs (old_fs);
+	set_fs(old_fs);
 	if (!ret) {
-		ret = put_user (RESOURCE32(r.rlim_cur), &rlim->rlim_cur);
-		ret |= __put_user (RESOURCE32(r.rlim_max), &rlim->rlim_max);
+		if (r.rlim_cur >= 0xffffffff)
+			r.rlim_cur = 0xffffffff;
+		if (r.rlim_max >= 0xffffffff)
+			r.rlim_max = 0xffffffff;
+		ret = put_user(r.rlim_cur, &rlim->rlim_cur);
+		ret |= put_user(r.rlim_max, &rlim->rlim_max);
 	}
 	return ret;
 }
 
-extern asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim);
+extern asmlinkage long sys_setrlimit (unsigned int resource, struct rlimit *rlim);
 
 asmlinkage long
-sys32_setrlimit(unsigned int resource, struct rlimit32 *rlim)
+sys32_setrlimit (unsigned int resource, struct rlimit32 *rlim)
 {
 	struct rlimit r;
 	int ret;
-	mm_segment_t old_fs = get_fs ();
+	mm_segment_t old_fs = get_fs();
 
-	if (resource >= RLIM_NLIMITS) return -EINVAL;
-	if (get_user (r.rlim_cur, &rlim->rlim_cur) ||
-	    __get_user (r.rlim_max, &rlim->rlim_max))
+	if (resource >= RLIM_NLIMITS)
+		return -EINVAL;
+	if (get_user(r.rlim_cur, &rlim->rlim_cur) || get_user(r.rlim_max, &rlim->rlim_max))
 		return -EFAULT;
 	if (r.rlim_cur = RLIM_INFINITY32)
 		r.rlim_cur = RLIM_INFINITY;
 	if (r.rlim_max = RLIM_INFINITY32)
 		r.rlim_max = RLIM_INFINITY;
-	set_fs (KERNEL_DS);
+	set_fs(KERNEL_DS);
 	ret = sys_setrlimit(resource, &r);
-	set_fs (old_fs);
+	set_fs(old_fs);
 	return ret;
 }
 
@@ -1154,25 +1309,141 @@
 	unsigned	msg_flags;
 };
 
-static inline int
-shape_msg(struct msghdr *mp, struct msghdr32 *mp32)
-{
-	int ret;
-	unsigned int i;
+struct cmsghdr32 {
+	__kernel_size_t32 cmsg_len;
+	int               cmsg_level;
+	int               cmsg_type;
+};
 
-	if (!access_ok(VERIFY_READ, mp32, sizeof(*mp32)))
-		return(-EFAULT);
-	ret = __get_user(i, &mp32->msg_name);
-	mp->msg_name = (void *)A(i);
-	ret |= __get_user(mp->msg_namelen, &mp32->msg_namelen);
-	ret |= __get_user(i, &mp32->msg_iov);
+/* Bleech... */
+#define __CMSG32_NXTHDR(ctl, len, cmsg, cmsglen) __cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen))
+#define CMSG32_NXTHDR(mhdr, cmsg, cmsglen)	cmsg32_nxthdr((mhdr), (cmsg), (cmsglen))
+#define CMSG32_ALIGN(len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) )
+#define CMSG32_DATA(cmsg) \
+	((void *)((char *)(cmsg) + CMSG32_ALIGN(sizeof(struct cmsghdr32))))
+#define CMSG32_SPACE(len) \
+	(CMSG32_ALIGN(sizeof(struct cmsghdr32)) + CMSG32_ALIGN(len))
+#define CMSG32_LEN(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + (len))
+#define __CMSG32_FIRSTHDR(ctl,len) \
+	((len) >= sizeof(struct cmsghdr32) ? (struct cmsghdr32 *)(ctl) : (struct cmsghdr32 *)NULL)
+#define CMSG32_FIRSTHDR(msg)	__CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
+
+static inline struct cmsghdr32 *
+__cmsg32_nxthdr (void *ctl, __kernel_size_t size, struct cmsghdr32 *cmsg, int cmsg_len)
+{
+	struct cmsghdr32 * ptr;
+
+	ptr = (struct cmsghdr32 *)(((unsigned char *) cmsg) + CMSG32_ALIGN(cmsg_len));
+	if ((unsigned long)((char*)(ptr+1) - (char *) ctl) > size)
+		return NULL;
+	return ptr;
+}
+
+static inline struct cmsghdr32 *
+cmsg32_nxthdr (struct msghdr *msg, struct cmsghdr32 *cmsg, int cmsg_len)
+{
+	return __cmsg32_nxthdr(msg->msg_control, msg->msg_controllen, cmsg, cmsg_len);
+}
+
+static inline int
+get_msghdr32 (struct msghdr *mp, struct msghdr32 *mp32)
+{
+	int ret;
+	unsigned int i;
+
+	if (!access_ok(VERIFY_READ, mp32, sizeof(*mp32)))
+		return -EFAULT;
+	ret = __get_user(i, &mp32->msg_name);
+	mp->msg_name = (void *)A(i);
+	ret |= __get_user(mp->msg_namelen, &mp32->msg_namelen);
+	ret |= __get_user(i, &mp32->msg_iov);
 	mp->msg_iov = (struct iovec *)A(i);
 	ret |= __get_user(mp->msg_iovlen, &mp32->msg_iovlen);
 	ret |= __get_user(i, &mp32->msg_control);
 	mp->msg_control = (void *)A(i);
 	ret |= __get_user(mp->msg_controllen, &mp32->msg_controllen);
 	ret |= __get_user(mp->msg_flags, &mp32->msg_flags);
-	return(ret ? -EFAULT : 0);
+	return ret ? -EFAULT : 0;
+}
+
+/*
+ * There is a lot of hair here because the alignment rules (and thus placement) of cmsg
+ * headers and length are different for 32-bit apps.  -DaveM
+ */
+static int
+get_cmsghdr32 (struct msghdr *kmsg, unsigned char *stackbuf, struct sock *sk, size_t *bufsize)
+{
+	struct cmsghdr *kcmsg, *kcmsg_base;
+	__kernel_size_t kcmlen, tmp;
+	__kernel_size_t32 ucmlen;
+	struct cmsghdr32 *ucmsg;
+	long err;
+
+	kcmlen = 0;
+	kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;
+	ucmsg = CMSG32_FIRSTHDR(kmsg);
+	while (ucmsg != NULL) {
+		if (get_user(ucmlen, &ucmsg->cmsg_len))
+			return -EFAULT;
+
+		/* Catch bogons. */
+		if (CMSG32_ALIGN(ucmlen) < CMSG32_ALIGN(sizeof(struct cmsghdr32)))
+			return -EINVAL;
+		if ((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control) + ucmlen)
+		    > kmsg->msg_controllen)
+			return -EINVAL;
+
+		tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
+		       CMSG_ALIGN(sizeof(struct cmsghdr)));
+		kcmlen += tmp;
+		ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
+	}
+	if (kcmlen = 0)
+		return -EINVAL;
+
+	/*
+	 * The kcmlen holds the 64-bit version of the control length.  It may not be
+	 * modified as we do not stick it into the kmsg until we have successfully copied
+	 * over all of the data from the user.
+	 */
+	if (kcmlen > *bufsize) {
+		*bufsize = kcmlen;
+		kcmsg_base = kcmsg = sock_kmalloc(sk, kcmlen, GFP_KERNEL);
+	}
+	if (kcmsg = NULL)
+		return -ENOBUFS;
+
+	/* Now copy them over neatly. */
+	memset(kcmsg, 0, kcmlen);
+	ucmsg = CMSG32_FIRSTHDR(kmsg);
+	while (ucmsg != NULL) {
+		err = get_user(ucmlen, &ucmsg->cmsg_len);
+		tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
+		       CMSG_ALIGN(sizeof(struct cmsghdr)));
+		kcmsg->cmsg_len = tmp;
+		err |= get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level);
+		err |= get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type);
+
+		/* Copy over the data. */
+		err |= copy_from_user(CMSG_DATA(kcmsg), CMSG32_DATA(ucmsg),
+				      (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))));
+		if (err)
+			goto out_free_efault;
+
+		/* Advance. */
+		kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp));
+		ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
+	}
+
+	/* Ok, looks like we made it.  Hook it up and return success. */
+	kmsg->msg_control = kcmsg_base;
+	kmsg->msg_controllen = kcmlen;
+	return 0;
+
+out_free_efault:
+	if (kcmsg_base != (struct cmsghdr *)stackbuf)
+		sock_kfree_s(sk, kcmsg_base, kcmlen);
+	return -EFAULT;
 }
 
 /*
@@ -1187,20 +1458,17 @@
  */
 
 static inline int
-verify_iovec32(struct msghdr *m, struct iovec *iov, char *address, int mode)
+verify_iovec32 (struct msghdr *m, struct iovec *iov, char *address, int mode)
 {
 	int size, err, ct;
 	struct iovec32 *iov32;
 
-	if(m->msg_namelen)
-	{
-		if(mode=VERIFY_READ)
-		{
-			err=move_addr_to_kernel(m->msg_name, m->msg_namelen, address);
-			if(err<0)
+	if (m->msg_namelen) {
+		if (mode = VERIFY_READ) {
+			err = move_addr_to_kernel(m->msg_name, m->msg_namelen, address);
+			if (err < 0)
 				goto out;
 		}
-
 		m->msg_name = address;
 	} else
 		m->msg_name = NULL;
@@ -1209,7 +1477,7 @@
 	size = m->msg_iovlen * sizeof(struct iovec32);
 	if (copy_from_user(iov, m->msg_iov, size))
 		goto out;
-	m->msg_iov=iov;
+	m->msg_iov = iov;
 
 	err = 0;
 	iov32 = (struct iovec32 *)iov;
@@ -1222,8 +1490,188 @@
 	return err;
 }
 
-extern __inline__ void
-sockfd_put(struct socket *sock)
+static void
+put_cmsg32(struct msghdr *kmsg, int level, int type, int len, void *data)
+{
+	struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control;
+	struct cmsghdr32 cmhdr;
+	int cmlen = CMSG32_LEN(len);
+
+	if(cm = NULL || kmsg->msg_controllen < sizeof(*cm)) {
+		kmsg->msg_flags |= MSG_CTRUNC;
+		return;
+	}
+
+	if(kmsg->msg_controllen < cmlen) {
+		kmsg->msg_flags |= MSG_CTRUNC;
+		cmlen = kmsg->msg_controllen;
+	}
+	cmhdr.cmsg_level = level;
+	cmhdr.cmsg_type = type;
+	cmhdr.cmsg_len = cmlen;
+
+	if(copy_to_user(cm, &cmhdr, sizeof cmhdr))
+		return;
+	if(copy_to_user(CMSG32_DATA(cm), data,
+			cmlen - sizeof(struct cmsghdr32)))
+		return;
+	cmlen = CMSG32_SPACE(len);
+	kmsg->msg_control += cmlen;
+	kmsg->msg_controllen -= cmlen;
+}
+
+static void
+scm_detach_fds32 (struct msghdr *kmsg, struct scm_cookie *scm)
+{
+	struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control;
+	int fdmax = (kmsg->msg_controllen - sizeof(struct cmsghdr32))
+		/ sizeof(int);
+	int fdnum = scm->fp->count;
+	struct file **fp = scm->fp->fp;
+	int *cmfptr;
+	int err = 0, i;
+
+	if (fdnum < fdmax)
+		fdmax = fdnum;
+
+	for (i = 0, cmfptr = (int *) CMSG32_DATA(cm);
+	     i < fdmax;
+	     i++, cmfptr++) {
+		int new_fd;
+		err = get_unused_fd();
+		if (err < 0)
+			break;
+		new_fd = err;
+		err = put_user(new_fd, cmfptr);
+		if (err) {
+			put_unused_fd(new_fd);
+			break;
+		}
+		/* Bump the usage count and install the file. */
+		get_file(fp[i]);
+		current->files->fd[new_fd] = fp[i];
+	}
+
+	if (i > 0) {
+		int cmlen = CMSG32_LEN(i * sizeof(int));
+		if (!err)
+			err = put_user(SOL_SOCKET, &cm->cmsg_level);
+		if (!err)
+			err = put_user(SCM_RIGHTS, &cm->cmsg_type);
+		if (!err)
+			err = put_user(cmlen, &cm->cmsg_len);
+		if (!err) {
+			cmlen = CMSG32_SPACE(i * sizeof(int));
+			kmsg->msg_control += cmlen;
+			kmsg->msg_controllen -= cmlen;
+		}
+	}
+	if (i < fdnum)
+		kmsg->msg_flags |= MSG_CTRUNC;
+
+	/*
+	 * All of the files that fit in the message have had their
+	 * usage counts incremented, so we just free the list.
+	 */
+	__scm_destroy(scm);
+}
+
+/*
+ * In these cases we (currently) can just copy to data over verbatim because all CMSGs
+ * created by the kernel have well defined types which have the same layout in both the
+ * 32-bit and 64-bit API.  One must add some special cased conversions here if we start
+ * sending control messages with incompatible types.
+ *
+ * SCM_RIGHTS and SCM_CREDENTIALS are done by hand in recvmsg32 right after
+ * we do our work.  The remaining cases are:
+ *
+ * SOL_IP	IP_PKTINFO	struct in_pktinfo	32-bit clean
+ *		IP_TTL		int			32-bit clean
+ *		IP_TOS		__u8			32-bit clean
+ *		IP_RECVOPTS	variable length		32-bit clean
+ *		IP_RETOPTS	variable length		32-bit clean
+ *		(these last two are clean because the types are defined
+ *		 by the IPv4 protocol)
+ *		IP_RECVERR	struct sock_extended_err +
+ *				struct sockaddr_in	32-bit clean
+ * SOL_IPV6	IPV6_RECVERR	struct sock_extended_err +
+ *				struct sockaddr_in6	32-bit clean
+ *		IPV6_PKTINFO	struct in6_pktinfo	32-bit clean
+ *		IPV6_HOPLIMIT	int			32-bit clean
+ *		IPV6_FLOWINFO	u32			32-bit clean
+ *		IPV6_HOPOPTS	ipv6 hop exthdr		32-bit clean
+ *		IPV6_DSTOPTS	ipv6 dst exthdr(s)	32-bit clean
+ *		IPV6_RTHDR	ipv6 routing exthdr	32-bit clean
+ *		IPV6_AUTHHDR	ipv6 auth exthdr	32-bit clean
+ */
+static void
+cmsg32_recvmsg_fixup (struct msghdr *kmsg, unsigned long orig_cmsg_uptr)
+{
+	unsigned char *workbuf, *wp;
+	unsigned long bufsz, space_avail;
+	struct cmsghdr *ucmsg;
+	long err;
+
+	bufsz = ((unsigned long)kmsg->msg_control) - orig_cmsg_uptr;
+	space_avail = kmsg->msg_controllen + bufsz;
+	wp = workbuf = kmalloc(bufsz, GFP_KERNEL);
+	if (workbuf = NULL)
+		goto fail;
+
+	/* To make this more sane we assume the kernel sends back properly
+	 * formatted control messages.  Because of how the kernel will truncate
+	 * the cmsg_len for MSG_TRUNC cases, we need not check that case either.
+	 */
+	ucmsg = (struct cmsghdr *) orig_cmsg_uptr;
+	while (((unsigned long)ucmsg) < ((unsigned long)kmsg->msg_control)) {
+		struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp;
+		int clen64, clen32;
+
+		/*
+		 * UCMSG is the 64-bit format CMSG entry in user-space.  KCMSG32 is within
+		 * the kernel space temporary buffer we use to convert into a 32-bit style
+		 * CMSG.
+		 */
+		err = get_user(kcmsg32->cmsg_len, &ucmsg->cmsg_len);
+		err |= get_user(kcmsg32->cmsg_level, &ucmsg->cmsg_level);
+		err |= get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type);
+		if (err)
+			goto fail2;
+
+		clen64 = kcmsg32->cmsg_len;
+		copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),
+			       clen64 - CMSG_ALIGN(sizeof(*ucmsg)));
+		clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +
+			  CMSG32_ALIGN(sizeof(struct cmsghdr32)));
+		kcmsg32->cmsg_len = clen32;
+
+		ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64));
+		wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32));
+	}
+
+	/* Copy back fixed up data, and adjust pointers. */
+	bufsz = (wp - workbuf);
+	if (copy_to_user((void *)orig_cmsg_uptr, workbuf, bufsz))
+		goto fail2;
+
+	kmsg->msg_control = (struct cmsghdr *) (((char *)orig_cmsg_uptr) + bufsz);
+	kmsg->msg_controllen = space_avail - bufsz;
+	kfree(workbuf);
+	return;
+
+  fail2:
+	kfree(workbuf);
+  fail:
+	/*
+	 * If we leave the 64-bit format CMSG chunks in there, the application could get
+	 * confused and crash.  So to ensure greater recovery, we report no CMSGs.
+	 */
+	kmsg->msg_controllen += bufsz;
+	kmsg->msg_control = (void *) orig_cmsg_uptr;
+}
+
+static inline void
+sockfd_put (struct socket *sock)
 {
 	fput(sock->file);
 }
@@ -1234,13 +1682,14 @@
 					   24 for IPv6,
 					   about 80 for AX.25 */
 
-extern struct socket *sockfd_lookup(int fd, int *err);
+extern struct socket *sockfd_lookup (int fd, int *err);
 
 /*
  *	BSD sendmsg interface
  */
 
-int sys32_sendmsg(int fd, struct msghdr32 *msg, unsigned flags)
+int
+sys32_sendmsg (int fd, struct msghdr32 *msg, unsigned flags)
 {
 	struct socket *sock;
 	char address[MAX_SOCK_ADDR];
@@ -1248,10 +1697,11 @@
 	unsigned char ctl[sizeof(struct cmsghdr) + 20];	/* 20 is size of ipv6_pktinfo */
 	unsigned char *ctl_buf = ctl;
 	struct msghdr msg_sys;
-	int err, ctl_len, iov_size, total_len;
+	int err, iov_size, total_len;
+	size_t ctl_len;
 
 	err = -EFAULT;
-	if (shape_msg(&msg_sys, msg))
+	if (get_msghdr32(&msg_sys, msg))
 		goto out;
 
 	sock = sockfd_lookup(fd, &err);
@@ -1282,20 +1732,12 @@
 
 	if (msg_sys.msg_controllen > INT_MAX)
 		goto out_freeiov;
-	ctl_len = msg_sys.msg_controllen;
-	if (ctl_len)
-	{
-		if (ctl_len > sizeof(ctl))
-		{
-			err = -ENOBUFS;
-			ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL);
-			if (ctl_buf = NULL)
-				goto out_freeiov;
-		}
-		err = -EFAULT;
-		if (copy_from_user(ctl_buf, msg_sys.msg_control, ctl_len))
-			goto out_freectl;
-		msg_sys.msg_control = ctl_buf;
+	if (msg_sys.msg_controllen) {
+		ctl_len = sizeof(ctl);
+		err = get_cmsghdr32(&msg_sys, ctl_buf, sock->sk, &ctl_len);
+		if (err)
+			goto out_freeiov;
+		ctl_buf = msg_sys.msg_control;
 	}
 	msg_sys.msg_flags = flags;
 
@@ -1303,7 +1745,6 @@
 		msg_sys.msg_flags |= MSG_DONTWAIT;
 	err = sock_sendmsg(sock, &msg_sys, total_len);
 
-out_freectl:
 	if (ctl_buf != ctl)
 		sock_kfree_s(sock->sk, ctl_buf, ctl_len);
 out_freeiov:
@@ -1328,6 +1769,7 @@
 	struct msghdr msg_sys;
 	unsigned long cmsg_ptr;
 	int err, iov_size, total_len, len;
+	struct scm_cookie scm;
 
 	/* kernel mode address */
 	char addr[MAX_SOCK_ADDR];
@@ -1336,8 +1778,8 @@
 	struct sockaddr *uaddr;
 	int *uaddr_len;
 
-	err=-EFAULT;
-	if (shape_msg(&msg_sys, msg))
+	err = -EFAULT;
+	if (get_msghdr32(&msg_sys, msg))
 		goto out;
 
 	sock = sockfd_lookup(fd, &err);
@@ -1374,13 +1816,42 @@
 
 	if (sock->file->f_flags & O_NONBLOCK)
 		flags |= MSG_DONTWAIT;
-	err = sock_recvmsg(sock, &msg_sys, total_len, flags);
-	if (err < 0)
-		goto out_freeiov;
-	len = err;
 
-	if (uaddr != NULL) {
-		err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len);
+	memset(&scm, 0, sizeof(scm));
+
+	lock_kernel();
+	{
+		err = sock->ops->recvmsg(sock, &msg_sys, total_len, flags, &scm);
+		if (err < 0)
+			goto out_unlock_freeiov;
+
+		len = err;
+		if (!msg_sys.msg_control) {
+			if (sock->passcred || scm.fp)
+				msg_sys.msg_flags |= MSG_CTRUNC;
+			if (scm.fp)
+				__scm_destroy(&scm);
+		} else {
+			/*
+			 * If recvmsg processing itself placed some control messages into
+			 * user space, it's is using 64-bit CMSG processing, so we need to
+			 * fix it up before we tack on more stuff.
+			 */
+			if ((unsigned long) msg_sys.msg_control != cmsg_ptr)
+				cmsg32_recvmsg_fixup(&msg_sys, cmsg_ptr);
+
+			/* Wheee... */
+			if (sock->passcred)
+				put_cmsg32(&msg_sys, SOL_SOCKET, SCM_CREDENTIALS,
+					   sizeof(scm.creds), &scm.creds);
+			if (scm.fp != NULL)
+				scm_detach_fds32(&msg_sys, &scm);
+		}
+	}
+	unlock_kernel();
+
+	if (uaddr != NULL) {
+		err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len);
 		if (err < 0)
 			goto out_freeiov;
 	}
@@ -1393,20 +1864,23 @@
 		goto out_freeiov;
 	err = len;
 
-out_freeiov:
+  out_freeiov:
 	if (iov != iovstack)
 		sock_kfree_s(sock->sk, iov, iov_size);
-out_put:
+  out_put:
 	sockfd_put(sock);
-out:
+  out:
 	return err;
+
+  out_unlock_freeiov:
+	goto out_freeiov;
 }
 
 /* Argument list sizes for sys_socketcall */
 #define AL(x) ((x) * sizeof(u32))
-static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
-				AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
-				AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};
+static const unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
+				    AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
+				    AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};
 #undef AL
 
 extern asmlinkage long sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
@@ -1435,7 +1909,8 @@
 extern asmlinkage long sys_shutdown(int fd, int how);
 extern asmlinkage long sys_listen(int fd, int backlog);
 
-asmlinkage long sys32_socketcall(int call, u32 *args)
+asmlinkage long
+sys32_socketcall (int call, u32 *args)
 {
 	int ret;
 	u32 a[6];
@@ -1463,16 +1938,13 @@
 			ret = sys_listen(a0, a1);
 			break;
 		case SYS_ACCEPT:
-			ret = sys_accept(a0, (struct sockaddr *)A(a1),
-					  (int *)A(a[2]));
+			ret = sys_accept(a0, (struct sockaddr *)A(a1), (int *)A(a[2]));
 			break;
 		case SYS_GETSOCKNAME:
-			ret = sys_getsockname(a0, (struct sockaddr *)A(a1),
-					       (int *)A(a[2]));
+			ret = sys_getsockname(a0, (struct sockaddr *)A(a1), (int *)A(a[2]));
 			break;
 		case SYS_GETPEERNAME:
-			ret = sys_getpeername(a0, (struct sockaddr *)A(a1),
-					       (int *)A(a[2]));
+			ret = sys_getpeername(a0, (struct sockaddr *)A(a1), (int *)A(a[2]));
 			break;
 		case SYS_SOCKETPAIR:
 			ret = sys_socketpair(a0, a1, a[2], (int *)A(a[3]));
@@ -1500,12 +1972,10 @@
 			ret = sys_getsockopt(a0, a1, a[2], a[3], a[4]);
 			break;
 		case SYS_SENDMSG:
-			ret = sys32_sendmsg(a0, (struct msghdr32 *)A(a1),
-					     a[2]);
+			ret = sys32_sendmsg(a0, (struct msghdr32 *) A(a1), a[2]);
 			break;
 		case SYS_RECVMSG:
-			ret = sys32_recvmsg(a0, (struct msghdr32 *)A(a1),
-					     a[2]);
+			ret = sys32_recvmsg(a0, (struct msghdr32 *) A(a1), a[2]);
 			break;
 		default:
 			ret = EINVAL;
@@ -1522,15 +1992,28 @@
 
 struct msgbuf32 { s32 mtype; char mtext[1]; };
 
-struct ipc_perm32
-{
-	key_t	  key;
-	__kernel_uid_t32  uid;
-	__kernel_gid_t32  gid;
-	__kernel_uid_t32  cuid;
-	__kernel_gid_t32  cgid;
+struct ipc_perm32 {
+	key_t key;
+	__kernel_uid_t32 uid;
+	__kernel_gid_t32 gid;
+	__kernel_uid_t32 cuid;
+	__kernel_gid_t32 cgid;
+	__kernel_mode_t32 mode;
+	unsigned short seq;
+};
+
+struct ipc64_perm32 {
+	key_t key;
+	__kernel_uid32_t32 uid;
+	__kernel_gid32_t32 gid;
+	__kernel_uid32_t32 cuid;
+	__kernel_gid32_t32 cgid;
 	__kernel_mode_t32 mode;
-	unsigned short  seq;
+	unsigned short __pad1;
+	unsigned short seq;
+	unsigned short __pad2;
+	unsigned int unused1;
+	unsigned int unused2;
 };
 
 struct semid_ds32 {
@@ -1544,8 +2027,18 @@
 	unsigned short  sem_nsems;              /* no. of semaphores in array */
 };
 
-struct msqid_ds32
-{
+struct semid64_ds32 {
+	struct ipc64_perm32 sem_perm;
+	__kernel_time_t32 sem_otime;
+	unsigned int __unused1;
+	__kernel_time_t32 sem_ctime;
+	unsigned int __unused2;
+	unsigned int sem_nsems;
+	unsigned int __unused3;
+	unsigned int __unused4;
+};
+
+struct msqid_ds32 {
 	struct ipc_perm32 msg_perm;
 	u32 msg_first;
 	u32 msg_last;
@@ -1561,110 +2054,206 @@
 	__kernel_ipc_pid_t32 msg_lrpid;
 };
 
+struct msqid64_ds32 {
+	struct ipc64_perm32 msg_perm;
+	__kernel_time_t32 msg_stime;
+	unsigned int __unused1;
+	__kernel_time_t32 msg_rtime;
+	unsigned int __unused2;
+	__kernel_time_t32 msg_ctime;
+	unsigned int __unused3;
+	unsigned int msg_cbytes;
+	unsigned int msg_qnum;
+	unsigned int msg_qbytes;
+	__kernel_pid_t32 msg_lspid;
+	__kernel_pid_t32 msg_lrpid;
+	unsigned int __unused4;
+	unsigned int __unused5;
+};
+
 struct shmid_ds32 {
-	struct ipc_perm32       shm_perm;
-	int                     shm_segsz;
-	__kernel_time_t32       shm_atime;
-	__kernel_time_t32       shm_dtime;
-	__kernel_time_t32       shm_ctime;
-	__kernel_ipc_pid_t32    shm_cpid;
-	__kernel_ipc_pid_t32    shm_lpid;
-	unsigned short          shm_nattch;
+	struct ipc_perm32 shm_perm;
+	int shm_segsz;
+	__kernel_time_t32 shm_atime;
+	__kernel_time_t32 shm_dtime;
+	__kernel_time_t32 shm_ctime;
+	__kernel_ipc_pid_t32 shm_cpid;
+	__kernel_ipc_pid_t32 shm_lpid;
+	unsigned short shm_nattch;
+};
+
+struct shmid64_ds32 {
+	struct ipc64_perm shm_perm;
+	__kernel_size_t32 shm_segsz;
+	__kernel_time_t32 shm_atime;
+	unsigned int __unused1;
+	__kernel_time_t32 shm_dtime;
+	unsigned int __unused2;
+	__kernel_time_t32 shm_ctime;
+	unsigned int __unused3;
+	__kernel_pid_t32 shm_cpid;
+	__kernel_pid_t32 shm_lpid;
+	unsigned int shm_nattch;
+	unsigned int __unused4;
+	unsigned int __unused5;
+};
+
+struct shminfo64_32 {
+	unsigned int shmmax;
+	unsigned int shmmin;
+	unsigned int shmmni;
+	unsigned int shmseg;
+	unsigned int shmall;
+	unsigned int __unused1;
+	unsigned int __unused2;
+	unsigned int __unused3;
+	unsigned int __unused4;
 };
 
+struct shm_info32 {
+	int used_ids;
+	u32 shm_tot, shm_rss, shm_swp;
+	u32 swap_attempts, swap_successes;
+};
+
+struct ipc_kludge {
+	struct msgbuf *msgp;
+	long msgtyp;
+};
+
+#define SEMOP		 1
+#define SEMGET		 2
+#define SEMCTL		 3
+#define MSGSND		11
+#define MSGRCV		12
+#define MSGGET		13
+#define MSGCTL		14
+#define SHMAT		21
+#define SHMDT		22
+#define SHMGET		23
+#define SHMCTL		24
+
 #define IPCOP_MASK(__x)	(1UL << (__x))
 
 static int
-do_sys32_semctl(int first, int second, int third, void *uptr)
+ipc_parse_version32 (int *cmd)
+{
+	if (*cmd & IPC_64) {
+		*cmd ^= IPC_64;
+		return IPC_64;
+	} else {
+		return IPC_OLD;
+	}
+}
+
+static int
+semctl32 (int first, int second, int third, void *uptr)
 {
 	union semun fourth;
 	u32 pad;
 	int err = 0, err2;
 	struct semid64_ds s;
-	struct semid_ds32 *usp;
 	mm_segment_t old_fs;
+	int version = ipc_parse_version32(&third);
 
 	if (!uptr)
 		return -EINVAL;
 	if (get_user(pad, (u32 *)uptr))
 		return -EFAULT;
-	if(third = SETVAL)
+	if (third = SETVAL)
 		fourth.val = (int)pad;
 	else
 		fourth.__pad = (void *)A(pad);
 	switch (third) {
-
-	case IPC_INFO:
-	case IPC_RMID:
-	case IPC_SET:
-	case SEM_INFO:
-	case GETVAL:
-	case GETPID:
-	case GETNCNT:
-	case GETZCNT:
-	case GETALL:
-	case SETVAL:
-	case SETALL:
-		err = sys_semctl (first, second, third, fourth);
+	      case IPC_INFO:
+	      case IPC_RMID:
+	      case IPC_SET:
+	      case SEM_INFO:
+	      case GETVAL:
+	      case GETPID:
+	      case GETNCNT:
+	      case GETZCNT:
+	      case GETALL:
+	      case SETVAL:
+	      case SETALL:
+		err = sys_semctl(first, second, third, fourth);
 		break;
 
-	case IPC_STAT:
-	case SEM_STAT:
-		usp = (struct semid_ds32 *)A(pad);
+	      case IPC_STAT:
+	      case SEM_STAT:
 		fourth.__pad = &s;
-		old_fs = get_fs ();
-		set_fs (KERNEL_DS);
-		err = sys_semctl (first, second, third, fourth);
-		set_fs (old_fs);
-		err2 = put_user(s.sem_perm.key, &usp->sem_perm.key);
-		err2 |= __put_user(s.sem_perm.uid, &usp->sem_perm.uid);
-		err2 |= __put_user(s.sem_perm.gid, &usp->sem_perm.gid);
-		err2 |= __put_user(s.sem_perm.cuid,
-				   &usp->sem_perm.cuid);
-		err2 |= __put_user (s.sem_perm.cgid,
-				    &usp->sem_perm.cgid);
-		err2 |= __put_user (s.sem_perm.mode,
-				    &usp->sem_perm.mode);
-		err2 |= __put_user (s.sem_perm.seq, &usp->sem_perm.seq);
-		err2 |= __put_user (s.sem_otime, &usp->sem_otime);
-		err2 |= __put_user (s.sem_ctime, &usp->sem_ctime);
-		err2 |= __put_user (s.sem_nsems, &usp->sem_nsems);
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_semctl(first, second, third, fourth);
+		set_fs(old_fs);
+
+		if (version = IPC_64) {
+			struct semid64_ds32 *usp64 = (struct semid64_ds32 *) A(pad);
+
+			if (!access_ok(VERIFY_WRITE, usp64, sizeof(*usp64))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(s.sem_perm.key, &usp64->sem_perm.key);
+			err2 |= __put_user(s.sem_perm.uid, &usp64->sem_perm.uid);
+			err2 |= __put_user(s.sem_perm.gid, &usp64->sem_perm.gid);
+			err2 |= __put_user(s.sem_perm.cuid, &usp64->sem_perm.cuid);
+			err2 |= __put_user(s.sem_perm.cgid, &usp64->sem_perm.cgid);
+			err2 |= __put_user(s.sem_perm.mode, &usp64->sem_perm.mode);
+			err2 |= __put_user(s.sem_perm.seq, &usp64->sem_perm.seq);
+			err2 |= __put_user(s.sem_otime, &usp64->sem_otime);
+			err2 |= __put_user(s.sem_ctime, &usp64->sem_ctime);
+			err2 |= __put_user(s.sem_nsems, &usp64->sem_nsems);
+		} else {
+			struct semid_ds32 *usp32 = (struct semid_ds32 *) A(pad);
+
+			if (!access_ok(VERIFY_WRITE, usp32, sizeof(*usp32))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(s.sem_perm.key, &usp32->sem_perm.key);
+			err2 |= __put_user(s.sem_perm.uid, &usp32->sem_perm.uid);
+			err2 |= __put_user(s.sem_perm.gid, &usp32->sem_perm.gid);
+			err2 |= __put_user(s.sem_perm.cuid, &usp32->sem_perm.cuid);
+			err2 |= __put_user(s.sem_perm.cgid, &usp32->sem_perm.cgid);
+			err2 |= __put_user(s.sem_perm.mode, &usp32->sem_perm.mode);
+			err2 |= __put_user(s.sem_perm.seq, &usp32->sem_perm.seq);
+			err2 |= __put_user(s.sem_otime, &usp32->sem_otime);
+			err2 |= __put_user(s.sem_ctime, &usp32->sem_ctime);
+			err2 |= __put_user(s.sem_nsems, &usp32->sem_nsems);
+		}
 		if (err2)
-			err = -EFAULT;
+		    err = -EFAULT;
 		break;
-
 	}
-
 	return err;
 }
 
 static int
 do_sys32_msgsnd (int first, int second, int third, void *uptr)
 {
-	struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf)
-				    + 4, GFP_USER);
+	struct msgbuf *p = kmalloc(second + sizeof(struct msgbuf) + 4, GFP_USER);
 	struct msgbuf32 *up = (struct msgbuf32 *)uptr;
 	mm_segment_t old_fs;
 	int err;
 
 	if (!p)
 		return -ENOMEM;
-	err = get_user (p->mtype, &up->mtype);
-	err |= __copy_from_user (p->mtext, &up->mtext, second);
+	err = get_user(p->mtype, &up->mtype);
+	err |= copy_from_user(p->mtext, &up->mtext, second);
 	if (err)
 		goto out;
-	old_fs = get_fs ();
-	set_fs (KERNEL_DS);
-	err = sys_msgsnd (first, p, second, third);
-	set_fs (old_fs);
-out:
-	kfree (p);
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_msgsnd(first, p, second, third);
+	set_fs(old_fs);
+  out:
+	kfree(p);
 	return err;
 }
 
 static int
-do_sys32_msgrcv (int first, int second, int msgtyp, int third,
-		 int version, void *uptr)
+do_sys32_msgrcv (int first, int second, int msgtyp, int third, int version, void *uptr)
 {
 	struct msgbuf32 *up;
 	struct msgbuf *p;
@@ -1679,185 +2268,281 @@
 		if (!uptr)
 			goto out;
 		err = -EFAULT;
-		if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge)))
+		if (copy_from_user(&ipck, uipck, sizeof(struct ipc_kludge)))
 			goto out;
 		uptr = (void *)A(ipck.msgp);
 		msgtyp = ipck.msgtyp;
 	}
 	err = -ENOMEM;
-	p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER);
+	p = kmalloc(second + sizeof(struct msgbuf) + 4, GFP_USER);
 	if (!p)
 		goto out;
-	old_fs = get_fs ();
-	set_fs (KERNEL_DS);
-	err = sys_msgrcv (first, p, second + 4, msgtyp, third);
-	set_fs (old_fs);
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_msgrcv(first, p, second + 4, msgtyp, third);
+	set_fs(old_fs);
 	if (err < 0)
 		goto free_then_out;
 	up = (struct msgbuf32 *)uptr;
-	if (put_user (p->mtype, &up->mtype) ||
-	    __copy_to_user (&up->mtext, p->mtext, err))
+	if (put_user(p->mtype, &up->mtype) || copy_to_user(&up->mtext, p->mtext, err))
 		err = -EFAULT;
 free_then_out:
-	kfree (p);
+	kfree(p);
 out:
 	return err;
 }
 
 static int
-do_sys32_msgctl (int first, int second, void *uptr)
+msgctl32 (int first, int second, void *uptr)
 {
 	int err = -EINVAL, err2;
 	struct msqid_ds m;
 	struct msqid64_ds m64;
-	struct msqid_ds32 *up = (struct msqid_ds32 *)uptr;
+	struct msqid_ds32 *up32 = (struct msqid_ds32 *)uptr;
+	struct msqid64_ds32 *up64 = (struct msqid64_ds32 *)uptr;
 	mm_segment_t old_fs;
+	int version = ipc_parse_version32(&second);
 
 	switch (second) {
-
-	case IPC_INFO:
-	case IPC_RMID:
-	case MSG_INFO:
-		err = sys_msgctl (first, second, (struct msqid_ds *)uptr);
-		break;
-
-	case IPC_SET:
-		err = get_user (m.msg_perm.uid, &up->msg_perm.uid);
-		err |= __get_user (m.msg_perm.gid, &up->msg_perm.gid);
-		err |= __get_user (m.msg_perm.mode, &up->msg_perm.mode);
-		err |= __get_user (m.msg_qbytes, &up->msg_qbytes);
+	      case IPC_INFO:
+	      case IPC_RMID:
+	      case MSG_INFO:
+		err = sys_msgctl(first, second, (struct msqid_ds *)uptr);
+		break;
+
+	      case IPC_SET:
+		if (version = IPC_64) {
+			err = get_user(m.msg_perm.uid, &up64->msg_perm.uid);
+			err |= get_user(m.msg_perm.gid, &up64->msg_perm.gid);
+			err |= get_user(m.msg_perm.mode, &up64->msg_perm.mode);
+			err |= get_user(m.msg_qbytes, &up64->msg_qbytes);
+		} else {
+			err = get_user(m.msg_perm.uid, &up32->msg_perm.uid);
+			err |= get_user(m.msg_perm.gid, &up32->msg_perm.gid);
+			err |= get_user(m.msg_perm.mode, &up32->msg_perm.mode);
+			err |= get_user(m.msg_qbytes, &up32->msg_qbytes);
+		}
 		if (err)
 			break;
-		old_fs = get_fs ();
-		set_fs (KERNEL_DS);
-		err = sys_msgctl (first, second, &m);
-		set_fs (old_fs);
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_msgctl(first, second, &m);
+		set_fs(old_fs);
 		break;
 
-	case IPC_STAT:
-	case MSG_STAT:
-		old_fs = get_fs ();
-		set_fs (KERNEL_DS);
-		err = sys_msgctl (first, second, (void *) &m64);
-		set_fs (old_fs);
-		err2 = put_user (m64.msg_perm.key, &up->msg_perm.key);
-		err2 |= __put_user(m64.msg_perm.uid, &up->msg_perm.uid);
-		err2 |= __put_user(m64.msg_perm.gid, &up->msg_perm.gid);
-		err2 |= __put_user(m64.msg_perm.cuid, &up->msg_perm.cuid);
-		err2 |= __put_user(m64.msg_perm.cgid, &up->msg_perm.cgid);
-		err2 |= __put_user(m64.msg_perm.mode, &up->msg_perm.mode);
-		err2 |= __put_user(m64.msg_perm.seq, &up->msg_perm.seq);
-		err2 |= __put_user(m64.msg_stime, &up->msg_stime);
-		err2 |= __put_user(m64.msg_rtime, &up->msg_rtime);
-		err2 |= __put_user(m64.msg_ctime, &up->msg_ctime);
-		err2 |= __put_user(m64.msg_cbytes, &up->msg_cbytes);
-		err2 |= __put_user(m64.msg_qnum, &up->msg_qnum);
-		err2 |= __put_user(m64.msg_qbytes, &up->msg_qbytes);
-		err2 |= __put_user(m64.msg_lspid, &up->msg_lspid);
-		err2 |= __put_user(m64.msg_lrpid, &up->msg_lrpid);
-		if (err2)
-			err = -EFAULT;
-		break;
+	      case IPC_STAT:
+	      case MSG_STAT:
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_msgctl(first, second, (void *) &m64);
+		set_fs(old_fs);
 
+		if (version = IPC_64) {
+			if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(m64.msg_perm.key, &up64->msg_perm.key);
+			err2 |= __put_user(m64.msg_perm.uid, &up64->msg_perm.uid);
+			err2 |= __put_user(m64.msg_perm.gid, &up64->msg_perm.gid);
+			err2 |= __put_user(m64.msg_perm.cuid, &up64->msg_perm.cuid);
+			err2 |= __put_user(m64.msg_perm.cgid, &up64->msg_perm.cgid);
+			err2 |= __put_user(m64.msg_perm.mode, &up64->msg_perm.mode);
+			err2 |= __put_user(m64.msg_perm.seq, &up64->msg_perm.seq);
+			err2 |= __put_user(m64.msg_stime, &up64->msg_stime);
+			err2 |= __put_user(m64.msg_rtime, &up64->msg_rtime);
+			err2 |= __put_user(m64.msg_ctime, &up64->msg_ctime);
+			err2 |= __put_user(m64.msg_cbytes, &up64->msg_cbytes);
+			err2 |= __put_user(m64.msg_qnum, &up64->msg_qnum);
+			err2 |= __put_user(m64.msg_qbytes, &up64->msg_qbytes);
+			err2 |= __put_user(m64.msg_lspid, &up64->msg_lspid);
+			err2 |= __put_user(m64.msg_lrpid, &up64->msg_lrpid);
+			if (err2)
+				err = -EFAULT;
+		} else {
+			if (!access_ok(VERIFY_WRITE, up32, sizeof(*up32))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(m64.msg_perm.key, &up32->msg_perm.key);
+			err2 |= __put_user(m64.msg_perm.uid, &up32->msg_perm.uid);
+			err2 |= __put_user(m64.msg_perm.gid, &up32->msg_perm.gid);
+			err2 |= __put_user(m64.msg_perm.cuid, &up32->msg_perm.cuid);
+			err2 |= __put_user(m64.msg_perm.cgid, &up32->msg_perm.cgid);
+			err2 |= __put_user(m64.msg_perm.mode, &up32->msg_perm.mode);
+			err2 |= __put_user(m64.msg_perm.seq, &up32->msg_perm.seq);
+			err2 |= __put_user(m64.msg_stime, &up32->msg_stime);
+			err2 |= __put_user(m64.msg_rtime, &up32->msg_rtime);
+			err2 |= __put_user(m64.msg_ctime, &up32->msg_ctime);
+			err2 |= __put_user(m64.msg_cbytes, &up32->msg_cbytes);
+			err2 |= __put_user(m64.msg_qnum, &up32->msg_qnum);
+			err2 |= __put_user(m64.msg_qbytes, &up32->msg_qbytes);
+			err2 |= __put_user(m64.msg_lspid, &up32->msg_lspid);
+			err2 |= __put_user(m64.msg_lrpid, &up32->msg_lrpid);
+			if (err2)
+				err = -EFAULT;
+		}
+		break;
 	}
-
 	return err;
 }
 
 static int
-do_sys32_shmat (int first, int second, int third, int version, void *uptr)
+shmat32 (int first, int second, int third, int version, void *uptr)
 {
 	unsigned long raddr;
 	u32 *uaddr = (u32 *)A((u32)third);
 	int err;
 
 	if (version = 1)
-		return -EINVAL;
-	err = sys_shmat (first, uptr, second, &raddr);
+		return -EINVAL;	/* iBCS2 emulator entry point: unsupported */
+	err = sys_shmat(first, uptr, second, &raddr);
 	if (err)
 		return err;
 	return put_user(raddr, uaddr);
 }
 
 static int
-do_sys32_shmctl (int first, int second, void *uptr)
+shmctl32 (int first, int second, void *uptr)
 {
 	int err = -EFAULT, err2;
 	struct shmid_ds s;
 	struct shmid64_ds s64;
-	struct shmid_ds32 *up = (struct shmid_ds32 *)uptr;
+	struct shmid_ds32 *up32 = (struct shmid_ds32 *)uptr;
+	struct shmid64_ds32 *up64 = (struct shmid64_ds32 *)uptr;
 	mm_segment_t old_fs;
-	struct shm_info32 {
-		int used_ids;
-		u32 shm_tot, shm_rss, shm_swp;
-		u32 swap_attempts, swap_successes;
-	} *uip = (struct shm_info32 *)uptr;
+	struct shm_info32 *uip = (struct shm_info32 *)uptr;
 	struct shm_info si;
+	int version = ipc_parse_version32(&second);
+	struct shminfo64 smi;
+	struct shminfo *usi32 = (struct shminfo *) uptr;
+	struct shminfo64_32 *usi64 = (struct shminfo64_32 *) uptr;
 
 	switch (second) {
+	      case IPC_INFO:
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_shmctl(first, second, (struct shmid_ds *)&smi);
+		set_fs(old_fs);
+
+		if (version = IPC_64) {
+			if (!access_ok(VERIFY_WRITE, usi64, sizeof(*usi64))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(smi.shmmax, &usi64->shmmax);
+			err2 |= __put_user(smi.shmmin, &usi64->shmmin);
+			err2 |= __put_user(smi.shmmni, &usi64->shmmni);
+			err2 |= __put_user(smi.shmseg, &usi64->shmseg);
+			err2 |= __put_user(smi.shmall, &usi64->shmall);
+		} else {
+			if (!access_ok(VERIFY_WRITE, usi32, sizeof(*usi32))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(smi.shmmax, &usi32->shmmax);
+			err2 |= __put_user(smi.shmmin, &usi32->shmmin);
+			err2 |= __put_user(smi.shmmni, &usi32->shmmni);
+			err2 |= __put_user(smi.shmseg, &usi32->shmseg);
+			err2 |= __put_user(smi.shmall, &usi32->shmall);
+		}
+		if (err2)
+			err = -EFAULT;
+		break;
 
-	case IPC_INFO:
-	case IPC_RMID:
-	case SHM_LOCK:
-	case SHM_UNLOCK:
-		err = sys_shmctl (first, second, (struct shmid_ds *)uptr);
+	      case IPC_RMID:
+	      case SHM_LOCK:
+	      case SHM_UNLOCK:
+		err = sys_shmctl(first, second, (struct shmid_ds *)uptr);
 		break;
-	case IPC_SET:
-		err = get_user (s.shm_perm.uid, &up->shm_perm.uid);
-		err |= __get_user (s.shm_perm.gid, &up->shm_perm.gid);
-		err |= __get_user (s.shm_perm.mode, &up->shm_perm.mode);
+
+	      case IPC_SET:
+		if (version = IPC_64) {
+			err = get_user(s.shm_perm.uid, &up64->shm_perm.uid);
+			err |= get_user(s.shm_perm.gid, &up64->shm_perm.gid);
+			err |= get_user(s.shm_perm.mode, &up64->shm_perm.mode);
+		} else {
+			err = get_user(s.shm_perm.uid, &up32->shm_perm.uid);
+			err |= get_user(s.shm_perm.gid, &up32->shm_perm.gid);
+			err |= get_user(s.shm_perm.mode, &up32->shm_perm.mode);
+		}
 		if (err)
 			break;
-		old_fs = get_fs ();
-		set_fs (KERNEL_DS);
-		err = sys_shmctl (first, second, &s);
-		set_fs (old_fs);
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_shmctl(first, second, &s);
+		set_fs(old_fs);
 		break;
 
-	case IPC_STAT:
-	case SHM_STAT:
-		old_fs = get_fs ();
-		set_fs (KERNEL_DS);
-		err = sys_shmctl (first, second, (void *) &s64);
-		set_fs (old_fs);
+	      case IPC_STAT:
+	      case SHM_STAT:
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_shmctl(first, second, (void *) &s64);
+		set_fs(old_fs);
 		if (err < 0)
 			break;
-		err2 = put_user (s64.shm_perm.key, &up->shm_perm.key);
-		err2 |= __put_user (s64.shm_perm.uid, &up->shm_perm.uid);
-		err2 |= __put_user (s64.shm_perm.gid, &up->shm_perm.gid);
-		err2 |= __put_user (s64.shm_perm.cuid,
-				    &up->shm_perm.cuid);
-		err2 |= __put_user (s64.shm_perm.cgid,
-				    &up->shm_perm.cgid);
-		err2 |= __put_user (s64.shm_perm.mode,
-				    &up->shm_perm.mode);
-		err2 |= __put_user (s64.shm_perm.seq, &up->shm_perm.seq);
-		err2 |= __put_user (s64.shm_atime, &up->shm_atime);
-		err2 |= __put_user (s64.shm_dtime, &up->shm_dtime);
-		err2 |= __put_user (s64.shm_ctime, &up->shm_ctime);
-		err2 |= __put_user (s64.shm_segsz, &up->shm_segsz);
-		err2 |= __put_user (s64.shm_nattch, &up->shm_nattch);
-		err2 |= __put_user (s64.shm_cpid, &up->shm_cpid);
-		err2 |= __put_user (s64.shm_lpid, &up->shm_lpid);
+		if (version = IPC_64) {
+			if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(s64.shm_perm.key, &up64->shm_perm.key);
+			err2 |= __put_user(s64.shm_perm.uid, &up64->shm_perm.uid);
+			err2 |= __put_user(s64.shm_perm.gid, &up64->shm_perm.gid);
+			err2 |= __put_user(s64.shm_perm.cuid, &up64->shm_perm.cuid);
+			err2 |= __put_user(s64.shm_perm.cgid, &up64->shm_perm.cgid);
+			err2 |= __put_user(s64.shm_perm.mode, &up64->shm_perm.mode);
+			err2 |= __put_user(s64.shm_perm.seq, &up64->shm_perm.seq);
+			err2 |= __put_user(s64.shm_atime, &up64->shm_atime);
+			err2 |= __put_user(s64.shm_dtime, &up64->shm_dtime);
+			err2 |= __put_user(s64.shm_ctime, &up64->shm_ctime);
+			err2 |= __put_user(s64.shm_segsz, &up64->shm_segsz);
+			err2 |= __put_user(s64.shm_nattch, &up64->shm_nattch);
+			err2 |= __put_user(s64.shm_cpid, &up64->shm_cpid);
+			err2 |= __put_user(s64.shm_lpid, &up64->shm_lpid);
+		} else {
+			if (!access_ok(VERIFY_WRITE, up32, sizeof(*up32))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(s64.shm_perm.key, &up32->shm_perm.key);
+			err2 |= __put_user(s64.shm_perm.uid, &up32->shm_perm.uid);
+			err2 |= __put_user(s64.shm_perm.gid, &up32->shm_perm.gid);
+			err2 |= __put_user(s64.shm_perm.cuid, &up32->shm_perm.cuid);
+			err2 |= __put_user(s64.shm_perm.cgid, &up32->shm_perm.cgid);
+			err2 |= __put_user(s64.shm_perm.mode, &up32->shm_perm.mode);
+			err2 |= __put_user(s64.shm_perm.seq, &up32->shm_perm.seq);
+			err2 |= __put_user(s64.shm_atime, &up32->shm_atime);
+			err2 |= __put_user(s64.shm_dtime, &up32->shm_dtime);
+			err2 |= __put_user(s64.shm_ctime, &up32->shm_ctime);
+			err2 |= __put_user(s64.shm_segsz, &up32->shm_segsz);
+			err2 |= __put_user(s64.shm_nattch, &up32->shm_nattch);
+			err2 |= __put_user(s64.shm_cpid, &up32->shm_cpid);
+			err2 |= __put_user(s64.shm_lpid, &up32->shm_lpid);
+		}
 		if (err2)
 			err = -EFAULT;
 		break;
 
-	case SHM_INFO:
-		old_fs = get_fs ();
-		set_fs (KERNEL_DS);
-		err = sys_shmctl (first, second, (void *)&si);
-		set_fs (old_fs);
+	      case SHM_INFO:
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_shmctl(first, second, (void *)&si);
+		set_fs(old_fs);
 		if (err < 0)
 			break;
-		err2 = put_user (si.used_ids, &uip->used_ids);
-		err2 |= __put_user (si.shm_tot, &uip->shm_tot);
-		err2 |= __put_user (si.shm_rss, &uip->shm_rss);
-		err2 |= __put_user (si.shm_swp, &uip->shm_swp);
-		err2 |= __put_user (si.swap_attempts,
-				    &uip->swap_attempts);
-		err2 |= __put_user (si.swap_successes,
-				    &uip->swap_successes);
+
+		if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip))) {
+			err = -EFAULT;
+			break;
+		}
+		err2 = __put_user(si.used_ids, &uip->used_ids);
+		err2 |= __put_user(si.shm_tot, &uip->shm_tot);
+		err2 |= __put_user(si.shm_rss, &uip->shm_rss);
+		err2 |= __put_user(si.shm_swp, &uip->shm_swp);
+		err2 |= __put_user(si.swap_attempts, &uip->swap_attempts);
+		err2 |= __put_user(si.swap_successes, &uip->swap_successes);
 		if (err2)
 			err = -EFAULT;
 		break;
@@ -1869,59 +2554,42 @@
 asmlinkage long
 sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth)
 {
-	int version, err;
+	int version;
 
 	version = call >> 16; /* hack for backward compatibility */
 	call &= 0xffff;
 
 	switch (call) {
-
-	case SEMOP:
+	      case SEMOP:
 		/* struct sembuf is the same on 32 and 64bit :)) */
-		err = sys_semop (first, (struct sembuf *)AA(ptr),
-				 second);
-		break;
-	case SEMGET:
-		err = sys_semget (first, second, third);
-		break;
-	case SEMCTL:
-		err = do_sys32_semctl (first, second, third,
-				       (void *)AA(ptr));
-		break;
-
-	case MSGSND:
-		err = do_sys32_msgsnd (first, second, third,
-				       (void *)AA(ptr));
-		break;
-	case MSGRCV:
-		err = do_sys32_msgrcv (first, second, fifth, third,
-				       version, (void *)AA(ptr));
-		break;
-	case MSGGET:
-		err = sys_msgget ((key_t) first, second);
-		break;
-	case MSGCTL:
-		err = do_sys32_msgctl (first, second, (void *)AA(ptr));
-		break;
+		return sys_semop(first, (struct sembuf *)AA(ptr), second);
+	      case SEMGET:
+		return sys_semget(first, second, third);
+	      case SEMCTL:
+		return semctl32(first, second, third, (void *)AA(ptr));
+
+	      case MSGSND:
+		return do_sys32_msgsnd(first, second, third, (void *)AA(ptr));
+	      case MSGRCV:
+		return do_sys32_msgrcv(first, second, fifth, third, version, (void *)AA(ptr));
+	      case MSGGET:
+		return sys_msgget((key_t) first, second);
+	      case MSGCTL:
+		return msgctl32(first, second, (void *)AA(ptr));
+
+	      case SHMAT:
+		return shmat32(first, second, third, version, (void *)AA(ptr));
+		break;
+	      case SHMDT:
+		return sys_shmdt((char *)AA(ptr));
+	      case SHMGET:
+		return sys_shmget(first, second, third);
+	      case SHMCTL:
+		return shmctl32(first, second, (void *)AA(ptr));
 
-	case SHMAT:
-		err = do_sys32_shmat (first, second, third, version, (void *)AA(ptr));
-		break;
-	case SHMDT:
-		err = sys_shmdt ((char *)AA(ptr));
-		break;
-	case SHMGET:
-		err = sys_shmget (first, second, third);
-		break;
-	case SHMCTL:
-		err = do_sys32_shmctl (first, second, (void *)AA(ptr));
-		break;
-	default:
-		err = -EINVAL;
-		break;
+	      default:
+		return -EINVAL;
 	}
-
-	return err;
 }
 
 /*
@@ -1929,7 +2597,8 @@
  * sys_gettimeofday().  IA64 did this but i386 Linux did not
  * so we have to implement this system call here.
  */
-asmlinkage long sys32_time(int * tloc)
+asmlinkage long
+sys32_time (int *tloc)
 {
 	int i;
 
@@ -1937,7 +2606,7 @@
 	   stuff it to user space. No side effects */
 	i = CURRENT_TIME;
 	if (tloc) {
-		if (put_user(i,tloc))
+		if (put_user(i, tloc))
 			i = -EFAULT;
 	}
 	return i;
@@ -1967,7 +2636,10 @@
 {
 	int err;
 
-	err = put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec);
+	if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru)))
+		return -EFAULT;
+
+	err = __put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec);
 	err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec);
 	err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec);
 	err |= __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec);
@@ -1989,8 +2661,7 @@
 }
 
 asmlinkage long
-sys32_wait4(__kernel_pid_t32 pid, unsigned int *stat_addr, int options,
-	    struct rusage32 *ru)
+sys32_wait4 (int pid, unsigned int *stat_addr, int options, struct rusage32 *ru)
 {
 	if (!ru)
 		return sys_wait4(pid, stat_addr, options, NULL);
@@ -2000,37 +2671,38 @@
 		unsigned int status;
 		mm_segment_t old_fs = get_fs();
 
-		set_fs (KERNEL_DS);
+		set_fs(KERNEL_DS);
 		ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r);
-		set_fs (old_fs);
-		if (put_rusage (ru, &r)) return -EFAULT;
-		if (stat_addr && put_user (status, stat_addr))
+		set_fs(old_fs);
+		if (put_rusage(ru, &r))
+			return -EFAULT;
+		if (stat_addr && put_user(status, stat_addr))
 			return -EFAULT;
 		return ret;
 	}
 }
 
 asmlinkage long
-sys32_waitpid(__kernel_pid_t32 pid, unsigned int *stat_addr, int options)
+sys32_waitpid (int pid, unsigned int *stat_addr, int options)
 {
 	return sys32_wait4(pid, stat_addr, options, NULL);
 }
 
 
-extern asmlinkage long
-sys_getrusage(int who, struct rusage *ru);
+extern asmlinkage long sys_getrusage (int who, struct rusage *ru);
 
 asmlinkage long
-sys32_getrusage(int who, struct rusage32 *ru)
+sys32_getrusage (int who, struct rusage32 *ru)
 {
 	struct rusage r;
 	int ret;
 	mm_segment_t old_fs = get_fs();
 
-	set_fs (KERNEL_DS);
+	set_fs(KERNEL_DS);
 	ret = sys_getrusage(who, &r);
-	set_fs (old_fs);
-	if (put_rusage (ru, &r)) return -EFAULT;
+	set_fs(old_fs);
+	if (put_rusage (ru, &r))
+		return -EFAULT;
 	return ret;
 }
 
@@ -2041,41 +2713,41 @@
 	__kernel_clock_t32 tms_cstime;
 };
 
-extern asmlinkage long sys_times(struct tms * tbuf);
+extern asmlinkage long sys_times (struct tms * tbuf);
 
 asmlinkage long
-sys32_times(struct tms32 *tbuf)
+sys32_times (struct tms32 *tbuf)
 {
+	mm_segment_t old_fs = get_fs();
 	struct tms t;
 	long ret;
-	mm_segment_t old_fs = get_fs ();
 	int err;
 
-	set_fs (KERNEL_DS);
+	set_fs(KERNEL_DS);
 	ret = sys_times(tbuf ? &t : NULL);
-	set_fs (old_fs);
+	set_fs(old_fs);
 	if (tbuf) {
 		err = put_user (IA32_TICK(t.tms_utime), &tbuf->tms_utime);
-		err |= __put_user (IA32_TICK(t.tms_stime), &tbuf->tms_stime);
-		err |= __put_user (IA32_TICK(t.tms_cutime), &tbuf->tms_cutime);
-		err |= __put_user (IA32_TICK(t.tms_cstime), &tbuf->tms_cstime);
+		err |= put_user (IA32_TICK(t.tms_stime), &tbuf->tms_stime);
+		err |= put_user (IA32_TICK(t.tms_cutime), &tbuf->tms_cutime);
+		err |= put_user (IA32_TICK(t.tms_cstime), &tbuf->tms_cstime);
 		if (err)
 			ret = -EFAULT;
 	}
 	return IA32_TICK(ret);
 }
 
-unsigned int
+static unsigned int
 ia32_peek (struct pt_regs *regs, struct task_struct *child, unsigned long addr, unsigned int *val)
 {
 	size_t copied;
 	unsigned int ret;
 
 	copied = access_process_vm(child, addr, val, sizeof(*val), 0);
-	return(copied != sizeof(ret) ? -EIO : 0);
+	return (copied != sizeof(ret)) ? -EIO : 0;
 }
 
-unsigned int
+static unsigned int
 ia32_poke (struct pt_regs *regs, struct task_struct *child, unsigned long addr, unsigned int val)
 {
 
@@ -2105,135 +2777,87 @@
 #define PT_UESP	15
 #define PT_SS	16
 
-unsigned int
-getreg(struct task_struct *child, int regno)
+static unsigned int
+getreg (struct task_struct *child, int regno)
 {
 	struct pt_regs *child_regs;
 
 	child_regs = ia64_task_regs(child);
 	switch (regno / sizeof(int)) {
-
-	case PT_EBX:
-		return(child_regs->r11);
-	case PT_ECX:
-		return(child_regs->r9);
-	case PT_EDX:
-		return(child_regs->r10);
-	case PT_ESI:
-		return(child_regs->r14);
-	case PT_EDI:
-		return(child_regs->r15);
-	case PT_EBP:
-		return(child_regs->r13);
-	case PT_EAX:
-	case PT_ORIG_EAX:
-		return(child_regs->r8);
-	case PT_EIP:
-		return(child_regs->cr_iip);
-	case PT_UESP:
-		return(child_regs->r12);
-	case PT_EFL:
-		return(child->thread.eflag);
-	case PT_DS:
-	case PT_ES:
-	case PT_FS:
-	case PT_GS:
-	case PT_SS:
-		return((unsigned int)__USER_DS);
-	case PT_CS:
-		return((unsigned int)__USER_CS);
-	default:
-		printk(KERN_ERR "getregs:unknown register %d\n", regno);
+	      case PT_EBX: return child_regs->r11;
+	      case PT_ECX: return child_regs->r9;
+	      case PT_EDX: return child_regs->r10;
+	      case PT_ESI: return child_regs->r14;
+	      case PT_EDI: return child_regs->r15;
+	      case PT_EBP: return child_regs->r13;
+	      case PT_EAX: return child_regs->r8;
+	      case PT_ORIG_EAX: return child_regs->r1; /* see dispatch_to_ia32_handler() */
+	      case PT_EIP: return child_regs->cr_iip;
+	      case PT_UESP: return child_regs->r12;
+	      case PT_EFL: return child->thread.eflag;
+	      case PT_DS: case PT_ES: case PT_FS: case PT_GS: case PT_SS:
+		return __USER_DS;
+	      case PT_CS: return __USER_CS;
+	      default:
+		printk(KERN_ERR "ia32.getreg(): unknown register %d\n", regno);
 		break;
-
 	}
-	return(0);
+	return 0;
 }
 
-void
-putreg(struct task_struct *child, int regno, unsigned int value)
+static void
+putreg (struct task_struct *child, int regno, unsigned int value)
 {
 	struct pt_regs *child_regs;
 
 	child_regs = ia64_task_regs(child);
 	switch (regno / sizeof(int)) {
-
-	case PT_EBX:
-		child_regs->r11 = value;
-		break;
-	case PT_ECX:
-		child_regs->r9 = value;
-		break;
-	case PT_EDX:
-		child_regs->r10 = value;
-		break;
-	case PT_ESI:
-		child_regs->r14 = value;
-		break;
-	case PT_EDI:
-		child_regs->r15 = value;
-		break;
-	case PT_EBP:
-		child_regs->r13 = value;
-		break;
-	case PT_EAX:
-	case PT_ORIG_EAX:
-		child_regs->r8 = value;
-		break;
-	case PT_EIP:
-		child_regs->cr_iip = value;
-		break;
-	case PT_UESP:
-		child_regs->r12 = value;
-		break;
-	case PT_EFL:
-		child->thread.eflag = value;
-		break;
-	case PT_DS:
-	case PT_ES:
-	case PT_FS:
-	case PT_GS:
-	case PT_SS:
+	      case PT_EBX: child_regs->r11 = value; break;
+	      case PT_ECX: child_regs->r9 = value; break;
+	      case PT_EDX: child_regs->r10 = value; break;
+	      case PT_ESI: child_regs->r14 = value; break;
+	      case PT_EDI: child_regs->r15 = value; break;
+	      case PT_EBP: child_regs->r13 = value; break;
+	      case PT_EAX: child_regs->r8 = value; break;
+	      case PT_ORIG_EAX: child_regs->r1 = value; break;
+	      case PT_EIP: child_regs->cr_iip = value; break;
+	      case PT_UESP: child_regs->r12 = value; break;
+	      case PT_EFL: child->thread.eflag = value; break;
+	      case PT_DS: case PT_ES: case PT_FS: case PT_GS: case PT_SS:
 		if (value != __USER_DS)
-			printk(KERN_ERR "setregs:try to set invalid segment register %d = %x\n",
+			printk(KERN_ERR
+			       "ia32.putreg: attempt to set invalid segment register %d = %x\n",
 			       regno, value);
 		break;
-	case PT_CS:
+	      case PT_CS:
 		if (value != __USER_CS)
-			printk(KERN_ERR "setregs:try to set invalid segment register %d = %x\n",
+			printk(KERN_ERR
+			       "ia32.putreg: attempt to to set invalid segment register %d = %x\n",
 			       regno, value);
 		break;
-	default:
-		printk(KERN_ERR "getregs:unknown register %d\n", regno);
+	      default:
+		printk(KERN_ERR "ia32.putreg: unknown register %d\n", regno);
 		break;
-
 	}
 }
 
 static inline void
-ia32f2ia64f(void *dst, void *src)
+ia32f2ia64f (void *dst, void *src)
 {
-
-	__asm__ ("ldfe f6=[%1] ;;\n\t"
-		 "stf.spill [%0]ö"
-		:
-		: "r"(dst), "r"(src));
+	asm volatile ("ldfe f6=[%1];; stf.spill [%0]ö" :: "r"(dst), "r"(src) : "memory");
 	return;
 }
 
 static inline void
-ia64f2ia32f(void *dst, void *src)
+ia64f2ia32f (void *dst, void *src)
 {
-
-	__asm__ ("ldf.fill f6=[%1] ;;\n\t"
-		 "stfe [%0]ö"
-		:
-		: "r"(dst),  "r"(src));
+	asm volatile ("ldf.fill f6=[%1];; stfe [%0]ö" :: "r"(dst),  "r"(src) : "memory");
 	return;
 }
 
-void
-put_fpreg(int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp, int tos)
+static void
+put_fpreg (int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp,
+	   int tos)
 {
 	struct _fpreg_ia32 *f;
 	char buf[32];
@@ -2242,62 +2866,59 @@
 	if ((regno += tos) >= 8)
 		regno -= 8;
 	switch (regno) {
-
-	case 0:
+	      case 0:
 		ia64f2ia32f(f, &ptp->f8);
 		break;
-	case 1:
+	      case 1:
 		ia64f2ia32f(f, &ptp->f9);
 		break;
-	case 2:
-	case 3:
-	case 4:
-	case 5:
-	case 6:
-	case 7:
+	      case 2:
+	      case 3:
+	      case 4:
+	      case 5:
+	      case 6:
+	      case 7:
 		ia64f2ia32f(f, &swp->f10 + (regno - 2));
 		break;
-
 	}
-	__copy_to_user(reg, f, sizeof(*reg));
+	copy_to_user(reg, f, sizeof(*reg));
 }
 
-void
-get_fpreg(int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp, int tos)
+static void
+get_fpreg (int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp,
+	   int tos)
 {
 
 	if ((regno += tos) >= 8)
 		regno -= 8;
 	switch (regno) {
-
-	case 0:
-		__copy_from_user(&ptp->f8, reg, sizeof(*reg));
+	      case 0:
+		copy_from_user(&ptp->f8, reg, sizeof(*reg));
 		break;
-	case 1:
-		__copy_from_user(&ptp->f9, reg, sizeof(*reg));
+	      case 1:
+		copy_from_user(&ptp->f9, reg, sizeof(*reg));
 		break;
-	case 2:
-	case 3:
-	case 4:
-	case 5:
-	case 6:
-	case 7:
-		__copy_from_user(&swp->f10 + (regno - 2), reg, sizeof(*reg));
+	      case 2:
+	      case 3:
+	      case 4:
+	      case 5:
+	      case 6:
+	      case 7:
+		copy_from_user(&swp->f10 + (regno - 2), reg, sizeof(*reg));
 		break;
-
 	}
 	return;
 }
 
-int
-save_ia32_fpstate(struct task_struct *tsk, struct _fpstate_ia32 *save)
+static int
+save_ia32_fpstate (struct task_struct *tsk, struct _fpstate_ia32 *save)
 {
 	struct switch_stack *swp;
 	struct pt_regs *ptp;
 	int i, tos;
 
 	if (!access_ok(VERIFY_WRITE, save, sizeof(*save)))
-		return(-EIO);
+		return -EIO;
 	__put_user(tsk->thread.fcr, &save->cw);
 	__put_user(tsk->thread.fsr, &save->sw);
 	__put_user(tsk->thread.fsr >> 32, &save->tag);
@@ -2313,11 +2934,11 @@
 	tos = (tsk->thread.fsr >> 11) & 3;
 	for (i = 0; i < 8; i++)
 		put_fpreg(i, &save->_st[i], ptp, swp, tos);
-	return(0);
+	return 0;
 }
 
-int
-restore_ia32_fpstate(struct task_struct *tsk, struct _fpstate_ia32 *save)
+static int
+restore_ia32_fpstate (struct task_struct *tsk, struct _fpstate_ia32 *save)
 {
 	struct switch_stack *swp;
 	struct pt_regs *ptp;
@@ -2340,10 +2961,11 @@
 	tos = (tsk->thread.fsr >> 11) & 3;
 	for (i = 0; i < 8; i++)
 		get_fpreg(i, &save->_st[i], ptp, swp, tos);
-	return(ret ? -EFAULT : 0);
+	return ret ? -EFAULT : 0;
 }
 
-asmlinkage long sys_ptrace(long, pid_t, unsigned long, unsigned long, long, long, long, long, long);
+extern asmlinkage long sys_ptrace (long, pid_t, unsigned long, unsigned long, long, long, long,
+				   long, long);
 
 /*
  *  Note that the IA32 version of `ptrace' calls the IA64 routine for
@@ -2358,13 +2980,12 @@
 {
 	struct pt_regs *regs = (struct pt_regs *) &stack;
 	struct task_struct *child;
+	unsigned int value, tmp;
 	long i, ret;
-	unsigned int value;
 
 	lock_kernel();
 	if (request = PTRACE_TRACEME) {
-		ret = sys_ptrace(request, pid, addr, data,
-				arg4, arg5, arg6, arg7, stack);
+		ret = sys_ptrace(request, pid, addr, data, arg4, arg5, arg6, arg7, stack);
 		goto out;
 	}
 
@@ -2379,8 +3000,7 @@
 		goto out;
 
 	if (request = PTRACE_ATTACH) {
-		ret = sys_ptrace(request, pid, addr, data,
-				arg4, arg5, arg6, arg7, stack);
+		ret = sys_ptrace(request, pid, addr, data, arg4, arg5, arg6, arg7, stack);
 		goto out;
 	}
 	ret = -ESRCH;
@@ -2398,21 +3018,32 @@
 	      case PTRACE_PEEKDATA:	/* read word at location addr */
 		ret = ia32_peek(regs, child, addr, &value);
 		if (ret = 0)
-			ret = put_user(value, (unsigned int *)A(data));
+			ret = put_user(value, (unsigned int *) A(data));
 		else
 			ret = -EIO;
 		goto out;
 
 	      case PTRACE_POKETEXT:
 	      case PTRACE_POKEDATA:	/* write the word at location addr */
-		ret = ia32_poke(regs, child, addr, (unsigned int)data);
+		ret = ia32_poke(regs, child, addr, data);
 		goto out;
 
 	      case PTRACE_PEEKUSR:	/* read word at addr in USER area */
-		ret = 0;
+		ret = -EIO;
+		if ((addr & 3) || addr > 17*sizeof(int))
+			break;
+
+		tmp = getreg(child, addr);
+		if (!put_user(tmp, (unsigned int *) A(data)))
+			ret = 0;
 		break;
 
 	      case PTRACE_POKEUSR:	/* write word at addr in USER area */
+		ret = -EIO;
+		if ((addr & 3) || addr > 17*sizeof(int))
+			break;
+
+		putreg(child, addr, data);
 		ret = 0;
 		break;
 
@@ -2421,28 +3052,25 @@
 			ret = -EIO;
 			break;
 		}
-		for ( i = 0; i < 17*sizeof(int); i += sizeof(int) ) {
-			__put_user(getreg(child, i), (unsigned int *) A(data));
+		for (i = 0; i < 17*sizeof(int); i += sizeof(int) ) {
+			put_user(getreg(child, i), (unsigned int *) A(data));
 			data += sizeof(int);
 		}
 		ret = 0;
 		break;
 
 	      case IA32_PTRACE_SETREGS:
-	      {
-		unsigned int tmp;
 		if (!access_ok(VERIFY_READ, (int *) A(data), 17*sizeof(int))) {
 			ret = -EIO;
 			break;
 		}
-		for ( i = 0; i < 17*sizeof(int); i += sizeof(int) ) {
-			__get_user(tmp, (unsigned int *) A(data));
+		for (i = 0; i < 17*sizeof(int); i += sizeof(int) ) {
+			get_user(tmp, (unsigned int *) A(data));
 			putreg(child, i, tmp);
 			data += sizeof(int);
 		}
 		ret = 0;
 		break;
-	      }
 
 	      case IA32_PTRACE_GETFPREGS:
 		ret = save_ia32_fpstate(child, (struct _fpstate_ia32 *) A(data));
@@ -2457,10 +3085,8 @@
 	      case PTRACE_KILL:
 	      case PTRACE_SINGLESTEP:	/* execute chile for one instruction */
 	      case PTRACE_DETACH:	/* detach a process */
-		unlock_kernel();
-		ret = sys_ptrace(request, pid, addr, data,
-				arg4, arg5, arg6, arg7, stack);
-		return(ret);
+		ret = sys_ptrace(request, pid, addr, data, arg4, arg5, arg6, arg7, stack);
+		break;
 
 	      default:
 		ret = -EIO;
@@ -2477,7 +3103,10 @@
 {
 	int err;
 
-	err = get_user(kfl->l_type, &ufl->l_type);
+	if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)))
+		return -EFAULT;
+
+	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);
@@ -2490,6 +3119,9 @@
 {
 	int err;
 
+	if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)))
+		return -EFAULT;
+
 	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);
@@ -2498,71 +3130,43 @@
 	return err;
 }
 
-extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd,
-				 unsigned long arg);
+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)
+sys32_fcntl (unsigned int fd, unsigned int cmd, unsigned int arg)
 {
-	struct flock f;
 	mm_segment_t old_fs;
+	struct flock f;
 	long ret;
 
 	switch (cmd) {
-	case F_GETLK:
-	case F_SETLK:
-	case F_SETLKW:
-		if(get_flock32(&f, (struct flock32 *)((long)arg)))
+	      case F_GETLK:
+	      case F_SETLK:
+	      case F_SETLKW:
+		if (get_flock32(&f, (struct flock32 *) A(arg)))
 			return -EFAULT;
 		old_fs = get_fs();
 		set_fs(KERNEL_DS);
-		ret = sys_fcntl(fd, cmd, (unsigned long)&f);
+		ret = sys_fcntl(fd, cmd, (unsigned long) &f);
 		set_fs(old_fs);
-		if(cmd = F_GETLK && put_flock32(&f, (struct flock32 *)((long)arg)))
+		if (cmd = F_GETLK && put_flock32(&f, (struct flock32 *) A(arg)))
 			return -EFAULT;
 		return ret;
-	default:
+
+	      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 sys_fcntl(fd, cmd, arg);
 	}
-
-	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)
+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;
 
@@ -2577,7 +3181,7 @@
 #define IOLEN	((65536 / 4) * 4096)
 
 asmlinkage long
-sys_iopl (int level)
+sys32_iopl (int level)
 {
 	extern unsigned long ia64_iobase;
 	int fd;
@@ -2612,9 +3216,8 @@
 	up_write(&current->mm->mmap_sem);
 
 	if (addr >= 0) {
-		ia64_set_kr(IA64_KR_IO_BASE, addr);
 		old = (old & ~0x3000) | (level << 12);
-		__asm__ __volatile__("mov ar.eflag=%0 ;;" :: "r"(old));
+		asm volatile ("mov ar.eflag=%0;;" :: "r"(old));
 	}
 
 	fput(file);
@@ -2623,7 +3226,7 @@
 }
 
 asmlinkage long
-sys_ioperm (unsigned int from, unsigned int num, int on)
+sys32_ioperm (unsigned int from, unsigned int num, int on)
 {
 
 	/*
@@ -2636,7 +3239,7 @@
 	 * XXX proper ioperm() support should be emulated by
 	 *	manipulating the page protections...
 	 */
-	return sys_iopl(3);
+	return sys32_iopl(3);
 }
 
 typedef struct {
@@ -2646,10 +3249,8 @@
 } ia32_stack_t;
 
 asmlinkage long
-sys32_sigaltstack (const ia32_stack_t *uss32, ia32_stack_t *uoss32,
-long arg2, long arg3, long arg4,
-long arg5, long arg6, long arg7,
-long stack)
+sys32_sigaltstack (ia32_stack_t *uss32, ia32_stack_t *uoss32,
+		   long arg2, long arg3, long arg4, long arg5, long arg6, long arg7, long stack)
 {
 	struct pt_regs *pt = (struct pt_regs *) &stack;
 	stack_t uss, uoss;
@@ -2658,8 +3259,8 @@
 	mm_segment_t old_fs = get_fs();
 
 	if (uss32)
-		if (copy_from_user(&buf32, (void *)A(uss32), sizeof(ia32_stack_t)))
-			return(-EFAULT);
+		if (copy_from_user(&buf32, uss32, sizeof(ia32_stack_t)))
+			return -EFAULT;
 	uss.ss_sp = (void *) (long) buf32.ss_sp;
 	uss.ss_flags = buf32.ss_flags;
 	uss.ss_size = buf32.ss_size;
@@ -2672,34 +3273,34 @@
 		buf32.ss_sp = (long) uoss.ss_sp;
 		buf32.ss_flags = uoss.ss_flags;
 		buf32.ss_size = uoss.ss_size;
-		if (copy_to_user((void*)A(uoss32), &buf32, sizeof(ia32_stack_t)))
-			return(-EFAULT);
+		if (copy_to_user(uoss32, &buf32, sizeof(ia32_stack_t)))
+			return -EFAULT;
 	}
-	return(ret);
+	return ret;
 }
 
 asmlinkage int
-sys_pause (void)
+sys32_pause (void)
 {
 	current->state = TASK_INTERRUPTIBLE;
 	schedule();
 	return -ERESTARTNOHAND;
 }
 
-asmlinkage long sys_msync(unsigned long start, size_t len, int flags);
+asmlinkage long sys_msync (unsigned long start, size_t len, int flags);
 
 asmlinkage int
-sys32_msync(unsigned int start, unsigned int len, int flags)
+sys32_msync (unsigned int start, unsigned int len, int flags)
 {
 	unsigned int addr;
 
 	if (OFFSET4K(start))
 		return -EINVAL;
-	addr = start & PAGE_MASK;
-	return(sys_msync(addr, len + (start - addr), flags));
+	addr = PAGE_START(start);
+	return sys_msync(addr, len + (start - addr), flags);
 }
 
-struct sysctl_ia32 {
+struct sysctl32 {
 	unsigned int	name;
 	int		nlen;
 	unsigned int	oldval;
@@ -2712,16 +3313,16 @@
 extern asmlinkage long sys_sysctl(struct __sysctl_args *args);
 
 asmlinkage long
-sys32_sysctl(struct sysctl_ia32 *args32)
+sys32_sysctl (struct sysctl32 *args)
 {
-	struct sysctl_ia32 a32;
+	struct sysctl32 a32;
 	mm_segment_t old_fs = get_fs ();
 	void *oldvalp, *newvalp;
 	size_t oldlen;
 	int *namep;
 	long ret;
 
-	if (copy_from_user(&a32, args32, sizeof (a32)))
+	if (copy_from_user(&a32, args, sizeof(a32)))
 		return -EFAULT;
 
 	/*
@@ -2754,7 +3355,7 @@
 }
 
 asmlinkage long
-sys32_newuname(struct new_utsname * name)
+sys32_newuname (struct new_utsname *name)
 {
 	extern asmlinkage long sys_newuname(struct new_utsname * name);
 	int ret = sys_newuname(name);
@@ -2765,10 +3366,10 @@
 	return ret;
 }
 
-extern asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
+extern asmlinkage long sys_getresuid (uid_t *ruid, uid_t *euid, uid_t *suid);
 
 asmlinkage long
-sys32_getresuid (u16 *ruid, u16 *euid, u16 *suid)
+sys32_getresuid16 (u16 *ruid, u16 *euid, u16 *suid)
 {
 	uid_t a, b, c;
 	int ret;
@@ -2786,7 +3387,7 @@
 extern asmlinkage long sys_getresgid (gid_t *rgid, gid_t *egid, gid_t *sgid);
 
 asmlinkage long
-sys32_getresgid(u16 *rgid, u16 *egid, u16 *sgid)
+sys32_getresgid16 (u16 *rgid, u16 *egid, u16 *sgid)
 {
 	gid_t a, b, c;
 	int ret;
@@ -2796,15 +3397,13 @@
 	ret = sys_getresgid(&a, &b, &c);
 	set_fs(old_fs);
 
-	if (!ret) {
-		ret  = put_user(a, rgid);
-		ret |= put_user(b, egid);
-		ret |= put_user(c, sgid);
-	}
-	return ret;
+	if (ret)
+		return ret;
+
+	return put_user(a, rgid) | put_user(b, egid) | put_user(c, sgid);
 }
 
-int
+asmlinkage long
 sys32_lseek (unsigned int fd, int offset, unsigned int whence)
 {
 	extern off_t sys_lseek (unsigned int fd, off_t offset, unsigned int origin);
@@ -2813,36 +3412,272 @@
 	return sys_lseek(fd, offset, whence);
 }
 
-#ifdef	NOTYET  /* UNTESTED FOR IA64 FROM HERE DOWN */
+extern asmlinkage long sys_getgroups (int gidsetsize, gid_t *grouplist);
 
-/* In order to reduce some races, while at the same time doing additional
- * checking and hopefully speeding things up, we copy filenames to the
- * kernel data space before using them..
- *
- * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
- */
-static inline int
-do_getname32(const char *filename, char *page)
+asmlinkage long
+sys32_getgroups16 (int gidsetsize, short *grouplist)
 {
-	int retval;
+	mm_segment_t old_fs = get_fs();
+	gid_t gl[NGROUPS];
+	int ret, i;
 
-	/* 32bit pointer will be always far below TASK_SIZE :)) */
-	retval = strncpy_from_user((char *)page, (char *)filename, PAGE_SIZE);
-	if (retval > 0) {
-		if (retval < PAGE_SIZE)
-			return 0;
-		return -ENAMETOOLONG;
-	} else if (!retval)
-		retval = -ENOENT;
-	return retval;
+	set_fs(KERNEL_DS);
+	ret = sys_getgroups(gidsetsize, gl);
+	set_fs(old_fs);
+
+	if (gidsetsize && ret > 0 && ret <= NGROUPS)
+		for (i = 0; i < ret; i++, grouplist++)
+			if (put_user(gl[i], grouplist))
+				return -EFAULT;
+	return ret;
 }
 
-char *
-getname32(const char *filename)
+extern asmlinkage long sys_setgroups (int gidsetsize, gid_t *grouplist);
+
+asmlinkage long
+sys32_setgroups16 (int gidsetsize, short *grouplist)
 {
-	char *tmp, *result;
+	mm_segment_t old_fs = get_fs();
+	gid_t gl[NGROUPS];
+	int ret, i;
 
-	result = ERR_PTR(-ENOMEM);
+	if ((unsigned) gidsetsize > NGROUPS)
+		return -EINVAL;
+	for (i = 0; i < gidsetsize; i++, grouplist++)
+		if (get_user(gl[i], grouplist))
+			return -EFAULT;
+	set_fs(KERNEL_DS);
+	ret = sys_setgroups(gidsetsize, gl);
+	set_fs(old_fs);
+	return ret;
+}
+
+/*
+ * Unfortunately, the x86 compiler aligns variables of type "long long" to a 4 byte boundary
+ * only, which means that the x86 version of "struct flock64" doesn't match the ia64 version
+ * of struct flock.
+ */
+
+static inline long
+ia32_put_flock (struct flock *l, unsigned long addr)
+{
+	return (put_user(l->l_type, (short *) addr)
+		| put_user(l->l_whence, (short *) (addr + 2))
+		| put_user(l->l_start, (long *) (addr + 4))
+		| put_user(l->l_len, (long *) (addr + 12))
+		| put_user(l->l_pid, (int *) (addr + 20)));
+}
+
+static inline long
+ia32_get_flock (struct flock *l, unsigned long addr)
+{
+	unsigned int start_lo, start_hi, len_lo, len_hi;
+	int err = (get_user(l->l_type, (short *) addr)
+		   | get_user(l->l_whence, (short *) (addr + 2))
+		   | get_user(start_lo, (int *) (addr + 4))
+		   | get_user(start_hi, (int *) (addr + 8))
+		   | get_user(len_lo, (int *) (addr + 12))
+		   | get_user(len_hi, (int *) (addr + 16))
+		   | get_user(l->l_pid, (int *) (addr + 20)));
+	l->l_start = ((unsigned long) start_hi << 32) | start_lo;
+	l->l_len = ((unsigned long) len_hi << 32) | len_lo;
+	return err;
+}
+
+asmlinkage long
+sys32_fcntl64 (unsigned int fd, unsigned int cmd, unsigned int arg)
+{
+	mm_segment_t old_fs;
+	struct flock f;
+	long ret;
+
+	switch (cmd) {
+	      case F_GETLK64:
+	      case F_SETLK64:
+	      case F_SETLKW64:
+		if (ia32_get_flock(&f, 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 && ia32_put_flock(&f, arg))
+			return -EFAULT;
+		break;
+
+	      default:
+		ret = sys32_fcntl(fd, cmd, arg);
+		break;
+	}
+	return ret;
+}
+
+asmlinkage long
+sys32_truncate64 (unsigned int path, unsigned int len_lo, unsigned int len_hi)
+{
+	extern asmlinkage long sys_truncate (const char *path, unsigned long length);
+
+	return sys_truncate((const char *) A(path), ((unsigned long) len_hi << 32) | len_lo);
+}
+
+asmlinkage long
+sys32_ftruncate64 (int fd, unsigned int len_lo, unsigned int len_hi)
+{
+	extern asmlinkage long sys_ftruncate (int fd, unsigned long length);
+
+	return sys_ftruncate(fd, ((unsigned long) len_hi << 32) | len_lo);
+}
+
+static int
+putstat64 (struct stat64 *ubuf, struct stat *kbuf)
+{
+	int err;
+
+	if (clear_user(ubuf, sizeof(*ubuf)))
+		return 1;
+
+	err  = __put_user(kbuf->st_dev, &ubuf->st_dev);
+	err |= __put_user(kbuf->st_ino, &ubuf->__st_ino);
+	err |= __put_user(kbuf->st_ino, &ubuf->st_ino_lo);
+	err |= __put_user(kbuf->st_ino >> 32, &ubuf->st_ino_hi);
+	err |= __put_user(kbuf->st_mode, &ubuf->st_mode);
+	err |= __put_user(kbuf->st_nlink, &ubuf->st_nlink);
+	err |= __put_user(kbuf->st_uid, &ubuf->st_uid);
+	err |= __put_user(kbuf->st_gid, &ubuf->st_gid);
+	err |= __put_user(kbuf->st_rdev, &ubuf->st_rdev);
+	err |= __put_user(kbuf->st_size, &ubuf->st_size_lo);
+	err |= __put_user((kbuf->st_size >> 32), &ubuf->st_size_hi);
+	err |= __put_user(kbuf->st_atime, &ubuf->st_atime);
+	err |= __put_user(kbuf->st_mtime, &ubuf->st_mtime);
+	err |= __put_user(kbuf->st_ctime, &ubuf->st_ctime);
+	err |= __put_user(kbuf->st_blksize, &ubuf->st_blksize);
+	err |= __put_user(kbuf->st_blocks, &ubuf->st_blocks);
+	return err;
+}
+
+asmlinkage long
+sys32_stat64 (char *filename, struct stat64 *statbuf)
+{
+	mm_segment_t old_fs = get_fs();
+	struct stat s;
+	long ret;
+
+	set_fs(KERNEL_DS);
+	ret = sys_newstat(filename, &s);
+	set_fs(old_fs);
+	if (putstat64(statbuf, &s))
+		return -EFAULT;
+	return ret;
+}
+
+asmlinkage long
+sys32_lstat64 (char *filename, struct stat64 *statbuf)
+{
+	mm_segment_t old_fs = get_fs();
+	struct stat s;
+	long ret;
+
+	set_fs(KERNEL_DS);
+	ret = sys_newlstat(filename, &s);
+	set_fs(old_fs);
+	if (putstat64(statbuf, &s))
+		return -EFAULT;
+	return ret;
+}
+
+asmlinkage long
+sys32_fstat64 (unsigned int fd, struct stat64 *statbuf)
+{
+	mm_segment_t old_fs = get_fs();
+	struct stat s;
+	long ret;
+
+	set_fs(KERNEL_DS);
+	ret = sys_newfstat(fd, &s);
+	set_fs(old_fs);
+	if (putstat64(statbuf, &s))
+		return -EFAULT;
+	return ret;
+}
+
+asmlinkage long
+sys32_sigpending (unsigned int *set)
+{
+	return do_sigpending(set, sizeof(*set));
+}
+
+struct sysinfo32 {
+	s32 uptime;
+	u32 loads[3];
+	u32 totalram;
+	u32 freeram;
+	u32 sharedram;
+	u32 bufferram;
+	u32 totalswap;
+	u32 freeswap;
+	unsigned short procs;
+	char _f[22];
+};
+
+asmlinkage long
+sys32_sysinfo (struct sysinfo32 *info)
+{
+	extern asmlinkage long sys_sysinfo (struct sysinfo *);
+	mm_segment_t old_fs = get_fs();
+	struct sysinfo s;
+	long ret, err;
+
+	set_fs(KERNEL_DS);
+	ret = sys_sysinfo(&s);
+	set_fs(old_fs);
+
+	if (!access_ok(VERIFY_WRITE, info, sizeof(*info)))
+		return -EFAULT;
+
+	err  = __put_user(s.uptime, &info->uptime);
+	err |= __put_user(s.loads[0], &info->loads[0]);
+	err |= __put_user(s.loads[1], &info->loads[1]);
+	err |= __put_user(s.loads[2], &info->loads[2]);
+	err |= __put_user(s.totalram, &info->totalram);
+	err |= __put_user(s.freeram, &info->freeram);
+	err |= __put_user(s.sharedram, &info->sharedram);
+	err |= __put_user(s.bufferram, &info->bufferram);
+	err |= __put_user(s.totalswap, &info->totalswap);
+	err |= __put_user(s.freeswap, &info->freeswap);
+	err |= __put_user(s.procs, &info->procs);
+	if (err)
+		return -EFAULT;
+	return ret;
+}
+
+/* In order to reduce some races, while at the same time doing additional
+ * checking and hopefully speeding things up, we copy filenames to the
+ * kernel data space before using them..
+ *
+ * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
+ */
+static inline int
+do_getname32 (const char *filename, char *page)
+{
+	int retval;
+
+	/* 32bit pointer will be always far below TASK_SIZE :)) */
+	retval = strncpy_from_user((char *)page, (char *)filename, PAGE_SIZE);
+	if (retval > 0) {
+		if (retval < PAGE_SIZE)
+			return 0;
+		return -ENAMETOOLONG;
+	} else if (!retval)
+		retval = -ENOENT;
+	return retval;
+}
+
+static char *
+getname32 (const char *filename)
+{
+	char *tmp, *result;
+
+	result = ERR_PTR(-ENOMEM);
 	tmp = (char *)__get_free_page(GFP_KERNEL);
 	if (tmp)  {
 		int retval = do_getname32(filename, tmp);
@@ -2856,178 +3691,132 @@
 	return result;
 }
 
-/* 32-bit timeval and related flotsam.  */
-
-extern asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
-
-asmlinkage long
-sys32_ioperm(u32 from, u32 num, int on)
-{
-	return sys_ioperm((unsigned long)from, (unsigned long)num, on);
-}
-
 struct dqblk32 {
-    __u32 dqb_bhardlimit;
-    __u32 dqb_bsoftlimit;
-    __u32 dqb_curblocks;
-    __u32 dqb_ihardlimit;
-    __u32 dqb_isoftlimit;
-    __u32 dqb_curinodes;
-    __kernel_time_t32 dqb_btime;
-    __kernel_time_t32 dqb_itime;
+	__u32 dqb_bhardlimit;
+	__u32 dqb_bsoftlimit;
+	__u32 dqb_curblocks;
+	__u32 dqb_ihardlimit;
+	__u32 dqb_isoftlimit;
+	__u32 dqb_curinodes;
+	__kernel_time_t32 dqb_btime;
+	__kernel_time_t32 dqb_itime;
 };
 
-extern asmlinkage long sys_quotactl(int cmd, const char *special, int id,
-				   caddr_t addr);
-
 asmlinkage long
-sys32_quotactl(int cmd, const char *special, int id, unsigned long addr)
+sys32_quotactl (int cmd, unsigned int special, int id, struct dqblk32 *addr)
 {
+	extern asmlinkage long sys_quotactl (int, const char *, int, caddr_t);
 	int cmds = cmd >> SUBCMDSHIFT;
-	int err;
-	struct dqblk d;
 	mm_segment_t old_fs;
+	struct dqblk d;
 	char *spec;
+	long err;
 
 	switch (cmds) {
-	case Q_GETQUOTA:
+	      case Q_GETQUOTA:
 		break;
-	case Q_SETQUOTA:
-	case Q_SETUSE:
-	case Q_SETQLIM:
-		if (copy_from_user (&d, (struct dqblk32 *)addr,
-				    sizeof (struct dqblk32)))
+	      case Q_SETQUOTA:
+	      case Q_SETUSE:
+	      case Q_SETQLIM:
+		if (copy_from_user (&d, addr, sizeof(struct dqblk32)))
 			return -EFAULT;
 		d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime;
 		d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime;
 		break;
-	default:
-		return sys_quotactl(cmd, special,
-				    id, (caddr_t)addr);
+	      default:
+		return sys_quotactl(cmd, (void *) A(special), id, (caddr_t) addr);
 	}
-	spec = getname32 (special);
+	spec = getname32((void *) A(special));
 	err = PTR_ERR(spec);
-	if (IS_ERR(spec)) return err;
+	if (IS_ERR(spec))
+		return err;
 	old_fs = get_fs ();
-	set_fs (KERNEL_DS);
+	set_fs(KERNEL_DS);
 	err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d);
-	set_fs (old_fs);
-	putname (spec);
+	set_fs(old_fs);
+	putname(spec);
 	if (cmds = Q_GETQUOTA) {
 		__kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
 		((struct dqblk32 *)&d)->dqb_itime = i;
 		((struct dqblk32 *)&d)->dqb_btime = b;
-		if (copy_to_user ((struct dqblk32 *)addr, &d,
-				  sizeof (struct dqblk32)))
+		if (copy_to_user(addr, &d, sizeof(struct dqblk32)))
 			return -EFAULT;
 	}
 	return err;
 }
 
-extern asmlinkage long sys_utime(char * filename, struct utimbuf * times);
-
-struct utimbuf32 {
-	__kernel_time_t32 actime, modtime;
-};
-
 asmlinkage long
-sys32_utime(char * filename, struct utimbuf32 *times)
+sys32_sched_rr_get_interval (pid_t pid, struct timespec32 *interval)
 {
-	struct utimbuf t;
-	mm_segment_t old_fs;
-	int ret;
-	char *filenam;
+	extern asmlinkage long sys_sched_rr_get_interval (pid_t, struct timespec *);
+	mm_segment_t old_fs = get_fs();
+	struct timespec t;
+	long ret;
 
-	if (!times)
-		return sys_utime(filename, NULL);
-	if (get_user (t.actime, &times->actime) ||
-	    __get_user (t.modtime, &times->modtime))
-		return -EFAULT;
-	filenam = getname32 (filename);
-	ret = PTR_ERR(filenam);
-	if (!IS_ERR(filenam)) {
-		old_fs = get_fs();
-		set_fs (KERNEL_DS);
-		ret = sys_utime(filenam, &t);
-		set_fs (old_fs);
-		putname (filenam);
-	}
+	set_fs(KERNEL_DS);
+	ret = sys_sched_rr_get_interval(pid, &t);
+	set_fs(old_fs);
+	if (put_user (t.tv_sec, &interval->tv_sec) || put_user (t.tv_nsec, &interval->tv_nsec))
+		return -EFAULT;
 	return ret;
 }
 
-/*
- * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
- * 64-bit unsigned longs.
- */
-
-static inline int
-get_fd_set32(unsigned long n, unsigned long *fdset, u32 *ufdset)
+asmlinkage long
+sys32_pread (unsigned int fd, void *buf, unsigned int count, u32 pos_lo, u32 pos_hi)
 {
-	if (ufdset) {
-		unsigned long odd;
-
-		if (verify_area(VERIFY_WRITE, ufdset, n*sizeof(u32)))
-			return -EFAULT;
+	extern asmlinkage long sys_pread (unsigned int, char *, size_t, loff_t);
+	return sys_pread(fd, buf, count, ((unsigned long) pos_hi << 32) | pos_lo);
+}
 
-		odd = n & 1UL;
-		n &= ~1UL;
-		while (n) {
-			unsigned long h, l;
-			__get_user(l, ufdset);
-			__get_user(h, ufdset+1);
-			ufdset += 2;
-			*fdset++ = h << 32 | l;
-			n -= 2;
-		}
-		if (odd)
-			__get_user(*fdset, ufdset);
-	} else {
-		/* Tricky, must clear full unsigned long in the
-		 * kernel fdset at the end, this makes sure that
-		 * actually happens.
-		 */
-		memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32));
-	}
-	return 0;
+asmlinkage long
+sys32_pwrite (unsigned int fd, void *buf, unsigned int count, u32 pos_lo, u32 pos_hi)
+{
+	extern asmlinkage long sys_pwrite (unsigned int, const char *, size_t, loff_t);
+	return sys_pwrite(fd, buf, count, ((unsigned long) pos_hi << 32) | pos_lo);
 }
 
-static inline void
-set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset)
+asmlinkage long
+sys32_sendfile (int out_fd, int in_fd, int *offset, unsigned int count)
 {
-	unsigned long odd;
+	extern asmlinkage long sys_sendfile (int, int, off_t *, size_t);
+	mm_segment_t old_fs = get_fs();
+	long ret;
+	off_t of;
 
-	if (!ufdset)
-		return;
+	if (offset && get_user(of, offset))
+		return -EFAULT;
 
-	odd = n & 1UL;
-	n &= ~1UL;
-	while (n) {
-		unsigned long h, l;
-		l = *fdset++;
-		h = l >> 32;
-		__put_user(l, ufdset);
-		__put_user(h, ufdset+1);
-		ufdset += 2;
-		n -= 2;
-	}
-	if (odd)
-		__put_user(*fdset, ufdset);
-}
+	set_fs(KERNEL_DS);
+	ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
+	set_fs(old_fs);
+
+	if (!ret && offset && put_user(of, offset))
+		return -EFAULT;
 
-extern asmlinkage long sys_sysfs(int option, unsigned long arg1,
-				unsigned long arg2);
+	return ret;
+}
 
 asmlinkage long
-sys32_sysfs(int option, u32 arg1, u32 arg2)
+sys32_personality (unsigned int personality)
 {
-	return sys_sysfs(option, arg1, arg2);
+	extern asmlinkage long sys_personality (unsigned long);
+	long ret;
+
+	if (current->personality = PER_LINUX32 && personality = PER_LINUX)
+		personality = PER_LINUX32;
+	ret = sys_personality(personality);
+	if (ret = PER_LINUX32)
+		ret = PER_LINUX;
+	return ret;
 }
 
+#ifdef	NOTYET  /* UNTESTED FOR IA64 FROM HERE DOWN */
+
 struct ncp_mount_data32 {
 	int version;
 	unsigned int ncp_fd;
 	__kernel_uid_t32 mounted_uid;
-	__kernel_pid_t32 wdog_pid;
+	int wdog_pid;
 	unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
 	unsigned int time_out;
 	unsigned int retry_count;
@@ -3061,1485 +3850,169 @@
 	__kernel_uid_t32 uid;
 	__kernel_gid_t32 gid;
 	__kernel_mode_t32 file_mode;
-	__kernel_mode_t32 dir_mode;
-};
-
-static void *
-do_smb_super_data_conv(void *raw_data)
-{
-	struct smb_mount_data *s = (struct smb_mount_data *)raw_data;
-	struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data;
-
-	s->version = s32->version;
-	s->mounted_uid = s32->mounted_uid;
-	s->uid = s32->uid;
-	s->gid = s32->gid;
-	s->file_mode = s32->file_mode;
-	s->dir_mode = s32->dir_mode;
-	return raw_data;
-}
-
-static int
-copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel)
-{
-	int i;
-	unsigned long page;
-	struct vm_area_struct *vma;
-
-	*kernel = 0;
-	if(!user)
-		return 0;
-	vma = find_vma(current->mm, (unsigned long)user);
-	if(!vma || (unsigned long)user < vma->vm_start)
-		return -EFAULT;
-	if(!(vma->vm_flags & VM_READ))
-		return -EFAULT;
-	i = vma->vm_end - (unsigned long) user;
-	if(PAGE_SIZE <= (unsigned long) i)
-		i = PAGE_SIZE - 1;
-	if(!(page = __get_free_page(GFP_KERNEL)))
-		return -ENOMEM;
-	if(copy_from_user((void *) page, user, i)) {
-		free_page(page);
-		return -EFAULT;
-	}
-	*kernel = page;
-	return 0;
-}
-
-extern asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
-				unsigned long new_flags, void *data);
-
-#define SMBFS_NAME	"smbfs"
-#define NCPFS_NAME	"ncpfs"
-
-asmlinkage long
-sys32_mount(char *dev_name, char *dir_name, char *type,
-	    unsigned long new_flags, u32 data)
-{
-	unsigned long type_page;
-	int err, is_smb, is_ncp;
-
-	if(!capable(CAP_SYS_ADMIN))
-		return -EPERM;
-	is_smb = is_ncp = 0;
-	err = copy_mount_stuff_to_kernel((const void *)type, &type_page);
-	if(err)
-		return err;
-	if(type_page) {
-		is_smb = !strcmp((char *)type_page, SMBFS_NAME);
-		is_ncp = !strcmp((char *)type_page, NCPFS_NAME);
-	}
-	if(!is_smb && !is_ncp) {
-		if(type_page)
-			free_page(type_page);
-		return sys_mount(dev_name, dir_name, type, new_flags,
-				 (void *)AA(data));
-	} else {
-		unsigned long dev_page, dir_page, data_page;
-
-		err = copy_mount_stuff_to_kernel((const void *)dev_name,
-						 &dev_page);
-		if(err)
-			goto out;
-		err = copy_mount_stuff_to_kernel((const void *)dir_name,
-						 &dir_page);
-		if(err)
-			goto dev_out;
-		err = copy_mount_stuff_to_kernel((const void *)AA(data),
-						 &data_page);
-		if(err)
-			goto dir_out;
-		if(is_ncp)
-			do_ncp_super_data_conv((void *)data_page);
-		else if(is_smb)
-			do_smb_super_data_conv((void *)data_page);
-		else
-			panic("The problem is here...");
-		err = do_mount((char *)dev_page, (char *)dir_page,
-				(char *)type_page, new_flags,
-				(void *)data_page);
-		if(data_page)
-			free_page(data_page);
-	dir_out:
-		if(dir_page)
-			free_page(dir_page);
-	dev_out:
-		if(dev_page)
-			free_page(dev_page);
-	out:
-		if(type_page)
-			free_page(type_page);
-		return err;
-	}
-}
-
-struct sysinfo32 {
-	s32 uptime;
-	u32 loads[3];
-	u32 totalram;
-	u32 freeram;
-	u32 sharedram;
-	u32 bufferram;
-	u32 totalswap;
-	u32 freeswap;
-	unsigned short procs;
-	char _f[22];
-};
-
-extern asmlinkage long sys_sysinfo(struct sysinfo *info);
-
-asmlinkage long
-sys32_sysinfo(struct sysinfo32 *info)
-{
-	struct sysinfo s;
-	int ret, err;
-	mm_segment_t old_fs = get_fs ();
-
-	set_fs (KERNEL_DS);
-	ret = sys_sysinfo(&s);
-	set_fs (old_fs);
-	err = put_user (s.uptime, &info->uptime);
-	err |= __put_user (s.loads[0], &info->loads[0]);
-	err |= __put_user (s.loads[1], &info->loads[1]);
-	err |= __put_user (s.loads[2], &info->loads[2]);
-	err |= __put_user (s.totalram, &info->totalram);
-	err |= __put_user (s.freeram, &info->freeram);
-	err |= __put_user (s.sharedram, &info->sharedram);
-	err |= __put_user (s.bufferram, &info->bufferram);
-	err |= __put_user (s.totalswap, &info->totalswap);
-	err |= __put_user (s.freeswap, &info->freeswap);
-	err |= __put_user (s.procs, &info->procs);
-	if (err)
-		return -EFAULT;
-	return ret;
-}
-
-extern asmlinkage long sys_sched_rr_get_interval(pid_t pid,
-						struct timespec *interval);
-
-asmlinkage long
-sys32_sched_rr_get_interval(__kernel_pid_t32 pid, struct timespec32 *interval)
-{
-	struct timespec t;
-	int ret;
-	mm_segment_t old_fs = get_fs ();
-
-	set_fs (KERNEL_DS);
-	ret = sys_sched_rr_get_interval(pid, &t);
-	set_fs (old_fs);
-	if (put_user (t.tv_sec, &interval->tv_sec) ||
-	    __put_user (t.tv_nsec, &interval->tv_nsec))
-		return -EFAULT;
-	return ret;
-}
-
-extern asmlinkage long sys_sigprocmask(int how, old_sigset_t *set,
-				      old_sigset_t *oset);
-
-asmlinkage long
-sys32_sigprocmask(int how, old_sigset_t32 *set, old_sigset_t32 *oset)
-{
-	old_sigset_t s;
-	int ret;
-	mm_segment_t old_fs = get_fs();
-
-	if (set && get_user (s, set)) return -EFAULT;
-	set_fs (KERNEL_DS);
-	ret = sys_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL);
-	set_fs (old_fs);
-	if (ret) return ret;
-	if (oset && put_user (s, oset)) return -EFAULT;
-	return 0;
-}
-
-extern asmlinkage long sys_sigpending(old_sigset_t *set);
-
-asmlinkage long
-sys32_sigpending(old_sigset_t32 *set)
-{
-	old_sigset_t s;
-	int ret;
-	mm_segment_t old_fs = get_fs();
-
-	set_fs (KERNEL_DS);
-	ret = sys_sigpending(&s);
-	set_fs (old_fs);
-	if (put_user (s, set)) return -EFAULT;
-	return ret;
-}
-
-extern asmlinkage long sys_rt_sigpending(sigset_t *set, size_t sigsetsize);
-
-asmlinkage long
-sys32_rt_sigpending(sigset_t32 *set, __kernel_size_t32 sigsetsize)
-{
-	sigset_t s;
-	sigset_t32 s32;
-	int ret;
-	mm_segment_t old_fs = get_fs();
-
-	set_fs (KERNEL_DS);
-	ret = sys_rt_sigpending(&s, sigsetsize);
-	set_fs (old_fs);
-	if (!ret) {
-		switch (_NSIG_WORDS) {
-		case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
-		case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
-		case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
-		case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
-		}
-		if (copy_to_user (set, &s32, sizeof(sigset_t32)))
-			return -EFAULT;
-	}
-	return ret;
-}
-
-siginfo_t32 *
-siginfo64to32(siginfo_t32 *d, siginfo_t *s)
-{
-	memset(d, 0, sizeof(siginfo_t32));
-	d->si_signo = s->si_signo;
-	d->si_errno = s->si_errno;
-	d->si_code = s->si_code;
-	if (s->si_signo >= SIGRTMIN) {
-		d->si_pid = s->si_pid;
-		d->si_uid = s->si_uid;
-		/* XXX: Ouch, how to find this out??? */
-		d->si_int = s->si_int;
-	} else switch (s->si_signo) {
-	/* XXX: What about POSIX1.b timers */
-	case SIGCHLD:
-		d->si_pid = s->si_pid;
-		d->si_status = s->si_status;
-		d->si_utime = s->si_utime;
-		d->si_stime = s->si_stime;
-		break;
-	case SIGSEGV:
-	case SIGBUS:
-	case SIGFPE:
-	case SIGILL:
-		d->si_addr = (long)(s->si_addr);
-		/* XXX: Do we need to translate this from ia64 to ia32 traps? */
-		d->si_trapno = s->si_trapno;
-		break;
-	case SIGPOLL:
-		d->si_band = s->si_band;
-		d->si_fd = s->si_fd;
-		break;
-	default:
-		d->si_pid = s->si_pid;
-		d->si_uid = s->si_uid;
-		break;
-	}
-	return d;
-}
-
-siginfo_t *
-siginfo32to64(siginfo_t *d, siginfo_t32 *s)
-{
-	d->si_signo = s->si_signo;
-	d->si_errno = s->si_errno;
-	d->si_code = s->si_code;
-	if (s->si_signo >= SIGRTMIN) {
-		d->si_pid = s->si_pid;
-		d->si_uid = s->si_uid;
-		/* XXX: Ouch, how to find this out??? */
-		d->si_int = s->si_int;
-	} else switch (s->si_signo) {
-	/* XXX: What about POSIX1.b timers */
-	case SIGCHLD:
-		d->si_pid = s->si_pid;
-		d->si_status = s->si_status;
-		d->si_utime = s->si_utime;
-		d->si_stime = s->si_stime;
-		break;
-	case SIGSEGV:
-	case SIGBUS:
-	case SIGFPE:
-	case SIGILL:
-		d->si_addr = (void *)A(s->si_addr);
-		/* XXX: Do we need to translate this from ia32 to ia64 traps? */
-		d->si_trapno = s->si_trapno;
-		break;
-	case SIGPOLL:
-		d->si_band = s->si_band;
-		d->si_fd = s->si_fd;
-		break;
-	default:
-		d->si_pid = s->si_pid;
-		d->si_uid = s->si_uid;
-		break;
-	}
-	return d;
-}
-
-extern asmlinkage long
-sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo,
-		    const struct timespec *uts, size_t sigsetsize);
-
-asmlinkage long
-sys32_rt_sigtimedwait(sigset_t32 *uthese, siginfo_t32 *uinfo,
-		      struct timespec32 *uts, __kernel_size_t32 sigsetsize)
-{
-	sigset_t s;
-	sigset_t32 s32;
-	struct timespec t;
-	int ret;
-	mm_segment_t old_fs = get_fs();
-	siginfo_t info;
-	siginfo_t32 info32;
-
-	if (copy_from_user (&s32, uthese, sizeof(sigset_t32)))
-		return -EFAULT;
-	switch (_NSIG_WORDS) {
-	case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
-	case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
-	case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
-	case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
-	}
-	if (uts) {
-		ret = get_user (t.tv_sec, &uts->tv_sec);
-		ret |= __get_user (t.tv_nsec, &uts->tv_nsec);
-		if (ret)
-			return -EFAULT;
-	}
-	set_fs (KERNEL_DS);
-	ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize);
-	set_fs (old_fs);
-	if (ret >= 0 && uinfo) {
-		if (copy_to_user (uinfo, siginfo64to32(&info32, &info),
-				  sizeof(siginfo_t32)))
-			return -EFAULT;
-	}
-	return ret;
-}
-
-extern asmlinkage long
-sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo);
-
-asmlinkage long
-sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo)
-{
-	siginfo_t info;
-	siginfo_t32 info32;
-	int ret;
-	mm_segment_t old_fs = get_fs();
-
-	if (copy_from_user (&info32, uinfo, sizeof(siginfo_t32)))
-		return -EFAULT;
-	/* XXX: Is this correct? */
-	siginfo32to64(&info, &info32);
-	set_fs (KERNEL_DS);
-	ret = sys_rt_sigqueueinfo(pid, sig, &info);
-	set_fs (old_fs);
-	return ret;
-}
-
-extern asmlinkage long sys_setreuid(uid_t ruid, uid_t euid);
-
-asmlinkage long sys32_setreuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid)
-{
-	uid_t sruid, seuid;
-
-	sruid = (ruid = (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid);
-	seuid = (euid = (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid);
-	return sys_setreuid(sruid, seuid);
-}
-
-extern asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid);
-
-asmlinkage long
-sys32_setresuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid,
-		__kernel_uid_t32 suid)
-{
-	uid_t sruid, seuid, ssuid;
-
-	sruid = (ruid = (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid);
-	seuid = (euid = (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid);
-	ssuid = (suid = (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)suid);
-	return sys_setresuid(sruid, seuid, ssuid);
-}
-
-extern asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
-
-asmlinkage long
-sys32_getresuid(__kernel_uid_t32 *ruid, __kernel_uid_t32 *euid,
-		__kernel_uid_t32 *suid)
-{
-	uid_t a, b, c;
-	int ret;
-	mm_segment_t old_fs = get_fs();
-
-	set_fs (KERNEL_DS);
-	ret = sys_getresuid(&a, &b, &c);
-	set_fs (old_fs);
-	if (put_user (a, ruid) || put_user (b, euid) || put_user (c, suid))
-		return -EFAULT;
-	return ret;
-}
-
-extern asmlinkage long sys_setregid(gid_t rgid, gid_t egid);
-
-asmlinkage long
-sys32_setregid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid)
-{
-	gid_t srgid, segid;
-
-	srgid = (rgid = (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid);
-	segid = (egid = (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid);
-	return sys_setregid(srgid, segid);
-}
-
-extern asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid);
-
-asmlinkage long
-sys32_setresgid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid,
-		__kernel_gid_t32 sgid)
-{
-	gid_t srgid, segid, ssgid;
-
-	srgid = (rgid = (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid);
-	segid = (egid = (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid);
-	ssgid = (sgid = (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)sgid);
-	return sys_setresgid(srgid, segid, ssgid);
-}
-
-extern asmlinkage long sys_getgroups(int gidsetsize, gid_t *grouplist);
-
-asmlinkage long
-sys32_getgroups(int gidsetsize, __kernel_gid_t32 *grouplist)
-{
-	gid_t gl[NGROUPS];
-	int ret, i;
-	mm_segment_t old_fs = get_fs ();
-
-	set_fs (KERNEL_DS);
-	ret = sys_getgroups(gidsetsize, gl);
-	set_fs (old_fs);
-	if (gidsetsize && ret > 0 && ret <= NGROUPS)
-		for (i = 0; i < ret; i++, grouplist++)
-			if (__put_user (gl[i], grouplist))
-				return -EFAULT;
-	return ret;
-}
-
-extern asmlinkage long sys_setgroups(int gidsetsize, gid_t *grouplist);
-
-asmlinkage long
-sys32_setgroups(int gidsetsize, __kernel_gid_t32 *grouplist)
-{
-	gid_t gl[NGROUPS];
-	int ret, i;
-	mm_segment_t old_fs = get_fs ();
-
-	if ((unsigned) gidsetsize > NGROUPS)
-		return -EINVAL;
-	for (i = 0; i < gidsetsize; i++, grouplist++)
-		if (__get_user (gl[i], grouplist))
-			return -EFAULT;
-	set_fs (KERNEL_DS);
-	ret = sys_setgroups(gidsetsize, gl);
-	set_fs (old_fs);
-	return ret;
-}
-
-
-/* XXX These as well... */
-extern __inline__ struct socket *
-socki_lookup(struct inode *inode)
-{
-	return &inode->u.socket_i;
-}
-
-extern __inline__ struct socket *
-sockfd_lookup(int fd, int *err)
-{
-	struct file *file;
-	struct inode *inode;
-
-	if (!(file = fget(fd)))
-	{
-		*err = -EBADF;
-		return NULL;
-	}
-
-	inode = file->f_dentry->d_inode;
-	if (!inode->i_sock || !socki_lookup(inode))
-	{
-		*err = -ENOTSOCK;
-		fput(file);
-		return NULL;
-	}
-
-	return socki_lookup(inode);
-}
-
-struct msghdr32 {
-	u32               msg_name;
-	int               msg_namelen;
-	u32               msg_iov;
-	__kernel_size_t32 msg_iovlen;
-	u32               msg_control;
-	__kernel_size_t32 msg_controllen;
-	unsigned          msg_flags;
-};
-
-struct cmsghdr32 {
-	__kernel_size_t32 cmsg_len;
-	int               cmsg_level;
-	int               cmsg_type;
-};
-
-/* Bleech... */
-#define __CMSG32_NXTHDR(ctl, len, cmsg, cmsglen) \
-	__cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen))
-#define CMSG32_NXTHDR(mhdr, cmsg, cmsglen) \
-	cmsg32_nxthdr((mhdr), (cmsg), (cmsglen))
-
-#define CMSG32_ALIGN(len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) )
-
-#define CMSG32_DATA(cmsg) \
-	((void *)((char *)(cmsg) + CMSG32_ALIGN(sizeof(struct cmsghdr32))))
-#define CMSG32_SPACE(len) \
-	(CMSG32_ALIGN(sizeof(struct cmsghdr32)) + CMSG32_ALIGN(len))
-#define CMSG32_LEN(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + (len))
-
-#define __CMSG32_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr32) ? \
-				    (struct cmsghdr32 *)(ctl) : \
-				    (struct cmsghdr32 *)NULL)
-#define CMSG32_FIRSTHDR(msg) \
-	__CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
-
-__inline__ struct cmsghdr32 *
-__cmsg32_nxthdr(void *__ctl, __kernel_size_t __size,
-		struct cmsghdr32 *__cmsg, int __cmsg_len)
-{
-	struct cmsghdr32 * __ptr;
-
-	__ptr = (struct cmsghdr32 *)(((unsigned char *) __cmsg) +
-				     CMSG32_ALIGN(__cmsg_len));
-	if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size)
-		return NULL;
-
-	return __ptr;
-}
-
-__inline__ struct cmsghdr32 *
-cmsg32_nxthdr (struct msghdr *__msg, struct cmsghdr32 *__cmsg, int __cmsg_len)
-{
-	return __cmsg32_nxthdr(__msg->msg_control, __msg->msg_controllen,
-			       __cmsg, __cmsg_len);
-}
-
-static inline int
-iov_from_user32_to_kern(struct iovec *kiov, struct iovec32 *uiov32, int niov)
-{
-	int tot_len = 0;
-
-	while(niov > 0) {
-		u32 len, buf;
-
-		if(get_user(len, &uiov32->iov_len) ||
-		   get_user(buf, &uiov32->iov_base)) {
-			tot_len = -EFAULT;
-			break;
-		}
-		tot_len += len;
-		kiov->iov_base = (void *)A(buf);
-		kiov->iov_len = (__kernel_size_t) len;
-		uiov32++;
-		kiov++;
-		niov--;
-	}
-	return tot_len;
-}
-
-static inline int
-msghdr_from_user32_to_kern(struct msghdr *kmsg, struct msghdr32 *umsg)
-{
-	u32 tmp1, tmp2, tmp3;
-	int err;
-
-	err = get_user(tmp1, &umsg->msg_name);
-	err |= __get_user(tmp2, &umsg->msg_iov);
-	err |= __get_user(tmp3, &umsg->msg_control);
-	if (err)
-		return -EFAULT;
-
-	kmsg->msg_name = (void *)A(tmp1);
-	kmsg->msg_iov = (struct iovec *)A(tmp2);
-	kmsg->msg_control = (void *)A(tmp3);
-
-	err = get_user(kmsg->msg_namelen, &umsg->msg_namelen);
-	err |= get_user(kmsg->msg_iovlen, &umsg->msg_iovlen);
-	err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen);
-	err |= get_user(kmsg->msg_flags, &umsg->msg_flags);
-
-	return err;
-}
-
-/* I've named the args so it is easy to tell whose space the pointers are in. */
-static int
-verify_iovec32(struct msghdr *kern_msg, struct iovec *kern_iov,
-	       char *kern_address, int mode)
-{
-	int tot_len;
-
-	if(kern_msg->msg_namelen) {
-		if(mode=VERIFY_READ) {
-			int err = move_addr_to_kernel(kern_msg->msg_name,
-						      kern_msg->msg_namelen,
-						      kern_address);
-			if(err < 0)
-				return err;
-		}
-		kern_msg->msg_name = kern_address;
-	} else
-		kern_msg->msg_name = NULL;
-
-	if(kern_msg->msg_iovlen > UIO_FASTIOV) {
-		kern_iov = kmalloc(kern_msg->msg_iovlen * sizeof(struct iovec),
-				   GFP_KERNEL);
-		if(!kern_iov)
-			return -ENOMEM;
-	}
-
-	tot_len = iov_from_user32_to_kern(kern_iov,
-					  (struct iovec32 *)kern_msg->msg_iov,
-					  kern_msg->msg_iovlen);
-	if(tot_len >= 0)
-		kern_msg->msg_iov = kern_iov;
-	else if(kern_msg->msg_iovlen > UIO_FASTIOV)
-		kfree(kern_iov);
-
-	return tot_len;
-}
-
-/* There is a lot of hair here because the alignment rules (and
- * thus placement) of cmsg headers and length are different for
- * 32-bit apps.  -DaveM
- */
-static int
-cmsghdr_from_user32_to_kern(struct msghdr *kmsg, unsigned char *stackbuf,
-			    int stackbuf_size)
-{
-	struct cmsghdr32 *ucmsg;
-	struct cmsghdr *kcmsg, *kcmsg_base;
-	__kernel_size_t32 ucmlen;
-	__kernel_size_t kcmlen, tmp;
-
-	kcmlen = 0;
-	kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;
-	ucmsg = CMSG32_FIRSTHDR(kmsg);
-	while(ucmsg != NULL) {
-		if(get_user(ucmlen, &ucmsg->cmsg_len))
-			return -EFAULT;
-
-		/* Catch bogons. */
-		if(CMSG32_ALIGN(ucmlen) <
-		   CMSG32_ALIGN(sizeof(struct cmsghdr32)))
-			return -EINVAL;
-		if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control)
-				   + ucmlen) > kmsg->msg_controllen)
-			return -EINVAL;
-
-		tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
-		       CMSG_ALIGN(sizeof(struct cmsghdr)));
-		kcmlen += tmp;
-		ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
-	}
-	if(kcmlen = 0)
-		return -EINVAL;
-
-	/* The kcmlen holds the 64-bit version of the control length.
-	 * It may not be modified as we do not stick it into the kmsg
-	 * until we have successfully copied over all of the data
-	 * from the user.
-	 */
-	if(kcmlen > stackbuf_size)
-		kcmsg_base = kcmsg = kmalloc(kcmlen, GFP_KERNEL);
-	if(kcmsg = NULL)
-		return -ENOBUFS;
-
-	/* Now copy them over neatly. */
-	memset(kcmsg, 0, kcmlen);
-	ucmsg = CMSG32_FIRSTHDR(kmsg);
-	while(ucmsg != NULL) {
-		__get_user(ucmlen, &ucmsg->cmsg_len);
-		tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
-		       CMSG_ALIGN(sizeof(struct cmsghdr)));
-		kcmsg->cmsg_len = tmp;
-		__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level);
-		__get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type);
-
-		/* Copy over the data. */
-		if(copy_from_user(CMSG_DATA(kcmsg),
-				  CMSG32_DATA(ucmsg),
-				  (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg)))))
-			goto out_free_efault;
-
-		/* Advance. */
-		kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp));
-		ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
-	}
-
-	/* Ok, looks like we made it.  Hook it up and return success. */
-	kmsg->msg_control = kcmsg_base;
-	kmsg->msg_controllen = kcmlen;
-	return 0;
-
-out_free_efault:
-	if(kcmsg_base != (struct cmsghdr *)stackbuf)
-		kfree(kcmsg_base);
-	return -EFAULT;
-}
-
-static void
-put_cmsg32(struct msghdr *kmsg, int level, int type, int len, void *data)
-{
-	struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control;
-	struct cmsghdr32 cmhdr;
-	int cmlen = CMSG32_LEN(len);
-
-	if(cm = NULL || kmsg->msg_controllen < sizeof(*cm)) {
-		kmsg->msg_flags |= MSG_CTRUNC;
-		return;
-	}
-
-	if(kmsg->msg_controllen < cmlen) {
-		kmsg->msg_flags |= MSG_CTRUNC;
-		cmlen = kmsg->msg_controllen;
-	}
-	cmhdr.cmsg_level = level;
-	cmhdr.cmsg_type = type;
-	cmhdr.cmsg_len = cmlen;
-
-	if(copy_to_user(cm, &cmhdr, sizeof cmhdr))
-		return;
-	if(copy_to_user(CMSG32_DATA(cm), data,
-			cmlen - sizeof(struct cmsghdr32)))
-		return;
-	cmlen = CMSG32_SPACE(len);
-	kmsg->msg_control += cmlen;
-	kmsg->msg_controllen -= cmlen;
-}
-
-static void scm_detach_fds32(struct msghdr *kmsg, struct scm_cookie *scm)
-{
-	struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control;
-	int fdmax = (kmsg->msg_controllen - sizeof(struct cmsghdr32))
-		/ sizeof(int);
-	int fdnum = scm->fp->count;
-	struct file **fp = scm->fp->fp;
-	int *cmfptr;
-	int err = 0, i;
-
-	if (fdnum < fdmax)
-		fdmax = fdnum;
-
-	for (i = 0, cmfptr = (int *) CMSG32_DATA(cm);
-	     i < fdmax;
-	     i++, cmfptr++) {
-		int new_fd;
-		err = get_unused_fd();
-		if (err < 0)
-			break;
-		new_fd = err;
-		err = put_user(new_fd, cmfptr);
-		if (err) {
-			put_unused_fd(new_fd);
-			break;
-		}
-		/* Bump the usage count and install the file. */
-		fp[i]->f_count++;
-		current->files->fd[new_fd] = fp[i];
-	}
-
-	if (i > 0) {
-		int cmlen = CMSG32_LEN(i * sizeof(int));
-		if (!err)
-			err = put_user(SOL_SOCKET, &cm->cmsg_level);
-		if (!err)
-			err = put_user(SCM_RIGHTS, &cm->cmsg_type);
-		if (!err)
-			err = put_user(cmlen, &cm->cmsg_len);
-		if (!err) {
-			cmlen = CMSG32_SPACE(i * sizeof(int));
-			kmsg->msg_control += cmlen;
-			kmsg->msg_controllen -= cmlen;
-		}
-	}
-	if (i < fdnum)
-		kmsg->msg_flags |= MSG_CTRUNC;
-
-	/*
-	 * All of the files that fit in the message have had their
-	 * usage counts incremented, so we just free the list.
-	 */
-	__scm_destroy(scm);
-}
-
-/* In these cases we (currently) can just copy to data over verbatim
- * because all CMSGs created by the kernel have well defined types which
- * have the same layout in both the 32-bit and 64-bit API.  One must add
- * some special cased conversions here if we start sending control messages
- * with incompatible types.
- *
- * SCM_RIGHTS and SCM_CREDENTIALS are done by hand in recvmsg32 right after
- * we do our work.  The remaining cases are:
- *
- * SOL_IP	IP_PKTINFO	struct in_pktinfo	32-bit clean
- *		IP_TTL		int			32-bit clean
- *		IP_TOS		__u8			32-bit clean
- *		IP_RECVOPTS	variable length		32-bit clean
- *		IP_RETOPTS	variable length		32-bit clean
- *		(these last two are clean because the types are defined
- *		 by the IPv4 protocol)
- *		IP_RECVERR	struct sock_extended_err +
- *				struct sockaddr_in	32-bit clean
- * SOL_IPV6	IPV6_RECVERR	struct sock_extended_err +
- *				struct sockaddr_in6	32-bit clean
- *		IPV6_PKTINFO	struct in6_pktinfo	32-bit clean
- *		IPV6_HOPLIMIT	int			32-bit clean
- *		IPV6_FLOWINFO	u32			32-bit clean
- *		IPV6_HOPOPTS	ipv6 hop exthdr		32-bit clean
- *		IPV6_DSTOPTS	ipv6 dst exthdr(s)	32-bit clean
- *		IPV6_RTHDR	ipv6 routing exthdr	32-bit clean
- *		IPV6_AUTHHDR	ipv6 auth exthdr	32-bit clean
- */
-static void
-cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr)
-{
-	unsigned char *workbuf, *wp;
-	unsigned long bufsz, space_avail;
-	struct cmsghdr *ucmsg;
-
-	bufsz = ((unsigned long)kmsg->msg_control) - orig_cmsg_uptr;
-	space_avail = kmsg->msg_controllen + bufsz;
-	wp = workbuf = kmalloc(bufsz, GFP_KERNEL);
-	if(workbuf = NULL)
-		goto fail;
-
-	/* To make this more sane we assume the kernel sends back properly
-	 * formatted control messages.  Because of how the kernel will truncate
-	 * the cmsg_len for MSG_TRUNC cases, we need not check that case either.
-	 */
-	ucmsg = (struct cmsghdr *) orig_cmsg_uptr;
-	while(((unsigned long)ucmsg) < ((unsigned long)kmsg->msg_control)) {
-		struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp;
-		int clen64, clen32;
-
-		/* UCMSG is the 64-bit format CMSG entry in user-space.
-		 * KCMSG32 is within the kernel space temporary buffer
-		 * we use to convert into a 32-bit style CMSG.
-		 */
-		__get_user(kcmsg32->cmsg_len, &ucmsg->cmsg_len);
-		__get_user(kcmsg32->cmsg_level, &ucmsg->cmsg_level);
-		__get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type);
-
-		clen64 = kcmsg32->cmsg_len;
-		copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),
-			       clen64 - CMSG_ALIGN(sizeof(*ucmsg)));
-		clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +
-			  CMSG32_ALIGN(sizeof(struct cmsghdr32)));
-		kcmsg32->cmsg_len = clen32;
-
-		ucmsg = (struct cmsghdr *) (((char *)ucmsg) +
-					    CMSG_ALIGN(clen64));
-		wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32));
-	}
-
-	/* Copy back fixed up data, and adjust pointers. */
-	bufsz = (wp - workbuf);
-	copy_to_user((void *)orig_cmsg_uptr, workbuf, bufsz);
-
-	kmsg->msg_control = (struct cmsghdr *)
-		(((char *)orig_cmsg_uptr) + bufsz);
-	kmsg->msg_controllen = space_avail - bufsz;
-
-	kfree(workbuf);
-	return;
-
-fail:
-	/* If we leave the 64-bit format CMSG chunks in there,
-	 * the application could get confused and crash.  So to
-	 * ensure greater recovery, we report no CMSGs.
-	 */
-	kmsg->msg_controllen += bufsz;
-	kmsg->msg_control = (void *) orig_cmsg_uptr;
-}
-
-asmlinkage long
-sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags)
-{
-	struct socket *sock;
-	char address[MAX_SOCK_ADDR];
-	struct iovec iov[UIO_FASTIOV];
-	unsigned char ctl[sizeof(struct cmsghdr) + 20];
-	unsigned char *ctl_buf = ctl;
-	struct msghdr kern_msg;
-	int err, total_len;
-
-	if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
-		return -EFAULT;
-	if(kern_msg.msg_iovlen > UIO_MAXIOV)
-		return -EINVAL;
-	err = verify_iovec32(&kern_msg, iov, address, VERIFY_READ);
-	if (err < 0)
-		goto out;
-	total_len = err;
-
-	if(kern_msg.msg_controllen) {
-		err = cmsghdr_from_user32_to_kern(&kern_msg, ctl, sizeof(ctl));
-		if(err)
-			goto out_freeiov;
-		ctl_buf = kern_msg.msg_control;
-	}
-	kern_msg.msg_flags = user_flags;
-
-	sock = sockfd_lookup(fd, &err);
-	if (sock != NULL) {
-		if (sock->file->f_flags & O_NONBLOCK)
-			kern_msg.msg_flags |= MSG_DONTWAIT;
-		err = sock_sendmsg(sock, &kern_msg, total_len);
-		sockfd_put(sock);
-	}
-
-	/* N.B. Use kfree here, as kern_msg.msg_controllen might change? */
-	if(ctl_buf != ctl)
-		kfree(ctl_buf);
-out_freeiov:
-	if(kern_msg.msg_iov != iov)
-		kfree(kern_msg.msg_iov);
-out:
-	return err;
-}
-
-asmlinkage long
-sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int user_flags)
-{
-	struct iovec iovstack[UIO_FASTIOV];
-	struct msghdr kern_msg;
-	char addr[MAX_SOCK_ADDR];
-	struct socket *sock;
-	struct iovec *iov = iovstack;
-	struct sockaddr *uaddr;
-	int *uaddr_len;
-	unsigned long cmsg_ptr;
-	int err, total_len, len = 0;
-
-	if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
-		return -EFAULT;
-	if(kern_msg.msg_iovlen > UIO_MAXIOV)
-		return -EINVAL;
-
-	uaddr = kern_msg.msg_name;
-	uaddr_len = &user_msg->msg_namelen;
-	err = verify_iovec32(&kern_msg, iov, addr, VERIFY_WRITE);
-	if (err < 0)
-		goto out;
-	total_len = err;
-
-	cmsg_ptr = (unsigned long) kern_msg.msg_control;
-	kern_msg.msg_flags = 0;
-
-	sock = sockfd_lookup(fd, &err);
-	if (sock != NULL) {
-		struct scm_cookie scm;
-
-		if (sock->file->f_flags & O_NONBLOCK)
-			user_flags |= MSG_DONTWAIT;
-		memset(&scm, 0, sizeof(scm));
-		lock_kernel();
-		err = sock->ops->recvmsg(sock, &kern_msg, total_len,
-					 user_flags, &scm);
-		if(err >= 0) {
-			len = err;
-			if(!kern_msg.msg_control) {
-				if(sock->passcred || scm.fp)
-					kern_msg.msg_flags |= MSG_CTRUNC;
-				if(scm.fp)
-					__scm_destroy(&scm);
-			} else {
-				/* If recvmsg processing itself placed some
-				 * control messages into user space, it's is
-				 * using 64-bit CMSG processing, so we need
-				 * to fix it up before we tack on more stuff.
-				 */
-				if((unsigned long) kern_msg.msg_control
-				   != cmsg_ptr)
-					cmsg32_recvmsg_fixup(&kern_msg,
-							     cmsg_ptr);
-
-				/* Wheee... */
-				if(sock->passcred)
-					put_cmsg32(&kern_msg,
-						   SOL_SOCKET, SCM_CREDENTIALS,
-						   sizeof(scm.creds),
-						   &scm.creds);
-				if(scm.fp != NULL)
-					scm_detach_fds32(&kern_msg, &scm);
-			}
-		}
-		unlock_kernel();
-		sockfd_put(sock);
-	}
-
-	if(uaddr != NULL && err >= 0)
-		err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr,
-					uaddr_len);
-	if(cmsg_ptr != 0 && err >= 0) {
-		unsigned long ucmsg_ptr = ((unsigned long)kern_msg.msg_control);
-		__kernel_size_t32 uclen = (__kernel_size_t32) (ucmsg_ptr
-							       - cmsg_ptr);
-		err |= __put_user(uclen, &user_msg->msg_controllen);
-	}
-	if(err >= 0)
-		err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags);
-	if(kern_msg.msg_iov != iov)
-		kfree(kern_msg.msg_iov);
-out:
-	if(err < 0)
-		return err;
-	return len;
-}
-
-extern void check_pending(int signum);
-
-#ifdef CONFIG_MODULES
-
-extern asmlinkage unsigned long sys_create_module(const char *name_user,
-						  size_t size);
-
-asmlinkage unsigned long
-sys32_create_module(const char *name_user, __kernel_size_t32 size)
-{
-	return sys_create_module(name_user, (size_t)size);
-}
-
-extern asmlinkage long sys_init_module(const char *name_user,
-				      struct module *mod_user);
-
-/* Hey, when you're trying to init module, take time and prepare us a nice 64bit
- * module structure, even if from 32bit modutils... Why to pollute kernel... :))
- */
-asmlinkage long
-sys32_init_module(const char *name_user, struct module *mod_user)
-{
-	return sys_init_module(name_user, mod_user);
-}
-
-extern asmlinkage long sys_delete_module(const char *name_user);
-
-asmlinkage long
-sys32_delete_module(const char *name_user)
-{
-	return sys_delete_module(name_user);
-}
-
-struct module_info32 {
-	u32 addr;
-	u32 size;
-	u32 flags;
-	s32 usecount;
-};
-
-/* Query various bits about modules.  */
-
-static inline long
-get_mod_name(const char *user_name, char **buf)
-{
-	unsigned long page;
-	long retval;
-
-	if ((unsigned long)user_name >= TASK_SIZE
-	    && !segment_eq(get_fs (), KERNEL_DS))
-		return -EFAULT;
-
-	page = __get_free_page(GFP_KERNEL);
-	if (!page)
-		return -ENOMEM;
-
-	retval = strncpy_from_user((char *)page, user_name, PAGE_SIZE);
-	if (retval > 0) {
-		if (retval < PAGE_SIZE) {
-			*buf = (char *)page;
-			return retval;
-		}
-		retval = -ENAMETOOLONG;
-	} else if (!retval)
-		retval = -EINVAL;
-
-	free_page(page);
-	return retval;
-}
-
-static inline void
-put_mod_name(char *buf)
-{
-	free_page((unsigned long)buf);
-}
-
-static __inline__ struct module *
-find_module(const char *name)
-{
-	struct module *mod;
-
-	for (mod = module_list; mod ; mod = mod->next) {
-		if (mod->flags & MOD_DELETED)
-			continue;
-		if (!strcmp(mod->name, name))
-			break;
-	}
-
-	return mod;
-}
-
-static int
-qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret)
-{
-	struct module *mod;
-	size_t nmod, space, len;
-
-	nmod = space = 0;
-
-	for (mod = module_list; mod->next != NULL; mod = mod->next, ++nmod) {
-		len = strlen(mod->name)+1;
-		if (len > bufsize)
-			goto calc_space_needed;
-		if (copy_to_user(buf, mod->name, len))
-			return -EFAULT;
-		buf += len;
-		bufsize -= len;
-		space += len;
-	}
-
-	if (put_user(nmod, ret))
-		return -EFAULT;
-	else
-		return 0;
-
-calc_space_needed:
-	space += len;
-	while ((mod = mod->next)->next != NULL)
-		space += strlen(mod->name)+1;
-
-	if (put_user(space, ret))
-		return -EFAULT;
-	else
-		return -ENOSPC;
-}
-
-static int
-qm_deps(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
-{
-	size_t i, space, len;
-
-	if (mod->next = NULL)
-		return -EINVAL;
-	if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING)
-		if (put_user(0, ret))
-			return -EFAULT;
-		else
-			return 0;
-
-	space = 0;
-	for (i = 0; i < mod->ndeps; ++i) {
-		const char *dep_name = mod->deps[i].dep->name;
-
-		len = strlen(dep_name)+1;
-		if (len > bufsize)
-			goto calc_space_needed;
-		if (copy_to_user(buf, dep_name, len))
-			return -EFAULT;
-		buf += len;
-		bufsize -= len;
-		space += len;
-	}
-
-	if (put_user(i, ret))
-		return -EFAULT;
-	else
-		return 0;
-
-calc_space_needed:
-	space += len;
-	while (++i < mod->ndeps)
-		space += strlen(mod->deps[i].dep->name)+1;
-
-	if (put_user(space, ret))
-		return -EFAULT;
-	else
-		return -ENOSPC;
-}
-
-static int
-qm_refs(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
-{
-	size_t nrefs, space, len;
-	struct module_ref *ref;
-
-	if (mod->next = NULL)
-		return -EINVAL;
-	if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING)
-		if (put_user(0, ret))
-			return -EFAULT;
-		else
-			return 0;
-
-	space = 0;
-	for (nrefs = 0, ref = mod->refs; ref ; ++nrefs, ref = ref->next_ref) {
-		const char *ref_name = ref->ref->name;
-
-		len = strlen(ref_name)+1;
-		if (len > bufsize)
-			goto calc_space_needed;
-		if (copy_to_user(buf, ref_name, len))
-			return -EFAULT;
-		buf += len;
-		bufsize -= len;
-		space += len;
-	}
-
-	if (put_user(nrefs, ret))
-		return -EFAULT;
-	else
-		return 0;
-
-calc_space_needed:
-	space += len;
-	while ((ref = ref->next_ref) != NULL)
-		space += strlen(ref->ref->name)+1;
-
-	if (put_user(space, ret))
-		return -EFAULT;
-	else
-		return -ENOSPC;
-}
-
-static inline int
-qm_symbols(struct module *mod, char *buf, size_t bufsize,
-	   __kernel_size_t32 *ret)
-{
-	size_t i, space, len;
-	struct module_symbol *s;
-	char *strings;
-	unsigned *vals;
-
-	if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING)
-		if (put_user(0, ret))
-			return -EFAULT;
-		else
-			return 0;
-
-	space = mod->nsyms * 2*sizeof(u32);
-
-	i = len = 0;
-	s = mod->syms;
-
-	if (space > bufsize)
-		goto calc_space_needed;
-
-	if (!access_ok(VERIFY_WRITE, buf, space))
-		return -EFAULT;
-
-	bufsize -= space;
-	vals = (unsigned *)buf;
-	strings = buf+space;
-
-	for (; i < mod->nsyms ; ++i, ++s, vals += 2) {
-		len = strlen(s->name)+1;
-		if (len > bufsize)
-			goto calc_space_needed;
-
-		if (copy_to_user(strings, s->name, len)
-		    || __put_user(s->value, vals+0)
-		    || __put_user(space, vals+1))
-			return -EFAULT;
-
-		strings += len;
-		bufsize -= len;
-		space += len;
-	}
-
-	if (put_user(i, ret))
-		return -EFAULT;
-	else
-		return 0;
+	__kernel_mode_t32 dir_mode;
+};
 
-calc_space_needed:
-	for (; i < mod->nsyms; ++i, ++s)
-		space += strlen(s->name)+1;
+static void *
+do_smb_super_data_conv(void *raw_data)
+{
+	struct smb_mount_data *s = (struct smb_mount_data *)raw_data;
+	struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data;
 
-	if (put_user(space, ret))
-		return -EFAULT;
-	else
-		return -ENOSPC;
+	s->version = s32->version;
+	s->mounted_uid = s32->mounted_uid;
+	s->uid = s32->uid;
+	s->gid = s32->gid;
+	s->file_mode = s32->file_mode;
+	s->dir_mode = s32->dir_mode;
+	return raw_data;
 }
 
-static inline int
-qm_info(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
+static int
+copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel)
 {
-	int error = 0;
-
-	if (mod->next = NULL)
-		return -EINVAL;
-
-	if (sizeof(struct module_info32) <= bufsize) {
-		struct module_info32 info;
-		info.addr = (unsigned long)mod;
-		info.size = mod->size;
-		info.flags = mod->flags;
-		info.usecount -			((mod_member_present(mod, can_unload)
-			  && mod->can_unload)
-			 ? -1 : atomic_read(&mod->uc.usecount));
-
-		if (copy_to_user(buf, &info, sizeof(struct module_info32)))
-			return -EFAULT;
-	} else
-		error = -ENOSPC;
+	int i;
+	unsigned long page;
+	struct vm_area_struct *vma;
 
-	if (put_user(sizeof(struct module_info32), ret))
+	*kernel = 0;
+	if(!user)
+		return 0;
+	vma = find_vma(current->mm, (unsigned long)user);
+	if(!vma || (unsigned long)user < vma->vm_start)
 		return -EFAULT;
-
-	return error;
+	if(!(vma->vm_flags & VM_READ))
+		return -EFAULT;
+	i = vma->vm_end - (unsigned long) user;
+	if(PAGE_SIZE <= (unsigned long) i)
+		i = PAGE_SIZE - 1;
+	if(!(page = __get_free_page(GFP_KERNEL)))
+		return -ENOMEM;
+	if(copy_from_user((void *) page, user, i)) {
+		free_page(page);
+		return -EFAULT;
+	}
+	*kernel = page;
+	return 0;
 }
 
+extern asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
+				unsigned long new_flags, void *data);
+
+#define SMBFS_NAME	"smbfs"
+#define NCPFS_NAME	"ncpfs"
+
 asmlinkage long
-sys32_query_module(char *name_user, int which, char *buf,
-		   __kernel_size_t32 bufsize, u32 ret)
+sys32_mount(char *dev_name, char *dir_name, char *type,
+	    unsigned long new_flags, u32 data)
 {
-	struct module *mod;
-	int err;
+	unsigned long type_page;
+	int err, is_smb, is_ncp;
 
-	lock_kernel();
-	if (name_user = 0) {
-		/* This finds "kernel_module" which is not exported. */
-		for(mod = module_list; mod->next != NULL; mod = mod->next)
-			;
+	if(!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	is_smb = is_ncp = 0;
+	err = copy_mount_stuff_to_kernel((const void *)type, &type_page);
+	if(err)
+		return err;
+	if(type_page) {
+		is_smb = !strcmp((char *)type_page, SMBFS_NAME);
+		is_ncp = !strcmp((char *)type_page, NCPFS_NAME);
+	}
+	if(!is_smb && !is_ncp) {
+		if(type_page)
+			free_page(type_page);
+		return sys_mount(dev_name, dir_name, type, new_flags,
+				 (void *)AA(data));
 	} else {
-		long namelen;
-		char *name;
+		unsigned long dev_page, dir_page, data_page;
 
-		if ((namelen = get_mod_name(name_user, &name)) < 0) {
-			err = namelen;
-			goto out;
-		}
-		err = -ENOENT;
-		if (namelen = 0) {
-			/* This finds "kernel_module" which is not exported. */
-			for(mod = module_list;
-			    mod->next != NULL;
-			    mod = mod->next) ;
-		} else if ((mod = find_module(name)) = NULL) {
-			put_mod_name(name);
+		err = copy_mount_stuff_to_kernel((const void *)dev_name,
+						 &dev_page);
+		if(err)
 			goto out;
-		}
-		put_mod_name(name);
-	}
-
-	switch (which)
-	{
-	case 0:
-		err = 0;
-		break;
-	case QM_MODULES:
-		err = qm_modules(buf, bufsize, (__kernel_size_t32 *)AA(ret));
-		break;
-	case QM_DEPS:
-		err = qm_deps(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret));
-		break;
-	case QM_REFS:
-		err = qm_refs(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret));
-		break;
-	case QM_SYMBOLS:
-		err = qm_symbols(mod, buf, bufsize,
-				 (__kernel_size_t32 *)AA(ret));
-		break;
-	case QM_INFO:
-		err = qm_info(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret));
-		break;
-	default:
-		err = -EINVAL;
-		break;
+		err = copy_mount_stuff_to_kernel((const void *)dir_name,
+						 &dir_page);
+		if(err)
+			goto dev_out;
+		err = copy_mount_stuff_to_kernel((const void *)AA(data),
+						 &data_page);
+		if(err)
+			goto dir_out;
+		if(is_ncp)
+			do_ncp_super_data_conv((void *)data_page);
+		else if(is_smb)
+			do_smb_super_data_conv((void *)data_page);
+		else
+			panic("The problem is here...");
+		err = do_mount((char *)dev_page, (char *)dir_page,
+				(char *)type_page, new_flags,
+				(void *)data_page);
+		if(data_page)
+			free_page(data_page);
+	dir_out:
+		if(dir_page)
+			free_page(dir_page);
+	dev_out:
+		if(dev_page)
+			free_page(dev_page);
+	out:
+		if(type_page)
+			free_page(type_page);
+		return err;
 	}
-out:
-	unlock_kernel();
-	return err;
 }
 
-struct kernel_sym32 {
-	u32 value;
-	char name[60];
-};
-
-extern asmlinkage long sys_get_kernel_syms(struct kernel_sym *table);
+extern asmlinkage long sys_setreuid(uid_t ruid, uid_t euid);
 
-asmlinkage long
-sys32_get_kernel_syms(struct kernel_sym32 *table)
+asmlinkage long sys32_setreuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid)
 {
-	int len, i;
-	struct kernel_sym *tbl;
-	mm_segment_t old_fs;
+	uid_t sruid, seuid;
 
-	len = sys_get_kernel_syms(NULL);
-	if (!table) return len;
-	tbl = kmalloc (len * sizeof (struct kernel_sym), GFP_KERNEL);
-	if (!tbl) return -ENOMEM;
-	old_fs = get_fs();
-	set_fs (KERNEL_DS);
-	sys_get_kernel_syms(tbl);
-	set_fs (old_fs);
-	for (i = 0; i < len; i++, table += sizeof (struct kernel_sym32)) {
-		if (put_user (tbl[i].value, &table->value) ||
-		    copy_to_user (table->name, tbl[i].name, 60))
-			break;
-	}
-	kfree (tbl);
-	return i;
+	sruid = (ruid = (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid);
+	seuid = (euid = (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid);
+	return sys_setreuid(sruid, seuid);
 }
 
-#else /* CONFIG_MODULES */
-
-asmlinkage unsigned long
-sys32_create_module(const char *name_user, size_t size)
-{
-	return -ENOSYS;
-}
+extern asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid);
 
 asmlinkage long
-sys32_init_module(const char *name_user, struct module *mod_user)
+sys32_setresuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid,
+		__kernel_uid_t32 suid)
 {
-	return -ENOSYS;
-}
+	uid_t sruid, seuid, ssuid;
 
-asmlinkage long
-sys32_delete_module(const char *name_user)
-{
-	return -ENOSYS;
+	sruid = (ruid = (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid);
+	seuid = (euid = (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid);
+	ssuid = (suid = (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)suid);
+	return sys_setresuid(sruid, seuid, ssuid);
 }
 
+extern asmlinkage long sys_setregid(gid_t rgid, gid_t egid);
+
 asmlinkage long
-sys32_query_module(const char *name_user, int which, char *buf, size_t bufsize,
-		 size_t *ret)
+sys32_setregid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid)
 {
-	/* Let the program know about the new interface.  Not that
-	   it'll do them much good.  */
-	if (which = 0)
-		return 0;
+	gid_t srgid, segid;
 
-	return -ENOSYS;
+	srgid = (rgid = (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid);
+	segid = (egid = (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid);
+	return sys_setregid(srgid, segid);
 }
 
+extern asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid);
+
 asmlinkage long
-sys32_get_kernel_syms(struct kernel_sym *table)
+sys32_setresgid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid,
+		__kernel_gid_t32 sgid)
 {
-	return -ENOSYS;
-}
+	gid_t srgid, segid, ssgid;
 
-#endif  /* CONFIG_MODULES */
+	srgid = (rgid = (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid);
+	segid = (egid = (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid);
+	ssgid = (sgid = (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)sgid);
+	return sys_setresgid(srgid, segid, ssgid);
+}
 
 /* Stuff for NFS server syscalls... */
 struct nfsctl_svc32 {
@@ -4820,154 +4293,6 @@
 	return err;
 }
 
-asmlinkage long sys_utimes(char *, struct timeval *);
-
-asmlinkage long
-sys32_utimes(char *filename, struct timeval32 *tvs)
-{
-	char *kfilename;
-	struct timeval ktvs[2];
-	mm_segment_t old_fs;
-	int ret;
-
-	kfilename = getname32(filename);
-	ret = PTR_ERR(kfilename);
-	if (!IS_ERR(kfilename)) {
-		if (tvs) {
-			if (get_tv32(&ktvs[0], tvs) ||
-			    get_tv32(&ktvs[1], 1+tvs))
-				return -EFAULT;
-		}
-
-		old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		ret = sys_utimes(kfilename, &ktvs[0]);
-		set_fs(old_fs);
-
-		putname(kfilename);
-	}
-	return ret;
-}
-
-/* These are here just in case some old ia32 binary calls it. */
-asmlinkage long
-sys32_pause(void)
-{
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	return -ERESTARTNOHAND;
-}
-
-/* PCI config space poking. */
-extern asmlinkage long sys_pciconfig_read(unsigned long bus,
-					 unsigned long dfn,
-					 unsigned long off,
-					 unsigned long len,
-					 unsigned char *buf);
-
-extern asmlinkage long sys_pciconfig_write(unsigned long bus,
-					  unsigned long dfn,
-					  unsigned long off,
-					  unsigned long len,
-					  unsigned char *buf);
-
-asmlinkage long
-sys32_pciconfig_read(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf)
-{
-	return sys_pciconfig_read((unsigned long) bus,
-				  (unsigned long) dfn,
-				  (unsigned long) off,
-				  (unsigned long) len,
-				  (unsigned char *)AA(ubuf));
-}
-
-asmlinkage long
-sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf)
-{
-	return sys_pciconfig_write((unsigned long) bus,
-				   (unsigned long) dfn,
-				   (unsigned long) off,
-				   (unsigned long) len,
-				   (unsigned char *)AA(ubuf));
-}
-
-extern asmlinkage long sys_prctl(int option, unsigned long arg2,
-				unsigned long arg3, unsigned long arg4,
-				unsigned long arg5);
-
-asmlinkage long
-sys32_prctl(int option, u32 arg2, u32 arg3, u32 arg4, u32 arg5)
-{
-	return sys_prctl(option,
-			 (unsigned long) arg2,
-			 (unsigned long) arg3,
-			 (unsigned long) arg4,
-			 (unsigned long) arg5);
-}
-
-
-extern asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
-				    size_t count, loff_t pos);
-
-extern asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
-				     size_t count, loff_t pos);
-
-typedef __kernel_ssize_t32 ssize_t32;
-
-asmlinkage ssize_t32
-sys32_pread(unsigned int fd, char *ubuf, __kernel_size_t32 count,
-	    u32 poshi, u32 poslo)
-{
-	return sys_pread(fd, ubuf, count,
-			 ((loff_t)AA(poshi) << 32) | AA(poslo));
-}
-
-asmlinkage ssize_t32
-sys32_pwrite(unsigned int fd, char *ubuf, __kernel_size_t32 count,
-	     u32 poshi, u32 poslo)
-{
-	return sys_pwrite(fd, ubuf, count,
-			  ((loff_t)AA(poshi) << 32) | AA(poslo));
-}
-
-
-extern asmlinkage long sys_personality(unsigned long);
-
-asmlinkage long
-sys32_personality(unsigned long personality)
-{
-	int ret;
-	if (current->personality = PER_LINUX32 && personality = PER_LINUX)
-		personality = PER_LINUX32;
-	ret = sys_personality(personality);
-	if (ret = PER_LINUX32)
-		ret = PER_LINUX;
-	return ret;
-}
-
-extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset,
-				       size_t count);
-
-asmlinkage long
-sys32_sendfile(int out_fd, int in_fd, __kernel_off_t32 *offset, s32 count)
-{
-	mm_segment_t old_fs = get_fs();
-	int ret;
-	off_t of;
-
-	if (offset && get_user(of, offset))
-		return -EFAULT;
-
-	set_fs(KERNEL_DS);
-	ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
-	set_fs(old_fs);
-
-	if (!ret && offset && put_user(of, offset))
-		return -EFAULT;
-
-	return ret;
-}
-
 /* Handle adjtimex compatability. */
 
 struct timex32 {
@@ -5041,4 +4366,4 @@
 
 	return ret;
 }
-#endif	// NOTYET
+#endif /* NOTYET */
diff -urN linux-2.4.13/arch/ia64/kernel/Makefile linux-2.4.13-lia/arch/ia64/kernel/Makefile
--- linux-2.4.13/arch/ia64/kernel/Makefile	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/Makefile	Wed Oct 10 17:55:55 2001
@@ -16,7 +16,7 @@
 obj-y := acpi.o entry.o gate.o efi.o efi_stub.o ia64_ksyms.o irq.o irq_ia64.o irq_lsapic.o ivt.o \
 	 machvec.o pal.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 iosapic.o
+obj-$(CONFIG_IA64_GENERIC) += iosapic.o
 obj-$(CONFIG_IA64_DIG) += iosapic.o
 obj-$(CONFIG_IA64_PALINFO) += palinfo.o
 obj-$(CONFIG_EFI_VARS) += efivars.o
diff -urN linux-2.4.13/arch/ia64/kernel/acpi.c linux-2.4.13-lia/arch/ia64/kernel/acpi.c
--- linux-2.4.13/arch/ia64/kernel/acpi.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/acpi.c	Thu Oct  4 00:21:39 2001
@@ -9,7 +9,7 @@
  * Copyright (C) 2000 Hewlett-Packard Co.
  * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 2000 Intel Corp.
- * Copyright (C) 2000 J.I. Lee <jung-ik.lee@intel.com>
+ * Copyright (C) 2000,2001 J.I. Lee <jung-ik.lee@intel.com>
  *      ACPI based kernel configuration manager.
  *      ACPI 2.0 & IA64 ext 0.71
  */
@@ -34,6 +34,9 @@
 
 #undef ACPI_DEBUG		/* Guess what this does? */
 
+/* global array to record platform interrupt vectors for generic int routing */
+int platform_irq_list[ACPI_MAX_PLATFORM_IRQS];
+
 /* These are ugly but will be reclaimed by the kernel */
 int __initdata available_cpus;
 int __initdata total_cpus;
@@ -42,7 +45,9 @@
 void (*pm_power_off) (void);
 
 asm (".weak iosapic_register_legacy_irq");
+asm (".weak iosapic_register_platform_irq");
 asm (".weak iosapic_init");
+asm (".weak iosapic_version");
 
 const char *
 acpi_get_sysname (void)
@@ -55,6 +60,8 @@
 	return "hpsim";
 # elif defined (CONFIG_IA64_SGI_SN1)
 	return "sn1";
+# elif defined (CONFIG_IA64_SGI_SN2)
+	return "sn2";
 # elif defined (CONFIG_IA64_DIG)
 	return "dig";
 # else
@@ -65,6 +72,25 @@
 }
 
 /*
+ * Interrupt routing API for device drivers.
+ * Provides the interrupt vector for a generic platform event
+ * (currently only CPEI implemented)
+ */
+int
+acpi_request_vector(u32 int_type)
+{
+	int vector = -1;
+
+	if (int_type < ACPI_MAX_PLATFORM_IRQS) {
+		/* correctable platform error interrupt */
+		vector = platform_irq_list[int_type];
+	} else
+		printk("acpi_request_vector(): invalid interrupt type\n");
+
+	return vector;
+}
+
+/*
  * Configure legacy IRQ information.
  */
 static void __init
@@ -139,15 +165,93 @@
 }
 
 /*
- * Info on platform interrupt sources: NMI. PMI, INIT, etc.
+ * Extract iosapic info from madt (again) to determine which iosapic
+ * this platform interrupt resides in
+ */
+static int __init
+acpi20_which_iosapic (int global_vector, acpi_madt_t *madt, u32 *irq_base, char **iosapic_address)
+{
+	acpi_entry_iosapic_t *iosapic;
+	char *p, *end;
+	int ver, max_pin;
+
+	p = (char *) (madt + 1);
+	end = p + (madt->header.length - sizeof(acpi_madt_t));
+
+	while (p < end) {
+		switch (*p) {
+		      case ACPI20_ENTRY_IO_SAPIC:
+			/* collect IOSAPIC info for platform int use later */
+			iosapic = (acpi_entry_iosapic_t *)p;
+			*irq_base = iosapic->irq_base;
+			*iosapic_address = ioremap(iosapic->address, 0);
+			/* is this the iosapic we're looking for? */
+			ver = iosapic_version(*iosapic_address);
+			max_pin = (ver >> 16) & 0xff;
+			if ((global_vector - *irq_base) <= max_pin)
+				return 0;		/* found it! */
+			break;
+		      default:
+			break;
+		}
+		p += p[1];
+	}
+	return 1;
+}
+
+/*
+ * Info on platform interrupt sources: NMI, PMI, INIT, etc.
  */
 static void __init
-acpi20_platform (char *p)
+acpi20_platform (char *p, acpi_madt_t *madt)
 {
+	int vector;
+	u32 irq_base;
+	char *iosapic_address;
+	unsigned long polarity = 0, trigger = 0;
 	acpi20_entry_platform_src_t *plat = (acpi20_entry_platform_src_t *) p;
 
 	printk("PLATFORM: IOSAPIC %x -> Vector %x on CPU %.04u:%.04u\n",
 	       plat->iosapic_vector, plat->global_vector, plat->eid, plat->id);
+
+	/* record platform interrupt vectors for generic int routing code */
+
+	if (!iosapic_register_platform_irq) {
+		printk("acpi20_platform(): no ACPI platform IRQ support\n");
+		return;
+	}
+
+	/* extract polarity and trigger info from flags */
+	switch (plat->flags) {
+	      case 0x5: polarity = 1; trigger = 1; break;
+	      case 0x7: polarity = 0; trigger = 1; break;
+	      case 0xd: polarity = 1; trigger = 0; break;
+	      case 0xf: polarity = 0; trigger = 0; break;
+	      default:
+		printk("acpi20_platform(): unknown flags 0x%x\n", plat->flags);
+		break;
+	}
+
+	/* which iosapic does this IRQ belong to? */
+	if (acpi20_which_iosapic(plat->global_vector, madt, &irq_base, &iosapic_address)) {
+		printk("acpi20_platform(): I/O SAPIC not found!\n");
+		return;
+	}
+
+	/*
+	 * get vector assignment for this IRQ, set attributes, and program the IOSAPIC
+	 * routing table
+	 */
+	vector = iosapic_register_platform_irq(plat->int_type,
+					       plat->global_vector,
+					       plat->iosapic_vector,
+					       plat->eid,
+					       plat->id,
+					       polarity,
+					       trigger,
+					       irq_base,
+					       iosapic_address);
+	platform_irq_list[plat->int_type] = vector;
 }
 
 /*
@@ -173,8 +277,10 @@
 static void __init
 acpi20_parse_madt (acpi_madt_t *madt)
 {
-	acpi_entry_iosapic_t *iosapic;
+	acpi_entry_iosapic_t *iosapic = NULL;
+	acpi20_entry_lsapic_t *lsapic = NULL;
 	char *p, *end;
+	int i;
 
 	/* Base address of IPI Message Block */
 	if (madt->lapic_address) {
@@ -186,23 +292,27 @@
 	p = (char *) (madt + 1);
 	end = p + (madt->header.length - sizeof(acpi_madt_t));
 
+	/* Initialize platform interrupt vector array */
+	for (i = 0; i < ACPI_MAX_PLATFORM_IRQS; i++)
+		platform_irq_list[i] = -1;
+
 	/*
-	 * Splitted entry parsing to ensure ordering.
+	 * Split-up entry parsing to ensure ordering.
 	 */
-
 	while (p < end) {
 		switch (*p) {
-		case ACPI20_ENTRY_LOCAL_APIC_ADDR_OVERRIDE:
+		      case ACPI20_ENTRY_LOCAL_APIC_ADDR_OVERRIDE:
 			printk("ACPI 2.0 MADT: LOCAL APIC Override\n");
 			acpi20_lapic_addr_override(p);
 			break;
 
-		case ACPI20_ENTRY_LOCAL_SAPIC:
+		      case ACPI20_ENTRY_LOCAL_SAPIC:
 			printk("ACPI 2.0 MADT: LOCAL SAPIC\n");
+			lsapic = (acpi20_entry_lsapic_t *) p;
 			acpi20_lsapic(p);
 			break;
 
-		case ACPI20_ENTRY_IO_SAPIC:
+		      case ACPI20_ENTRY_IO_SAPIC:
 			iosapic = (acpi_entry_iosapic_t *) p;
 			if (iosapic_init)
 				/*
@@ -218,26 +328,25 @@
 					);
 			break;
 
-		case ACPI20_ENTRY_PLATFORM_INT_SOURCE:
+		      case ACPI20_ENTRY_PLATFORM_INT_SOURCE:
 			printk("ACPI 2.0 MADT: PLATFORM INT SOURCE\n");
-			acpi20_platform(p);
+			acpi20_platform(p, madt);
 			break;
 
-		case ACPI20_ENTRY_LOCAL_APIC:
+		      case ACPI20_ENTRY_LOCAL_APIC:
 			printk("ACPI 2.0 MADT: LOCAL APIC entry\n"); break;
-		case ACPI20_ENTRY_IO_APIC:
+		      case ACPI20_ENTRY_IO_APIC:
 			printk("ACPI 2.0 MADT: IO APIC entry\n"); break;
-		case ACPI20_ENTRY_NMI_SOURCE:
+		      case ACPI20_ENTRY_NMI_SOURCE:
 			printk("ACPI 2.0 MADT: NMI SOURCE entry\n"); break;
-		case ACPI20_ENTRY_LOCAL_APIC_NMI:
+		      case ACPI20_ENTRY_LOCAL_APIC_NMI:
 			printk("ACPI 2.0 MADT: LOCAL APIC NMI entry\n"); break;
-		case ACPI20_ENTRY_INT_SRC_OVERRIDE:
+		      case ACPI20_ENTRY_INT_SRC_OVERRIDE:
 			break;
-		default:
+		      default:
 			printk("ACPI 2.0 MADT: unknown entry skip\n"); break;
 			break;
 		}
-
 		p += p[1];
 	}
 
@@ -245,16 +354,35 @@
 	end = p + (madt->header.length - sizeof(acpi_madt_t));
 
 	while (p < end) {
+		switch (*p) {
+		      case ACPI20_ENTRY_LOCAL_APIC:
+			if (lsapic) break;
+			printk("ACPI 2.0 MADT: LOCAL APIC entry\n");
+			/* parse local apic if there's no local Sapic */
+			break;
+		      case ACPI20_ENTRY_IO_APIC:
+			if (iosapic) break;
+			printk("ACPI 2.0 MADT: IO APIC entry\n");
+			/* parse ioapic if there's no ioSapic */
+			break;
+		      default:
+			break;
+		}
+		p += p[1];
+	}
 
+	p = (char *) (madt + 1);
+	end = p + (madt->header.length - sizeof(acpi_madt_t));
+
+	while (p < end) {
 		switch (*p) {
-		case ACPI20_ENTRY_INT_SRC_OVERRIDE:
+		      case ACPI20_ENTRY_INT_SRC_OVERRIDE:
 			printk("ACPI 2.0 MADT: INT SOURCE Override\n");
 			acpi_legacy_irq(p);
 			break;
-		default:
+		      default:
 			break;
 		}
-
 		p += p[1];
 	}
 
diff -urN linux-2.4.13/arch/ia64/kernel/efi.c linux-2.4.13-lia/arch/ia64/kernel/efi.c
--- linux-2.4.13/arch/ia64/kernel/efi.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/efi.c	Thu Oct  4 00:21:39 2001
@@ -482,5 +482,7 @@
 static void __exit
 efivars_exit(void)
 {
+#ifdef CONFIG_PROC_FS
  	remove_proc_entry(efi_dir->name, NULL);
+#endif
 }
diff -urN linux-2.4.13/arch/ia64/kernel/efi_stub.S linux-2.4.13-lia/arch/ia64/kernel/efi_stub.S
--- linux-2.4.13/arch/ia64/kernel/efi_stub.S	Thu Apr  5 12:51:47 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/efi_stub.S	Thu Oct  4 00:21:39 2001
@@ -1,8 +1,8 @@
 /*
  * EFI call stub.
  *
- * Copyright (C) 1999-2000 Hewlett-Packard Co
- * Copyright (C) 1999-2000 David Mosberger <davidm@hpl.hp.com>
+ * Copyright (C) 1999-2001 Hewlett-Packard Co
+ *	David Mosberger <davidm@hpl.hp.com>
  *
  * This stub allows us to make EFI calls in physical mode with interrupts
  * turned off.  We need this because we can't call SetVirtualMap() until
@@ -68,17 +68,17 @@
 	;;
 	andcm r16=loc3,r16		// get psr with IT, DT, and RT bits cleared
 	mov out3=in4
-	br.call.sptk.few rp=ia64_switch_mode
+	br.call.sptk.many rp=ia64_switch_mode
 .ret0:	mov out4=in5
 	mov out5=in6
 	mov out6=in7
-	br.call.sptk.few rp¶		// call the EFI function
+	br.call.sptk.many rp¶		// call the EFI function
 .ret1:	mov ar.rsc=0			// put RSE in enforced lazy, LE mode
 	mov r16=loc3
-	br.call.sptk.few rp=ia64_switch_mode // return to virtual mode
+	br.call.sptk.many rp=ia64_switch_mode // return to virtual mode
 .ret2:	mov ar.rsc=loc4			// restore RSE configuration
 	mov ar.pfs=loc1
 	mov rp=loc0
 	mov gp=loc2
-	br.ret.sptk.few rp
+	br.ret.sptk.many rp
 END(efi_call_phys)
diff -urN linux-2.4.13/arch/ia64/kernel/efivars.c linux-2.4.13-lia/arch/ia64/kernel/efivars.c
--- linux-2.4.13/arch/ia64/kernel/efivars.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/efivars.c	Wed Oct 10 17:40:37 2001
@@ -65,6 +65,7 @@
 
 MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
 MODULE_DESCRIPTION("/proc interface to EFI Variables");
+MODULE_LICENSE("GPL");
 
 #define EFIVARS_VERSION "0.03 2001-Apr-20"
 
@@ -276,21 +277,20 @@
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
 
-	spin_lock(&efivars_lock);
 	MOD_INC_USE_COUNT;
 
 	var_data = kmalloc(size, GFP_KERNEL);
 	if (!var_data) {
 		MOD_DEC_USE_COUNT;
-		spin_unlock(&efivars_lock);
 		return -ENOMEM;
 	}
 	if (copy_from_user(var_data, buffer, size)) {
 		MOD_DEC_USE_COUNT;
-		spin_unlock(&efivars_lock);
+                kfree(var_data);
 		return -EFAULT;
 	}
 
+	spin_lock(&efivars_lock);
 
 	/* Since the data ptr we've currently got is probably for
 	   a different variable find the right variable.
diff -urN linux-2.4.13/arch/ia64/kernel/entry.S linux-2.4.13-lia/arch/ia64/kernel/entry.S
--- linux-2.4.13/arch/ia64/kernel/entry.S	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/entry.S	Wed Oct 24 18:13:32 2001
@@ -4,7 +4,7 @@
  * Kernel entry points.
  *
  * Copyright (C) 1998-2001 Hewlett-Packard Co
- * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
  * Copyright (C) 1999 Asit Mallick <Asit.K.Mallick@intel.com>
@@ -15,7 +15,7 @@
  * kernel stack. This allows us to handle interrupts without changing
  * to physical mode.
  *
- * Jonathan Nickin	<nicklin@missioncriticallinux.com>
+ * Jonathan Nicklin	<nicklin@missioncriticallinux.com>
  * Patrick O'Rourke	<orourke@missioncriticallinux.com>
  * 11/07/2000
  /
@@ -55,7 +55,7 @@
 	mov out1=in1			// argv
 	mov out2=in2			// envp
 	add out3\x16,sp			// regs
-	br.call.sptk.few rp=sys_execve
+	br.call.sptk.many rp=sys_execve
 .ret0:	cmp4.ge p6,p7=r8,r0
 	mov ar.pfs=loc1			// restore ar.pfs
 	sxt4 r8=r8			// return 64-bit result
@@ -64,7 +64,7 @@
 (p6)	cmp.ne pKern,pUser=r0,r0	// a successful execve() lands us in user-mode...
 	mov rp=loc0
 (p6)	mov ar.pfs=r0			// clear ar.pfs on success
-(p7)	br.ret.sptk.few rp
+(p7)	br.ret.sptk.many rp
 
 	/*
 	 * In theory, we'd have to zap this state only to prevent leaking of
@@ -85,7 +85,7 @@
 	ldf.fill f26=[sp];	ldf.fill f27=[sp];	mov f28ð
 	ldf.fill f29=[sp];	ldf.fill f30=[sp];	mov f31ð
 	mov ar.lc=0
-	br.ret.sptk.few rp
+	br.ret.sptk.many rp
 END(ia64_execve)
 
 GLOBAL_ENTRY(sys_clone2)
@@ -99,7 +99,7 @@
 	mov out3=in2
 	adds out2=IA64_SWITCH_STACK_SIZE+16,sp	// out2 = &regs
 	mov out0=in0				// out0 = clone_flags
-	br.call.sptk.few rp=do_fork
+	br.call.sptk.many rp=do_fork
 .ret1:	.restore sp
 	adds sp=IA64_SWITCH_STACK_SIZE,sp	// pop the switch stack
 	mov ar.pfs=loc1
@@ -118,7 +118,7 @@
 	mov out3=0
 	adds out2=IA64_SWITCH_STACK_SIZE+16,sp	// out2 = &regs
 	mov out0=in0				// out0 = clone_flags
-	br.call.sptk.few rp=do_fork
+	br.call.sptk.many rp=do_fork
 .ret2:	.restore sp
 	adds sp=IA64_SWITCH_STACK_SIZE,sp	// pop the switch stack
 	mov ar.pfs=loc1
@@ -143,7 +143,7 @@
 	shr.u r26=r20,KERNEL_PG_SHIFT
 	mov r16=KERNEL_PG_NUM
 	;;
-	cmp.ne p6,p7=r26,r16		// check >= 64M && < 128M
+	cmp.ne p6,p7=r26,r16		// check whether r26 != KERNEL_PG_NUM
 	adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0
 	;;
 	/*
@@ -151,12 +151,13 @@
 	 * again.
 	 */
 (p6)	cmp.eq p7,p6=r26,r27
-(p6)	br.cond.dpnt.few .map
+(p6)	br.cond.dpnt .map
 	;;
-.done:	ld8 sp=[r21]			// load kernel stack pointer of new task
+.done:
 (p6)	ssm psr.ic			// if we we had to map, renable the psr.ic bit FIRST!!!
 	;;
 (p6)	srlz.d
+	ld8 sp=[r21]			// load kernel stack pointer of new task
 	mov IA64_KR(CURRENT)=r20	// update "current" application register
 	mov r8=r13			// return pointer to previously running task
 	mov r13=in0			// set "current" pointer
@@ -167,7 +168,7 @@
 #ifdef CONFIG_SMP
 	sync.i				// ensure "fc"s done by this CPU are visible on other CPUs
 #endif
-	br.ret.sptk.few rp		// boogie on out in new context
+	br.ret.sptk.many rp		// boogie on out in new context
 
 .map:
 	rsm psr.i | psr.ic
@@ -184,7 +185,7 @@
 	mov IA64_KR(CURRENT_STACK)=r26	// remember last page we mapped...
 	;;
 	itr.d dtr[r25]=r23		// wire in new mapping...
-	br.cond.sptk.many .done
+	br.cond.sptk .done
 END(ia64_switch_to)
 
 /*
@@ -212,24 +213,18 @@
 	.save @priunat,r17
 	mov r17=ar.unat		// preserve caller's
 	.body
-#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC))
 	adds r3€,sp
 	;;
 	lfetch.fault.excl.nt1 [r3],128
-#endif
 	mov ar.rsc=0		// put RSE in mode: enforced lazy, little endian, pl 0
-#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC))
 	adds r2\x16+128,sp
 	;;
 	lfetch.fault.excl.nt1 [r2],128
 	lfetch.fault.excl.nt1 [r3],128
-#endif
 	adds r14=SW(R4)+16,sp
-#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC))
 	;;
 	lfetch.fault.excl [r2]
 	lfetch.fault.excl [r3]
-#endif
 	adds r15=SW(R5)+16,sp
 	;;
 	mov r18=ar.fpsr		// preserve fpsr
@@ -309,7 +304,7 @@
 	st8 [r2]=r20		// save ar.bspstore
 	st8 [r3]=r21		// save predicate registers
 	mov ar.rsc=3		// put RSE back into eager mode, pl 0
-	br.cond.sptk.few b7
+	br.cond.sptk.many b7
 END(save_switch_stack)
 
 /*
@@ -321,11 +316,9 @@
 ENTRY(load_switch_stack)
 	.prologue
 	.altrp b7
-	.body
-#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC))
 
+	.body
 	lfetch.fault.nt1 [sp]
-#endif
 	adds r2=SW(AR_BSPSTORE)+16,sp
 	adds r3=SW(AR_UNAT)+16,sp
 	mov ar.rsc=0						// put RSE into enforced lazy mode
@@ -426,7 +419,7 @@
 	;;
 (p6)	st4 [r2]=r8
 (p6)	mov r8=-1
-	br.ret.sptk.few rp
+	br.ret.sptk.many rp
 END(__ia64_syscall)
 
 	/*
@@ -441,11 +434,11 @@
 	.body
 	mov loc2¶
 	;;
-	br.call.sptk.few rp=syscall_trace
+	br.call.sptk.many rp=syscall_trace
 .ret3:	mov rp=loc0
 	mov ar.pfs=loc1
 	mov b6=loc2
-	br.ret.sptk.few rp
+	br.ret.sptk.many rp
 END(invoke_syscall_trace)
 
 	/*
@@ -462,21 +455,21 @@
 
 GLOBAL_ENTRY(ia64_trace_syscall)
 	PT_REGS_UNWIND_INFO(0)
-	br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch syscall args
-.ret6:	br.call.sptk.few rp¶			// do the syscall
+	br.call.sptk.many rp=invoke_syscall_trace // give parent a chance to catch syscall args
+.ret6:	br.call.sptk.many rp¶			// do the syscall
 strace_check_retval:
 	cmp.lt p6,p0=r8,r0			// syscall failed?
 	adds r2=PT(R8)+16,sp			// r2 = &pt_regs.r8
 	adds r3=PT(R10)+16,sp			// r3 = &pt_regs.r10
 	mov r10=0
-(p6)	br.cond.sptk.few strace_error		// syscall failed ->
+(p6)	br.cond.sptk strace_error		// syscall failed ->
 	;;					// avoid RAW on r10
 strace_save_retval:
 .mem.offset 0,0;	st8.spill [r2]=r8	// store return value in slot for r8
 .mem.offset 8,0;	st8.spill [r3]=r10	// clear error indication in slot for r10
 ia64_strace_leave_kernel:
-	br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch return value
-.rety:	br.cond.sptk.many ia64_leave_kernel
+	br.call.sptk.many rp=invoke_syscall_trace // give parent a chance to catch return value
+.rety:	br.cond.sptk ia64_leave_kernel
 
 strace_error:
 	ld8 r3=[r2]				// load pt_regs.r8
@@ -487,7 +480,7 @@
 	;;
 (p6)	mov r10=-1
 (p6)	mov r8=r9
-	br.cond.sptk.few strace_save_retval
+	br.cond.sptk strace_save_retval
 END(ia64_trace_syscall)
 
 GLOBAL_ENTRY(ia64_ret_from_clone)
@@ -497,7 +490,7 @@
 	 * Called by ia64_switch_to after do_fork()->copy_thread().  r8 contains the
 	 * address of the previously executing task.
 	 */
-	br.call.sptk.few rp=invoke_schedule_tail
+	br.call.sptk.many rp=ia64_invoke_schedule_tail
 .ret8:
 	adds r2=IA64_TASK_PTRACE_OFFSET,r13
 	;;
@@ -505,7 +498,7 @@
 	;;
 	mov r8=0
 	tbit.nz p6,p0=r2,PT_TRACESYS_BIT
-(p6)	br strace_check_retval
+(p6)	br.cond.spnt strace_check_retval
 	;;					// added stop bits to prevent r8 dependency
 END(ia64_ret_from_clone)
 	// fall through
@@ -519,7 +512,7 @@
 (p6)	st8.spill [r2]=r8	// store return value in slot for r8 and set unat bit
 	.mem.offset 8,0
 (p6)	st8.spill [r3]=r0	// clear error indication in slot for r10 and set unat bit
-(p7)	br.cond.spnt.few handle_syscall_error	// handle potential syscall failure
+(p7)	br.cond.spnt handle_syscall_error	// handle potential syscall failure
 END(ia64_ret_from_syscall)
 	// fall through
 GLOBAL_ENTRY(ia64_leave_kernel)
@@ -527,22 +520,22 @@
 	lfetch.fault [sp]
 	movl r14=.restart
 	;;
-	MOVBR(.ret.sptk,rp,r14,.restart)
+	mov.ret.sptk rp=r14,.restart
 .restart:
 	adds r17=IA64_TASK_NEED_RESCHED_OFFSET,r13
 	adds r18=IA64_TASK_SIGPENDING_OFFSET,r13
 #ifdef CONFIG_PERFMON
-	adds r19=IA64_TASK_PFM_NOTIFY_OFFSET,r13
+	adds r19=IA64_TASK_PFM_MUST_BLOCK_OFFSET,r13
 #endif
 	;;
 #ifdef CONFIG_PERFMON
-	ld8 r19=[r19]				// load current->task.pfm_notify
+(pUser)	ld8 r19=[r19]				// load current->thread.pfm_must_block
 #endif
-	ld8 r17=[r17]				// load current->need_resched
-	ld4 r18=[r18]				// load current->sigpending
+(pUser)	ld8 r17=[r17]				// load current->need_resched
+(pUser)	ld4 r18=[r18]				// load current->sigpending
 	;;
 #ifdef CONFIG_PERFMON
-	cmp.ne p9,p0=r19,r0			// current->task.pfm_notify != 0?
+(pUser)	cmp.ne.unc p9,p0=r19,r0			// current->thread.pfm_must_block != 0?
 #endif
 (pUser)	cmp.ne.unc p7,p0=r17,r0			// current->need_resched != 0?
 (pUser)	cmp.ne.unc p8,p0=r18,r0			// current->sigpending != 0?
@@ -550,7 +543,7 @@
 	adds r2=PT(R8)+16,r12
 	adds r3=PT(R9)+16,r12
 #ifdef CONFIG_PERFMON
-(p9)	br.call.spnt.many b7=pfm_overflow_notify
+(p9)	br.call.spnt.many b7=pfm_block_on_overflow
 #endif
 #if __GNUC__ < 3
 (p7)	br.call.spnt.many b7=invoke_schedule
@@ -650,13 +643,13 @@
 	movl r17=PERCPU_ADDR+IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET
 	;;
 	ld4 r17=[r17]		// r17 = cpu_data->phys_stacked_size_p8
-(pKern)	br.cond.dpnt.few skip_rbs_switch
+(pKern)	br.cond.dpnt skip_rbs_switch
 	/*
 	 * Restore user backing store.
 	 *
 	 * NOTE: alloc, loadrs, and cover can't be predicated.
 	 */
-(pNonSys) br.cond.dpnt.few dont_preserve_current_frame
+(pNonSys) br.cond.dpnt dont_preserve_current_frame
 	cover				// add current frame into dirty partition
 	;;
 	mov r19=ar.bsp			// get new backing store pointer
@@ -687,7 +680,7 @@
 	shladd in0=loc1,3,r17
 	mov in1=0
 	;;
-	.align 32
+//	.align 32	// gas-2.11.90 is unable to generate a stop bit after .align
 rse_clear_invalid:
 	// cycle 0
  { .mii
@@ -706,7 +699,7 @@
 }{ .mib
 	mov loc3=0
 	mov loc4=0
-(pRecurse) br.call.sptk.few b6=rse_clear_invalid
+(pRecurse) br.call.sptk.many b6=rse_clear_invalid
 
 }{ .mfi	// cycle 2
 	mov loc5=0
@@ -715,7 +708,7 @@
 }{ .mib
 	mov loc6=0
 	mov loc7=0
-(pReturn) br.ret.sptk.few b6
+(pReturn) br.ret.sptk.many b6
 }
 #	undef pRecurse
 #	undef pReturn
@@ -761,24 +754,24 @@
 	;;
 .mem.offset 0,0; st8.spill [r2]=r9	// store errno in pt_regs.r8 and set unat bit
 .mem.offset 8,0; st8.spill [r3]=r10	// store error indication in pt_regs.r10 and set unat bit
-	br.cond.sptk.many ia64_leave_kernel
+	br.cond.sptk ia64_leave_kernel
 END(handle_syscall_error)
 
 	/*
 	 * Invoke schedule_tail(task) while preserving in0-in7, which may be needed
 	 * in case a system call gets restarted.
 	 */
-ENTRY(invoke_schedule_tail)
+GLOBAL_ENTRY(ia64_invoke_schedule_tail)
 	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
 	alloc loc1=ar.pfs,8,2,1,0
 	mov loc0=rp
 	mov out0=r8				// Address of previous task
 	;;
-	br.call.sptk.few rp=schedule_tail
+	br.call.sptk.many rp=schedule_tail
 .ret11:	mov ar.pfs=loc1
 	mov rp=loc0
 	br.ret.sptk.many rp
-END(invoke_schedule_tail)
+END(ia64_invoke_schedule_tail)
 
 #if __GNUC__ < 3
 
@@ -797,7 +790,7 @@
 	mov loc0=rp
 	;;
 	.body
-	br.call.sptk.few rp=schedule
+	br.call.sptk.many rp=schedule
 .ret14:	mov ar.pfs=loc1
 	mov rp=loc0
 	br.ret.sptk.many rp
@@ -824,7 +817,7 @@
 	.spillpsp ar.unat, 16			// (note that offset is relative to psp+0x10!)
 	st8 [sp]=r9,-16				// allocate space for ar.unat and save it
 	.body
-	br.call.sptk.few rp=ia64_do_signal
+	br.call.sptk.many rp=ia64_do_signal
 .ret15:	.restore sp
 	adds sp\x16,sp				// pop scratch stack space
 	;;
@@ -849,7 +842,7 @@
 	.spillpsp ar.unat, 16			// (note that offset is relative to psp+0x10!)
 	st8 [sp]=r9,-16				// allocate space for ar.unat and save it
 	.body
-	br.call.sptk.few rp=ia64_rt_sigsuspend
+	br.call.sptk.many rp=ia64_rt_sigsuspend
 .ret17:	.restore sp
 	adds sp\x16,sp				// pop scratch stack space
 	;;
@@ -871,15 +864,15 @@
 	cmp.eq pNonSys,pSys=r0,r0		// sigreturn isn't a normal syscall...
 	;;
 	adds out0\x16,sp				// out0 = &sigscratch
-	br.call.sptk.few rp=ia64_rt_sigreturn
+	br.call.sptk.many rp=ia64_rt_sigreturn
 .ret19:	.restore sp 0
 	adds sp\x16,sp
 	;;
 	ld8 r9=[sp]				// load new ar.unat
-	MOVBR(.sptk,b7,r8,ia64_leave_kernel)
+	mov.sptk b7=r8,ia64_leave_kernel
 	;;
 	mov ar.unat=r9
-	br b7
+	br.many b7
 END(sys_rt_sigreturn)
 
 GLOBAL_ENTRY(ia64_prepare_handle_unaligned)
@@ -890,7 +883,7 @@
 	mov r16=r0
 	.prologue
 	DO_SAVE_SWITCH_STACK
-	br.call.sptk.few rp=ia64_handle_unaligned // stack frame setup in ivt
+	br.call.sptk.many rp=ia64_handle_unaligned // stack frame setup in ivt
 .ret21:	.body
 	DO_LOAD_SWITCH_STACK
 	br.cond.sptk.many rp			  // goes to ia64_leave_kernel
@@ -920,14 +913,14 @@
 	adds out0\x16,sp				// &info
 	mov out1=r13				// current
 	adds out2\x16+EXTRA_FRAME_SIZE,sp	// &switch_stack
-	br.call.sptk.few rp=unw_init_frame_info
+	br.call.sptk.many rp=unw_init_frame_info
 1:	adds out0\x16,sp				// &info
 	mov b6=loc2
 	mov loc2=gp				// save gp across indirect function call
 	;;
 	ld8 gp=[in0]
 	mov out1=in1				// arg
-	br.call.sptk.few rp¶			// invoke the callback function
+	br.call.sptk.many rp¶			// invoke the callback function
 1:	mov gp=loc2				// restore gp
 
 	// For now, we don't allow changing registers from within
@@ -1026,7 +1019,7 @@
 	data8 sys_setpriority
 	data8 sys_statfs
 	data8 sys_fstatfs
-	data8 ia64_ni_syscall			// 1105
+	data8 sys_gettid			// 1105
 	data8 sys_semget
 	data8 sys_semop
 	data8 sys_semctl
@@ -1137,7 +1130,7 @@
 	data8 sys_clone2
 	data8 sys_getdents64
 	data8 sys_getunwind			// 1215
-	data8 ia64_ni_syscall
+	data8 sys_readahead
 	data8 ia64_ni_syscall
 	data8 ia64_ni_syscall
 	data8 ia64_ni_syscall
diff -urN linux-2.4.13/arch/ia64/kernel/entry.h linux-2.4.13-lia/arch/ia64/kernel/entry.h
--- linux-2.4.13/arch/ia64/kernel/entry.h	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/entry.h	Thu Oct  4 00:21:39 2001
@@ -1,12 +1,5 @@
 #include <linux/config.h>
 
-/* XXX fixme */
-#if defined(CONFIG_ITANIUM_B1_SPECIFIC)
-# define MOVBR(type,br,gr,lbl)	mov br=gr
-#else
-# define MOVBR(type,br,gr,lbl)	mov##type br=gr,lbl
-#endif
-
 /*
  * Preserved registers that are shared between code in ivt.S and entry.S.  Be
  * careful not to step on these!
@@ -62,7 +55,7 @@
 	;;					\
 	.fframe IA64_SWITCH_STACK_SIZE;		\
 	adds sp=-IA64_SWITCH_STACK_SIZE,sp;	\
-	MOVBR(.ret.sptk,b7,r28,1f);		\
+	mov.ret.sptk b7=r28,1f;			\
 	SWITCH_STACK_SAVES(0);			\
 	br.cond.sptk.many save_switch_stack;	\
 1:
@@ -71,7 +64,7 @@
 	movl r28\x1f;				\
 	;;					\
 	invala;					\
-	MOVBR(.ret.sptk,b7,r28,1f);		\
+	mov.ret.sptk b7=r28,1f;			\
 	br.cond.sptk.many load_switch_stack;	\
 1:	.restore sp;				\
 	adds sp=IA64_SWITCH_STACK_SIZE,sp
diff -urN linux-2.4.13/arch/ia64/kernel/fw-emu.c linux-2.4.13-lia/arch/ia64/kernel/fw-emu.c
--- linux-2.4.13/arch/ia64/kernel/fw-emu.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/fw-emu.c	Wed Oct 24 18:13:46 2001
@@ -174,6 +174,43 @@
 "	;;\n"
 "	mov ar.lc=r9\n"
 "	mov r8=r0\n"
+"	;;\n"
+"1:	cmp.eq p6,p7\x15,r28		/* PAL_PERF_MON_INFO */\n"
+"(p7)	br.cond.sptk.few 1f\n"
+"	mov r8=0			/* status = 0 */\n"
+"	movl r9 =0x12082004		/* generic=4 width2 retired=8 cycles\x18 */\n"
+"	mov r10=0			/* reserved */\n"
+"	mov r11=0			/* reserved */\n"
+"	mov r16=0xffff			/* implemented PMC */\n"
+"	mov r17=0xffff			/* implemented PMD */\n"
+"	add r18=8,r29			/* second index */\n"
+"	;;\n"
+"	st8 [r29]=r16,16		/* store implemented PMC */\n"
+"	st8 [r18]=r0,16			/* clear remaining bits  */\n"
+"	;;\n"
+"	st8 [r29]=r0,16			/* store implemented PMC */\n"
+"	st8 [r18]=r0,16			/* clear remaining bits  */\n"
+"	;;\n"
+"	st8 [r29]=r17,16		/* store implemented PMD */\n"
+"	st8 [r18]=r0,16			/* clear remaining bits  */\n"
+"	mov r16=0xf0			/* cycles count capable PMC */\n"
+"	;;\n"
+"	st8 [r29]=r0,16			/* store implemented PMC */\n"
+"	st8 [r18]=r0,16			/* clear remaining bits  */\n"
+"	mov r17=0x10			/* retired bundles capable PMC */\n"
+"	;;\n"
+"	st8 [r29]=r16,16		/* store cycles capable */\n"
+"	st8 [r18]=r0,16			/* clear remaining bits  */\n"
+"	;;\n"
+"	st8 [r29]=r0,16			/* store implemented PMC */\n"
+"	st8 [r18]=r0,16			/* clear remaining bits  */\n"
+"	;;\n"
+"	st8 [r29]=r17,16		/* store retired bundle capable */\n"
+"	st8 [r18]=r0,16			/* clear remaining bits  */\n"
+"	;;\n"
+"	st8 [r29]=r0,16			/* store implemented PMC */\n"
+"	st8 [r18]=r0,16			/* clear remaining bits  */\n"
+"	;;\n"
 "1:	br.cond.sptk.few rp\n"
 "stacked:\n"
 "	br.ret.sptk.few rp\n"
@@ -414,11 +451,6 @@
 #ifdef CONFIG_IA64_SDV
 	strcpy(sal_systab->oem_id, "Intel");
 	strcpy(sal_systab->product_id, "SDV");
-#endif
-
-#ifdef CONFIG_IA64_SGI_SN1_SIM
-	strcpy(sal_systab->oem_id, "SGI");
-	strcpy(sal_systab->product_id, "SN1");
 #endif
 
 	/* fill in an entry point: */
diff -urN linux-2.4.13/arch/ia64/kernel/gate.S linux-2.4.13-lia/arch/ia64/kernel/gate.S
--- linux-2.4.13/arch/ia64/kernel/gate.S	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/gate.S	Thu Oct  4 00:21:39 2001
@@ -3,7 +3,7 @@
  * region.  For now, it contains the signal trampoline code only.
  *
  * Copyright (C) 1999-2001 Hewlett-Packard Co
- * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ * 	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #include <asm/asmmacro.h>
@@ -18,7 +18,6 @@
 #	define ARG0_OFF		(16 + IA64_SIGFRAME_ARG0_OFFSET)
 #	define ARG1_OFF		(16 + IA64_SIGFRAME_ARG1_OFFSET)
 #	define ARG2_OFF		(16 + IA64_SIGFRAME_ARG2_OFFSET)
-#	define RBS_BASE_OFF	(16 + IA64_SIGFRAME_RBS_BASE_OFFSET)
 #	define SIGHANDLER_OFF	(16 + IA64_SIGFRAME_HANDLER_OFFSET)
 #	define SIGCONTEXT_OFF	(16 + IA64_SIGFRAME_SIGCONTEXT_OFFSET)
 
@@ -32,6 +31,8 @@
 #	define PR_OFF		IA64_SIGCONTEXT_PR_OFFSET
 #	define RP_OFF		IA64_SIGCONTEXT_B0_OFFSET
 #	define SP_OFF		IA64_SIGCONTEXT_R12_OFFSET
+#	define RBS_BASE_OFF	IA64_SIGCONTEXT_RBS_BASE_OFFSET
+#	define LOADRS_OFF	IA64_SIGCONTEXT_LOADRS_OFFSET
 #	define base0		r2
 #	define base1		r3
 	/*
@@ -73,34 +74,37 @@
 	.vframesp SP_OFF+SIGCONTEXT_OFF
 	.body
 
-	.prologue
+	.label_state 1
+
 	adds base0=SIGHANDLER_OFF,sp
-	adds base1=RBS_BASE_OFF,sp
+	adds base1=RBS_BASE_OFF+SIGCONTEXT_OFF,sp
 	br.call.sptk.many rp\x1f
 1:
 	ld8 r17=[base0],(ARG0_OFF-SIGHANDLER_OFF)	// get pointer to signal handler's plabel
-	ld8 r15=[base1],(ARG1_OFF-RBS_BASE_OFF)		// get address of new RBS base (or NULL)
+	ld8 r15=[base1]					// get address of new RBS base (or NULL)
 	cover				// push args in interrupted frame onto backing store
 	;;
+	cmp.ne p8,p0=r15,r0		// do we need to switch the rbs?
+	mov.m r9=ar.bsp			// fetch ar.bsp
+	.spillsp.p p8, ar.rnat, RNAT_OFF+SIGCONTEXT_OFF
+(p8)	br.cond.spnt setup_rbs		// yup -> (clobbers r14, r15, and r16)
+back_from_setup_rbs:
+
 	.save ar.pfs, r8
 	alloc r8=ar.pfs,0,0,3,0		// get CFM0, EC0, and CPL0 into r8
 	ld8 out0=[base0],16		// load arg0 (signum)
+	adds base1=(ARG1_OFF-(RBS_BASE_OFF+SIGCONTEXT_OFF)),base1
 	;;
 	ld8 out1=[base1]		// load arg1 (siginfop)
 	ld8 r10=[r17],8			// get signal handler entry point
 	;;
 	ld8 out2=[base0]		// load arg2 (sigcontextp)
 	ld8 gp=[r17]			// get signal handler's global pointer
-	cmp.ne p8,p0=r15,r0		// do we need to switch the rbs?
 
-	mov.m r17=ar.bsp		// fetch ar.bsp
-	.spillsp.p p8, ar.rnat, RNAT_OFF+SIGCONTEXT_OFF
-(p8)	br.cond.spnt.few setup_rbs	// yup -> (clobbers r14 and r16)
-back_from_setup_rbs:
 	adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp
 	;;
 	.spillsp ar.bsp, BSP_OFF+SIGCONTEXT_OFF
-	st8 [base0]=r17,(CFM_OFF-BSP_OFF)	// save sc_ar_bsp
+	st8 [base0]=r9,(CFM_OFF-BSP_OFF)	// save sc_ar_bsp
 	dep r8=0,r8,38,26			// clear EC0, CPL0 and reserved bits
 	adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp
 	;;
@@ -123,7 +127,7 @@
 	;;
 	stf.spill [base0]ñ4,32
 	stf.spill [base1]ñ5,32
-	br.call.sptk.few rp¶			// call the signal handler
+	br.call.sptk.many rp¶			// call the signal handler
 .ret0:	adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp
 	;;
 	ld8 r15=[base0],(CFM_OFF-BSP_OFF)	// fetch sc_ar_bsp and advance to CFM_OFF
@@ -131,7 +135,7 @@
 	;;
 	ld8 r8=[base0]				// restore (perhaps modified) CFM0, EC0, and CPL0
 	cmp.ne p8,p0=r14,r15			// do we need to restore the rbs?
-(p8)	br.cond.spnt.few restore_rbs		// yup -> (clobbers r14 and r16)
+(p8)	br.cond.spnt restore_rbs		// yup -> (clobbers r14 and r16)
 	;;
 back_from_restore_rbs:
 	adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp
@@ -154,30 +158,52 @@
 	mov r15=__NR_rt_sigreturn
 	break __BREAK_SYSCALL
 
+	.body
+	.copy_state 1
 setup_rbs:
-	flushrs					// must be first in insn
 	mov ar.rsc=0				// put RSE into enforced lazy mode
-	adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp
 	;;
-	mov r14=ar.rnat				// get rnat as updated by flushrs
-	mov ar.bspstore=r15			// set new register backing store area
+	.save ar.rnat, r16
+	mov r16=ar.rnat				// save RNaT before switching backing store area
+	adds r14=(RNAT_OFF+SIGCONTEXT_OFF),sp
+
+	mov ar.bspstore=r15			// switch over to new register backing store area
 	;;
 	.spillsp ar.rnat, RNAT_OFF+SIGCONTEXT_OFF
-	st8 [r16]=r14				// save sc_ar_rnat
+	st8 [r14]=r16				// save sc_ar_rnat
+	adds r14=(LOADRS_OFF+SIGCONTEXT_OFF),sp
+
+	mov.m r16=ar.bsp			// sc_loadrs <- (new bsp - new bspstore) << 16
+	;;
+	invala
+	sub r15=r16,r15
+	;;
+	shl r15=r15,16
+	;;
+	st8 [r14]=r15				// save sc_loadrs
 	mov ar.rsc=0xf				// set RSE into eager mode, pl 3
-	invala					// invalidate ALAT
-	br.cond.sptk.many back_from_setup_rbs
+	br.cond.sptk back_from_setup_rbs
 
+	.prologue
+	.copy_state 1
+	.spillsp ar.rnat, RNAT_OFF+SIGCONTEXT_OFF
+	.body
 restore_rbs:
-	flushrs
-	mov ar.rsc=0				// put RSE into enforced lazy mode
+	alloc r2=ar.pfs,0,0,0,0			// alloc null frame
+	adds r16=(LOADRS_OFF+SIGCONTEXT_OFF),sp
+	;;
+	ld8 r14=[r16]
 	adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp
 	;;
+	mov ar.rsc=r14				// put RSE into enforced lazy mode
 	ld8 r14=[r16]				// get new rnat
-	mov ar.bspstore=r15			// set old register backing store area
 	;;
-	mov ar.rnat=r14				// establish new rnat
+	loadrs					// restore dirty partition
+	;;
+	mov ar.bspstore=r15			// switch back to old register backing store area
+	;;
+	mov ar.rnat=r14				// restore RNaT
 	mov ar.rsc=0xf				// (will be restored later on from sc_ar_rsc)
 	// invala not necessary as that will happen when returning to user-mode
-	br.cond.sptk.many back_from_restore_rbs
+	br.cond.sptk back_from_restore_rbs
 END(ia64_sigtramp)
diff -urN linux-2.4.13/arch/ia64/kernel/head.S linux-2.4.13-lia/arch/ia64/kernel/head.S
--- linux-2.4.13/arch/ia64/kernel/head.S	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/head.S	Thu Oct  4 00:21:39 2001
@@ -6,8 +6,8 @@
  * entry point.
  *
  * Copyright (C) 1998-2001 Hewlett-Packard Co
- * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 2001 Stephane Eranian <eranian@hpl.hp.com>
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+ *	Stephane Eranian <eranian@hpl.hp.com>
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
  * Copyright (C) 1999 Intel Corp.
@@ -86,7 +86,8 @@
 	/*
 	 * Switch into virtual mode:
 	 */
-	movl r16=(IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN)
+	movl r16=(IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN \
+		  |IA64_PSR_DI)
 	;;
 	mov cr.ipsr=r16
 	movl r17\x1f
@@ -183,31 +184,31 @@
 	alloc r2=ar.pfs,0,0,2,0
 	movl out0=alive_msg
 	;;
-	br.call.sptk.few rpêrly_printk
+	br.call.sptk.many rpêrly_printk
 1:	// force new bundle
 #endif /* CONFIG_IA64_EARLY_PRINTK */
 
 #ifdef CONFIG_SMP
-(isAP)	br.call.sptk.few rp=start_secondary
+(isAP)	br.call.sptk.many rp=start_secondary
 .ret0:
-(isAP)	br.cond.sptk.few self
+(isAP)	br.cond.sptk self
 #endif
 
 	// This is executed by the bootstrap processor (bsp) only:
 
 #ifdef CONFIG_IA64_FW_EMU
 	// initialize PAL & SAL emulator:
-	br.call.sptk.few rp=sys_fw_init
+	br.call.sptk.many rp=sys_fw_init
 .ret1:
 #endif
-	br.call.sptk.few rp=start_kernel
+	br.call.sptk.many rp=start_kernel
 .ret2:	addl r3=@ltoff(halt_msg),gp
 	;;
 	alloc r2=ar.pfs,8,0,2,0
 	;;
 	ld8 out0=[r3]
-	br.call.sptk.few b0=console_print
-self:	br.sptk.few self		// endless loop
+	br.call.sptk.many b0=console_print
+self:	br.sptk.many self		// endless loop
 END(_start)
 
 GLOBAL_ENTRY(ia64_save_debug_regs)
@@ -218,7 +219,7 @@
 	add r19=IA64_NUM_DBG_REGS*8,in0
 	;;
 1:	mov r16Ûr[r18]
-#if defined(CONFIG_ITANIUM_C0_SPECIFIC)
+#ifdef CONFIG_ITANIUM
 	;;
 	srlz.d
 #endif
@@ -227,17 +228,15 @@
 	;;
 	st8.nta [in0]=r16,8
 	st8.nta [r19]=r17,8
-	br.cloop.sptk.few 1b
+	br.cloop.sptk.many 1b
 	;;
 	mov ar.lc=r20			// restore ar.lc
-	br.ret.sptk.few rp
+	br.ret.sptk.many rp
 END(ia64_save_debug_regs)
 
 GLOBAL_ENTRY(ia64_load_debug_regs)
 	alloc r16=ar.pfs,1,0,0,0
-#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC))
 	lfetch.nta [in0]
-#endif
 	mov r20=ar.lc			// preserve ar.lc
 	add r19=IA64_NUM_DBG_REGS*8,in0
 	mov ar.lc=IA64_NUM_DBG_REGS-1
@@ -248,15 +247,15 @@
 	add r18=1,r18
 	;;
 	mov dbr[r18]=r16
-#if defined(CONFIG_ITANIUM_BSTEP_SPECIFIC) || defined(CONFIG_ITANIUM_C0_SPECIFIC)
+#ifdef CONFIG_ITANIUM
 	;;
-	srlz.d
+	srlz.d				// Errata 132 (NoFix status)
 #endif
 	mov ibr[r18]=r17
-	br.cloop.sptk.few 1b
+	br.cloop.sptk.many 1b
 	;;
 	mov ar.lc=r20			// restore ar.lc
-	br.ret.sptk.few rp
+	br.ret.sptk.many rp
 END(ia64_load_debug_regs)
 
 GLOBAL_ENTRY(__ia64_save_fpu)
@@ -406,7 +405,7 @@
 	;;
 	stf.spill.nta [in0]ñ26,32
 	stf.spill.nta [ r3]ñ27,32
-	br.ret.sptk.few rp
+	br.ret.sptk.many rp
 END(__ia64_save_fpu)
 
 GLOBAL_ENTRY(__ia64_load_fpu)
@@ -556,7 +555,7 @@
 	;;
 	ldf.fill.nta f126=[in0],32
 	ldf.fill.nta f127=[ r3],32
-	br.ret.sptk.few rp
+	br.ret.sptk.many rp
 END(__ia64_load_fpu)
 
 GLOBAL_ENTRY(__ia64_init_fpu)
@@ -690,7 +689,7 @@
 	;;
 	ldf.fill f126=[sp]
 	mov      f127ð
-	br.ret.sptk.few rp
+	br.ret.sptk.many rp
 END(__ia64_init_fpu)
 
 /*
@@ -738,7 +737,7 @@
 	rfi				// must be last insn in group
 	;;
 1:	mov rp=r14
-	br.ret.sptk.few rp
+	br.ret.sptk.many rp
 END(ia64_switch_mode)
 
 #ifdef CONFIG_IA64_BRL_EMU
@@ -752,7 +751,7 @@
 	alloc r16=ar.pfs,1,0,0,0;		\
 	mov reg=r32;				\
 	;;					\
-	br.ret.sptk rp;				\
+	br.ret.sptk.many rp;			\
  END(ia64_set_##reg)
 
 SET_REG(b1);
@@ -816,12 +815,11 @@
 	;;
 	cmp.ne p15,p0=tmp,r0
 	mov tmp=ar.itc
-(p15)	br.cond.sptk.few .retry	// lock is still busy
+(p15)	br.cond.sptk .retry	// lock is still busy
 	;;
 	// try acquiring lock (we know ar.ccv is still zero!):
 	mov tmp=1
 	;;
-	IA64_SEMFIX_INSN
 	cmpxchg4.acq tmp=[r31],tmp,ar.ccv
 	;;
 	cmp.eq p15,p0=tmp,r0
diff -urN linux-2.4.13/arch/ia64/kernel/ia64_ksyms.c linux-2.4.13-lia/arch/ia64/kernel/ia64_ksyms.c
--- linux-2.4.13/arch/ia64/kernel/ia64_ksyms.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/ia64_ksyms.c	Thu Oct  4 00:21:39 2001
@@ -145,4 +145,3 @@
 #include <linux/proc_fs.h>
 extern struct proc_dir_entry *efi_dir;
 EXPORT_SYMBOL(efi_dir);
-
diff -urN linux-2.4.13/arch/ia64/kernel/iosapic.c linux-2.4.13-lia/arch/ia64/kernel/iosapic.c
--- linux-2.4.13/arch/ia64/kernel/iosapic.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/iosapic.c	Thu Oct  4 00:21:39 2001
@@ -53,6 +53,7 @@
 #include <asm/acpi-ext.h>
 #include <asm/acpikcfg.h>
 #include <asm/delay.h>
+#include <asm/hw_irq.h>
 #include <asm/io.h>
 #include <asm/iosapic.h>
 #include <asm/machvec.h>
@@ -325,7 +326,7 @@
 	set_affinity:	iosapic_set_affinity
 };
 
-static unsigned int
+unsigned int
 iosapic_version (char *addr)
 {
 	/*
@@ -342,6 +343,113 @@
 }
 
 /*
+ * ACPI can describe IOSAPIC interrupts via static tables and namespace
+ * methods.  This provides an interface to register those interrupts and
+ * program the IOSAPIC RTE.
+ */
+int
+iosapic_register_irq (u32 global_vector, unsigned long polarity, unsigned long
+                      edge_triggered, u32 base_irq, char *iosapic_address)
+{
+	irq_desc_t *idesc;
+	struct hw_interrupt_type *irq_type;
+	int vector;
+
+	vector = iosapic_irq_to_vector(global_vector);
+	if (vector < 0)
+		vector = ia64_alloc_irq();
+
+	/* fill in information from this vector's IOSAPIC */
+	iosapic_irq[vector].addr = iosapic_address;
+	iosapic_irq[vector].base_irq = base_irq;
+	iosapic_irq[vector].pin	= global_vector - iosapic_irq[vector].base_irq;
+	iosapic_irq[vector].polarity = polarity ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW;
+	iosapic_irq[vector].dmode    = IOSAPIC_LOWEST_PRIORITY;
+
+	if (edge_triggered) {
+		iosapic_irq[vector].trigger = IOSAPIC_EDGE;
+		irq_type = &irq_type_iosapic_edge;
+	} else {
+		iosapic_irq[vector].trigger = IOSAPIC_LEVEL;
+		irq_type = &irq_type_iosapic_level;
+	}
+
+	idesc = irq_desc(vector);
+	if (idesc->handler != irq_type) {
+		if (idesc->handler != &no_irq_type)
+			printk("iosapic_register_irq(): changing vector 0x%02x from"
+			       "%s to %s\n", vector, idesc->handler->typename, irq_type->typename);
+		idesc->handler = irq_type;
+	}
+
+	printk("IOSAPIC %x(%s,%s) -> Vector %x\n", global_vector,
+	       (polarity ? "high" : "low"), (edge_triggered ? "edge" : "level"), vector);
+
+	/* program the IOSAPIC routing table */
+	set_rte(vector, (ia64_get_lid() >> 16) & 0xffff);
+	return vector;
+}
+
+/*
+ * ACPI calls this when it finds an entry for a platform interrupt.
+ * Note that the irq_base and IOSAPIC address must be set in iosapic_init().
+ */
+int
+iosapic_register_platform_irq (u32 int_type, u32 global_vector, u32 iosapic_vector,
+			       u16 eid, u16 id, unsigned long polarity,
+			       unsigned long edge_triggered, u32 base_irq, char *iosapic_address)
+{
+	struct hw_interrupt_type *irq_type;
+	irq_desc_t *idesc;
+	int vector;
+
+	switch (int_type) {
+	      case ACPI20_ENTRY_PIS_CPEI:
+		vector = IA64_PCE_VECTOR;
+		iosapic_irq[vector].dmode = IOSAPIC_LOWEST_PRIORITY;
+		break;
+	      case ACPI20_ENTRY_PIS_INIT:
+		vector = ia64_alloc_irq();
+		iosapic_irq[vector].dmode = IOSAPIC_INIT;
+		break;
+	      default:
+		printk("iosapic_register_platform_irq(): invalid int type\n");
+		return -1;
+	}
+
+	/* fill in information from this vector's IOSAPIC */
+	iosapic_irq[vector].addr = iosapic_address;
+	iosapic_irq[vector].base_irq = base_irq;
+	iosapic_irq[vector].pin	= global_vector - iosapic_irq[vector].base_irq;
+	iosapic_irq[vector].polarity = polarity ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW;
+
+	if (edge_triggered) {
+		iosapic_irq[vector].trigger = IOSAPIC_EDGE;
+		irq_type = &irq_type_iosapic_edge;
+	} else {
+		iosapic_irq[vector].trigger = IOSAPIC_LEVEL;
+		irq_type = &irq_type_iosapic_level;
+	}
+
+	idesc = irq_desc(vector);
+	if (idesc->handler != irq_type) {
+		if (idesc->handler != &no_irq_type)
+			printk("iosapic_register_platform_irq(): changing vector 0x%02x from"
+			       "%s to %s\n", vector, idesc->handler->typename, irq_type->typename);
+		idesc->handler = irq_type;
+	}
+
+	printk("PLATFORM int %x: IOSAPIC %x(%s,%s) -> Vector %x CPU %.02u:%.02u\n",
+	       int_type, global_vector, (polarity ? "high" : "low"),
+	       (edge_triggered ? "edge" : "level"), vector, eid, id);
+
+	/* program the IOSAPIC routing table */
+	set_rte(vector, ((id << 8) | eid) & 0xffff);
+	return vector;
+}
+
+
+/*
  * ACPI calls this when it finds an entry for a legacy ISA interrupt.  Note that the
  * irq_base and IOSAPIC address must be set in iosapic_init().
  */
@@ -436,7 +544,7 @@
 			/* the interrupt route is for another controller... */
 			continue;
 
-		if (irq < 16)
+		if (pcat_compat && (irq < 16))
 			vector = isa_irq_to_vector(irq);
 		else {
 			vector = iosapic_irq_to_vector(irq);
@@ -515,6 +623,23 @@
 				printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> 0x%02x\n",
 				       dev->bus->number, PCI_SLOT(dev->devfn), pin, vector);
 				dev->irq = vector;
+
+#ifdef CONFIG_SMP
+				/*
+				 * For platforms that do not support interrupt redirect
+				 * via the XTP interface, we can round-robin the PCI
+				 * device interrupts to the processors
+				 */
+				if (!(smp_int_redirect & SMP_IRQ_REDIRECTION)) {
+					static int cpu_index = 0;
+
+					set_rte(vector, cpu_physical_id(cpu_index) & 0xffff);
+
+					cpu_index++;
+					if (cpu_index >= smp_num_cpus)
+						cpu_index = 0;
+				}
+#endif
 			}
 		}
 		/*
diff -urN linux-2.4.13/arch/ia64/kernel/irq.c linux-2.4.13-lia/arch/ia64/kernel/irq.c
--- linux-2.4.13/arch/ia64/kernel/irq.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/irq.c	Thu Oct  4 00:21:39 2001
@@ -33,6 +33,7 @@
 #include <linux/irq.h>
 #include <linux/proc_fs.h>
 
+#include <asm/atomic.h>
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <asm/system.h>
@@ -121,7 +122,10 @@
 	end_none
 };
 
-volatile unsigned long irq_err_count;
+atomic_t irq_err_count;
+#if defined(CONFIG_X86) && defined(CONFIG_X86_IO_APIC) && defined(APIC_MISMATCH_DEBUG)
+atomic_t irq_mis_count;
+#endif
 
 /*
  * Generic, controller-independent functions:
@@ -164,14 +168,17 @@
 		p += sprintf(p, "%10u ",
 			nmi_count(cpu_logical_map(j)));
 	p += sprintf(p, "\n");
-#if defined(CONFIG_SMP) && defined(__i386__)
+#if defined(CONFIG_SMP) && defined(CONFIG_X86)
 	p += sprintf(p, "LOC: ");
 	for (j = 0; j < smp_num_cpus; j++)
 		p += sprintf(p, "%10u ",
 			apic_timer_irqs[cpu_logical_map(j)]);
 	p += sprintf(p, "\n");
 #endif
-	p += sprintf(p, "ERR: %10lu\n", irq_err_count);
+	p += sprintf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
+#if defined(CONFIG_X86) && defined(CONFIG_X86_IO_APIC) && defined(APIC_MISMATCH_DEBUG)
+	p += sprintf(p, "MIS: %10u\n", atomic_read(&irq_mis_count));
+#endif
 	return p - buf;
 }
 
@@ -183,7 +190,7 @@
 
 #ifdef CONFIG_SMP
 unsigned int global_irq_holder = NO_PROC_ID;
-volatile unsigned long global_irq_lock; /* long for set_bit --RR */
+unsigned volatile long global_irq_lock; /* pedantic: long for set_bit --RR */
 
 extern void show_stack(unsigned long* esp);
 
@@ -201,14 +208,14 @@
 		printk(" %d",bh_count(i));
 
 	printk(" ]\nStack dumps:");
-#if defined(__ia64__)
+#if defined(CONFIG_IA64)
 	/*
 	 * We can't unwind the stack of another CPU without access to
 	 * the registers of that CPU.  And sending an IPI when we're
 	 * in a potentially wedged state doesn't sound like a smart
 	 * idea.
 	 */
-#elif defined(__i386__)
+#elif defined(CONFIG_X86)
 	for(i=0;i< smp_num_cpus;i++) {
 		unsigned long esp;
 		if(i=cpu)
@@ -261,7 +268,7 @@
 /*
  * We have to allow irqs to arrive between __sti and __cli
  */
-# ifdef __ia64__
+# ifdef CONFIG_IA64
 #  define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop 0")
 # else
 #  define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop")
@@ -331,6 +338,9 @@
 		/* Uhhuh.. Somebody else got it. Wait.. */
 		do {
 			do {
+#ifdef CONFIG_X86
+				rep_nop();
+#endif
 			} while (test_bit(0,&global_irq_lock));
 		} while (test_and_set_bit(0,&global_irq_lock));
 	}
@@ -364,7 +374,7 @@
 {
 	unsigned int flags;
 
-#ifdef __ia64__
+#ifdef CONFIG_IA64
 	__save_flags(flags);
 	if (flags & IA64_PSR_I) {
 		__cli();
@@ -403,7 +413,7 @@
 	int cpu = smp_processor_id();
 
 	__save_flags(flags);
-#ifdef __ia64__
+#ifdef CONFIG_IA64
 	local_enabled = (flags & IA64_PSR_I) != 0;
 #else
 	local_enabled = (flags >> EFLAGS_IF_SHIFT) & 1;
@@ -476,13 +486,19 @@
 	return status;
 }
 
-/*
- * Generic enable/disable code: this just calls
- * down into the PIC-specific version for the actual
- * hardware disable after having gotten the irq
- * controller lock.
+/**
+ *	disable_irq_nosync - disable an irq without waiting
+ *	@irq: Interrupt to disable
+ *
+ *	Disable the selected interrupt line.  Disables and Enables are
+ *	nested.
+ *	Unlike disable_irq(), this function does not ensure existing
+ *	instances of the IRQ handler have completed before returning.
+ *
+ *	This function may be called from IRQ context.
  */
-void inline disable_irq_nosync(unsigned int irq)
+
+inline void disable_irq_nosync(unsigned int irq)
 {
 	irq_desc_t *desc = irq_desc(irq);
 	unsigned long flags;
@@ -495,10 +511,19 @@
 	spin_unlock_irqrestore(&desc->lock, flags);
 }
 
-/*
- * Synchronous version of the above, making sure the IRQ is
- * no longer running on any other IRQ..
+/**
+ *	disable_irq - disable an irq and wait for completion
+ *	@irq: Interrupt to disable
+ *
+ *	Disable the selected interrupt line.  Enables and Disables are
+ *	nested.
+ *	This function waits for any pending IRQ handlers for this interrupt
+ *	to complete before returning. If you use this function while
+ *	holding a resource the IRQ handler may need you will deadlock.
+ *
+ *	This function may be called - with care - from IRQ context.
  */
+
 void disable_irq(unsigned int irq)
 {
 	disable_irq_nosync(irq);
@@ -512,6 +537,17 @@
 #endif
 }
 
+/**
+ *	enable_irq - enable handling of an irq
+ *	@irq: Interrupt to enable
+ *
+ *	Undoes the effect of one call to disable_irq().  If this
+ *	matches the last disable, processing of interrupts on this
+ *	IRQ line is re-enabled.
+ *
+ *	This function may be called from IRQ context.
+ */
+
 void enable_irq(unsigned int irq)
 {
 	irq_desc_t *desc = irq_desc(irq);
@@ -533,7 +569,8 @@
 		desc->depth--;
 		break;
 	case 0:
-		printk("enable_irq() unbalanced from %p\n", (void *) __builtin_return_address(0));
+		printk("enable_irq(%u) unbalanced from %p\n",
+		       irq, (void *) __builtin_return_address(0));
 	}
 	spin_unlock_irqrestore(&desc->lock, flags);
 }
@@ -626,11 +663,41 @@
 		desc->handler->end(irq);
 		spin_unlock(&desc->lock);
 	}
-	if (local_softirq_pending())
-		do_softirq();
 	return 1;
 }
 
+/**
+ *	request_irq - allocate an interrupt line
+ *	@irq: Interrupt line to allocate
+ *	@handler: Function to be called when the IRQ occurs
+ *	@irqflags: Interrupt type flags
+ *	@devname: An ascii name for the claiming device
+ *	@dev_id: A cookie passed back to the handler function
+ *
+ *	This call allocates interrupt resources and enables the
+ *	interrupt line and IRQ handling. From the point this
+ *	call is made your handler function may be invoked. Since
+ *	your handler function must clear any interrupt the board 
+ *	raises, you must take care both to initialise your hardware
+ *	and to set up the interrupt handler in the right order.
+ *
+ *	Dev_id must be globally unique. Normally the address of the
+ *	device data structure is used as the cookie. Since the handler
+ *	receives this value it makes sense to use it.
+ *
+ *	If your interrupt is shared you must pass a non NULL dev_id
+ *	as this is required when freeing the interrupt.
+ *
+ *	Flags:
+ *
+ *	SA_SHIRQ		Interrupt is shared
+ *
+ *	SA_INTERRUPT		Disable local interrupts while processing
+ *
+ *	SA_SAMPLE_RANDOM	The interrupt can be used for entropy
+ *
+ */
+
 int request_irq(unsigned int irq,
 		void (*handler)(int, void *, struct pt_regs *),
 		unsigned long irqflags,
@@ -676,6 +743,24 @@
 	return retval;
 }
 
+/**
+ *	free_irq - free an interrupt
+ *	@irq: Interrupt line to free
+ *	@dev_id: Device identity to free
+ *
+ *	Remove an interrupt handler. The handler is removed and if the
+ *	interrupt line is no longer in use by any driver it is disabled.
+ *	On a shared IRQ the caller must ensure the interrupt is disabled
+ *	on the card it drives before calling this function. The function
+ *	does not return until any executing interrupts for this IRQ
+ *	have completed.
+ *
+ *	This function may be called from interrupt context. 
+ *
+ *	Bugs: Attempting to free an irq in a handler for the same irq hangs
+ *	      the machine.
+ */
+
 void free_irq(unsigned int irq, void *dev_id)
 {
 	irq_desc_t *desc;
@@ -726,6 +811,17 @@
  * with "IRQ_WAITING" cleared and the interrupt
  * disabled.
  */
+
+static DECLARE_MUTEX(probe_sem);
+
+/**
+ *	probe_irq_on	- begin an interrupt autodetect
+ *
+ *	Commence probing for an interrupt. The interrupts are scanned
+ *	and a mask of potential interrupt lines is returned.
+ *
+ */
+
 unsigned long probe_irq_on(void)
 {
 	unsigned int i;
@@ -733,6 +829,7 @@
 	unsigned long val;
 	unsigned long delay;
 
+	down(&probe_sem);
 	/*
 	 * something may have generated an irq long ago and we want to
 	 * flush such a longstanding irq before considering it as spurious.
@@ -799,10 +896,19 @@
 	return val;
 }
 
-/*
- * Return a mask of triggered interrupts (this
- * can handle only legacy ISA interrupts).
+/**
+ *	probe_irq_mask - scan a bitmap of interrupt lines
+ *	@val:	mask of interrupts to consider
+ *
+ *	Scan the ISA bus interrupt lines and return a bitmap of
+ *	active interrupts. The interrupt probe logic state is then
+ *	returned to its previous value.
+ *
+ *	Note: we need to scan all the irq's even though we will
+ *	only return ISA irq numbers - just so that we reset them
+ *	all to a known state.
  */
+
 unsigned int probe_irq_mask(unsigned long val)
 {
 	int i;
@@ -825,14 +931,29 @@
 		}
 		spin_unlock_irq(&desc->lock);
 	}
+	up(&probe_sem);
 
 	return mask & val;
 }
 
-/*
- * Return the one interrupt that triggered (this can
- * handle any interrupt source)
+/**
+ *	probe_irq_off	- end an interrupt autodetect
+ *	@val: mask of potential interrupts (unused)
+ *
+ *	Scans the unused interrupt lines and returns the line which
+ *	appears to have triggered the interrupt. If no interrupt was
+ *	found then zero is returned. If more than one interrupt is
+ *	found then minus the first candidate is returned to indicate
+ *	their is doubt.
+ *
+ *	The interrupt probe logic state is returned to its previous
+ *	value.
+ *
+ *	BUGS: When used in a module (which arguably shouldnt happen)
+ *	nothing prevents two IRQ probe callers from overlapping. The
+ *	results of this are non-optimal.
  */
+
 int probe_irq_off(unsigned long val)
 {
 	int i, irq_found, nr_irqs;
@@ -857,6 +978,7 @@
 		}
 		spin_unlock_irq(&desc->lock);
 	}
+	up(&probe_sem);
 
 	if (nr_irqs > 1)
 		irq_found = -irq_found;
@@ -911,7 +1033,7 @@
 
 	if (!shared) {
 		desc->depth = 0;
-		desc->status &= ~IRQ_DISABLED;
+		desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING);
 		desc->handler->startup(irq);
 	}
 	spin_unlock_irqrestore(&desc->lock,flags);
@@ -922,20 +1044,9 @@
 
 static struct proc_dir_entry * root_irq_dir;
 static struct proc_dir_entry * irq_dir [NR_IRQS];
-static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
-
-static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
 
 #define HEX_DIGITS 8
 
-static int irq_affinity_read_proc (char *page, char **start, off_t off,
-			int count, int *eof, void *data)
-{
-	if (count < HEX_DIGITS+1)
-		return -EINVAL;
-	return sprintf (page, "%08lx\n", irq_affinity[(long)data]);
-}
-
 static unsigned int parse_hex_value (const char *buffer,
 		unsigned long count, unsigned long *ret)
 {
@@ -973,6 +1084,20 @@
 	return 0;
 }
 
+#if CONFIG_SMP
+
+static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
+
+static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
+
+static int irq_affinity_read_proc (char *page, char **start, off_t off,
+			int count, int *eof, void *data)
+{
+	if (count < HEX_DIGITS+1)
+		return -EINVAL;
+	return sprintf (page, "%08lx\n", irq_affinity[(long)data]);
+}
+
 static int irq_affinity_write_proc (struct file *file, const char *buffer,
 					unsigned long count, void *data)
 {
@@ -984,7 +1109,6 @@
 
 	err = parse_hex_value(buffer, count, &new_value);
 
-#if CONFIG_SMP
 	/*
 	 * Do not allow disabling IRQs completely - it's a too easy
 	 * way to make the system unusable accidentally :-) At least
@@ -992,7 +1116,6 @@
 	 */
 	if (!(new_value & cpu_online_map))
 		return -EINVAL;
-#endif
 
 	irq_affinity[irq] = new_value;
 	irq_desc(irq)->handler->set_affinity(irq, new_value);
@@ -1000,6 +1123,8 @@
 	return full_count;
 }
 
+#endif /* CONFIG_SMP */
+
 static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
 			int count, int *eof, void *data)
 {
@@ -1027,7 +1152,6 @@
 
 static void register_irq_proc (unsigned int irq)
 {
-	struct proc_dir_entry *entry;
 	char name [MAX_NAMELEN];
 
 	if (!root_irq_dir || (irq_desc(irq)->handler = &no_irq_type))
@@ -1039,15 +1163,22 @@
 	/* create /proc/irq/1234 */
 	irq_dir[irq] = proc_mkdir(name, root_irq_dir);
 
-	/* create /proc/irq/1234/smp_affinity */
-	entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
-
-	entry->nlink = 1;
-	entry->data = (void *)(long)irq;
-	entry->read_proc = irq_affinity_read_proc;
-	entry->write_proc = irq_affinity_write_proc;
+#if CONFIG_SMP
+	{
+		struct proc_dir_entry *entry;
+		/* create /proc/irq/1234/smp_affinity */
+		entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
+
+		if (entry) {
+			entry->nlink = 1;
+			entry->data = (void *)(long)irq;
+			entry->read_proc = irq_affinity_read_proc;
+			entry->write_proc = irq_affinity_write_proc;
+		}
 
-	smp_affinity_entry[irq] = entry;
+		smp_affinity_entry[irq] = entry;
+	}
+#endif
 }
 
 unsigned long prof_cpu_mask = -1;
@@ -1062,6 +1193,9 @@
 
 	/* create /proc/irq/prof_cpu_mask */
 	entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
+
+	if (!entry)
+		return;
 
 	entry->nlink = 1;
 	entry->data = (void *)&prof_cpu_mask;
diff -urN linux-2.4.13/arch/ia64/kernel/irq_ia64.c linux-2.4.13-lia/arch/ia64/kernel/irq_ia64.c
--- linux-2.4.13/arch/ia64/kernel/irq_ia64.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/irq_ia64.c	Thu Oct  4 00:21:39 2001
@@ -1,9 +1,9 @@
 /*
  * linux/arch/ia64/kernel/irq.c
  *
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com>
- * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ *	Stephane Eranian <eranian@hpl.hp.com>
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
  *  6/10/99: Updated to bring in sync with x86 version to facilitate
  *	     support for SMP and different interrupt controllers.
@@ -131,6 +131,13 @@
 		ia64_eoi();
 		vector = ia64_get_ivr();
 	}
+	/*
+	 * This must be done *after* the ia64_eoi().  For example, the keyboard softirq
+	 * handler needs to be able to wait for further keyboard interrupts, which can't
+	 * come through until ia64_eoi() has been done.
+	 */
+	if (local_softirq_pending())
+		do_softirq();
 }
 
 #ifdef CONFIG_SMP
diff -urN linux-2.4.13/arch/ia64/kernel/ivt.S linux-2.4.13-lia/arch/ia64/kernel/ivt.S
--- linux-2.4.13/arch/ia64/kernel/ivt.S	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/ivt.S	Wed Oct 10 17:58:45 2001
@@ -2,8 +2,8 @@
  * arch/ia64/kernel/ivt.S
  *
  * Copyright (C) 1998-2001 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com>
- * Copyright (C) 1998-2001 David Mosberger <davidm@hpl.hp.com>
+ *	Stephane Eranian <eranian@hpl.hp.com>
+ *	David Mosberger <davidm@hpl.hp.com>
  *
  * 00/08/23 Asit Mallick <asit.k.mallick@intel.com> TLB handling for SMP
  * 00/12/20 David Mosberger-Tang <davidm@hpl.hp.com> DTLB/ITLB handler now uses virtual PT.
@@ -157,7 +157,7 @@
 	;;
 (p10)	itc.i r18				// insert the instruction TLB entry
 (p11)	itc.d r18				// insert the data TLB entry
-(p6)	br.spnt.many page_fault			// handle bad address/page not present (page fault)
+(p6)	br.cond.spnt.many page_fault		// handle bad address/page not present (page fault)
 	mov cr.ifa=r22
 
 	/*
@@ -213,7 +213,7 @@
 	;;
 	mov b0=r29
 	tbit.z p6,p0=r18,_PAGE_P_BIT		// page present bit cleared?
-(p6)	br.cond.spnt.many page_fault
+(p6)	br.cond.spnt page_fault
 	;;
 	itc.i r18
 	;;
@@ -251,7 +251,7 @@
 	;;
 	mov b0=r29
 	tbit.z p6,p0=r18,_PAGE_P_BIT		// page present bit cleared?
-(p6)	br.cond.spnt.many page_fault
+(p6)	br.cond.spnt page_fault
 	;;
 	itc.d r18
 	;;
@@ -286,7 +286,7 @@
 	;;
 (p8)	mov cr.iha=r17
 (p8)	mov r29°				// save b0
-(p8)	br.cond.dptk.many itlb_fault
+(p8)	br.cond.dptk itlb_fault
 #endif
 	extr.u r23=r21,IA64_PSR_CPL0_BIT,2	// extract psr.cpl
 	shr.u r18=r16,57	// move address bit 61 to bit 4
@@ -297,7 +297,7 @@
 	dep r19=r17,r19,0,12	// insert PTE control bits into r19
 	;;
 	or r19=r19,r18		// set bit 4 (uncached) if the access was to region 6
-(p8)	br.cond.spnt.many page_fault
+(p8)	br.cond.spnt page_fault
 	;;
 	itc.i r19		// insert the TLB entry
 	mov pr=r31,-1
@@ -324,7 +324,7 @@
 	;;
 (p8)	mov cr.iha=r17
 (p8)	mov r29°				// save b0
-(p8)	br.cond.dptk.many dtlb_fault
+(p8)	br.cond.dptk dtlb_fault
 #endif
 	extr.u r23=r21,IA64_PSR_CPL0_BIT,2	// extract psr.cpl
 	tbit.nz p6,p7=r20,IA64_ISR_SP_BIT	// is speculation bit on?
@@ -333,7 +333,7 @@
 	;;
 	andcm r18=0x10,r18	// bit 4=~address-bit(61)
 	cmp.ne p8,p0=r0,r23
-(p8)	br.cond.spnt.many page_fault
+(p8)	br.cond.spnt page_fault
 
 	dep r21=-1,r21,IA64_PSR_ED_BIT,1
 	dep r19=r17,r19,0,12	// insert PTE control bits into r19
@@ -429,7 +429,7 @@
 	;;
 (p7)	cmp.eq.or.andcm p6,p7=r17,r0		// was L2 entry NULL?
 	dep r17=r19,r17,3,(PAGE_SHIFT-3)	// compute address of L3 page table entry
-(p6)	br.cond.spnt.many page_fault
+(p6)	br.cond.spnt page_fault
 	mov b0=r30
 	br.sptk.many b0				// return to continuation point
 END(nested_dtlb_miss)
@@ -534,15 +534,6 @@
 	;;
 1:	ld8 r18=[r17]
 	;;
-# if defined(CONFIG_IA32_SUPPORT) && 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.
-	 */
-	tbit.z p6,p0=r18,_PAGE_P_BIT		// page present bit cleared?
-(p6)	br.sptk page_fault			// page wasn't present
-# endif
 	mov ar.ccv=r18				// set compare value for cmpxchg
 	or r25=_PAGE_A,r18			// set the accessed bit
 	;;
@@ -564,15 +555,6 @@
 	;;
 1:	ld8 r18=[r17]
 	;;
-# if defined(CONFIG_IA32_SUPPORT) && 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.
-	 */
-	tbit.z p6,p0=r18,_PAGE_P_BIT		// page present bit cleared?
-(p6)	br.sptk page_fault			// page wasn't present
-# endif
 	or r18=_PAGE_A,r18			// set the accessed bit
 	mov b0=r29				// restore b0
 	;;
@@ -640,7 +622,7 @@
 	mov r31=pr		// prepare to save predicates
 	;;
 	cmp.eq p0,p7=r16,r17	// is this a system call? (p7 <- false, if so)
-(p7)	br.cond.spnt.many non_syscall
+(p7)	br.cond.spnt non_syscall
 
 	SAVE_MIN				// uses r31; defines r2:
 
@@ -656,7 +638,7 @@
 	adds r3=8,r2		// set up second base pointer for SAVE_REST
 	;;
 	SAVE_REST
-	br.call.sptk rpÞmine_args		// clear NaT bits in (potential) syscall args
+	br.call.sptk.many rpÞmine_args	// clear NaT bits in (potential) syscall args
 
 	mov r3%5
 	adds r15=-1024,r15			// r15 contains the syscall number---subtract 1024
@@ -698,7 +680,7 @@
 	st8 [r16]=r18				// store new value for cr.isr
 
 (p8)	br.call.sptk.many b6¶			// ignore this return addr
-	br.cond.sptk.many ia64_trace_syscall
+	br.cond.sptk ia64_trace_syscall
 	// NOT REACHED
 END(break_fault)
 
@@ -811,8 +793,8 @@
 	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
+(p6)	br.call.dpnt.many b6¶		// call returns to ia64_leave_kernel
+	br.sptk.many ia64_leave_kernel
 END(dispatch_illegal_op_fault)
 
 	.align 1024
@@ -855,30 +837,30 @@
 	adds r15=IA64_PT_REGS_R1_OFFSET + 16,sp
 	;;
 	cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0
-	st8 [r15]=r8		// save orignal EAX in r1 (IA32 procs don't use the GP)
+	st8 [r15]=r8		// save original EAX in r1 (IA32 procs don't use the GP)
 	;;
 	alloc r15=ar.pfs,0,0,6,0	// must first in an insn group
 	;;
-	ld4 r8=[r14],8          // r8 = EAX (syscall number)
-	mov r15"2		// sys_vfork - last implemented system call
+	ld4 r8=[r14],8		// r8 = eax (syscall number)
+	mov r15#0		// number of entries in ia32 system call table
 	;;
-	cmp.leu.unc p6,p7=r8,r15
-	ld4 out1=[r14],8        // r9 = ecx
+	cmp.ltu.unc p6,p7=r8,r15
+	ld4 out1=[r14],8	// r9 = ecx
 	;;
-	ld4 out2=[r14],8         // r10 = edx
+	ld4 out2=[r14],8	// r10 = edx
 	;;
-	ld4 out0=[r14]           // r11 = ebx
+	ld4 out0=[r14]		// r11 = ebx
 	adds r14=(IA64_PT_REGS_R8_OFFSET-(8*3)) + 16,sp
 	;;
-	ld4 out5=[r14],8         // r13 = ebp
+	ld4 out5=[r14],8	// r13 = ebp
 	;;
-	ld4 out3=[r14],8         // r14 = esi
+	ld4 out3=[r14],8	// r14 = esi
 	adds r2=IA64_TASK_PTRACE_OFFSET,r13	// r2 = &current->ptrace
 	;;
-	ld4 out4=[r14]           // R15 = edi
+	ld4 out4=[r14]		// r15 = edi
 	movl r16=ia32_syscall_table
 	;;
-(p6)    shladd r16=r8,3,r16     // Force ni_syscall if not valid syscall number
+(p6)    shladd r16=r8,3,r16	// force ni_syscall if not valid syscall number
 	ld8 r2=[r2]		// r2 = current->ptrace
 	;;
 	ld8 r16=[r16]
@@ -889,12 +871,12 @@
 	;;
 	mov rp=r15
 (p8)	br.call.sptk.many b6¶
-	br.cond.sptk.many ia32_trace_syscall
+	br.cond.sptk ia32_trace_syscall
 
 non_ia32_syscall:
 	alloc r15=ar.pfs,0,0,2,0
-	mov out0=r14                            // interrupt #
-	add out1\x16,sp                          // pointer to pt_regs
+	mov out0=r14				// interrupt #
+	add out1\x16,sp				// pointer to pt_regs
 	;;			// avoid WAW on CFM
 	br.call.sptk.many rp=ia32_bad_interrupt
 .ret1:	movl r15=ia64_leave_kernel
@@ -1085,7 +1067,7 @@
 	mov r31=pr
 	;;
 	cmp4.eq p6,p0=0,r16
-(p6)	br.sptk dispatch_illegal_op_fault
+(p6)	br.sptk.many dispatch_illegal_op_fault
 	;;
 	mov r19$		// fault number
 	br.sptk.many dispatch_to_fault_handler
diff -urN linux-2.4.13/arch/ia64/kernel/mca.c linux-2.4.13-lia/arch/ia64/kernel/mca.c
--- linux-2.4.13/arch/ia64/kernel/mca.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/mca.c	Wed Oct 10 17:42:06 2001
@@ -3,12 +3,20 @@
  * Purpose:	Generic MCA handling layer
  *
  * Updated for latest kernel
+ * Copyright (C) 2001 Intel
+ * Copyright (C) Fred Lewis (frederick.v.lewis@intel.com)
+ *
  * Copyright (C) 2000 Intel
  * Copyright (C) Chuck Fleckenstein (cfleck@co.intel.com)
  *
  * Copyright (C) 1999 Silicon Graphics, Inc.
  * Copyright (C) Vijay Chander(vijay@engr.sgi.com)
  *
+ * 01/01/03 F. Lewis    Added setup of CMCI and CPEI IRQs, logging of corrected
+ *                      platform errors, completed code for logging of
+ *                      corrected & uncorrected machine check errors, and
+ *                      updated for conformance with Nov. 2000 revision of the
+ *                      SAL 3.0 spec.
  * 00/03/29 C. Fleckenstein  Fixed PAL/SAL update issues, began MCA bug fixes, logging issues,
  *                           added min save state dump, added INIT handler.
  */
@@ -16,6 +24,7 @@
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/smp_lock.h>
 
@@ -27,8 +36,10 @@
 #include <asm/mca.h>
 
 #include <asm/irq.h>
-#include <asm/machvec.h>
+#include <asm/hw_irq.h>
+#include <asm/acpi-ext.h>
 
+#undef MCA_PRT_XTRA_DATA
 
 typedef struct ia64_fptr {
 	unsigned long fp;
@@ -38,22 +49,67 @@
 ia64_mc_info_t			ia64_mc_info;
 ia64_mca_sal_to_os_state_t	ia64_sal_to_os_handoff_state;
 ia64_mca_os_to_sal_state_t	ia64_os_to_sal_handoff_state;
-u64				ia64_mca_proc_state_dump[256];
+u64				ia64_mca_proc_state_dump[512];
 u64				ia64_mca_stack[1024];
 u64				ia64_mca_stackframe[32];
 u64				ia64_mca_bspstore[1024];
 u64				ia64_init_stack[INIT_TASK_SIZE] __attribute__((aligned(16)));
 
-static void			ia64_mca_cmc_vector_setup(int		enable,
-							  int_vector_t	cmc_vector);
 static void			ia64_mca_wakeup_ipi_wait(void);
 static void			ia64_mca_wakeup(int cpu);
 static void			ia64_mca_wakeup_all(void);
-static void			ia64_log_init(int,int);
-static void			ia64_log_get(int,int, prfunc_t);
-static void			ia64_log_clear(int,int,int, prfunc_t);
+static void			ia64_log_init(int);
 extern void		        ia64_monarch_init_handler (void);
 extern void		        ia64_slave_init_handler (void);
+extern struct hw_interrupt_type irq_type_iosapic_level;
+
+static struct irqaction cmci_irqaction = {
+	handler:    ia64_mca_cmc_int_handler,
+	flags:      SA_INTERRUPT,
+	name:       "cmc_hndlr"
+};
+
+static struct irqaction mca_rdzv_irqaction = {
+	handler:    ia64_mca_rendez_int_handler,
+	flags:      SA_INTERRUPT,
+	name:       "mca_rdzv"
+};
+
+static struct irqaction mca_wkup_irqaction = {
+	handler:    ia64_mca_wakeup_int_handler,
+	flags:      SA_INTERRUPT,
+	name:       "mca_wkup"
+};
+
+static struct irqaction mca_cpe_irqaction = {
+	handler:    ia64_mca_cpe_int_handler,
+	flags:      SA_INTERRUPT,
+	name:       "cpe_hndlr"
+};
+
+/*
+ *  ia64_mca_log_sal_error_record
+ *
+ *  This function retrieves a specified error record type from SAL, sends it to
+ *  the system log, and notifies SALs to clear the record from its non-volatile
+ *  memory.
+ *
+ *  Inputs  :   sal_info_type   (Type of error record MCA/CMC/CPE/INIT)
+ *  Outputs :   None
+ */
+void
+ia64_mca_log_sal_error_record(int sal_info_type)
+{
+	/* Get the MCA error record */
+	if (!ia64_log_get(sal_info_type, (prfunc_t)printk))
+		return;                 // no record retrieved
+
+	/* Log the error record */
+	ia64_log_print(sal_info_type, (prfunc_t)printk);
+
+	/* Clear the CMC SAL logs now that they have been logged */
+	ia64_sal_clear_state_info(sal_info_type);
+}
 
 /*
  * hack for now, add platform dependent handlers
@@ -67,10 +123,14 @@
 }
 
 void
-cmci_handler_platform (int cmc_irq, void *arg, struct pt_regs *ptregs)
+ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs)
 {
+	IA64_MCA_DEBUG("ia64_mca_cpe_int_handler: received interrupt. vector = %#x\n", cpe_irq);
 
+	/* Get the CMC error record and log it */
+	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE);
 }
+
 /*
  * This routine will be used to deal with platform specific handling
  * of the init, i.e. drop into the kernel debugger on server machine,
@@ -81,17 +141,72 @@
 init_handler_platform (struct pt_regs *regs)
 {
 	/* if a kernel debugger is available call it here else just dump the registers */
+
 	show_regs(regs);		/* dump the state info */
+	while (1);			/* hang city if no debugger */
 }
 
+/*
+ * ia64_mca_init_platform
+ *
+ *  External entry for platform specific MCA initialization.
+ *
+ *  Inputs
+ *      None
+ *
+ *  Outputs
+ *      None
+ */
 void
-log_print_platform ( void *cur_buff_ptr, prfunc_t prfunc)
+ia64_mca_init_platform (void)
 {
+
 }
 
+/*
+ *  ia64_mca_check_errors
+ *
+ *  External entry to check for error records which may have been posted by SAL
+ *  for a prior failure which resulted in a machine shutdown before an the
+ *  error could be logged.  This function must be called after the filesystem
+ *  is initialized.
+ *
+ *  Inputs  :   None
+ *
+ *  Outputs :   None
+ */
 void
-ia64_mca_init_platform (void)
+ia64_mca_check_errors (void)
 {
+	/*
+	 *  If there is an MCA error record pending, get it and log it.
+	 */
+	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);
+}
+
+/*
+ * ia64_mca_register_cpev
+ *
+ *  Register the corrected platform error vector with SAL.
+ *
+ *  Inputs
+ *      cpev        Corrected Platform Error Vector number
+ *
+ *  Outputs
+ *      None
+ */
+static void
+ia64_mca_register_cpev (int cpev)
+{
+	/* Register the CPE interrupt vector with SAL */
+	if (ia64_sal_mc_set_params(SAL_MC_PARAM_CPE_INT, SAL_MC_PARAM_MECHANISM_INT, cpev, 0, 0)) {
+		printk("ia64_mca_platform_init: failed to register Corrected "
+		       "Platform Error interrupt vector with SAL.\n");
+		return;
+	}
+
+	IA64_MCA_DEBUG("ia64_mca_platform_init: corrected platform error "
+		       "vector %#x setup and enabled\n", cpev);
 }
 
 #endif /* PLATFORM_MCA_HANDLERS */
@@ -140,30 +255,36 @@
 				     && !ia64_pmss_dump_bank0))
 			printk("\n");
 	}
-	/* hang city for now, until we include debugger or copy to ptregs to show: */
-	while (1);
 }
 
 /*
  * ia64_mca_cmc_vector_setup
- *	Setup the correctable machine check vector register in the processor
+ *
+ *  Setup the corrected machine check vector register in the processor and
+ *  unmask interrupt.  This function is invoked on a per-processor basis.
+ *
  * Inputs
- *	Enable (1 - enable cmc interrupt , 0 - disable)
- *	CMC handler entry point (if enabled)
+ *      None
  *
  * Outputs
  *	None
  */
-static void
-ia64_mca_cmc_vector_setup(int		enable,
-			  int_vector_t	cmc_vector)
+void
+ia64_mca_cmc_vector_setup (void)
 {
 	cmcv_reg_t	cmcv;
 
 	cmcv.cmcv_regval	= 0;
-	cmcv.cmcv_mask	= enable;
-	cmcv.cmcv_vector	= cmc_vector;
+	cmcv.cmcv_mask      = 0;        /* Unmask/enable interrupt */
+	cmcv.cmcv_vector    = IA64_CMC_VECTOR;
 	ia64_set_cmcv(cmcv.cmcv_regval);
+
+	IA64_MCA_DEBUG("ia64_mca_platform_init: CPU %d corrected "
+		       "machine check vector %#x setup and enabled.\n",
+		       smp_processor_id(), IA64_CMC_VECTOR);
+
+	IA64_MCA_DEBUG("ia64_mca_platform_init: CPU %d CMCV = %#016lx\n",
+		       smp_processor_id(), ia64_get_cmcv());
 }
 
 
@@ -174,26 +295,58 @@
 void
 mca_test(void)
 {
-	slpi_buf.slpi_valid.slpi_psi = 1;
-	slpi_buf.slpi_valid.slpi_cache_check = 1;
-	slpi_buf.slpi_valid.slpi_tlb_check = 1;
-	slpi_buf.slpi_valid.slpi_bus_check = 1;
-	slpi_buf.slpi_valid.slpi_minstate = 1;
-	slpi_buf.slpi_valid.slpi_bank1_gr = 1;
-	slpi_buf.slpi_valid.slpi_br = 1;
-	slpi_buf.slpi_valid.slpi_cr = 1;
-	slpi_buf.slpi_valid.slpi_ar = 1;
-	slpi_buf.slpi_valid.slpi_rr = 1;
-	slpi_buf.slpi_valid.slpi_fr = 1;
+	slpi_buf.valid.psi_static_struct = 1;
+	slpi_buf.valid.num_cache_check = 1;
+	slpi_buf.valid.num_tlb_check = 1;
+	slpi_buf.valid.num_bus_check = 1;
+	slpi_buf.valid.processor_static_info.minstate = 1;
+	slpi_buf.valid.processor_static_info.br = 1;
+	slpi_buf.valid.processor_static_info.cr = 1;
+	slpi_buf.valid.processor_static_info.ar = 1;
+	slpi_buf.valid.processor_static_info.rr = 1;
+	slpi_buf.valid.processor_static_info.fr = 1;
 
 	ia64_os_mca_dispatch();
 }
 
 #endif /* #if defined(MCA_TEST) */
 
+
+/*
+ *  verify_guid
+ *
+ *  Compares a test guid to a target guid and returns result.
+ *
+ *  Inputs
+ *      test_guid *     (ptr to guid to be verified)
+ *      target_guid *   (ptr to standard guid to be verified against)
+ *
+ *  Outputs
+ *      0               (test verifies against target)
+ *      non-zero        (test guid does not verify)
+ */
+static int
+verify_guid (efi_guid_t *test, efi_guid_t *target)
+{
+	int     rc;
+
+	if ((rc = memcmp((void *)test, (void *)target, sizeof(efi_guid_t)))) {
+		IA64_MCA_DEBUG("ia64_mca_print: invalid guid = "
+			       "{ %08x, %04x, %04x, { %#02x, %#02x, %#02x, %#02x, "
+			       "%#02x, %#02x, %#02x, %#02x, } } \n ",
+			       test->data1, test->data2, test->data3, test->data4[0],
+			       test->data4[1], test->data4[2], test->data4[3],
+			       test->data4[4], test->data4[5], test->data4[6],
+			       test->data4[7]);
+	}
+
+	return rc;
+}
+
 /*
  * ia64_mca_init
- *	Do all the mca specific initialization on a per-processor basis.
+ *
+ *  Do all the system level mca specific initialization.
  *
  *	1. Register spinloop and wakeup request interrupt vectors
  *
@@ -201,77 +354,80 @@
  *
  *	3. Register OS_INIT handler entry point
  *
- *	4. Initialize CMCV register to enable/disable CMC interrupt on the
- *	   processor and hook a handler in the platform-specific ia64_mca_init.
+ *  4. Initialize MCA/CMC/INIT related log buffers maintained by the OS.
  *
- *	5. Initialize MCA/CMC/INIT related log buffers maintained by the OS.
+ *  Note that this initialization is done very early before some kernel
+ *  services are available.
  *
- * Inputs
- *	None
- * Outputs
- *	None
+ *  Inputs  :   None
+ *
+ *  Outputs :   None
  */
 void __init
 ia64_mca_init(void)
 {
 	ia64_fptr_t *mon_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler;
 	ia64_fptr_t *slave_init_ptr = (ia64_fptr_t *)ia64_slave_init_handler;
+	ia64_fptr_t *mca_hldlr_ptr = (ia64_fptr_t *)ia64_os_mca_dispatch;
 	int i;
+	s64 rc;
 
-	IA64_MCA_DEBUG("ia64_mca_init : begin\n");
+	IA64_MCA_DEBUG("ia64_mca_init: begin\n");
 
 	/* Clear the Rendez checkin flag for all cpus */
-	for(i = 0 ; i < IA64_MAXCPUS; i++)
+	for(i = 0 ; i < NR_CPUS; i++)
 		ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
 
-	/* NOTE : The actual irqs for the rendez, wakeup and
-	 * cmc interrupts are requested in the platform-specific
-	 * mca initialization code.
-	 */
 	/*
 	 * Register the rendezvous spinloop and wakeup mechanism with SAL
 	 */
 
 	/* Register the rendezvous interrupt vector with SAL */
-	if (ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT,
-				   SAL_MC_PARAM_MECHANISM_INT,
-				   IA64_MCA_RENDEZ_VECTOR,
-				   IA64_MCA_RENDEZ_TIMEOUT,
-				   0))
+	if ((rc = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT,
+					 SAL_MC_PARAM_MECHANISM_INT,
+					 IA64_MCA_RENDEZ_VECTOR,
+					 IA64_MCA_RENDEZ_TIMEOUT,
+					 0)))
+	{
+		printk("ia64_mca_init: Failed to register rendezvous interrupt "
+		       "with SAL.  rc = %ld\n", rc);
 		return;
+	}
 
 	/* Register the wakeup interrupt vector with SAL */
-	if (ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP,
-				   SAL_MC_PARAM_MECHANISM_INT,
-				   IA64_MCA_WAKEUP_VECTOR,
-				   0,
-				   0))
+	if ((rc = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP,
+					 SAL_MC_PARAM_MECHANISM_INT,
+					 IA64_MCA_WAKEUP_VECTOR,
+					 0, 0)))
+	{
+		printk("ia64_mca_init: Failed to register wakeup interrupt with SAL.  rc = %ld\n",
+		       rc);
 		return;
+	}
 
-	IA64_MCA_DEBUG("ia64_mca_init : registered mca rendezvous spinloop and wakeup mech.\n");
-	/*
-	 * Setup the correctable machine check vector
-	 */
-	ia64_mca_cmc_vector_setup(IA64_CMC_INT_ENABLE, IA64_CMC_VECTOR);
-
-	IA64_MCA_DEBUG("ia64_mca_init : correctable mca vector setup done\n");
+	IA64_MCA_DEBUG("ia64_mca_init: registered mca rendezvous spinloop and wakeup mech.\n");
 
-	ia64_mc_info.imi_mca_handler		= __pa(ia64_os_mca_dispatch);
+	ia64_mc_info.imi_mca_handler        = __pa(mca_hldlr_ptr->fp);
 	/*
 	 * XXX - disable SAL checksum by setting size to 0; should be
 	 *	__pa(ia64_os_mca_dispatch_end) - __pa(ia64_os_mca_dispatch);
 	 */
 	ia64_mc_info.imi_mca_handler_size	= 0;
-	/* Register the os mca handler with SAL */
-	if (ia64_sal_set_vectors(SAL_VECTOR_OS_MCA,
-				 ia64_mc_info.imi_mca_handler,
-				 __pa(ia64_get_gp()),
-				 ia64_mc_info.imi_mca_handler_size,
-				 0,0,0))
 
+	/* Register the os mca handler with SAL */
+	if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_MCA,
+				       ia64_mc_info.imi_mca_handler,
+				       mca_hldlr_ptr->gp,
+				       ia64_mc_info.imi_mca_handler_size,
+				       0, 0, 0)))
+	{
+		printk("ia64_mca_init: Failed to register os mca handler with SAL.  rc = %ld\n",
+		       rc);
 		return;
+	}
 
-	IA64_MCA_DEBUG("ia64_mca_init : registered os mca handler with SAL\n");
+	IA64_MCA_DEBUG("ia64_mca_init: registered os mca handler with SAL at 0x%lx, gp = 0x%lx\n",
+		       ia64_mc_info.imi_mca_handler, mca_hldlr_ptr->gp);
 
 	/*
 	 * XXX - disable SAL checksum by setting size to 0, should be
@@ -282,53 +438,87 @@
 	ia64_mc_info.imi_slave_init_handler		= __pa(slave_init_ptr->fp);
 	ia64_mc_info.imi_slave_init_handler_size	= 0;
 
-	IA64_MCA_DEBUG("ia64_mca_init : os init handler at %lx\n",ia64_mc_info.imi_monarch_init_handler);
+	IA64_MCA_DEBUG("ia64_mca_init: os init handler at %lx\n",
+		       ia64_mc_info.imi_monarch_init_handler);
 
 	/* Register the os init handler with SAL */
-	if (ia64_sal_set_vectors(SAL_VECTOR_OS_INIT,
-				 ia64_mc_info.imi_monarch_init_handler,
-				 __pa(ia64_get_gp()),
-				 ia64_mc_info.imi_monarch_init_handler_size,
-				 ia64_mc_info.imi_slave_init_handler,
-				 __pa(ia64_get_gp()),
-				 ia64_mc_info.imi_slave_init_handler_size))
+	if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_INIT,
+				       ia64_mc_info.imi_monarch_init_handler,
+				       __pa(ia64_get_gp()),
+				       ia64_mc_info.imi_monarch_init_handler_size,
+				       ia64_mc_info.imi_slave_init_handler,
+				       __pa(ia64_get_gp()),
+				       ia64_mc_info.imi_slave_init_handler_size)))
+	{
+		printk("ia64_mca_init: Failed to register m/s init handlers with SAL. rc = %ld\n",
+		       rc);
+		return;
+	}
 
+	IA64_MCA_DEBUG("ia64_mca_init: registered os init handler with SAL\n");
 
-		return;
+	/*
+	 *  Configure the CMCI vector and handler. Interrupts for CMC are
+	 *  per-processor, so AP CMC interrupts are setup in smp_callin() (smp.c).
+	 */
+	register_percpu_irq(IA64_CMC_VECTOR, &cmci_irqaction);
+	ia64_mca_cmc_vector_setup();       /* Setup vector on BSP & enable */
 
-	IA64_MCA_DEBUG("ia64_mca_init : registered os init handler with SAL\n");
+	/* Setup the MCA rendezvous interrupt vector */
+	register_percpu_irq(IA64_MCA_RENDEZ_VECTOR, &mca_rdzv_irqaction);
+
+	/* Setup the MCA wakeup interrupt vector */
+	register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction);
+
+	/* Setup the CPE interrupt vector */
+	{
+		irq_desc_t *desc;
+		unsigned int irq;
+		int cpev = acpi_request_vector(ACPI20_ENTRY_PIS_CPEI);
+
+		if (cpev >= 0) {
+			for (irq = 0; irq < NR_IRQS; ++irq)
+				if (irq_to_vector(irq) = cpev) {
+					desc = irq_desc(irq);
+					desc->status |= IRQ_PER_CPU;
+					desc->handler = &irq_type_iosapic_level;
+					setup_irq(irq, &mca_cpe_irqaction);
+				}
+			ia64_mca_register_cpev(cpev);
+		} else
+			printk("ia64_mca_init: Failed to get routed CPEI vector from ACPI.\n");
+	}
 
 	/* Initialize the areas set aside by the OS to buffer the
 	 * platform/processor error states for MCA/INIT/CMC
 	 * handling.
 	 */
-	ia64_log_init(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR);
-	ia64_log_init(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PLATFORM);
-	ia64_log_init(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR);
-	ia64_log_init(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PLATFORM);
-	ia64_log_init(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR);
-	ia64_log_init(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PLATFORM);
-
-	ia64_mca_init_platform();
-
-	IA64_MCA_DEBUG("ia64_mca_init : platform-specific mca handling setup done\n");
+	ia64_log_init(SAL_INFO_TYPE_MCA);
+	ia64_log_init(SAL_INFO_TYPE_INIT);
+	ia64_log_init(SAL_INFO_TYPE_CMC);
+	ia64_log_init(SAL_INFO_TYPE_CPE);
 
 #if defined(MCA_TEST)
 	mca_test();
 #endif /* #if defined(MCA_TEST) */
 
 	printk("Mca related initialization done\n");
+
+#if 0   // Too early in initialization -- error log is lost
+	/* Do post-failure MCA error logging */
+	ia64_mca_check_errors();
+#endif  // Too early in initialization -- error log is lost
 }
 
 /*
  * ia64_mca_wakeup_ipi_wait
+ *
  *	Wait for the inter-cpu interrupt to be sent by the
  *	monarch processor once it is done with handling the
  *	MCA.
- * Inputs
- *	None
- * Outputs
- *	None
+ *
+ *  Inputs  :   None
+ *  Outputs :   None
  */
 void
 ia64_mca_wakeup_ipi_wait(void)
@@ -339,16 +529,16 @@
 
 	do {
 		switch(irr_num) {
-		case 0:
+		      case 0:
 			irr = ia64_get_irr0();
 			break;
-		case 1:
+		      case 1:
 			irr = ia64_get_irr1();
 			break;
-		case 2:
+		      case 2:
 			irr = ia64_get_irr2();
 			break;
-		case 3:
+		      case 3:
 			irr = ia64_get_irr3();
 			break;
 		}
@@ -357,26 +547,28 @@
 
 /*
  * ia64_mca_wakeup
+ *
  *	Send an inter-cpu interrupt to wake-up a particular cpu
  *	and mark that cpu to be out of rendez.
- * Inputs
- *	cpuid
- * Outputs
- *	None
+ *
+ *  Inputs  :   cpuid
+ *  Outputs :   None
  */
 void
 ia64_mca_wakeup(int cpu)
 {
 	platform_send_ipi(cpu, IA64_MCA_WAKEUP_VECTOR, IA64_IPI_DM_INT, 0);
 	ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
+
 }
+
 /*
  * ia64_mca_wakeup_all
+ *
  *	Wakeup all the cpus which have rendez'ed previously.
- * Inputs
- *	None
- * Outputs
- *	None
+ *
+ *  Inputs  :   None
+ *  Outputs :   None
  */
 void
 ia64_mca_wakeup_all(void)
@@ -389,15 +581,16 @@
 			ia64_mca_wakeup(cpu);
 
 }
+
 /*
  * ia64_mca_rendez_interrupt_handler
+ *
  *	This is handler used to put slave processors into spinloop
  *	while the monarch processor does the mca handling and later
  *	wake each slave up once the monarch is done.
- * Inputs
- *	None
- * Outputs
- *	None
+ *
+ *  Inputs  :   None
+ *  Outputs :   None
  */
 void
 ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs)
@@ -423,23 +616,22 @@
 
 	/* Enable all interrupts */
 	restore_flags(flags);
-
-
 }
 
 
 /*
  * ia64_mca_wakeup_int_handler
+ *
  *	The interrupt handler for processing the inter-cpu interrupt to the
  *	slave cpu which was spinning in the rendez loop.
  *	Since this spinning is done by turning off the interrupts and
  *	polling on the wakeup-interrupt bit in the IRR, there is
  *	nothing useful to be done in the handler.
- *  Inputs
- *	wakeup_irq	(Wakeup-interrupt bit)
+ *
+ *  Inputs  :   wakeup_irq  (Wakeup-interrupt bit)
  *	arg		(Interrupt handler specific argument)
  *	ptregs		(Exception frame at the time of the interrupt)
- *  Outputs
+ *  Outputs :   None
  *
  */
 void
@@ -450,16 +642,16 @@
 
 /*
  * ia64_return_to_sal_check
+ *
  *	This is function called before going back from the OS_MCA handler
  *	to the OS_MCA dispatch code which finally takes the control back
  *	to the SAL.
  *	The main purpose of this routine is to setup the OS_MCA to SAL
  *	return state which can be used by the OS_MCA dispatch code
  *	just before going back to SAL.
- * Inputs
- *	None
- * Outputs
- *	None
+ *
+ *  Inputs  :   None
+ *  Outputs :   None
  */
 
 void
@@ -474,11 +666,13 @@
 	ia64_os_to_sal_handoff_state.imots_sal_check_ra  		ia64_sal_to_os_handoff_state.imsto_sal_check_ra;
 
-	/* For now ignore the MCA */
-	ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_CORRECTED;
+	/* Cold Boot for uncorrectable MCA */
+	ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT;
 }
+
 /*
  * ia64_mca_ucmc_handler
+ *
  *	This is uncorrectable machine check handler called from OS_MCA
  *	dispatch code which is in turn called from SAL_CHECK().
  *	This is the place where the core of OS MCA handling is done.
@@ -487,93 +681,92 @@
  *	monarch processor. Once the  monarch is done with MCA handling
  *	further MCA logging is enabled by clearing logs.
  *	Monarch also has the duty of sending wakeup-IPIs to pull the
- *	slave processors out of rendez. spinloop.
- * Inputs
- *	None
- * Outputs
- *	None
+ *  slave processors out of rendezvous spinloop.
+ *
+ *  Inputs  :   None
+ *  Outputs :   None
  */
 void
 ia64_mca_ucmc_handler(void)
 {
+#if 0   /* stubbed out @FVL */
+	/*
+	 *  Attempting to log a DBE error Causes "reserved register/field panic"
+	 *  in printk.
+	 */
 
-	/* Get the MCA processor log */
-	ia64_log_get(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk);
-	/* Get the MCA platform log */
-	ia64_log_get(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PLATFORM, (prfunc_t)printk);
-
-	ia64_log_print(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk);
+	/* Get the MCA error record and log it */
+	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);
+#endif  /* stubbed out @FVL */
 
 	/*
-	 * Do some error handling - Platform-specific mca handler is called at this point
+	 *  Do Platform-specific mca error handling if required.
 	 */
-
 	mca_handler_platform() ;
 
-	/* Clear the SAL MCA logs */
-	ia64_log_clear(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR, 1, printk);
-	ia64_log_clear(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PLATFORM, 1, printk);
-
-	/* Wakeup all the processors which are spinning in the rendezvous
-	 * loop.
+	/*
+	 *  Wakeup all the processors which are spinning in the rendezvous
+	 *  loop.
 	 */
 	ia64_mca_wakeup_all();
+
+	/* Return to SAL */
 	ia64_return_to_sal_check();
 }
 
 /*
  * ia64_mca_cmc_int_handler
- *	This is correctable machine check interrupt handler.
+ *
+ *  This is corrected machine check interrupt handler.
  *	Right now the logs are extracted and displayed in a well-defined
  *	format.
+ *
  * Inputs
- *	None
+ *      interrupt number
+ *      client data arg ptr
+ *      saved registers ptr
+ *
  * Outputs
  *	None
  */
 void
 ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs)
 {
-	/* Get the CMC processor log */
-	ia64_log_get(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk);
-	/* Get the CMC platform log */
-	ia64_log_get(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PLATFORM, (prfunc_t)printk);
-
-
-	ia64_log_print(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk);
-	cmci_handler_platform(cmc_irq, arg, ptregs);
+	IA64_MCA_DEBUG("ia64_mca_cmc_int_handler: received interrupt vector = %#x on CPU %d\n",
+		       cmc_irq, smp_processor_id());
 
-	/* Clear the CMC SAL logs now that they have been saved in the OS buffer */
-	ia64_sal_clear_state_info(SAL_INFO_TYPE_CMC);
+	/* Get the CMC error record and log it */
+	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC);
 }
 
 /*
  * IA64_MCA log support
  */
 #define IA64_MAX_LOGS		2	/* Double-buffering for nested MCAs */
-#define IA64_MAX_LOG_TYPES	3	/* MCA, CMC, INIT */
-#define IA64_MAX_LOG_SUBTYPES	2	/* Processor, Platform */
+#define IA64_MAX_LOG_TYPES      4   /* MCA, INIT, CMC, CPE */
 
-typedef struct ia64_state_log_s {
+typedef struct ia64_state_log_s
+{
 	spinlock_t	isl_lock;
 	int		isl_index;
-	ia64_psilog_t	isl_log[IA64_MAX_LOGS];	/* need space to store header + error log */
+	ia64_err_rec_t  isl_log[IA64_MAX_LOGS]; /* need space to store header + error log */
 } ia64_state_log_t;
 
-static ia64_state_log_t	ia64_state_log[IA64_MAX_LOG_TYPES][IA64_MAX_LOG_SUBTYPES];
+static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES];
 
-#define IA64_LOG_LOCK_INIT(it, sit)	spin_lock_init(&ia64_state_log[it][sit].isl_lock)
-#define IA64_LOG_LOCK(it, sit)		spin_lock_irqsave(&ia64_state_log[it][sit].isl_lock, s)
-#define IA64_LOG_UNLOCK(it, sit)	spin_unlock_irqrestore(&ia64_state_log[it][sit].isl_lock,\
-							       s)
-#define IA64_LOG_NEXT_INDEX(it, sit)	ia64_state_log[it][sit].isl_index
-#define IA64_LOG_CURR_INDEX(it, sit)	1 - ia64_state_log[it][sit].isl_index
-#define IA64_LOG_INDEX_INC(it, sit)	\
-	ia64_state_log[it][sit].isl_index = 1 - ia64_state_log[it][sit].isl_index
-#define IA64_LOG_INDEX_DEC(it, sit)	\
-	ia64_state_log[it][sit].isl_index = 1 - ia64_state_log[it][sit].isl_index
-#define IA64_LOG_NEXT_BUFFER(it, sit)	(void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_NEXT_INDEX(it,sit)]))
-#define IA64_LOG_CURR_BUFFER(it, sit)	(void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_CURR_INDEX(it,sit)]))
+/* Note:  Some of these macros assume IA64_MAX_LOGS is always 2.  Should be */
+/* fixed. @FVL                                                              */
+#define IA64_LOG_LOCK_INIT(it) spin_lock_init(&ia64_state_log[it].isl_lock)
+#define IA64_LOG_LOCK(it)      spin_lock_irqsave(&ia64_state_log[it].isl_lock, s)
+#define IA64_LOG_UNLOCK(it)    spin_unlock_irqrestore(&ia64_state_log[it].isl_lock,s)
+#define IA64_LOG_NEXT_INDEX(it)    ia64_state_log[it].isl_index
+#define IA64_LOG_CURR_INDEX(it)    1 - ia64_state_log[it].isl_index
+#define IA64_LOG_INDEX_INC(it) \
+    ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index
+#define IA64_LOG_INDEX_DEC(it) \
+    ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index
+#define IA64_LOG_NEXT_BUFFER(it)   (void *)(&(ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)]))
+#define IA64_LOG_CURR_BUFFER(it)   (void *)(&(ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)]))
 
 /*
  * C portion of the OS INIT handler
@@ -584,123 +777,217 @@
  *
  * Returns:
  *   0 if SAL must warm boot the System
- *   1 if SAL must retrun to interrupted context using PAL_MC_RESUME
+ *   1 if SAL must return to interrupted context using PAL_MC_RESUME
  *
  */
-
 void
 ia64_init_handler (struct pt_regs *regs)
 {
 	sal_log_processor_info_t *proc_ptr;
-	ia64_psilog_t *plog_ptr;
+	ia64_err_rec_t *plog_ptr;
 
 	printk("Entered OS INIT handler\n");
 
 	/* Get the INIT processor log */
-	ia64_log_get(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk);
-	/* Get the INIT platform log */
-	ia64_log_get(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PLATFORM, (prfunc_t)printk);
+	if (!ia64_log_get(SAL_INFO_TYPE_INIT, (prfunc_t)printk))
+		return;                 // no record retrieved
 
 #ifdef IA64_DUMP_ALL_PROC_INFO
-	ia64_log_print(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk);
+	ia64_log_print(SAL_INFO_TYPE_INIT, (prfunc_t)printk);
 #endif
 
 	/*
 	 * get pointer to min state save area
 	 *
 	 */
-	plog_ptr=(ia64_psilog_t *)IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_INIT,
-						       SAL_SUB_INFO_TYPE_PROCESSOR);
-	proc_ptr = &plog_ptr->devlog.proclog;
+	plog_ptr=(ia64_err_rec_t *)IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_INIT);
+	proc_ptr = &plog_ptr->proc_err;
 
-	ia64_process_min_state_save(&proc_ptr->slpi_min_state_area,regs);
-
-	init_handler_platform(regs);              /* call platform specific routines */
+	ia64_process_min_state_save(&proc_ptr->processor_static_info.min_state_area,
+				    regs);
 
 	/* Clear the INIT SAL logs now that they have been saved in the OS buffer */
 	ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT);
+
+	init_handler_platform(regs);              /* call platform specific routines */
+}
+
+/*
+ *  ia64_log_prt_guid
+ *
+ *  Print a formatted GUID.
+ *
+ * Inputs   :   p_guid      (ptr to the GUID)
+ *              prfunc      (print function)
+ * Outputs  :   None
+ *
+ */
+void
+ia64_log_prt_guid (efi_guid_t *p_guid, prfunc_t prfunc)
+{
+	printk("GUID = { %08x, %04x, %04x, { %#02x, %#02x, %#02x, %#02x, "
+	       "%#02x, %#02x, %#02x, %#02x, } } \n ", p_guid->data1,
+	       p_guid->data2, p_guid->data3, p_guid->data4[0], p_guid->data4[1],
+	       p_guid->data4[2], p_guid->data4[3], p_guid->data4[4],
+	       p_guid->data4[5], p_guid->data4[6], p_guid->data4[7]);
+}
+
+static void
+ia64_log_hexdump(unsigned char *p, unsigned long n_ch, prfunc_t prfunc)
+{
+	int i, j;
+
+	if (!p)
+		return;
+
+	for (i = 0; i < n_ch;) {
+		prfunc("%p ", (void *)p);
+		for (j = 0; (j < 16) && (i < n_ch); i++, j++, p++) {
+			prfunc("%02x ", *p);
+		}
+		prfunc("\n");
+	}
+}
+
+#ifdef MCA_PRT_XTRA_DATA    // for test only @FVL
+
+static void
+ia64_log_prt_record_header (sal_log_record_header_t *rh, prfunc_t prfunc)
+{
+	prfunc("SAL RECORD HEADER:  Record buffer = %p,  header size = %ld\n",
+	       (void *)rh, sizeof(sal_log_record_header_t));
+	ia64_log_hexdump((unsigned char *)rh, sizeof(sal_log_record_header_t),
+			 (prfunc_t)prfunc);
+	prfunc("Total record length = %d\n", rh->len);
+	ia64_log_prt_guid(&rh->platform_guid, prfunc);
+	prfunc("End of SAL RECORD HEADER\n");
+}
+
+static void
+ia64_log_prt_section_header (sal_log_section_hdr_t *sh, prfunc_t prfunc)
+{
+	prfunc("SAL SECTION HEADER:  Record buffer = %p,  header size = %ld\n",
+	       (void *)sh, sizeof(sal_log_section_hdr_t));
+	ia64_log_hexdump((unsigned char *)sh, sizeof(sal_log_section_hdr_t),
+			 (prfunc_t)prfunc);
+	prfunc("Length of section & header = %d\n", sh->len);
+	ia64_log_prt_guid(&sh->guid, prfunc);
+	prfunc("End of SAL SECTION HEADER\n");
 }
+#endif  // MCA_PRT_XTRA_DATA for test only @FVL
 
 /*
  * ia64_log_init
  *	Reset the OS ia64 log buffer
- * Inputs	:	info_type	(SAL_INFO_TYPE_{MCA,INIT,CMC})
- *			sub_info_type	(SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM})
+ * Inputs   :   info_type   (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE})
  * Outputs	:	None
  */
 void
-ia64_log_init(int sal_info_type, int sal_sub_info_type)
+ia64_log_init(int sal_info_type)
 {
-	IA64_LOG_LOCK_INIT(sal_info_type, sal_sub_info_type);
-	IA64_LOG_NEXT_INDEX(sal_info_type, sal_sub_info_type) = 0;
-	memset(IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type), 0,
-	       sizeof(ia64_psilog_t) * IA64_MAX_LOGS);
+	IA64_LOG_LOCK_INIT(sal_info_type);
+	IA64_LOG_NEXT_INDEX(sal_info_type) = 0;
+	memset(IA64_LOG_NEXT_BUFFER(sal_info_type), 0,
+	       sizeof(ia64_err_rec_t) * IA64_MAX_LOGS);
 }
 
 /*
  * ia64_log_get
+ *
  *	Get the current MCA log from SAL and copy it into the OS log buffer.
- * Inputs	:	info_type	(SAL_INFO_TYPE_{MCA,INIT,CMC})
- *			sub_info_type	(SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM})
- * Outputs	:	None
+ *
+ *  Inputs  :   info_type   (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE})
+ *              prfunc      (fn ptr of log output function)
+ *  Outputs :   size        (total record length)
  *
  */
-void
-ia64_log_get(int sal_info_type, int sal_sub_info_type, prfunc_t prfunc)
+u64
+ia64_log_get(int sal_info_type, prfunc_t prfunc)
 {
-	sal_log_header_t	*log_buffer;
-	int			s,total_len=0;
-
-	IA64_LOG_LOCK(sal_info_type, sal_sub_info_type);
+	sal_log_record_header_t     *log_buffer;
+	u64                         total_len = 0;
+	int                         s;
 
+	IA64_LOG_LOCK(sal_info_type);
 
 	/* Get the process state information */
-	log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type);
-
-	if (!(total_len=ia64_sal_get_state_info(sal_info_type,(u64 *)log_buffer)))
-		prfunc("ia64_mca_log_get : Getting processor log failed\n");
-
-	IA64_MCA_DEBUG("ia64_log_get: retrieved %d bytes of error information\n",total_len);
+	log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type);
 
-	IA64_LOG_INDEX_INC(sal_info_type, sal_sub_info_type);
-
-	IA64_LOG_UNLOCK(sal_info_type, sal_sub_info_type);
+	total_len = ia64_sal_get_state_info(sal_info_type, (u64 *)log_buffer);
 
+	if (total_len) {
+		IA64_LOG_INDEX_INC(sal_info_type);
+		IA64_LOG_UNLOCK(sal_info_type);
+		IA64_MCA_DEBUG("ia64_log_get: SAL error record type %d retrieved. "
+			       "Record length = %ld\n", sal_info_type, total_len);
+		return total_len;
+	} else {
+		IA64_LOG_UNLOCK(sal_info_type);
+		prfunc("ia64_log_get: Failed to retrieve SAL error record type %d\n",
+		       sal_info_type);
+		return 0;
+	}
 }
 
 /*
- * ia64_log_clear
- *	Clear the current MCA log from SAL and dpending on the clear_os_buffer flags
- *	clear the OS log buffer also
- * Inputs	:	info_type	(SAL_INFO_TYPE_{MCA,INIT,CMC})
- *			sub_info_type	(SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM})
- *			clear_os_buffer
+ *  ia64_log_prt_oem_data
+ *
+ *  Print OEM specific data if included.
+ *
+ * Inputs   :   header_len  (length passed in section header)
+ *              sect_len    (default length of section type)
+ *              p_data      (ptr to data)
  *			prfunc		(print function)
  * Outputs	:	None
  *
  */
 void
-ia64_log_clear(int sal_info_type, int sal_sub_info_type, int clear_os_buffer, prfunc_t prfunc)
+ia64_log_prt_oem_data (int header_len, int sect_len, u8 *p_data, prfunc_t prfunc)
 {
-	if (ia64_sal_clear_state_info(sal_info_type))
-		prfunc("ia64_mca_log_get : Clearing processor log failed\n");
-
-	if (clear_os_buffer) {
-		sal_log_header_t	*log_buffer;
-		int			s;
-
-		IA64_LOG_LOCK(sal_info_type, sal_sub_info_type);
+	int oem_data_len, i;
 
-		/* Get the process state information */
-		log_buffer = IA64_LOG_CURR_BUFFER(sal_info_type, sal_sub_info_type);
-
-		memset(log_buffer, 0, sizeof(ia64_psilog_t));
-
-		IA64_LOG_INDEX_DEC(sal_info_type, sal_sub_info_type);
-
-		IA64_LOG_UNLOCK(sal_info_type, sal_sub_info_type);
+	if ((oem_data_len = header_len - sect_len) > 0) {
+		prfunc(" OEM Specific Data:");
+		for (i = 0; i < oem_data_len; i++, p_data++)
+			prfunc(" %02x", *p_data);
 	}
+	prfunc("\n");
+}
 
+/*
+ *  ia64_log_rec_header_print
+ *
+ *  Log info from the SAL error record header.
+ *
+ *  Inputs  :   lh *    (ptr to SAL log error record header)
+ *              prfunc  (fn ptr of log output function to use)
+ *  Outputs :   None
+ */
+void
+ia64_log_rec_header_print (sal_log_record_header_t *lh, prfunc_t prfunc)
+{
+	char str_buf[32];
+
+	sprintf(str_buf, "%2d.%02d",
+		(lh->revision.major >> 4) * 10 + (lh->revision.major & 0xf),
+		(lh->revision.minor >> 4) * 10 + (lh->revision.minor & 0xf));
+	prfunc("+Err Record ID: %d    SAL Rev: %s\n", lh->id, str_buf);
+	sprintf(str_buf, "%02d/%02d/%04d/ %02d:%02d:%02d",
+		(lh->timestamp.slh_month >> 4) * 10 +
+		(lh->timestamp.slh_month & 0xf),
+		(lh->timestamp.slh_day >> 4) * 10 +
+		(lh->timestamp.slh_day & 0xf),
+		(lh->timestamp.slh_century >> 4) * 1000 +
+		(lh->timestamp.slh_century & 0xf) * 100 +
+		(lh->timestamp.slh_year >> 4) * 10 +
+		(lh->timestamp.slh_year & 0xf),
+		(lh->timestamp.slh_hour >> 4) * 10 +
+		(lh->timestamp.slh_hour & 0xf),
+		(lh->timestamp.slh_minute >> 4) * 10 +
+		(lh->timestamp.slh_minute & 0xf),
+		(lh->timestamp.slh_second >> 4) * 10 +
+		(lh->timestamp.slh_second & 0xf));
+	prfunc("+Time: %s    Severity %d\n", str_buf, lh->severity);
 }
 
 /*
@@ -729,6 +1016,33 @@
 		prfunc("+ %s[%d] 0x%lx\n", reg_prefix, i, regs[i]);
 }
 
+/*
+ * ia64_log_processor_fp_regs_print
+ *  Print the contents of the saved floating page register(s) in the format
+ *      <reg_prefix>[<index>] <value>
+ *
+ * Inputs:  ia64_fpreg  (Register save buffer)
+ *          reg_num     (# of registers)
+ *          reg_class   (application/banked/control/bank1_general)
+ *          reg_prefix  (ar/br/cr/b1_gr)
+ * Outputs: None
+ *
+ */
+void
+ia64_log_processor_fp_regs_print (struct ia64_fpreg *regs,
+                                  int               reg_num,
+                                  char              *reg_class,
+                                  char              *reg_prefix,
+                                  prfunc_t          prfunc)
+{
+	int i;
+
+	prfunc("+%s Registers\n", reg_class);
+	for (i = 0; i < reg_num; i++)
+		prfunc("+ %s[%d] 0x%lx%016lx\n", reg_prefix, i, regs[i].u.bits[1],
+		       regs[i].u.bits[0]);
+}
+
 static char *pal_mesi_state[] = {
 	"Invalid",
 	"Shared",
@@ -754,69 +1068,91 @@
 /*
  * ia64_log_cache_check_info_print
  *	Display the machine check information related to cache error(s).
- * Inputs	:	i		(Multiple errors are logged, i - index of logged error)
- *			info		(Machine check info logged by the PAL and later
+ * Inputs:  i           (Multiple errors are logged, i - index of logged error)
+ *          cc_info *   (Ptr to cache check info logged by the PAL and later
  *					 captured by the SAL)
- *			target_addr	(Address which caused the cache error)
- * Outputs	:	None
+ *          prfunc      (fn ptr of print function to be used for output)
+ * Outputs: None
  */
 void
-ia64_log_cache_check_info_print(int			i,
-				pal_cache_check_info_t	info,
-				u64			target_addr,
-				prfunc_t		prfunc)
+ia64_log_cache_check_info_print (int                      i,
+                                 sal_log_mod_error_info_t *cache_check_info,
+				 prfunc_t		prfunc)
 {
+	pal_cache_check_info_t  *info;
+	u64                     target_addr;
+
+	if (!cache_check_info->valid.check_info) {
+		IA64_MCA_DEBUG("ia64_mca_log_print: invalid cache_check_info[%d]\n",i);
+		return;                 /* If check info data not valid, skip it */
+	}
+
+	info        = (pal_cache_check_info_t *)&cache_check_info->check_info;
+	target_addr = cache_check_info->target_identifier;
+
 	prfunc("+ Cache check info[%d]\n+", i);
-	prfunc("  Level: L%d",info.level);
-	if (info.mv)
-		prfunc(" ,Mesi: %s",pal_mesi_state[info.mesi]);
-	prfunc(" ,Index: %d,", info.index);
-	if (info.ic)
-		prfunc(" ,Cache: Instruction");
-	if (info.dc)
-		prfunc(" ,Cache: Data");
-	if (info.tl)
-		prfunc(" ,Line: Tag");
-	if (info.dl)
-		prfunc(" ,Line: Data");
-	prfunc(" ,Operation: %s,", pal_cache_op[info.op]);
-	if (info.wv)
-		prfunc(" ,Way: %d,", info.way);
-	if (info.tv)
-		prfunc(" ,Target Addr: 0x%lx", target_addr);
-	if (info.mc)
-		prfunc(" ,MC: Corrected");
+	prfunc("  Level: L%d,",info->level);
+	if (info->mv)
+		prfunc(" Mesi: %s,",pal_mesi_state[info->mesi]);
+	prfunc(" Index: %d,", info->index);
+	if (info->ic)
+		prfunc(" Cache: Instruction,");
+	if (info->dc)
+		prfunc(" Cache: Data,");
+	if (info->tl)
+		prfunc(" Line: Tag,");
+	if (info->dl)
+		prfunc(" Line: Data,");
+	prfunc(" Operation: %s,", pal_cache_op[info->op]);
+	if (info->wv)
+		prfunc(" Way: %d,", info->way);
+	if (cache_check_info->valid.target_identifier)
+		/* Hope target address is saved in target_identifier */
+		if (info->tv)
+			prfunc(" Target Addr: 0x%lx,", target_addr);
+	if (info->mc)
+		prfunc(" MC: Corrected");
 	prfunc("\n");
 }
 
 /*
  * ia64_log_tlb_check_info_print
  *	Display the machine check information related to tlb error(s).
- * Inputs	:	i		(Multiple errors are logged, i - index of logged error)
- *			info		(Machine check info logged by the PAL and later
+ * Inputs:  i           (Multiple errors are logged, i - index of logged error)
+ *          tlb_info *  (Ptr to machine check info logged by the PAL and later
  *					 captured by the SAL)
- * Outputs	:	None
+ *          prfunc      (fn ptr of print function to be used for output)
+ * Outputs: None
  */
-
 void
-ia64_log_tlb_check_info_print(int			i,
-			      pal_tlb_check_info_t	info,
-			      prfunc_t			prfunc)
+ia64_log_tlb_check_info_print (int                      i,
+                               sal_log_mod_error_info_t *tlb_check_info,
+                               prfunc_t                 prfunc)
+
 {
+	pal_tlb_check_info_t    *info;
+
+	if (!tlb_check_info->valid.check_info) {
+		IA64_MCA_DEBUG("ia64_mca_log_print: invalid tlb_check_info[%d]\n", i);
+		return;                 /* If check info data not valid, skip it */
+	}
+
+	info = (pal_tlb_check_info_t *)&tlb_check_info->check_info;
+
 	prfunc("+ TLB Check Info [%d]\n+", i);
-	if (info.itc)
+	if (info->itc)
 		prfunc("  Failure: Instruction Translation Cache");
-	if (info.dtc)
+	if (info->dtc)
 		prfunc("  Failure: Data Translation Cache");
-	if (info.itr) {
+	if (info->itr) {
 		prfunc("  Failure: Instruction Translation Register");
-		prfunc(" ,Slot: %d", info.tr_slot);
+		prfunc(" ,Slot: %d", info->tr_slot);
 	}
-	if (info.dtr) {
+	if (info->dtr) {
 		prfunc("  Failure: Data Translation Register");
-		prfunc(" ,Slot: %d", info.tr_slot);
+		prfunc(" ,Slot: %d", info->tr_slot);
 	}
-	if (info.mc)
+	if (info->mc)
 		prfunc(" ,MC: Corrected");
 	prfunc("\n");
 }
@@ -824,159 +1160,719 @@
 /*
  * ia64_log_bus_check_info_print
  *	Display the machine check information related to bus error(s).
- * Inputs	:	i		(Multiple errors are logged, i - index of logged error)
- *			info		(Machine check info logged by the PAL and later
+ * Inputs:  i           (Multiple errors are logged, i - index of logged error)
+ *          bus_info *  (Ptr to machine check info logged by the PAL and later
  *					 captured by the SAL)
- *			req_addr	(Address of the requestor of the transaction)
- *			resp_addr	(Address of the responder of the transaction)
- *			target_addr	(Address where the data was to be delivered to  or
- *					 obtained from)
- * Outputs	:	None
+ *          prfunc      (fn ptr of print function to be used for output)
+ * Outputs: None
  */
 void
-ia64_log_bus_check_info_print(int			i,
-			      pal_bus_check_info_t	info,
-			      u64			req_addr,
-			      u64			resp_addr,
-			      u64			targ_addr,
-			      prfunc_t			prfunc)
-{
+ia64_log_bus_check_info_print (int                      i,
+                               sal_log_mod_error_info_t *bus_check_info,
+                               prfunc_t                 prfunc)
+{
+	pal_bus_check_info_t *info;
+	u64         req_addr;   /* Address of the requestor of the transaction */
+	u64         resp_addr;  /* Address of the responder of the transaction */
+	u64         targ_addr;  /* Address where the data was to be delivered to */
+	/* or obtained from */
+
+	if (!bus_check_info->valid.check_info) {
+		IA64_MCA_DEBUG("ia64_mca_log_print: invalid bus_check_info[%d]\n", i);
+		return;                 /* If check info data not valid, skip it */
+	}
+
+	info      = (pal_bus_check_info_t *)&bus_check_info->check_info;
+	req_addr  = bus_check_info->requestor_identifier;
+	resp_addr = bus_check_info->responder_identifier;
+	targ_addr = bus_check_info->target_identifier;
+
 	prfunc("+ BUS Check Info [%d]\n+", i);
-	prfunc(" Status Info: %d", info.bsi);
-	prfunc(" ,Severity: %d", info.sev);
-	prfunc(" ,Transaction Type: %d", info.type);
-	prfunc(" ,Transaction Size: %d", info.size);
-	if (info.cc)
+	prfunc(" Status Info: %d", info->bsi);
+	prfunc(" ,Severity: %d", info->sev);
+	prfunc(" ,Transaction Type: %d", info->type);
+	prfunc(" ,Transaction Size: %d", info->size);
+	if (info->cc)
 		prfunc(" ,Cache-cache-transfer");
-	if (info.ib)
+	if (info->ib)
 		prfunc(" ,Error: Internal");
-	if (info.eb)
+	if (info->eb)
 		prfunc(" ,Error: External");
-	if (info.mc)
+	if (info->mc)
 		prfunc(" ,MC: Corrected");
-	if (info.tv)
+	if (info->tv)
 		prfunc(" ,Target Address: 0x%lx", targ_addr);
-	if (info.rq)
+	if (info->rq)
 		prfunc(" ,Requestor Address: 0x%lx", req_addr);
-	if (info.tv)
+	if (info->tv)
 		prfunc(" ,Responder Address: 0x%lx", resp_addr);
 	prfunc("\n");
 }
 
 /*
+ *  ia64_log_mem_dev_err_info_print
+ *
+ *  Format and log the platform memory device error record section data.
+ *
+ *  Inputs:  mem_dev_err_info * (Ptr to memory device error record section
+ *                               returned by SAL)
+ *           prfunc             (fn ptr of print function to be used for output)
+ *  Outputs: None
+ */
+void
+ia64_log_mem_dev_err_info_print (sal_log_mem_dev_err_info_t *mdei,
+                                 prfunc_t                   prfunc)
+{
+	prfunc("+ Mem Error Detail: ");
+
+	if (mdei->valid.error_status)
+		prfunc(" Error Status: %#lx,", mdei->error_status);
+	if (mdei->valid.physical_addr)
+		prfunc(" Physical Address: %#lx,", mdei->physical_addr);
+	if (mdei->valid.addr_mask)
+		prfunc(" Address Mask: %#lx,", mdei->addr_mask);
+	if (mdei->valid.node)
+		prfunc(" Node: %d,", mdei->node);
+	if (mdei->valid.card)
+		prfunc(" Card: %d,", mdei->card);
+	if (mdei->valid.module)
+		prfunc(" Module: %d,", mdei->module);
+	if (mdei->valid.bank)
+		prfunc(" Bank: %d,", mdei->bank);
+	if (mdei->valid.device)
+		prfunc(" Device: %d,", mdei->device);
+	if (mdei->valid.row)
+		prfunc(" Row: %d,", mdei->row);
+	if (mdei->valid.column)
+		prfunc(" Column: %d,", mdei->column);
+	if (mdei->valid.bit_position)
+		prfunc(" Bit Position: %d,", mdei->bit_position);
+	if (mdei->valid.target_id)
+		prfunc(" ,Target Address: %#lx,", mdei->target_id);
+	if (mdei->valid.requestor_id)
+		prfunc(" ,Requestor Address: %#lx,", mdei->requestor_id);
+	if (mdei->valid.responder_id)
+		prfunc(" ,Responder Address: %#lx,", mdei->responder_id);
+	if (mdei->valid.bus_spec_data)
+		prfunc(" Bus Specific Data: %#lx,", mdei->bus_spec_data);
+	prfunc("\n");
+
+	if (mdei->valid.oem_id) {
+		u8  *p_data = &(mdei->oem_id[0]);
+		int i;
+
+		prfunc(" OEM Memory Controller ID:");
+		for (i = 0; i < 16; i++, p_data++)
+			prfunc(" %02x", *p_data);
+		prfunc("\n");
+	}
+
+	if (mdei->valid.oem_data) {
+		ia64_log_prt_oem_data((int)mdei->header.len,
+				      (int)sizeof(sal_log_mem_dev_err_info_t) - 1,
+				      &(mdei->oem_data[0]), prfunc);
+	}
+}
+
+/*
+ *  ia64_log_sel_dev_err_info_print
+ *
+ *  Format and log the platform SEL device error record section data.
+ *
+ *  Inputs:  sel_dev_err_info * (Ptr to the SEL device error record section
+ *                               returned by SAL)
+ *           prfunc             (fn ptr of print function to be used for output)
+ *  Outputs: None
+ */
+void
+ia64_log_sel_dev_err_info_print (sal_log_sel_dev_err_info_t *sdei,
+                                 prfunc_t                   prfunc)
+{
+	int     i;
+
+	prfunc("+ SEL Device Error Detail: ");
+
+	if (sdei->valid.record_id)
+		prfunc(" Record ID: %#x", sdei->record_id);
+	if (sdei->valid.record_type)
+		prfunc(" Record Type: %#x", sdei->record_type);
+	prfunc(" Time Stamp: ");
+	for (i = 0; i < 4; i++)
+		prfunc("%1d", sdei->timestamp[i]);
+	if (sdei->valid.generator_id)
+		prfunc(" Generator ID: %#x", sdei->generator_id);
+	if (sdei->valid.evm_rev)
+		prfunc(" Message Format Version: %#x", sdei->evm_rev);
+	if (sdei->valid.sensor_type)
+		prfunc(" Sensor Type: %#x", sdei->sensor_type);
+	if (sdei->valid.sensor_num)
+		prfunc(" Sensor Number: %#x", sdei->sensor_num);
+	if (sdei->valid.event_dir)
+		prfunc(" Event Direction Type: %#x", sdei->event_dir);
+	if (sdei->valid.event_data1)
+		prfunc(" Data1: %#x", sdei->event_data1);
+	if (sdei->valid.event_data2)
+		prfunc(" Data2: %#x", sdei->event_data2);
+	if (sdei->valid.event_data3)
+		prfunc(" Data3: %#x", sdei->event_data3);
+	prfunc("\n");
+
+}
+
+/*
+ *  ia64_log_pci_bus_err_info_print
+ *
+ *  Format and log the platform PCI bus error record section data.
+ *
+ *  Inputs:  pci_bus_err_info * (Ptr to the PCI bus error record section
+ *                               returned by SAL)
+ *           prfunc             (fn ptr of print function to be used for output)
+ *  Outputs: None
+ */
+void
+ia64_log_pci_bus_err_info_print (sal_log_pci_bus_err_info_t *pbei,
+                                 prfunc_t                   prfunc)
+{
+	prfunc("+ PCI Bus Error Detail: ");
+
+	if (pbei->valid.err_status)
+		prfunc(" Error Status: %#lx", pbei->err_status);
+	if (pbei->valid.err_type)
+		prfunc(" Error Type: %#x", pbei->err_type);
+	if (pbei->valid.bus_id)
+		prfunc(" Bus ID: %#x", pbei->bus_id);
+	if (pbei->valid.bus_address)
+		prfunc(" Bus Address: %#lx", pbei->bus_address);
+	if (pbei->valid.bus_data)
+		prfunc(" Bus Data: %#lx", pbei->bus_data);
+	if (pbei->valid.bus_cmd)
+		prfunc(" Bus Command: %#lx", pbei->bus_cmd);
+	if (pbei->valid.requestor_id)
+		prfunc(" Requestor ID: %#lx", pbei->requestor_id);
+	if (pbei->valid.responder_id)
+		prfunc(" Responder ID: %#lx", pbei->responder_id);
+	if (pbei->valid.target_id)
+		prfunc(" Target ID: %#lx", pbei->target_id);
+	if (pbei->valid.oem_data)
+		prfunc("\n");
+
+	if (pbei->valid.oem_data) {
+		ia64_log_prt_oem_data((int)pbei->header.len,
+				      (int)sizeof(sal_log_pci_bus_err_info_t) - 1,
+				      &(pbei->oem_data[0]), prfunc);
+	}
+}
+
+/*
+ *  ia64_log_smbios_dev_err_info_print
+ *
+ *  Format and log the platform SMBIOS device error record section data.
+ *
+ *  Inputs:  smbios_dev_err_info * (Ptr to the SMBIOS device error record
+ *                                  section returned by SAL)
+ *           prfunc             (fn ptr of print function to be used for output)
+ *  Outputs: None
+ */
+void
+ia64_log_smbios_dev_err_info_print (sal_log_smbios_dev_err_info_t *sdei,
+                                    prfunc_t                      prfunc)
+{
+	u8      i;
+
+	prfunc("+ SMBIOS Device Error Detail: ");
+
+	if (sdei->valid.event_type)
+		prfunc(" Event Type: %#x", sdei->event_type);
+	if (sdei->valid.time_stamp) {
+		prfunc(" Time Stamp: ");
+		for (i = 0; i < 6; i++)
+			prfunc("%d", sdei->time_stamp[i]);
+	}
+	if ((sdei->valid.data) && (sdei->valid.length)) {
+		prfunc(" Data: ");
+		for (i = 0; i < sdei->length; i++)
+			prfunc(" %02x", sdei->data[i]);
+	}
+	prfunc("\n");
+}
+
+/*
+ *  ia64_log_pci_comp_err_info_print
+ *
+ *  Format and log the platform PCI component error record section data.
+ *
+ *  Inputs:  pci_comp_err_info * (Ptr to the PCI component error record section
+ *                                returned by SAL)
+ *           prfunc             (fn ptr of print function to be used for output)
+ *  Outputs: None
+ */
+void
+ia64_log_pci_comp_err_info_print(sal_log_pci_comp_err_info_t *pcei,
+				 prfunc_t                     prfunc)
+{
+	u32     n_mem_regs, n_io_regs;
+	u64     i, n_pci_data;
+	u64     *p_reg_data;
+	u8      *p_oem_data;
+
+	prfunc("+ PCI Component Error Detail: ");
+
+	if (pcei->valid.err_status)
+		prfunc(" Error Status: %#lx\n", pcei->err_status);
+	if (pcei->valid.comp_info)
+		prfunc(" Component Info: Vendor Id = %#x, Device Id = %#x,"
+		       " Class Code = %#x, Seg/Bus/Dev/Func = %d/%d/%d/%d\n",
+		       pcei->comp_info.vendor_id, pcei->comp_info.device_id,
+		       pcei->comp_info.class_code, pcei->comp_info.seg_num,
+		       pcei->comp_info.bus_num, pcei->comp_info.dev_num,
+		       pcei->comp_info.func_num);
+
+	n_mem_regs = (pcei->valid.num_mem_regs) ? pcei->num_mem_regs : 0;
+	n_io_regs =  (pcei->valid.num_io_regs)  ? pcei->num_io_regs  : 0;
+	p_reg_data = &(pcei->reg_data_pairs[0]);
+	p_oem_data = (u8 *)p_reg_data +
+		(n_mem_regs + n_io_regs) * 2 * sizeof(u64);
+	n_pci_data = p_oem_data - (u8 *)pcei;
+
+	if (n_pci_data > pcei->header.len) {
+		prfunc(" Invalid PCI Component Error Record format: length = %ld, "
+		       " Size PCI Data = %d, Num Mem-Map/IO-Map Regs = %ld/%ld\n",
+		       pcei->header.len, n_pci_data, n_mem_regs, n_io_regs);
+		return;
+	}
+
+	if (n_mem_regs) {
+		prfunc(" Memory Mapped Registers\n Address \tValue\n");
+		for (i = 0; i < pcei->num_mem_regs; i++) {
+			prfunc(" %#lx %#lx\n", p_reg_data[0], p_reg_data[1]);
+			p_reg_data += 2;
+		}
+	}
+	if (n_io_regs) {
+		prfunc(" I/O Mapped Registers\n Address \tValue\n");
+		for (i = 0; i < pcei->num_io_regs; i++) {
+			prfunc(" %#lx %#lx\n", p_reg_data[0], p_reg_data[1]);
+			p_reg_data += 2;
+		}
+	}
+	if (pcei->valid.oem_data) {
+		ia64_log_prt_oem_data((int)pcei->header.len, n_pci_data,
+				      p_oem_data, prfunc);
+		prfunc("\n");
+	}
+}
+
+/*
+ *  ia64_log_plat_specific_err_info_print
+ *
+ *  Format and log the platform specifie error record section data.
+ *
+ *  Inputs:  sel_dev_err_info * (Ptr to the platform specific error record
+ *                               section returned by SAL)
+ *           prfunc             (fn ptr of print function to be used for output)
+ *  Outputs: None
+ */
+void
+ia64_log_plat_specific_err_info_print (sal_log_plat_specific_err_info_t *psei,
+                                       prfunc_t                         prfunc)
+{
+	prfunc("+ Platform Specific Error Detail: ");
+
+	if (psei->valid.err_status)
+		prfunc(" Error Status: %#lx", psei->err_status);
+	if (psei->valid.guid) {
+		prfunc(" GUID: ");
+		ia64_log_prt_guid(&psei->guid, prfunc);
+	}
+	if (psei->valid.oem_data) {
+		ia64_log_prt_oem_data((int)psei->header.len,
+				      (int)sizeof(sal_log_plat_specific_err_info_t) - 1,
+				      &(psei->oem_data[0]), prfunc);
+	}
+	prfunc("\n");
+}
+
+/*
+ *  ia64_log_host_ctlr_err_info_print
+ *
+ *  Format and log the platform host controller error record section data.
+ *
+ *  Inputs:  host_ctlr_err_info * (Ptr to the host controller error record
+ *                                 section returned by SAL)
+ *           prfunc             (fn ptr of print function to be used for output)
+ *  Outputs: None
+ */
+void
+ia64_log_host_ctlr_err_info_print (sal_log_host_ctlr_err_info_t *hcei,
+                                   prfunc_t                     prfunc)
+{
+	prfunc("+ Host Controller Error Detail: ");
+
+	if (hcei->valid.err_status)
+		prfunc(" Error Status: %#lx", hcei->err_status);
+	if (hcei->valid.requestor_id)
+		prfunc(" Requestor ID: %#lx", hcei->requestor_id);
+	if (hcei->valid.responder_id)
+		prfunc(" Responder ID: %#lx", hcei->responder_id);
+	if (hcei->valid.target_id)
+		prfunc(" Target ID: %#lx", hcei->target_id);
+	if (hcei->valid.bus_spec_data)
+		prfunc(" Bus Specific Data: %#lx", hcei->bus_spec_data);
+	if (hcei->valid.oem_data) {
+		ia64_log_prt_oem_data((int)hcei->header.len,
+				      (int)sizeof(sal_log_host_ctlr_err_info_t) - 1,
+				      &(hcei->oem_data[0]), prfunc);
+	}
+	prfunc("\n");
+}
+
+/*
+ *  ia64_log_plat_bus_err_info_print
+ *
+ *  Format and log the platform bus error record section data.
+ *
+ *  Inputs:  plat_bus_err_info * (Ptr to the platform bus error record section
+ *                                returned by SAL)
+ *           prfunc             (fn ptr of print function to be used for output)
+ *  Outputs: None
+ */
+void
+ia64_log_plat_bus_err_info_print (sal_log_plat_bus_err_info_t *pbei,
+                                  prfunc_t                    prfunc)
+{
+	prfunc("+ Platform Bus Error Detail: ");
+
+	if (pbei->valid.err_status)
+		prfunc(" Error Status: %#lx", pbei->err_status);
+	if (pbei->valid.requestor_id)
+		prfunc(" Requestor ID: %#lx", pbei->requestor_id);
+	if (pbei->valid.responder_id)
+		prfunc(" Responder ID: %#lx", pbei->responder_id);
+	if (pbei->valid.target_id)
+		prfunc(" Target ID: %#lx", pbei->target_id);
+	if (pbei->valid.bus_spec_data)
+		prfunc(" Bus Specific Data: %#lx", pbei->bus_spec_data);
+	if (pbei->valid.oem_data) {
+		ia64_log_prt_oem_data((int)pbei->header.len,
+				      (int)sizeof(sal_log_plat_bus_err_info_t) - 1,
+				      &(pbei->oem_data[0]), prfunc);
+	}
+	prfunc("\n");
+}
+
+/*
+ *  ia64_log_proc_dev_err_info_print
+ *
+ *  Display the processor device error record.
+ *
+ *  Inputs:  sal_log_processor_info_t * (Ptr to processor device error record
+ *                                       section body).
+ *           prfunc                     (fn ptr of print function to be used
+ *                                       for output).
+ *  Outputs: None
+ */
+void
+ia64_log_proc_dev_err_info_print (sal_log_processor_info_t  *slpi,
+                                  prfunc_t                  prfunc)
+{
+	size_t  d_len = slpi->header.len - sizeof(sal_log_section_hdr_t);
+	sal_processor_static_info_t *spsi;
+	int                         i;
+	sal_log_mod_error_info_t    *p_data;
+
+	prfunc("+Processor Device Error Info Section\n");
+
+#ifdef MCA_PRT_XTRA_DATA    // for test only @FVL
+	{
+		char    *p_data = (char *)&slpi->valid;
+
+		prfunc("SAL_PROC_DEV_ERR SECTION DATA:  Data buffer = %p, "
+		       "Data size = %ld\n", (void *)p_data, d_len);
+		ia64_log_hexdump(p_data, d_len, prfunc);
+		prfunc("End of SAL_PROC_DEV_ERR SECTION DATA\n");
+	}
+#endif  // MCA_PRT_XTRA_DATA for test only @FVL
+
+	if (slpi->valid.proc_error_map)
+		prfunc(" Processor Error Map: %#lx\n", slpi->proc_error_map);
+
+	if (slpi->valid.proc_state_param)
+		prfunc(" Processor State Param: %#lx\n", slpi->proc_state_parameter);
+
+	if (slpi->valid.proc_cr_lid)
+		prfunc(" Processor LID: %#lx\n", slpi->proc_cr_lid);
+
+	/*
+	 *  Note: March 2001 SAL spec states that if the number of elements in any
+	 *  of  the MOD_ERROR_INFO_STRUCT arrays is zero, the entire array is
+	 *  absent. Also, current implementations only allocate space for number of
+	 *  elements used.  So we walk the data pointer from here on.
+	 */
+	p_data = &slpi->cache_check_info[0];
+
+	/* Print the cache check information if any*/
+	for (i = 0 ; i < slpi->valid.num_cache_check; i++, p_data++)
+		ia64_log_cache_check_info_print(i, p_data, prfunc);
+
+	/* Print the tlb check information if any*/
+	for (i = 0 ; i < slpi->valid.num_tlb_check; i++, p_data++)
+		ia64_log_tlb_check_info_print(i, p_data, prfunc);
+
+	/* Print the bus check information if any*/
+	for (i = 0 ; i < slpi->valid.num_bus_check; i++, p_data++)
+		ia64_log_bus_check_info_print(i, p_data, prfunc);
+
+	/* Print the reg file check information if any*/
+	for (i = 0 ; i < slpi->valid.num_reg_file_check; i++, p_data++)
+		ia64_log_hexdump((u8 *)p_data, sizeof(sal_log_mod_error_info_t),
+				 prfunc);    /* Just hex dump for now */
+
+	/* Print the ms check information if any*/
+	for (i = 0 ; i < slpi->valid.num_ms_check; i++, p_data++)
+		ia64_log_hexdump((u8 *)p_data, sizeof(sal_log_mod_error_info_t),
+				 prfunc);    /* Just hex dump for now */
+
+	/* Print CPUID registers if any*/
+	if (slpi->valid.cpuid_info) {
+		u64     *p = (u64 *)p_data;
+
+		prfunc(" CPUID Regs: %#lx %#lx %#lx %#lx\n", p[0], p[1], p[2], p[3]);
+		p_data++;
+	}
+
+	/* Print processor static info if any */
+	if (slpi->valid.psi_static_struct) {
+		spsi = (sal_processor_static_info_t *)p_data;
+
+		/* Print branch register contents if valid */
+		if (spsi->valid.br)
+			ia64_log_processor_regs_print(spsi->br, 8, "Branch", "br",
+						      prfunc);
+
+		/* Print control register contents if valid */
+		if (spsi->valid.cr)
+			ia64_log_processor_regs_print(spsi->cr, 128, "Control", "cr",
+						      prfunc);
+
+		/* Print application register contents if valid */
+		if (spsi->valid.ar)
+			ia64_log_processor_regs_print(spsi->ar, 128, "Application",
+						      "ar", prfunc);
+
+		/* Print region register contents if valid */
+		if (spsi->valid.rr)
+			ia64_log_processor_regs_print(spsi->rr, 8, "Region", "rr",
+						      prfunc);
+
+		/* Print floating-point register contents if valid */
+		if (spsi->valid.fr)
+			ia64_log_processor_fp_regs_print(spsi->fr, 128, "Floating-point", "fr",
+							 prfunc);
+	}
+}
+
+/*
  * ia64_log_processor_info_print
+ *
  *	Display the processor-specific information logged by PAL as a part
  *	of MCA or INIT or CMC.
- * Inputs	:	lh	(Pointer of the sal log header which specifies the format
- *				 of SAL state info as specified by the SAL spec).
+ *
+ *  Inputs   :  lh      (Pointer of the sal log header which specifies the
+ *                       format of SAL state info as specified by the SAL spec).
+ *              prfunc  (fn ptr of print function to be used for output).
  * Outputs	:	None
  */
 void
-ia64_log_processor_info_print(sal_log_header_t *lh, prfunc_t prfunc)
+ia64_log_processor_info_print(sal_log_record_header_t *lh, prfunc_t prfunc)
 {
-	sal_log_processor_info_t	*slpi;
-	int				i;
+	sal_log_section_hdr_t       *slsh;
+	int                         n_sects;
+	int                         ercd_pos;
 
 	if (!lh)
 		return;
 
-	if (lh->slh_log_type != SAL_SUB_INFO_TYPE_PROCESSOR)
+#ifdef MCA_PRT_XTRA_DATA    // for test only @FVL
+	ia64_log_prt_record_header(lh, prfunc);
+#endif  // MCA_PRT_XTRA_DATA for test only @FVL
+
+	if ((ercd_pos = sizeof(sal_log_record_header_t)) >= lh->len) {
+		IA64_MCA_DEBUG("ia64_mca_log_print: "
+			       "truncated SAL CMC error record. len = %d\n",
+			       lh->len);
 		return;
+	}
 
-	slpi = (sal_log_processor_info_t *)((char *)lh+sizeof(sal_log_header_t));  /* point to proc info */
+	/* Print record header info */
+	ia64_log_rec_header_print(lh, prfunc);
 
-	if (!slpi) {
-		prfunc("No Processor Error Log found\n");
-		return;
+	for (n_sects = 0; (ercd_pos < lh->len); n_sects++, ercd_pos += slsh->len) {
+		/* point to next section header */
+		slsh = (sal_log_section_hdr_t *)((char *)lh + ercd_pos);
+
+#ifdef MCA_PRT_XTRA_DATA    // for test only @FVL
+		ia64_log_prt_section_header(slsh, prfunc);
+#endif  // MCA_PRT_XTRA_DATA for test only @FVL
+
+		if (verify_guid((void *)&slsh->guid, (void *)&(SAL_PROC_DEV_ERR_SECT_GUID))) {
+			IA64_MCA_DEBUG("ia64_mca_log_print: unsupported record section\n");
+			continue;
+		}
+
+		/*
+		 *  Now process processor device error record section
+		 */
+		ia64_log_proc_dev_err_info_print((sal_log_processor_info_t *)slsh,
+						 printk);
 	}
 
-	/* Print branch register contents if valid */
-	if (slpi->slpi_valid.slpi_br)
-		ia64_log_processor_regs_print(slpi->slpi_br, 8, "Branch", "br", prfunc);
+	IA64_MCA_DEBUG("ia64_mca_log_print: "
+		       "found %d sections in SAL CMC error record. len = %d\n",
+		       n_sects, lh->len);
+	if (!n_sects) {
+		prfunc("No Processor Device Error Info Section found\n");
+		return;
+	}
+}
 
-	/* Print control register contents if valid */
-	if (slpi->slpi_valid.slpi_cr)
-		ia64_log_processor_regs_print(slpi->slpi_cr, 128, "Control", "cr", prfunc);
+/*
+ *  ia64_log_platform_info_print
+ *
+ *  Format and Log the SAL Platform Error Record.
+ *
+ *  Inputs  :   lh      (Pointer to the sal error record header with format
+ *                       specified by the SAL spec).
+ *              prfunc  (fn ptr of log output function to use)
+ *  Outputs :   None
+ */
+void
+ia64_log_platform_info_print (sal_log_record_header_t *lh, prfunc_t prfunc)
+{
+	sal_log_section_hdr_t       *slsh;
+	int                         n_sects;
+	int                         ercd_pos;
 
-	/* Print application register contents if valid */
-	if (slpi->slpi_valid.slpi_ar)
-		ia64_log_processor_regs_print(slpi->slpi_br, 128, "Application", "ar", prfunc);
+	if (!lh)
+		return;
 
-	/* Print region register contents if valid */
-	if (slpi->slpi_valid.slpi_rr)
-		ia64_log_processor_regs_print(slpi->slpi_rr, 8, "Region", "rr", prfunc);
+#ifdef MCA_PRT_XTRA_DATA    // for test only @FVL
+	ia64_log_prt_record_header(lh, prfunc);
+#endif  // MCA_PRT_XTRA_DATA for test only @FVL
+
+	if ((ercd_pos = sizeof(sal_log_record_header_t)) >= lh->len) {
+		IA64_MCA_DEBUG("ia64_mca_log_print: "
+			       "truncated SAL error record. len = %d\n",
+			       lh->len);
+		return;
+	}
 
-	/* Print floating-point register contents if valid */
-	if (slpi->slpi_valid.slpi_fr)
-		ia64_log_processor_regs_print(slpi->slpi_fr, 128, "Floating-point", "fr",
-					      prfunc);
+	/* Print record header info */
+	ia64_log_rec_header_print(lh, prfunc);
 
-	/* Print the cache check information if any*/
-	for (i = 0 ; i < MAX_CACHE_ERRORS; i++)
-		ia64_log_cache_check_info_print(i,
-					slpi->slpi_cache_check_info[i].slpi_cache_check,
-					slpi->slpi_cache_check_info[i].slpi_target_address,
-						prfunc);
-	/* Print the tlb check information if any*/
-	for (i = 0 ; i < MAX_TLB_ERRORS; i++)
-		ia64_log_tlb_check_info_print(i,slpi->slpi_tlb_check_info[i], prfunc);
+	for (n_sects = 0; (ercd_pos < lh->len); n_sects++, ercd_pos += slsh->len) {
+		/* point to next section header */
+		slsh = (sal_log_section_hdr_t *)((char *)lh + ercd_pos);
+
+#ifdef MCA_PRT_XTRA_DATA    // for test only @FVL
+		ia64_log_prt_section_header(slsh, prfunc);
+
+		if (efi_guidcmp(slsh->guid, SAL_PROC_DEV_ERR_SECT_GUID) != 0) {
+			size_t  d_len = slsh->len - sizeof(sal_log_section_hdr_t);
+			char    *p_data = (char *)&((sal_log_mem_dev_err_info_t *)slsh)->valid;
+
+			prfunc("Start of Platform Err Data Section:  Data buffer = %p, "
+			       "Data size = %ld\n", (void *)p_data, d_len);
+			ia64_log_hexdump(p_data, d_len, prfunc);
+			prfunc("End of Platform Err Data Section\n");
+		}
+#endif  // MCA_PRT_XTRA_DATA for test only @FVL
 
-	/* Print the bus check information if any*/
-	for (i = 0 ; i < MAX_BUS_ERRORS; i++)
-		ia64_log_bus_check_info_print(i,
-					slpi->slpi_bus_check_info[i].slpi_bus_check,
-					slpi->slpi_bus_check_info[i].slpi_requestor_addr,
-					slpi->slpi_bus_check_info[i].slpi_responder_addr,
-					slpi->slpi_bus_check_info[i].slpi_target_addr,
-					      prfunc);
+		/*
+		 *  Now process CPE error record section
+		 */
+		if (efi_guidcmp(slsh->guid, SAL_PROC_DEV_ERR_SECT_GUID) = 0) {
+			ia64_log_proc_dev_err_info_print((sal_log_processor_info_t *)slsh,
+							 prfunc);
+		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_MEM_DEV_ERR_SECT_GUID) = 0) {
+			prfunc("+Platform Memory Device Error Info Section\n");
+			ia64_log_mem_dev_err_info_print((sal_log_mem_dev_err_info_t *)slsh,
+							prfunc);
+		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_SEL_DEV_ERR_SECT_GUID) = 0) {
+			prfunc("+Platform SEL Device Error Info Section\n");
+			ia64_log_sel_dev_err_info_print((sal_log_sel_dev_err_info_t *)slsh,
+							prfunc);
+		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_PCI_BUS_ERR_SECT_GUID) = 0) {
+			prfunc("+Platform PCI Bus Error Info Section\n");
+			ia64_log_pci_bus_err_info_print((sal_log_pci_bus_err_info_t *)slsh,
+							prfunc);
+		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID) = 0) {
+			prfunc("+Platform SMBIOS Device Error Info Section\n");
+			ia64_log_smbios_dev_err_info_print((sal_log_smbios_dev_err_info_t *)slsh,
+							   prfunc);
+		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_PCI_COMP_ERR_SECT_GUID) = 0) {
+			prfunc("+Platform PCI Component Error Info Section\n");
+			ia64_log_pci_comp_err_info_print((sal_log_pci_comp_err_info_t *)slsh,
+							 prfunc);
+		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_SPECIFIC_ERR_SECT_GUID) = 0) {
+			prfunc("+Platform Specific Error Info Section\n");
+			ia64_log_plat_specific_err_info_print((sal_log_plat_specific_err_info_t *)
+							      slsh,
+							      prfunc);
+		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_HOST_CTLR_ERR_SECT_GUID) = 0) {
+			prfunc("+Platform Host Controller Error Info Section\n");
+			ia64_log_host_ctlr_err_info_print((sal_log_host_ctlr_err_info_t *)slsh,
+							  prfunc);
+		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_BUS_ERR_SECT_GUID) = 0) {
+			prfunc("+Platform Bus Error Info Section\n");
+			ia64_log_plat_bus_err_info_print((sal_log_plat_bus_err_info_t *)slsh,
+							 prfunc);
+		} else {
+			IA64_MCA_DEBUG("ia64_mca_log_print: unsupported record section\n");
+			continue;
+		}
+	}
 
+	IA64_MCA_DEBUG("ia64_mca_log_print: found %d sections in SAL error record. len = %d\n",
+		       n_sects, lh->len);
+	if (!n_sects) {
+		prfunc("No Platform Error Info Sections found\n");
+		return;
+	}
 }
 
 /*
  * ia64_log_print
- *	Display the contents of the OS error log information
- * Inputs	:	info_type	(SAL_INFO_TYPE_{MCA,INIT,CMC})
- *			sub_info_type	(SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM})
+ *
+ *  Displays the contents of the OS error log information
+ *
+ *  Inputs   :  info_type   (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE})
+ *              prfunc      (fn ptr of log output function to use)
  * Outputs	:	None
  */
 void
-ia64_log_print(int sal_info_type, int sal_sub_info_type, prfunc_t prfunc)
+ia64_log_print(int sal_info_type, prfunc_t prfunc)
 {
-	char	*info_type, *sub_info_type;
-
 	switch(sal_info_type) {
-	case SAL_INFO_TYPE_MCA:
-		info_type = "MCA";
+	      case SAL_INFO_TYPE_MCA:
+		prfunc("+BEGIN HARDWARE ERROR STATE AT MCA\n");
+		ia64_log_platform_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc);
+		prfunc("+END HARDWARE ERROR STATE AT MCA\n");
 		break;
-	case SAL_INFO_TYPE_INIT:
-		info_type = "INIT";
+	      case SAL_INFO_TYPE_INIT:
+		prfunc("+MCA INIT ERROR LOG (UNIMPLEMENTED)\n");
 		break;
-	case SAL_INFO_TYPE_CMC:
-		info_type = "CMC";
+	      case SAL_INFO_TYPE_CMC:
+		prfunc("+BEGIN HARDWARE ERROR STATE AT CMC\n");
+		ia64_log_processor_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc);
+		prfunc("+END HARDWARE ERROR STATE AT CMC\n");
 		break;
-	default:
-		info_type = "UNKNOWN";
+	      case SAL_INFO_TYPE_CPE:
+		prfunc("+BEGIN HARDWARE ERROR STATE AT CPE\n");
+		ia64_log_platform_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc);
+		prfunc("+END HARDWARE ERROR STATE AT CPE\n");
 		break;
-	}
-
-	switch(sal_sub_info_type) {
-	case SAL_SUB_INFO_TYPE_PROCESSOR:
-		sub_info_type = "PROCESSOR";
-		break;
-	case SAL_SUB_INFO_TYPE_PLATFORM:
-		sub_info_type = "PLATFORM";
-		break;
-	default:
-		sub_info_type = "UNKNOWN";
+	      default:
+		prfunc("+MCA UNKNOWN ERROR LOG (UNIMPLEMENTED)\n");
 		break;
 	}
-
-	prfunc("+BEGIN HARDWARE ERROR STATE [%s %s]\n", info_type, sub_info_type);
-	if (sal_sub_info_type = SAL_SUB_INFO_TYPE_PROCESSOR)
-		ia64_log_processor_info_print(
-				      IA64_LOG_CURR_BUFFER(sal_info_type, sal_sub_info_type),
-				      prfunc);
-	else
-		log_print_platform(IA64_LOG_CURR_BUFFER(sal_info_type, sal_sub_info_type),prfunc);
-	prfunc("+END HARDWARE ERROR STATE [%s %s]\n", info_type, sub_info_type);
 }
diff -urN linux-2.4.13/arch/ia64/kernel/mca_asm.S linux-2.4.13-lia/arch/ia64/kernel/mca_asm.S
--- linux-2.4.13/arch/ia64/kernel/mca_asm.S	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/mca_asm.S	Thu Oct  4 00:21:39 2001
@@ -9,6 +9,7 @@
 //
 #include <linux/config.h>
 
+#include <asm/asmmacro.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
 #include <asm/mca_asm.h>
@@ -23,7 +24,7 @@
 #include "minstate.h"
 
 /*
- *	SAL_TO_OS_MCA_HANDOFF_STATE
+ *  SAL_TO_OS_MCA_HANDOFF_STATE (SAL 3.0 spec)
  *		1. GR1 = OS GP
  *		2. GR8 = PAL_PROC physical address
  *		3. GR9 = SAL_PROC physical address
@@ -33,6 +34,7 @@
  */
 #define SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(_tmp)		\
 	movl	_tmp=ia64_sal_to_os_handoff_state;;	\
+	DATA_VA_TO_PA(_tmp);;				\
 	st8	[_tmp]=r1,0x08;;			\
 	st8	[_tmp]=r8,0x08;;			\
 	st8	[_tmp]=r9,0x08;;			\
@@ -41,47 +43,29 @@
 	st8	[_tmp]=r12,0x08;;
 
 /*
- *	OS_MCA_TO_SAL_HANDOFF_STATE
- *		1. GR8 = OS_MCA status
- *		2. GR9 = SAL GP (physical)
- *		3. GR22 = New min state save area pointer
+ *  OS_MCA_TO_SAL_HANDOFF_STATE (SAL 3.0 spec)
+ *      1. GR8 = OS_MCA return status
+ *	2. GR9 = SAL GP (physical)
+ *      3. GR10 = 0/1 returning same/new context
+ *      4. GR22 = New min state save area pointer
+ *      returns ptr to SAL rtn save loc in _tmp
  */
-#define OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(_tmp)	\
-	movl	_tmp=ia64_os_to_sal_handoff_state;;	\
-	DATA_VA_TO_PA(_tmp);;				\
-	ld8	r8=[_tmp],0x08;;			\
-	ld8	r9=[_tmp],0x08;;			\
-	ld8	r22=[_tmp],0x08;;
-
-/*
- *	BRANCH
- *		Jump to the instruction referenced by
- *	"to_label".
- *		Branch is taken only if the predicate
- *	register "p" is true.
- *		"ip" is the address of the instruction
- *	located at "from_label".
- *		"temp" is a scratch register like r2
- *		"adjust" needed for HP compiler.
- *	A screwup somewhere with constant arithmetic.
- */
-#define BRANCH(to_label, temp, p, adjust)		\
-100:	(p)	mov		temp=ip;		\
-		;;					\
-	(p)	adds		temp=to_label-100b,temp;\
-		;;					\
-	(p)	adds		temp­just,temp;	\
-		;;					\
-	(p)	mov		b1=temp	;		\
-	(p)	br		b1
+#define OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(_tmp)				\
+	movl	_tmp=ia64_os_to_sal_handoff_state;;				\
+	DATA_VA_TO_PA(_tmp);;							\
+	ld8	r8=[_tmp],0x08;;						\
+	ld8	r9=[_tmp],0x08;;						\
+	ld8     r10=[_tmp],0x08;;						\
+	ld8     r22=[_tmp],0x08;;						\
+	movl    _tmp=ia64_sal_to_os_handoff_state;;				\
+	DATA_VA_TO_PA(_tmp);;							\
+	add     _tmp=0x28,_tmp;;            // point to SAL rtn save location
 
 	.global ia64_os_mca_dispatch
 	.global ia64_os_mca_dispatch_end
 	.global ia64_sal_to_os_handoff_state
 	.global	ia64_os_to_sal_handoff_state
-	.global	ia64_os_mca_ucmc_handler
 	.global	ia64_mca_proc_state_dump
-	.global ia64_mca_proc_state_restore
 	.global	ia64_mca_stack
 	.global	ia64_mca_stackframe
 	.global	ia64_mca_bspstore
@@ -100,7 +84,7 @@
 #endif	/* #if defined(MCA_TEST) */
 
 	// Save the SAL to OS MCA handoff state as defined
-	// by SAL SPEC 2.5
+	// by SAL SPEC 3.0
 	// NOTE : The order in which the state gets saved
 	//	  is dependent on the way the C-structure
 	//	  for ia64_mca_sal_to_os_state_t has been
@@ -110,15 +94,20 @@
 	// LOG PROCESSOR STATE INFO FROM HERE ON..
 	;;
 begin_os_mca_dump:
-	BRANCH(ia64_os_mca_proc_state_dump, r2, p0, 0x0)
-	;;
+	br	ia64_os_mca_proc_state_dump;;
+
 ia64_os_mca_done_dump:
 
 	// Setup new stack frame for OS_MCA handling
-	movl        r2=ia64_mca_bspstore		// local bspstore area location in r2
-	movl        r3=ia64_mca_stackframe		// save stack frame to memory in r3
+	movl    r2=ia64_mca_bspstore;;      // local bspstore area location in r2
+	DATA_VA_TO_PA(r2);;
+	movl    r3=ia64_mca_stackframe;;    // save stack frame to memory in r3
+	DATA_VA_TO_PA(r3);;
 	rse_switch_context(r6,r3,r2);;                  // RSC management in this new context
 	movl        r12=ia64_mca_stack;;
+	mov     r2=8*1024;;                 // stack size must be same as c array
+	add     r12=r2,r12;;                // stack base @ bottom of array
+	DATA_VA_TO_PA(r12);;
 
 	// Enter virtual mode from physical mode
 	VIRTUAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_begin, r4)
@@ -127,7 +116,7 @@
 	// call our handler
 	movl		r2=ia64_mca_ucmc_handler;;
 	mov		b6=r2;;
-	br.call.sptk.few	b0¶
+	br.call.sptk.many    b0¶;;
 .ret0:
 	// Revert back to physical mode before going back to SAL
 	PHYSICAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_end, r4)
@@ -135,9 +124,9 @@
 
 #if defined(MCA_TEST)
 	// Pretend that we are in interrupt context
-	mov		r2=psr
-	dep		r2=0, r2, PSR_IC, 2;
-	mov		psr.l = r2
+	mov	r2=psr;;
+	dep	r2=0, r2, PSR_IC, 2;;
+	mov	psr.l = r2;;
 #endif	/* #if defined(MCA_TEST) */
 
 	// restore the original stack frame here
@@ -152,15 +141,14 @@
 	mov		r8=gp
 	;;
 begin_os_mca_restore:
-	BRANCH(ia64_os_mca_proc_state_restore, r2, p0, 0x0)
-	;;
+	br	ia64_os_mca_proc_state_restore;;
 
 ia64_os_mca_done_restore:
 	;;
 	// branch back to SALE_CHECK
 	OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(r2)
 	ld8		r3=[r2];;
-	mov		b0=r3                       // SAL_CHECK return address
+	mov		b0=r3;;			      // SAL_CHECK return address
 	br		b0
 	;;
 ia64_os_mca_dispatch_end:
@@ -178,8 +166,10 @@
 //--
 
 ia64_os_mca_proc_state_dump:
-// Get and save GR0-31 from Proc. Min. State Save Area to SAL PSI
+// Save bank 1 GRs 16-31 which will be used by c-language code when we switch
+//  to virtual addressing mode.
 	movl		r2=ia64_mca_proc_state_dump;;           // Os state dump area
+        DATA_VA_TO_PA(r2)                   // convert to to physical address
 
 // save ar.NaT
 	mov		r5=ar.unat                  // ar.unat
@@ -250,16 +240,16 @@
 // if PSR.ic=0, reading interruption registers causes an illegal operation fault
 	mov		r3=psr;;
 	tbit.nz.unc	p6,p0=r3,PSR_IC;;           // PSI Valid Log bit pos. test
-(p6)    st8		[r2]=r0,9*8+160             // increment by 168 byte inc.
+(p6)    st8     [r2]=r0,9*8+160             // increment by 232 byte inc.
 begin_skip_intr_regs:
-	BRANCH(SkipIntrRegs,  r9, p6, 0x0)
-	;;
+(p6)	br		SkipIntrRegs;;
+
 	add		r4=8,r2                  // duplicate r2 in r4
 	add		r6=2*8,r2                // duplicate r2 in r6
 
 	mov		r3=cr16                     // cr.ipsr
 	mov		r5=cr17                     // cr.isr
-	mov		r7=r0;;                     // cr.ida => cr18
+        mov     r7=r0;;                     // cr.ida => cr18 (reserved)
 	st8		[r2]=r3,3*8
 	st8		[r4]=r5,3*8
 	st8		[r6]=r7,3*8;;
@@ -394,8 +384,7 @@
 	br.cloop.sptk.few	cStRR
 	;;
 end_os_mca_dump:
-	BRANCH(ia64_os_mca_done_dump, r2, p0, -0x10)
-	;;
+	br	ia64_os_mca_done_dump;;
 
 //EndStub//////////////////////////////////////////////////////////////////////
 
@@ -484,11 +473,10 @@
 // if PSR.ic=1, reading interruption registers causes an illegal operation fault
 	mov		r3=psr;;
 	tbit.nz.unc	p6,p0=r3,PSR_IC;;           // PSI Valid Log bit pos. test
-(p6)    st8		[r2]=r0,9*8+160             // increment by 160 byte inc.
+(p6)    st8     [r2]=r0,9*8+160             // increment by 232 byte inc.
 
 begin_rskip_intr_regs:
-	BRANCH(rSkipIntrRegs, r9, p6, 0x0)
-	;;
+(p6)	br		rSkipIntrRegs;;
 
 	add		r4=8,r2                  // duplicate r2 in r4
 	add		r6=2*8,r2;;              // duplicate r2 in r4
@@ -498,7 +486,7 @@
 	ld8		r7=[r6],3*8;;
 	mov		cr16=r3                     // cr.ipsr
 	mov		cr17=r5                     // cr.isr is read only
-//      mov		cr18=r7;;                   // cr.ida
+//      mov     cr18=r7;;                   // cr.ida (reserved - don't restore)
 
 	ld8		r3=[r2],3*8
 	ld8		r5=[r4],3*8
@@ -629,8 +617,8 @@
 	mov		ar.lc=r5
 	;;
 end_os_mca_restore:
-	BRANCH(ia64_os_mca_done_restore, r2, p0, -0x20)
-	;;
+	br	ia64_os_mca_done_restore;;
+
 //EndStub//////////////////////////////////////////////////////////////////////
 
 // ok, the issue here is that we need to save state information so
@@ -660,12 +648,7 @@
 //		6. GR12 = Return address to location within SAL_INIT procedure
 
 
-	.text
-	.align 16
-.global ia64_monarch_init_handler
-.proc ia64_monarch_init_handler
-ia64_monarch_init_handler:
-
+GLOBAL_ENTRY(ia64_monarch_init_handler)
 #if defined(CONFIG_SMP) && defined(SAL_MPINIT_WORKAROUND)
 	//
 	// work around SAL bug that sends all processors to monarch entry
@@ -741,13 +724,12 @@
 	adds out0\x16,sp				// out0 = pointer to pt_regs
 	;;
 
-	br.call.sptk.few rp=ia64_init_handler
+	br.call.sptk.many rp=ia64_init_handler
 .ret1:
 
 return_from_init:
 	br.sptk return_from_init
-
-	.endp
+END(ia64_monarch_init_handler)
 
 //
 // SAL to OS entry point for INIT on the slave processor
@@ -755,14 +737,6 @@
 // as a part of ia64_mca_init.
 //
 
-	.text
-	.align 16
-.global ia64_slave_init_handler
-.proc ia64_slave_init_handler
-ia64_slave_init_handler:
-
-
-slave_init_spin_me:
-	br.sptk slave_init_spin_me
-	;;
-	.endp
+GLOBAL_ENTRY(ia64_slave_init_handler)
+1:	br.sptk 1b
+END(ia64_slave_init_handler)
diff -urN linux-2.4.13/arch/ia64/kernel/pal.S linux-2.4.13-lia/arch/ia64/kernel/pal.S
--- linux-2.4.13/arch/ia64/kernel/pal.S	Thu Apr  5 12:51:47 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/pal.S	Thu Oct  4 00:21:39 2001
@@ -4,8 +4,9 @@
  *
  * 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>
+ * Copyright (C) 1999-2001 Hewlett-Packard Co
+ *	David Mosberger <davidm@hpl.hp.com>
+ *	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
@@ -31,7 +32,7 @@
 	movl r2=pal_entry_point
 	;;
 	st8 [r2]=in0
-	br.ret.sptk.few rp
+	br.ret.sptk.many rp
 END(ia64_pal_handler_init)
 
 /*
@@ -41,7 +42,7 @@
  */
 GLOBAL_ENTRY(ia64_pal_default_handler)
 	mov r8=-1
-	br.cond.sptk.few rp
+	br.cond.sptk.many rp
 END(ia64_pal_default_handler)
 
 /*
@@ -79,13 +80,13 @@
 	;;
 (p6)	srlz.i
 	mov rp = r8
-	br.cond.sptk.few b7
+	br.cond.sptk.many b7
 1:	mov psr.l = loc3
 	mov ar.pfs = loc1
 	mov rp = loc0
 	;;
 	srlz.d				// seralize restoration of psr.l
-	br.ret.sptk.few	b0
+	br.ret.sptk.many b0
 END(ia64_pal_call_static)
 
 /*
@@ -120,7 +121,7 @@
 	mov rp = loc0
 	;;
 	srlz.d				// serialize restoration of psr.l
-	br.ret.sptk.few	b0
+	br.ret.sptk.many b0
 END(ia64_pal_call_stacked)
 
 /*
@@ -173,13 +174,13 @@
 	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
+	br.call.sptk.many rp=ia64_switch_mode
 .ret1:	mov rp = r8			// install return address (physical)
-	br.cond.sptk.few b7
+	br.cond.sptk.many b7
 1:
 	mov ar.rsc=0			// 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
+	br.call.sptk.many rp=ia64_switch_mode // return to virtual mode
 .ret2:
 	mov psr.l = loc3		// restore init PSR
 
@@ -188,7 +189,7 @@
 	;;
 	mov ar.rsc=loc4			// restore RSE configuration
 	srlz.d				// seralize restoration of psr.l
-	br.ret.sptk.few	b0
+	br.ret.sptk.many b0
 END(ia64_pal_call_phys_static)
 
 /*
@@ -227,13 +228,13 @@
 	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
+	br.call.sptk.many rp=ia64_switch_mode
 .ret6:
 	br.call.sptk.many rp·		// now make the call
 .ret7:
 	mov ar.rsc=0			// 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
+	br.call.sptk.many rp=ia64_switch_mode	// return to virtual mode
 
 .ret8:	mov psr.l  = loc3		// restore init PSR
 	mov ar.pfs = loc1
@@ -241,6 +242,6 @@
 	;;
 	mov ar.rsc=loc4			// restore RSE configuration
 	srlz.d				// seralize restoration of psr.l
-	br.ret.sptk.few	b0
+	br.ret.sptk.many b0
 END(ia64_pal_call_phys_stacked)
 
diff -urN linux-2.4.13/arch/ia64/kernel/palinfo.c linux-2.4.13-lia/arch/ia64/kernel/palinfo.c
--- linux-2.4.13/arch/ia64/kernel/palinfo.c	Thu Apr  5 12:51:47 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/palinfo.c	Wed Oct 24 18:14:08 2001
@@ -6,12 +6,13 @@
  * 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>
+ * Copyright (C) 2000-2001 Hewlett-Packard Co
+ *	Stephane Eranian <eranian@hpl.hp.com>
  *
  * 05/26/2000	S.Eranian	initial release
  * 08/21/2000	S.Eranian	updated to July 2000 PAL specs
  * 02/05/2001   S.Eranian	fixed module support
+ * 10/23/2001	S.Eranian	updated pal_perf_mon_info bug fixes
  */
 #include <linux/config.h>
 #include <linux/types.h>
@@ -32,8 +33,9 @@
 
 MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
 MODULE_DESCRIPTION("/proc interface to IA-64 PAL");
+MODULE_LICENSE("GPL");
 
-#define PALINFO_VERSION "0.4"
+#define PALINFO_VERSION "0.5"
 
 #ifdef CONFIG_SMP
 #define cpu_is_online(i) (cpu_online_map & (1UL << i))
@@ -606,15 +608,6 @@
 
 	if (ia64_pal_perf_mon_info(pm_buffer, &pm_info) != 0) return 0;
 
-#ifdef IA64_PAL_PERF_MON_INFO_BUG
-	/*
-	 * This bug has been fixed in PAL 2.2.9 and higher
-	 */
-	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" \
@@ -636,6 +629,14 @@
 	p = bitregister_process(p, pm_buffer+8, 256);
 
 	p += sprintf(p, "\nRetired bundles count capable : ");
+
+#ifdef CONFIG_ITANIUM
+	/*
+	 * PAL_PERF_MON_INFO reports that only PMC4 can be used to count CPU_CYCLES
+	 * which is wrong, both PMC4 and PMD5 support it.
+	 */
+	if (pm_buffer[12] = 0x10) pm_buffer[12]=0x30;
+#endif
 
 	p = bitregister_process(p, pm_buffer+12, 256);
 
diff -urN linux-2.4.13/arch/ia64/kernel/pci.c linux-2.4.13-lia/arch/ia64/kernel/pci.c
--- linux-2.4.13/arch/ia64/kernel/pci.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/pci.c	Thu Oct  4 00:21:39 2001
@@ -38,6 +38,10 @@
 #define DBG(x...)
 #endif
 
+#ifdef CONFIG_IA64_MCA
+extern void ia64_mca_check_errors( void );
+#endif
+
 /*
  * This interrupt-safe spinlock protects all accesses to PCI
  * configuration space.
@@ -122,6 +126,10 @@
 #	define PCI_BUSES_TO_SCAN 255
 	int i;
 
+#ifdef CONFIG_IA64_MCA
+	ia64_mca_check_errors();    /* For post-failure MCA error logging */
+#endif
+
 	platform_pci_fixup(0);	/* phase 0 initialization (before PCI bus has been scanned) */
 
 	printk("PCI: Probing PCI hardware\n");
@@ -194,4 +202,40 @@
 pcibios_setup (char *str)
 {
 	return NULL;
+}
+
+int
+pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
+		     enum pci_mmap_state mmap_state, int write_combine)
+{
+	/*
+	 * I/O space cannot be accessed via normal processor loads and stores on this
+	 * platform.
+	 */
+	if (mmap_state = pci_mmap_io)
+		/*
+		 * XXX we could relax this for I/O spaces for which ACPI indicates that
+		 * the space is 1-to-1 mapped.  But at the moment, we don't support
+		 * multiple PCI address spaces and the legacy I/O space is not 1-to-1
+		 * mapped, so this is moot.
+		 */
+		return -EINVAL;
+
+	/*
+	 * Leave vm_pgoff as-is, the PCI space address is the physical address on this
+	 * platform.
+	 */
+	vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO);
+
+	if (write_combine)
+		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+	else
+		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	if (remap_page_range(vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
+			     vma->vm_end - vma->vm_start,
+			     vma->vm_page_prot))
+		return -EAGAIN;
+
+	return 0;
 }
diff -urN linux-2.4.13/arch/ia64/kernel/perfmon.c linux-2.4.13-lia/arch/ia64/kernel/perfmon.c
--- linux-2.4.13/arch/ia64/kernel/perfmon.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/perfmon.c	Thu Oct  4 00:21:39 2001
@@ -38,7 +38,7 @@
 
 #ifdef CONFIG_PERFMON
 
-#define PFM_VERSION		"0.2"
+#define PFM_VERSION		"0.3"
 #define PFM_SMPL_HDR_VERSION	1
 
 #define PMU_FIRST_COUNTER	4	/* first generic counter */
@@ -52,6 +52,7 @@
 #define PFM_DISABLE		0xa6	/* freeze only */
 #define PFM_RESTART		0xcf
 #define PFM_CREATE_CONTEXT	0xa7
+#define PFM_DESTROY_CONTEXT	0xa8
 /*
  * Those 2 are just meant for debugging. I considered using sysctl() for
  * that but it is a little bit too pervasive. This solution is at least
@@ -60,6 +61,8 @@
 #define PFM_DEBUG_ON		0xe0
 #define PFM_DEBUG_OFF		0xe1
 
+#define PFM_DEBUG_BASE		PFM_DEBUG_ON
+
 
 /*
  * perfmon API flags
@@ -68,7 +71,8 @@
 #define PFM_FL_INHERIT_ONCE	 0x01	/* clone pfm_context only once across fork() */
 #define PFM_FL_INHERIT_ALL	 0x02	/* always clone pfm_context across fork() */
 #define PFM_FL_SMPL_OVFL_NOBLOCK 0x04	/* do not block on sampling buffer overflow */
-#define PFM_FL_SYSTEMWIDE	 0x08	/* create a systemwide context */
+#define PFM_FL_SYSTEM_WIDE	 0x08	/* create a system wide context */
+#define PFM_FL_EXCL_INTR	 0x10	/* exclude interrupt from system wide monitoring */
 
 /*
  * PMC API flags
@@ -87,7 +91,7 @@
 #endif
 
 #define PMC_IS_IMPL(i)		(i < pmu_conf.num_pmcs && pmu_conf.impl_regs[i>>6] & (1<< (i&~(64-1))))
-#define PMD_IS_IMPL(i)	(i < pmu_conf.num_pmds &&  pmu_conf.impl_regs[4+(i>>6)] & (1<< (i&~(64-1))))
+#define PMD_IS_IMPL(i)		(i < pmu_conf.num_pmds &&  pmu_conf.impl_regs[4+(i>>6)] & (1<< (i&~(64-1))))
 #define PMD_IS_COUNTER(i)	(i>=PMU_FIRST_COUNTER && i < (PMU_FIRST_COUNTER+pmu_conf.max_counters))
 #define PMC_IS_COUNTER(i)	(i>=PMU_FIRST_COUNTER && i < (PMU_FIRST_COUNTER+pmu_conf.max_counters))
 
@@ -197,7 +201,8 @@
 	unsigned int noblock:1;	/* block/don't block on overflow with notification */
 	unsigned int system:1;	/* do system wide monitoring */
 	unsigned int frozen:1;	/* pmu must be kept frozen on ctxsw in */
-	unsigned int reserved:27;
+	unsigned int exclintr:1;/* exlcude interrupts from system wide monitoring */
+	unsigned int reserved:26;
 } pfm_context_flags_t;
 
 typedef struct pfm_context {
@@ -207,26 +212,33 @@
 	unsigned long		ctx_iear_counter;	/* which PMD holds I-EAR */
 	unsigned long		ctx_btb_counter;	/* which PMD holds BTB */
 
-	pid_t			ctx_notify_pid;	/* who to notify on overflow */
-	int			ctx_notify_sig;	/* XXX: SIGPROF or other */
-	pfm_context_flags_t	ctx_flags;	/* block/noblock */
-	pid_t			ctx_creator;	/* pid of creator (debug) */
-	unsigned long		ctx_ovfl_regs;	/* which registers just overflowed (notification) */
-	unsigned long		ctx_smpl_regs;	/* which registers to record on overflow */
+	spinlock_t		ctx_notify_lock;
+	pfm_context_flags_t	ctx_flags;		/* block/noblock */
+	int			ctx_notify_sig;		/* XXX: SIGPROF or other */
+	struct task_struct	*ctx_notify_task;	/* who to notify on overflow */
+	struct task_struct	*ctx_creator;		/* pid of creator (debug) */
+
+	unsigned long		ctx_ovfl_regs;		/* which registers just overflowed (notification) */
+	unsigned long		ctx_smpl_regs;		/* which registers to record on overflow */
+
+	struct semaphore	ctx_restart_sem; 	/* use for blocking notification mode */
 
-	struct semaphore	ctx_restart_sem; /* use for blocking notification mode */
+	unsigned long		ctx_used_pmds[4]; 	/* bitmask of used PMD (speedup ctxsw) */
+	unsigned long		ctx_used_pmcs[4]; 	/* bitmask of used PMC (speedup ctxsw) */
 
 	pfm_counter_t		ctx_pmds[IA64_NUM_PMD_COUNTERS]; /* XXX: size should be dynamic */
+
 } pfm_context_t;
 
+#define CTX_USED_PMD(ctx,n) (ctx)->ctx_used_pmds[(n)>>6] |= 1<< ((n) % 64)
+#define CTX_USED_PMC(ctx,n) (ctx)->ctx_used_pmcs[(n)>>6] |= 1<< ((n) % 64)
+
 #define ctx_fl_inherit	ctx_flags.inherit
 #define ctx_fl_noblock	ctx_flags.noblock
 #define ctx_fl_system	ctx_flags.system
 #define ctx_fl_frozen	ctx_flags.frozen
+#define ctx_fl_exclintr	ctx_flags.exclintr
 
-#define CTX_IS_DEAR(c,n)	((c)->ctx_dear_counter = (n))
-#define CTX_IS_IEAR(c,n)	((c)->ctx_iear_counter = (n))
-#define CTX_IS_BTB(c,n)		((c)->ctx_btb_counter = (n))
 #define CTX_OVFL_NOBLOCK(c)	((c)->ctx_fl_noblock = 1)
 #define CTX_INHERIT_MODE(c)	((c)->ctx_fl_inherit)
 #define CTX_HAS_SMPL(c)		((c)->ctx_smpl_buf != NULL)
@@ -234,17 +246,15 @@
 static pmu_config_t pmu_conf;
 
 /* for debug only */
-static unsigned long pfm_debug=0;	/* 0= nodebug, >0= debug output on */
+static int pfm_debug=0;	/* 0= nodebug, >0= debug output on */
+
 #define DBprintk(a) \
 	do { \
-		if (pfm_debug >0) { printk(__FUNCTION__" "); printk a; } \
+		if (pfm_debug >0) { printk(__FUNCTION__" %d: ", __LINE__); printk a; } \
 	} while (0);
 
-static void perfmon_softint(unsigned long ignored);
 static void ia64_reset_pmu(void);
 
-DECLARE_TASKLET(pfm_tasklet, perfmon_softint, 0);
-
 /*
  * structure used to pass information between the interrupt handler
  * and the tasklet.
@@ -256,26 +266,42 @@
 	unsigned long	bitvect;	/* which counters have overflowed */
 } notification_info_t;
 
-#define notification_is_invalid(i)	(i->to_pid < 2)
 
-/* will need to be cache line padded */
-static notification_info_t notify_info[NR_CPUS];
+typedef struct {
+	unsigned long pfs_proc_sessions;
+	unsigned long pfs_sys_session; /* can only be 0/1 */
+	unsigned long pfs_dfl_dcr;	/* XXX: hack */
+	unsigned int  pfs_pp;
+} pfm_session_t;
 
-/*
- * We force cache line alignment to avoid false sharing
- * given that we have one entry per CPU.
- */
-static struct {
+struct {
 	struct task_struct *owner;
 } ____cacheline_aligned pmu_owners[NR_CPUS];
-/* helper macros */
+
+
+/* 
+ * helper macros
+ */
 #define SET_PMU_OWNER(t)	do { pmu_owners[smp_processor_id()].owner = (t); } while(0);
 #define PMU_OWNER()		pmu_owners[smp_processor_id()].owner
 
+#ifdef CONFIG_SMP
+#define PFM_CAN_DO_LAZY()	(smp_num_cpus=1 && pfs_info.pfs_sys_session=0)
+#else
+#define PFM_CAN_DO_LAZY()	(pfs_info.pfs_sys_session=0)
+#endif
+
+static void pfm_lazy_save_regs (struct task_struct *ta);
+
 /* for debug only */
 static struct proc_dir_entry *perfmon_dir;
 
 /*
+ * XXX: hack to indicate that a system wide monitoring session is active
+ */
+static pfm_session_t pfs_info;
+
+/*
  * finds the number of PM(C|D) registers given
  * the bitvector returned by PAL
  */
@@ -339,8 +365,7 @@
 static inline unsigned long
 kvirt_to_pa(unsigned long adr)
 {
-	__u64 pa;
-	__asm__ __volatile__ ("tpa %0 = %1" : "=r"(pa) : "r"(adr) : "memory");
+	__u64 pa = ia64_tpa(adr);
 	DBprintk(("kv2pa(%lx-->%lx)\n", adr, pa));
 	return pa;
 }
@@ -568,25 +593,44 @@
 static int
 pfx_is_sane(pfreq_context_t *pfx)
 {
+	int ctx_flags;
+
 	/* valid signal */
-	if (pfx->notify_sig < 1 || pfx->notify_sig >= _NSIG) return 0;
+	//if (pfx->notify_sig < 1 || pfx->notify_sig >= _NSIG) return -EINVAL;
+	if (pfx->notify_sig !=0 && pfx->notify_sig != SIGPROF) return -EINVAL;
 
 	/* cannot send to process 1, 0 means do not notify */
-	if (pfx->notify_pid < 0 || pfx->notify_pid = 1) return 0;
+	if (pfx->notify_pid < 0 || pfx->notify_pid = 1) return -EINVAL;
+
+	ctx_flags = pfx->flags;
 
+	if (ctx_flags & PFM_FL_SYSTEM_WIDE) {
+#ifdef CONFIG_SMP
+		if (smp_num_cpus > 1) {
+			printk("perfmon: system wide monitoring on SMP not yet supported\n");
+			return -EINVAL;
+		}
+#endif
+		if ((ctx_flags & PFM_FL_SMPL_OVFL_NOBLOCK) = 0) {
+			printk("perfmon: system wide monitoring cannot use blocking notification mode\n");
+			return -EINVAL;
+		}
+	}
 	/* probably more to add here */
 
-	return 1;
+	return 0;
 }
 
 static int
-pfm_context_create(struct task_struct *task, int flags, perfmon_req_t *req)
+pfm_context_create(int flags, perfmon_req_t *req)
 {
 	pfm_context_t *ctx;
+	struct task_struct *task = NULL;
 	perfmon_req_t tmp;
 	void *uaddr = NULL;
-	int ret = -EFAULT;
+	int ret;
 	int ctx_flags;
+	pid_t pid;
 
 	/* to go away */
 	if (flags) {
@@ -595,48 +639,156 @@
 
 	if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
+	ret = pfx_is_sane(&tmp.pfr_ctx);
+	if (ret < 0) return ret;
+
 	ctx_flags = tmp.pfr_ctx.flags;
 
-	/* not yet supported */
-	if (ctx_flags & PFM_FL_SYSTEMWIDE) return -EINVAL;
+	if (ctx_flags & PFM_FL_SYSTEM_WIDE) {
+		/*
+		 * XXX: This is not AT ALL SMP safe
+		 */
+		if (pfs_info.pfs_proc_sessions > 0) return -EBUSY;
+		if (pfs_info.pfs_sys_session > 0) return -EBUSY;
+
+		pfs_info.pfs_sys_session = 1;
 
-	if (!pfx_is_sane(&tmp.pfr_ctx)) return -EINVAL;
+	} else if (pfs_info.pfs_sys_session >0) {
+		/* no per-process monitoring while there is a system wide session */
+		return -EBUSY;
+	} else
+		pfs_info.pfs_proc_sessions++;
 
 	ctx = pfm_context_alloc();
-	if (!ctx) return -ENOMEM;
+	if (!ctx) goto error;
+
+	/* record the creator (debug only) */
+	ctx->ctx_creator = current;
+
+	pid = tmp.pfr_ctx.notify_pid;
+
+	spin_lock_init(&ctx->ctx_notify_lock);
+
+	if (pid = current->pid) {
+		ctx->ctx_notify_task = task = current;
+		current->thread.pfm_context = ctx;
+
+		atomic_set(&current->thread.pfm_notifiers_check, 1);
+
+	} else if (pid!=0) {
+		read_lock(&tasklist_lock);
+
+		task = find_task_by_pid(pid);
+		if (task) {
+			/*
+		 	 * record who to notify
+		 	 */
+			ctx->ctx_notify_task = task;
+
+			/* 
+		 	 * make visible
+		 	 * must be done inside critical section
+		 	 *
+		 	 * if the initialization does not go through it is still
+		 	 * okay because child will do the scan for nothing which
+		 	 * won't hurt.
+		 	 */
+			current->thread.pfm_context = ctx;
+
+			/*
+			 * will cause task to check on exit for monitored
+			 * processes that would notify it. see release_thread()
+			 * Note: the scan MUST be done in release thread, once the
+			 * task has been detached from the tasklist otherwise you are
+			 * exposed to race conditions.
+			 */
+			atomic_add(1, &task->thread.pfm_notifiers_check);
+		}
+		read_unlock(&tasklist_lock);
+	}
 
-	/* record who the creator is (for debug) */
-	ctx->ctx_creator = task->pid;
+	/*
+	 * notification process does not exist
+	 */
+	if (pid != 0 && task = NULL) {
+		ret = -EINVAL;
+		goto buffer_error;
+	}
 
-	ctx->ctx_notify_pid = tmp.pfr_ctx.notify_pid;
 	ctx->ctx_notify_sig = SIGPROF;	/* siginfo imposes a fixed signal */
 
 	if (tmp.pfr_ctx.smpl_entries) {
 		DBprintk((" sampling entries=%ld\n",tmp.pfr_ctx.smpl_entries));
-		if ((ret=pfm_smpl_buffer_alloc(ctx, tmp.pfr_ctx.smpl_regs, tmp.pfr_ctx.smpl_entries, &uaddr)) ) goto buffer_error;
+
+		ret = pfm_smpl_buffer_alloc(ctx, tmp.pfr_ctx.smpl_regs, 
+						 tmp.pfr_ctx.smpl_entries, &uaddr);
+		if (ret<0) goto buffer_error;
+
 		tmp.pfr_ctx.smpl_vaddr = uaddr;
 	}
 	/* initialization of context's flags */
-	ctx->ctx_fl_inherit = ctx_flags & PFM_FL_INHERIT_MASK;
-	ctx->ctx_fl_noblock = (ctx_flags & PFM_FL_SMPL_OVFL_NOBLOCK) ? 1 : 0;
-	ctx->ctx_fl_system  = (ctx_flags & PFM_FL_SYSTEMWIDE) ? 1: 0;
-	ctx->ctx_fl_frozen  = 0;
+	ctx->ctx_fl_inherit  = ctx_flags & PFM_FL_INHERIT_MASK;
+	ctx->ctx_fl_noblock  = (ctx_flags & PFM_FL_SMPL_OVFL_NOBLOCK) ? 1 : 0;
+	ctx->ctx_fl_system   = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0;
+	ctx->ctx_fl_exclintr = (ctx_flags & PFM_FL_EXCL_INTR) ? 1: 0;
+	ctx->ctx_fl_frozen   = 0;
+
+	/* 
+	 * Keep track of the pmds we want to sample
+	 * XXX: may be we don't need to save/restore the DEAR/IEAR pmds
+	 * but we do need the BTB for sure. This is because of a hardware
+	 * buffer of 1 only for non-BTB pmds.
+	 */
+	ctx->ctx_used_pmds[0] = tmp.pfr_ctx.smpl_regs;
+	ctx->ctx_used_pmcs[0] = 1; /* always save/restore PMC[0] */
 
 	sema_init(&ctx->ctx_restart_sem, 0); /* init this semaphore to locked */
 
-	if (copy_to_user(req, &tmp, sizeof(tmp))) goto buffer_error;
 
-	DBprintk((" context=%p, pid=%d notify_sig %d notify_pid=%d\n",(void *)ctx, task->pid, ctx->ctx_notify_sig, ctx->ctx_notify_pid));
-	DBprintk((" context=%p, pid=%d flags=0x%x inherit=%d noblock=%d system=%d\n",(void *)ctx, task->pid, ctx_flags, ctx->ctx_fl_inherit, ctx->ctx_fl_noblock, ctx->ctx_fl_system));
+	if (copy_to_user(req, &tmp, sizeof(tmp))) {
+		ret = -EFAULT;
+		goto buffer_error;
+	}
+
+	DBprintk((" context=%p, pid=%d notify_sig %d notify_task=%p\n",(void *)ctx, current->pid, ctx->ctx_notify_sig, ctx->ctx_notify_task));
+	DBprintk((" context=%p, pid=%d flags=0x%x inherit=%d noblock=%d system=%d\n",(void *)ctx, current->pid, ctx_flags, ctx->ctx_fl_inherit, ctx->ctx_fl_noblock, ctx->ctx_fl_system));
+
+	/*
+	 * when no notification is required, we can make this visible at the last moment
+	 */
+	if (pid = 0) current->thread.pfm_context = ctx;
+
+	/*
+	 * by default, we always include interrupts for system wide
+	 * DCR.pp is set by default to zero by kernel  in cpu_init()
+	 */
+	if (ctx->ctx_fl_system) {
+		if (ctx->ctx_fl_exclintr = 0) {
+			unsigned long dcr = ia64_get_dcr();
+
+			ia64_set_dcr(dcr|IA64_DCR_PP);
+			/*
+			* keep track of the kernel default value
+			 */
+			pfs_info.pfs_dfl_dcr = dcr;
 
-	/* link with task */
-	task->thread.pfm_context = ctx;
+			DBprintk((" dcr.pp is set\n"));
+		}
+	} 
 
 	return 0;
 
 buffer_error:
-	vfree(ctx);
-
+	pfm_context_free(ctx);
+error:
+	/*
+	 * undo session reservation
+	 */
+	if (ctx_flags & PFM_FL_SYSTEM_WIDE) {
+		pfs_info.pfs_sys_session = 0;
+	} else {
+		pfs_info.pfs_proc_sessions--;
+	}
 	return ret;
 }
 
@@ -656,8 +808,20 @@
 
 			/* upper part is ignored on rval */
 			ia64_set_pmd(cnum, ctx->ctx_pmds[i].smpl_rval);
+
+			/*
+			 * we must reset BTB index (clears pmd16.full to make
+			 * sure we do not report the same branches twice.
+			 * The non-blocking case in handled in update_counters()
+			 */
+			if (cnum = ctx->ctx_btb_counter) {
+				DBprintk(("reseting PMD16\n"));
+				ia64_set_pmd(16, 0);
+			}
 		}
 	}
+	/* just in case ! */
+	ctx->ctx_ovfl_regs = 0;
 }
 
 static int
@@ -695,20 +859,23 @@
 			} else if (PMC_IS_BTB(&tmp.pfr_reg.reg_value)) {
 				ctx->ctx_btb_counter = cnum;
 			}
-
+#if 0
 			if (tmp.pfr_reg.reg_flags & PFM_REGFL_OVFL_NOTIFY)
 				ctx->ctx_pmds[cnum - PMU_FIRST_COUNTER].flags |= PFM_REGFL_OVFL_NOTIFY;
+#endif
 		}
-
+		/* keep track of what we use */
+		CTX_USED_PMC(ctx, cnum);
 		ia64_set_pmc(cnum, tmp.pfr_reg.reg_value);
-			DBprintk((" setting PMC[%ld]=0x%lx flags=0x%x\n", cnum, tmp.pfr_reg.reg_value, ctx->ctx_pmds[cnum - PMU_FIRST_COUNTER].flags));
+
+		DBprintk((" setting PMC[%ld]=0x%lx flags=0x%x used_pmcs=0%lx\n", cnum, tmp.pfr_reg.reg_value, ctx->ctx_pmds[cnum - PMU_FIRST_COUNTER].flags, ctx->ctx_used_pmcs[0]));
 
 	}
 	/*
 	 * we have to set this here event hough we haven't necessarily started monitoring
 	 * because we may be context switched out
 	 */
-	th->flags |= IA64_THREAD_PM_VALID;
+	if (ctx->ctx_fl_system=0) th->flags |= IA64_THREAD_PM_VALID;
 
 	return 0;
 }
@@ -741,25 +908,32 @@
 			ctx->ctx_pmds[k].val  = tmp.pfr_reg.reg_value & ~pmu_conf.perf_ovfl_val;
 			ctx->ctx_pmds[k].smpl_rval = tmp.pfr_reg.reg_smpl_reset;
 			ctx->ctx_pmds[k].ovfl_rval = tmp.pfr_reg.reg_ovfl_reset;
+
+			if (tmp.pfr_reg.reg_flags & PFM_REGFL_OVFL_NOTIFY)
+				ctx->ctx_pmds[cnum - PMU_FIRST_COUNTER].flags |= PFM_REGFL_OVFL_NOTIFY;
 		}
+		/* keep track of what we use */
+		CTX_USED_PMD(ctx, cnum);
 
 		/* writes to unimplemented part is ignored, so this is safe */
 		ia64_set_pmd(cnum, tmp.pfr_reg.reg_value);
 
 		/* to go away */
 		ia64_srlz_d();
-		DBprintk((" setting PMD[%ld]:  pmd.val=0x%lx pmd.ovfl_rval=0x%lx pmd.smpl_rval=0x%lx pmd=%lx\n",
+		DBprintk((" setting PMD[%ld]:  ovfl_notify=%d pmd.val=0x%lx pmd.ovfl_rval=0x%lx pmd.smpl_rval=0x%lx pmd=%lx used_pmds=0%lx\n",
 					cnum,
+					PMD_OVFL_NOTIFY(ctx, cnum - PMU_FIRST_COUNTER),
 					ctx->ctx_pmds[k].val,
 					ctx->ctx_pmds[k].ovfl_rval,
 					ctx->ctx_pmds[k].smpl_rval,
-					ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val));
+					ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val,
+					ctx->ctx_used_pmds[0]));
 	}
 	/*
 	 * we have to set this here event hough we haven't necessarily started monitoring
 	 * because we may be context switched out
 	 */
-	th->flags |= IA64_THREAD_PM_VALID;
+	if (ctx->ctx_fl_system=0) th->flags |= IA64_THREAD_PM_VALID;
 
 	return 0;
 }
@@ -783,6 +957,8 @@
 	/* XXX: ctx locking may be required here */
 
 	for (i = 0; i < count; i++, req++) {
+		unsigned long reg_val = ~0, ctx_val = ~0;
+
 		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
 		if (!PMD_IS_IMPL(tmp.pfr_reg.reg_num)) return -EINVAL;
@@ -791,23 +967,25 @@
 			if (ta = current){
 				val = ia64_get_pmd(tmp.pfr_reg.reg_num);
 			} else {
-				val = th->pmd[tmp.pfr_reg.reg_num];
+				val = reg_val = th->pmd[tmp.pfr_reg.reg_num];
 			}
 			val &= pmu_conf.perf_ovfl_val;
 			/*
 			 * lower part of .val may not be zero, so we must be an addition because of
 			 * residual count (see update_counters).
 			 */
-			val += ctx->ctx_pmds[tmp.pfr_reg.reg_num - PMU_FIRST_COUNTER].val;
+			val += ctx_val = ctx->ctx_pmds[tmp.pfr_reg.reg_num - PMU_FIRST_COUNTER].val;
 		} else {
 			/* for now */
 			if (ta != current) return -EINVAL;
 
+			ia64_srlz_d();
 			val = ia64_get_pmd(tmp.pfr_reg.reg_num);
 		}
 		tmp.pfr_reg.reg_value = val;
 
-		DBprintk((" reading PMD[%ld]=0x%lx\n", tmp.pfr_reg.reg_num, val));
+		DBprintk((" reading PMD[%ld]=0x%lx reg=0x%lx ctx_val=0x%lx pmc=0x%lx\n", 
+					tmp.pfr_reg.reg_num, val, reg_val, ctx_val, ia64_get_pmc(tmp.pfr_reg.reg_num)));
 
 		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
 	}
@@ -822,7 +1000,7 @@
 	void *sem = &ctx->ctx_restart_sem;
 
 	if (task = current) {
-		DBprintk((" restartig self %d frozen=%d \n", current->pid, ctx->ctx_fl_frozen));
+		DBprintk((" restarting self %d frozen=%d \n", current->pid, ctx->ctx_fl_frozen));
 
 		pfm_reset_regs(ctx);
 
@@ -871,6 +1049,23 @@
 	return 0;
 }
 
+/*
+ * system-wide mode: propagate activation/desactivation throughout the tasklist
+ *
+ * XXX: does not work for SMP, of course
+ */
+static void
+pfm_process_tasklist(int cmd)
+{
+	struct task_struct *p;
+	struct pt_regs *regs;
+
+	for_each_task(p) {
+		regs = (struct pt_regs *)((unsigned long)p + IA64_STK_OFFSET);
+		regs--;
+		ia64_psr(regs)->pp = cmd;
+	}
+}
 
 static int
 do_perfmonctl (struct task_struct *task, int cmd, int flags, perfmon_req_t *req, int count, struct pt_regs *regs)
@@ -881,19 +1076,26 @@
 
 	memset(&tmp, 0, sizeof(tmp));
 
+	if (ctx = NULL && cmd != PFM_CREATE_CONTEXT && cmd < PFM_DEBUG_BASE) {
+		DBprintk((" PFM_WRITE_PMCS: no context for task %d\n", task->pid));
+		return -EINVAL;
+	}
+
 	switch (cmd) {
 		case PFM_CREATE_CONTEXT:
 			/* a context has already been defined */
 			if (ctx) return -EBUSY;
 
-			/* may be a temporary limitation */
+			/*
+			 * cannot directly create a context in another process
+			 */
 			if (task != current) return -EINVAL;
 
 			if (req = NULL || count != 1) return -EINVAL;
 
 			if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT;
 
-			return pfm_context_create(task, flags, req);
+			return pfm_context_create(flags, req);
 
 		case PFM_WRITE_PMCS:
 			/* we don't quite support this right now */
@@ -901,10 +1103,6 @@
 
 			if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT;
 
-			if (!ctx) {
-				DBprintk((" PFM_WRITE_PMCS: no context for task %d\n", task->pid));
-				return -EINVAL;
-			}
 			return pfm_write_pmcs(task, req, count);
 
 		case PFM_WRITE_PMDS:
@@ -913,45 +1111,41 @@
 
 			if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT;
 
-			if (!ctx) {
-				DBprintk((" PFM_WRITE_PMDS: no context for task %d\n", task->pid));
-				return -EINVAL;
-			}
 			return pfm_write_pmds(task, req, count);
 
 		case PFM_START:
 			/* we don't quite support this right now */
 			if (task != current) return -EINVAL;
 
-			if (!ctx) {
-				DBprintk((" PFM_START: no context for task %d\n", task->pid));
-				return -EINVAL;
-			}
+			if (PMU_OWNER()  && PMU_OWNER() != current && PFM_CAN_DO_LAZY()) pfm_lazy_save_regs(PMU_OWNER());
 
 			SET_PMU_OWNER(current);
 
 			/* will start monitoring right after rfi */
 			ia64_psr(regs)->up = 1;
+			ia64_psr(regs)->pp = 1;
+
+			if (ctx->ctx_fl_system) {
+				pfm_process_tasklist(1);
+				pfs_info.pfs_pp = 1;
+			}
 
 			/*
 			 * mark the state as valid.
 			 * this will trigger save/restore at context switch
 			 */
-			th->flags |= IA64_THREAD_PM_VALID;
+			if (ctx->ctx_fl_system=0) th->flags |= IA64_THREAD_PM_VALID;
 
 			ia64_set_pmc(0, 0);
 			ia64_srlz_d();
 
-		break;
+			break;
 
 		case PFM_ENABLE:
 			/* we don't quite support this right now */
 			if (task != current) return -EINVAL;
 
-			if (!ctx) {
-				DBprintk((" PFM_ENABLE: no context for task %d\n", task->pid));
-				return -EINVAL;
-			}
+			if (PMU_OWNER()  && PMU_OWNER() != current && PFM_CAN_DO_LAZY()) pfm_lazy_save_regs(PMU_OWNER());
 
 			/* reset all registers to stable quiet state */
 			ia64_reset_pmu();
@@ -969,7 +1163,7 @@
 			 * mark the state as valid.
 			 * this will trigger save/restore at context switch
 			 */
-			th->flags |= IA64_THREAD_PM_VALID;
+			if (ctx->ctx_fl_system=0) th->flags |= IA64_THREAD_PM_VALID;
 
 			/* simply unfreeze */
 			ia64_set_pmc(0, 0);
@@ -983,54 +1177,41 @@
 			/* simply freeze */
 			ia64_set_pmc(0, 1);
 			ia64_srlz_d();
+			/*
+			 * XXX: cannot really toggle IA64_THREAD_PM_VALID
+			 * but context is still considered valid, so any 
+			 * read request would return something valid. Same
+			 * thing when this task terminates (pfm_flush_regs()).
+			 */
 			break;
 
 		case PFM_READ_PMDS:
 			if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT;
 			if (!access_ok(VERIFY_WRITE, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT;
 
-			if (!ctx) {
-				DBprintk((" PFM_READ_PMDS: no context for task %d\n", task->pid));
-				return -EINVAL;
-			}
 			return pfm_read_pmds(task, req, count);
 
 	      case PFM_STOP:
 			/* we don't quite support this right now */
 			if (task != current) return -EINVAL;
 
-			ia64_set_pmc(0, 1);
-			ia64_srlz_d();
-
+			/* simply stop monitors, not PMU */
 			ia64_psr(regs)->up = 0;
+			ia64_psr(regs)->pp = 0;
 
-			th->flags &= ~IA64_THREAD_PM_VALID;
-
-			SET_PMU_OWNER(NULL);
-
-			/* we probably will need some more cleanup here */
-			break;
-
-	      case PFM_DEBUG_ON:
-			printk(" debugging on\n");
-			pfm_debug = 1;
-			break;
+			if (ctx->ctx_fl_system) {
+				pfm_process_tasklist(0);
+				pfs_info.pfs_pp = 0;
+			}
 
-	      case PFM_DEBUG_OFF:
-			printk(" debugging off\n");
-			pfm_debug = 0;
 			break;
 
 	      case PFM_RESTART: /* temporary, will most likely end up as a PFM_ENABLE */
 
-			if ((th->flags & IA64_THREAD_PM_VALID) = 0) {
+			if ((th->flags & IA64_THREAD_PM_VALID) = 0 && ctx->ctx_fl_system=0) {
 				printk(" PFM_RESTART not monitoring\n");
 				return -EINVAL;
 			}
-			if (!ctx) {
-				printk(" PFM_RESTART no ctx for %d\n", task->pid);
-				return -EINVAL;
-			}
 			if (CTX_OVFL_NOBLOCK(ctx) = 0 && ctx->ctx_fl_frozen=0) {
 				printk("task %d without pmu_frozen set\n", task->pid);
 				return -EINVAL;
@@ -1038,6 +1219,37 @@
 
 			return pfm_do_restart(task); /* we only look at first entry */
 
+	      case PFM_DESTROY_CONTEXT:
+			/* we don't quite support this right now */
+			if (task != current) return -EINVAL;
+
+			/* first stop monitors */
+			ia64_psr(regs)->up = 0;
+			ia64_psr(regs)->pp = 0;
+
+			/* then freeze PMU */
+			ia64_set_pmc(0, 1);
+			ia64_srlz_d();
+
+			/* don't save/restore on context switch */
+			if (ctx->ctx_fl_system =0) task->thread.flags &= ~IA64_THREAD_PM_VALID;
+
+			SET_PMU_OWNER(NULL);
+
+			/* now free context and related state */
+			pfm_context_exit(task);
+			break;
+
+	      case PFM_DEBUG_ON:
+			printk("perfmon debugging on\n");
+			pfm_debug = 1;
+			break;
+
+	      case PFM_DEBUG_OFF:
+			printk("perfmon debugging off\n");
+			pfm_debug = 0;
+			break;
+
 	      default:
 			DBprintk((" UNknown command 0x%x\n", cmd));
 			return -EINVAL;
@@ -1074,11 +1286,8 @@
 	/* XXX: pid interface is going away in favor of pfm context */
 	if (pid != current->pid) {
 		read_lock(&tasklist_lock);
-		{
-			child = find_task_by_pid(pid);
-			if (child)
-				get_task_struct(child);
-		}
+
+		child = find_task_by_pid(pid);
 
 		if (!child) goto abort_call;
 
@@ -1101,93 +1310,44 @@
 	return ret;
 }
 
-
-/*
- * This function is invoked on the exit path of the kernel. Therefore it must make sure
- * it does does modify the caller's input registers (in0-in7) in case of entry by system call
- * which can be restarted. That's why it's declared as a system call and all 8 possible args
- * are declared even though not used.
- */
 #if __GNUC__ >= 3
 void asmlinkage
-pfm_overflow_notify(void)
+pfm_block_on_overflow(void)
 #else
 void asmlinkage
-pfm_overflow_notify(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7)
+pfm_block_on_overflow(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7)
 #endif
 {
-	struct task_struct *task;
 	struct thread_struct *th = &current->thread;
 	pfm_context_t *ctx = current->thread.pfm_context;
-	struct siginfo si;
 	int ret;
 
 	/*
-	 * do some sanity checks first
-	 */
-	if (!ctx) {
-		printk("perfmon: process %d has no PFM context\n", current->pid);
-		return;
-	}
-	if (ctx->ctx_notify_pid < 2) {
-		printk("perfmon: process %d invalid notify_pid=%d\n", current->pid, ctx->ctx_notify_pid);
-		return;
-	}
-
-	DBprintk((" current=%d ctx=%p bv=0%lx\n", current->pid, (void *)ctx, ctx->ctx_ovfl_regs));
-	/*
 	 * NO matter what notify_pid is,
 	 * we clear overflow, won't notify again
 	 */
-	th->pfm_pend_notify = 0;
+	th->pfm_must_block = 0;
 
 	/*
-	 * When measuring in kernel mode and non-blocking fashion, it is possible to
-	 * get an overflow while executing this code. Therefore the state of pend_notify
-	 * and ovfl_regs can be altered. The important point is not to loose any notification.
-	 * It is fine to get called for nothing. To make sure we do collect as much state as
-	 * possible, update_counters() always uses |= to add bit to the ovfl_regs field.
-	 *
-	 * In certain cases, it is possible to come here, with ovfl_regs = 0;
-	 *
-	 * XXX: pend_notify and ovfl_regs could be merged maybe !
+	 * do some sanity checks first
 	 */
-	if (ctx->ctx_ovfl_regs = 0) {
-		printk("perfmon: spurious overflow notification from pid %d\n", current->pid);
+	if (!ctx) {
+		printk("perfmon: process %d has no PFM context\n", current->pid);
 		return;
 	}
-	read_lock(&tasklist_lock);
-
-	task = find_task_by_pid(ctx->ctx_notify_pid);
-
-	if (task) {
-		si.si_signo    = ctx->ctx_notify_sig;
-		si.si_errno    = 0;
-		si.si_code     = PROF_OVFL; /* goes to user */
-		si.si_addr     = NULL;
-		si.si_pid      = current->pid; /* who is sending */
-		si.si_pfm_ovfl = ctx->ctx_ovfl_regs;
-
-		DBprintk((" SIGPROF to %d @ %p\n", task->pid, (void *)task));
-
-		/* must be done with tasklist_lock locked */
-		ret = send_sig_info(ctx->ctx_notify_sig, &si, task);
-		if (ret != 0) {
-			DBprintk((" send_sig_info(process %d, SIGPROF)=%d\n", ctx->ctx_notify_pid, ret));
-			task = NULL; /* will cause return */
-		}
-	} else {
-		printk("perfmon: notify_pid %d not found\n", ctx->ctx_notify_pid);
+	if (ctx->ctx_notify_task = 0) {
+		printk("perfmon: process %d has no task to notify\n", current->pid);
+		return;
 	}
 
-	read_unlock(&tasklist_lock);
+	DBprintk((" current=%d task=%d\n", current->pid, ctx->ctx_notify_task->pid));
 
-	/* now that we have released the lock handle error condition */
-	if (!task || CTX_OVFL_NOBLOCK(ctx)) {
-		/* we clear all pending overflow bits in noblock mode */
-		ctx->ctx_ovfl_regs = 0;
+	/* should not happen */
+	if (CTX_OVFL_NOBLOCK(ctx)) {
+		printk("perfmon: process %d non-blocking ctx should not be here\n", current->pid);
 		return;
 	}
+
 	DBprintk((" CPU%d %d before sleep\n", smp_processor_id(), current->pid));
 
 	/*
@@ -1211,9 +1371,6 @@
 
 		pfm_reset_regs(ctx);
 
-		/* now we can clear this mask */
-		ctx->ctx_ovfl_regs = 0;
-
 		/*
 		 * Unlock sampling buffer and reset index atomically
 		 * XXX: not really needed when blocking
@@ -1232,84 +1389,14 @@
 	}
 }
 
-static void
-perfmon_softint(unsigned long ignored)
-{
-	notification_info_t *info;
-	int my_cpu = smp_processor_id();
-	struct task_struct *task;
-	struct siginfo si;
-
-	info = notify_info+my_cpu;
-
-	DBprintk((" CPU%d current=%d to_pid=%d from_pid=%d bv=0x%lx\n", \
-		smp_processor_id(), current->pid, info->to_pid, info->from_pid, info->bitvect));
-
-	/* assumption check */
-	if (info->from_pid = info->to_pid) {
-		DBprintk((" Tasklet assumption error: from=%d tor=%d\n", info->from_pid, info->to_pid));
-		return;
-	}
-
-	if (notification_is_invalid(info)) {
-		DBprintk((" invalid notification information\n"));
-		return;
-	}
-
-	/* sanity check */
-	if (info->to_pid = 1) {
-		DBprintk((" cannot notify init\n"));
-		return;
-	}
-	/*
-	 * XXX: needs way more checks here to make sure we send to a task we have control over
-	 */
-	read_lock(&tasklist_lock);
-
-	task = find_task_by_pid(info->to_pid);
-
-	DBprintk((" after find %p\n", (void *)task));
-
-	if (task) {
-		int ret;
-
-		si.si_signo    = SIGPROF;
-		si.si_errno    = 0;
-		si.si_code     = PROF_OVFL; /* goes to user */
-		si.si_addr     =  NULL;
-		si.si_pid      = info->from_pid; /* who is sending */
-		si.si_pfm_ovfl = info->bitvect;
-
-		DBprintk((" SIGPROF to %d @ %p\n", task->pid, (void *)task));
-
-		/* must be done with tasklist_lock locked */
-		ret = send_sig_info(SIGPROF, &si, task);
-		if (ret != 0)
-			DBprintk((" send_sig_info(process %d, SIGPROF)=%d\n", info->to_pid, ret));
-
-		/* invalidate notification */
-		info->to_pid  = info->from_pid = 0;
-		info->bitvect = 0;
-	}
-
-	read_unlock(&tasklist_lock);
-
-	DBprintk((" after unlock %p\n", (void *)task));
-
-	if (!task) {
-		printk("perfmon: CPU%d cannot find process %d\n", smp_processor_id(), info->to_pid);
-	}
-}
-
 /*
  * main overflow processing routine.
  * it can be called from the interrupt path or explicitely during the context switch code
  * Return:
- *	0 : do not unfreeze the PMU
- *	1 : PMU can be unfrozen
+ *	new value of pmc[0]. if 0x0 then unfreeze, else keep frozen
  */
-static unsigned long
-update_counters (struct task_struct *ta, u64 pmc0, struct pt_regs *regs)
+unsigned long
+update_counters (struct task_struct *task, u64 pmc0, struct pt_regs *regs)
 {
 	unsigned long mask, i, cnum;
 	struct thread_struct *th;
@@ -1317,7 +1404,9 @@
 	unsigned long bv = 0;
 	int my_cpu = smp_processor_id();
 	int ret = 1, buffer_is_full = 0;
-	int ovfl_is_smpl, can_notify, need_reset_pmd16=0;
+	int ovfl_has_long_recovery, can_notify, need_reset_pmd16=0;
+	struct siginfo si;
+
 	/*
 	 * It is never safe to access the task for which the overflow interrupt is destinated
 	 * using the current variable as the interrupt may occur in the middle of a context switch
@@ -1331,23 +1420,23 @@
 	 * valid one, i.e. the one that caused the interrupt.
 	 */
 
-	if (ta = NULL) {
+	if (task = NULL) {
 		DBprintk((" owners[%d]=NULL\n", my_cpu));
 		return 0x1;
 	}
-	th  = &ta->thread;
+	th  = &task->thread;
 	ctx = th->pfm_context;
 
 	/*
 	 * XXX: debug test
 	 * Don't think this could happen given upfront tests
 	 */
-	if ((th->flags & IA64_THREAD_PM_VALID) = 0) {
-		printk("perfmon: Spurious overflow interrupt: process %d not using perfmon\n", ta->pid);
+	if ((th->flags & IA64_THREAD_PM_VALID) = 0 && ctx->ctx_fl_system = 0) {
+		printk("perfmon: Spurious overflow interrupt: process %d not using perfmon\n", task->pid);
 		return 0x1;
 	}
 	if (!ctx) {
-		printk("perfmon: Spurious overflow interrupt: process %d has no PFM context\n", ta->pid);
+		printk("perfmon: Spurious overflow interrupt: process %d has no PFM context\n", task->pid);
 		return 0;
 	}
 
@@ -1355,16 +1444,21 @@
 	 * sanity test. Should never happen
 	 */
 	if ((pmc0 & 0x1 )= 0) {
-		printk("perfmon: pid %d pmc0=0x%lx assumption error for freeze bit\n", ta->pid, pmc0);
+		printk("perfmon: pid %d pmc0=0x%lx assumption error for freeze bit\n", task->pid, pmc0);
 		return 0x0;
 	}
 
 	mask = pmc0 >> PMU_FIRST_COUNTER;
 
-	DBprintk(("pmc0=0x%lx pid=%d\n", pmc0, ta->pid));
-
-	DBprintk(("ctx is in %s mode\n", CTX_OVFL_NOBLOCK(ctx) ? "NO-BLOCK" : "BLOCK"));
+	DBprintk(("pmc0=0x%lx pid=%d owner=%d iip=0x%lx, ctx is in %s mode used_pmds=0x%lx used_pmcs=0x%lx\n", 
+				pmc0, task->pid, PMU_OWNER()->pid, regs->cr_iip, 
+				CTX_OVFL_NOBLOCK(ctx) ? "NO-BLOCK" : "BLOCK",
+				ctx->ctx_used_pmds[0],
+				ctx->ctx_used_pmcs[0]));
 
+	/*
+	 * XXX: need to record sample only when an EAR/BTB has overflowed
+	 */
 	if (CTX_HAS_SMPL(ctx)) {
 		pfm_smpl_buffer_desc_t *psb = ctx->ctx_smpl_buf;
 		unsigned long *e, m, idx=0;
@@ -1372,11 +1466,15 @@
 		int j;
 
 		idx = ia64_fetch_and_add(1, &psb->psb_index);
-		DBprintk((" trying to record index=%ld entries=%ld\n", idx, psb->psb_entries));
+		DBprintk((" recording index=%ld entries=%ld\n", idx, psb->psb_entries));
 
 		/*
 		 * XXX: there is a small chance that we could run out on index before resetting
 		 * but index is unsigned long, so it will take some time.....
+		 * We use > instead of = because fetch_and_add() is off by one (see below)
+		 *
+		 * This case can happen in non-blocking mode or with multiple processes.
+		 * For non-blocking, we need to reload and continue.
 		 */
 		if (idx > psb->psb_entries) {
 			buffer_is_full = 1;
@@ -1388,7 +1486,7 @@
 
 		h = (perfmon_smpl_entry_t *)(((char *)psb->psb_addr) + idx*(psb->psb_entry_size));
 
-		h->pid  = ta->pid;
+		h->pid  = task->pid;
 		h->cpu  = my_cpu;
 		h->rate = 0;
 		h->ip   = regs ? regs->cr_iip : 0x0; /* where did the fault happened */
@@ -1398,6 +1496,7 @@
 		h->stamp = perfmon_get_stamp();
 
 		e = (unsigned long *)(h+1);
+
 		/*
 		 * selectively store PMDs in increasing index number
 		 */
@@ -1406,35 +1505,66 @@
 				if (PMD_IS_COUNTER(j))
 					*e =  ctx->ctx_pmds[j-PMU_FIRST_COUNTER].val
 					    + (ia64_get_pmd(j) & pmu_conf.perf_ovfl_val);
-				else
+				else {
 					*e = ia64_get_pmd(j); /* slow */
+				}
 				DBprintk((" e=%p pmd%d =0x%lx\n", (void *)e, j, *e));
 				e++;
 			}
 		}
-		/* make the new entry visible to user, needs to be atomic */
+		/*
+		 * make the new entry visible to user, needs to be atomic
+		 */
 		ia64_fetch_and_add(1, &psb->psb_hdr->hdr_count);
 
 		DBprintk((" index=%ld entries=%ld hdr_count=%ld\n", idx, psb->psb_entries, psb->psb_hdr->hdr_count));
-
-		/* sampling buffer full ? */
+		/* 
+		 * sampling buffer full ? 
+		 */
 		if (idx = (psb->psb_entries-1)) {
-			bv = mask;
+			/*
+			 * will cause notification, cannot be 0
+			 */
+			bv = mask << PMU_FIRST_COUNTER;
+
 			buffer_is_full = 1;
 
 			DBprintk((" sampling buffer full must notify bv=0x%lx\n", bv));
 
-			if (!CTX_OVFL_NOBLOCK(ctx)) goto buffer_full;
+			/*
+			 * we do not reload here, when context is blocking
+			 */
+			if (!CTX_OVFL_NOBLOCK(ctx)) goto no_reload;
+
 			/*
 			 * here, we have a full buffer but we are in non-blocking mode
-			 * so we need to reloads overflowed PMDs with sampling reset values
-			 * and restart
+			 * so we need to reload overflowed PMDs with sampling reset values
+			 * and restart right away.
 			 */
 		}
+		/* FALL THROUGH */
 	}
 reload_pmds:
-	ovfl_is_smpl = CTX_OVFL_NOBLOCK(ctx) && buffer_is_full;
-	can_notify   = CTX_HAS_SMPL(ctx) = 0 && ctx->ctx_notify_pid;
+
+	/*
+	 * in the case of a non-blocking context, we reload
+	 * with the ovfl_rval when no user notification is taking place (short recovery)
+	 * otherwise when the buffer is full which requires user interaction) then we use
+	 * smpl_rval which is the long_recovery path (disturbance introduce by user execution).
+	 *
+	 * XXX: implies that when buffer is full then there is always notification.
+	 */
+	ovfl_has_long_recovery = CTX_OVFL_NOBLOCK(ctx) && buffer_is_full;
+
+	/*
+	 * XXX: CTX_HAS_SMPL() should really be something like CTX_HAS_SMPL() and is activated,i.e.,
+	 * one of the PMC is configured for EAR/BTB.
+	 *
+	 * When sampling, we can only notify when the sampling buffer is full.
+	 */
+	can_notify   = CTX_HAS_SMPL(ctx) = 0 && ctx->ctx_notify_task;
+
+	DBprintk((" ovfl_has_long_recovery=%d can_notify=%d\n", ovfl_has_long_recovery, can_notify));
 
 	for (i = 0, cnum = PMU_FIRST_COUNTER; mask ; cnum++, i++, mask >>= 1) {
 
@@ -1456,7 +1586,7 @@
 		DBprintk((" pmod[%ld].val=0x%lx pmd=0x%lx\n", i, ctx->ctx_pmds[i].val, ia64_get_pmd(cnum)&pmu_conf.perf_ovfl_val));
 
 		if (can_notify && PMD_OVFL_NOTIFY(ctx, i)) {
-			DBprintk((" CPU%d should notify process %d with signal %d\n", my_cpu, ctx->ctx_notify_pid, ctx->ctx_notify_sig));
+			DBprintk((" CPU%d should notify task %p with signal %d\n", my_cpu, ctx->ctx_notify_task, ctx->ctx_notify_sig));
 			bv |= 1 << i;
 		} else {
 			DBprintk((" CPU%d PMD[%ld] overflow, no notification\n", my_cpu, cnum));
@@ -1467,93 +1597,150 @@
 			 */
 
 			/* writes to upper part are ignored, so this is safe */
-			if (ovfl_is_smpl) {
-				DBprintk((" CPU%d PMD[%ld] reloaded with smpl_val=%lx\n", my_cpu, cnum,ctx->ctx_pmds[i].smpl_rval));
+			if (ovfl_has_long_recovery) {
+				DBprintk((" CPU%d PMD[%ld] reload with smpl_val=%lx\n", my_cpu, cnum,ctx->ctx_pmds[i].smpl_rval));
 				ia64_set_pmd(cnum, ctx->ctx_pmds[i].smpl_rval);
 			} else {
-				DBprintk((" CPU%d PMD[%ld] reloaded with ovfl_val=%lx\n", my_cpu, cnum,ctx->ctx_pmds[i].smpl_rval));
+				DBprintk((" CPU%d PMD[%ld] reload with ovfl_val=%lx\n", my_cpu, cnum,ctx->ctx_pmds[i].smpl_rval));
 				ia64_set_pmd(cnum, ctx->ctx_pmds[i].ovfl_rval);
 			}
 		}
 		if (cnum = ctx->ctx_btb_counter) need_reset_pmd16=1;
 	}
 	/*
-	 * In case of BTB, overflow
-	 * we need to reset the BTB index.
+	 * In case of BTB overflow we need to reset the BTB index.
 	 */
 	if (need_reset_pmd16) {
 		DBprintk(("reset PMD16\n"));
 		ia64_set_pmd(16, 0);
 	}
-buffer_full:
-	/* see pfm_overflow_notify() on details for why we use |= here */
-	ctx->ctx_ovfl_regs  |= bv;
 
-	/* nobody to notify, return and unfreeze */
+no_reload:
+
+	/*
+	 * some counters overflowed, but they did not require
+	 * user notification, so after having reloaded them above
+	 * we simply restart
+	 */
 	if (!bv) return 0x0;
 
+	ctx->ctx_ovfl_regs  = bv; /* keep track of what to reset when unblocking */
+	/*
+	 * Now we know that:
+	 * 	- we have some counters which overflowed (contains in bv)
+	 * 	- someone has asked to be notified on overflow. 
+	 */
+
+	
+	/*
+	 * If the notification task is still present, then notify_task is non
+	 * null. It is clean by that task if it ever exits before we do. 
+	 */
 
-	if (ctx->ctx_notify_pid = ta->pid) {
-		struct siginfo si;
+	if (ctx->ctx_notify_task) {
 
 		si.si_errno    = 0;
 		si.si_addr     = NULL;
-		si.si_pid      = ta->pid; /* who is sending */
-
+		si.si_pid      = task->pid; /* who is sending */
 
 		si.si_signo    = ctx->ctx_notify_sig; /* is SIGPROF */
 		si.si_code     = PROF_OVFL; /* goes to user */
 		si.si_pfm_ovfl = bv;
 
 
+	
 		/*
-		 * in this case, we don't stop the task, we let it go on. It will
-		 * necessarily go to the signal handler (if any) when it goes back to
-		 * user mode.
+		 * when the target of the signal is not ourself, we have to be more
+		 * careful. The notify_task may being cleared by the target task itself
+		 * in release_thread(). We must ensure mutual exclusion here such that
+		 * the signal is delivered (even to a dying task) safely.
 		 */
-		DBprintk((" sending %d notification to self %d\n", si.si_signo, ta->pid));
-
 
-		/* this call is safe in an interrupt handler */
-		ret = send_sig_info(ctx->ctx_notify_sig, &si, ta);
-		if (ret != 0)
-			printk(" send_sig_info(process %d, SIGPROF)=%d\n", ta->pid, ret);
-		/*
-		 * no matter if we block or not, we keep PMU frozen and do not unfreeze on ctxsw
-		 */
-		ctx->ctx_fl_frozen = 1;
+		if (ctx->ctx_notify_task != current) {
+			/*
+			 * grab the notification lock for this task
+			 */
+			spin_lock(&ctx->ctx_notify_lock);
 
-	} else {
-#if 0
 			/*
-			 * The tasklet is guaranteed to be scheduled for this CPU only
+			 * now notify_task cannot be modified until we're done
+			 * if NULL, they it got modified while we were in the handler
 			 */
-			notify_info[my_cpu].to_pid   = ctx->notify_pid;
-			notify_info[my_cpu].from_pid = ta->pid; /* for debug only */
-			notify_info[my_cpu].bitvect  = bv;
-			/* tasklet is inserted and active */
-			tasklet_schedule(&pfm_tasklet);
-#endif
+			if (ctx->ctx_notify_task = NULL) {
+				spin_unlock(&ctx->ctx_notify_lock);
+				goto lost_notify;
+			}
 			/*
-			 * stored the vector of overflowed registers for use in notification
-			 * mark that a notification/blocking is pending (arm the trap)
+			 * required by send_sig_info() to make sure the target
+			 * task does not disappear on us.
 			 */
-		th->pfm_pend_notify = 1;
+			read_lock(&tasklist_lock);
+		}
+		/*
+	 	 * in this case, we don't stop the task, we let it go on. It will
+	 	 * necessarily go to the signal handler (if any) when it goes back to
+	 	 * user mode.
+	 	 */
+		DBprintk((" %d sending %d notification to %d\n", task->pid, si.si_signo, ctx->ctx_notify_task->pid));
+
+
+		/* 
+		 * this call is safe in an interrupt handler, so does read_lock() on tasklist_lock
+		 */
+		ret = send_sig_info(ctx->ctx_notify_sig, &si, ctx->ctx_notify_task);
+		if (ret != 0) printk(" send_sig_info(process %d, SIGPROF)=%d\n",  ctx->ctx_notify_task->pid, ret);
+		/*
+		 * now undo the protections in order
+		 */
+		if (ctx->ctx_notify_task != current) {
+			read_unlock(&tasklist_lock);
+			spin_unlock(&ctx->ctx_notify_lock);
+		}
 
 		/*
-		 * if we do block, then keep PMU frozen until restart
+		 * if we block set the pfm_must_block bit
+		 * when in block mode, we can effectively block only when the notified
+		 * task is not self, otherwise we would deadlock. 
+		 * in this configuration, the notification is sent, the task will not 
+		 * block on the way back to user mode, but the PMU will be kept frozen
+		 * until PFM_RESTART.
+		 * Note that here there is still a race condition with notify_task
+		 * possibly being nullified behind our back, but this is fine because
+		 * it can only be changed to NULL which by construction, can only be
+		 * done when notify_task != current. So if it was already different
+		 * before, changing it to NULL will still maintain this invariant.
+		 * Of course, when it is equal to current it cannot change at this point.
 		 */
-		if (!CTX_OVFL_NOBLOCK(ctx)) ctx->ctx_fl_frozen = 1;
+		if (!CTX_OVFL_NOBLOCK(ctx) && ctx->ctx_notify_task != current) {
+				th->pfm_must_block = 1; /* will cause blocking */
+		}
+	} else {
+lost_notify:
+		DBprintk((" notification task has disappeared !\n"));
+		/*
+		 * for a non-blocking context, we make sure we do not fall into the pfm_overflow_notify()
+		 * trap. Also in the case of a blocking context with lost notify process, then we do not
+		 * want to block either (even though it is interruptible). In this case, the PMU will be kept
+		 * frozen and the process will run to completion without monitoring enabled.
+		 *
+		 * Of course, we cannot loose notify process when self-monitoring.
+		 */
+		th->pfm_must_block = 0; 
 
-		DBprintk((" process %d notify ovfl_regs=0x%lx\n", ta->pid, bv));
 	}
 	/*
-	 * keep PMU frozen (and overflowed bits cleared) when we have to stop,
-	 * otherwise return a resume 'value' for PMC[0]
-	 *
-	 * XXX: maybe that's enough to get rid of ctx_fl_frozen ?
+	 * if we block, we keep the PMU frozen. If non-blocking we restart.
+	 * in the case of non-blocking were the notify process is lost, we also 
+	 * restart. 
 	 */
-	DBprintk((" will return pmc0=0x%x\n",ctx->ctx_fl_frozen ? 0x1 : 0x0));
+	if (!CTX_OVFL_NOBLOCK(ctx)) 
+		ctx->ctx_fl_frozen  = 1;
+	else
+		ctx->ctx_fl_frozen = 0;
+
+	DBprintk((" reload pmc0=0x%x must_block=%ld\n",
+				ctx->ctx_fl_frozen ? 0x1 : 0x0, th->pfm_must_block));
+
 	return ctx->ctx_fl_frozen ? 0x1 : 0x0;
 }
 
@@ -1595,10 +1782,17 @@
 	u64 pmc0 = ia64_get_pmc(0);
 	int i;
 
-	p += sprintf(p, "PMC[0]=%lx\nPerfmon debug: %s\n", pmc0, pfm_debug ? "On" : "Off");
+	p += sprintf(p, "CPU%d.pmc[0]=%lx\nPerfmon debug: %s\n", smp_processor_id(), pmc0, pfm_debug ? "On" : "Off");
+	p += sprintf(p, "proc_sessions=%lu sys_sessions=%lu\n", 
+			pfs_info.pfs_proc_sessions, 
+			pfs_info.pfs_sys_session);
+
 	for(i=0; i < NR_CPUS; i++) {
-		if (cpu_is_online(i))
-			p += sprintf(p, "CPU%d.PMU %d\n", i, pmu_owners[i].owner ? pmu_owners[i].owner->pid: 0);
+		if (cpu_is_online(i)) {
+			p += sprintf(p, "CPU%d.pmu_owner: %-6d\n",
+					i, 
+					pmu_owners[i].owner ? pmu_owners[i].owner->pid: -1);
+		}
 	}
 	return p - page;
 }
@@ -1648,8 +1842,8 @@
 	}
 	pmu_conf.perf_ovfl_val = (1L << pm_info.pal_perf_mon_info_s.width) - 1;
 	pmu_conf.max_counters  = pm_info.pal_perf_mon_info_s.generic;
-	pmu_conf.num_pmds      = find_num_pm_regs(pmu_conf.impl_regs);
-	pmu_conf.num_pmcs      = find_num_pm_regs(&pmu_conf.impl_regs[4]);
+	pmu_conf.num_pmcs      = find_num_pm_regs(pmu_conf.impl_regs);
+	pmu_conf.num_pmds      = find_num_pm_regs(&pmu_conf.impl_regs[4]);
 
 	printk("perfmon: %d bits counters (max value 0x%lx)\n", pm_info.pal_perf_mon_info_s.width, pmu_conf.perf_ovfl_val);
 	printk("perfmon: %ld PMC/PMD pairs, %ld PMCs, %ld PMDs\n", pmu_conf.max_counters, pmu_conf.num_pmcs, pmu_conf.num_pmds);
@@ -1681,21 +1875,19 @@
 	ia64_srlz_d();
 }
 
-/*
- * XXX: for system wide this function MUST never be called
- */
 void
 pfm_save_regs (struct task_struct *ta)
 {
 	struct task_struct *owner;
+	pfm_context_t *ctx;
 	struct thread_struct *t;
 	u64 pmc0, psr;
+	unsigned long mask;
 	int i;
 
-	if (ta = NULL) {
-		panic(__FUNCTION__" task is NULL\n");
-	}
-	t = &ta->thread;
+	t   = &ta->thread;
+	ctx = ta->thread.pfm_context;
+
 	/*
 	 * We must make sure that we don't loose any potential overflow
 	 * interrupt while saving PMU context. In this code, external
@@ -1715,7 +1907,7 @@
 	 * in kernel.
 	 * By now, we could still have an overflow interrupt in-flight.
 	 */
-	__asm__ __volatile__ ("rum psr.up;;"::: "memory");
+	__asm__ __volatile__ ("rsm psr.up|psr.pp;;"::: "memory");
 
 	/*
 	 * Mark the PMU as not owned
@@ -1744,7 +1936,6 @@
 	 * next process does not start with monitoring on if not requested
 	 */
 	ia64_set_pmc(0, 1);
-	ia64_srlz_d();
 
 	/*
 	 * Check for overflow bits and proceed manually if needed
@@ -1755,94 +1946,111 @@
 	 * next time the task exits from the kernel.
 	 */
 	if (pmc0 & ~0x1) {
-		if (owner != ta) printk(__FUNCTION__" owner=%p task=%p\n", (void *)owner, (void *)ta);
-		printk(__FUNCTION__" Warning: pmc[0]=0x%lx explicit call\n", pmc0);
-
-		pmc0 = update_counters(owner, pmc0, NULL);
+		update_counters(owner, pmc0, NULL);
 		/* we will save the updated version of pmc0 */
 	}
-
 	/*
 	 * restore PSR for context switch to save
 	 */
 	__asm__ __volatile__ ("mov psr.l=%0;; srlz.i;;"::"r"(psr): "memory");
 
+	/*
+	 * we do not save registers if we can do lazy
+	 */
+	if (PFM_CAN_DO_LAZY()) {
+		SET_PMU_OWNER(owner);
+		return;
+	}
 
 	/*
 	 * XXX needs further optimization.
 	 * Also must take holes into account
 	 */
-	for (i=0; i< pmu_conf.num_pmds; i++) {
-		t->pmd[i] = ia64_get_pmd(i);
+	mask = ctx->ctx_used_pmds[0];
+	for (i=0; mask; i++, mask>>=1) {
+		if (mask & 0x1) t->pmd[i] =ia64_get_pmd(i);
 	}
 
 	/* skip PMC[0], we handle it separately */
-	for (i=1; i< pmu_conf.num_pmcs; i++) {
-		t->pmc[i] = ia64_get_pmc(i);
+	mask = ctx->ctx_used_pmcs[0]>>1;
+	for (i=1; mask; i++, mask>>=1) {
+		if (mask & 0x1) t->pmc[i] = ia64_get_pmc(i);
 	}
-
 	/*
 	 * Throughout this code we could have gotten an overflow interrupt. It is transformed
 	 * into a spurious interrupt as soon as we give up pmu ownership.
 	 */
 }
 
-void
-pfm_load_regs (struct task_struct *ta)
+static void
+pfm_lazy_save_regs (struct task_struct *ta)
 {
-	struct thread_struct *t = &ta->thread;
-	pfm_context_t *ctx = ta->thread.pfm_context;
+	pfm_context_t *ctx;
+	struct thread_struct *t;
+	unsigned long mask;
 	int i;
 
+	DBprintk(("  on [%d] by [%d]\n", ta->pid, current->pid));
+
+	t   = &ta->thread;
+	ctx = ta->thread.pfm_context;
 	/*
 	 * XXX needs further optimization.
 	 * Also must take holes into account
 	 */
-	for (i=0; i< pmu_conf.num_pmds; i++) {
-		ia64_set_pmd(i, t->pmd[i]);
+	mask = ctx->ctx_used_pmds[0];
+	for (i=0; mask; i++, mask>>=1) {
+		if (mask & 0x1) t->pmd[i] =ia64_get_pmd(i);
 	}
-
-	/* skip PMC[0] to avoid side effects */
-	for (i=1; i< pmu_conf.num_pmcs; i++) {
-		ia64_set_pmc(i, t->pmc[i]);
+	
+	/* skip PMC[0], we handle it separately */
+	mask = ctx->ctx_used_pmcs[0]>>1;
+	for (i=1; mask; i++, mask>>=1) {
+		if (mask & 0x1) t->pmc[i] = ia64_get_pmc(i);
 	}
+	SET_PMU_OWNER(NULL);
+}
+
+void
+pfm_load_regs (struct task_struct *ta)
+{
+	struct thread_struct *t = &ta->thread;
+	pfm_context_t *ctx = ta->thread.pfm_context;
+	struct task_struct *owner;
+	unsigned long mask;
+	int i;
+
+	owner = PMU_OWNER();
+	if (owner = ta) goto skip_restore;
+	if (owner) pfm_lazy_save_regs(owner);
 
-	/*
-	 * we first restore ownership of the PMU to the 'soon to be current'
-	 * context. This way, if, as soon as we unfreeze the PMU at the end
-	 * of this function, we get an interrupt, we attribute it to the correct
-	 * task
-	 */
 	SET_PMU_OWNER(ta);
 
-#if 0
-	/*
-	 * check if we had pending overflow before context switching out
-	 * If so, we invoke the handler manually, i.e. simulate interrupt.
-	 *
-	 * XXX: given that we do not use the tasklet anymore to stop, we can
-	 * move this back to the pfm_save_regs() routine.
-	 */
-	if (t->pmc[0] & ~0x1) {
-		/* freeze set in pfm_save_regs() */
-		DBprintk((" pmc[0]=0x%lx manual interrupt\n",t->pmc[0]));
-		update_counters(ta, t->pmc[0], NULL);
+	mask = ctx->ctx_used_pmds[0];
+	for (i=0; mask; i++, mask>>=1) {
+		if (mask & 0x1) ia64_set_pmd(i, t->pmd[i]);
 	}
-#endif
 
+	/* skip PMC[0] to avoid side effects */
+	mask = ctx->ctx_used_pmcs[0]>>1;
+	for (i=1; mask; i++, mask>>=1) {
+		if (mask & 0x1) ia64_set_pmc(i, t->pmc[i]);
+	}
+skip_restore:
 	/*
 	 * unfreeze only when possible
 	 */
 	if (ctx->ctx_fl_frozen = 0) {
 		ia64_set_pmc(0, 0);
 		ia64_srlz_d();
+		/* place where we potentially (kernel level) start monitoring again */
 	}
 }
 
 
 /*
  * This function is called when a thread exits (from exit_thread()).
- * This is a simplified pfm_save_regs() that simply flushes hthe current
+ * This is a simplified pfm_save_regs() that simply flushes the current
  * register state into the save area taking into account any pending
  * overflow. This time no notification is sent because the taks is dying
  * anyway. The inline processing of overflows avoids loosing some counts.
@@ -1933,12 +2141,20 @@
 		/* collect latest results */
 		ctx->ctx_pmds[i].val += ia64_get_pmd(j) & pmu_conf.perf_ovfl_val;
 
+		/*
+		 * now everything is in ctx_pmds[] and we need
+		 * to clear the saved context from save_regs() such that
+		 * pfm_read_pmds() gets the correct value
+		 */
+		ta->thread.pmd[j] = 0;
+
 		/* take care of overflow inline */
 		if (mask & 0x1) {
 			ctx->ctx_pmds[i].val += 1 + pmu_conf.perf_ovfl_val;
 			DBprintk((" PMD[%d] overflowed pmd=0x%lx pmds.val=0x%lx\n",
 			j, ia64_get_pmd(j), ctx->ctx_pmds[i].val));
 		}
+		mask >>=1;
 	}
 }
 
@@ -1977,7 +2193,7 @@
 
 	/* clears all PMD registers */
 	for(i=0;i< pmu_conf.num_pmds; i++) {
-		if (PMD_IS_IMPL(i)) ia64_set_pmd(i,0);
+		if (PMD_IS_IMPL(i))  ia64_set_pmd(i,0);
 	}
 	ia64_srlz_d();
 }
@@ -1986,7 +2202,7 @@
  * task is the newly created task
  */
 int
-pfm_inherit(struct task_struct *task)
+pfm_inherit(struct task_struct *task, struct pt_regs *regs)
 {
 	pfm_context_t *ctx = current->thread.pfm_context;
 	pfm_context_t *nctx;
@@ -1994,12 +2210,22 @@
 	int i, cnum;
 
 	/*
+	 * bypass completely for system wide
+	 */
+	if (pfs_info.pfs_sys_session) {
+		DBprintk((" enabling psr.pp for %d\n", task->pid));
+		ia64_psr(regs)->pp = pfs_info.pfs_pp;
+		return 0;
+	}
+
+	/*
 	 * takes care of easiest case first
 	 */
 	if (CTX_INHERIT_MODE(ctx) = PFM_FL_INHERIT_NONE) {
 		DBprintk((" removing PFM context for %d\n", task->pid));
 		task->thread.pfm_context     = NULL;
-		task->thread.pfm_pend_notify = 0;
+		task->thread.pfm_must_block  = 0;
+		atomic_set(&task->thread.pfm_notifiers_check, 0);
 		/* copy_thread() clears IA64_THREAD_PM_VALID */
 		return 0;
 	}
@@ -2009,9 +2235,11 @@
 	/* copy content */
 	*nctx = *ctx;
 
-	if (ctx->ctx_fl_inherit = PFM_FL_INHERIT_ONCE) {
+	if (CTX_INHERIT_MODE(ctx) = PFM_FL_INHERIT_ONCE) {
 		nctx->ctx_fl_inherit = PFM_FL_INHERIT_NONE;
+		atomic_set(&task->thread.pfm_notifiers_check, 0);
 		DBprintk((" downgrading to INHERIT_NONE for %d\n", task->pid));
+		pfs_info.pfs_proc_sessions++;
 	}
 
 	/* initialize counters in new context */
@@ -2033,7 +2261,7 @@
 	sema_init(&nctx->ctx_restart_sem, 0); /* reset this semaphore to locked */
 
 	/* clear pending notification */
-	th->pfm_pend_notify = 0;
+	th->pfm_must_block = 0;
 
 	/* link with new task */
 	th->pfm_context     = nctx;
@@ -2052,7 +2280,10 @@
 	return 0;
 }
 
-/* called from exit_thread() */
+/* 
+ * called from release_thread(), at this point this task is not in the 
+ * tasklist anymore
+ */
 void
 pfm_context_exit(struct task_struct *task)
 {
@@ -2068,16 +2299,126 @@
 		pfm_smpl_buffer_desc_t *psb = ctx->ctx_smpl_buf;
 
 		/* if only user left, then remove */
-		DBprintk((" pid %d: task %d sampling psb->refcnt=%d\n", current->pid, task->pid, psb->psb_refcnt.counter));
+		DBprintk((" [%d] [%d] psb->refcnt=%d\n", current->pid, task->pid, psb->psb_refcnt.counter));
 
 		if (atomic_dec_and_test(&psb->psb_refcnt) ) {
 			rvfree(psb->psb_hdr, psb->psb_size);
 			vfree(psb);
-			DBprintk((" pid %d: cleaning task %d sampling buffer\n", current->pid, task->pid ));
+			DBprintk((" [%d] cleaning [%d] sampling buffer\n", current->pid, task->pid ));
+		}
+	}
+	DBprintk((" [%d] cleaning [%d] pfm_context @%p\n", current->pid, task->pid, (void *)ctx));
+
+	/*
+	 * To avoid getting the notified task scan the entire process list
+	 * when it exits because it would have pfm_notifiers_check set, we 
+	 * decrease it by 1 to inform the task, that one less task is going
+	 * to send it notification. each new notifer increases this field by
+	 * 1 in pfm_context_create(). Of course, there is race condition between
+	 * decreasing the value and the notified task exiting. The danger comes
+	 * from the fact that we have a direct pointer to its task structure
+	 * thereby bypassing the tasklist. We must make sure that if we have 
+	 * notify_task!= NULL, the target task is still somewhat present. It may
+	 * already be detached from the tasklist but that's okay. Note that it is
+	 * okay if we 'miss the deadline' and the task scans the list for nothing,
+	 * it will affect performance but not correctness. The correctness is ensured
+	 * by using the notify_lock whic prevents the notify_task from changing on us.
+	 * Once holdhing this lock, if we see notify_task!= NULL, then it will stay like
+	 * that until we release the lock. If it is NULL already then we came too late.
+	 */
+	spin_lock(&ctx->ctx_notify_lock);
+
+	if (ctx->ctx_notify_task) {
+		DBprintk((" [%d] [%d] atomic_sub on [%d] notifiers=%u\n", current->pid, task->pid,
+					ctx->ctx_notify_task->pid, 
+					atomic_read(&ctx->ctx_notify_task->thread.pfm_notifiers_check)));
+
+		atomic_sub(1, &ctx->ctx_notify_task->thread.pfm_notifiers_check);
+	}
+
+	spin_unlock(&ctx->ctx_notify_lock);
+
+	if (ctx->ctx_fl_system) {
+		/*
+		 * if included interrupts (true by default), then reset
+		 * to get default value
+		 */
+		if (ctx->ctx_fl_exclintr = 0) {
+			/*
+			 * reload kernel default DCR value
+			 */
+			ia64_set_dcr(pfs_info.pfs_dfl_dcr);
+			DBprintk((" restored dcr to 0x%lx\n", pfs_info.pfs_dfl_dcr));
 		}
+		/* 
+		 * free system wide session slot
+		 */
+		pfs_info.pfs_sys_session = 0;
+	} else {
+		pfs_info.pfs_proc_sessions--;
 	}
-	DBprintk((" pid %d: task %d pfm_context is freed @%p\n", current->pid, task->pid, (void *)ctx));
+
 	pfm_context_free(ctx);
+	/* 
+	 *  clean pfm state in thread structure,
+	 */
+	task->thread.pfm_context    = NULL;
+	task->thread.pfm_must_block = 0;
+	/* pfm_notifiers is cleaned in pfm_cleanup_notifiers() */
+
+}
+
+void
+pfm_cleanup_notifiers(struct task_struct *task)
+{
+	struct task_struct *p;
+	pfm_context_t *ctx;
+
+	DBprintk((" [%d] called\n", task->pid));
+
+	read_lock(&tasklist_lock);
+
+	for_each_task(p) {
+		/*
+		 * It is safe to do the 2-step test here, because thread.ctx
+		 * is cleaned up only in release_thread() and at that point
+		 * the task has been detached from the tasklist which is an
+		 * operation which uses the write_lock() on the tasklist_lock
+		 * so it cannot run concurrently to this loop. So we have the
+		 * guarantee that if we find p and it has a perfmon ctx then
+		 * it is going to stay like this for the entire execution of this
+		 * loop.
+		 */
+		ctx = p->thread.pfm_context;
+
+		DBprintk((" [%d] scanning task [%d] ctx=%p\n", task->pid, p->pid, ctx));
+
+		if (ctx && ctx->ctx_notify_task = task) {
+			DBprintk((" trying for notifier %d in %d\n", task->pid, p->pid));
+			/*
+			 * the spinlock is required to take care of a race condition
+			 * with the send_sig_info() call. We must make sure that 
+			 * either the send_sig_info() completes using a valid task,
+			 * or the notify_task is cleared before the send_sig_info()
+			 * can pick up a stale value. Note that by the time this
+			 * function is executed the 'task' is already detached from the
+			 * tasklist. The problem is that the notifiers have a direct
+			 * pointer to it. It is okay to send a signal to a task in this
+			 * stage, it simply will have no effect. But it is better than sending
+			 * to a completely destroyed task or worse to a new task using the same
+			 * task_struct address.
+			 */
+			spin_lock(&ctx->ctx_notify_lock);
+
+			ctx->ctx_notify_task = NULL;
+
+			spin_unlock(&ctx->ctx_notify_lock);
+
+			DBprintk((" done for notifier %d in %d\n", task->pid, p->pid));
+		}
+	}
+	read_unlock(&tasklist_lock);
+
 }
 
 #else /* !CONFIG_PERFMON */
diff -urN linux-2.4.13/arch/ia64/kernel/process.c linux-2.4.13-lia/arch/ia64/kernel/process.c
--- linux-2.4.13/arch/ia64/kernel/process.c	Wed Oct 10 16:31:44 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/process.c	Wed Oct 24 18:14:43 2001
@@ -63,7 +63,8 @@
 {
 	unsigned long ip = regs->cr_iip + ia64_psr(regs)->ri;
 
-	printk("\npsr : %016lx ifs : %016lx ip  : [<%016lx>]    %s\n",
+	printk("\nPid: %d, comm: %20s\n", current->pid, current->comm);
+	printk("psr : %016lx ifs : %016lx ip  : [<%016lx>]    %s\n",
 	       regs->cr_ipsr, regs->cr_ifs, ip, print_tainted());
 	printk("unat: %016lx pfs : %016lx rsc : %016lx\n",
 	       regs->ar_unat, regs->ar_pfs, regs->ar_rsc);
@@ -201,7 +202,7 @@
 {
 	unsigned long rbs, child_rbs, rbs_size, stack_offset, stack_top, stack_used;
 	struct switch_stack *child_stack, *stack;
-	extern char ia64_ret_from_clone;
+	extern char ia64_ret_from_clone, ia32_ret_from_clone;
 	struct pt_regs *child_ptregs;
 	int retval = 0;
 
@@ -250,7 +251,10 @@
 		child_ptregs->r12 = (unsigned long) (child_ptregs + 1); /* kernel sp */
 		child_ptregs->r13 = (unsigned long) p;		/* set `current' pointer */
 	}
-	child_stack->b0 = (unsigned long) &ia64_ret_from_clone;
+	if (IS_IA32_PROCESS(regs))
+		child_stack->b0 = (unsigned long) &ia32_ret_from_clone;
+	else
+		child_stack->b0 = (unsigned long) &ia64_ret_from_clone;
 	child_stack->ar_bspstore = child_rbs + rbs_size;
 
 	/* copy parts of thread_struct: */
@@ -285,9 +289,8 @@
 		ia32_save_state(p);
 #endif
 #ifdef CONFIG_PERFMON
-	p->thread.pfm_pend_notify = 0;
 	if (p->thread.pfm_context)
-		retval = pfm_inherit(p);
+		retval = pfm_inherit(p, child_ptregs);
 #endif
 	return retval;
 }
@@ -441,11 +444,24 @@
 }
 
 #ifdef CONFIG_PERFMON
+/*
+ * By the time we get here, the task is detached from the tasklist. This is important
+ * because it means that no other tasks can ever find it as a notifiied task, therfore
+ * there is no race condition between this code and let's say a pfm_context_create().
+ * Conversely, the pfm_cleanup_notifiers() cannot try to access a task's pfm context if
+ * this other task is in the middle of its own pfm_context_exit() because it would alreayd
+ * be out of the task list. Note that this case is very unlikely between a direct child
+ * and its parents (if it is the notified process) because of the way the exit is notified
+ * via SIGCHLD.
+ */
 void
 release_thread (struct task_struct *task)
 {
 	if (task->thread.pfm_context)
 		pfm_context_exit(task);
+
+	if (atomic_read(&task->thread.pfm_notifiers_check) > 0)
+		pfm_cleanup_notifiers(task);
 }
 #endif
 
@@ -516,6 +532,29 @@
 }
 
 void
+cpu_halt (void)
+{
+	pal_power_mgmt_info_u_t power_info[8];
+	unsigned long min_power;
+	int i, min_power_state;
+
+	if (ia64_pal_halt_info(power_info) != 0)
+		return;
+
+	min_power_state = 0;
+	min_power = power_info[0].pal_power_mgmt_info_s.power_consumption;
+	for (i = 1; i < 8; ++i)
+		if (power_info[i].pal_power_mgmt_info_s.im
+		    && power_info[i].pal_power_mgmt_info_s.power_consumption < min_power) {
+			min_power = power_info[i].pal_power_mgmt_info_s.power_consumption;
+			min_power_state = i;
+		}
+
+	while (1)
+		ia64_pal_halt(min_power_state);
+}
+
+void
 machine_restart (char *restart_cmd)
 {
 	(*efi.reset_system)(EFI_RESET_WARM, 0, 0, 0);
@@ -524,6 +563,7 @@
 void
 machine_halt (void)
 {
+	cpu_halt();
 }
 
 void
@@ -531,4 +571,5 @@
 {
 	if (pm_power_off)
 		pm_power_off();
+	machine_halt();
 }
diff -urN linux-2.4.13/arch/ia64/kernel/ptrace.c linux-2.4.13-lia/arch/ia64/kernel/ptrace.c
--- linux-2.4.13/arch/ia64/kernel/ptrace.c	Mon Sep 24 15:06:13 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/ptrace.c	Wed Oct 10 17:43:07 2001
@@ -2,7 +2,7 @@
  * Kernel support for the ptrace() and syscall tracing interfaces.
  *
  * Copyright (C) 1999-2001 Hewlett-Packard Co
- * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * Derived from the x86 and Alpha versions.  Most of the code in here
  * could actually be factored into a common set of routines.
@@ -794,11 +794,14 @@
  *
  * Make sure the single step bit is not set.
  */
-void ptrace_disable(struct task_struct *child)
+void
+ptrace_disable (struct task_struct *child)
 {
+	struct ia64_psr *child_psr = ia64_psr(ia64_task_regs(child));
+
 	/* make sure the single step/take-branch tra bits are not set: */
-	ia64_psr(pt)->ss = 0;
-	ia64_psr(pt)->tb = 0;
+	child_psr->ss = 0;
+	child_psr->tb = 0;
 
 	/* Turn off flag indicating that the KRBS is sync'd with child's VM: */
 	child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED;
@@ -809,7 +812,7 @@
 	    long arg4, long arg5, long arg6, long arg7, long stack)
 {
 	struct pt_regs *pt, *regs = (struct pt_regs *) &stack;
-	unsigned long flags, urbs_end;
+	unsigned long urbs_end;
 	struct task_struct *child;
 	struct switch_stack *sw;
 	long ret;
@@ -855,6 +858,19 @@
 	if (child->p_pptr != current)
 		goto out_tsk;
 
+	if (request != PTRACE_KILL) {
+		if (child->state != TASK_STOPPED)
+			goto out_tsk;
+
+#ifdef CONFIG_SMP
+		while (child->has_cpu) {
+			if (child->state != TASK_STOPPED)
+				goto out_tsk;
+			barrier();
+		}
+#endif
+	}
+
 	pt = ia64_task_regs(child);
 	sw = (struct switch_stack *) (child->thread.ksp + 16);
 
@@ -925,7 +941,7 @@
 			child->ptrace &= ~PT_TRACESYS;
 		child->exit_code = data;
 
-		/* make sure the single step/take-branch tra bits are not set: */
+		/* make sure the single step/taken-branch trap bits are not set: */
 		ia64_psr(pt)->ss = 0;
 		ia64_psr(pt)->tb = 0;
 
diff -urN linux-2.4.13/arch/ia64/kernel/sal.c linux-2.4.13-lia/arch/ia64/kernel/sal.c
--- linux-2.4.13/arch/ia64/kernel/sal.c	Thu Jan  4 12:50:17 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/sal.c	Thu Oct  4 00:21:39 2001
@@ -1,8 +1,8 @@
 /*
  * System Abstraction Layer (SAL) interface routines.
  *
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
  */
@@ -18,8 +18,6 @@
 #include <asm/sal.h>
 #include <asm/pal.h>
 
-#define SAL_DEBUG
-
 spinlock_t sal_lock = SPIN_LOCK_UNLOCKED;
 
 static struct {
@@ -122,10 +120,8 @@
 		switch (*p) {
 		      case SAL_DESC_ENTRY_POINT:
 			ep = (struct ia64_sal_desc_entry_point *) p;
-#ifdef SAL_DEBUG
-			printk("sal[%d] - entry: pal_proc=0x%lx, sal_proc=0x%lx\n",
-			       i, ep->pal_proc, ep->sal_proc);
-#endif
+			printk("SAL: entry: pal_proc=0x%lx, sal_proc=0x%lx\n",
+			       ep->pal_proc, ep->sal_proc);
 			ia64_pal_handler_init(__va(ep->pal_proc));
 			ia64_sal_handler_init(__va(ep->sal_proc), __va(ep->gp));
 			break;
@@ -138,17 +134,12 @@
 #ifdef CONFIG_SMP
 		      {
 			      struct ia64_sal_desc_ap_wakeup *ap = (void *) p;
-# ifdef SAL_DEBUG
-			      printk("sal[%d] - wakeup type %x, 0x%lx\n",
-				     i, ap->mechanism, ap->vector);
-# endif
+
 			      switch (ap->mechanism) {
 				    case IA64_SAL_AP_EXTERNAL_INT:
 				      ap_wakeup_vector = ap->vector;
-# ifdef SAL_DEBUG
 				      printk("SAL: AP wakeup using external interrupt "
 					     "vector 0x%lx\n", ap_wakeup_vector);
-# endif
 				      break;
 
 				    default:
@@ -163,21 +154,13 @@
 			      struct ia64_sal_desc_platform_feature *pf = (void *) p;
 			      printk("SAL: Platform features ");
 
-#ifdef CONFIG_IA64_HAVE_IRQREDIR
-			      /*
-			       * Early versions of SAL say we don't have
-			       * IRQ redirection, even though we do...
-			       */
-			      pf->feature_mask |= (1 << 1);
-#endif
-
 			      if (pf->feature_mask & (1 << 0))
 				      printk("BusLock ");
 
 			      if (pf->feature_mask & (1 << 1)) {
 				      printk("IRQ_Redirection ");
 #ifdef CONFIG_SMP
-				      if (no_int_routing) 
+				      if (no_int_routing)
 					      smp_int_redirect &= ~SMP_IRQ_REDIRECTION;
 				      else
 					      smp_int_redirect |= SMP_IRQ_REDIRECTION;
diff -urN linux-2.4.13/arch/ia64/kernel/setup.c linux-2.4.13-lia/arch/ia64/kernel/setup.c
--- linux-2.4.13/arch/ia64/kernel/setup.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/setup.c	Thu Oct  4 00:21:39 2001
@@ -534,10 +534,13 @@
 	/*
 	 * Initialize default control register to defer all speculative faults.  The
 	 * kernel MUST NOT depend on a particular setting of these bits (in other words,
-	 * the kernel must have recovery code for all speculative accesses).
+	 * the kernel must have recovery code for all speculative accesses).  Turn on
+	 * dcr.lc as per recommendation by the architecture team.  Most IA-32 apps
+	 * shouldn't be affected by this (moral: keep your ia32 locks aligned and you'll
+	 * be fine).
 	 */
 	ia64_set_dcr(  IA64_DCR_DM | IA64_DCR_DP | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_DR
-		     | IA64_DCR_DA | IA64_DCR_DD);
+		     | IA64_DCR_DA | IA64_DCR_DD | IA64_DCR_LC);
 #ifndef CONFIG_SMP
 	ia64_set_fpu_owner(0);
 #endif
diff -urN linux-2.4.13/arch/ia64/kernel/sigframe.h linux-2.4.13-lia/arch/ia64/kernel/sigframe.h
--- linux-2.4.13/arch/ia64/kernel/sigframe.h	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/sigframe.h	Thu Oct  4 00:21:52 2001
@@ -1,3 +1,9 @@
+struct sigscratch {
+	unsigned long scratch_unat;	/* ar.unat for the general registers saved in pt */
+	unsigned long pad;
+	struct pt_regs pt;
+};
+
 struct sigframe {
 	/*
 	 * Place signal handler args where user-level unwinder can find them easily.
@@ -7,10 +13,11 @@
 	unsigned long arg0;		/* signum */
 	unsigned long arg1;		/* siginfo pointer */
 	unsigned long arg2;		/* sigcontext pointer */
+	/*
+	 * End of architected state.
+	 */
 
-	unsigned long rbs_base;		/* base of new register backing store (or NULL) */
 	void *handler;			/* pointer to the plabel of the signal handler */
-
 	struct siginfo info;
 	struct sigcontext sc;
 };
diff -urN linux-2.4.13/arch/ia64/kernel/signal.c linux-2.4.13-lia/arch/ia64/kernel/signal.c
--- linux-2.4.13/arch/ia64/kernel/signal.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/signal.c	Thu Oct  4 00:21:52 2001
@@ -2,7 +2,7 @@
  * Architecture-specific signal handling support.
  *
  * Copyright (C) 1999-2001 Hewlett-Packard Co
- * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * Derived from i386 and Alpha versions.
  */
@@ -39,12 +39,6 @@
 # define GET_SIGSET(k,u)	__get_user((k)->sig[0], &(u)->sig[0])
 #endif
 
-struct sigscratch {
-	unsigned long scratch_unat;	/* ar.unat for the general registers saved in pt */
-	unsigned long pad;
-	struct pt_regs pt;
-};
-
 extern long ia64_do_signal (sigset_t *, struct sigscratch *, long);	/* forward decl */
 
 long
@@ -55,6 +49,10 @@
 	/* XXX: Don't preclude handling different sized sigset_t's.  */
 	if (sigsetsize != sizeof(sigset_t))
 		return -EINVAL;
+
+	if (!access_ok(VERIFY_READ, uset, sigsetsize))
+		return -EFAULT;
+
 	if (GET_SIGSET(&set, uset))
 		return -EFAULT;
 
@@ -73,15 +71,9 @@
 	 * pre-set the correct error code here to ensure that the right values
 	 * get saved in sigcontext by ia64_do_signal.
 	 */
-#ifdef CONFIG_IA32_SUPPORT
-        if (IS_IA32_PROCESS(&scr->pt)) {
-                scr->pt.r8 = -EINTR;
-        } else
-#endif
-	{
-		scr->pt.r8 = EINTR;
-		scr->pt.r10 = -1;
-	}
+	scr->pt.r8 = EINTR;
+	scr->pt.r10 = -1;
+
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
@@ -139,10 +131,9 @@
 		struct ia64_psr *psr = ia64_psr(&scr->pt);
 
 		__copy_from_user(current->thread.fph, &sc->sc_fr[32], 96*16);
-		if (!psr->dfh) {
-			psr->mfh = 0;
+		psr->mfh = 0;	/* drop signal handler's fph contents... */
+		if (!psr->dfh)
 			__ia64_load_fpu(current->thread.fph);
-		}
 	}
 	return err;
 }
@@ -380,7 +371,8 @@
 	err  = __put_user(sig, &frame->arg0);
 	err |= __put_user(&frame->info, &frame->arg1);
 	err |= __put_user(&frame->sc, &frame->arg2);
-	err |= __put_user(new_rbs, &frame->rbs_base);
+	err |= __put_user(new_rbs, &frame->sc.sc_rbs_base);
+	err |= __put_user(0, &frame->sc.sc_loadrs);	/* initialize to zero */
 	err |= __put_user(ka->sa.sa_handler, &frame->handler);
 
 	err |= copy_siginfo_to_user(&frame->info, info);
@@ -460,6 +452,7 @@
 long
 ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
 {
+	struct signal_struct *sig;
 	struct k_sigaction *ka;
 	siginfo_t info;
 	long restart = in_syscall;
@@ -571,8 +564,8 @@
 			      case SIGSTOP:
 				current->state = TASK_STOPPED;
 				current->exit_code = signr;
-				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags
-				      & SA_NOCLDSTOP))
+				sig = current->p_pptr->sig;
+				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
 					notify_parent(current, SIGCHLD);
 				schedule();
 				continue;
diff -urN linux-2.4.13/arch/ia64/kernel/smp.c linux-2.4.13-lia/arch/ia64/kernel/smp.c
--- linux-2.4.13/arch/ia64/kernel/smp.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/smp.c	Wed Oct 10 18:50:56 2001
@@ -48,6 +48,7 @@
 #include <asm/sal.h>
 #include <asm/system.h>
 #include <asm/unistd.h>
+#include <asm/mca.h>
 
 /* The 'big kernel lock' */
 spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
@@ -70,20 +71,18 @@
 
 #define IPI_CALL_FUNC		0
 #define IPI_CPU_STOP		1
-#ifndef CONFIG_ITANIUM_PTCG
-# define IPI_FLUSH_TLB		2
-#endif  /*!CONFIG_ITANIUM_PTCG */
 
 static void
 stop_this_cpu (void)
 {
+	extern void cpu_halt (void);
 	/*
 	 * Remove this CPU:
 	 */
 	clear_bit(smp_processor_id(), &cpu_online_map);
 	max_xtp();
 	__cli();
-	for (;;);
+	cpu_halt();
 }
 
 void
@@ -136,49 +135,6 @@
 			stop_this_cpu();
 			break;
 
-#ifndef CONFIG_ITANIUM_PTCG
-		case IPI_FLUSH_TLB:
-		{
-			extern unsigned long flush_start, flush_end, flush_nbits, flush_rid;
-			extern atomic_t flush_cpu_count;
-			unsigned long saved_rid = ia64_get_rr(flush_start);
-			unsigned long end = flush_end;
-			unsigned long start = flush_start;
-			unsigned long nbits = flush_nbits;
-
-			/*
-			 * Current CPU may be running with different RID so we need to
-			 * reload the RID of flushed address.  Purging the translation
-			 * also needs ALAT invalidation; we do not need "invala" here
-			 * since it is done in ia64_leave_kernel.
-			 */
-			ia64_srlz_d();
-			if (saved_rid != flush_rid) {
-				ia64_set_rr(flush_start, flush_rid);
-				ia64_srlz_d();
-			}
-
-			do {
-				/*
-				 * Purge local TLB entries.
-				 */
-				__asm__ __volatile__ ("ptc.l %0,%1" ::
-						      "r"(start), "r"(nbits<<2) : "memory");
-				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();
-			}
-			atomic_dec(&flush_cpu_count);
-			break;
-		}
-#endif	/* !CONFIG_ITANIUM_PTCG */
-
 		default:
 			printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which);
 			break;
@@ -228,30 +184,6 @@
 	platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0);
 }
 
-#ifndef CONFIG_ITANIUM_PTCG
-
-void
-smp_send_flush_tlb (void)
-{
-	send_IPI_allbutself(IPI_FLUSH_TLB);
-}
-
-void
-smp_resend_flush_tlb (void)
-{
-	int i;
-
-	/*
-	 * Really need a null IPI but since this rarely should happen & since this code
-	 * will go away, lets not add one.
-	 */
-	for (i = 0; i < smp_num_cpus; ++i)
-		if (i != smp_processor_id())
-			smp_send_reschedule(i);
-}
-
-#endif  /* !CONFIG_ITANIUM_PTCG */
-
 void
 smp_flush_tlb_all (void)
 {
@@ -277,10 +209,6 @@
 {
 	struct call_data_struct data;
 	int cpus = 1;
-#if (defined(CONFIG_ITANIUM_B0_SPECIFIC) \
-     || defined(CONFIG_ITANIUM_B1_SPECIFIC) || defined(CONFIG_ITANIUM_B2_SPECIFIC))
-	unsigned long timeout;
-#endif
 
 	if (cpuid = smp_processor_id()) {
 		printk(__FUNCTION__" trying to call self\n");
@@ -295,26 +223,15 @@
 		atomic_set(&data.finished, 0);
 
 	spin_lock_bh(&call_lock);
-	call_data = &data;
-
-#if (defined(CONFIG_ITANIUM_B0_SPECIFIC) \
-     || defined(CONFIG_ITANIUM_B1_SPECIFIC) || defined(CONFIG_ITANIUM_B2_SPECIFIC))
-  resend:
-  	send_IPI_single(cpuid, IPI_CALL_FUNC);
 
-	/*  Wait for response */
-	timeout = jiffies + HZ;
-	while ((atomic_read(&data.started) != cpus) && time_before(jiffies, timeout))
-		barrier();
-	if (atomic_read(&data.started) != cpus)
-		goto resend;
-#else
+	call_data = &data;
+	mb();	/* ensure store to call_data precedes setting of IPI_CALL_FUNC */
   	send_IPI_single(cpuid, IPI_CALL_FUNC);
 
 	/* Wait for response */
 	while (atomic_read(&data.started) != cpus)
 		barrier();
-#endif
+
 	if (wait)
 		while (atomic_read(&data.finished) != cpus)
 			barrier();
@@ -348,10 +265,6 @@
 {
 	struct call_data_struct data;
 	int cpus = smp_num_cpus-1;
-#if (defined(CONFIG_ITANIUM_B0_SPECIFIC) \
-     || defined(CONFIG_ITANIUM_B1_SPECIFIC) || defined(CONFIG_ITANIUM_B2_SPECIFIC))
-	unsigned long timeout;
-#endif
 
 	if (!cpus)
 		return 0;
@@ -364,27 +277,14 @@
 		atomic_set(&data.finished, 0);
 
 	spin_lock_bh(&call_lock);
-	call_data = &data;
-
-#if (defined(CONFIG_ITANIUM_B0_SPECIFIC) \
-     || defined(CONFIG_ITANIUM_B1_SPECIFIC) || defined(CONFIG_ITANIUM_B2_SPECIFIC))
-  resend:
-	/*  Send a message to all other CPUs and wait for them to respond */
-	send_IPI_allbutself(IPI_CALL_FUNC);
 
-	/* Wait for response */
-	timeout = jiffies + HZ;
-	while ((atomic_read(&data.started) != cpus) && time_before(jiffies, timeout))
-		barrier();
-	if (atomic_read(&data.started) != cpus)
-		goto resend;
-#else
+	call_data = &data;
+	mb();	/* ensure store to call_data precedes setting of IPI_CALL_FUNC */
 	send_IPI_allbutself(IPI_CALL_FUNC);
 
 	/* Wait for response */
 	while (atomic_read(&data.started) != cpus)
 		barrier();
-#endif
 
 	if (wait)
 		while (atomic_read(&data.finished) != cpus)
diff -urN linux-2.4.13/arch/ia64/kernel/smpboot.c linux-2.4.13-lia/arch/ia64/kernel/smpboot.c
--- linux-2.4.13/arch/ia64/kernel/smpboot.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/smpboot.c	Thu Oct  4 00:21:39 2001
@@ -33,6 +33,7 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/machvec.h>
+#include <asm/mca.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
@@ -42,6 +43,8 @@
 #include <asm/system.h>
 #include <asm/unistd.h>
 
+#define SMP_DEBUG 0
+
 #if SMP_DEBUG
 #define Dprintk(x...)  printk(x)
 #else
@@ -310,7 +313,7 @@
 }
 
 
-void __init
+static void __init
 smp_callin (void)
 {
 	int cpuid, phys_id;
@@ -324,8 +327,7 @@
 	phys_id = hard_smp_processor_id();
 
 	if (test_and_set_bit(cpuid, &cpu_online_map)) {
-		printk("huh, phys CPU#0x%x, CPU#0x%x already present??\n", 
-					phys_id, cpuid);
+		printk("huh, phys CPU#0x%x, CPU#0x%x already present??\n", phys_id, cpuid);
 		BUG();
 	}
 
@@ -341,6 +343,12 @@
 	 * Get our bogomips.
 	 */
 	ia64_init_itm();
+
+#ifdef CONFIG_IA64_MCA
+	ia64_mca_cmc_vector_setup();	/* Setup vector on AP & enable */
+	ia64_mca_check_errors();	/* For post-failure MCA error logging */
+#endif
+
 #ifdef CONFIG_PERFMON
 	perfmon_init_percpu();
 #endif
@@ -364,14 +372,15 @@
 {
 	extern int cpu_idle (void);
 
+	Dprintk("start_secondary: starting CPU 0x%x\n", hard_smp_processor_id());
 	efi_map_pal_code();
 	cpu_init();
 	smp_callin();
-	Dprintk("CPU %d is set to go. \n", smp_processor_id());
+	Dprintk("CPU %d is set to go.\n", smp_processor_id());
 	while (!atomic_read(&smp_commenced))
 		;
 
-	Dprintk("CPU %d is starting idle. \n", smp_processor_id());
+	Dprintk("CPU %d is starting idle.\n", smp_processor_id());
 	return cpu_idle();
 }
 
@@ -415,7 +424,7 @@
 	unhash_process(idle);
 	init_tasks[cpu] = idle;
 
-	Dprintk("Sending Wakeup Vector to AP 0x%x/0x%x.\n", cpu, sapicid);
+	Dprintk("Sending wakeup vector %u to AP 0x%x/0x%x.\n", ap_wakeup_vector, cpu, sapicid);
 
 	platform_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0);
 
@@ -424,7 +433,6 @@
 	 */
 	Dprintk("Waiting on callin_map ...");
 	for (timeout = 0; timeout < 100000; timeout++) {
-		Dprintk(".");
 		if (test_bit(cpu, &cpu_callin_map))
 			break;  /* It has booted */
 		udelay(100);
diff -urN linux-2.4.13/arch/ia64/kernel/sys_ia64.c linux-2.4.13-lia/arch/ia64/kernel/sys_ia64.c
--- linux-2.4.13/arch/ia64/kernel/sys_ia64.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/sys_ia64.c	Thu Oct  4 00:21:39 2001
@@ -19,24 +19,29 @@
 #include <asm/shmparam.h>
 #include <asm/uaccess.h>
 
-#define COLOR_ALIGN(addr)	(((addr) + SHMLBA - 1) & ~(SHMLBA - 1))
-
 unsigned long
 arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len,
 			unsigned long pgoff, unsigned long flags)
 {
-	struct vm_area_struct * vmm;
 	long map_shared = (flags & MAP_SHARED);
+	unsigned long align_mask = PAGE_SIZE - 1;
+	struct vm_area_struct * vmm;
 
 	if (len > RGN_MAP_LIMIT)
 		return -ENOMEM;
 	if (!addr)
 		addr = TASK_UNMAPPED_BASE;
 
-	if (map_shared)
-		addr = COLOR_ALIGN(addr);
-	else
-		addr = PAGE_ALIGN(addr);
+	if (map_shared && (TASK_SIZE > 0xfffffffful))
+		/*
+		 * For 64-bit tasks, align shared segments to 1MB to avoid potential
+		 * performance penalty due to virtual aliasing (see ASDM).  For 32-bit
+		 * tasks, we prefer to avoid exhausting the address space too quickly by
+		 * limiting alignment to a single page.
+		 */
+		align_mask = SHMLBA - 1;
+
+	addr = (addr + align_mask) & ~align_mask;
 
 	for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
 		/* At this point:  (!vmm || addr < vmm->vm_end). */
@@ -46,9 +51,7 @@
 			return -ENOMEM;
 		if (!vmm || addr + len <= vmm->vm_start)
 			return addr;
-		addr = vmm->vm_end;
-		if (map_shared)
-			addr = COLOR_ALIGN(addr);
+		addr = (vmm->vm_end + align_mask) & ~align_mask;
 	}
 }
 
@@ -184,8 +187,10 @@
 		if (!file)
 			return -EBADF;
 
-		if (!file->f_op || !file->f_op->mmap)
-			return -ENODEV;
+		if (!file->f_op || !file->f_op->mmap) {
+			addr = -ENODEV;
+			goto out;
+		}
 	}
 
 	/*
@@ -194,22 +199,26 @@
 	 */
 	len = PAGE_ALIGN(len);
 	if (len = 0)
-		return addr;
+		goto out;
 
 	/* don't permit mappings into unmapped space or the virtual page table of a region: */
 	roff = rgn_offset(addr);
-	if ((len | roff | (roff + len)) >= RGN_MAP_LIMIT)
-		return -EINVAL;
+	if ((len | roff | (roff + len)) >= RGN_MAP_LIMIT) {
+		addr = -EINVAL;
+		goto out;
+	}
 
 	/* don't permit mappings that would cross a region boundary: */
-	if (rgn_index(addr) != rgn_index(addr + len))
-		return -EINVAL;
+	if (rgn_index(addr) != rgn_index(addr + len)) {
+		addr = -EINVAL;
+		goto out;
+	}
 
 	down_write(&current->mm->mmap_sem);
 	addr = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
 	up_write(&current->mm->mmap_sem);
 
-	if (file)
+out:	if (file)
 		fput(file);
 	return addr;
 }
diff -urN linux-2.4.13/arch/ia64/kernel/time.c linux-2.4.13-lia/arch/ia64/kernel/time.c
--- linux-2.4.13/arch/ia64/kernel/time.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/time.c	Thu Oct  4 00:21:39 2001
@@ -145,6 +145,9 @@
 	tv->tv_usec = usec;
 }
 
+/* XXX there should be a cleaner way for declaring an alias... */
+asm (".global get_fast_time; get_fast_time = do_gettimeofday");
+
 static void
 timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
diff -urN linux-2.4.13/arch/ia64/kernel/traps.c linux-2.4.13-lia/arch/ia64/kernel/traps.c
--- linux-2.4.13/arch/ia64/kernel/traps.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/traps.c	Wed Oct 24 18:15:16 2001
@@ -1,20 +1,19 @@
 /*
  * Architecture-specific trap handling.
  *
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * 05/12/00 grao <goutham.rao@intel.com> : added isr in siginfo for SIGFPE
  */
 
 /*
- * The fpu_fault() handler needs to be able to access and update all
- * floating point registers.  Those saved in pt_regs can be accessed
- * through that structure, but those not saved, will be accessed
- * directly.  To make this work, we need to ensure that the compiler
- * does not end up using a preserved floating point register on its
- * own.  The following achieves this by declaring preserved registers
- * that are not marked as "fixed" as global register variables.
+ * fp_emulate() needs to be able to access and update all floating point registers.  Those
+ * saved in pt_regs can be accessed through that structure, but those not saved, will be
+ * accessed directly.  To make this work, we need to ensure that the compiler does not end
+ * up using a preserved floating point register on its own.  The following achieves this
+ * by declaring preserved registers that are not marked as "fixed" as global register
+ * variables.
  */
 register double f2 asm ("f2"); register double f3 asm ("f3");
 register double f4 asm ("f4"); register double f5 asm ("f5");
@@ -33,13 +32,17 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/vt_kern.h>		/* For unblank_screen() */
 
+#include <asm/hardirq.h>
 #include <asm/ia32.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
 
 #include <asm/fpswa.h>
 
+extern spinlock_t timerlist_lock;
+
 static fpswa_interface_t *fpswa_interface;
 
 void __init
@@ -51,30 +54,74 @@
 		fpswa_interface = __va(ia64_boot_param->fpswa);
 }
 
+/*
+ * Unlock any spinlocks which will prevent us from getting the message out (timerlist_lock
+ * is acquired through the console unblank code)
+ */
 void
-die_if_kernel (char *str, struct pt_regs *regs, long err)
+bust_spinlocks (int yes)
 {
-	if (user_mode(regs)) {
-#if 0
-		/* XXX for debugging only */
-		printk ("!!die_if_kernel: %s(%d): %s %ld\n",
-			current->comm, current->pid, str, err);
-		show_regs(regs);
+	spin_lock_init(&timerlist_lock);
+	if (yes) {
+		oops_in_progress = 1;
+#ifdef CONFIG_SMP
+		global_irq_lock = 0;	/* Many serial drivers do __global_cli() */
 #endif
-		return;
+	} else {
+		int loglevel_save = console_loglevel;
+#ifdef CONFIG_VT
+		unblank_screen();
+#endif
+		oops_in_progress = 0;
+		/*
+		 * OK, the message is on the console.  Now we call printk() without
+		 * oops_in_progress set so that printk will give klogd a poke.  Hold onto
+		 * your hats...
+		 */
+		console_loglevel = 15;		/* NMI oopser may have shut the console up */
+		printk(" ");
+		console_loglevel = loglevel_save;
 	}
+}
 
-	printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err);
-
-	show_regs(regs);
+void
+die (const char *str, struct pt_regs *regs, long err)
+{
+	static struct {
+		spinlock_t lock;
+		int lock_owner;
+		int lock_owner_depth;
+	} die = {
+		lock:			SPIN_LOCK_UNLOCKED,
+		lock_owner:		-1,
+		lock_owner_depth:	0
+	};
 
-	if (current->thread.flags & IA64_KERNEL_DEATH) {
-		printk("die_if_kernel recursion detected.\n");
-		sti();
-		while (1);
+	if (die.lock_owner != smp_processor_id()) {
+		console_verbose();
+		spin_lock_irq(&die.lock);
+		die.lock_owner = smp_processor_id();
+		die.lock_owner_depth = 0;
+		bust_spinlocks(1);
 	}
-	current->thread.flags |= IA64_KERNEL_DEATH;
-	do_exit(SIGSEGV);
+
+	if (++die.lock_owner_depth < 3) {
+		printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err);
+		show_regs(regs);
+  	} else
+		printk(KERN_ERR "Recursive die() failure, output suppressed\n");
+
+	bust_spinlocks(0);
+	die.lock_owner = -1;
+	spin_unlock_irq(&die.lock);
+  	do_exit(SIGSEGV);
+}
+
+void
+die_if_kernel (char *str, struct pt_regs *regs, long err)
+{
+	if (!user_mode(regs))
+		die(str, regs, err);
 }
 
 void
@@ -169,14 +216,12 @@
 }
 
 /*
- * disabled_fph_fault() is called when a user-level process attempts
- * to access one of the registers f32..f127 when it doesn't own the
- * fp-high register partition.  When this happens, we save the current
- * fph partition in the task_struct of the fpu-owner (if necessary)
- * and then load the fp-high partition of the current task (if
- * necessary).  Note that the kernel has access to fph by the time we
- * get here, as the IVT's "Diabled FP-Register" handler takes care of
- * clearing psr.dfh.
+ * disabled_fph_fault() is called when a user-level process attempts to access f32..f127
+ * and it doesn't own the fp-high register partition.  When this happens, we save the
+ * current fph partition in the task_struct of the fpu-owner (if necessary) and then load
+ * the fp-high partition of the current task (if necessary).  Note that the kernel has
+ * access to fph by the time we get here, as the IVT's "Disabled FP-Register" handler takes
+ * care of clearing psr.dfh.
  */
 static inline void
 disabled_fph_fault (struct pt_regs *regs)
@@ -277,7 +322,7 @@
 
 	if (jiffies - last_time > 5*HZ)
 		fpu_swa_count = 0;
-	if (++fpu_swa_count < 5) {
+	if ((++fpu_swa_count < 5) && !(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) {
 		last_time = jiffies;
 		printk(KERN_WARNING "%s(%d): floating-point assist fault at ip %016lx\n",
 		       current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri);
@@ -478,12 +523,12 @@
 	      case 32: /* fp fault */
 	      case 33: /* fp trap */
 		result = handle_fpu_swa((vector = 32) ? 1 : 0, regs, isr);
-		if (result < 0) {
+		if ((result < 0) || (current->thread.flags & IA64_THREAD_FPEMU_SIGFPE)) {
 			siginfo.si_signo = SIGFPE;
 			siginfo.si_errno = 0;
 			siginfo.si_code = FPE_FLTINV;
 			siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
-			force_sig(SIGFPE, current);
+			force_sig_info(SIGFPE, &siginfo, current);
 		}
 		return;
 
@@ -510,6 +555,10 @@
 		break;
 
 	      case 46:
+#ifdef CONFIG_IA32_SUPPORT
+		if (ia32_intercept(regs, isr) = 0)
+			return;
+#endif
 		printk("Unexpected IA-32 intercept trap (Trap 46)\n");
 		printk("  iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx, iim - 0x%lx\n",
 		       regs->cr_iip, ifa, isr, iim);
diff -urN linux-2.4.13/arch/ia64/kernel/unaligned.c linux-2.4.13-lia/arch/ia64/kernel/unaligned.c
--- linux-2.4.13/arch/ia64/kernel/unaligned.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/unaligned.c	Wed Oct 24 18:15:29 2001
@@ -5,6 +5,8 @@
  * Copyright (C) 1999-2000 Stephane Eranian <eranian@hpl.hp.com>
  * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
  *
+ * 2001/10/11	Fix unaligned access to rotating registers in s/w pipelined loops.
+ * 2001/08/13	Correct size of extended floats (float_fsz) from 16 to 10 bytes.
  * 2001/01/17	Add support emulation of unaligned kernel accesses.
  */
 #include <linux/kernel.h>
@@ -282,9 +284,19 @@
 	unsigned long rnats, nat_mask;
 	unsigned long on_kbs;
 	long sof = (regs->cr_ifs) & 0x7f;
+	long sor = 8 * ((regs->cr_ifs >> 14) & 0xf);
+	long rrb_gr = (regs->cr_ifs >> 18) & 0x7f;
+	long ridx;
+
+	if ((r1 - 32) > sor)
+		ridx = -sof + (r1 - 32);
+	else if ((r1 - 32) < (sor - rrb_gr))
+		ridx = -sof + (r1 - 32) + rrb_gr;
+	else
+		ridx = -sof + (r1 - 32) - (sor - rrb_gr);
 
-	DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld\n",
-	       r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f);
+	DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n",
+	       r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx);
 
 	if ((r1 - 32) >= sof) {
 		/* this should never happen, as the "rsvd register fault" has higher priority */
@@ -293,7 +305,7 @@
 	}
 
 	on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore);
-	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + (r1 - 32));
+	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, ridx);
 	if (addr >= kbs) {
 		/* the register is on the kernel backing store: easy... */
 		rnat_addr = ia64_rse_rnat_addr(addr);
@@ -318,12 +330,12 @@
 		return;
 	}
 
-	bspstore = (unsigned long *) regs->ar_bspstore;
+	bspstore = (unsigned long *)regs->ar_bspstore;
 	ubs_end = ia64_rse_skip_regs(bspstore, on_kbs);
 	bsp     = ia64_rse_skip_regs(ubs_end, -sof);
-	addr    = ia64_rse_skip_regs(bsp, r1 - 32);
+	addr    = ia64_rse_skip_regs(bsp, ridx + sof);
 
-	DPRINT("ubs_end=%p bsp=%p addr=%px\n", (void *) ubs_end, (void *) bsp, (void *) addr);
+	DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr);
 
 	ia64_poke(current, sw, (unsigned long) ubs_end, (unsigned long) addr, val);
 
@@ -353,9 +365,19 @@
 	unsigned long rnats, nat_mask;
 	unsigned long on_kbs;
 	long sof = (regs->cr_ifs) & 0x7f;
+	long sor = 8 * ((regs->cr_ifs >> 14) & 0xf);
+	long rrb_gr = (regs->cr_ifs >> 18) & 0x7f;
+	long ridx;
+
+	if ((r1 - 32) > sor)
+		ridx = -sof + (r1 - 32);
+	else if ((r1 - 32) < (sor - rrb_gr))
+		ridx = -sof + (r1 - 32) + rrb_gr;
+	else
+		ridx = -sof + (r1 - 32) - (sor - rrb_gr);
 
-	DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld\n",
-	       r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f);
+	DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n",
+	       r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx);
 
 	if ((r1 - 32) >= sof) {
 		/* this should never happen, as the "rsvd register fault" has higher priority */
@@ -364,7 +386,7 @@
 	}
 
 	on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore);
-	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + (r1 - 32));
+	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, ridx);
 	if (addr >= kbs) {
 		/* the register is on the kernel backing store: easy... */
 		*val = *addr;
@@ -390,7 +412,7 @@
 	bspstore = (unsigned long *)regs->ar_bspstore;
 	ubs_end = ia64_rse_skip_regs(bspstore, on_kbs);
 	bsp     = ia64_rse_skip_regs(ubs_end, -sof);
-	addr    = ia64_rse_skip_regs(bsp, r1 - 32);
+	addr    = ia64_rse_skip_regs(bsp, ridx + sof);
 
 	DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr);
 
@@ -908,7 +930,7 @@
  * floating point operations sizes in bytes
  */
 static const unsigned char float_fsz[4]={
-	16, /* extended precision (e) */
+	10, /* extended precision (e) */
 	8,  /* integer (8)            */
 	4,  /* single precision (s)   */
 	8   /* double precision (d)   */
@@ -978,11 +1000,11 @@
 	unsigned long len = float_fsz[ld.x6_sz];
 
 	/*
-	 * fr0 & fr1 don't need to be checked because Illegal Instruction
-	 * faults have higher priority than unaligned faults.
+	 * fr0 & fr1 don't need to be checked because Illegal Instruction faults have
+	 * higher priority than unaligned faults.
 	 *
-	 * r0 cannot be found as the base as it would never generate an
-	 * unaligned reference.
+	 * r0 cannot be found as the base as it would never generate an unaligned
+	 * reference.
 	 */
 
 	/*
@@ -996,8 +1018,10 @@
 	 * invalidate the ALAT entry and execute updates, if any.
 	 */
 	if (ld.x6_op != 0x2) {
-		/* this assumes little-endian byte-order: */
-
+		/*
+		 * This assumes little-endian byte-order.  Note that there is no "ldfpe"
+		 * instruction:
+		 */
 		if (copy_from_user(&fpr_init[0], (void *) ifa, len)
 		    || copy_from_user(&fpr_init[1], (void *) (ifa + len), len))
 			return -1;
@@ -1337,7 +1361,7 @@
 
 	/*
 	 * IMPORTANT:
-	 * Notice that the swictch statement DOES not cover all possible instructions
+	 * Notice that the switch statement DOES not cover all possible instructions
 	 * that DO generate unaligned references. This is made on purpose because for some
 	 * instructions it DOES NOT make sense to try and emulate the access. Sometimes it
 	 * is WRONG to try and emulate. Here is a list of instruction we don't emulate i.e.,
diff -urN linux-2.4.13/arch/ia64/kernel/unwind.c linux-2.4.13-lia/arch/ia64/kernel/unwind.c
--- linux-2.4.13/arch/ia64/kernel/unwind.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/kernel/unwind.c	Thu Oct  4 00:21:39 2001
@@ -504,7 +504,7 @@
 	return 0;
 }
 
-inline int
+int
 unw_access_pr (struct unw_frame_info *info, unsigned long *val, int write)
 {
 	unsigned long *addr;
diff -urN linux-2.4.13/arch/ia64/lib/clear_page.S linux-2.4.13-lia/arch/ia64/lib/clear_page.S
--- linux-2.4.13/arch/ia64/lib/clear_page.S	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/lib/clear_page.S	Thu Oct  4 00:21:39 2001
@@ -47,5 +47,5 @@
 	br.cloop.dptk.few 1b
 	;;
 	mov ar.lc = r2		// restore lc
-	br.ret.sptk.few rp
+	br.ret.sptk.many rp
 END(clear_page)
diff -urN linux-2.4.13/arch/ia64/lib/clear_user.S linux-2.4.13-lia/arch/ia64/lib/clear_user.S
--- linux-2.4.13/arch/ia64/lib/clear_user.S	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/lib/clear_user.S	Thu Oct  4 00:21:39 2001
@@ -8,7 +8,7 @@
  *	r8:	number of bytes that didn't get cleared due to a fault
  *
  * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co
- * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
+ *	Stephane Eranian <eranian@hpl.hp.com>
  */
 
 #include <asm/asmmacro.h>
@@ -62,11 +62,11 @@
 	;;				// avoid WAW on CFM
 	adds tmp=-1,len			// br.ctop is repeat/until
 	mov ret0=len			// return value is length at this point
-(p6)	br.ret.spnt.few rp
+(p6)	br.ret.spnt.many rp
 	;;
 	cmp.lt p6,p0\x16,len		// if len > 16 then long memset
 	mov ar.lc=tmp			// initialize lc for small count
-(p6)	br.cond.dptk.few long_do_clear
+(p6)	br.cond.dptk .long_do_clear
 	;;				// WAR on ar.lc
 	//
 	// worst case 16 iterations, avg 8 iterations
@@ -79,7 +79,7 @@
 1:
 	EX( .Lexit1, st1 [buf]=r0,1 )
 	adds len=-1,len			// countdown length using len
-	br.cloop.dptk.few 1b
+	br.cloop.dptk 1b
 	;;				// avoid RAW on ar.lc
 	//
 	// .Lexit4: comes from byte by byte loop
@@ -87,7 +87,7 @@
 .Lexit1:
 	mov ret0=len			// faster than using ar.lc
 	mov ar.lc=saved_lc
-	br.ret.sptk.few rp		// end of short clear_user
+	br.ret.sptk.many rp		// end of short clear_user
 
 
 	//
@@ -98,7 +98,7 @@
 	// instead of ret0 is due to the fact that the exception code
 	// changes the values of r8.
 	//
-long_do_clear:
+.long_do_clear:
 	tbit.nz p6,p0=buf,0		// odd alignment (for long_do_clear)
 	;;
 	EX( .Lexit3, (p6) st1 [buf]=r0,1 )	// 1-byte aligned
@@ -119,7 +119,7 @@
 	;;
 	cmp.eq p6,p0=r0,cnt
 	adds tmp=-1,cnt
-(p6)	br.cond.dpnt.few .dotail	// we have less than 16 bytes left
+(p6)	br.cond.dpnt .dotail		// we have less than 16 bytes left
 	;;
 	adds buf2=8,buf			// setup second base pointer
 	mov ar.lc=tmp
@@ -148,7 +148,7 @@
 	;;				// needed to get len correct when error
 	st8 [buf2]=r0,16
 	adds len=-16,len
-	br.cloop.dptk.few 2b
+	br.cloop.dptk 2b
 	;;
 	mov ar.lc=saved_lc
 	//
@@ -178,7 +178,7 @@
 	;;
 	EX( .Lexit2, (p7) st1 [buf]=r0 )	// only 1 byte left
 	mov ret0=r0				// success
-	br.ret.dptk.few rp			// end of most likely path
+	br.ret.sptk.many rp			// end of most likely path
 
 	//
 	// Outlined error handling code
@@ -205,5 +205,5 @@
 .Lexit3:
 	mov ret0=len
 	mov ar.lc=saved_lc
-	br.ret.dptk.few rp
+	br.ret.sptk.many rp
 END(__do_clear_user)
diff -urN linux-2.4.13/arch/ia64/lib/copy_page.S linux-2.4.13-lia/arch/ia64/lib/copy_page.S
--- linux-2.4.13/arch/ia64/lib/copy_page.S	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/lib/copy_page.S	Thu Oct  4 00:21:39 2001
@@ -90,5 +90,5 @@
 	mov pr=saved_pr,0xffffffffffff0000	// restore predicates
 	mov ar.pfs=saved_pfs
 	mov ar.lc=saved_lc
-	br.ret.sptk.few rp
+	br.ret.sptk.many rp
 END(copy_page)
diff -urN linux-2.4.13/arch/ia64/lib/copy_user.S linux-2.4.13-lia/arch/ia64/lib/copy_user.S
--- linux-2.4.13/arch/ia64/lib/copy_user.S	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/lib/copy_user.S	Thu Oct  4 00:21:39 2001
@@ -19,8 +19,8 @@
  *	ret0	0 in case of success. The number of bytes NOT copied in
  *		case of error.
  *
- * Copyright (C) 2000 Hewlett-Packard Co
- * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
+ * Copyright (C) 2000-2001 Hewlett-Packard Co
+ *	Stephane Eranian <eranian@hpl.hp.com>
  *
  * Fixme:
  *	- handle the case where we have more than 16 bytes and the alignment
@@ -85,7 +85,7 @@
 	cmp.eq p8,p0=r0,len	// check for zero length
 	.save ar.lc, saved_lc
 	mov saved_lc=ar.lc	// preserve ar.lc (slow)
-(p8)	br.ret.spnt.few rp	// empty mempcy()
+(p8)	br.ret.spnt.many rp	// empty mempcy()
 	;;
 	add enddst=dst,len	// first byte after end of source
 	add endsrc=src,len	// first byte after end of destination
@@ -103,26 +103,26 @@
 	cmp.lt p10,p7=COPY_BREAK,len	// if len > COPY_BREAK then long copy
 
 	xor tmp=src,dst		// same alignment test prepare
-(p10)	br.cond.dptk.few long_copy_user
+(p10)	br.cond.dptk .long_copy_user
 	;;			// RAW pr.rot/p16 ?
 	//
 	// Now we do the byte by byte loop with software pipeline
 	//
 	// p7 is necessarily false by now
 1:
-	EX(failure_in_pipe1,(p16) ld1 val1[0]=[src1],1)
-	EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1)
+	EX(.failure_in_pipe1,(p16) ld1 val1[0]=[src1],1)
+	EX(.failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1)
 	br.ctop.dptk.few 1b
 	;;
 	mov ar.lc=saved_lc
 	mov pr=saved_pr,0xffffffffffff0000
 	mov ar.pfs=saved_pfs		// restore ar.ec
-	br.ret.sptk.few rp	// end of short memcpy
+	br.ret.sptk.many rp		// end of short memcpy
 
 	//
 	// Not 8-byte aligned
 	//
-diff_align_copy_user:
+.diff_align_copy_user:
 	// At this point we know we have more than 16 bytes to copy
 	// and also that src and dest do _not_ have the same alignment.
 	and src2=0x7,src1				// src offset
@@ -153,7 +153,7 @@
 	// We know src1 is not 8-byte aligned in this case.
 	//
 	cmp.eq p14,p15=r0,dst2
-(p15)	br.cond.spnt.few 1f
+(p15)	br.cond.spnt 1f
 	;;
 	sub t1=8,src2
 	mov t2=src2
@@ -163,7 +163,7 @@
 	;;
 	sub lshiftd,rshift
 	;;
-	br.cond.spnt.few word_copy_user
+	br.cond.spnt .word_copy_user
 	;;
 1:
 	cmp.leu	p14,p15=src2,dst2
@@ -192,15 +192,15 @@
 	mov ar.lc=cnt
 	;;
 2:
-	EX(failure_in_pipe2,(p16) ld1 val1[0]=[src1],1)
-	EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1)
+	EX(.failure_in_pipe2,(p16) ld1 val1[0]=[src1],1)
+	EX(.failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1)
 	br.ctop.dptk.few 2b
 	;;
 	clrrrb
 	;;
-word_copy_user:
+.word_copy_user:
 	cmp.gtu p9,p0\x16,len1
-(p9)	br.cond.spnt.few 4f		// if (16 > len1) skip 8-byte copy
+(p9)	br.cond.spnt 4f			// if (16 > len1) skip 8-byte copy
 	;;
 	shr.u cnt=len1,3		// number of 64-bit words
 	;;
@@ -232,24 +232,24 @@
 #define EPI_1		p[PIPE_DEPTH-2]
 #define SWITCH(pred, shift)	cmp.eq pred,p0=shift,rshift
 #define CASE(pred, shift)	\
-	(pred)	br.cond.spnt.few copy_user_bit##shift
+	(pred)	br.cond.spnt .copy_user_bit##shift
 #define BODY(rshift)						\
-copy_user_bit##rshift:						\
+.copy_user_bit##rshift:						\
 1:								\
-	EX(failure_out,(EPI) st8 [dst1]=tmp,8);			\
+	EX(.failure_out,(EPI) st8 [dst1]=tmp,8);		\
 (EPI_1) shrp tmp=val1[PIPE_DEPTH-3],val1[PIPE_DEPTH-2],rshift;	\
 	EX(3f,(p16) ld8 val1[0]=[src1],8);			\
-	br.ctop.dptk.few 1b;					\
+	br.ctop.dptk 1b;					\
 	;;							\
-	br.cond.sptk.few .diff_align_do_tail;			\
+	br.cond.sptk.many .diff_align_do_tail;			\
 2:								\
 (EPI)	st8 [dst1]=tmp,8;					\
 (EPI_1)	shrp tmp=val1[PIPE_DEPTH-3],val1[PIPE_DEPTH-2],rshift;	\
 3:								\
 (p16)	mov val1[0]=r0;						\
-	br.ctop.dptk.few 2b;					\
+	br.ctop.dptk 2b;					\
 	;;							\
-	br.cond.sptk.few failure_in2
+	br.cond.sptk.many .failure_in2
 
 	//
 	// Since the instruction 'shrp' requires a fixed 128-bit value
@@ -301,25 +301,25 @@
 	mov ar.lc=len1
 	;;
 5:
-	EX(failure_in_pipe1,(p16) ld1 val1[0]=[src1],1)
-	EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1)
+	EX(.failure_in_pipe1,(p16) ld1 val1[0]=[src1],1)
+	EX(.failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1)
 	br.ctop.dptk.few 5b
 	;;
 	mov ar.lc=saved_lc
 	mov pr=saved_pr,0xffffffffffff0000
 	mov ar.pfs=saved_pfs
-	br.ret.dptk.few rp
+	br.ret.sptk.many rp
 
 	//
 	// Beginning of long mempcy (i.e. > 16 bytes)
 	//
-long_copy_user:
+.long_copy_user:
 	tbit.nz p6,p7=src1,0	// odd alignement
 	and tmp=7,tmp
 	;;
 	cmp.eq p10,p8=r0,tmp
 	mov len1=len		// copy because of rotation
-(p8)	br.cond.dpnt.few diff_align_copy_user
+(p8)	br.cond.dpnt .diff_align_copy_user
 	;;
 	// At this point we know we have more than 16 bytes to copy
 	// and also that both src and dest have the same alignment
@@ -327,11 +327,11 @@
 	// forward slowly until we reach 16byte alignment: no need to
 	// worry about reaching the end of buffer.
 	//
-	EX(failure_in1,(p6) ld1 val1[0]=[src1],1)	// 1-byte aligned
+	EX(.failure_in1,(p6) ld1 val1[0]=[src1],1)	// 1-byte aligned
 (p6)	adds len1=-1,len1;;
 	tbit.nz p7,p0=src1,1
 	;;
-	EX(failure_in1,(p7) ld2 val1[1]=[src1],2)	// 2-byte aligned
+	EX(.failure_in1,(p7) ld2 val1[1]=[src1],2)	// 2-byte aligned
 (p7)	adds len1=-2,len1;;
 	tbit.nz p8,p0=src1,2
 	;;
@@ -339,28 +339,28 @@
 	// Stop bit not required after ld4 because if we fail on ld4
 	// we have never executed the ld1, therefore st1 is not executed.
 	//
-	EX(failure_in1,(p8) ld4 val2[0]=[src1],4)	// 4-byte aligned
+	EX(.failure_in1,(p8) ld4 val2[0]=[src1],4)	// 4-byte aligned
 	;;
-	EX(failure_out,(p6) st1 [dst1]=val1[0],1)
+	EX(.failure_out,(p6) st1 [dst1]=val1[0],1)
 	tbit.nz p9,p0=src1,3
 	;;
 	//
 	// Stop bit not required after ld8 because if we fail on ld8
 	// we have never executed the ld2, therefore st2 is not executed.
 	//
-	EX(failure_in1,(p9) ld8 val2[1]=[src1],8)	// 8-byte aligned
-	EX(failure_out,(p7) st2 [dst1]=val1[1],2)
+	EX(.failure_in1,(p9) ld8 val2[1]=[src1],8)	// 8-byte aligned
+	EX(.failure_out,(p7) st2 [dst1]=val1[1],2)
 (p8)	adds len1=-4,len1
 	;;
-	EX(failure_out, (p8) st4 [dst1]=val2[0],4)
+	EX(.failure_out, (p8) st4 [dst1]=val2[0],4)
 (p9)	adds len1=-8,len1;;
 	shr.u cnt=len1,4		// number of 128-bit (2x64bit) words
 	;;
-	EX(failure_out, (p9) st8 [dst1]=val2[1],8)
+	EX(.failure_out, (p9) st8 [dst1]=val2[1],8)
 	tbit.nz p6,p0=len1,3
 	cmp.eq p7,p0=r0,cnt
 	adds tmp=-1,cnt			// br.ctop is repeat/until
-(p7)	br.cond.dpnt.few .dotail	// we have less than 16 bytes left
+(p7)	br.cond.dpnt .dotail		// we have less than 16 bytes left
 	;;
 	adds src2=8,src1
 	adds dst2=8,dst1
@@ -370,12 +370,12 @@
 	// 16bytes/iteration
 	//
 2:
-	EX(failure_in3,(p16) ld8 val1[0]=[src1],16)
+	EX(.failure_in3,(p16) ld8 val1[0]=[src1],16)
 (p16)	ld8 val2[0]=[src2],16
 
-	EX(failure_out, (EPI)	st8 [dst1]=val1[PIPE_DEPTH-1],16)
+	EX(.failure_out, (EPI)	st8 [dst1]=val1[PIPE_DEPTH-1],16)
 (EPI)	st8 [dst2]=val2[PIPE_DEPTH-1],16
-	br.ctop.dptk.few 2b
+	br.ctop.dptk 2b
 	;;			// RAW on src1 when fall through from loop
 	//
 	// Tail correction based on len only
@@ -384,29 +384,28 @@
 	// is 16 byte aligned AND we have less than 16 bytes to copy.
 	//
 .dotail:
-	EX(failure_in1,(p6) ld8 val1[0]=[src1],8)	// at least 8 bytes
+	EX(.failure_in1,(p6) ld8 val1[0]=[src1],8)	// at least 8 bytes
 	tbit.nz p7,p0=len1,2
 	;;
-	EX(failure_in1,(p7) ld4 val1[1]=[src1],4)	// at least 4 bytes
+	EX(.failure_in1,(p7) ld4 val1[1]=[src1],4)	// at least 4 bytes
 	tbit.nz p8,p0=len1,1
 	;;
-	EX(failure_in1,(p8) ld2 val2[0]=[src1],2)	// at least 2 bytes
+	EX(.failure_in1,(p8) ld2 val2[0]=[src1],2)	// at least 2 bytes
 	tbit.nz p9,p0=len1,0
 	;;
-	EX(failure_out, (p6) st8 [dst1]=val1[0],8)
+	EX(.failure_out, (p6) st8 [dst1]=val1[0],8)
 	;;
-	EX(failure_in1,(p9) ld1 val2[1]=[src1])		// only 1 byte left
+	EX(.failure_in1,(p9) ld1 val2[1]=[src1])	// only 1 byte left
 	mov ar.lc=saved_lc
 	;;
-	EX(failure_out,(p7) st4 [dst1]=val1[1],4)
+	EX(.failure_out,(p7) st4 [dst1]=val1[1],4)
 	mov pr=saved_pr,0xffffffffffff0000
 	;;
-	EX(failure_out, (p8)	st2 [dst1]=val2[0],2)
+	EX(.failure_out, (p8)	st2 [dst1]=val2[0],2)
 	mov ar.pfs=saved_pfs
 	;;
-	EX(failure_out, (p9)	st1 [dst1]=val2[1])
-	br.ret.dptk.few rp
-
+	EX(.failure_out, (p9)	st1 [dst1]=val2[1])
+	br.ret.sptk.many rp
 
 
 	//
@@ -433,32 +432,32 @@
 	//	  pipeline going. We can't really do this inline because
 	//	  p16 is always reset to 1 when lc > 0.
 	//
-failure_in_pipe1:
+.failure_in_pipe1:
 	sub ret0=endsrc,src1	// number of bytes to zero, i.e. not copied
 1:
 (p16)	mov val1[0]=r0
 (EPI)	st1 [dst1]=val1[PIPE_DEPTH-1],1
-	br.ctop.dptk.few 1b
+	br.ctop.dptk 1b
 	;;
 	mov pr=saved_pr,0xffffffffffff0000
 	mov ar.lc=saved_lc
 	mov ar.pfs=saved_pfs
-	br.ret.dptk.few rp
+	br.ret.sptk.many rp
 
 	//
 	// This is the case where the byte by byte copy fails on the load
 	// when we copy the head. We need to finish the pipeline and copy
 	// zeros for the rest of the destination. Since this happens
 	// at the top we still need to fill the body and tail.
-failure_in_pipe2:
+.failure_in_pipe2:
 	sub ret0=endsrc,src1	// number of bytes to zero, i.e. not copied
 2:
 (p16)	mov val1[0]=r0
 (EPI)	st1 [dst1]=val1[PIPE_DEPTH-1],1
-	br.ctop.dptk.few 2b
+	br.ctop.dptk 2b
 	;;
 	sub len=enddst,dst1,1		// precompute len
-	br.cond.dptk.few failure_in1bis
+	br.cond.dptk.many .failure_in1bis
 	;;
 
 	//
@@ -533,9 +532,7 @@
 	// This means that we are in a situation similar the a fault in the
 	// head part. That's nice!
 	//
-failure_in1:
-//	sub ret0=enddst,dst1	// number of bytes to zero, i.e. not copied
-//	sub len=enddst,dst1,1
+.failure_in1:
 	sub ret0=endsrc,src1	// number of bytes to zero, i.e. not copied
 	sub len=endsrc,src1,1
 	//
@@ -546,18 +543,17 @@
 	// calling side.
 	//
 	;;
-failure_in1bis:			// from (failure_in3)
+.failure_in1bis:		// from (.failure_in3)
 	mov ar.lc=len		// Continue with a stupid byte store.
 	;;
 5:
 	st1 [dst1]=r0,1
-	br.cloop.dptk.few 5b
+	br.cloop.dptk 5b
 	;;
-skip_loop:
 	mov pr=saved_pr,0xffffffffffff0000
 	mov ar.lc=saved_lc
 	mov ar.pfs=saved_pfs
-	br.ret.dptk.few rp
+	br.ret.sptk.many rp
 
 	//
 	// Here we simply restart the loop but instead
@@ -569,7 +565,7 @@
 	// we MUST use src1/endsrc here and not dst1/enddst because
 	// of the pipeline effect.
 	//
-failure_in3:
+.failure_in3:
 	sub ret0=endsrc,src1	// number of bytes to zero, i.e. not copied
 	;;
 2:
@@ -577,36 +573,36 @@
 (p16)	mov val2[0]=r0
 (EPI)	st8 [dst1]=val1[PIPE_DEPTH-1],16
 (EPI)	st8 [dst2]=val2[PIPE_DEPTH-1],16
-	br.ctop.dptk.few 2b
+	br.ctop.dptk 2b
 	;;
 	cmp.ne p6,p0=dst1,enddst	// Do we need to finish the tail ?
 	sub len=enddst,dst1,1		// precompute len
-(p6)	br.cond.dptk.few failure_in1bis
+(p6)	br.cond.dptk .failure_in1bis
 	;;
 	mov pr=saved_pr,0xffffffffffff0000
 	mov ar.lc=saved_lc
 	mov ar.pfs=saved_pfs
-	br.ret.dptk.few rp
+	br.ret.sptk.many rp
 
-failure_in2:
+.failure_in2:
 	sub ret0=endsrc,src1
 	cmp.ne p6,p0=dst1,enddst	// Do we need to finish the tail ?
 	sub len=enddst,dst1,1		// precompute len
-(p6)	br.cond.dptk.few failure_in1bis
+(p6)	br.cond.dptk .failure_in1bis
 	;;
 	mov pr=saved_pr,0xffffffffffff0000
 	mov ar.lc=saved_lc
 	mov ar.pfs=saved_pfs
-	br.ret.dptk.few rp
+	br.ret.sptk.many rp
 
 	//
 	// handling of failures on stores: that's the easy part
 	//
-failure_out:
+.failure_out:
 	sub ret0=enddst,dst1
 	mov pr=saved_pr,0xffffffffffff0000
 	mov ar.lc=saved_lc
 
 	mov ar.pfs=saved_pfs
-	br.ret.dptk.few rp
+	br.ret.sptk.many rp
 END(__copy_user)
diff -urN linux-2.4.13/arch/ia64/lib/do_csum.S linux-2.4.13-lia/arch/ia64/lib/do_csum.S
--- linux-2.4.13/arch/ia64/lib/do_csum.S	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/lib/do_csum.S	Thu Oct  4 00:21:39 2001
@@ -16,7 +16,6 @@
  *		back-to-back 8-byte words per loop. Clean up the initialization
  *		for the loop. Support the cases where load latency = 1 or 2.
  *		Set CONFIG_IA64_LOAD_LATENCY to 1 or 2 (default).
- *
  */
 
 #include <asm/asmmacro.h>
@@ -130,7 +129,7 @@
 	;;			// avoid WAW on CFM
 	mov tmp3=0x7		// a temporary mask/value
 	add tmp1=buf,len	// last byte's address
-(p6)	br.ret.spnt.few rp	// return if true (hope we can avoid that)
+(p6)	br.ret.spnt.many rp	// return if true (hope we can avoid that)
 
 	and firstoff=7,buf	// how many bytes off for first1 element
 	tbit.nz p15,p0=buf,0	// is buf an odd address ?
@@ -181,9 +180,9 @@
 	cmp.ltu p6,p0=result1[0],word1[0]	// check the carry
 	;;
 (p6)	adds result1[0]=1,result1[0]
-(p8)	br.cond.dptk.few do_csum_exit	// if (within an 8-byte word)
+(p8)	br.cond.dptk .do_csum_exit	// if (within an 8-byte word)
 	;;
-(p11)	br.cond.dptk.few do_csum16	// if (count is even)
+(p11)	br.cond.dptk .do_csum16		// if (count is even)
 	;;
 	// Here count is odd.
 	ld8 word1[1]=[first1],8		// load an 8-byte word
@@ -196,14 +195,14 @@
 	;;
 (p6)	adds result1[0]=1,result1[0]
 	;;
-(p9)	br.cond.sptk.few do_csum_exit	// if (count = 1) exit
+(p9)	br.cond.sptk .do_csum_exit	// if (count = 1) exit
 	// Fall through to caluculate the checksum, feeding result1[0] as
 	// the initial value in result1[0].
 	;;
 	//
 	// Calculate the checksum loading two 8-byte words per loop.
 	//
-do_csum16:
+.do_csum16:
 	mov saved_lc=ar.lc
 	shr.u count=count,1	// we do 16 bytes per loop
 	;;
@@ -225,7 +224,7 @@
 	;;
 	add first2=8,first1
 	;;
-(p9)	br.cond.sptk.few do_csum_exit
+(p9)	br.cond.sptk .do_csum_exit
 	;;
 	nop.m	0
 	nop.i	0
@@ -241,7 +240,7 @@
 2:
 (p16)	ld8 word1[0]=[first1],16
 (p16)	ld8 word2[0]=[first2],16
-	br.ctop.sptk.few 1b
+	br.ctop.sptk 1b
 	;;
 	// Since len is a 32-bit value, carry cannot be larger than
 	// a 64-bit value.
@@ -263,7 +262,7 @@
 	;;
 (p6)	adds result1[0]=1,result1[0]
 	;;
-do_csum_exit:
+.do_csum_exit:
 	movl tmp3=0xffffffff
 	;;
 	// XXX Fixme
@@ -299,7 +298,7 @@
 	;;
 	mov ar.lc=saved_lc
 (p15)	shr.u ret0=ret0,64-16	// + shift back to position = swap bytes
-	br.ret.sptk.few rp
+	br.ret.sptk.many rp
 
 //	I (Jun Nakajima) wrote an equivalent code (see below), but it was
 //	not much better than the original. So keep the original there so that
@@ -331,6 +330,6 @@
 //(p15)	mux1 ret0=ret0,@rev		// reverse word
 //	;;
 //(p15)	shr.u ret0=ret0,64-16	// + shift back to position = swap bytes
-//	br.ret.sptk.few rp
+//	br.ret.sptk.many rp
 
 END(do_csum)
diff -urN linux-2.4.13/arch/ia64/lib/idiv32.S linux-2.4.13-lia/arch/ia64/lib/idiv32.S
--- linux-2.4.13/arch/ia64/lib/idiv32.S	Mon Oct  9 17:54:56 2000
+++ linux-2.4.13-lia/arch/ia64/lib/idiv32.S	Thu Oct  4 00:21:39 2001
@@ -79,5 +79,5 @@
 	;;
 #endif
 	getf.sig r8 = f6		// transfer result to result register
-	br.ret.sptk rp
+	br.ret.sptk.many rp
 END(NAME)
diff -urN linux-2.4.13/arch/ia64/lib/idiv64.S linux-2.4.13-lia/arch/ia64/lib/idiv64.S
--- linux-2.4.13/arch/ia64/lib/idiv64.S	Thu Apr  5 12:51:47 2001
+++ linux-2.4.13-lia/arch/ia64/lib/idiv64.S	Thu Oct  4 00:21:39 2001
@@ -89,5 +89,5 @@
 #endif
 	getf.sig r8 = f17		// transfer result to result register
 	ldf.fill f17 = [sp]
-	br.ret.sptk rp
+	br.ret.sptk.many rp
 END(NAME)
diff -urN linux-2.4.13/arch/ia64/lib/memcpy.S linux-2.4.13-lia/arch/ia64/lib/memcpy.S
--- linux-2.4.13/arch/ia64/lib/memcpy.S	Thu Apr  5 12:51:47 2001
+++ linux-2.4.13-lia/arch/ia64/lib/memcpy.S	Thu Oct  4 00:21:39 2001
@@ -9,20 +9,14 @@
  * Output:
  * 	no return value
  *
- * Copyright (C) 2000 Hewlett-Packard Co
- * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
- * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 2000-2001 Hewlett-Packard Co
+ *	Stephane Eranian <eranian@hpl.hp.com>
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #include <linux/config.h>
 
 #include <asm/asmmacro.h>
 
-#if defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)
-# define BRP(args...)	nop.b 0
-#else
-# define BRP(args...)	brp.loop.imp args
-#endif
-
 GLOBAL_ENTRY(bcopy)
 	.regstk 3,0,0,0
 	mov r8=in0
@@ -103,8 +97,8 @@
 	cmp.ne p6,p0=t0,r0
 
 	mov src=in1		// copy because of rotation
-(p7)	br.cond.spnt.few memcpy_short
-(p6)	br.cond.spnt.few memcpy_long
+(p7)	br.cond.spnt.few .memcpy_short
+(p6)	br.cond.spnt.few .memcpy_long
 	;;
 	nop.m	0
 	;;
@@ -119,7 +113,7 @@
 1: { .mib
 (p[0])	ld8 val[0]=[src],8
 	nop.i 0
-	BRP(1b, 2f)
+	brp.loop.imp 1b, 2f
 }
 2: { .mfb
 (p[N-1])st8 [dst]=val[N-1],8
@@ -139,14 +133,14 @@
 	 * issues, we want to avoid read-modify-write of entire words.
 	 */
 	.align 32
-memcpy_short:
+.memcpy_short:
 	adds cnt=-1,in2		// br.ctop is repeat/until
 	mov ar.ec=MEM_LAT
-	BRP(1f, 2f)
+	brp.loop.imp 1f, 2f
 	;;
 	mov ar.lc=cnt
 	;;
-	nop.m	0			
+	nop.m	0
 	;;
 	nop.m	0
 	nop.i	0
@@ -163,7 +157,7 @@
 1: { .mib
 (p[0])	ld1 val[0]=[src],1
 	nop.i 0
-	BRP(1b, 2f)
+	brp.loop.imp 1b, 2f
 } ;;
 2: { .mfb
 (p[MEM_LAT-1])st1 [dst]=val[MEM_LAT-1],1
@@ -202,7 +196,7 @@
 
 #define LOG_LOOP_SIZE	6
 
-memcpy_long:
+.memcpy_long:
 	alloc t3=ar.pfs,3,Nrot,0,Nrot	// resize register frame
 	and t0=-8,src		// t0 = src & ~7
 	and t2=7,src		// t2 = src & 7
@@ -247,7 +241,7 @@
 	mov t4=ip
   }	;;
 	and src2=-8,src			// align source pointer
-	adds t4=memcpy_loops-1b,t4
+	adds t4=.memcpy_loops-1b,t4
 	mov ar.ec=N
 
 	and t0=7,src			// t0 = src & 7
@@ -266,7 +260,7 @@
 	mov pr=cnt,0x38			// set (p5,p4,p3) to # of bytes last-word bytes to copy
 	mov ar.lc=t2
 	;;
-	nop.m	0			
+	nop.m	0
 	;;
 	nop.m	0
 	nop.i	0
@@ -278,7 +272,7 @@
 	br.sptk.few b6
 	;;
 
-memcpy_tail:
+.memcpy_tail:
 	// At this point, (p5,p4,p3) are set to the number of bytes left to copy (which is
 	// less than 8) and t0 contains the last few bytes of the src buffer:
 (p5)	st4 [dst]=t0,4
@@ -300,7 +294,7 @@
  1: { .mib											\
 	(p[0])		ld8 val[0]=[src2],8;							\
 	(p[MEM_LAT+3])	shrp w[0]=val[MEM_LAT+3],val[MEM_LAT+4-index],shift;			\
-			BRP(1b, 2f)								\
+			brp.loop.imp 1b, 2f							\
     };												\
  2: { .mfb											\
 	(p[MEM_LAT+4])	st8 [dst]=w[1],8;							\
@@ -311,8 +305,8 @@
 			ld8 val[N-1]=[src_end];	/* load last word (may be same as val[N]) */	\
 			;;									\
 			shrp t0=val[N-1],val[N-index],shift;					\
-			br memcpy_tail
-memcpy_loops:
+			br .memcpy_tail
+.memcpy_loops:
 	COPY(0, 1) /* no point special casing this---it doesn't go any faster without shrp */
 	COPY(8, 0)
 	COPY(16, 0)
diff -urN linux-2.4.13/arch/ia64/lib/memset.S linux-2.4.13-lia/arch/ia64/lib/memset.S
--- linux-2.4.13/arch/ia64/lib/memset.S	Thu Apr  5 12:51:47 2001
+++ linux-2.4.13-lia/arch/ia64/lib/memset.S	Thu Oct  4 00:21:40 2001
@@ -43,11 +43,11 @@
 
 	adds tmp=-1,len		// br.ctop is repeat/until
 	tbit.nz p6,p0=buf,0	// odd alignment
-(p8)	br.ret.spnt.few rp
+(p8)	br.ret.spnt.many rp
 
 	cmp.lt p7,p0\x16,len	// if len > 16 then long memset
 	mux1 val=val,@brcst	// prepare value
-(p7)	br.cond.dptk.few long_memset
+(p7)	br.cond.dptk .long_memset
 	;;
 	mov ar.lc=tmp		// initialize lc for small count
 	;;			// avoid RAW and WAW on ar.lc
@@ -57,11 +57,11 @@
 	;;				// avoid RAW on ar.lc
 	mov ar.lc=saved_lc
 	mov ar.pfs=saved_pfs
-	br.ret.sptk.few rp	// end of short memset
+	br.ret.sptk.many rp	// end of short memset
 
 	// at this point we know we have more than 16 bytes to copy
 	// so we focus on alignment
-long_memset:
+.long_memset:
 (p6)	st1 [buf]=val,1		// 1-byte aligned
 (p6)	adds len=-1,len;;	// sync because buf is modified
 	tbit.nz p6,p0=buf,1
@@ -80,7 +80,7 @@
 	;;
 	cmp.eq p6,p0=r0,cnt
 	adds tmp=-1,cnt
-(p6)	br.cond.dpnt.few .dotail // we have less than 16 bytes left
+(p6)	br.cond.dpnt .dotail	// we have less than 16 bytes left
 	;;
 	adds buf2=8,buf		// setup second base pointer
 	mov ar.lc=tmp
@@ -104,5 +104,5 @@
 	mov ar.lc=saved_lc
 	;;
 (p6)	st1 [buf]=val		// only 1 byte left
-	br.ret.dptk.few rp
+	br.ret.sptk.many rp
 END(memset)
diff -urN linux-2.4.13/arch/ia64/lib/strlen.S linux-2.4.13-lia/arch/ia64/lib/strlen.S
--- linux-2.4.13/arch/ia64/lib/strlen.S	Thu Apr  5 12:51:47 2001
+++ linux-2.4.13-lia/arch/ia64/lib/strlen.S	Thu Oct  4 00:21:40 2001
@@ -11,7 +11,7 @@
  *	does not count the \0
  *
  * Copyright (C) 1999, 2001 Hewlett-Packard Co
- * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
+ *	Stephane Eranian <eranian@hpl.hp.com>
  *
  * 09/24/99 S.Eranian add speculation recovery code
  */
@@ -116,7 +116,7 @@
 	ld8.s w[0]=[src],8	// speculatively load next to next
 	cmp.eq.and p6,p0=8,val1	// p6 = p6 and val1=8
 	cmp.eq.and p6,p0=8,val2	// p6 = p6 and mask=8
-(p6)	br.wtop.dptk.few 1b	// loop until p6 = 0
+(p6)	br.wtop.dptk 1b		// loop until p6 = 0
 	;;
 	//
 	// We must return try the recovery code iff
@@ -127,14 +127,14 @@
 	//
 	cmp.eq  p8,p9=8,val1	// p6 = val1 had zero (disambiguate)
 	tnat.nz p6,p7=val1	// test NaT on val1
-(p6)	br.cond.spnt.few recover// jump to recovery if val1 is NaT
+(p6)	br.cond.spnt .recover	// jump to recovery if val1 is NaT
 	;;
 	//
 	// if we come here p7 is true, i.e., initialized for // cmp
 	//
 	cmp.eq.and  p7,p0=8,val1// val1=8?
 	tnat.nz.and p7,p0=val2	// test NaT if val2
-(p7)	br.cond.spnt.few recover// jump to recovery if val2 is NaT
+(p7)	br.cond.spnt .recover	// jump to recovery if val2 is NaT
 	;;
 (p8)	mov val1=val2		// the other test got us out of the loop
 (p8)	adds src=-16,src	// correct position when 3 ahead
@@ -146,7 +146,7 @@
 	;;
 	sub ret0=ret0,tmp	// adjust
 	mov ar.pfs=saved_pfs	// because of ar.ec, restore no matter what
-	br.ret.sptk.few rp	// end of normal execution
+	br.ret.sptk.many rp	// end of normal execution
 
 	//
 	// Outlined recovery code when speculation failed
@@ -165,7 +165,7 @@
 	//	- today we restart from the beginning of the string instead
 	//	  of trying to continue where we left off.
 	//
-recover:
+.recover:
 	ld8 val=[base],8	// will fail if unrecoverable fault
 	;;
 	or val=val,mask		// remask first bytes
@@ -180,7 +180,7 @@
 	czx1.r val1=val		// search 0 byte from right
 	;;
 	cmp.eq p6,p0=8,val1	// val1=8 ?
-(p6)	br.wtop.dptk.few 2b	// loop until p6 = 0
+(p6)	br.wtop.dptk 2b		// loop until p6 = 0
 	;;			// (avoid WAW on p63)
 	sub ret0ºse,orig	// distance from base
 	sub tmp=8,val1
@@ -188,5 +188,5 @@
 	;;
 	sub ret0=ret0,tmp	// length=now - back -1
 	mov ar.pfs=saved_pfs	// because of ar.ec, restore no matter what
-	br.ret.sptk.few rp	// end of successful recovery code
+	br.ret.sptk.many rp	// end of successful recovery code
 END(strlen)
diff -urN linux-2.4.13/arch/ia64/lib/strlen_user.S linux-2.4.13-lia/arch/ia64/lib/strlen_user.S
--- linux-2.4.13/arch/ia64/lib/strlen_user.S	Thu Apr  5 12:51:47 2001
+++ linux-2.4.13-lia/arch/ia64/lib/strlen_user.S	Thu Oct  4 00:21:40 2001
@@ -8,8 +8,8 @@
  *	ret0	0 in case of fault, strlen(buffer)+1 otherwise
  *
  * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co
- * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com>
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+ *	Stephane Eranian <eranian@hpl.hp.com>
  *
  * 01/19/99 S.Eranian heavily enhanced version (see details below)
  * 09/24/99 S.Eranian added speculation recovery code
@@ -108,7 +108,7 @@
 	mov ar.ec=r0		// clear epilogue counter (saved in ar.pfs)
 	;;
 	add base=-16,src	// keep track of aligned base
-	chk.s v[1], recover	// if already NaT, then directly skip to recover
+	chk.s v[1], .recover	// if already NaT, then directly skip to recover
 	or v[1]=v[1],mask	// now we have a safe initial byte pattern
 	;;
 1:
@@ -130,14 +130,14 @@
 	//
 	cmp.eq  p8,p9=8,val1	// p6 = val1 had zero (disambiguate)
 	tnat.nz p6,p7=val1	// test NaT on val1
-(p6)	br.cond.spnt.few recover// jump to recovery if val1 is NaT
+(p6)	br.cond.spnt .recover	// jump to recovery if val1 is NaT
 	;;
 	//
 	// if we come here p7 is true, i.e., initialized for // cmp
 	//
 	cmp.eq.and  p7,p0=8,val1// val1=8?
 	tnat.nz.and p7,p0=val2	// test NaT if val2
-(p7)	br.cond.spnt.few recover// jump to recovery if val2 is NaT
+(p7)	br.cond.spnt .recover	// jump to recovery if val2 is NaT
 	;;
 (p8)	mov val1=val2		// val2 contains the value
 (p8)	adds src=-16,src	// correct position when 3 ahead
@@ -149,7 +149,7 @@
 	;;
 	sub ret0=ret0,tmp	// length=now - back -1
 	mov ar.pfs=saved_pfs	// because of ar.ec, restore no matter what
-	br.ret.sptk.few rp	// end of normal execution
+	br.ret.sptk.many rp	// end of normal execution
 
 	//
 	// Outlined recovery code when speculation failed
@@ -162,7 +162,7 @@
 	//	- today we restart from the beginning of the string instead
 	//	  of trying to continue where we left off.
 	//
-recover:
+.recover:
 	EX(.Lexit1, ld8 val=[base],8)	// load the initial bytes
 	;;
 	or val=val,mask			// remask first bytes
@@ -185,7 +185,7 @@
 	;;
 	sub ret0=ret0,tmp	// length=now - back -1
 	mov ar.pfs=saved_pfs	// because of ar.ec, restore no matter what
-	br.ret.sptk.few rp	// end of successful recovery code
+	br.ret.sptk.many rp	// end of successful recovery code
 
 	//
 	// We failed even on the normal load (called from exception handler)
@@ -194,5 +194,5 @@
 	mov ret0=0
 	mov pr=saved_pr,0xffffffffffff0000
 	mov ar.pfs=saved_pfs	// because of ar.ec, restore no matter what
-	br.ret.sptk.few rp
+	br.ret.sptk.many rp
 END(__strlen_user)
diff -urN linux-2.4.13/arch/ia64/lib/strncpy_from_user.S linux-2.4.13-lia/arch/ia64/lib/strncpy_from_user.S
--- linux-2.4.13/arch/ia64/lib/strncpy_from_user.S	Thu Apr  5 12:51:47 2001
+++ linux-2.4.13-lia/arch/ia64/lib/strncpy_from_user.S	Thu Oct  4 00:21:40 2001
@@ -40,5 +40,5 @@
 (p6)	mov r8=in2		// buffer filled up---return buffer length
 (p7)	sub r8=in1,r9,1		// return string length (excluding NUL character)
 [.Lexit:]
-	br.ret.sptk.few rp
+	br.ret.sptk.many rp
 END(__strncpy_from_user)
diff -urN linux-2.4.13/arch/ia64/lib/strnlen_user.S linux-2.4.13-lia/arch/ia64/lib/strnlen_user.S
--- linux-2.4.13/arch/ia64/lib/strnlen_user.S	Thu Apr  5 12:51:47 2001
+++ linux-2.4.13-lia/arch/ia64/lib/strnlen_user.S	Thu Oct  4 00:21:40 2001
@@ -33,7 +33,7 @@
 	add r9=1,r9
 	;;
 	cmp.eq p6,p0=r8,r0
-(p6)	br.dpnt.few .Lexit
+(p6)	br.cond.dpnt .Lexit
 	br.cloop.dptk.few .Loop1
 
 	add r9=1,in1			// NUL not found---return N+1
@@ -41,5 +41,5 @@
 .Lexit:
 	mov r8=r9
 	mov ar.lc=r16			// restore ar.lc
-	br.ret.sptk.few rp
+	br.ret.sptk.many rp
 END(__strnlen_user)
diff -urN linux-2.4.13/arch/ia64/mm/fault.c linux-2.4.13-lia/arch/ia64/mm/fault.c
--- linux-2.4.13/arch/ia64/mm/fault.c	Thu Apr  5 12:51:47 2001
+++ linux-2.4.13-lia/arch/ia64/mm/fault.c	Thu Oct  4 00:21:40 2001
@@ -1,8 +1,8 @@
 /*
  * MMU fault handling support.
  *
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -16,7 +16,7 @@
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
 
-extern void die_if_kernel (char *, struct pt_regs *, long);
+extern void die (char *, struct pt_regs *, long);
 
 /*
  * This routine is analogous to expand_stack() but instead grows the
@@ -46,16 +46,15 @@
 void
 ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs)
 {
+	int signal = SIGSEGV, code = SEGV_MAPERR;
+	struct vm_area_struct *vma, *prev_vma;
 	struct mm_struct *mm = current->mm;
 	struct exception_fixup fix;
-	struct vm_area_struct *vma, *prev_vma;
 	struct siginfo si;
-	int signal = SIGSEGV;
 	unsigned long mask;
 
 	/*
-	 * If we're in an interrupt or have no user
-	 * context, we must not take the fault..
+	 * If we're in an interrupt or have no user context, we must not take the fault..
 	 */
 	if (in_interrupt() || !mm)
 		goto no_context;
@@ -71,6 +70,8 @@
 		goto check_expansion;
 
   good_area:
+	code = SEGV_ACCERR;
+
 	/* OK, we've got a good vm_area for this memory area.  Check the access permissions: */
 
 #	define VM_READ_BIT	0
@@ -89,12 +90,13 @@
 	if ((vma->vm_flags & mask) != mask)
 		goto bad_area;
 
+  survive:
 	/*
 	 * If for any reason at all we couldn't handle the fault, make
 	 * sure we exit gracefully rather than endlessly redo the
 	 * fault.
 	 */
-	switch (handle_mm_fault(mm, vma, address, mask) != 0) {
+	switch (handle_mm_fault(mm, vma, address, mask)) {
 	      case 1:
 		++current->min_flt;
 		break;
@@ -147,7 +149,7 @@
 	if (user_mode(regs)) {
 		si.si_signo = signal;
 		si.si_errno = 0;
-		si.si_code = SI_KERNEL;
+		si.si_code = code;
 		si.si_addr = (void *) address;
 		force_sig_info(signal, &si, current);
 		return;
@@ -174,17 +176,29 @@
 	}
 
 	/*
-	 * Oops. The kernel tried to access some bad page. We'll have
-	 * to terminate things with extreme prejudice.
+	 * Oops. The kernel tried to access some bad page. We'll have to terminate things
+	 * with extreme prejudice.
 	 */
-	printk(KERN_ALERT "Unable to handle kernel paging request at "
-	       "virtual address %016lx\n", address);
-	die_if_kernel("Oops", regs, isr);
+	bust_spinlocks(1);
+
+	if (address < PAGE_SIZE)
+		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+	else
+		printk(KERN_ALERT "Unable to handle kernel paging request at "
+		       "virtual address %016lx\n", address);
+	die("Oops", regs, isr);
+	bust_spinlocks(0);
 	do_exit(SIGKILL);
 	return;
 
   out_of_memory:
 	up_read(&mm->mmap_sem);
+	if (current->pid = 1) {
+		current->policy |= SCHED_YIELD;
+		schedule();
+		down_read(&mm->mmap_sem);
+		goto survive;
+	}
 	printk("VM: killing process %s\n", current->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
diff -urN linux-2.4.13/arch/ia64/mm/init.c linux-2.4.13-lia/arch/ia64/mm/init.c
--- linux-2.4.13/arch/ia64/mm/init.c	Mon Sep 24 15:06:13 2001
+++ linux-2.4.13-lia/arch/ia64/mm/init.c	Wed Oct 10 17:43:54 2001
@@ -167,13 +167,40 @@
 }
 
 void
-show_mem (void)
+show_mem(void)
 {
 	int i, total = 0, reserved = 0;
 	int shared = 0, cached = 0;
 
 	printk("Mem-info:\n");
 	show_free_areas();
+
+#ifdef CONFIG_DISCONTIGMEM
+	{
+		pg_data_t *pgdat = pgdat_list;
+
+		printk("Free swap:       %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+		do {
+			printk("Node ID: %d\n", pgdat->node_id);
+			for(i = 0; i < pgdat->node_size; i++) {
+				if (PageReserved(pgdat->node_mem_map+i))
+					reserved++;
+				else if (PageSwapCache(pgdat->node_mem_map+i))
+					cached++;
+				else if (page_count(pgdat->node_mem_map + i))
+					shared += page_count(pgdat->node_mem_map + i) - 1;
+			}
+			printk("\t%d pages of RAM\n", pgdat->node_size);
+			printk("\t%d reserved pages\n", reserved);
+			printk("\t%d pages shared\n", shared);
+			printk("\t%d pages swap cached\n", cached);
+			pgdat = pgdat->node_next;
+		} while (pgdat);
+		printk("Total of %ld pages in page table cache\n", pgtable_cache_size);
+		show_buffers();
+		printk("%d free buffer pages\n", nr_free_buffer_pages());
+	}
+#else /* !CONFIG_DISCONTIGMEM */
 	printk("Free swap:       %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
 	i = max_mapnr;
 	while (i-- > 0) {
@@ -191,6 +218,7 @@
 	printk("%d pages swap cached\n", cached);
 	printk("%ld pages in page table cache\n", pgtable_cache_size);
 	show_buffers();
+#endif /* !CONFIG_DISCONTIGMEM */
 }
 
 /*
diff -urN linux-2.4.13/arch/ia64/mm/tlb.c linux-2.4.13-lia/arch/ia64/mm/tlb.c
--- linux-2.4.13/arch/ia64/mm/tlb.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.13-lia/arch/ia64/mm/tlb.c	Wed Oct 10 17:45:07 2001
@@ -2,7 +2,7 @@
  * TLB support routines.
  *
  * Copyright (C) 1998-2001 Hewlett-Packard Co
- * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * 08/02/00 A. Mallick <asit.k.mallick@intel.com>
  *		Modified RID allocation for SMP
@@ -41,89 +41,6 @@
 };
 
 /*
- * Seralize usage of ptc.g
- */
-spinlock_t ptcg_lock = SPIN_LOCK_UNLOCKED; /* see <asm/pgtable.h> */
-
-#if defined(CONFIG_SMP) && !defined(CONFIG_ITANIUM_PTCG)
-
-#include <linux/irq.h>
-
-unsigned long	flush_end, flush_start, flush_nbits, flush_rid;
-atomic_t flush_cpu_count;
-
-/*
- * flush_tlb_no_ptcg is called with ptcg_lock locked
- */
-static inline void
-flush_tlb_no_ptcg (unsigned long start, unsigned long end, unsigned long nbits)
-{
-	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
-	 * dead-lock; to avoid this we enable interrupt and raise the TPR
-	 * to enable ONLY IPI.
-	 */
-	__save_flags(flags);
-	if (!(flags & IA64_PSR_I)) {
-		saved_tpr = ia64_get_tpr();
-		ia64_srlz_d();
-		ia64_set_tpr(IA64_IPI_VECTOR - 16);
-		ia64_srlz_d();
-		local_irq_enable();
-	}
-
-	spin_lock(&ptcg_lock);
-	flush_rid = ia64_get_rr(start);
-	ia64_srlz_d();
-	flush_start = start;
-	flush_end = end;
-	flush_nbits = nbits;
-	atomic_set(&flush_cpu_count, smp_num_cpus - 1);
-	smp_send_flush_tlb();
-	/*
-	 * 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");
-		start += (1UL << nbits);
-	} while (start < end);
-
-	ia64_srlz_i();			/* srlz.i implies srlz.d */
-
-	/*
-	 * Wait for other CPUs to finish purging entries.
-	 */
-#if defined(CONFIG_ITANIUM_BSTEP_SPECIFIC)
-	{
-		extern void smp_resend_flush_tlb (void);
-		unsigned long start = ia64_get_itc();
-
-		while (atomic_read(&flush_cpu_count) > 0) {
-			if ((ia64_get_itc() - start) > 400000UL) {
-				smp_resend_flush_tlb();
-				start = ia64_get_itc();
-			}
-		}
-	}
-#else
-	while (atomic_read(&flush_cpu_count)) {
-		/* Nothing */
-	}
-#endif
-	if (!(flags & IA64_PSR_I)) {
-		local_irq_disable();
-		ia64_set_tpr(saved_tpr);
-		ia64_srlz_d();
-	}
-}
-
-#endif /* CONFIG_SMP && !CONFIG_ITANIUM_PTCG */
-
-/*
  * Acquire the ia64_ctx.lock before calling this function!
  */
 void
@@ -162,6 +79,26 @@
 	flush_tlb_all();
 }
 
+static void
+ia64_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits)
+{
+	static spinlock_t ptcg_lock = SPIN_LOCK_UNLOCKED;
+
+	/* HW requires global serialization of ptc.ga.  */
+	spin_lock(&ptcg_lock);
+	{
+		do {
+			/*
+			 * Flush ALAT entries also.
+			 */
+			asm volatile ("ptc.ga %0,%1;;srlz.i;;" :: "r"(start), "r"(nbits<<2)
+				      : "memory");
+			start += (1UL << nbits);
+		} while (start < end);
+	}
+	spin_unlock(&ptcg_lock);
+}
+
 void
 __flush_tlb_all (void)
 {
@@ -222,23 +159,15 @@
 	}
 	start &= ~((1UL << nbits) - 1);
 
-#if defined(CONFIG_SMP) && !defined(CONFIG_ITANIUM_PTCG)
-	flush_tlb_no_ptcg(start, end, nbits);
-#else
-	spin_lock(&ptcg_lock);
-	do {
 # ifdef CONFIG_SMP
-		/*
-		 * Flush ALAT entries also.
-		 */
-		asm volatile ("ptc.ga %0,%1;;srlz.i;;" :: "r"(start), "r"(nbits<<2) : "memory");
+	platform_global_tlb_purge(start, end, nbits);
 # else
+	do {
 		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) */
-	spin_unlock(&ptcg_lock);
+# endif
+
 	ia64_insn_group_barrier();
 	ia64_srlz_i();			/* srlz.i implies srlz.d */
 	ia64_insn_group_barrier();
diff -urN linux-2.4.13/arch/ia64/sn/sn1/llsc4.c linux-2.4.13-lia/arch/ia64/sn/sn1/llsc4.c
--- linux-2.4.13/arch/ia64/sn/sn1/llsc4.c	Thu Apr  5 12:51:47 2001
+++ linux-2.4.13-lia/arch/ia64/sn/sn1/llsc4.c	Thu Oct  4 00:21:40 2001
@@ -35,16 +35,6 @@
 static int	inttest=0;
 #endif
 
-#ifdef IA64_SEMFIX_INSN
-#undef IA64_SEMFIX_INSN
-#endif
-#ifdef IA64_SEMFIX
-#undef IA64_SEMFIX
-#endif
-# define IA64_SEMFIX_INSN
-# define IA64_SEMFIX    ""
-
-
 /*
  * Test parameter table for AUTOTEST
  */
@@ -192,7 +182,6 @@
 	printk ("     llscfail    \t%s\tForce a failure to test the trigger & error messages\n", fail_enabled ? "on" : "off");
 	printk ("     llscselt    \t%s\tSelective triger on failures\n", selective_trigger ? "on" : "off");
 	printk ("     llscblkadr  \t%s\tDump data block addresses\n", dump_block_addrs_opt ? "on" : "off");
-	printk ("  SEMFIX: %s\n", IA64_SEMFIX);
 	printk ("\n");
 }
 __setup("autotest", autotest_enable);
diff -urN linux-2.4.13/arch/ia64/tools/print_offsets.c linux-2.4.13-lia/arch/ia64/tools/print_offsets.c
--- linux-2.4.13/arch/ia64/tools/print_offsets.c	Tue Jul 31 10:30:09 2001
+++ linux-2.4.13-lia/arch/ia64/tools/print_offsets.c	Thu Oct  4 00:21:52 2001
@@ -57,11 +57,8 @@
     { "IA64_TASK_PROCESSOR_OFFSET",	offsetof (struct task_struct, processor) },
     { "IA64_TASK_THREAD_OFFSET",	offsetof (struct task_struct, thread) },
     { "IA64_TASK_THREAD_KSP_OFFSET",	offsetof (struct task_struct, thread.ksp) },
-#ifdef CONFIG_IA32_SUPPORT
-    { "IA64_TASK_THREAD_SIGMASK_OFFSET",offsetof (struct task_struct, thread.un.sigmask) },
-#endif
 #ifdef CONFIG_PERFMON
-    { "IA64_TASK_PFM_NOTIFY_OFFSET",	offsetof(struct task_struct, thread.pfm_pend_notify) },
+    { "IA64_TASK_PFM_MUST_BLOCK_OFFSET",offsetof(struct task_struct, thread.pfm_must_block) },
 #endif
     { "IA64_TASK_PID_OFFSET",		offsetof (struct task_struct, pid) },
     { "IA64_TASK_MM_OFFSET",		offsetof (struct task_struct, mm) },
@@ -165,17 +162,18 @@
     { "IA64_SIGCONTEXT_FR6_OFFSET",	offsetof (struct sigcontext, sc_fr[6]) },
     { "IA64_SIGCONTEXT_PR_OFFSET",	offsetof (struct sigcontext, sc_pr) },
     { "IA64_SIGCONTEXT_R12_OFFSET",	offsetof (struct sigcontext, sc_gr[12]) },
+    { "IA64_SIGCONTEXT_RBS_BASE_OFFSET",offsetof (struct sigcontext, sc_rbs_base) },
+    { "IA64_SIGCONTEXT_LOADRS_OFFSET",	offsetof (struct sigcontext, sc_loadrs) },
     { "IA64_SIGFRAME_ARG0_OFFSET",		offsetof (struct sigframe, arg0) },
     { "IA64_SIGFRAME_ARG1_OFFSET",		offsetof (struct sigframe, arg1) },
     { "IA64_SIGFRAME_ARG2_OFFSET",		offsetof (struct sigframe, arg2) },
-    { "IA64_SIGFRAME_RBS_BASE_OFFSET",		offsetof (struct sigframe, rbs_base) },
     { "IA64_SIGFRAME_HANDLER_OFFSET",		offsetof (struct sigframe, handler) },
     { "IA64_SIGFRAME_SIGCONTEXT_OFFSET",	offsetof (struct sigframe, sc) },
     { "IA64_CLONE_VFORK",		CLONE_VFORK },
     { "IA64_CLONE_VM",			CLONE_VM },
     { "IA64_CPU_IRQ_COUNT_OFFSET",	offsetof (struct cpuinfo_ia64, irq_stat.f.irq_count) },
     { "IA64_CPU_BH_COUNT_OFFSET",	offsetof (struct cpuinfo_ia64, irq_stat.f.bh_count) },
-    { "IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET",	offsetof (struct cpuinfo_ia64, phys_stacked_size_p8) },
+    { "IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET",offsetof (struct cpuinfo_ia64, phys_stacked_size_p8)},
 };
 
 static const char *tabs = "\t\t\t\t\t\t\t\t\t\t";
diff -urN linux-2.4.13/arch/parisc/kernel/traps.c linux-2.4.13-lia/arch/parisc/kernel/traps.c
--- linux-2.4.13/arch/parisc/kernel/traps.c	Wed Oct 10 16:31:44 2001
+++ linux-2.4.13-lia/arch/parisc/kernel/traps.c	Wed Oct 24 18:17:29 2001
@@ -43,7 +43,6 @@
 
 static inline void console_verbose(void)
 {
-	extern int console_loglevel;
 	console_loglevel = 15;
 }
 
diff -urN linux-2.4.13/drivers/acpi/acpiconf.c linux-2.4.13-lia/drivers/acpi/acpiconf.c
--- linux-2.4.13/drivers/acpi/acpiconf.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/acpi/acpiconf.c	Wed Oct 10 17:47:00 2001
@@ -0,0 +1,593 @@
+/*
+ *  acpiconf.c - ACPI based kernel configuration
+ *
+ *  Copyright (C) 2000-2001 Intel Corp.
+ *  Copyright (C) 2000-2001 J.I. Lee <Jung-Ik.Lee@intel.com>
+ *
+ *  Revision History:
+ *	 9/15/2000 J.I.
+ *		Major revision:	for new ACPI initialization requirements
+ *	11/15/2000 J.I.
+ *		Major revision:	ACPI 2.0 tables support
+ *	04/23/2001 J.I.
+ *		Rewrote functions to support multiple _PRTs of child P2Ps
+ *		under root pci bus
+ */
+
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <asm/system.h>
+#include <asm/iosapic.h>
+#include <asm/efi.h>
+#include <asm/acpikcfg.h>
+#include "acpi.h"
+#include "osconf.h"
+#include "acpiconf.h"
+
+
+static	int	acpi_cf_initialized __initdata = 0;
+
+acpi_status	__init
+acpi_cf_init (
+	void * rsdp
+	)
+{
+	acpi_status	status;
+
+	acpi_os_bind_osd(ACPI_CF_PHASE_BOOTTIME);
+
+	status = acpi_initialize_subsystem ();
+	if (ACPI_FAILURE(status)) {
+		printk ("Acpi cfg:initialize_subsystem error=0x%x\n", status);
+		return status;
+	}
+	dprintk(("Acpi cfg:initialize_subsystem pass\n"));
+
+	status = acpi_load_tables ();
+	if (ACPI_FAILURE(status)) {
+		printk ("Acpi cfg:load firmware tables error=0x%x\n", status);
+		acpi_terminate();
+		return status;
+	}
+	dprintk(("Acpi cfg:load firmware tables pass\n"));
+
+	status = acpi_enable_subsystem (ACPI_FULL_INITIALIZATION);
+	if (ACPI_FAILURE(status)) {
+		printk ("Acpi cfg:enable_subsystem error=0x%x\n", status);
+		acpi_terminate();
+		return status;
+	}
+	dprintk(("Acpi cfg:enable_subsystem pass\n"));
+
+	acpi_cf_initialized++;
+
+	return AE_OK;
+}
+
+
+acpi_status	__init
+acpi_cf_terminate ( void )
+{
+	acpi_status	status;
+
+	if (! ACPI_CF_INITIALIZED()) {
+		acpi_os_bind_osd(ACPI_CF_PHASE_RUNTIME);
+		return AE_ERROR;
+	}
+
+	status = acpi_disable ();
+	if (ACPI_FAILURE(status)) {
+		printk ("Acpi cfg:disable fail=0x%x\n", status);
+		/* fall thru...*/
+	}
+
+	status = acpi_terminate ();
+	if (ACPI_FAILURE(status)) {
+		printk ("Acpi cfg:acpi terminate error=0x%x\n", status);
+		/* fall thru...*/
+	}
+
+	acpi_cf_cleanup();
+	acpi_os_bind_osd(ACPI_CF_PHASE_RUNTIME);
+
+	acpi_cf_initialized--;
+
+	return status;
+}
+
+
+acpi_status	__init
+acpi_cf_get_pci_vectors (
+	struct pci_vector_struct	**vectors,
+	int				*num_pci_vectors
+	)
+{
+	acpi_status	status;
+	void		*prts;
+
+	if (! ACPI_CF_INITIALIZED()) {
+		status = acpi_cf_init((void *)efi.acpi);
+		if (ACPI_FAILURE (status))
+			return status;
+	}
+
+	*vectors = NULL;
+	*num_pci_vectors = 0;
+
+	status = acpi_cf_get_prt (&prts);
+	if (ACPI_FAILURE (status)) {
+		printk("Acpi cfg: get prt fail\n");
+		return status;
+	}
+
+	status = acpi_cf_convert_prt_to_vectors (prts, vectors, num_pci_vectors);
+#ifdef	CONFIG_ACPI_KERNEL_CONFIG_DEBUG
+	if (ACPI_SUCCESS(status)) {
+		acpi_cf_print_pci_vectors (*vectors, *num_pci_vectors);
+	}
+#endif
+	printk("Acpi cfg: get PCI interrupt vectors %s\n",
+		(ACPI_SUCCESS(status))?"pass":"fail");
+
+	return status;
+}
+
+
+static	pci_routing_table	*pci_routing_tables[PCI_MAX_BUS] __initdata = {NULL};
+
+
+typedef struct _acpi_rpb {
+	NATIVE_UINT	rpb_busnum;
+	NATIVE_UINT	lastbusnum;
+	acpi_handle	rpb_handle;
+} acpi_rpb_t;
+
+
+static acpi_status	__init
+acpi_cf_evaluate_method (
+	acpi_handle	handle,
+	UINT8		*method_name,
+	NATIVE_UINT	*nuint
+	)
+{
+	UINT32			tnuint = 0;
+	acpi_status		status;
+
+	acpi_buffer		ret_buf;
+	acpi_object		*ext_obj;
+	UINT8			buf[PATHNAME_MAX];
+
+
+	ret_buf.length  = PATHNAME_MAX;
+	ret_buf.pointer = (void *) buf;
+
+	status = acpi_evaluate_object(handle, method_name, NULL, &ret_buf);
+	if (ACPI_FAILURE(status)) {
+		if (status = AE_NOT_FOUND) {
+			printk("Acpi cfg: no %s found\n", method_name);
+		} else {
+			printk("Acpi cfg: %s fail=0x%x\n", method_name, status);
+		}
+	} else {
+		ext_obj = (acpi_object *) ret_buf.pointer;
+
+		switch (ext_obj->type) {
+		case ACPI_TYPE_INTEGER:
+			tnuint = (NATIVE_UINT) ext_obj->integer.value;
+			break;
+		default:
+			printk("Acpi cfg: %s obj type incorrect\n", method_name);
+			status = AE_TYPE;
+			break;
+		}
+	}
+
+	*nuint = tnuint;
+	return (status);
+}
+
+
+static acpi_status	__init
+acpi_cf_evaluate_PRT (
+	acpi_handle		handle,
+	pci_routing_table	**prt
+	)
+{
+	acpi_buffer		acpi_buffer;
+	acpi_status		status;
+
+	acpi_buffer.length  = 0;
+	acpi_buffer.pointer = NULL;
+
+	status = acpi_get_irq_routing_table (handle, &acpi_buffer);
+
+	switch (status) {
+	case AE_BUFFER_OVERFLOW:
+		dprintk(("Acpi cfg: _PRT found. need %d bytes\n",
+			acpi_buffer.length));
+		break;		/* found */
+	default:
+		printk("Acpi cfg: _PRT fail=0x%x\n", status);
+	case AE_NOT_FOUND:
+		return status;
+	}
+
+	*prt = (pci_routing_table *) acpi_os_callocate (acpi_buffer.length);
+	if (!*prt) {
+		printk("Acpi cfg: callocate %d bytes for _PRT fail\n",
+			acpi_buffer.length);
+		return AE_NO_MEMORY;
+	}
+	acpi_buffer.pointer = (void *) *prt;
+
+	status = acpi_get_irq_routing_table (handle, &acpi_buffer);
+	if (ACPI_FAILURE(status)) {
+		printk("Acpi cfg: _PRT fail=0x%x.\n", status);
+		acpi_os_free(prt);
+	}
+
+	return status;
+}
+
+static acpi_status	__init
+acpi_cf_get_root_pci_callback (
+	acpi_handle		handle,
+	UINT32			Level,
+	void			*context,
+	void			**retval
+	)
+{
+	NATIVE_UINT		busnum = 0;
+	acpi_status		status;
+	acpi_rpb_t		rpb;
+	pci_routing_table	*prt;
+
+	UINT8			path_name[PATHNAME_MAX];
+#ifdef	CONFIG_ACPI_KERNEL_CONFIG_DEBUG
+	acpi_buffer		ret_buf;
+
+	ret_buf.length  = PATHNAME_MAX;
+	ret_buf.pointer = (void *) path_name;
+
+	status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &ret_buf);
+#else
+	memset(path_name, 0, sizeof (path_name));
+#endif
+
+	/*
+	 * get bus number of this pci root bridge
+	 */
+	status = acpi_cf_evaluate_method(handle, METHOD_NAME__BBN, &busnum);
+	if (ACPI_FAILURE(status)) {
+		printk("Acpi cfg:%s evaluate _BBN fail=0x%x\n",
+			path_name, status);
+		return (status);
+	}
+	printk("Acpi cfg:%s ROOT PCI bus %ld\n", path_name, busnum);
+
+	/*
+	 * evaluate root pci bridge's _CRS for Bus number range for child P2P
+	 * (bus min/max/len) - not yet.
+	 */
+
+	/*
+	 * get immediate _PRT of this root pci bridge if any
+	 */
+	status = acpi_cf_evaluate_PRT (handle, &prt);
+	switch(status) {
+	case AE_NOT_FOUND:
+		break;
+	default:
+		if (ACPI_FAILURE(status)) {
+			printk("Acpi cfg:%s _PRT fail=0x%x\n",
+				path_name, status);
+			return status;
+		}
+		dprintk(("Acpi cfg:%s bus %ld got _PRT\n", path_name, busnum));
+		acpi_cf_add_to_pci_routing_tables (busnum, prt);
+		break;
+	}
+
+
+	/*
+	 * walk down this root pci bridge to get _PRTs if any
+	 */
+	rpb.rpb_busnum = rpb.lastbusnum = busnum;
+	rpb.rpb_handle = handle;
+	status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
+					handle,
+					ACPI_UINT32_MAX,
+					acpi_cf_get_prt_callback,
+					&rpb,
+					NULL );
+	if (ACPI_FAILURE(status))
+		printk("Acpi cfg:%s walk namespace for _PRT error=0x%x\n",
+			path_name, status);
+
+	return (status);
+}
+
+
+/*
+ * handle _PRTs of immediate P2Ps of root pci. 
+ */
+static acpi_status	__init
+acpi_cf_associate_prt_to_bus (
+	acpi_handle		handle,
+	acpi_rpb_t		*rpb,
+	NATIVE_UINT		*retbusnum,
+	NATIVE_UINT		depth
+	)
+{
+	acpi_status		status;
+	UINT32			segbus;
+	NATIVE_UINT		devfn;
+	UINT8			bn;
+
+	UINT8			path_name[PATHNAME_MAX];
+	acpi_pci_id		pci_id;
+
+#ifdef	CONFIG_ACPI_KERNEL_CONFIG_DEBUG
+	acpi_buffer		ret_buf;
+
+	ret_buf.length  = PATHNAME_MAX;
+	ret_buf.pointer = (void *) path_name;
+
+	status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &ret_buf);
+#else
+	memset(path_name, 0, sizeof (path_name));
+#endif
+
+	/*
+	 * get devfn from _ADR
+	 */
+	status = acpi_cf_evaluate_method(handle, METHOD_NAME__ADR, &devfn);
+	if (ACPI_FAILURE(status)) {
+		*retbusnum = rpb->rpb_busnum + 1;
+		printk("Acpi cfg:%s _ADR fail=0x%x. Set busnum to %ld\n",
+			path_name, status, *retbusnum);
+		return AE_OK;
+	}
+	dprintk(("Acpi cfg:%s _ADR =0x%x\n", path_name, (UINT32)devfn));
+
+
+	/*
+	 * access pci config space for bus number
+	 *	segbus = from rpb, devfn = from _ADR
+	 */
+	pci_id.segment = 0;
+	pci_id.bus = (u16)(rpb->rpb_busnum & 0xffffffff);
+	pci_id.device = (u16)((devfn >> 16) & 0xffff);
+	pci_id.function = (u16)(devfn & 0xffff);
+
+	status = acpi_os_read_pci_configuration(&pci_id, PCI_PRIMARY_BUS,
+						&bn, 8);
+	if (ACPI_FAILURE(status)) {
+		*retbusnum = rpb->rpb_busnum + 1;
+		printk("Acpi cfg:%s pci read fail=0x%x. b:df:a=%x:%x:%x\n",
+			path_name, status, segbus, (UINT32)devfn,
+			PCI_PRIMARY_BUS);
+		printk("Acpi cfg:%s Set busnum to %ld\n",
+			path_name, *retbusnum);
+		return AE_OK;
+	}
+	dprintk(("Acpi cfg:%s pribus %d\n", path_name, bn));
+
+
+	status = acpi_os_read_pci_configuration(&pci_id, PCI_SECONDARY_BUS,
+						&bn, 8);
+	if (ACPI_FAILURE(status)) {
+		*retbusnum = rpb->rpb_busnum + 1;
+		printk("Acpi cfg:%s pci read fail=0x%x. b:df:a=%x:%x:%x\n",
+			path_name, status, segbus, (UINT32)devfn,
+			PCI_SECONDARY_BUS);
+		printk("Acpi cfg:%s Set busnum to %ld\n",
+			path_name, *retbusnum);
+		return AE_OK;
+	}
+	dprintk(("Acpi cfg:%s busnum %d\n", path_name, bn));
+
+	*retbusnum = (NATIVE_UINT)bn;
+	return AE_OK;
+}
+
+
+static acpi_status	__init
+acpi_cf_get_prt (
+	void		**prts
+	)
+{
+	acpi_status	status;
+
+	status = acpi_get_devices ( PCI_ROOT_HID_STRING,
+				acpi_cf_get_root_pci_callback,
+				NULL,
+				NULL );
+
+	if (ACPI_FAILURE(status)) {
+		printk("Acpi cfg:get_device PCI ROOT HID error=0x%x\n", status);
+	}
+
+	*prts = (void *)pci_routing_tables;
+
+	return status;
+}
+
+static acpi_status	__init
+acpi_cf_get_prt_callback (
+	acpi_handle		handle,
+	UINT32			Level,
+	void			*context,
+	void			**retval
+	)
+{
+	pci_routing_table	*prt;
+	NATIVE_UINT		busnum = 0;
+	NATIVE_UINT		temp = 0x0F;
+	acpi_status		status;
+
+	UINT8			path_name[PATHNAME_MAX];
+
+#ifdef	CONFIG_ACPI_KERNEL_CONFIG_DEBUG
+	acpi_buffer		ret_buf;
+
+	ret_buf.length  = PATHNAME_MAX;
+	ret_buf.pointer = (void *) path_name;
+
+	status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &ret_buf);
+#else
+	memset(path_name, 0, sizeof (path_name));
+#endif
+
+	status = acpi_cf_evaluate_PRT (handle, &prt);
+	switch(status) {
+	case AE_NOT_FOUND:
+		return AE_OK;
+	default:
+		if (ACPI_FAILURE(status)) {
+			printk("Acpi cfg:%s _PRT fail=0x%x\n",
+				path_name, status);
+			return status;
+		}
+	}
+
+	/*
+	 * evaluate _STA in case this device does not exist
+	 */
+	status = acpi_cf_evaluate_method(handle, METHOD_NAME__STA, &temp);
+	switch(status) {
+	case AE_NOT_FOUND:
+		break;
+	default:
+		if (ACPI_FAILURE(status)) {
+			printk("Acpi cfg:%s _STA fail=0x%x\n",
+				path_name, status);
+			return status;
+		}
+		if (!(temp & ACPI_STA_DEVICE_PRESENT)) {
+			dprintk(("Acpi cfg:%s not exist. _PRT discarded\n",
+				path_name));
+			acpi_os_free(prt);
+			return AE_OK;
+		}
+		break;
+	}
+
+	/*
+	 * associate a bus number to this _PRT since 
+	 * this _PRT is not on root pci bridge 
+	 */
+	acpi_cf_associate_prt_to_bus(handle, context, &busnum, 0);
+
+	printk("Acpi cfg:%s busnum %ld got _PRT\n", path_name, busnum);
+	acpi_cf_add_to_pci_routing_tables (busnum, prt);
+
+	return AE_OK;
+}
+
+
+static void	__init
+acpi_cf_add_to_pci_routing_tables (
+	NATIVE_UINT		busnum,
+	pci_routing_table	*prt
+	)
+{
+	if ( busnum >= PCI_MAX_BUS ) {
+		printk("Acpi cfg:invalid pci bus number %ld\n", busnum);
+		acpi_os_free(prt);
+		return;
+	}
+
+	if (pci_routing_tables[busnum]) {
+		printk("Acpi cfg:duplicate PRT for pci bus %ld. overiding...\n", busnum);
+		acpi_os_free(pci_routing_tables[busnum]);
+	}
+
+	pci_routing_tables[busnum] = prt;
+}
+
+
+#define	DUMPVECTOR(pv)	printk("PCI bus=0x%x id=0x%x pin=0x%x irq=0x%x\n", pv->bus, pv->pci_id, pv->pin, pv->irq);
+
+static acpi_status	__init
+acpi_cf_convert_prt_to_vectors (
+	void				*prts,
+	struct pci_vector_struct	**vectors,
+	int				*num_pci_vectors
+	)
+{
+	struct pci_vector_struct	*pvec;
+	pci_routing_table		**pprts, *prt, *prtf;
+	int				nvec = 0;
+	int				i;
+
+
+	pprts = (pci_routing_table **)prts;
+
+	for ( i = 0; i < PCI_MAX_BUS; i++) {
+		prt = *pprts++;
+		if (prt) {
+			for ( ; prt->length > 0; nvec++) {
+				prt = (pci_routing_table *) ((NATIVE_UINT)prt + (NATIVE_UINT)prt->length);
+			}
+		}
+	}
+
+	*num_pci_vectors = nvec;
+	*vectors = acpi_os_callocate (sizeof(struct pci_vector_struct) * nvec);
+	if (!*vectors) {
+		printk("Acpi cfg: callocate for pci_vector error\n");
+		return AE_NO_MEMORY;
+	}
+
+	pvec = *vectors;
+	pprts = (pci_routing_table **)prts;
+
+	for ( i = 0; i < PCI_MAX_BUS; i++) {
+		prt = prtf = *pprts++;
+		if (prt) {
+			for ( ; prt->length > 0; pvec++) {
+				pvec->bus	= (UINT16)i;
+				pvec->pci_id	= prt->address;
+				pvec->pin	= (UINT8)prt->pin;
+				pvec->irq	= (UINT8)prt->source_index;
+
+				prt = (pci_routing_table *) ((NATIVE_UINT)prt + (NATIVE_UINT)prt->length);
+			}
+			acpi_os_free((void *)prtf);
+		}
+	}
+
+	return AE_OK;
+}
+
+
+void	__init
+acpi_cf_cleanup ( void )
+{
+	/* nothing to free, pci_vectors are used by the kernel */
+}
+
+
+#ifdef	CONFIG_ACPI_KERNEL_CONFIG_DEBUG
+void	__init
+acpi_cf_print_pci_vectors (
+	struct pci_vector_struct	*vectors,
+	int				num_pci_vectors
+	)
+{
+	struct pci_vector_struct	*pvec;
+	int				i;
+
+	printk("number of PCI interrupt vectors = %d\n", num_pci_vectors);
+
+	pvec = vectors;
+	for (i = 0; i < num_pci_vectors; i++) {
+		DUMPVECTOR(pvec);
+		pvec++;
+	}
+}
+#endif
diff -urN linux-2.4.13/drivers/acpi/acpiconf.h linux-2.4.13-lia/drivers/acpi/acpiconf.h
--- linux-2.4.13/drivers/acpi/acpiconf.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/acpi/acpiconf.h	Fri Oct 12 09:03:25 2001
@@ -0,0 +1,63 @@
+/*
+ *  acpiconf.h - ACPI based kernel configuration 
+ *
+ *  Copyright (C) 2000 Intel Corp.
+ *  Copyright (C) 2000 J.I. Lee <Jung-Ik.Lee@intel.com>
+ */
+
+#include <linux/init.h>
+
+#define	PCI_MAX_BUS		0x100
+#define	ACPI_STA_DEVICE_PRESENT	0x01
+
+#ifdef	CONFIG_ACPI_KERNEL_CONFIG_DEBUG
+#define	ACPI_CF_INITIALIZED()	(acpi_cf_initialized > 0)
+#undef	dprintk
+#define	dprintk(a)	printk a
+#else
+#define	ACPI_CF_INITIALIZED()	1
+#undef	dprintk
+#define	dprintk(a)
+#endif
+
+
+extern
+void	__init
+acpi_os_bind_osd(int acpi_phase);
+
+
+static
+acpi_status	__init
+acpi_cf_get_prt (void **prts);
+
+
+static
+acpi_status	__init
+acpi_cf_get_prt_callback (
+	acpi_handle		handle,
+	UINT32			level,
+	void			*context,
+	void			**retval
+	);
+
+
+static
+void	__init
+acpi_cf_add_to_pci_routing_tables (
+	NATIVE_UINT		busnum,
+	pci_routing_table	*prt
+	);
+
+
+static
+acpi_status	__init
+acpi_cf_convert_prt_to_vectors (
+	void				*prts,
+	struct pci_vector_struct	**vectors,
+	int				*num_pci_vectors
+	);
+
+
+void	__init
+acpi_cf_cleanup ( void );
+
diff -urN linux-2.4.13/drivers/acpi/hardware/hwacpi.c linux-2.4.13-lia/drivers/acpi/hardware/hwacpi.c
--- linux-2.4.13/drivers/acpi/hardware/hwacpi.c	Mon Sep 24 15:06:41 2001
+++ linux-2.4.13-lia/drivers/acpi/hardware/hwacpi.c	Thu Oct  4 00:21:40 2001
@@ -196,6 +196,7 @@
 {
 
 	acpi_status             status = AE_NO_HARDWARE_RESPONSE;
+	u32			retries = 20;
 
 
 	FUNCTION_TRACE ("Hw_set_mode");
@@ -220,11 +221,14 @@
 
 	/* Give the platform some time to react */
 
-	acpi_os_stall (5000);
+	while (retries-- > 0) {
+		acpi_os_stall (5000);
 
-	if (acpi_hw_get_mode () = mode) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Mode %X successfully enabled\n", mode));
-		status = AE_OK;
+		if (acpi_hw_get_mode () = mode) {
+			ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Mode %X successfully enabled\n", mode));
+			status = AE_OK;
+			break;
+		}
 	}
 
 	return_ACPI_STATUS (status);
diff -urN linux-2.4.13/drivers/acpi/include/actypes.h linux-2.4.13-lia/drivers/acpi/include/actypes.h
--- linux-2.4.13/drivers/acpi/include/actypes.h	Mon Sep 24 15:06:42 2001
+++ linux-2.4.13-lia/drivers/acpi/include/actypes.h	Thu Oct  4 00:21:40 2001
@@ -60,6 +60,7 @@
 typedef int                             INT32;
 typedef unsigned int                    UINT32;
 typedef COMPILER_DEPENDENT_UINT64       UINT64;
+typedef	long				INT64;
 
 typedef UINT64                          NATIVE_UINT;
 typedef INT64                           NATIVE_INT;
diff -urN linux-2.4.13/drivers/acpi/include/acutils.h linux-2.4.13-lia/drivers/acpi/include/acutils.h
--- linux-2.4.13/drivers/acpi/include/acutils.h	Mon Sep 24 15:06:42 2001
+++ linux-2.4.13-lia/drivers/acpi/include/acutils.h	Wed Oct 24 18:17:40 2001
@@ -383,6 +383,7 @@
 /* Method name strings */
 
 #define METHOD_NAME__HID        "_HID"
+#define METHOD_NAME__CID        "_CID"
 #define METHOD_NAME__UID        "_UID"
 #define METHOD_NAME__ADR        "_ADR"
 #define METHOD_NAME__STA        "_STA"
@@ -396,6 +397,11 @@
 	NATIVE_CHAR             *object_name,
 	acpi_namespace_node     *device_node,
 	acpi_integer            *address);
+
+acpi_status
+acpi_ut_execute_CID (
+	acpi_namespace_node     *device_node,
+	ACPI_DEVICE_ID          *cid);
 
 acpi_status
 acpi_ut_execute_HID (
diff -urN linux-2.4.13/drivers/acpi/include/platform/acgcc.h linux-2.4.13-lia/drivers/acpi/include/platform/acgcc.h
--- linux-2.4.13/drivers/acpi/include/platform/acgcc.h	Wed Oct 24 10:17:44 2001
+++ linux-2.4.13-lia/drivers/acpi/include/platform/acgcc.h	Wed Oct 24 18:17:50 2001
@@ -42,11 +42,32 @@
 
 /*! [Begin] no source code translation */
 
+#include <linux/interrupt.h>
+
+#include <asm/processor.h>
 #include <asm/pal.h>
 
 #define halt()              ia64_pal_halt_light()           /* PAL_HALT[_LIGHT] */
 #define safe_halt()         ia64_pal_halt(1)                /* PAL_HALT */
 
+static inline void
+wbinvd (void)
+{
+	unsigned long flags, vector, position = 0;
+	long status;
+
+	do {
+		ia64_clear_ic(flags);
+		status = ia64_pal_cache_flush(0x3, (PAL_CACHE_FLUSH_INVALIDATE
+						    | PAL_CACHE_FLUSH_CHK_INTRS),
+					      &position, &vector);
+		local_irq_restore(flags);
+		if (status = 1) {
+			ia64_eoi();
+			hw_resend_irq(NULL, vector);
+		}
+	} while (status = 1);
+}
 
 #define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \
 	do { \
diff -urN linux-2.4.13/drivers/acpi/namespace/nsxfobj.c linux-2.4.13-lia/drivers/acpi/namespace/nsxfobj.c
--- linux-2.4.13/drivers/acpi/namespace/nsxfobj.c	Mon Sep 24 15:06:43 2001
+++ linux-2.4.13-lia/drivers/acpi/namespace/nsxfobj.c	Wed Oct 24 18:18:06 2001
@@ -588,6 +588,7 @@
 	acpi_namespace_node     *node;
 	u32                     flags;
 	ACPI_DEVICE_ID          device_id;
+	ACPI_DEVICE_ID          compatible_id;
 	ACPI_GET_DEVICES_INFO   *info;
 
 
@@ -628,7 +629,17 @@
 		}
 
 		if (STRNCMP (device_id.buffer, info->hid, sizeof (device_id.buffer)) != 0) {
-			return (AE_OK);
+			status = acpi_ut_execute_CID (node, &compatible_id);
+			if (status = AE_NOT_FOUND) {
+				return (AE_OK);
+			}
+			else if (ACPI_FAILURE (status)) {
+				return (AE_CTRL_DEPTH);
+			}
+
+			if (STRNCMP (compatible_id.buffer, info->hid, sizeof (compatible_id.buffer)) != 0) {
+				return (AE_OK);
+			}
 		}
 	}
 
diff -urN linux-2.4.13/drivers/acpi/os.c linux-2.4.13-lia/drivers/acpi/os.c
--- linux-2.4.13/drivers/acpi/os.c	Mon Sep 24 15:06:43 2001
+++ linux-2.4.13-lia/drivers/acpi/os.c	Thu Oct  4 00:21:40 2001
@@ -31,6 +31,8 @@
  * - Fixed improper kernel_thread parameters 
  */
 
+#include <linux/config.h>
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
@@ -48,7 +50,8 @@
 
 #ifdef _IA64
 #include <asm/hw_irq.h>
-#endif 
+#include <asm/delay.h>
+#endif
 
 #define _COMPONENT	ACPI_OS_SERVICES
 	MODULE_NAME	("os")
@@ -61,6 +64,33 @@
 
 
 /*****************************************************************************
+ *			       Function Binding
+ *****************************************************************************/
+
+#ifdef	CONFIG_ACPI_KERNEL_CONFIG
+#include "osconf.h"
+
+struct acpi_osd acpi_osd_rt = {
+	/* these are runtime osd entries that differ from boottime entries */
+	acpi_os_allocate_rt,
+	acpi_os_callocate_rt,
+	acpi_os_free_rt,
+	acpi_os_queue_for_execution_rt,
+	acpi_os_read_pci_configuration_rt,
+	acpi_os_write_pci_configuration_rt,
+	acpi_os_stall_rt
+};
+#else
+#define	acpi_os_allocate_rt		acpi_os_allocate
+#define	acpi_os_callocate_rt		acpi_os_callocate
+#define	acpi_os_free_rt			acpi_os_free
+#define acpi_os_queue_for_execution_rt	acpi_os_queue_for_execution
+#define acpi_os_read_pci_configuration_rt	acpi_os_read_pci_configuration
+#define acpi_os_write_pci_configuration_rt	acpi_os_write_pci_configuration
+#define acpi_os_stall_rt acpi_os_stall
+#endif
+
+/*****************************************************************************
  *			       Debugger Stuff
  *****************************************************************************/
 
@@ -137,13 +167,13 @@
 }
 
 void *
-acpi_os_allocate(u32 size)
+acpi_os_allocate_rt(u32 size)
 {
 	return kmalloc(size, GFP_KERNEL);
 }
 
 void *
-acpi_os_callocate(u32 size)
+acpi_os_callocate_rt(u32 size)
 {
 	void *ptr = acpi_os_allocate(size);
 	if (ptr)
@@ -153,7 +183,7 @@
 }
 
 void
-acpi_os_free(void *ptr)
+acpi_os_free_rt(void *ptr)
 {
 	kfree(ptr);
 }
@@ -233,12 +263,105 @@
 	(*acpi_irq_handler)(acpi_irq_context);
 }
 
+#ifdef	CONFIG_ACPI_KERNEL_CONFIG
+struct irqaction	acpiirqaction;
+/*
+ * codes from request_irq and free_irq.
+ */
 acpi_status
 acpi_os_install_interrupt_handler(u32 irq, OSD_HANDLER handler, void *context)
 {
-#ifdef _IA64
+	struct irqaction	*act;
+	int	retval;
+
+	if (irq >= NR_IRQS) {
+		printk("ACPI: install SCI handler fail: invalid irq%d\n", irq);
+		return AE_ERROR;
+	}
+
+	if (!handler) {
+		printk("ACPI: install SCI handler fail: invalid handler\n");
+		return AE_ERROR;
+	}
+
+	act = & acpiirqaction;
+
 	irq = isa_irq_to_vector(irq);
-#endif /*_IA64*/
+	acpi_irq_irq = irq;
+	acpi_irq_handler = handler;
+	acpi_irq_context = context;
+
+	act->handler = acpi_irq;
+	act->flags = SA_INTERRUPT | SA_SHIRQ;
+	act->mask = 0;
+	act->name = "acpi";
+	act->next = NULL;
+	act->dev_id = acpi_irq;
+
+	retval = setup_irq(irq, act);
+	if (retval) {
+		printk("ACPI: install SCI handler fail: setup_irq\n");
+		acpi_irq_handler = NULL;
+		return AE_ERROR;
+	}
+	printk("ACPI: install SCI %d handler pass\n", irq);
+
+	return AE_OK;
+}
+
+acpi_status
+acpi_os_remove_interrupt_handler(u32 irq, OSD_HANDLER handler)
+{
+	irq_desc_t *desc;
+	struct irqaction **p;
+	unsigned long flags;
+
+	if (!acpi_irq_handler)
+		return AE_OK;
+
+	irq = isa_irq_to_vector(irq);
+	if (irq != acpi_irq_irq) return AE_ERROR;
+
+	acpi_irq_handler = NULL;
+
+	desc = irq_desc(irq);
+	spin_lock_irqsave(&desc->lock,flags);
+	p = &desc->action;
+	for (;;) {
+		struct irqaction * action = *p;
+		if (action) {
+			struct irqaction **pp = p;
+			p = &action->next;
+			if (action->dev_id != acpi_irq)
+				continue;
+
+			/* Found it - now remove it from the list of entries */
+			*pp = action->next;
+			if (!desc->action) {
+				desc->status |= IRQ_DISABLED;
+				desc->handler->shutdown(irq);
+			}
+			spin_unlock_irqrestore(&desc->lock,flags);
+
+#ifdef CONFIG_SMP
+			/* Wait to make sure it's not being used on another CPU */
+			while (desc->status & IRQ_INPROGRESS)
+				barrier();
+#endif
+			return AE_OK;
+		}
+		printk("ACPI: Trying to free free IRQ%d\n",irq);
+		spin_unlock_irqrestore(&desc->lock,flags);
+		return AE_OK;
+	}
+
+	return AE_OK;
+}
+
+#else
+acpi_status
+acpi_os_install_interrupt_handler(u32 irq, OSD_HANDLER handler, void *context)
+{
 	acpi_irq_irq = irq;
 	acpi_irq_handler = handler;
 	acpi_irq_context = context;
@@ -267,6 +390,7 @@
 
 	return AE_OK;
 }
+#endif
 
 /*
  * Running in interpreter thread context, safe to sleep
@@ -280,7 +404,7 @@
 }
 
 void
-acpi_os_stall(u32 us)
+acpi_os_stall_rt(u32 us)
 {
 	if (us > 10000) {
 		mdelay(us / 1000);
@@ -322,7 +446,7 @@
 acpi_status
 acpi_os_write_port(
 	ACPI_IO_ADDRESS	port,
-	u32		value,
+	NATIVE_UINT	value,
 	u32		width)
 {
 	switch (width)
@@ -375,7 +499,7 @@
 acpi_status
 acpi_os_write_memory(
 	ACPI_PHYSICAL_ADDRESS	phys_addr,
-	u32			value,
+	NATIVE_UINT		value,
 	u32			width)
 {
 	switch (width)
@@ -468,7 +592,7 @@
 #else /*CONFIG_ACPI_PCI*/
 
 acpi_status
-acpi_os_read_pci_configuration (
+acpi_os_read_pci_configuration_rt (
 	acpi_pci_id	*pci_id,
 	u32		reg,
 	void		*value,
@@ -502,10 +626,10 @@
 }
 
 acpi_status
-acpi_os_write_pci_configuration (
+acpi_os_write_pci_configuration_rt (
 	acpi_pci_id	*pci_id,
 	u32		reg,
-	u32		value,
+	NATIVE_UINT	value,
 	u32		width)
 {
 	int devfn = PCI_DEVFN(pci_id->device, pci_id->function);
@@ -620,6 +744,22 @@
 		acpi_os_free(dpc);
 	}
 }
+
+#ifdef CONFIG_ACPI_KERNEL_CONFIG
+/*
+ * Queue for interpreter thread
+ */
+
+acpi_status
+acpi_os_queue_for_execution_rt(
+	u32 priority,
+	OSD_EXECUTION_CALLBACK callback,
+	void *context)
+{
+	(*callback)(context);
+	return AE_OK;
+}
+#endif
 
 acpi_status
 acpi_os_queue_for_execution(
diff -urN linux-2.4.13/drivers/acpi/osconf.c linux-2.4.13-lia/drivers/acpi/osconf.c
--- linux-2.4.13/drivers/acpi/osconf.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/acpi/osconf.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,286 @@
+/*
+ *  osconf.c - ACPI OS-dependent functions for Kernel Boot/Configuration time
+ *
+ *  Copyright (C) 2000 Intel Corp.
+ *  Copyright (C) 2000 J.I. Lee <Jung-Ik.Lee@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/pci.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/sal.h>
+#include <asm/delay.h>
+
+#include "acpi.h"
+#include "osconf.h"
+
+
+static void * __init acpi_os_allocate_bt(u32 size);
+static void * __init acpi_os_callocate_bt(u32 size);
+static void __init acpi_os_free_bt(void *ptr);
+static void __init acpi_os_stall_bt(u32 us);
+
+static acpi_status __init
+acpi_os_queue_for_execution_bt(
+	u32			priority,
+	OSD_EXECUTION_CALLBACK	callback,
+	void			*context
+	);
+
+static acpi_status __init
+acpi_os_read_pci_configuration_bt( acpi_pci_id *pci_id, u32 reg, void *value, u32 width);
+
+static acpi_status __init
+acpi_os_write_pci_configuration_bt( acpi_pci_id *pci_id, u32 reg, NATIVE_UINT value, u32 width);
+
+
+extern struct acpi_osd acpi_osd_rt;
+static struct acpi_osd acpi_osd_bt __initdata = {
+	/* these are boottime osd entries that differ from runtime entries */
+	acpi_os_allocate_bt,
+	acpi_os_callocate_bt,
+	acpi_os_free_bt,
+	acpi_os_queue_for_execution_bt,
+	acpi_os_read_pci_configuration_bt,
+	acpi_os_write_pci_configuration_bt,
+	acpi_os_stall_bt
+};
+static struct acpi_osd *acpi_osd = &acpi_osd_rt;
+
+#ifdef	CONFIG_ACPI_KERNEL_CONFIG_BM_PROFILE
+static void	__init
+acpi_cf_bm_statistics( void );
+#endif
+
+void __init
+acpi_os_bind_osd(int	acpi_phase)
+{
+	switch (acpi_phase) {
+	case	ACPI_CF_PHASE_BOOTTIME:
+		acpi_osd = &acpi_osd_bt;
+		printk("Acpi cfg:bind to Boot time Acpi OSD\n");
+		break;
+	case	ACPI_CF_PHASE_RUNTIME:
+	default:
+		acpi_osd = &acpi_osd_rt;
+		printk("Acpi cfg:bind to Run time Acpi OSD\n");
+#ifdef	CONFIG_ACPI_KERNEL_CONFIG_BM_PROFILE
+		acpi_cf_bm_statistics();
+#endif
+		break;
+	}
+}
+
+void *
+acpi_os_allocate(u32 size)
+{
+	return acpi_osd->allocate(size);
+}
+
+void *
+acpi_os_callocate(u32 size)
+{
+	return acpi_osd->callocate(size);
+}
+
+void
+acpi_os_free(void *ptr)
+{
+	acpi_osd->free(ptr);
+	return;
+}
+
+void
+acpi_os_stall(u32 us)
+{
+	acpi_osd->stall(us);
+	return;
+}
+
+acpi_status
+acpi_os_read_pci_configuration( acpi_pci_id *pci_id, u32 reg, void *value, u32 width)
+{
+	return acpi_osd->read_pci_configuration(pci_id, reg, value, width);
+}
+
+
+acpi_status
+acpi_os_write_pci_configuration( acpi_pci_id *pci_id, u32 reg, NATIVE_UINT value, u32 width)
+{
+	return acpi_osd->write_pci_configuration(pci_id, reg, value, width);
+}
+
+
+#ifdef	CONFIG_ACPI_KERNEL_CONFIG_BM_PROFILE
+/*
+ * Let's profile bootmem usage to see how much we consume. J.I.
+ */
+static	unsigned long	bm_alloc_size __initdata = 0;
+static	unsigned long	bm_alloc_size_max __initdata = 0;
+static	unsigned long	bm_alloc_count_max __initdata = 0;
+static	unsigned long	bm_free_count_max __initdata = 0;
+
+static void	__init
+acpi_cf_bm_checkin(void *ptr, u32 size)
+{
+	bm_alloc_count_max++;
+	bm_alloc_size += size;
+	if (bm_alloc_size > bm_alloc_size_max)
+		bm_alloc_size_max = bm_alloc_size;
+};
+
+static void	__init
+acpi_cf_bm_checkout(void *ptr, u32 size)
+{
+	bm_free_count_max++;
+	bm_alloc_size -= size;
+};
+
+static void	__init
+acpi_cf_bm_statistics( void )
+{
+	printk("Acpi cfg:bm_alloc_size_max =%ld bytes\n", bm_alloc_size_max);
+	printk("Acpi cfg:bm_alloc_count_max=%ld\n", bm_alloc_count_max);
+	printk("Acpi cfg:bm_free_count_max =%ld\n", bm_free_count_max);
+}
+#endif
+
+
+static void * __init
+acpi_os_allocate_bt(u32 size)
+{
+	void *ptr;
+
+	size += sizeof(unsigned long);
+	ptr = alloc_bootmem(size);
+
+	if (ptr) {
+#ifdef	CONFIG_ACPI_KERNEL_CONFIG_BM_PROFILE
+		acpi_cf_bm_checkin(ptr, size);
+#endif
+		*((unsigned long *)ptr) = (unsigned long)size;
+		ptr += sizeof(unsigned long);
+	}
+
+	return ptr;
+}
+
+static void * __init
+acpi_os_callocate_bt(u32 size)
+{
+	void *ptr = acpi_os_allocate_bt(size);
+
+	return ptr;
+}
+
+static void __init
+acpi_os_free_bt(void *ptr)
+{
+	unsigned long	size;
+
+	ptr -= sizeof(size);
+	size = *((unsigned long *)ptr);
+
+#ifdef	CONFIG_ACPI_KERNEL_CONFIG_BM_PROFILE
+	acpi_cf_bm_checkout(ptr, (unsigned long)size);
+#endif
+	//if (size)
+		free_bootmem (__pa((unsigned long)ptr), (u32)size);
+}
+
+
+static void __init
+acpi_os_stall_bt(u32 us)
+{
+	unsigned long start = ia64_get_itc();
+	unsigned long cycles = us*733;	/* XXX: 733 or 800 */
+	while (ia64_get_itc() - start < cycles)
+		/* skip */;
+}
+
+
+static acpi_status __init
+acpi_os_queue_for_execution_bt(
+	u32			priority,
+	OSD_EXECUTION_CALLBACK	callback,
+	void			*context)
+{
+	/*
+	 * run callback immediately
+	 */
+	(*callback)(context);
+	return AE_OK;
+}
+
+
+static acpi_status __init
+acpi_os_read_pci_configuration_bt (
+	acpi_pci_id	*pci_id,
+	u32		reg,
+	void		*value,
+	u32		width)
+{
+	unsigned int	devfn;
+	s64		status;
+	u64		lval;
+
+	devfn = PCI_DEVFN(pci_id->device, pci_id->function);
+
+	switch (width)
+	{
+	case 8:
+		status = ia64_sal_pci_config_read(PCI_CONFIG_ADDRESS((pci_id->bus), devfn, reg), 1, &lval);
+		*(u8*)value = (u8)lval;
+		break;
+	case 16:
+		status = ia64_sal_pci_config_read(PCI_CONFIG_ADDRESS((pci_id->bus), devfn, reg), 2, &lval);
+		*(u16*)value = (u16)lval;
+		break;
+	case 32:
+		status = ia64_sal_pci_config_read(PCI_CONFIG_ADDRESS((pci_id->bus), devfn, reg), 4, &lval);
+		*(u32*)value = (u32)lval;
+		break;
+	default:
+		BUG();
+	}
+
+	return status;
+}
+
+
+static acpi_status __init
+acpi_os_write_pci_configuration_bt (
+	acpi_pci_id	*pci_id,
+	u32		reg,
+	NATIVE_UINT	value,
+	u32		width)
+{
+	unsigned int	devfn;
+	s64		status;
+
+	devfn = PCI_DEVFN(pci_id->device, pci_id->function);
+
+	switch (width)
+	{
+	case 8:
+		status = ia64_sal_pci_config_write(PCI_CONFIG_ADDRESS((pci_id->bus), devfn, reg), 1, value);
+		break;
+	case 16:
+		status = ia64_sal_pci_config_write(PCI_CONFIG_ADDRESS((pci_id->bus), devfn, reg), 2, value);
+		break;
+	case 32:
+		status = ia64_sal_pci_config_write(PCI_CONFIG_ADDRESS((pci_id->bus), devfn, reg), 4, value);
+		break;
+	default:
+		BUG();
+	}
+
+	return status;
+}
diff -urN linux-2.4.13/drivers/acpi/osconf.h linux-2.4.13-lia/drivers/acpi/osconf.h
--- linux-2.4.13/drivers/acpi/osconf.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/acpi/osconf.h	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,57 @@
+/*
+ *  osconf.h - ACPI OS-dependent headers for Kernel Boot/Configuration time
+ *
+ *  Copyright (C) 2000 Intel Corp.
+ *  Copyright (C) 2000 J.I. Lee <Jung-Ik.Lee@intel.com>
+ */
+
+
+struct acpi_osd {
+	void * (*allocate)(u32 size);
+	void * (*callocate)(u32 size);
+	void  (*free)(void *ptr);
+	acpi_status (*queue_for_exec)(u32 pri, OSD_EXECUTION_CALLBACK cb, void *context);
+	acpi_status (*read_pci_configuration)(acpi_pci_id *pci_id, u32 reg, void *value, u32 width);
+	acpi_status (*write_pci_configuration)(acpi_pci_id *pci_id, u32 reg, NATIVE_UINT value, u32 width);
+	void (*stall)(u32 us);
+};
+
+
+#define	PCI_CONFIG_ADDRESS(bus, devfn, where) \
+	(((u64) bus << 16) | ((u64) (devfn & 0xff) << 8) | (where & 0xff))
+
+#define	ACPI_CF_PHASE_BOOTTIME	0x00
+#define	ACPI_CF_PHASE_RUNTIME	0x01
+
+
+/* acpi_osd functions */
+void * acpi_os_allocate(u32 size);
+void * acpi_os_callocate(u32 size);
+void acpi_os_free(void *ptr);
+void acpi_os_stall(u32 us);
+
+acpi_status
+acpi_os_read_pci_configuration( acpi_pci_id *pci_id, u32 reg, void *value, u32 width );
+
+acpi_status
+acpi_os_write_pci_configuration( acpi_pci_id *pci_id, u32 reg, NATIVE_UINT value, u32 width );
+
+
+/* acpi_osd_rt functions */
+extern void * acpi_os_allocate_rt(u32 size);
+extern void * acpi_os_callocate_rt(u32 size);
+extern void acpi_os_free_rt(void *ptr);
+extern void acpi_os_stall_rt(u32 us);
+
+extern acpi_status
+acpi_os_queue_for_execution_rt(
+	u32			priority,
+	OSD_EXECUTION_CALLBACK	callback,
+	void			*context
+	);
+
+extern acpi_status
+acpi_os_read_pci_configuration_rt( acpi_pci_id *pci_id, u32 reg, void *value, u32 width );
+
+extern acpi_status
+acpi_os_write_pci_configuration_rt( acpi_pci_id *pci_id, u32 reg, NATIVE_UINT value, u32 width );
diff -urN linux-2.4.13/drivers/acpi/ospm/include/ec.h linux-2.4.13-lia/drivers/acpi/ospm/include/ec.h
--- linux-2.4.13/drivers/acpi/ospm/include/ec.h	Mon Sep 24 15:06:44 2001
+++ linux-2.4.13-lia/drivers/acpi/ospm/include/ec.h	Thu Oct  4 00:21:40 2001
@@ -167,14 +167,14 @@
 acpi_status
 ec_io_read (
 	EC_CONTEXT              *ec,
-	u32         		io_port,
+	ACPI_IO_ADDRESS		io_port,
 	u8                      *data,
 	EC_EVENT                wait_event);
 
 acpi_status
 ec_io_write (
 	EC_CONTEXT              *ec,
-	u32         		io_port,
+	ACPI_IO_ADDRESS		io_port,
 	u8                      data,
 	EC_EVENT                wait_event);
 
diff -urN linux-2.4.13/drivers/acpi/ospm/system/sm_osl.c linux-2.4.13-lia/drivers/acpi/ospm/system/sm_osl.c
--- linux-2.4.13/drivers/acpi/ospm/system/sm_osl.c	Mon Sep 24 15:06:44 2001
+++ linux-2.4.13-lia/drivers/acpi/ospm/system/sm_osl.c	Thu Oct  4 00:21:40 2001
@@ -33,7 +33,9 @@
 #include <asm/uaccess.h>
 #include <linux/acpi.h>
 #include <asm/io.h>
+#ifndef __ia64__
 #include <linux/mc146818rtc.h>
+#endif
 #include <linux/delay.h>
 
 #include <acpi.h>
@@ -278,6 +280,7 @@
 	int                     *eof,
 	void                    *context)
 {
+#ifndef _IA64
 	char *str = page;
 	int len;
 	u32 sec,min,hr;
@@ -351,6 +354,9 @@
 	*start = page;
 
 	return len;
+#else
+	return 0;
+#endif
 }
 
 static int get_date_field(char **str, u32 *value)
@@ -381,6 +387,7 @@
 	unsigned long count,
 	void *data)
 {
+#ifndef _IA64
 	char buf[30];
 	char *str = buf;
 	u32 sec,min,hr;
@@ -520,6 +527,9 @@
 	error = 0;
  out:
 	return error ? error : count;
+#else
+	return 0;
+#endif
 }
 
 static int 
diff -urN linux-2.4.13/drivers/acpi/utilities/uteval.c linux-2.4.13-lia/drivers/acpi/utilities/uteval.c
--- linux-2.4.13/drivers/acpi/utilities/uteval.c	Mon Sep 24 15:06:47 2001
+++ linux-2.4.13-lia/drivers/acpi/utilities/uteval.c	Wed Oct 24 18:18:19 2001
@@ -115,6 +115,93 @@
 
 /*******************************************************************************
  *
+ * FUNCTION:    Acpi_ut_execute_CID
+ *
+ * PARAMETERS:  Device_node         - Node for the device
+ *              *Cid                - Where the CID is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Executes the _CID control method that returns the compatible
+ *              ID of the device.
+ *
+ *              NOTE: Internal function, no parameter validation
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_execute_CID (
+	acpi_namespace_node     *device_node,
+	ACPI_DEVICE_ID          *cid)
+{
+	acpi_operand_object     *obj_desc;
+	acpi_status             status;
+
+
+	FUNCTION_TRACE ("Ut_execute_CID");
+
+
+	/* Execute the method */
+
+	status = acpi_ns_evaluate_relative (device_node,
+			 METHOD_NAME__CID, NULL, &obj_desc);
+	if (ACPI_FAILURE (status)) {
+		if (status = AE_NOT_FOUND) {
+			ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "_CID on %4.4s was not found\n",
+				&device_node->name));
+		}
+
+		else {
+			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "_CID on %4.4s failed %s\n",
+				&device_node->name, acpi_format_exception (status)));
+		}
+
+		return_ACPI_STATUS (status);
+	}
+
+	/* Did we get a return object? */
+
+	if (!obj_desc) {
+		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No object was returned from _CID\n"));
+		return_ACPI_STATUS (AE_TYPE);
+	}
+
+	/*
+	 *  A _CID can return either a Number (32 bit compressed EISA ID) or
+	 *  a string
+	 */
+	if ((obj_desc->common.type != ACPI_TYPE_INTEGER) &&
+		(obj_desc->common.type != ACPI_TYPE_STRING)) {
+		status = AE_TYPE;
+		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+			"Type returned from _CID not a number or string: %s(%X) \n",
+			acpi_ut_get_type_name (obj_desc->common.type), obj_desc->common.type));
+	}
+
+	else {
+		if (obj_desc->common.type = ACPI_TYPE_INTEGER) {
+			/* Convert the Numeric CID to string */
+
+			acpi_ex_eisa_id_to_string ((u32) obj_desc->integer.value, cid->buffer);
+		}
+
+		else {
+			/* Copy the String CID from the returned object */
+
+			STRNCPY(cid->buffer, obj_desc->string.pointer, sizeof(cid->buffer));
+		}
+	}
+
+
+	/* On exit, we must delete the return object */
+
+	acpi_ut_remove_reference (obj_desc);
+
+	return_ACPI_STATUS (status);
+}
+
+/*******************************************************************************
+ *
  * FUNCTION:    Acpi_ut_execute_HID
  *
  * PARAMETERS:  Device_node         - Node for the device
diff -urN linux-2.4.13/drivers/char/Config.in linux-2.4.13-lia/drivers/char/Config.in
--- linux-2.4.13/drivers/char/Config.in	Wed Oct 24 10:17:45 2001
+++ linux-2.4.13-lia/drivers/char/Config.in	Wed Oct 24 10:21:08 2001
@@ -207,6 +207,9 @@
 dep_tristate '/dev/agpgart (AGP Support)' CONFIG_AGP $CONFIG_DRM_AGP
 if [ "$CONFIG_AGP" != "n" ]; then
    bool '  Intel 440LX/BX/GX and I815/I830M/I840/I850 support' CONFIG_AGP_INTEL
+   if [ "$CONFIG_IA64" != "n" ]; then
+   	bool '  Intel 460GX support' CONFIG_AGP_I460
+   fi
    bool '  Intel I810/I815/I830M (on-board) support' CONFIG_AGP_I810
    bool '  VIA chipset support' CONFIG_AGP_VIA
    bool '  AMD Irongate, 761, and 762 support' CONFIG_AGP_AMD
@@ -215,7 +218,17 @@
    bool '  Serverworks LE/HE support' CONFIG_AGP_SWORKS
 fi
 
-source drivers/char/drm/Config.in
+bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM
+
+if [ "$CONFIG_DRM" = "y" ]; then
+   bool '  Build drivers for new (XFree 4.1) DRM' CONFIG_DRM_NEW
+   if [ "$CONFIG_DRM_NEW" = "y" ]; then
+      source drivers/char/drm/Config.in
+   else
+      define_bool CONFIG_DRM_OLD y
+      source drivers/char/drm-4.0/Config.in
+   fi
+fi
 
 if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
    source drivers/char/pcmcia/Config.in
diff -urN linux-2.4.13/drivers/char/Makefile linux-2.4.13-lia/drivers/char/Makefile
--- linux-2.4.13/drivers/char/Makefile	Wed Oct 24 10:17:45 2001
+++ linux-2.4.13-lia/drivers/char/Makefile	Wed Oct 24 10:21:08 2001
@@ -25,7 +25,7 @@
 			misc.o pty.o random.o selection.o serial.o \
 			sonypi.o tty_io.o tty_ioctl.o generic_serial.o
 
-mod-subdirs	:=	joystick ftape drm pcmcia
+mod-subdirs	:=	joystick ftape drm pcmcia drm-4.0
 
 list-multi	:=	
 
@@ -138,6 +138,7 @@
 
 obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
 obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
+obj-$(CONFIG_SIM_SERIAL) += simserial.o
 obj-$(CONFIG_ROCKETPORT) += rocket.o
 obj-$(CONFIG_MOXA_SMARTIO) += mxser.o
 obj-$(CONFIG_MOXA_INTELLIO) += moxa.o
@@ -198,7 +199,8 @@
 obj-$(CONFIG_QIC02_TAPE) += tpqic02.o
 
 subdir-$(CONFIG_FTAPE) += ftape
-subdir-$(CONFIG_DRM) += drm
+subdir-$(CONFIG_DRM_NEW) += drm
+subdir-$(CONFIG_DRM_OLD) += drm-4.0
 subdir-$(CONFIG_PCMCIA) += pcmcia
 subdir-$(CONFIG_AGP) += agp
 
diff -urN linux-2.4.13/drivers/char/agp/agp.h linux-2.4.13-lia/drivers/char/agp/agp.h
--- linux-2.4.13/drivers/char/agp/agp.h	Wed Oct 10 16:31:46 2001
+++ linux-2.4.13-lia/drivers/char/agp/agp.h	Wed Oct 10 16:33:17 2001
@@ -84,8 +84,8 @@
 	void *dev_private_data;
 	struct pci_dev *dev;
 	gatt_mask *masks;
-	unsigned long *gatt_table;
-	unsigned long *gatt_table_real;
+	u32 *gatt_table;
+	u32 *gatt_table_real;
 	unsigned long scratch_page;
 	unsigned long gart_bus_addr;
 	unsigned long gatt_bus_addr;
@@ -111,6 +111,7 @@
 	void (*cleanup) (void);
 	void (*tlb_flush) (agp_memory *);
 	unsigned long (*mask_memory) (unsigned long, int);
+	unsigned long (*unmask_memory) (unsigned long);
 	void (*cache_flush) (void);
 	int (*create_gatt_table) (void);
 	int (*free_gatt_table) (void);
@@ -150,6 +151,10 @@
 #define A_IDXFIX()	(A_SIZE_FIX(agp_bridge.aperture_sizes) + i)
 #define MAXKEY		(4096 * 32)
 
+#ifndef max
+#define max(a,b)	(((a)>(b))?(a):(b))
+#endif
+
 #define AGPGART_MODULE_NAME	"agpgart"
 #define PFX			AGPGART_MODULE_NAME ": "
 
@@ -209,6 +214,9 @@
 #ifndef PCI_DEVICE_ID_INTEL_82443GX_1
 #define PCI_DEVICE_ID_INTEL_82443GX_1   0x71a1
 #endif
+#ifndef PCI_DEVICE_ID_INTEL_460GX
+#define PCI_DEVICE_ID_INTEL_460GX	 0x84ea
+#endif
 #ifndef PCI_DEVICE_ID_AMD_IRONGATE_0
 #define PCI_DEVICE_ID_AMD_IRONGATE_0    0x7006
 #endif
@@ -250,6 +258,15 @@
 #define INTEL_AGPCTRL   0xb0
 #define INTEL_NBXCFG    0x50
 #define INTEL_ERRSTS    0x91
+
+/* Intel 460GX Registers */
+#define INTEL_I460_APBASE		0x10
+#define INTEL_I460_BAPBASE		0x98
+#define INTEL_I460_GXBCTL		0xa0
+#define INTEL_I460_AGPSIZ		0xa2
+#define INTEL_I460_ATTBASE		0xfe200000
+#define INTEL_I460_GATT_VALID		(1UL << 24)
+#define INTEL_I460_GATT_COHERENT	(1UL << 25)
 
 /* intel i840 registers */
 #define INTEL_I840_MCHCFG   0x50
diff -urN linux-2.4.13/drivers/char/agp/agpgart_be.c linux-2.4.13-lia/drivers/char/agp/agpgart_be.c
--- linux-2.4.13/drivers/char/agp/agpgart_be.c	Wed Oct 10 16:31:46 2001
+++ linux-2.4.13-lia/drivers/char/agp/agpgart_be.c	Wed Oct 10 16:33:17 2001
@@ -22,6 +22,7 @@
  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 
  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  *
+ * 460GX support by Chris Ahna <christopher.j.ahna@intel.com>
  */
 #include <linux/config.h>
 #include <linux/version.h>
@@ -43,6 +44,9 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/smplock.h>
 
 #include <linux/agp_backend.h>
 #include "agp.h"
@@ -60,7 +64,7 @@
 EXPORT_SYMBOL(agp_backend_release);
 
 static void flush_cache(void);
-
+ 
 static struct agp_bridge_data agp_bridge;
 static int agp_try_unsupported __initdata = 0;
 
@@ -205,19 +209,56 @@
 		agp_bridge.free_by_type(curr);
 		return;
 	}
-	if (curr->page_count != 0) {
-		for (i = 0; i < curr->page_count; i++) {
-			curr->memory[i] &= ~(0x00000fff);
-			agp_bridge.agp_destroy_page((unsigned long)
-					 phys_to_virt(curr->memory[i]));
+	if(agp_bridge.cant_use_aperture = 0) {
+		if (curr->page_count != 0) {
+			for (i = 0; i < curr->page_count; i++) {
+				curr->memory[i] = agp_bridge.unmask_memory(
+					                     curr->memory[i]);
+				agp_bridge.agp_destroy_page((unsigned long)
+						 phys_to_virt(curr->memory[i]));
+			}
 		}
+	} else {
+		vfree(curr->vmptr);
 	}
+
 	agp_free_key(curr->key);
 	vfree(curr->memory);
 	kfree(curr);
 	MOD_DEC_USE_COUNT;
 }
 
+#define IN_VMALLOC(_x)	  (((_x) >= VMALLOC_START) && ((_x) < VMALLOC_END))
+
+/*
+ * Look up and return the pte corresponding to addr.  We only do this for
+ * agp_ioremap'ed addresses. 
+ */
+static pte_t * agp_lookup_pte(unsigned long addr) { 
+
+	pgd_t			*dir;
+	pmd_t			*pmd;
+	pte_t			*pte;
+
+	if(!IN_VMALLOC(addr))
+		return NULL;
+
+	dir = pgd_offset_k(addr);
+	pmd = pmd_offset(dir, addr);
+
+	if(pmd) {
+		pte = pte_offset(pmd, addr);
+
+		if(pte) {
+			return pte;
+		} else {
+			return NULL;
+		}
+	} else {
+		return NULL;
+	}
+}
+
 #define ENTRIES_PER_PAGE		(PAGE_SIZE / sizeof(unsigned long))
 
 agp_memory *agp_allocate_memory(size_t page_count, u32 type)
@@ -247,24 +288,60 @@
 	scratch_pages = (page_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE;
 
 	new = agp_create_memory(scratch_pages);
-
 	if (new = NULL) {
 	      	MOD_DEC_USE_COUNT;
 		return NULL;
 	}
-	for (i = 0; i < page_count; i++) {
-		new->memory[i] = agp_bridge.agp_alloc_page();
 
-		if (new->memory[i] = 0) {
-			/* Free this structure */
-			agp_free_memory(new);
+	if(agp_bridge.cant_use_aperture = 0) {
+		for (i = 0; i < page_count; i++) {
+			new->memory[i] = agp_bridge.agp_alloc_page();
+
+			if (new->memory[i] = 0) {
+				/* Free this structure */
+				agp_free_memory(new);
+				return NULL;
+			}
+			new->memory[i] +			    agp_bridge.mask_memory(
+					  virt_to_phys((void *) new->memory[i]),
+							  type);
+			new->page_count++;
+		}
+	} else {
+		void *vmblock;
+		unsigned long vaddr, paddr;
+		pte_t *pte;
+
+		vmblock = __vmalloc(page_count << PAGE_SHIFT, GFP_KERNEL,
+#ifdef __ia64__
+					pgprot_writecombine(PAGE_KERNEL));
+#else
+					PAGE_KERNEL);
+#endif
+		if(vmblock = NULL) {
+			MOD_DEC_USE_COUNT;
 			return NULL;
 		}
-		new->memory[i] -		    agp_bridge.mask_memory(
-				   virt_to_phys((void *) new->memory[i]),
-						  type);
-		new->page_count++;
+
+		new->vmptr = vmblock;
+		vaddr = (unsigned long) vmblock;
+
+		for(i = 0; i < page_count; i++, vaddr += PAGE_SIZE) {
+			pte = agp_lookup_pte(vaddr);
+			if(pte = NULL) {
+				MOD_DEC_USE_COUNT;
+				return NULL;
+			}
+#ifdef __ia64__
+			paddr = pte_val(*pte) & _PFN_MASK;
+#else
+			paddr = pte_val(*pte) & PAGE_MASK;
+#endif
+			new->memory[i] = agp_bridge.mask_memory(paddr, type);
+		}
+
+		new->page_count = page_count;
 	}
 
 	return new;
@@ -353,12 +430,13 @@
 		curr->is_flushed = TRUE;
 	}
 	ret_val = agp_bridge.insert_memory(curr, pg_start, curr->type);
-
+		
 	if (ret_val != 0) {
 		return ret_val;
 	}
 	curr->is_bound = TRUE;
 	curr->pg_start = pg_start;
+
 	return 0;
 }
 
@@ -377,6 +455,7 @@
 	if (ret_val != 0) {
 		return ret_val;
 	}
+
 	curr->is_bound = FALSE;
 	curr->pg_start = 0;
 	return 0;
@@ -387,9 +466,9 @@
 /* 
  * Driver routines - start
  * Currently this module supports the following chipsets:
- * i810, i815, 440lx, 440bx, 440gx, i840, i850, via vp3, via mvp3,
- * via kx133, via kt133, amd irongate, amd 761, amd 762, ALi M1541,
- * and generic support for the SiS chipsets.
+ * i810, 440lx, 440bx, 440gx, 460gx, i840, i850, via vp3, via mvp3, via kx133, 
+ * via kt133, amd irongate, ALi M1541, and generic support for the SiS 
+ * chipsets.
  */
 
 /* Generic Agp routines - Start */
@@ -614,7 +693,7 @@
 	for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
 		set_bit(PG_reserved, &page->flags);
 
-	agp_bridge.gatt_table_real = (unsigned long *) table;
+	agp_bridge.gatt_table_real = (u32 *) table;
 	CACHE_FLUSH();
 	agp_bridge.gatt_table = ioremap_nocache(virt_to_phys(table),
 					(PAGE_SIZE * (1 << page_order)));
@@ -832,6 +911,11 @@
 	agp_bridge.agp_enable(mode);
 }
 
+static unsigned long agp_generic_unmask_memory(unsigned long addr)
+{
+	return addr & ~(0x00000fff);
+}
+
 /* End - Generic Agp routines */
 
 #ifdef CONFIG_AGP_I810
@@ -1096,6 +1180,7 @@
 	agp_bridge.cleanup = intel_i810_cleanup;
 	agp_bridge.tlb_flush = intel_i810_tlbflush;
 	agp_bridge.mask_memory = intel_i810_mask_memory;
+	agp_bridge.unmask_memory = agp_generic_unmask_memory;
 	agp_bridge.agp_enable = intel_i810_agp_enable;
 	agp_bridge.cache_flush = global_cache_flush;
 	agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
@@ -1399,6 +1484,633 @@
 
 #endif /* CONFIG_AGP_I810 */
 
+#ifdef CONFIG_AGP_I460
+
+/* BIOS configures the chipset so that one of two apbase registers are used */
+static u8 intel_i460_dynamic_apbase = 0x10;
+
+/* 460 supports multiple GART page sizes, so GART pageshift is dynamic */ 
+static u8 intel_i460_pageshift = 12;
+
+/* Keep track of which is larger, chipset or kernel page size. */
+static u32 intel_i460_cpk = 1;
+
+/* Structure for tracking partial use of 4MB GART pages */
+static u32 **i460_pg_detail = NULL;
+static u32 *i460_pg_count = NULL;
+
+#define I460_CPAGES_PER_KPAGE (PAGE_SIZE >> intel_i460_pageshift)
+#define I460_KPAGES_PER_CPAGE ((1 << intel_i460_pageshift) >> PAGE_SHIFT)
+
+#define I460_SRAM_IO_DISABLE		(1 << 4)
+#define I460_BAPBASE_ENABLE		(1 << 3)
+#define I460_AGPSIZ_MASK		0x7
+#define I460_4M_PS			(1 << 1)
+
+#define log2(x)				ffz(~(x))
+
+static int intel_i460_fetch_size(void)
+{
+	int i;
+	u8 temp;
+	aper_size_info_8 *values;
+
+	/* Determine the GART page size */
+	pci_read_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL, &temp);
+	intel_i460_pageshift = (temp & I460_4M_PS) ? 22 : 12;
+
+	values = A_SIZE_8(agp_bridge.aperture_sizes);
+
+	pci_read_config_byte(agp_bridge.dev, INTEL_I460_AGPSIZ, &temp);
+
+	/* Exit now if the IO drivers for the GART SRAMS are turned off */
+	if(temp & I460_SRAM_IO_DISABLE) {
+		printk("[agpgart] GART SRAMS disabled on 460GX chipset\n");
+		printk("[agpgart] AGPGART operation not possible\n");
+		return 0;
+	}
+
+	/* Make sure we don't try to create an 2 ^ 23 entry GATT */
+	if((intel_i460_pageshift = 0) && ((temp & I460_AGPSIZ_MASK) = 4)) {
+		printk("[agpgart] We can't have a 32GB aperture with 4KB"
+			" GART pages\n");
+		return 0;
+	}
+
+	/* Determine the proper APBASE register */
+	if(temp & I460_BAPBASE_ENABLE)
+		intel_i460_dynamic_apbase = INTEL_I460_BAPBASE;
+	else intel_i460_dynamic_apbase = INTEL_I460_APBASE;
+
+	for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
+
+		/*
+		 * Dynamically calculate the proper num_entries and page_order 
+		 * values for the define aperture sizes. Take care not to
+		 * shift off the end of values[i].size.
+		 */	
+		values[i].num_entries = (values[i].size << 8) >>
+						(intel_i460_pageshift - 12);
+		values[i].page_order = log2((sizeof(u32)*values[i].num_entries)
+						>> PAGE_SHIFT);
+	}
+
+	for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
+		/* Neglect control bits when matching up size_value */
+		if ((temp & I460_AGPSIZ_MASK) = values[i].size_value) {
+			agp_bridge.previous_size +			    agp_bridge.current_size = (void *) (values + i);
+			agp_bridge.aperture_size_idx = i;
+			return values[i].size;
+		}
+	}
+
+	return 0;
+}
+
+/* There isn't anything to do here since 460 has no GART TLB. */ 
+static void intel_i460_tlb_flush(agp_memory * mem)
+{
+	return;
+}
+
+/*
+ * This utility function is needed to prevent corruption of the control bits
+ * which are stored along with the aperture size in 460's AGPSIZ register
+ */
+static void intel_i460_write_agpsiz(u8 size_value)
+{
+	u8 temp;
+
+	pci_read_config_byte(agp_bridge.dev, INTEL_I460_AGPSIZ, &temp);
+	pci_write_config_byte(agp_bridge.dev, INTEL_I460_AGPSIZ,
+		((temp & ~I460_AGPSIZ_MASK) | size_value));
+}
+
+static void intel_i460_cleanup(void)
+{
+	aper_size_info_8 *previous_size;
+
+	previous_size = A_SIZE_8(agp_bridge.previous_size);
+	intel_i460_write_agpsiz(previous_size->size_value);
+
+	if(intel_i460_cpk = 0)
+	{
+		vfree(i460_pg_detail);
+		vfree(i460_pg_count);
+	}
+}
+
+
+/* Control bits for Out-Of-GART coherency and Burst Write Combining */
+#define I460_GXBCTL_OOG		(1UL << 0)
+#define I460_GXBCTL_BWC		(1UL << 2)
+
+static int intel_i460_configure(void)
+{
+	union {
+		u32 small[2];
+		u64 large;
+	} temp;
+	u8 scratch;
+	int i;
+
+	aper_size_info_8 *current_size;
+
+	temp.large = 0;
+
+	current_size = A_SIZE_8(agp_bridge.current_size);
+	intel_i460_write_agpsiz(current_size->size_value);	
+
+	/*
+	 * Do the necessary rigmarole to read all eight bytes of APBASE.
+	 * This has to be done since the AGP aperture can be above 4GB on
+	 * 460 based systems.
+	 */
+	pci_read_config_dword(agp_bridge.dev, intel_i460_dynamic_apbase, 
+		&(temp.small[0]));
+	pci_read_config_dword(agp_bridge.dev, intel_i460_dynamic_apbase + 4,
+		&(temp.small[1]));
+
+	/* Clear BAR control bits */
+	agp_bridge.gart_bus_addr = temp.large & ~((1UL << 3) - 1); 
+
+	pci_read_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL, &scratch);
+	pci_write_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL,
+			  (scratch & 0x02) | I460_GXBCTL_OOG | I460_GXBCTL_BWC);
+
+	/* 
+	 * Initialize partial allocation trackers if a GART page is bigger than
+	 * a kernel page.
+	 */
+	if(I460_CPAGES_PER_KPAGE >= 1) {
+		intel_i460_cpk = 1;
+	} else {
+		intel_i460_cpk = 0;
+
+		i460_pg_detail = (void *) vmalloc(sizeof(*i460_pg_detail) *
+					current_size->num_entries);
+		i460_pg_count = (void *) vmalloc(sizeof(*i460_pg_count) *
+					current_size->num_entries);
+	
+		for (i = 0; i < current_size->num_entries; i++) {
+			i460_pg_count[i] = 0;
+			i460_pg_detail[i] = NULL;
+		}
+	}
+
+	return 0;
+}
+
+static int intel_i460_create_gatt_table(void) {
+
+	char *table;
+	int i;
+	int page_order;
+	int num_entries;
+	void *temp;
+	unsigned int read_back;
+
+	/*
+	 * Load up the fixed address of the GART SRAMS which hold our
+	 * GATT table.
+	 */
+	table = (char *) __va(INTEL_I460_ATTBASE);
+
+	temp = agp_bridge.current_size;
+	page_order = A_SIZE_8(temp)->page_order;
+	num_entries = A_SIZE_8(temp)->num_entries;
+
+	agp_bridge.gatt_table_real = (u32 *) table;
+	agp_bridge.gatt_table = ioremap_nocache(virt_to_phys(table),
+		 			     (PAGE_SIZE * (1 << page_order)));
+	agp_bridge.gatt_bus_addr = virt_to_phys(agp_bridge.gatt_table_real);
+
+	for (i = 0; i < num_entries; i++) {
+		agp_bridge.gatt_table[i] = 0;
+	}
+
+	/* 
+	 * The 460 spec says we have to read the last location written to 
+	 * make sure that all writes have taken effect
+	 */
+	read_back = agp_bridge.gatt_table[i - 1];
+
+	return 0;
+}
+
+static int intel_i460_free_gatt_table(void)
+{
+	int num_entries;
+	int i;
+	void *temp;
+	unsigned int read_back;
+
+	temp = agp_bridge.current_size;
+
+	num_entries = A_SIZE_8(temp)->num_entries;
+
+	for (i = 0; i < num_entries; i++) {
+		agp_bridge.gatt_table[i] = 0;
+	}
+	
+	/* 
+	 * The 460 spec says we have to read the last location written to 
+	 * make sure that all writes have taken effect
+	 */
+	read_back = agp_bridge.gatt_table[i - 1];
+
+	iounmap(agp_bridge.gatt_table);
+
+	return 0;
+}
+
+/* These functions are called when PAGE_SIZE exceeds the GART page size */	
+
+static int intel_i460_insert_memory_cpk(agp_memory * mem,
+				     off_t pg_start, int type)
+{
+	int i, j, k, num_entries;
+	void *temp;
+	unsigned int hold;
+	unsigned int read_back;
+
+	/* 
+	 * The rest of the kernel will compute page offsets in terms of
+	 * PAGE_SIZE.
+	 */
+	pg_start = I460_CPAGES_PER_KPAGE * pg_start;
+
+	temp = agp_bridge.current_size;
+	num_entries = A_SIZE_8(temp)->num_entries;
+
+	if((pg_start + I460_CPAGES_PER_KPAGE * mem->page_count) > num_entries) {
+		printk("[agpgart] Looks like we're out of AGP memory\n");
+		return -EINVAL;
+	}
+
+	j = pg_start;
+	while (j < (pg_start + I460_CPAGES_PER_KPAGE * mem->page_count)) {
+		if (!PGE_EMPTY(agp_bridge.gatt_table[j])) {
+			return -EBUSY;
+		}
+		j++;
+	}
+
+	if (mem->is_flushed = FALSE) {
+		CACHE_FLUSH();
+		mem->is_flushed = TRUE;
+	}
+
+	for (i = 0, j = pg_start; i < mem->page_count; i++) {
+
+		hold = (unsigned int) (mem->memory[i]);
+
+		for (k = 0; k < I460_CPAGES_PER_KPAGE; k++, j++, hold++)
+			agp_bridge.gatt_table[j] = hold;
+	}
+
+	/* 
+	 * The 460 spec says we have to read the last location written to 
+	 * make sure that all writes have taken effect
+	 */
+	read_back = agp_bridge.gatt_table[j - 1];
+
+	return 0;
+}
+
+static int intel_i460_remove_memory_cpk(agp_memory * mem, off_t pg_start,
+				     int type)
+{
+	int i;
+	unsigned int read_back;
+
+	pg_start = I460_CPAGES_PER_KPAGE * pg_start;
+
+	for (i = pg_start; i < (pg_start + I460_CPAGES_PER_KPAGE * 
+							mem->page_count); i++) 
+		agp_bridge.gatt_table[i] = 0;
+
+	/* 
+	 * The 460 spec says we have to read the last location written to 
+	 * make sure that all writes have taken effect
+	 */
+	read_back = agp_bridge.gatt_table[i - 1];
+
+	return 0;
+}
+
+/*
+ * These functions are called when the GART page size exceeds PAGE_SIZE.
+ *
+ * This situation is interesting since AGP memory allocations that are
+ * smaller than a single GART page are possible.  The structures i460_pg_count
+ * and i460_pg_detail track partial allocation of the large GART pages to
+ * work around this issue.
+ *
+ * i460_pg_count[pg_num] tracks the number of kernel pages in use within
+ * GART page pg_num.  i460_pg_detail[pg_num] is an array containing a
+ * psuedo-GART entry for each of the aforementioned kernel pages.  The whole
+ * of i460_pg_detail is equivalent to a giant GATT with page size equal to
+ * that of the kernel.
+ */	
+
+static void *intel_i460_alloc_large_page(int pg_num)
+{
+	int i;
+	void *bp, *bp_end;
+	struct page *page;
+
+	i460_pg_detail[pg_num] = (void *) vmalloc(sizeof(u32) * 
+							I460_KPAGES_PER_CPAGE);
+	if(i460_pg_detail[pg_num] = NULL) {
+		printk("[agpgart] Out of memory, we're in trouble...\n");
+		return NULL;
+	}
+
+	for(i = 0; i < I460_KPAGES_PER_CPAGE; i++)
+		i460_pg_detail[pg_num][i] = 0;
+
+	bp = (void *) __get_free_pages(GFP_KERNEL, 
+					intel_i460_pageshift - PAGE_SHIFT);
+	if(bp = NULL) {
+		printk("[agpgart] Couldn't alloc 4M GART page...\n");
+		return NULL;
+	}
+
+	bp_end = bp + ((PAGE_SIZE * 
+			    (1 << (intel_i460_pageshift - PAGE_SHIFT))) - 1);
+
+	for (page = virt_to_page(bp); page <= virt_to_page(bp_end); page++)
+	{
+		atomic_inc(&page->count);
+		set_bit(PG_locked, &page->flags);
+		atomic_inc(&agp_bridge.current_memory_agp);
+	}
+
+	return bp;		
+}
+
+static void intel_i460_free_large_page(int pg_num, unsigned long addr)
+{
+	struct page *page;
+	void *bp, *bp_end;
+
+	bp = (void *) __va(addr);
+	bp_end = bp + (PAGE_SIZE * 
+			(1 << (intel_i460_pageshift - PAGE_SHIFT)));
+
+	vfree(i460_pg_detail[pg_num]);
+	i460_pg_detail[pg_num] = NULL;
+
+	for (page = virt_to_page(bp); page < virt_to_page(bp_end); page++)
+	{
+		atomic_dec(&page->count);
+		clear_bit(PG_locked, &page->flags);
+		wake_up(&page->wait);
+		atomic_dec(&agp_bridge.current_memory_agp);
+	}
+
+	free_pages((unsigned long) bp, intel_i460_pageshift - PAGE_SHIFT);
+}
+	
+static int intel_i460_insert_memory_kpc(agp_memory * mem,
+				     off_t pg_start, int type)
+{
+	int i, pg, start_pg, end_pg, start_offset, end_offset, idx;
+	int num_entries;	
+	void *temp;
+	unsigned int read_back;
+
+	temp = agp_bridge.current_size;
+	num_entries = A_SIZE_8(temp)->num_entries;
+
+	/* Figure out what pg_start means in terms of our large GART pages */
+	start_pg 	= pg_start / I460_KPAGES_PER_CPAGE;
+	start_offset 	= pg_start % I460_KPAGES_PER_CPAGE;
+	end_pg 		= (pg_start + mem->page_count - 1) / 
+							I460_KPAGES_PER_CPAGE;
+	end_offset 	= (pg_start + mem->page_count - 1) % 
+							I460_KPAGES_PER_CPAGE;
+
+	if(end_pg > num_entries)
+	{
+		printk("[agpgart] Looks like we're out of AGP memory\n");
+		return -EINVAL;
+	}
+
+	/* Check if the requested region of the aperture is free */
+	for(pg = start_pg; pg <= end_pg; pg++)
+	{
+		/* Allocate new GART pages if necessary */
+		if(i460_pg_detail[pg] = NULL) {
+			temp = intel_i460_alloc_large_page(pg);
+			if(temp = NULL)
+				return -ENOMEM;
+			agp_bridge.gatt_table[pg] = agp_bridge.mask_memory(
+			    			       (unsigned long) temp, 0);
+			read_back = agp_bridge.gatt_table[pg];
+		}
+
+		for(idx = ((pg = start_pg) ? start_offset : 0);
+		    idx < ((pg = end_pg) ? (end_offset + 1) 
+				       : I460_KPAGES_PER_CPAGE);
+		    idx++) 
+		{
+			if(i460_pg_detail[pg][idx] != 0)
+				return -EBUSY;
+		}
+	}
+		
+	if (mem->is_flushed = FALSE) {
+		CACHE_FLUSH();
+		mem->is_flushed = TRUE;
+	}
+
+	for(pg = start_pg, i = 0; pg <= end_pg; pg++)
+	{
+		for(idx = ((pg = start_pg) ? start_offset : 0);
+		    idx < ((pg = end_pg) ? (end_offset + 1)
+				       : I460_KPAGES_PER_CPAGE);
+		    idx++, i++)
+		{
+			i460_pg_detail[pg][idx] = agp_bridge.gatt_table[pg] + 
+						      ((idx * PAGE_SIZE) >> 12);
+			i460_pg_count[pg]++;
+
+			/* Finally we fill in mem->memory... */
+			mem->memory[i] = ((unsigned long) (0xffffff & 
+						i460_pg_detail[pg][idx])) << 12;
+		}
+	}
+
+	return 0;
+}
+	
+static int intel_i460_remove_memory_kpc(agp_memory * mem,
+				     off_t pg_start, int type)
+{
+	int i, pg, start_pg, end_pg, start_offset, end_offset, idx;
+	int num_entries;
+	void *temp;
+	unsigned int read_back;
+	unsigned long addr;
+
+	temp = agp_bridge.current_size;
+	num_entries = A_SIZE_8(temp)->num_entries;
+
+	/* Figure out what pg_start means in terms of our large GART pages */
+	start_pg 	= pg_start / I460_KPAGES_PER_CPAGE;
+	start_offset 	= pg_start % I460_KPAGES_PER_CPAGE;
+	end_pg 		= (pg_start + mem->page_count - 1) / 
+						I460_KPAGES_PER_CPAGE;
+	end_offset 	= (pg_start + mem->page_count - 1) % 
+						I460_KPAGES_PER_CPAGE;
+
+	for(i = 0, pg = start_pg; pg <= end_pg; pg++)
+	{
+		for(idx = ((pg = start_pg) ? start_offset : 0);
+		    idx < ((pg = end_pg) ? (end_offset + 1)
+				       : I460_KPAGES_PER_CPAGE);
+		    idx++, i++) 
+		{
+			mem->memory[i] = 0;
+			i460_pg_detail[pg][idx] = 0;
+			i460_pg_count[pg]--;
+		}
+
+		/* Free GART pages if they are unused */
+		if(i460_pg_count[pg] = 0) {
+			addr = (0xffffffUL & (unsigned long) 
+					     (agp_bridge.gatt_table[pg])) << 12;
+
+			agp_bridge.gatt_table[pg] = 0;
+			read_back = agp_bridge.gatt_table[pg];
+
+			intel_i460_free_large_page(pg, addr);
+		}
+	}
+		
+	return 0;
+}
+
+/* Dummy routines to call the approriate {cpk,kpc} function */
+
+static int intel_i460_insert_memory(agp_memory * mem,
+				     off_t pg_start, int type)
+{
+	if(intel_i460_cpk)
+		return intel_i460_insert_memory_cpk(mem, pg_start, type);
+	else
+		return intel_i460_insert_memory_kpc(mem, pg_start, type);
+}
+
+static int intel_i460_remove_memory(agp_memory * mem,
+				     off_t pg_start, int type)
+{
+	if(intel_i460_cpk)
+		return intel_i460_remove_memory_cpk(mem, pg_start, type);
+	else
+		return intel_i460_remove_memory_kpc(mem, pg_start, type);
+}
+
+/*
+ * If the kernel page size is smaller that the chipset page size, we don't
+ * want to allocate memory until we know where it is to be bound in the
+ * aperture (a multi-kernel-page alloc might fit inside of an already
+ * allocated GART page).  Consequently, don't allocate or free anything
+ * if i460_cpk (meaning chipset pages per kernel page) isn't set.
+ *
+ * Let's just hope nobody counts on the allocated AGP memory being there
+ * before bind time (I don't think current drivers do)...
+ */ 
+static unsigned long intel_i460_alloc_page(void)
+{
+	if(intel_i460_cpk)
+		return agp_generic_alloc_page();
+
+	/* Returning NULL would cause problems */
+	return ((unsigned long) ~0UL);
+}
+
+static void intel_i460_destroy_page(unsigned long page)
+{
+	if(intel_i460_cpk)
+		agp_generic_destroy_page(page);
+}
+
+static gatt_mask intel_i460_masks[] +{
+	{ 
+	  INTEL_I460_GATT_VALID, 
+	  0
+	}
+};
+
+static unsigned long intel_i460_mask_memory(unsigned long addr, int type) 
+{
+	/* Make sure the returned address is a valid GATT entry */
+	return (agp_bridge.masks[0].mask | (((addr & 
+		     ~((1 << intel_i460_pageshift) - 1)) & 0xffffff000) >> 12));
+}
+
+static unsigned long intel_i460_unmask_memory(unsigned long addr)
+{
+	/* Turn a GATT entry into a physical address */
+	return ((addr & 0xffffff) << 12);
+}
+
+static aper_size_info_8 intel_i460_sizes[3] +{
+	/* 
+	 * The 32GB aperture is only available with a 4M GART page size.
+	 * Due to the dynamic GART page size, we can't figure out page_order
+	 * or num_entries until runtime.
+	 */
+	{32768, 0, 0, 4},
+	{1024, 0, 0, 2},
+	{256, 0, 0, 1}
+};
+
+static int __init intel_i460_setup (struct pci_dev *pdev)
+{
+
+        agp_bridge.masks = intel_i460_masks;
+        agp_bridge.num_of_masks = 1;
+        agp_bridge.aperture_sizes = (void *) intel_i460_sizes;
+        agp_bridge.size_type = U8_APER_SIZE;
+        agp_bridge.num_aperture_sizes = 3;
+        agp_bridge.dev_private_data = NULL;
+        agp_bridge.needs_scratch_page = FALSE;
+        agp_bridge.configure = intel_i460_configure;
+        agp_bridge.fetch_size = intel_i460_fetch_size;
+        agp_bridge.cleanup = intel_i460_cleanup;
+        agp_bridge.tlb_flush = intel_i460_tlb_flush;
+        agp_bridge.mask_memory = intel_i460_mask_memory;
+        agp_bridge.unmask_memory = intel_i460_unmask_memory;
+        agp_bridge.agp_enable = agp_generic_agp_enable;
+        agp_bridge.cache_flush = global_cache_flush;
+        agp_bridge.create_gatt_table = intel_i460_create_gatt_table;
+        agp_bridge.free_gatt_table = intel_i460_free_gatt_table;
+        agp_bridge.insert_memory = intel_i460_insert_memory;
+        agp_bridge.remove_memory = intel_i460_remove_memory;
+        agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+        agp_bridge.free_by_type = agp_generic_free_by_type;
+        agp_bridge.agp_alloc_page = intel_i460_alloc_page;
+        agp_bridge.agp_destroy_page = intel_i460_destroy_page;
+#if 0
+	agp_bridge.suspend = ??;
+	agp_bridge.resume = ??;
+#endif
+	agp_bridge.cant_use_aperture = 1;
+
+        return 0;
+
+        (void) pdev; /* unused */
+}
+
+#endif		/* CONFIG_AGP_I460 */
+
 #ifdef CONFIG_AGP_INTEL
 
 static int intel_fetch_size(void)
@@ -1579,6 +2291,7 @@
 	agp_bridge.cleanup = intel_cleanup;
 	agp_bridge.tlb_flush = intel_tlbflush;
 	agp_bridge.mask_memory = intel_mask_memory;
+	agp_bridge.unmask_memory = agp_generic_unmask_memory;
 	agp_bridge.agp_enable = agp_generic_agp_enable;
 	agp_bridge.cache_flush = global_cache_flush;
 	agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
@@ -1612,6 +2325,7 @@
 	agp_bridge.cleanup = intel_cleanup;
 	agp_bridge.tlb_flush = intel_tlbflush;
 	agp_bridge.mask_memory = intel_mask_memory;
+	agp_bridge.unmask_memory = agp_generic_unmask_memory;
 	agp_bridge.agp_enable = agp_generic_agp_enable;
 	agp_bridge.cache_flush = global_cache_flush;
 	agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
@@ -1645,6 +2359,7 @@
 	agp_bridge.cleanup = intel_cleanup;
 	agp_bridge.tlb_flush = intel_tlbflush;
 	agp_bridge.mask_memory = intel_mask_memory;
+	agp_bridge.unmask_memory = agp_generic_unmask_memory;
 	agp_bridge.agp_enable = agp_generic_agp_enable;
 	agp_bridge.cache_flush = global_cache_flush;
 	agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
@@ -1765,6 +2480,7 @@
 	agp_bridge.cleanup = via_cleanup;
 	agp_bridge.tlb_flush = via_tlbflush;
 	agp_bridge.mask_memory = via_mask_memory;
+	agp_bridge.unmask_memory = agp_generic_unmask_memory;
 	agp_bridge.agp_enable = agp_generic_agp_enable;
 	agp_bridge.cache_flush = global_cache_flush;
 	agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
@@ -1879,6 +2595,7 @@
 	agp_bridge.cleanup = sis_cleanup;
 	agp_bridge.tlb_flush = sis_tlbflush;
 	agp_bridge.mask_memory = sis_mask_memory;
+	agp_bridge.unmask_memory = agp_generic_unmask_memory;
 	agp_bridge.agp_enable = agp_generic_agp_enable;
 	agp_bridge.cache_flush = global_cache_flush;
 	agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
@@ -1901,8 +2618,8 @@
 #ifdef CONFIG_AGP_AMD
 
 typedef struct _amd_page_map {
-	unsigned long *real;
-	unsigned long *remapped;
+	u32 *real;
+	u32 *remapped;
 } amd_page_map;
 
 static struct _amd_irongate_private {
@@ -1915,7 +2632,7 @@
 {
 	int i;
 
-	page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
+	page_map->real = (u32 *) __get_free_page(GFP_KERNEL);
 	if (page_map->real = NULL) {
 		return -ENOMEM;
 	}
@@ -2170,7 +2887,7 @@
 			     off_t pg_start, int type)
 {
 	int i, j, num_entries;
-	unsigned long *cur_gatt;
+	u32 *cur_gatt;
 	unsigned long addr;
 
 	num_entries = A_SIZE_LVL2(agp_bridge.current_size)->num_entries;
@@ -2210,7 +2927,7 @@
 			     int type)
 {
 	int i;
-	unsigned long *cur_gatt;
+	u32 *cur_gatt;
 	unsigned long addr;
 
 	if (type != 0 || mem->type != 0) {
@@ -2257,6 +2974,7 @@
 	agp_bridge.cleanup = amd_irongate_cleanup;
 	agp_bridge.tlb_flush = amd_irongate_tlbflush;
 	agp_bridge.mask_memory = amd_irongate_mask_memory;
+	agp_bridge.unmask_memory = agp_generic_unmask_memory;
 	agp_bridge.agp_enable = agp_generic_agp_enable;
 	agp_bridge.cache_flush = global_cache_flush;
 	agp_bridge.create_gatt_table = amd_create_gatt_table;
@@ -2505,6 +3223,7 @@
 	agp_bridge.cleanup = ali_cleanup;
 	agp_bridge.tlb_flush = ali_tlbflush;
 	agp_bridge.mask_memory = ali_mask_memory;
+	agp_bridge.unmask_memory = agp_generic_unmask_memory;
 	agp_bridge.agp_enable = agp_generic_agp_enable;
 	agp_bridge.cache_flush = ali_cache_flush;
 	agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
@@ -3287,6 +4006,15 @@
 
 #endif /* CONFIG_AGP_INTEL */
 
+#ifdef CONFIG_AGP_I460
+	{ PCI_DEVICE_ID_INTEL_460GX,
+		PCI_VENDOR_ID_INTEL,
+		INTEL_460GX,
+		"Intel",
+		"460GX",
+		intel_i460_setup },
+#endif
+
 #ifdef CONFIG_AGP_SIS
 	{ PCI_DEVICE_ID_SI_630,
 		PCI_VENDOR_ID_SI,
@@ -3455,6 +4183,18 @@
 	return -ENODEV;
 }
 
+static int agp_check_supported_device(struct pci_dev *dev) {
+
+	int i;
+
+	for(i = 0; i < ARRAY_SIZE (agp_bridge_info); i++) {
+		if(dev->vendor = agp_bridge_info[i].vendor_id &&
+		   dev->device = agp_bridge_info[i].device_id)
+			return 1;
+	}
+
+	return 0;
+}
 
 /* Supported Device Scanning routine */
 
@@ -3464,8 +4204,14 @@
 	u8 cap_ptr = 0x00;
 	u32 cap_id, scratch;
 
-	if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) = NULL)
-		return -ENODEV;
+	/* 
+	 * Some systems have multiple host bridges (i.e. BigSur), so
+	 * we can't just use the first one we find.
+	 */
+	do {
+		if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, dev)) = NULL)
+			return -ENODEV;
+	} while(!agp_check_supported_device(dev));
 
 	agp_bridge.dev = dev;
 
diff -urN linux-2.4.13/drivers/char/drm/Config.in linux-2.4.13-lia/drivers/char/drm/Config.in
--- linux-2.4.13/drivers/char/drm/Config.in	Wed Aug  8 09:42:10 2001
+++ linux-2.4.13-lia/drivers/char/drm/Config.in	Thu Oct  4 00:21:40 2001
@@ -5,12 +5,9 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 #
 
-bool 'Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)' CONFIG_DRM
-if [ "$CONFIG_DRM" != "n" ]; then
-    tristate '  3dfx Banshee/Voodoo3+' CONFIG_DRM_TDFX
-    tristate '  3dlabs GMX 2000' CONFIG_DRM_GAMMA
-    tristate '  ATI Rage 128' CONFIG_DRM_R128
-    dep_tristate '  ATI Radeon' CONFIG_DRM_RADEON $CONFIG_AGP
-    dep_tristate '  Intel I810' CONFIG_DRM_I810 $CONFIG_AGP
-    dep_tristate '  Matrox g200/g400' CONFIG_DRM_MGA $CONFIG_AGP
-fi
+tristate '  3dfx Banshee/Voodoo3+' CONFIG_DRM_TDFX
+tristate '  3dlabs GMX 2000' CONFIG_DRM_GAMMA
+tristate '  ATI Rage 128' CONFIG_DRM_R128
+dep_tristate '  ATI Radeon' CONFIG_DRM_RADEON $CONFIG_AGP
+dep_tristate '  Intel I810' CONFIG_DRM_I810 $CONFIG_AGP
+dep_tristate '  Matrox g200/g400' CONFIG_DRM_MGA $CONFIG_AGP
diff -urN linux-2.4.13/drivers/char/drm/ati_pcigart.h linux-2.4.13-lia/drivers/char/drm/ati_pcigart.h
--- linux-2.4.13/drivers/char/drm/ati_pcigart.h	Mon Sep 24 15:06:57 2001
+++ linux-2.4.13-lia/drivers/char/drm/ati_pcigart.h	Thu Oct  4 00:21:40 2001
@@ -30,7 +30,10 @@
 #define __NO_VERSION__
 #include "drmP.h"
 
-#if PAGE_SIZE = 8192
+#if PAGE_SIZE = 16384
+# define ATI_PCIGART_TABLE_ORDER 	1
+# define ATI_PCIGART_TABLE_PAGES 	(1 << 1)
+#elif PAGE_SIZE = 8192
 # define ATI_PCIGART_TABLE_ORDER 	2
 # define ATI_PCIGART_TABLE_PAGES 	(1 << 2)
 #elif PAGE_SIZE = 4096
@@ -103,6 +106,7 @@
 		goto done;
 	}
 
+#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400)
 	if ( !dev->pdev ) {
 		DRM_ERROR( "PCI device unknown!\n" );
 		goto done;
@@ -117,6 +121,9 @@
 		address = 0;
 		goto done;
 	}
+#else
+	bus_address = virt_to_bus( (void *)address );
+#endif
 
 	pci_gart = (u32 *)address;
 
@@ -126,6 +133,7 @@
 	memset( pci_gart, 0, ATI_MAX_PCIGART_PAGES * sizeof(u32) );
 
 	for ( i = 0 ; i < pages ; i++ ) {
+#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400)
 		/* we need to support large memory configurations */
 		entry->busaddr[i] = pci_map_single(dev->pdev,
 					   page_address( entry->pagelist[i] ),
@@ -139,7 +147,9 @@
 			goto done;
 		}
 		page_base = (u32) entry->busaddr[i];
-
+#else
+		page_base = page_to_bus( entry->pagelist[i] );
+#endif
 		for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
 			*pci_gart++ = cpu_to_le32( page_base );
 			page_base += ATI_PCIGART_PAGE_SIZE;
@@ -164,6 +174,7 @@
 			      unsigned long addr,
 			      dma_addr_t bus_addr)
 {
+#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400)
 	drm_sg_mem_t *entry = dev->sg;
 	unsigned long pages;
 	int i;
@@ -188,6 +199,8 @@
 					 PAGE_SIZE, PCI_DMA_TODEVICE);
 		}
 	}
+
+#endif
 
 	if ( addr ) {
 		DRM(ati_free_pcigart_table)( addr );
diff -urN linux-2.4.13/drivers/char/drm/drmP.h linux-2.4.13-lia/drivers/char/drm/drmP.h
--- linux-2.4.13/drivers/char/drm/drmP.h	Mon Sep 24 15:06:58 2001
+++ linux-2.4.13-lia/drivers/char/drm/drmP.h	Thu Oct  4 00:21:52 2001
@@ -366,13 +366,13 @@
    if (len > DRM_PROC_LIMIT) { ret; *eof = 1; return len - offset; }
 
 				/* Mapping helper macros */
-#define DRM_IOREMAP(map)						\
-	(map)->handle = DRM(ioremap)( (map)->offset, (map)->size )
+#define DRM_IOREMAP(map, dev)						\
+	(map)->handle = DRM(ioremap)( (map)->offset, (map)->size, (dev) )
 
-#define DRM_IOREMAPFREE(map)						\
+#define DRM_IOREMAPFREE(map, dev)						\
 	do {								\
 		if ( (map)->handle && (map)->size )			\
-			DRM(ioremapfree)( (map)->handle, (map)->size );	\
+			DRM(ioremapfree)( (map)->handle, (map)->size, (dev) );	\
 	} while (0)
 
 #define DRM_FIND_MAP(_map, _o)						\
@@ -826,8 +826,8 @@
 extern unsigned long DRM(alloc_pages)(int order, int area);
 extern void	     DRM(free_pages)(unsigned long address, int order,
 				     int area);
-extern void	     *DRM(ioremap)(unsigned long offset, unsigned long size);
-extern void	     DRM(ioremapfree)(void *pt, unsigned long size);
+extern void	     *DRM(ioremap)(unsigned long offset, unsigned long size, drm_device_t *dev);
+extern void	     DRM(ioremapfree)(void *pt, unsigned long size, drm_device_t *dev);
 
 #if __REALLY_HAVE_AGP
 extern agp_memory    *DRM(alloc_agp)(int pages, u32 type);
diff -urN linux-2.4.13/drivers/char/drm/drm_agpsupport.h linux-2.4.13-lia/drivers/char/drm/drm_agpsupport.h
--- linux-2.4.13/drivers/char/drm/drm_agpsupport.h	Mon Sep 24 15:06:58 2001
+++ linux-2.4.13-lia/drivers/char/drm/drm_agpsupport.h	Thu Oct  4 00:21:40 2001
@@ -275,6 +275,7 @@
 		case INTEL_I815:	head->chipset = "Intel i815";	 break;
 		case INTEL_I840:	head->chipset = "Intel i840";    break;
 		case INTEL_I850:	head->chipset = "Intel i850";	 break;
+		case INTEL_460GX:	head->chipset = "Intel 460GX";	 break;
 #endif
 
 		case VIA_GENERIC:	head->chipset = "VIA";           break;
diff -urN linux-2.4.13/drivers/char/drm/drm_bufs.h linux-2.4.13-lia/drivers/char/drm/drm_bufs.h
--- linux-2.4.13/drivers/char/drm/drm_bufs.h	Fri Aug 10 18:14:41 2001
+++ linux-2.4.13-lia/drivers/char/drm/drm_bufs.h	Thu Oct  4 00:21:40 2001
@@ -107,7 +107,7 @@
 	switch ( map->type ) {
 	case _DRM_REGISTERS:
 	case _DRM_FRAME_BUFFER:
-#if !defined(__sparc__) && !defined(__alpha__)
+#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__)
 		if ( map->offset + map->size < map->offset ||
 		     map->offset < virt_to_phys(high_memory) ) {
 			DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
@@ -124,7 +124,7 @@
 					      MTRR_TYPE_WRCOMB, 1 );
 		}
 #endif
-		map->handle = DRM(ioremap)( map->offset, map->size );
+		map->handle = DRM(ioremap)( map->offset, map->size, dev );
 		break;
 
 	case _DRM_SHM:
@@ -249,7 +249,7 @@
 				DRM_DEBUG("mtrr_del = %d\n", retcode);
 			}
 #endif
-			DRM(ioremapfree)(map->handle, map->size);
+			DRM(ioremapfree)(map->handle, map->size, dev);
 			break;
 		case _DRM_SHM:
 			vfree(map->handle);
diff -urN linux-2.4.13/drivers/char/drm/drm_drv.h linux-2.4.13-lia/drivers/char/drm/drm_drv.h
--- linux-2.4.13/drivers/char/drm/drm_drv.h	Wed Oct 24 10:17:46 2001
+++ linux-2.4.13-lia/drivers/char/drm/drm_drv.h	Wed Oct 24 10:21:09 2001
@@ -439,7 +439,7 @@
 					DRM_DEBUG( "mtrr_del=%d\n", retcode );
 				}
 #endif
-				DRM(ioremapfree)( map->handle, map->size );
+				DRM(ioremapfree)( map->handle, map->size, dev );
 				break;
 			case _DRM_SHM:
 				vfree(map->handle);
diff -urN linux-2.4.13/drivers/char/drm/drm_memory.h linux-2.4.13-lia/drivers/char/drm/drm_memory.h
--- linux-2.4.13/drivers/char/drm/drm_memory.h	Fri Aug 10 18:14:41 2001
+++ linux-2.4.13-lia/drivers/char/drm/drm_memory.h	Thu Oct  4 00:21:40 2001
@@ -306,9 +306,14 @@
 	}
 }
 
-void *DRM(ioremap)(unsigned long offset, unsigned long size)
+void *DRM(ioremap)(unsigned long offset, unsigned long size, drm_device_t *dev)
 {
 	void *pt;
+#if __REALLY_HAVE_AGP
+	drm_map_t *map = NULL;
+	drm_map_list_t *r_list;
+	struct list_head *list;
+#endif
 
 	if (!size) {
 		DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
@@ -316,12 +321,51 @@
 		return NULL;
 	}
 
+#if __REALLY_HAVE_AGP
+	if(dev->agp->cant_use_aperture = 0)
+		goto standard_ioremap;
+
+	list_for_each(list, &dev->maplist->head) {
+		r_list = (drm_map_list_t *)list;
+		map = r_list->map;
+		if (!map) continue;
+		if (map->offset <= offset &&
+			(map->offset + map->size) >= (offset + size))
+			break;
+	}
+	
+	if(map && map->type = _DRM_AGP) {
+		struct drm_agp_mem *agpmem;
+
+		for(agpmem = dev->agp->memory; agpmem;
+					agpmem = agpmem->next) {
+			if(agpmem->bound <= offset &&
+			   (agpmem->bound + (agpmem->pages
+				<< PAGE_SHIFT)) >= (offset + size))
+				break;
+		}
+
+		if(agpmem = NULL)
+			goto ioremap_failure;
+
+		pt = agpmem->memory->vmptr + (offset - agpmem->bound);
+		goto ioremap_success;
+	}
+
+standard_ioremap:
+#endif
 	if (!(pt = ioremap(offset, size))) {
+#if __REALLY_HAVE_AGP
+ioremap_failure:
+#endif
 		spin_lock(&DRM(mem_lock));
 		++DRM(mem_stats)[DRM_MEM_MAPPINGS].fail_count;
 		spin_unlock(&DRM(mem_lock));
 		return NULL;
 	}
+#if __REALLY_HAVE_AGP
+ioremap_success:
+#endif
 	spin_lock(&DRM(mem_lock));
 	++DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count;
 	DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_allocated += size;
@@ -329,7 +373,7 @@
 	return pt;
 }
 
-void DRM(ioremapfree)(void *pt, unsigned long size)
+void DRM(ioremapfree)(void *pt, unsigned long size, drm_device_t *dev)
 {
 	int alloc_count;
 	int free_count;
@@ -337,7 +381,11 @@
 	if (!pt)
 		DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
 			      "Attempt to free NULL pointer\n");
+#if __REALLY_HAVE_AGP
+	else if(dev->agp->cant_use_aperture = 0)
+#else
 	else
+#endif
 		iounmap(pt);
 
 	spin_lock(&DRM(mem_lock));
diff -urN linux-2.4.13/drivers/char/drm/drm_scatter.h linux-2.4.13-lia/drivers/char/drm/drm_scatter.h
--- linux-2.4.13/drivers/char/drm/drm_scatter.h	Mon Sep 24 15:06:58 2001
+++ linux-2.4.13-lia/drivers/char/drm/drm_scatter.h	Thu Oct  4 00:21:40 2001
@@ -47,9 +47,11 @@
 
 	vfree( entry->virtual );
 
+#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400)
 	DRM(free)( entry->busaddr,
 		   entry->pages * sizeof(*entry->busaddr),
 		   DRM_MEM_PAGES );
+#endif
 	DRM(free)( entry->pagelist,
 		   entry->pages * sizeof(*entry->pagelist),
 		   DRM_MEM_PAGES );
@@ -97,6 +99,7 @@
 		return -ENOMEM;
 	}
 
+#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400)
 	entry->busaddr = DRM(alloc)( pages * sizeof(*entry->busaddr),
 				     DRM_MEM_PAGES );
 	if ( !entry->busaddr ) {
@@ -109,12 +112,15 @@
 		return -ENOMEM;
 	}
 	memset( (void *)entry->busaddr, 0, pages * sizeof(*entry->busaddr) );
+#endif
 
 	entry->virtual = vmalloc_32( pages << PAGE_SHIFT );
 	if ( !entry->virtual ) {
+#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400)
 		DRM(free)( entry->busaddr,
 			   entry->pages * sizeof(*entry->busaddr),
 			   DRM_MEM_PAGES );
+#endif
 		DRM(free)( entry->pagelist,
 			   entry->pages * sizeof(*entry->pagelist),
 			   DRM_MEM_PAGES );
diff -urN linux-2.4.13/drivers/char/drm/drm_vm.h linux-2.4.13-lia/drivers/char/drm/drm_vm.h
--- linux-2.4.13/drivers/char/drm/drm_vm.h	Wed Oct 24 10:17:48 2001
+++ linux-2.4.13-lia/drivers/char/drm/drm_vm.h	Wed Oct 24 10:21:09 2001
@@ -89,7 +89,7 @@
 
 	if (map && map->type = _DRM_AGP) {
 		unsigned long offset = address - vma->vm_start;
-		unsigned long baddr = VM_OFFSET(vma) + offset;
+		unsigned long baddr = VM_OFFSET(vma) + offset, paddr;
 		struct drm_agp_mem *agpmem;
 		struct page *page;
 
@@ -115,8 +115,19 @@
                  * Get the page, inc the use count, and return it
                  */
 		offset = (baddr - agpmem->bound) >> PAGE_SHIFT;
-		agpmem->memory->memory[offset] &= dev->agp->page_mask;
-		page = virt_to_page(__va(agpmem->memory->memory[offset]));
+
+		/*
+		 * This is bad.  What we really want to do here is unmask
+		 * the GART table entry held in the agp_memory structure.
+		 * There isn't a convenient way to call agp_bridge.unmask_
+		 * memory from here, so hard code it for now.
+		 */
+#if defined(__ia64__)
+		paddr = (agpmem->memory->memory[offset] & 0xffffff) << 12;
+#else
+		paddr = agpmem->memory->memory[offset] & dev->agp->page_mask;
+#endif
+		page = virt_to_page(__va(paddr));
 		get_page(page);
 
 		DRM_DEBUG("baddr = 0x%lx page = 0x%p, offset = 0x%lx\n",
@@ -255,7 +266,7 @@
 					DRM_DEBUG("mtrr_del = %d\n", retcode);
 				}
 #endif
-				DRM(ioremapfree)(map->handle, map->size);
+				DRM(ioremapfree)(map->handle, map->size, dev);
 				break;
 			case _DRM_SHM:
 				vfree(map->handle);
@@ -502,15 +513,21 @@
 
 	switch (map->type) {
         case _DRM_AGP:
-#if defined(__alpha__)
-                /*
-                 * On Alpha we can't talk to bus dma address from the
-                 * CPU, so for memory of type DRM_AGP, we'll deal with
-                 * sorting out the real physical pages and mappings
-                 * in nopage()
-                 */
-                vma->vm_ops = &DRM(vm_ops);
-                break;
+#if __REALLY_HAVE_AGP
+		if(dev->agp->cant_use_aperture = 1) {
+                	/*
+                	 * On some systems we can't talk to bus dma address from
+                	 * the CPU, so for memory of type DRM_AGP, we'll deal
+                	 * with sorting out the real physical pages and mappings
+                	 * in nopage()
+                	 */
+                	vma->vm_ops = &DRM(vm_ops);
+#if defined(__ia64__)
+			vma->vm_page_prot +			                pgprot_writecombine(vma->vm_page_prot);
+#endif
+			goto mapswitch_out;
+		}
 #endif
                 /* fall through to _DRM_FRAME_BUFFER... */        
 	case _DRM_FRAME_BUFFER:
@@ -522,8 +539,7 @@
 				pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT;
 			}
 #elif defined(__ia64__)
-			if (map->type != _DRM_AGP)
-				vma->vm_page_prot +			vma->vm_page_prot  					pgprot_writecombine(vma->vm_page_prot);
 #elif defined(__powerpc__)
 			pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE | _PAGE_GUARDED;
@@ -572,6 +588,9 @@
 	default:
 		return -EINVAL;	/* This should never happen. */
 	}
+#if __REALLY_HAVE_AGP
+mapswitch_out:
+#endif
 	vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
 
 #if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */
diff -urN linux-2.4.13/drivers/char/drm/i810_dma.c linux-2.4.13-lia/drivers/char/drm/i810_dma.c
--- linux-2.4.13/drivers/char/drm/i810_dma.c	Wed Aug  8 09:42:15 2001
+++ linux-2.4.13-lia/drivers/char/drm/i810_dma.c	Thu Oct  4 00:21:40 2001
@@ -315,7 +315,7 @@
 
 	   	if(dev_priv->ring.virtual_start) {
 		   	DRM(ioremapfree)((void *) dev_priv->ring.virtual_start,
-					 dev_priv->ring.Size);
+					 dev_priv->ring.Size, dev);
 		}
 	   	if(dev_priv->hw_status_page != 0UL) {
 		   	i810_free_page(dev, dev_priv->hw_status_page);
@@ -329,7 +329,8 @@
 		for (i = 0; i < dma->buf_count; i++) {
 			drm_buf_t *buf = dma->buflist[ i ];
 			drm_i810_buf_priv_t *buf_priv = buf->dev_private;
-			DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total);
+			DRM(ioremapfree)(buf_priv->kernel_virtual,
+							buf->total, dev);
 		}
 	}
    	return 0;
@@ -402,7 +403,7 @@
 	   	*buf_priv->in_use = I810_BUF_FREE;
 
 		buf_priv->kernel_virtual = DRM(ioremap)(buf->bus_address,
-							buf->total);
+							buf->total, dev);
 	}
 	return 0;
 }
@@ -458,7 +459,7 @@
 
    	dev_priv->ring.virtual_start = DRM(ioremap)(dev->agp->base +
 						    init->ring_start,
-						    init->ring_size);
+						    init->ring_size, dev);
 
    	if (dev_priv->ring.virtual_start = NULL) {
 		dev->dev_private = (void *) dev_priv;
diff -urN linux-2.4.13/drivers/char/drm/mga_dma.c linux-2.4.13-lia/drivers/char/drm/mga_dma.c
--- linux-2.4.13/drivers/char/drm/mga_dma.c	Wed Aug  8 09:42:15 2001
+++ linux-2.4.13-lia/drivers/char/drm/mga_dma.c	Thu Oct  4 00:21:40 2001
@@ -557,9 +557,9 @@
 		(drm_mga_sarea_t *)((u8 *)dev_priv->sarea->handle +
 				    init->sarea_priv_offset);
 
-	DRM_IOREMAP( dev_priv->warp );
-	DRM_IOREMAP( dev_priv->primary );
-	DRM_IOREMAP( dev_priv->buffers );
+	DRM_IOREMAP( dev_priv->warp, dev );
+	DRM_IOREMAP( dev_priv->primary, dev );
+	DRM_IOREMAP( dev_priv->buffers, dev );
 
 	if(!dev_priv->warp->handle ||
 	   !dev_priv->primary->handle ||
@@ -647,9 +647,9 @@
 	if ( dev->dev_private ) {
 		drm_mga_private_t *dev_priv = dev->dev_private;
 
-		DRM_IOREMAPFREE( dev_priv->warp );
-		DRM_IOREMAPFREE( dev_priv->primary );
-		DRM_IOREMAPFREE( dev_priv->buffers );
+		DRM_IOREMAPFREE( dev_priv->warp, dev );
+		DRM_IOREMAPFREE( dev_priv->primary, dev );
+		DRM_IOREMAPFREE( dev_priv->buffers, dev );
 
 		if ( dev_priv->head != NULL ) {
 			mga_freelist_cleanup( dev );
diff -urN linux-2.4.13/drivers/char/drm/r128_cce.c linux-2.4.13-lia/drivers/char/drm/r128_cce.c
--- linux-2.4.13/drivers/char/drm/r128_cce.c	Mon Sep 24 15:06:58 2001
+++ linux-2.4.13-lia/drivers/char/drm/r128_cce.c	Thu Oct  4 00:21:52 2001
@@ -216,7 +216,22 @@
 	int i;
 
 	for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
+#ifndef CONFIG_AGP_I460
 		if ( GET_RING_HEAD( &dev_priv->ring ) = dev_priv->ring.tail ) {
+#else
+		/*
+		 * XXX - this is (I think) a 460GX specific hack
+		 *
+		 * When doing texturing, ring.tail sometimes gets ahead of
+		 * PM4_BUFFER_DL_WPTR by 2; consequently, the card processes
+		 * its whole quota of instructions and *ring.head is still 2
+		 * short of ring.tail.  Work around this for now in lieu of
+		 * a better solution.
+		 */
+ 		if ( GET_RING_HEAD( &dev_priv->ring ) = dev_priv->ring.tail ||
+			( dev_priv->ring.tail -
+				GET_RING_HEAD( &dev_priv->ring ) ) = 2 ) {
+#endif
 			int pm4stat = R128_READ( R128_PM4_STAT );
 			if ( ( (pm4stat & R128_PM4_FIFOCNT_MASK) > 			       dev_priv->cce_fifo_size ) &&
@@ -341,8 +356,27 @@
 	SET_RING_HEAD( &dev_priv->ring, 0 );
 
 	if ( !dev_priv->is_pci ) {
+#if defined(CONFIG_AGP_I460) && defined(__ia64__)
+		/*
+		 * XXX - This is a 460GX specific hack
+		 *
+		 * We have to hack this right now.  460GX isn't claiming PCI
+		 * writes from the card into the AGP aperture.  Because of this,
+		 * we have to get space outside of the aperture for RPTR_ADDR.
+		 */
+		if( dev->agp->agp_info.chipset = INTEL_460GX ) {
+			unsigned long alt_rh_off;
+
+			alt_rh_off = __get_free_page(GFP_KERNEL | GFP_DMA);
+			atomic_inc(&virt_to_page(alt_rh_off)->count);
+			set_bit(PG_locked, &virt_to_page(alt_rh_off)->flags);
+
+			dev_priv->ring.head = (__volatile__ u32 *) alt_rh_off;
+			SET_RING_HEAD( &dev_priv->ring, 0 );
+		}
+#endif
 		R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR,
-			    dev_priv->ring_rptr->offset );
+				    	__pa( dev_priv->ring.head ) );
 	} else {
 		drm_sg_mem_t *entry = dev->sg;
 		unsigned long tmp_ofs, page_ofs;
@@ -350,11 +384,20 @@
 		tmp_ofs = dev_priv->ring_rptr->offset - dev->sg->handle;
 		page_ofs = tmp_ofs >> PAGE_SHIFT;
 
+#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400)
 		R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR,
      			    entry->busaddr[page_ofs]);
 		DRM_DEBUG( "ring rptr: offset=0x%08x handle=0x%08lx\n",
 			   entry->busaddr[page_ofs],
      			   entry->handle + tmp_ofs );
+#else
+		R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR,
+			    page_to_bus(entry->pagelist[page_ofs]));
+
+		DRM_DEBUG( "ring rptr: offset=0x%08lx handle=0x%08lx\n",
+			   page_to_bus(entry->pagelist[page_ofs]),
+			   entry->handle + tmp_ofs );
+#endif
 	}
 
 	/* Set watermark control */
@@ -550,9 +593,9 @@
 				     init->sarea_priv_offset);
 
 	if ( !dev_priv->is_pci ) {
-		DRM_IOREMAP( dev_priv->cce_ring );
-		DRM_IOREMAP( dev_priv->ring_rptr );
-		DRM_IOREMAP( dev_priv->buffers );
+		DRM_IOREMAP( dev_priv->cce_ring, dev );
+		DRM_IOREMAP( dev_priv->ring_rptr, dev );
+		DRM_IOREMAP( dev_priv->buffers, dev );
 		if(!dev_priv->cce_ring->handle ||
 		   !dev_priv->ring_rptr->handle ||
 		   !dev_priv->buffers->handle) {
@@ -624,9 +667,9 @@
 		drm_r128_private_t *dev_priv = dev->dev_private;
 
 		if ( !dev_priv->is_pci ) {
-			DRM_IOREMAPFREE( dev_priv->cce_ring );
-			DRM_IOREMAPFREE( dev_priv->ring_rptr );
-			DRM_IOREMAPFREE( dev_priv->buffers );
+			DRM_IOREMAPFREE( dev_priv->cce_ring, dev );
+			DRM_IOREMAPFREE( dev_priv->ring_rptr, dev );
+			DRM_IOREMAPFREE( dev_priv->buffers, dev );
 		} else {
 			if (!DRM(ati_pcigart_cleanup)( dev,
 						dev_priv->phys_pci_gart,
@@ -634,6 +677,21 @@
 				DRM_ERROR( "failed to cleanup PCI GART!\n" );
 		}
 
+#if defined(CONFIG_AGP_I460) && defined(__ia64__)
+		/*
+		 * Free the page we grabbed for RPTR_ADDR
+		 */
+		if( !dev_priv->is_pci && dev->agp->agp_info.chipset = INTEL_460GX ) {
+			unsigned long alt_rh_off +				(unsigned long) dev_priv->ring.head;
+
+			atomic_dec(&virt_to_page(alt_rh_off)->count);
+			clear_bit(PG_locked, &virt_to_page(alt_rh_off)->flags);
+			wake_up(&virt_to_page(alt_rh_off)->wait);
+			free_page(alt_rh_off);
+		}
+#endif
+	
 		DRM(free)( dev->dev_private, sizeof(drm_r128_private_t),
 			   DRM_MEM_DRIVER );
 		dev->dev_private = NULL;
diff -urN linux-2.4.13/drivers/char/drm/radeon_cp.c linux-2.4.13-lia/drivers/char/drm/radeon_cp.c
--- linux-2.4.13/drivers/char/drm/radeon_cp.c	Mon Sep 24 15:06:58 2001
+++ linux-2.4.13-lia/drivers/char/drm/radeon_cp.c	Thu Oct  4 00:21:52 2001
@@ -612,8 +612,27 @@
 	dev_priv->ring.tail = cur_read_ptr;
 
 	if ( !dev_priv->is_pci ) {
+#if defined(CONFIG_AGP_I460) && defined(__ia64__)
+		/*
+		 * XXX - This is a 460GX specific hack
+		 *
+		 * We have to hack this right now.  460GX isn't claiming PCI
+		 * writes from the card into the AGP aperture.  Because of this,
+		 * we have to get space outside of the aperture for RPTR_ADDR.
+		 */
+		if( dev->agp->agp_info.chipset = INTEL_460GX ) {
+			unsigned long alt_rh_off;
+
+			alt_rh_off = __get_free_page(GFP_KERNEL | GFP_DMA);
+			atomic_inc(&virt_to_page(alt_rh_off)->count);
+			set_bit(PG_locked, &virt_to_page(alt_rh_off)->flags);
+
+			dev_priv->ring.head = (__volatile__ u32 *) alt_rh_off;
+			*dev_priv->ring.head = cur_read_ptr;
+		}
+#endif
 		RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR,
-			      dev_priv->ring_rptr->offset );
+			      		__pa( dev_priv->ring.head ) );
 	} else {
 		drm_sg_mem_t *entry = dev->sg;
 		unsigned long tmp_ofs, page_ofs;
@@ -621,11 +640,19 @@
 		tmp_ofs = dev_priv->ring_rptr->offset - dev->sg->handle;
 		page_ofs = tmp_ofs >> PAGE_SHIFT;
 
+#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400)
+		RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR,
+			     entry->busaddr[page_ofs]);
+		DRM_DEBUG( "ring rptr: offset=0x%08x handle=0x%08lx\n",
+			   entry->busaddr[page_ofs],
+			   entry->handle + tmp_ofs );
+#else
 		RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR,
 			     entry->busaddr[page_ofs]);
 		DRM_DEBUG( "ring rptr: offset=0x%08x handle=0x%08lx\n",
 			   entry->busaddr[page_ofs],
 			   entry->handle + tmp_ofs );
+#endif
 	}
 
 	/* Set ring buffer size */
@@ -836,9 +863,9 @@
 				       init->sarea_priv_offset);
 
 	if ( !dev_priv->is_pci ) {
-		DRM_IOREMAP( dev_priv->cp_ring );
-		DRM_IOREMAP( dev_priv->ring_rptr );
-		DRM_IOREMAP( dev_priv->buffers );
+		DRM_IOREMAP( dev_priv->cp_ring, dev );
+		DRM_IOREMAP( dev_priv->ring_rptr, dev );
+		DRM_IOREMAP( dev_priv->buffers, dev );
 		if(!dev_priv->cp_ring->handle ||
 		   !dev_priv->ring_rptr->handle ||
 		   !dev_priv->buffers->handle) {
@@ -983,9 +1010,9 @@
 		drm_radeon_private_t *dev_priv = dev->dev_private;
 
 		if ( !dev_priv->is_pci ) {
-			DRM_IOREMAPFREE( dev_priv->cp_ring );
-			DRM_IOREMAPFREE( dev_priv->ring_rptr );
-			DRM_IOREMAPFREE( dev_priv->buffers );
+			DRM_IOREMAPFREE( dev_priv->cp_ring, dev );
+			DRM_IOREMAPFREE( dev_priv->ring_rptr, dev );
+			DRM_IOREMAPFREE( dev_priv->buffers, dev );
 		} else {
 			if (!DRM(ati_pcigart_cleanup)( dev,
 						dev_priv->phys_pci_gart,
@@ -993,6 +1020,21 @@
 				DRM_ERROR( "failed to cleanup PCI GART!\n" );
 		}
 
+#if defined(CONFIG_AGP_I460) && defined(__ia64__)
+		/*
+		 * Free the page we grabbed for RPTR_ADDR
+		 */
+		if( !dev_priv->is_pci && dev->agp->agp_info.chipset = INTEL_460GX ) {
+			unsigned long alt_rh_off +				(unsigned long) dev_priv->ring.head;
+
+			atomic_dec(&virt_to_page(alt_rh_off)->count);
+			clear_bit(PG_locked, &virt_to_page(alt_rh_off)->flags);
+			wake_up(&virt_to_page(alt_rh_off)->wait);
+			free_page(alt_rh_off);
+		}
+#endif
+	
 		DRM(free)( dev->dev_private, sizeof(drm_radeon_private_t),
 			   DRM_MEM_DRIVER );
 		dev->dev_private = NULL;
diff -urN linux-2.4.13/drivers/char/drm-4.0/Config.in linux-2.4.13-lia/drivers/char/drm-4.0/Config.in
--- linux-2.4.13/drivers/char/drm-4.0/Config.in	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/Config.in	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,13 @@
+#
+# drm device configuration
+#
+# This driver provides support for the
+# Direct Rendering Infrastructure (DRI) in XFree86 4.x.
+#
+
+tristate '  3dfx Banshee/Voodoo3+' CONFIG_DRM40_TDFX
+tristate '  3dlabs GMX 2000' CONFIG_DRM40_GAMMA
+dep_tristate '  ATI Rage 128' CONFIG_DRM40_R128 $CONFIG_AGP
+dep_tristate '  ATI Radeon' CONFIG_DRM40_RADEON $CONFIG_AGP
+dep_tristate '  Intel I810' CONFIG_DRM40_I810 $CONFIG_AGP
+dep_tristate '  Matrox g200/g400' CONFIG_DRM40_MGA $CONFIG_AGP
diff -urN linux-2.4.13/drivers/char/drm-4.0/Makefile linux-2.4.13-lia/drivers/char/drm-4.0/Makefile
--- linux-2.4.13/drivers/char/drm-4.0/Makefile	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/Makefile	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,104 @@
+#
+# Makefile for the drm device driver.  This driver provides support for
+# the Direct Rendering Infrastructure (DRI) in XFree86 4.x.
+#
+
+O_TARGET	:= drm.o
+
+export-objs     := gamma_drv.o tdfx_drv.o r128_drv.o ffb_drv.o mga_drv.o \
+		   i810_drv.o
+
+# lib-objs are included in every module so that radical changes to the
+# architecture of the DRM support library can be made at a later time.
+#
+# The downside is that each module is larger, and a system that uses
+# more than one module (i.e., a dual-head system) will use more memory
+# (but a system that uses exactly one module will use the same amount of
+# memory).
+#
+# The upside is that if the DRM support library ever becomes insufficient
+# for new families of cards, a new library can be implemented for those new
+# cards without impacting the drivers for the old cards.  This is significant,
+# because testing architectural changes to old cards may be impossible, and
+# may delay the implementation of a better architecture.  We've traded slight
+# memory waste (in the dual-head case) for greatly improved long-term
+# maintainability.
+#
+# NOTE: lib-objs will be eliminated in future versions, thereby
+# eliminating the need to compile the .o files into every module, but
+# for now we still need them.
+#
+
+lib-objs   := init.o memory.o proc.o auth.o context.o drawable.o bufs.o
+lib-objs   += lists.o lock.o ioctl.o fops.o vm.o dma.o ctxbitmap.o
+
+ifeq ($(CONFIG_AGP),y)
+ lib-objs  += agpsupport.o
+else
+ ifeq ($(CONFIG_AGP),m)
+  lib-objs  += agpsupport.o
+ endif
+endif
+
+list-multi  := gamma.o tdfx.o r128.o ffb.o mga.o i810.o
+gamma-objs  := gamma_drv.o  gamma_dma.o
+tdfx-objs   := tdfx_drv.o                 tdfx_context.o
+r128-objs   := r128_drv.o   r128_cce.o    r128_context.o r128_bufs.o r128_state.o
+ffb-objs    := ffb_drv.o                  ffb_context.o
+mga-objs    := mga_drv.o    mga_dma.o     mga_context.o  mga_bufs.o  mga_state.o
+i810-objs   := i810_drv.o   i810_dma.o    i810_context.o i810_bufs.o
+radeon-objs := radeon_drv.o radeon_cp.o   radeon_context.o radeon_bufs.o radeon_state.o
+
+obj-$(CONFIG_DRM40_GAMMA) += gamma.o
+obj-$(CONFIG_DRM40_TDFX)  += tdfx.o
+obj-$(CONFIG_DRM40_R128)  += r128.o
+obj-$(CONFIG_DRM40_RADEON)+= radeon.o
+obj-$(CONFIG_DRM40_FFB)   += ffb.o
+obj-$(CONFIG_DRM40_MGA)   += mga.o
+obj-$(CONFIG_DRM40_I810)  += i810.o
+
+
+# When linking into the kernel, link the library just once. 
+# If making modules, we include the library into each module
+
+lib-objs-mod := $(patsubst %.o,%-mod.o,$(lib-objs))
+
+ifdef MAKING_MODULES
+  lib = drmlib-mod.a
+else
+  obj-y += drmlib.a
+endif
+
+include $(TOPDIR)/Rules.make
+
+$(patsubst %.o,%.c,$(lib-objs-mod)): 
+	@ln -sf $(subst -mod,,$@) $@
+
+drmlib-mod.a: $(lib-objs-mod)
+	rm -f $@
+	$(AR) $(EXTRA_ARFLAGS) rcs $@ $(lib-objs-mod)
+
+drmlib.a: $(lib-objs)
+	rm -f $@
+	$(AR) $(EXTRA_ARFLAGS) rcs $@ $(lib-objs)
+
+gamma.o: $(gamma-objs) $(lib)
+	$(LD) -r -o $@ $(gamma-objs) $(lib)
+
+tdfx.o: $(tdfx-objs) $(lib)
+	$(LD) -r -o $@ $(tdfx-objs) $(lib)
+
+mga.o: $(mga-objs) $(lib)
+	$(LD) -r -o $@ $(mga-objs) $(lib)
+
+i810.o: $(i810-objs) $(lib)
+	$(LD) -r -o $@ $(i810-objs) $(lib)
+
+r128.o: $(r128-objs) $(lib)
+	$(LD) -r -o $@ $(r128-objs) $(lib)
+
+radeon.o: $(radeon-objs) $(lib)
+	$(LD) -r -o $@ $(radeon-objs) $(lib)
+
+ffb.o: $(ffb-objs) $(lib)
+	$(LD) -r -o $@ $(ffb-objs) $(lib)
diff -urN linux-2.4.13/drivers/char/drm-4.0/README.drm linux-2.4.13-lia/drivers/char/drm-4.0/README.drm
--- linux-2.4.13/drivers/char/drm-4.0/README.drm	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/README.drm	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,46 @@
+************************************************************
+* For the very latest on DRI development, please see:      *
+*     http://dri.sourceforge.net/                          *
+************************************************************
+
+The Direct Rendering Manager (drm) is a device-independent kernel-level
+device driver that provides support for the XFree86 Direct Rendering
+Infrastructure (DRI).
+
+The DRM supports the Direct Rendering Infrastructure (DRI) in four major
+ways:
+
+    1. The DRM provides synchronized access to the graphics hardware via
+       the use of an optimized two-tiered lock.
+
+    2. The DRM enforces the DRI security policy for access to the graphics
+       hardware by only allowing authenticated X11 clients access to
+       restricted regions of memory.
+
+    3. The DRM provides a generic DMA engine, complete with multiple
+       queues and the ability to detect the need for an OpenGL context
+       switch.
+
+    4. The DRM is extensible via the use of small device-specific modules
+       that rely extensively on the API exported by the DRM module.
+
+
+Documentation on the DRI is available from:
+    http://precisioninsight.com/piinsights.html
+
+For specific information about kernel-level support, see:
+
+    The Direct Rendering Manager, Kernel Support for the Direct Rendering
+    Infrastructure
+    http://precisioninsight.com/dr/drm.html
+
+    Hardware Locking for the Direct Rendering Infrastructure
+    http://precisioninsight.com/dr/locking.html
+
+    A Security Analysis of the Direct Rendering Infrastructure
+    http://precisioninsight.com/dr/security.html
+
+************************************************************
+* For the very latest on DRI development, please see:      *
+*     http://dri.sourceforge.net/                          *
+************************************************************
diff -urN linux-2.4.13/drivers/char/drm-4.0/agpsupport.c linux-2.4.13-lia/drivers/char/drm-4.0/agpsupport.c
--- linux-2.4.13/drivers/char/drm-4.0/agpsupport.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/agpsupport.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,349 @@
+/* agpsupport.c -- DRM support for AGP/GART backend -*- linux-c -*-
+ * Created: Mon Dec 13 09:56:45 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Author: Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include <linux/config.h>
+#include <linux/module.h>
+#if LINUX_VERSION_CODE < 0x020400
+#include "agpsupport-pre24.h"
+#else
+#define DRM_AGP_GET (drm_agp_t *)inter_module_get("drm_agp")
+#define DRM_AGP_PUT inter_module_put("drm_agp")
+#endif
+
+static const drm_agp_t *drm_agp = NULL;
+
+int drm_agp_info(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	agp_kern_info    *kern;
+	drm_agp_info_t   info;
+
+	if (!dev->agp->acquired || !drm_agp->copy_info) return -EINVAL;
+
+	kern                   = &dev->agp->agp_info;
+	info.agp_version_major = kern->version.major;
+	info.agp_version_minor = kern->version.minor;
+	info.mode              = kern->mode;
+	info.aperture_base     = kern->aper_base;
+	info.aperture_size     = kern->aper_size * 1024 * 1024;
+	info.memory_allowed    = kern->max_memory << PAGE_SHIFT;
+	info.memory_used       = kern->current_memory << PAGE_SHIFT;
+	info.id_vendor         = kern->device->vendor;
+	info.id_device         = kern->device->device;
+
+	if (copy_to_user((drm_agp_info_t *)arg, &info, sizeof(info)))
+		return -EFAULT;
+	return 0;
+}
+
+int drm_agp_acquire(struct inode *inode, struct file *filp, unsigned int cmd,
+		    unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	int              retcode;
+
+	if (dev->agp->acquired || !drm_agp->acquire) return -EINVAL;
+	if ((retcode = drm_agp->acquire())) return retcode;
+	dev->agp->acquired = 1;
+	return 0;
+}
+
+int drm_agp_release(struct inode *inode, struct file *filp, unsigned int cmd,
+		    unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+
+	if (!dev->agp->acquired || !drm_agp->release) return -EINVAL;
+	drm_agp->release();
+	dev->agp->acquired = 0;
+	return 0;
+	
+}
+
+void _drm_agp_release(void)
+{
+	if (drm_agp->release) drm_agp->release();
+}
+
+int drm_agp_enable(struct inode *inode, struct file *filp, unsigned int cmd,
+		   unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_agp_mode_t   mode;
+
+	if (!dev->agp->acquired || !drm_agp->enable) return -EINVAL;
+
+	if (copy_from_user(&mode, (drm_agp_mode_t *)arg, sizeof(mode)))
+		return -EFAULT;
+	
+	dev->agp->mode    = mode.mode;
+	drm_agp->enable(mode.mode);
+	dev->agp->base    = dev->agp->agp_info.aper_base;
+	dev->agp->enabled = 1;
+	return 0;
+}
+
+int drm_agp_alloc(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_agp_buffer_t request;
+	drm_agp_mem_t    *entry;
+	agp_memory       *memory;
+	unsigned long    pages;
+	u32 		 type;
+	if (!dev->agp->acquired) return -EINVAL;
+	if (copy_from_user(&request, (drm_agp_buffer_t *)arg, sizeof(request)))
+		return -EFAULT;
+	if (!(entry = drm_alloc(sizeof(*entry), DRM_MEM_AGPLISTS)))
+		return -ENOMEM;
+   
+   	memset(entry, 0, sizeof(*entry));
+
+	pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE;
+	type = (u32) request.type;
+
+	if (!(memory = drm_alloc_agp(pages, type))) {
+		drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+		return -ENOMEM;
+	}
+	
+	entry->handle    = (unsigned long)memory->memory;
+	entry->memory    = memory;
+	entry->bound     = 0;
+	entry->pages     = pages;
+	entry->prev      = NULL;
+	entry->next      = dev->agp->memory;
+	if (dev->agp->memory) dev->agp->memory->prev = entry;
+	dev->agp->memory = entry;
+
+	request.handle   = entry->handle;
+        request.physical = memory->physical;
+
+	if (copy_to_user((drm_agp_buffer_t *)arg, &request, sizeof(request))) {
+		dev->agp->memory       = entry->next;
+		dev->agp->memory->prev = NULL;
+		drm_free_agp(memory, pages);
+		drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+		return -EFAULT;
+	}
+	return 0;
+}
+
+static drm_agp_mem_t *drm_agp_lookup_entry(drm_device_t *dev,
+					   unsigned long handle)
+{
+	drm_agp_mem_t *entry;
+
+	for (entry = dev->agp->memory; entry; entry = entry->next) {
+		if (entry->handle = handle) return entry;
+	}
+	return NULL;
+}
+
+int drm_agp_unbind(struct inode *inode, struct file *filp, unsigned int cmd,
+		   unsigned long arg)
+{
+	drm_file_t	  *priv	 = filp->private_data;
+	drm_device_t	  *dev	 = priv->dev;
+	drm_agp_binding_t request;
+	drm_agp_mem_t     *entry;
+
+	if (!dev->agp->acquired) return -EINVAL;
+	if (copy_from_user(&request, (drm_agp_binding_t *)arg, sizeof(request)))
+		return -EFAULT;
+	if (!(entry = drm_agp_lookup_entry(dev, request.handle)))
+		return -EINVAL;
+	if (!entry->bound) return -EINVAL;
+	return drm_unbind_agp(entry->memory);
+}
+
+int drm_agp_bind(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	  *priv	 = filp->private_data;
+	drm_device_t	  *dev	 = priv->dev;
+	drm_agp_binding_t request;
+	drm_agp_mem_t     *entry;
+	int               retcode;
+	int               page;
+	
+	if (!dev->agp->acquired || !drm_agp->bind_memory) return -EINVAL;
+	if (copy_from_user(&request, (drm_agp_binding_t *)arg, sizeof(request)))
+		return -EFAULT;
+	if (!(entry = drm_agp_lookup_entry(dev, request.handle)))
+		return -EINVAL;
+	if (entry->bound) return -EINVAL;
+	page = (request.offset + PAGE_SIZE - 1) / PAGE_SIZE;
+	if ((retcode = drm_bind_agp(entry->memory, page))) return retcode;
+	entry->bound = dev->agp->base + (page << PAGE_SHIFT);
+	DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n", 
+		  dev->agp->base, entry->bound);
+	return 0;
+}
+
+int drm_agp_free(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_agp_buffer_t request;
+	drm_agp_mem_t    *entry;
+	
+	if (!dev->agp->acquired) return -EINVAL;
+	if (copy_from_user(&request, (drm_agp_buffer_t *)arg, sizeof(request)))
+		return -EFAULT;
+	if (!(entry = drm_agp_lookup_entry(dev, request.handle)))
+		return -EINVAL;
+	if (entry->bound) drm_unbind_agp(entry->memory);
+   
+	if (entry->prev) entry->prev->next = entry->next;
+	else             dev->agp->memory  = entry->next;
+	if (entry->next) entry->next->prev = entry->prev;
+	drm_free_agp(entry->memory, entry->pages);
+	drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+	return 0;
+}
+
+drm_agp_head_t *drm_agp_init(void)
+{
+	drm_agp_head_t *head         = NULL;
+
+	drm_agp = DRM_AGP_GET;
+	if (drm_agp) {
+		if (!(head = drm_alloc(sizeof(*head), DRM_MEM_AGPLISTS)))
+			return NULL;
+		memset((void *)head, 0, sizeof(*head));
+		drm_agp->copy_info(&head->agp_info);
+		if (head->agp_info.chipset = NOT_SUPPORTED) {
+			drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS);
+			return NULL;
+		}
+		head->memory = NULL;
+		switch (head->agp_info.chipset) {
+		case INTEL_GENERIC:	head->chipset = "Intel";         break;
+		case INTEL_LX:		head->chipset = "Intel 440LX";   break;
+		case INTEL_BX:		head->chipset = "Intel 440BX";   break;
+		case INTEL_GX:		head->chipset = "Intel 440GX";   break;
+		case INTEL_I810:	head->chipset = "Intel i810";    break;
+
+#if LINUX_VERSION_CODE >= 0x020400
+		case INTEL_I840:	head->chipset = "Intel i840";    break;
+#endif
+		case INTEL_460GX:	head->chipset = "Intel 460GX";	 break;
+
+		case VIA_GENERIC:	head->chipset = "VIA";           break;
+		case VIA_VP3:		head->chipset = "VIA VP3";       break;
+		case VIA_MVP3:		head->chipset = "VIA MVP3";      break;
+
+#if LINUX_VERSION_CODE >= 0x020400
+		case VIA_MVP4:		head->chipset = "VIA MVP4";      break;
+		case VIA_APOLLO_KX133:	head->chipset = "VIA Apollo KX133"; 
+			break;
+		case VIA_APOLLO_KT133:	head->chipset = "VIA Apollo KT133"; 
+			break;
+#endif
+
+		case VIA_APOLLO_PRO: 	head->chipset = "VIA Apollo Pro";
+			break;
+		case SIS_GENERIC:	head->chipset = "SiS";           break;
+		case AMD_GENERIC:	head->chipset = "AMD";           break;
+		case AMD_IRONGATE:	head->chipset = "AMD Irongate";  break;
+		case ALI_GENERIC:	head->chipset = "ALi";           break;
+		case ALI_M1541: 	head->chipset = "ALi M1541";     break;
+		case ALI_M1621: 	head->chipset = "ALi M1621";	 break;
+		case ALI_M1631: 	head->chipset = "ALi M1631";	 break;
+		case ALI_M1632: 	head->chipset = "ALi M1632";	 break;
+		case ALI_M1641: 	head->chipset = "ALi M1641";	 break;
+		case ALI_M1647: 	head->chipset = "ALi M1647";	 break;
+		case ALI_M1651: 	head->chipset = "ALi M1651";	 break;
+		case SVWRKS_GENERIC:	head->chipset = "Serverworks Generic";
+			break;
+		case SVWRKS_HE: 	head->chipset = "Serverworks HE"; break;
+		case SVWRKS_LE: 	head->chipset = "Serverworks LE"; break;
+
+		default:		head->chipset = "Unknown";       break;
+		}
+#if LINUX_VERSION_CODE <= 0x020408
+		head->cant_use_aperture = 0;
+		head->page_mask = ~(0xfff);
+#else
+		head->cant_use_aperture = head->agp_info.cant_use_aperture;
+		head->page_mask = head->agp_info.page_mask;
+#endif
+
+		DRM_INFO("AGP %d.%d on %s @ 0x%08lx %ZuMB\n",
+			 head->agp_info.version.major,
+			 head->agp_info.version.minor,
+			 head->chipset,
+			 head->agp_info.aper_base,
+			 head->agp_info.aper_size);
+	}
+	return head;
+}
+
+void drm_agp_uninit(void)
+{
+	DRM_AGP_PUT;
+	drm_agp = NULL;
+}
+
+agp_memory *drm_agp_allocate_memory(size_t pages, u32 type)
+{
+	if (!drm_agp->allocate_memory) return NULL;
+	return drm_agp->allocate_memory(pages, type);
+}
+
+int drm_agp_free_memory(agp_memory *handle)
+{
+	if (!handle || !drm_agp->free_memory) return 0;
+	drm_agp->free_memory(handle);
+	return 1;
+}
+
+int drm_agp_bind_memory(agp_memory *handle, off_t start)
+{
+	if (!handle || !drm_agp->bind_memory) return -EINVAL;
+	return drm_agp->bind_memory(handle, start);
+}
+
+int drm_agp_unbind_memory(agp_memory *handle)
+{
+	if (!handle || !drm_agp->unbind_memory) return -EINVAL;
+	return drm_agp->unbind_memory(handle);
+}
diff -urN linux-2.4.13/drivers/char/drm-4.0/auth.c linux-2.4.13-lia/drivers/char/drm-4.0/auth.c
--- linux-2.4.13/drivers/char/drm-4.0/auth.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/auth.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,162 @@
+/* auth.c -- IOCTLs for authentication -*- linux-c -*-
+ * Created: Tue Feb  2 08:37:54 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+static int drm_hash_magic(drm_magic_t magic)
+{
+	return magic & (DRM_HASH_SIZE-1);
+}
+
+static drm_file_t *drm_find_file(drm_device_t *dev, drm_magic_t magic)
+{
+	drm_file_t	  *retval = NULL;
+	drm_magic_entry_t *pt;
+	int		  hash	  = drm_hash_magic(magic);
+
+	down(&dev->struct_sem);
+	for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
+		if (pt->magic = magic) {
+			retval = pt->priv;
+			break;
+		}
+	}
+	up(&dev->struct_sem);
+	return retval;
+}
+
+int drm_add_magic(drm_device_t *dev, drm_file_t *priv, drm_magic_t magic)
+{
+	int		  hash;
+	drm_magic_entry_t *entry;
+	
+	DRM_DEBUG("%d\n", magic);
+	
+	hash	     = drm_hash_magic(magic);
+	entry	     = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC);
+	if (!entry) return -ENOMEM;
+	entry->magic = magic;
+	entry->priv  = priv;
+	entry->next  = NULL;
+
+	down(&dev->struct_sem);
+	if (dev->magiclist[hash].tail) {
+		dev->magiclist[hash].tail->next = entry;
+		dev->magiclist[hash].tail	= entry;
+	} else {
+		dev->magiclist[hash].head	= entry;
+		dev->magiclist[hash].tail	= entry;
+	}
+	up(&dev->struct_sem);
+	
+	return 0;
+}
+
+int drm_remove_magic(drm_device_t *dev, drm_magic_t magic)
+{
+	drm_magic_entry_t *prev = NULL;
+	drm_magic_entry_t *pt;
+	int		  hash;
+	
+	DRM_DEBUG("%d\n", magic);
+	hash = drm_hash_magic(magic);
+	
+	down(&dev->struct_sem);
+	for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) {
+		if (pt->magic = magic) {
+			if (dev->magiclist[hash].head = pt) {
+				dev->magiclist[hash].head = pt->next;
+			}
+			if (dev->magiclist[hash].tail = pt) {
+				dev->magiclist[hash].tail = prev;
+			}
+			if (prev) {
+				prev->next = pt->next;
+			}
+			up(&dev->struct_sem);
+			return 0;
+		}
+	}
+	up(&dev->struct_sem);
+
+	drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+	
+	return -EINVAL;
+}
+
+int drm_getmagic(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	static drm_magic_t sequence = 0;
+	static spinlock_t  lock	    = SPIN_LOCK_UNLOCKED;
+	drm_file_t	   *priv    = filp->private_data;
+	drm_device_t	   *dev	    = priv->dev;
+	drm_auth_t	   auth;
+
+				/* Find unique magic */
+	if (priv->magic) {
+		auth.magic = priv->magic;
+	} else {
+		do {
+			spin_lock(&lock);
+			if (!sequence) ++sequence; /* reserve 0 */
+			auth.magic = sequence++;
+			spin_unlock(&lock);
+		} while (drm_find_file(dev, auth.magic));
+		priv->magic = auth.magic;
+		drm_add_magic(dev, priv, auth.magic);
+	}
+	
+	DRM_DEBUG("%u\n", auth.magic);
+	if (copy_to_user((drm_auth_t *)arg, &auth, sizeof(auth)))
+		return -EFAULT;
+	return 0;
+}
+
+int drm_authmagic(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	   *priv    = filp->private_data;
+	drm_device_t	   *dev	    = priv->dev;
+	drm_auth_t	   auth;
+	drm_file_t	   *file;
+
+	if (copy_from_user(&auth, (drm_auth_t *)arg, sizeof(auth)))
+		return -EFAULT;
+	DRM_DEBUG("%u\n", auth.magic);
+	if ((file = drm_find_file(dev, auth.magic))) {
+		file->authenticated = 1;
+		drm_remove_magic(dev, auth.magic);
+		return 0;
+	}
+	return -EINVAL;
+}
diff -urN linux-2.4.13/drivers/char/drm-4.0/bufs.c linux-2.4.13-lia/drivers/char/drm-4.0/bufs.c
--- linux-2.4.13/drivers/char/drm-4.0/bufs.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/bufs.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,543 @@
+/* bufs.c -- IOCTLs to manage buffers -*- linux-c -*-
+ * Created: Tue Feb  2 08:37:54 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include "drmP.h"
+#include "linux/un.h"
+
+				/* Compute order.  Can be made faster. */
+int drm_order(unsigned long size)
+{
+	int	      order;
+	unsigned long tmp;
+
+	for (order = 0, tmp = size; tmp >>= 1; ++order);
+	if (size & ~(1 << order)) ++order;
+	return order;
+}
+
+int drm_addmap(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_map_t	*map;
+	
+	if (!(filp->f_mode & 3)) return -EACCES; /* Require read/write */
+
+	map	     = drm_alloc(sizeof(*map), DRM_MEM_MAPS);
+	if (!map) return -ENOMEM;
+	if (copy_from_user(map, (drm_map_t *)arg, sizeof(*map))) {
+		drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		return -EFAULT;
+	}
+
+	DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n",
+		  map->offset, map->size, map->type);
+	if ((map->offset & (~PAGE_MASK)) || (map->size & (~PAGE_MASK))) {
+		drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		return -EINVAL;
+	}
+	map->mtrr   = -1;
+	map->handle = 0;
+
+	switch (map->type) {
+	case _DRM_REGISTERS:
+	case _DRM_FRAME_BUFFER:
+#if !defined(__sparc__) && !defined(__ia64__)
+		if (map->offset + map->size < map->offset
+		    || map->offset < virt_to_phys(high_memory)) {
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+			return -EINVAL;
+		}
+#endif
+#ifdef CONFIG_MTRR
+		if (map->type = _DRM_FRAME_BUFFER
+		    || (map->flags & _DRM_WRITE_COMBINING)) {
+			map->mtrr = mtrr_add(map->offset, map->size,
+					     MTRR_TYPE_WRCOMB, 1);
+		}
+#endif
+		map->handle = drm_ioremap(map->offset, map->size, dev);
+		break;
+			
+
+	case _DRM_SHM:
+		map->handle = (void *)drm_alloc_pages(drm_order(map->size)
+						      - PAGE_SHIFT,
+						      DRM_MEM_SAREA);
+		DRM_DEBUG("%ld %d %p\n", map->size, drm_order(map->size),
+			  map->handle);
+		if (!map->handle) {
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+			return -ENOMEM;
+		}
+		map->offset = (unsigned long)map->handle;
+		if (map->flags & _DRM_CONTAINS_LOCK) {
+			dev->lock.hw_lock = map->handle; /* Pointer to lock */
+		}
+		break;
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+	case _DRM_AGP:
+		map->offset = map->offset + dev->agp->base;
+		break;
+#endif
+	default:
+		drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		return -EINVAL;
+	}
+
+	down(&dev->struct_sem);
+	if (dev->maplist) {
+		++dev->map_count;
+		dev->maplist = drm_realloc(dev->maplist,
+					   (dev->map_count-1)
+					   * sizeof(*dev->maplist),
+					   dev->map_count
+					   * sizeof(*dev->maplist),
+					   DRM_MEM_MAPS);
+	} else {
+		dev->map_count = 1;
+		dev->maplist = drm_alloc(dev->map_count*sizeof(*dev->maplist),
+					 DRM_MEM_MAPS);
+	}
+	dev->maplist[dev->map_count-1] = map;
+	up(&dev->struct_sem);
+
+	if (copy_to_user((drm_map_t *)arg, map, sizeof(*map)))
+		return -EFAULT;
+	if (map->type != _DRM_SHM) {
+		if (copy_to_user(&((drm_map_t *)arg)->handle,
+				 &map->offset,
+				 sizeof(map->offset)))
+			return -EFAULT;
+	}		
+	return 0;
+}
+
+int drm_addbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_desc_t	 request;
+	int		 count;
+	int		 order;
+	int		 size;
+	int		 total;
+	int		 page_order;
+	drm_buf_entry_t	 *entry;
+	unsigned long	 page;
+	drm_buf_t	 *buf;
+	int		 alignment;
+	unsigned long	 offset;
+	int		 i;
+	int		 byte_count;
+	int		 page_count;
+
+	if (!dma) return -EINVAL;
+
+	if (copy_from_user(&request,
+			   (drm_buf_desc_t *)arg,
+			   sizeof(request)))
+		return -EFAULT;
+
+	count	   = request.count;
+	order	   = drm_order(request.size);
+	size	   = 1 << order;
+	
+	DRM_DEBUG("count = %d, size = %d (%d), order = %d, queue_count = %d\n",
+		  request.count, request.size, size, order, dev->queue_count);
+
+	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
+	if (dev->queue_count) return -EBUSY; /* Not while in use */
+
+	alignment  = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size):size;
+	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
+	total	   = PAGE_SIZE << page_order;
+
+	spin_lock(&dev->count_lock);
+	if (dev->buf_use) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	atomic_inc(&dev->buf_alloc);
+	spin_unlock(&dev->count_lock);
+	
+	down(&dev->struct_sem);
+	entry = &dma->bufs[order];
+	if (entry->buf_count) {
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM;	/* May only call once for each order */
+	}
+	
+	if(count < 0 || count > 4096)
+	{
+		up(&dev->struct_sem);
+		return -EINVAL;
+	}
+	
+	entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
+				   DRM_MEM_BUFS);
+	if (!entry->buflist) {
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM;
+	}
+	memset(entry->buflist, 0, count * sizeof(*entry->buflist));
+
+	entry->seglist = drm_alloc(count * sizeof(*entry->seglist),
+				   DRM_MEM_SEGS);
+	if (!entry->seglist) {
+		drm_free(entry->buflist,
+			 count * sizeof(*entry->buflist),
+			 DRM_MEM_BUFS);
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM;
+	}
+	memset(entry->seglist, 0, count * sizeof(*entry->seglist));
+
+	dma->pagelist = drm_realloc(dma->pagelist,
+				    dma->page_count * sizeof(*dma->pagelist),
+				    (dma->page_count + (count << page_order))
+				    * sizeof(*dma->pagelist),
+				    DRM_MEM_PAGES);
+	DRM_DEBUG("pagelist: %d entries\n",
+		  dma->page_count + (count << page_order));
+
+
+	entry->buf_size	  = size;
+	entry->page_order = page_order;
+	byte_count	  = 0;
+	page_count	  = 0;
+	while (entry->buf_count < count) {
+		if (!(page = drm_alloc_pages(page_order, DRM_MEM_DMA))) break;
+		entry->seglist[entry->seg_count++] = page;
+		for (i = 0; i < (1 << page_order); i++) {
+			DRM_DEBUG("page %d @ 0x%08lx\n",
+				  dma->page_count + page_count,
+				  page + PAGE_SIZE * i);
+			dma->pagelist[dma->page_count + page_count++]
+				= page + PAGE_SIZE * i;
+		}
+		for (offset = 0;
+		     offset + size <= total && entry->buf_count < count;
+		     offset += alignment, ++entry->buf_count) {
+			buf	     = &entry->buflist[entry->buf_count];
+			buf->idx     = dma->buf_count + entry->buf_count;
+			buf->total   = alignment;
+			buf->order   = order;
+			buf->used    = 0;
+			buf->offset  = (dma->byte_count + byte_count + offset);
+			buf->address = (void *)(page + offset);
+			buf->next    = NULL;
+			buf->waiting = 0;
+			buf->pending = 0;
+			init_waitqueue_head(&buf->dma_wait);
+			buf->pid     = 0;
+#if DRM_DMA_HISTOGRAM
+			buf->time_queued     = 0;
+			buf->time_dispatched = 0;
+			buf->time_completed  = 0;
+			buf->time_freed	     = 0;
+#endif
+			DRM_DEBUG("buffer %d @ %p\n",
+				  entry->buf_count, buf->address);
+		}
+		byte_count += PAGE_SIZE << page_order;
+	}
+
+	dma->buflist = drm_realloc(dma->buflist,
+				   dma->buf_count * sizeof(*dma->buflist),
+				   (dma->buf_count + entry->buf_count)
+				   * sizeof(*dma->buflist),
+				   DRM_MEM_BUFS);
+	for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++)
+		dma->buflist[i] = &entry->buflist[i - dma->buf_count];
+
+	dma->buf_count	+= entry->buf_count;
+	dma->seg_count	+= entry->seg_count;
+	dma->page_count += entry->seg_count << page_order;
+	dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order);
+	
+	drm_freelist_create(&entry->freelist, entry->buf_count);
+	for (i = 0; i < entry->buf_count; i++) {
+		drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]);
+	}
+	
+	up(&dev->struct_sem);
+
+	request.count = entry->buf_count;
+	request.size  = size;
+
+	if (copy_to_user((drm_buf_desc_t *)arg,
+			 &request,
+			 sizeof(request)))
+		return -EFAULT;
+	
+	atomic_dec(&dev->buf_alloc);
+	return 0;
+}
+
+int drm_infobufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_info_t	 request;
+	int		 i;
+	int		 count;
+
+	if (!dma) return -EINVAL;
+
+	spin_lock(&dev->count_lock);
+	if (atomic_read(&dev->buf_alloc)) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	++dev->buf_use;		/* Can't allocate more after this call */
+	spin_unlock(&dev->count_lock);
+
+	if (copy_from_user(&request,
+			   (drm_buf_info_t *)arg,
+			   sizeof(request)))
+		return -EFAULT;
+
+	for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
+		if (dma->bufs[i].buf_count) ++count;
+	}
+	
+	DRM_DEBUG("count = %d\n", count);
+	
+	if (request.count >= count) {
+		for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
+			if (dma->bufs[i].buf_count) {
+				if (copy_to_user(&request.list[count].count,
+						 &dma->bufs[i].buf_count,
+						 sizeof(dma->bufs[0]
+							.buf_count)) ||
+				    copy_to_user(&request.list[count].size,
+						 &dma->bufs[i].buf_size,
+						 sizeof(dma->bufs[0].buf_size)) ||
+				    copy_to_user(&request.list[count].low_mark,
+						 &dma->bufs[i]
+						 .freelist.low_mark,
+						 sizeof(dma->bufs[0]
+							.freelist.low_mark)) ||
+				    copy_to_user(&request.list[count]
+						 .high_mark,
+						 &dma->bufs[i]
+						 .freelist.high_mark,
+						 sizeof(dma->bufs[0]
+							.freelist.high_mark)))
+					return -EFAULT;
+
+				DRM_DEBUG("%d %d %d %d %d\n",
+					  i,
+					  dma->bufs[i].buf_count,
+					  dma->bufs[i].buf_size,
+					  dma->bufs[i].freelist.low_mark,
+					  dma->bufs[i].freelist.high_mark);
+				++count;
+			}
+		}
+	}
+	request.count = count;
+
+	if (copy_to_user((drm_buf_info_t *)arg,
+			 &request,
+			 sizeof(request)))
+		return -EFAULT;
+	
+	return 0;
+}
+
+int drm_markbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_desc_t	 request;
+	int		 order;
+	drm_buf_entry_t	 *entry;
+
+	if (!dma) return -EINVAL;
+
+	if (copy_from_user(&request,
+			   (drm_buf_desc_t *)arg,
+			   sizeof(request)))
+		return -EFAULT;
+
+	DRM_DEBUG("%d, %d, %d\n",
+		  request.size, request.low_mark, request.high_mark);
+	order = drm_order(request.size);
+	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
+	entry = &dma->bufs[order];
+
+	if (request.low_mark < 0 || request.low_mark > entry->buf_count)
+		return -EINVAL;
+	if (request.high_mark < 0 || request.high_mark > entry->buf_count)
+		return -EINVAL;
+
+	entry->freelist.low_mark  = request.low_mark;
+	entry->freelist.high_mark = request.high_mark;
+	
+	return 0;
+}
+
+int drm_freebufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_free_t	 request;
+	int		 i;
+	int		 idx;
+	drm_buf_t	 *buf;
+
+	if (!dma) return -EINVAL;
+
+	if (copy_from_user(&request,
+			   (drm_buf_free_t *)arg,
+			   sizeof(request)))
+		return -EFAULT;
+
+	DRM_DEBUG("%d\n", request.count);
+	for (i = 0; i < request.count; i++) {
+		if (copy_from_user(&idx,
+				   &request.list[i],
+				   sizeof(idx)))
+			return -EFAULT;
+		if (idx < 0 || idx >= dma->buf_count) {
+			DRM_ERROR("Index %d (of %d max)\n",
+				  idx, dma->buf_count - 1);
+			return -EINVAL;
+		}
+		buf = dma->buflist[idx];
+		if (buf->pid != current->pid) {
+			DRM_ERROR("Process %d freeing buffer owned by %d\n",
+				  current->pid, buf->pid);
+			return -EINVAL;
+		}
+		drm_free_buffer(dev, buf);
+	}
+	
+	return 0;
+}
+
+int drm_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	int		 retcode = 0;
+	const int	 zero	 = 0;
+	unsigned long	 virtual;
+	unsigned long	 address;
+	drm_buf_map_t	 request;
+	int		 i;
+
+	if (!dma) return -EINVAL;
+	
+	DRM_DEBUG("\n");
+
+	spin_lock(&dev->count_lock);
+	if (atomic_read(&dev->buf_alloc)) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	++dev->buf_use;		/* Can't allocate more after this call */
+	spin_unlock(&dev->count_lock);
+
+	if (copy_from_user(&request,
+			   (drm_buf_map_t *)arg,
+			   sizeof(request)))
+		return -EFAULT;
+
+	if (request.count >= dma->buf_count) {
+		down_write(&current->mm->mmap_sem);
+		virtual = do_mmap(filp, 0, dma->byte_count,
+				  PROT_READ|PROT_WRITE, MAP_SHARED, 0);
+		up_write(&current->mm->mmap_sem);
+		if (virtual > -1024UL) {
+				/* Real error */
+			retcode = (signed long)virtual;
+			goto done;
+		}
+		request.virtual = (void *)virtual;
+
+		for (i = 0; i < dma->buf_count; i++) {
+			if (copy_to_user(&request.list[i].idx,
+					 &dma->buflist[i]->idx,
+					 sizeof(request.list[0].idx))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+			if (copy_to_user(&request.list[i].total,
+					 &dma->buflist[i]->total,
+					 sizeof(request.list[0].total))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+			if (copy_to_user(&request.list[i].used,
+					 &zero,
+					 sizeof(zero))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+			address = virtual + dma->buflist[i]->offset;
+			if (copy_to_user(&request.list[i].address,
+					 &address,
+					 sizeof(address))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+		}
+	}
+done:
+	request.count = dma->buf_count;
+	DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode);
+
+	if (copy_to_user((drm_buf_map_t *)arg,
+			 &request,
+			 sizeof(request)))
+		return -EFAULT;
+
+	return retcode;
+}
diff -urN linux-2.4.13/drivers/char/drm-4.0/context.c linux-2.4.13-lia/drivers/char/drm-4.0/context.c
--- linux-2.4.13/drivers/char/drm-4.0/context.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/context.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,321 @@
+/* context.c -- IOCTLs for contexts and DMA queues -*- linux-c -*-
+ * Created: Tue Feb  2 08:37:54 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+static int drm_init_queue(drm_device_t *dev, drm_queue_t *q, drm_ctx_t *ctx)
+{
+	DRM_DEBUG("\n");
+	
+	if (atomic_read(&q->use_count) != 1
+	    || atomic_read(&q->finalization)
+	    || atomic_read(&q->block_count)) {
+		DRM_ERROR("New queue is already in use: u%d f%d b%d\n",
+			  atomic_read(&q->use_count),
+			  atomic_read(&q->finalization),
+			  atomic_read(&q->block_count));
+	}
+		  
+	atomic_set(&q->finalization,  0);
+	atomic_set(&q->block_count,   0);
+	atomic_set(&q->block_read,    0);
+	atomic_set(&q->block_write,   0);
+	atomic_set(&q->total_queued,  0);
+	atomic_set(&q->total_flushed, 0);
+	atomic_set(&q->total_locks,   0);
+
+	init_waitqueue_head(&q->write_queue);
+	init_waitqueue_head(&q->read_queue);
+	init_waitqueue_head(&q->flush_queue);
+
+	q->flags = ctx->flags;
+
+	drm_waitlist_create(&q->waitlist, dev->dma->buf_count);
+
+	return 0;
+}
+
+
+/* drm_alloc_queue:
+PRE: 1) dev->queuelist[0..dev->queue_count] is allocated and will not
+	disappear (so all deallocation must be done after IOCTLs are off)
+     2) dev->queue_count < dev->queue_slots
+     3) dev->queuelist[i].use_count = 0 and
+	dev->queuelist[i].finalization = 0 if i not in use 
+POST: 1) dev->queuelist[i].use_count = 1
+      2) dev->queue_count < dev->queue_slots */
+		
+static int drm_alloc_queue(drm_device_t *dev)
+{
+	int	    i;
+	drm_queue_t *queue;
+	int	    oldslots;
+	int	    newslots;
+				/* Check for a free queue */
+	for (i = 0; i < dev->queue_count; i++) {
+		atomic_inc(&dev->queuelist[i]->use_count);
+		if (atomic_read(&dev->queuelist[i]->use_count) = 1
+		    && !atomic_read(&dev->queuelist[i]->finalization)) {
+			DRM_DEBUG("%d (free)\n", i);
+			return i;
+		}
+		atomic_dec(&dev->queuelist[i]->use_count);
+	}
+				/* Allocate a new queue */
+	
+	queue = drm_alloc(sizeof(*queue), DRM_MEM_QUEUES);
+	if(queue = NULL)
+		return -ENOMEM;	
+
+	memset(queue, 0, sizeof(*queue));
+	down(&dev->struct_sem);
+	atomic_set(&queue->use_count, 1);
+	
+	++dev->queue_count;
+	if (dev->queue_count >= dev->queue_slots) {
+		oldslots = dev->queue_slots * sizeof(*dev->queuelist);
+		if (!dev->queue_slots) dev->queue_slots = 1;
+		dev->queue_slots *= 2;
+		newslots = dev->queue_slots * sizeof(*dev->queuelist);
+
+		dev->queuelist = drm_realloc(dev->queuelist,
+					     oldslots,
+					     newslots,
+					     DRM_MEM_QUEUES);
+		if (!dev->queuelist) {
+			up(&dev->struct_sem);
+			DRM_DEBUG("out of memory\n");
+			return -ENOMEM;
+		}
+	}
+	dev->queuelist[dev->queue_count-1] = queue;
+	
+	up(&dev->struct_sem);
+	DRM_DEBUG("%d (new)\n", dev->queue_count - 1);
+	return dev->queue_count - 1;
+}
+
+int drm_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_ctx_res_t	res;
+	drm_ctx_t	ctx;
+	int		i;
+
+	DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
+	if (copy_from_user(&res, (drm_ctx_res_t *)arg, sizeof(res)))
+		return -EFAULT;
+	if (res.count >= DRM_RESERVED_CONTEXTS) {
+		memset(&ctx, 0, sizeof(ctx));
+		for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+			ctx.handle = i;
+			if (copy_to_user(&res.contexts[i],
+					 &i,
+					 sizeof(i)))
+				return -EFAULT;
+		}
+	}
+	res.count = DRM_RESERVED_CONTEXTS;
+	if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res)))
+		return -EFAULT;
+	return 0;
+}
+
+
+int drm_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+		return -EFAULT;
+	if ((ctx.handle = drm_alloc_queue(dev)) = DRM_KERNEL_CONTEXT) {
+				/* Init kernel's context and get a new one. */
+		drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx);
+		ctx.handle = drm_alloc_queue(dev);
+	}
+	drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx);
+	DRM_DEBUG("%d\n", ctx.handle);
+	if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx)))
+		return -EFAULT;
+	return 0;
+}
+
+int drm_modctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+	drm_queue_t	*q;
+		
+	if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+		return -EFAULT;
+	
+	DRM_DEBUG("%d\n", ctx.handle);
+	
+	if (ctx.handle < 0 || ctx.handle >= dev->queue_count) return -EINVAL;
+	q = dev->queuelist[ctx.handle];
+	
+	atomic_inc(&q->use_count);
+	if (atomic_read(&q->use_count) = 1) {
+				/* No longer in use */
+		atomic_dec(&q->use_count);
+		return -EINVAL;
+	}
+
+	if (DRM_BUFCOUNT(&q->waitlist)) {
+		atomic_dec(&q->use_count);
+		return -EBUSY;
+	}
+	
+	q->flags = ctx.flags;
+	
+	atomic_dec(&q->use_count);
+	return 0;
+}
+
+int drm_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+	drm_queue_t	*q;
+		
+	if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+		return -EFAULT;
+	
+	DRM_DEBUG("%d\n", ctx.handle);
+	
+	if (ctx.handle >= dev->queue_count) return -EINVAL;
+	q = dev->queuelist[ctx.handle];
+	
+	atomic_inc(&q->use_count);
+	if (atomic_read(&q->use_count) = 1) {
+				/* No longer in use */
+		atomic_dec(&q->use_count);
+		return -EINVAL;
+	}
+	
+	ctx.flags = q->flags;
+	atomic_dec(&q->use_count);
+	
+	if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx)))
+		return -EFAULT;
+	
+	return 0;
+}
+
+int drm_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+		return -EFAULT;
+	DRM_DEBUG("%d\n", ctx.handle);
+	return drm_context_switch(dev, dev->last_context, ctx.handle);
+}
+
+int drm_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+		return -EFAULT;
+	DRM_DEBUG("%d\n", ctx.handle);
+	drm_context_switch_complete(dev, ctx.handle);
+
+	return 0;
+}
+
+int drm_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	      unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+	drm_queue_t	*q;
+	drm_buf_t	*buf;
+
+	if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+		return -EFAULT;
+	DRM_DEBUG("%d\n", ctx.handle);
+	
+	if (ctx.handle >= dev->queue_count) return -EINVAL;
+	q = dev->queuelist[ctx.handle];
+	
+	atomic_inc(&q->use_count);
+	if (atomic_read(&q->use_count) = 1) {
+				/* No longer in use */
+		atomic_dec(&q->use_count);
+		return -EINVAL;
+	}
+	
+	atomic_inc(&q->finalization); /* Mark queue in finalization state */
+	atomic_sub(2, &q->use_count); /* Mark queue as unused (pending
+					 finalization) */
+
+	while (test_and_set_bit(0, &dev->interrupt_flag)) {
+		schedule();
+		if (signal_pending(current)) {
+			clear_bit(0, &dev->interrupt_flag);
+			return -EINTR;
+		}
+	}
+				/* Remove queued buffers */
+	while ((buf = drm_waitlist_get(&q->waitlist))) {
+		drm_free_buffer(dev, buf);
+	}
+	clear_bit(0, &dev->interrupt_flag);
+	
+				/* Wakeup blocked processes */
+	wake_up_interruptible(&q->read_queue);
+	wake_up_interruptible(&q->write_queue);
+	wake_up_interruptible(&q->flush_queue);
+	
+				/* Finalization over.  Queue is made
+				   available when both use_count and
+				   finalization become 0, which won't
+				   happen until all the waiting processes
+				   stop waiting. */
+	atomic_dec(&q->finalization);
+	return 0;
+}
diff -urN linux-2.4.13/drivers/char/drm-4.0/ctxbitmap.c linux-2.4.13-lia/drivers/char/drm-4.0/ctxbitmap.c
--- linux-2.4.13/drivers/char/drm-4.0/ctxbitmap.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/ctxbitmap.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,85 @@
+/* ctxbitmap.c -- Context bitmap management -*- linux-c -*-
+ * Created: Thu Jan 6 03:56:42 2000 by jhartmann@precisioninsight.com
+ * 
+ * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Jeff Hartmann <jhartmann@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+void drm_ctxbitmap_free(drm_device_t *dev, int ctx_handle)
+{
+	if (ctx_handle < 0) goto failed;
+
+	if (ctx_handle < DRM_MAX_CTXBITMAP) {
+		clear_bit(ctx_handle, dev->ctx_bitmap);
+		return;
+	}
+failed:
+       	DRM_ERROR("Attempt to free invalid context handle: %d\n",
+		  ctx_handle);
+       	return;
+}
+
+int drm_ctxbitmap_next(drm_device_t *dev)
+{
+	int bit;
+
+	bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP);
+	if (bit < DRM_MAX_CTXBITMAP) {
+		set_bit(bit, dev->ctx_bitmap);
+	   	DRM_DEBUG("drm_ctxbitmap_next bit : %d\n", bit);
+		return bit;
+	}
+	return -1;
+}
+
+int drm_ctxbitmap_init(drm_device_t *dev)
+{
+	int i;
+   	int temp;
+
+	dev->ctx_bitmap = (unsigned long *) drm_alloc(PAGE_SIZE, 
+						      DRM_MEM_CTXBITMAP);
+	if(dev->ctx_bitmap = NULL) {
+		return -ENOMEM;
+	}
+	memset((void *) dev->ctx_bitmap, 0, PAGE_SIZE);
+	for(i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+		temp = drm_ctxbitmap_next(dev);
+	   	DRM_DEBUG("drm_ctxbitmap_init : %d\n", temp);
+	}
+
+	return 0;
+}
+
+void drm_ctxbitmap_cleanup(drm_device_t *dev)
+{
+	drm_free((void *)dev->ctx_bitmap, PAGE_SIZE,
+		 DRM_MEM_CTXBITMAP);
+}
+
diff -urN linux-2.4.13/drivers/char/drm-4.0/dma.c linux-2.4.13-lia/drivers/char/drm-4.0/dma.c
--- linux-2.4.13/drivers/char/drm-4.0/dma.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/dma.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,546 @@
+/* dma.c -- DMA IOCTL and function support -*- linux-c -*-
+ * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinuxa.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+#include <linux/interrupt.h>	/* For task queue support */
+
+void drm_dma_setup(drm_device_t *dev)
+{
+	int i;
+	
+	if (!(dev->dma = drm_alloc(sizeof(*dev->dma), DRM_MEM_DRIVER))) {
+                printk(KERN_ERR "drm_dma_setup: can't drm_alloc dev->dma");
+                return;
+        }       
+	memset(dev->dma, 0, sizeof(*dev->dma));
+	for (i = 0; i <= DRM_MAX_ORDER; i++)
+		memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0]));
+}
+
+void drm_dma_takedown(drm_device_t *dev)
+{
+	drm_device_dma_t  *dma = dev->dma;
+	int		  i, j;
+
+	if (!dma) return;
+	
+				/* Clear dma buffers */
+	for (i = 0; i <= DRM_MAX_ORDER; i++) {
+		if (dma->bufs[i].seg_count) {
+			DRM_DEBUG("order %d: buf_count = %d,"
+				  " seg_count = %d\n",
+				  i,
+				  dma->bufs[i].buf_count,
+				  dma->bufs[i].seg_count);
+			for (j = 0; j < dma->bufs[i].seg_count; j++) {
+				drm_free_pages(dma->bufs[i].seglist[j],
+					       dma->bufs[i].page_order,
+					       DRM_MEM_DMA);
+			}
+			drm_free(dma->bufs[i].seglist,
+				 dma->bufs[i].seg_count
+				 * sizeof(*dma->bufs[0].seglist),
+				 DRM_MEM_SEGS);
+		}
+	   	if(dma->bufs[i].buf_count) {
+		   	for(j = 0; j < dma->bufs[i].buf_count; j++) {
+			   if(dma->bufs[i].buflist[j].dev_private) {
+			      drm_free(dma->bufs[i].buflist[j].dev_private,
+				       dma->bufs[i].buflist[j].dev_priv_size,
+				       DRM_MEM_BUFS);
+			   }
+			}
+		   	drm_free(dma->bufs[i].buflist,
+				 dma->bufs[i].buf_count *
+				 sizeof(*dma->bufs[0].buflist),
+				 DRM_MEM_BUFS);
+		   	drm_freelist_destroy(&dma->bufs[i].freelist);
+		}
+	}
+	
+	if (dma->buflist) {
+		drm_free(dma->buflist,
+			 dma->buf_count * sizeof(*dma->buflist),
+			 DRM_MEM_BUFS);
+	}
+
+	if (dma->pagelist) {
+		drm_free(dma->pagelist,
+			 dma->page_count * sizeof(*dma->pagelist),
+			 DRM_MEM_PAGES);
+	}
+	drm_free(dev->dma, sizeof(*dev->dma), DRM_MEM_DRIVER);
+	dev->dma = NULL;
+}
+
+#if DRM_DMA_HISTOGRAM
+/* This is slow, but is useful for debugging. */
+int drm_histogram_slot(unsigned long count)
+{
+	int value = DRM_DMA_HISTOGRAM_INITIAL;
+	int slot;
+
+	for (slot = 0;
+	     slot < DRM_DMA_HISTOGRAM_SLOTS;
+	     ++slot, value = DRM_DMA_HISTOGRAM_NEXT(value)) {
+		if (count < value) return slot;
+	}
+	return DRM_DMA_HISTOGRAM_SLOTS - 1;
+}
+
+void drm_histogram_compute(drm_device_t *dev, drm_buf_t *buf)
+{
+	cycles_t queued_to_dispatched;
+	cycles_t dispatched_to_completed;
+	cycles_t completed_to_freed;
+	int	 q2d, d2c, c2f, q2c, q2f;
+	
+	if (buf->time_queued) {
+		queued_to_dispatched	= (buf->time_dispatched
+					   - buf->time_queued);
+		dispatched_to_completed = (buf->time_completed
+					   - buf->time_dispatched);
+		completed_to_freed	= (buf->time_freed
+					   - buf->time_completed);
+
+		q2d = drm_histogram_slot(queued_to_dispatched);
+		d2c = drm_histogram_slot(dispatched_to_completed);
+		c2f = drm_histogram_slot(completed_to_freed);
+
+		q2c = drm_histogram_slot(queued_to_dispatched
+					 + dispatched_to_completed);
+		q2f = drm_histogram_slot(queued_to_dispatched
+					 + dispatched_to_completed
+					 + completed_to_freed);
+		
+		atomic_inc(&dev->histo.total);
+		atomic_inc(&dev->histo.queued_to_dispatched[q2d]);
+		atomic_inc(&dev->histo.dispatched_to_completed[d2c]);
+		atomic_inc(&dev->histo.completed_to_freed[c2f]);
+		
+		atomic_inc(&dev->histo.queued_to_completed[q2c]);
+		atomic_inc(&dev->histo.queued_to_freed[q2f]);
+
+	}
+	buf->time_queued     = 0;
+	buf->time_dispatched = 0;
+	buf->time_completed  = 0;
+	buf->time_freed	     = 0;
+}
+#endif
+
+void drm_free_buffer(drm_device_t *dev, drm_buf_t *buf)
+{
+	drm_device_dma_t *dma = dev->dma;
+
+	if (!buf) return;
+	
+	buf->waiting  = 0;
+	buf->pending  = 0;
+	buf->pid      = 0;
+	buf->used     = 0;
+#if DRM_DMA_HISTOGRAM
+	buf->time_completed = get_cycles();
+#endif
+	if (waitqueue_active(&buf->dma_wait)) {
+		wake_up_interruptible(&buf->dma_wait);
+	} else {
+				/* If processes are waiting, the last one
+				   to wake will put the buffer on the free
+				   list.  If no processes are waiting, we
+				   put the buffer on the freelist here. */
+		drm_freelist_put(dev, &dma->bufs[buf->order].freelist, buf);
+	}
+}
+
+void drm_reclaim_buffers(drm_device_t *dev, pid_t pid)
+{
+	drm_device_dma_t *dma = dev->dma;
+	int		 i;
+
+	if (!dma) return;
+	for (i = 0; i < dma->buf_count; i++) {
+		if (dma->buflist[i]->pid = pid) {
+			switch (dma->buflist[i]->list) {
+			case DRM_LIST_NONE:
+				drm_free_buffer(dev, dma->buflist[i]);
+				break;
+			case DRM_LIST_WAIT:
+				dma->buflist[i]->list = DRM_LIST_RECLAIM;
+				break;
+			default:
+				/* Buffer already on hardware. */
+				break;
+			}
+		}
+	}
+}
+
+int drm_context_switch(drm_device_t *dev, int old, int new)
+{
+	char	    buf[64];
+	drm_queue_t *q;
+
+	atomic_inc(&dev->total_ctx);
+
+	if (test_and_set_bit(0, &dev->context_flag)) {
+		DRM_ERROR("Reentering -- FIXME\n");
+		return -EBUSY;
+	}
+
+#if DRM_DMA_HISTOGRAM
+	dev->ctx_start = get_cycles();
+#endif
+	
+	DRM_DEBUG("Context switch from %d to %d\n", old, new);
+
+	if (new >= dev->queue_count) {
+		clear_bit(0, &dev->context_flag);
+		return -EINVAL;
+	}
+
+	if (new = dev->last_context) {
+		clear_bit(0, &dev->context_flag);
+		return 0;
+	}
+	
+	q = dev->queuelist[new];
+	atomic_inc(&q->use_count);
+	if (atomic_read(&q->use_count) = 1) {
+		atomic_dec(&q->use_count);
+		clear_bit(0, &dev->context_flag);
+		return -EINVAL;
+	}
+
+	if (drm_flags & DRM_FLAG_NOCTX) {
+		drm_context_switch_complete(dev, new);
+	} else {
+		sprintf(buf, "C %d %d\n", old, new);
+		drm_write_string(dev, buf);
+	}
+	
+	atomic_dec(&q->use_count);
+	
+	return 0;
+}
+
+int drm_context_switch_complete(drm_device_t *dev, int new)
+{
+	drm_device_dma_t *dma = dev->dma;
+	
+	dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */
+	dev->last_switch  = jiffies;
+	
+	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("Lock isn't held after context switch\n");
+	}
+
+	if (!dma || !(dma->next_buffer && dma->next_buffer->while_locked)) {
+		if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+				  DRM_KERNEL_CONTEXT)) {
+			DRM_ERROR("Cannot free lock\n");
+		}
+	}
+	
+#if DRM_DMA_HISTOGRAM
+	atomic_inc(&dev->histo.ctx[drm_histogram_slot(get_cycles()
+						      - dev->ctx_start)]);
+		   
+#endif
+	clear_bit(0, &dev->context_flag);
+	wake_up_interruptible(&dev->context_wait);
+	
+	return 0;
+}
+
+void drm_clear_next_buffer(drm_device_t *dev)
+{
+	drm_device_dma_t *dma = dev->dma;
+	
+	dma->next_buffer = NULL;
+	if (dma->next_queue && !DRM_BUFCOUNT(&dma->next_queue->waitlist)) {
+		wake_up_interruptible(&dma->next_queue->flush_queue);
+	}
+	dma->next_queue	 = NULL;
+}
+
+
+int drm_select_queue(drm_device_t *dev, void (*wrapper)(unsigned long))
+{
+	int	   i;
+	int	   candidate = -1;
+	int	   j	     = jiffies;
+
+	if (!dev) {
+		DRM_ERROR("No device\n");
+		return -1;
+	}
+	if (!dev->queuelist || !dev->queuelist[DRM_KERNEL_CONTEXT]) {
+				/* This only happens between the time the
+				   interrupt is initialized and the time
+				   the queues are initialized. */
+		return -1;
+	}
+
+				/* Doing "while locked" DMA? */
+	if (DRM_WAITCOUNT(dev, DRM_KERNEL_CONTEXT)) {
+		return DRM_KERNEL_CONTEXT;
+	}
+
+				/* If there are buffers on the last_context
+				   queue, and we have not been executing
+				   this context very long, continue to
+				   execute this context. */
+	if (dev->last_switch <= j
+	    && dev->last_switch + DRM_TIME_SLICE > j
+	    && DRM_WAITCOUNT(dev, dev->last_context)) {
+		return dev->last_context;
+	}
+
+				/* Otherwise, find a candidate */
+	for (i = dev->last_checked + 1; i < dev->queue_count; i++) {
+		if (DRM_WAITCOUNT(dev, i)) {
+			candidate = dev->last_checked = i;
+			break;
+		}
+	}
+
+	if (candidate < 0) {
+		for (i = 0; i < dev->queue_count; i++) {
+			if (DRM_WAITCOUNT(dev, i)) {
+				candidate = dev->last_checked = i;
+				break;
+			}
+		}
+	}
+
+	if (wrapper
+	    && candidate >= 0
+	    && candidate != dev->last_context
+	    && dev->last_switch <= j
+	    && dev->last_switch + DRM_TIME_SLICE > j) {
+		if (dev->timer.expires != dev->last_switch + DRM_TIME_SLICE) {
+			del_timer(&dev->timer);
+			dev->timer.function = wrapper;
+			dev->timer.data	    = (unsigned long)dev;
+			dev->timer.expires  = dev->last_switch+DRM_TIME_SLICE;
+			add_timer(&dev->timer);
+		}
+		return -1;
+	}
+
+	return candidate;
+}
+
+
+int drm_dma_enqueue(drm_device_t *dev, drm_dma_t *d)
+{
+	int		  i;
+	drm_queue_t	  *q;
+	drm_buf_t	  *buf;
+	int		  idx;
+	int		  while_locked = 0;
+	drm_device_dma_t  *dma = dev->dma;
+	DECLARE_WAITQUEUE(entry, current);
+
+	DRM_DEBUG("%d\n", d->send_count);
+
+	if (d->flags & _DRM_DMA_WHILE_LOCKED) {
+		int context = dev->lock.hw_lock->lock;
+		
+		if (!_DRM_LOCK_IS_HELD(context)) {
+			DRM_ERROR("No lock held during \"while locked\""
+				  " request\n");
+			return -EINVAL;
+		}
+		if (d->context != _DRM_LOCKING_CONTEXT(context)
+		    && _DRM_LOCKING_CONTEXT(context) != DRM_KERNEL_CONTEXT) {
+			DRM_ERROR("Lock held by %d while %d makes"
+				  " \"while locked\" request\n",
+				  _DRM_LOCKING_CONTEXT(context),
+				  d->context);
+			return -EINVAL;
+		}
+		q = dev->queuelist[DRM_KERNEL_CONTEXT];
+		while_locked = 1;
+	} else {
+		q = dev->queuelist[d->context];
+	}
+
+
+	atomic_inc(&q->use_count);
+	if (atomic_read(&q->block_write)) {
+		add_wait_queue(&q->write_queue, &entry);
+		atomic_inc(&q->block_count);
+		for (;;) {
+			current->state = TASK_INTERRUPTIBLE;
+			if (!atomic_read(&q->block_write)) break;
+			schedule();
+			if (signal_pending(current)) {
+				atomic_dec(&q->use_count);
+				remove_wait_queue(&q->write_queue, &entry);
+				return -EINTR;
+			}
+		}
+		atomic_dec(&q->block_count);
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&q->write_queue, &entry);
+	}
+	
+	for (i = 0; i < d->send_count; i++) {
+		idx = d->send_indices[i];
+		if (idx < 0 || idx >= dma->buf_count) {
+			atomic_dec(&q->use_count);
+			DRM_ERROR("Index %d (of %d max)\n",
+				  d->send_indices[i], dma->buf_count - 1);
+			return -EINVAL;
+		}
+		buf = dma->buflist[ idx ];
+		if (buf->pid != current->pid) {
+			atomic_dec(&q->use_count);
+			DRM_ERROR("Process %d using buffer owned by %d\n",
+				  current->pid, buf->pid);
+			return -EINVAL;
+		}
+		if (buf->list != DRM_LIST_NONE) {
+			atomic_dec(&q->use_count);
+			DRM_ERROR("Process %d using buffer %d on list %d\n",
+				  current->pid, buf->idx, buf->list);
+		}
+		buf->used	  = d->send_sizes[i];
+		buf->while_locked = while_locked;
+		buf->context	  = d->context;
+		if (!buf->used) {
+			DRM_ERROR("Queueing 0 length buffer\n");
+		}
+		if (buf->pending) {
+			atomic_dec(&q->use_count);
+			DRM_ERROR("Queueing pending buffer:"
+				  " buffer %d, offset %d\n",
+				  d->send_indices[i], i);
+			return -EINVAL;
+		}
+		if (buf->waiting) {
+			atomic_dec(&q->use_count);
+			DRM_ERROR("Queueing waiting buffer:"
+				  " buffer %d, offset %d\n",
+				  d->send_indices[i], i);
+			return -EINVAL;
+		}
+		buf->waiting = 1;
+		if (atomic_read(&q->use_count) = 1
+		    || atomic_read(&q->finalization)) {
+			drm_free_buffer(dev, buf);
+		} else {
+			drm_waitlist_put(&q->waitlist, buf);
+			atomic_inc(&q->total_queued);
+		}
+	}
+	atomic_dec(&q->use_count);
+	
+	return 0;
+}
+
+static int drm_dma_get_buffers_of_order(drm_device_t *dev, drm_dma_t *d,
+					int order)
+{
+	int		  i;
+	drm_buf_t	  *buf;
+	drm_device_dma_t  *dma = dev->dma;
+	
+	for (i = d->granted_count; i < d->request_count; i++) {
+		buf = drm_freelist_get(&dma->bufs[order].freelist,
+				       d->flags & _DRM_DMA_WAIT);
+		if (!buf) break;
+		if (buf->pending || buf->waiting) {
+			DRM_ERROR("Free buffer %d in use by %d (w%d, p%d)\n",
+				  buf->idx,
+				  buf->pid,
+				  buf->waiting,
+				  buf->pending);
+		}
+		buf->pid     = current->pid;
+		if (copy_to_user(&d->request_indices[i],
+				 &buf->idx,
+				 sizeof(buf->idx)))
+			return -EFAULT;
+
+		if (copy_to_user(&d->request_sizes[i],
+				 &buf->total,
+				 sizeof(buf->total)))
+			return -EFAULT;
+
+		++d->granted_count;
+	}
+	return 0;
+}
+
+
+int drm_dma_get_buffers(drm_device_t *dev, drm_dma_t *dma)
+{
+	int		  order;
+	int		  retcode = 0;
+	int		  tmp_order;
+	
+	order = drm_order(dma->request_size);
+
+	dma->granted_count = 0;
+	retcode		   = drm_dma_get_buffers_of_order(dev, dma, order);
+
+	if (dma->granted_count < dma->request_count
+	    && (dma->flags & _DRM_DMA_SMALLER_OK)) {
+		for (tmp_order = order - 1;
+		     !retcode
+			     && dma->granted_count < dma->request_count
+			     && tmp_order >= DRM_MIN_ORDER;
+		     --tmp_order) {
+			
+			retcode = drm_dma_get_buffers_of_order(dev, dma,
+							       tmp_order);
+		}
+	}
+
+	if (dma->granted_count < dma->request_count
+	    && (dma->flags & _DRM_DMA_LARGER_OK)) {
+		for (tmp_order = order + 1;
+		     !retcode
+			     && dma->granted_count < dma->request_count
+			     && tmp_order <= DRM_MAX_ORDER;
+		     ++tmp_order) {
+			
+			retcode = drm_dma_get_buffers_of_order(dev, dma,
+							       tmp_order);
+		}
+	}
+	return 0;
+}
diff -urN linux-2.4.13/drivers/char/drm-4.0/drawable.c linux-2.4.13-lia/drivers/char/drm-4.0/drawable.c
--- linux-2.4.13/drivers/char/drm-4.0/drawable.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/drawable.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,51 @@
+/* drawable.c -- IOCTLs for drawables -*- linux-c -*-
+ * Created: Tue Feb  2 08:37:54 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int drm_adddraw(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_draw_t draw;
+
+	draw.handle = 0;	/* NOOP */
+	DRM_DEBUG("%d\n", draw.handle);
+	if (copy_to_user((drm_draw_t *)arg, &draw, sizeof(draw)))
+		return -EFAULT;
+	return 0;
+}
+
+int drm_rmdraw(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	return 0;		/* NOOP */
+}
diff -urN linux-2.4.13/drivers/char/drm-4.0/drm.h linux-2.4.13-lia/drivers/char/drm-4.0/drm.h
--- linux-2.4.13/drivers/char/drm-4.0/drm.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/drm.h	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,414 @@
+/* drm.h -- Header for Direct Rendering Manager -*- linux-c -*-
+ * Created: Mon Jan  4 10:05:05 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ * Acknowledgements:
+ * Dec 1999, Richard Henderson <rth@twiddle.net>, move to generic cmpxchg.
+ *
+ */
+
+#ifndef _DRM_H_
+#define _DRM_H_
+
+#include <linux/config.h>
+#if defined(__linux__)
+#include <asm/ioctl.h>		/* For _IO* macros */
+#define DRM_IOCTL_NR(n)	     _IOC_NR(n)
+#elif defined(__FreeBSD__)
+#include <sys/ioccom.h>
+#define DRM_IOCTL_NR(n)	     ((n) & 0xff)
+#endif
+
+#define DRM_PROC_DEVICES "/proc/devices"
+#define DRM_PROC_MISC	 "/proc/misc"
+#define DRM_PROC_DRM	 "/proc/drm"
+#define DRM_DEV_DRM	 "/dev/drm"
+#define DRM_DEV_MODE	 (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
+#define DRM_DEV_UID	 0
+#define DRM_DEV_GID	 0
+
+
+#define DRM_NAME	"drm"	  /* Name in kernel, /dev, and /proc	    */
+#define DRM_MIN_ORDER	5	  /* At least 2^5 bytes = 32 bytes	    */
+#define DRM_MAX_ORDER	22	  /* Up to 2^22 bytes = 4MB		    */
+#define DRM_RAM_PERCENT 10	  /* How much system ram can we lock?	    */
+
+#define _DRM_LOCK_HELD	0x80000000 /* Hardware lock is held		    */
+#define _DRM_LOCK_CONT	0x40000000 /* Hardware lock is contended	    */
+#define _DRM_LOCK_IS_HELD(lock)	   ((lock) & _DRM_LOCK_HELD)
+#define _DRM_LOCK_IS_CONT(lock)	   ((lock) & _DRM_LOCK_CONT)
+#define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT))
+
+typedef unsigned long drm_handle_t;
+typedef unsigned int  drm_context_t;
+typedef unsigned int  drm_drawable_t;
+typedef unsigned int  drm_magic_t;
+
+/* Warning: If you change this structure, make sure you change
+ * XF86DRIClipRectRec in the server as well */
+
+typedef struct drm_clip_rect {
+           unsigned short x1;
+           unsigned short y1;
+           unsigned short x2;
+           unsigned short y2;
+} drm_clip_rect_t;
+
+/* Seperate include files for the i810/mga/r128 specific structures */
+#include "mga_drm.h"
+#include "i810_drm.h"
+#include "r128_drm.h"
+#include "radeon_drm.h"
+#ifdef CONFIG_DRM40_SIS
+#include "sis_drm.h"
+#endif
+
+typedef struct drm_version {
+	int    version_major;	  /* Major version			    */
+	int    version_minor;	  /* Minor version			    */
+	int    version_patchlevel;/* Patch level			    */
+	size_t name_len;	  /* Length of name buffer		    */
+	char   *name;		  /* Name of driver			    */
+	size_t date_len;	  /* Length of date buffer		    */
+	char   *date;		  /* User-space buffer to hold date	    */
+	size_t desc_len;	  /* Length of desc buffer		    */
+	char   *desc;		  /* User-space buffer to hold desc	    */
+} drm_version_t;
+
+typedef struct drm_unique {
+	size_t unique_len;	  /* Length of unique			    */
+	char   *unique;		  /* Unique name for driver instantiation   */
+} drm_unique_t;
+
+typedef struct drm_list {
+	int		 count;	  /* Length of user-space structures	    */
+	drm_version_t	 *version;
+} drm_list_t;
+
+typedef struct drm_block {
+	int		 unused;
+} drm_block_t;
+
+typedef struct drm_control {
+	enum {
+		DRM_ADD_COMMAND,
+		DRM_RM_COMMAND,
+		DRM_INST_HANDLER,
+		DRM_UNINST_HANDLER
+	}		 func;
+	int		 irq;
+} drm_control_t;
+
+typedef enum drm_map_type {
+	_DRM_FRAME_BUFFER = 0,	  /* WC (no caching), no core dump	    */
+	_DRM_REGISTERS	  = 1,	  /* no caching, no core dump		    */
+	_DRM_SHM	  = 2,	  /* shared, cached			    */
+	_DRM_AGP          = 3	  /* AGP/GART                               */
+} drm_map_type_t;
+
+typedef enum drm_map_flags {
+	_DRM_RESTRICTED	     = 0x01, /* Cannot be mapped to user-virtual    */
+	_DRM_READ_ONLY	     = 0x02,
+	_DRM_LOCKED	     = 0x04, /* shared, cached, locked		    */
+	_DRM_KERNEL	     = 0x08, /* kernel requires access		    */
+	_DRM_WRITE_COMBINING = 0x10, /* use write-combining if available    */
+	_DRM_CONTAINS_LOCK   = 0x20  /* SHM page that contains lock	    */
+} drm_map_flags_t;
+
+typedef struct drm_map {
+	unsigned long	offset;	 /* Requested physical address (0 for SAREA)*/
+	unsigned long	size;	 /* Requested physical size (bytes)	    */
+	drm_map_type_t	type;	 /* Type of memory to map		    */
+	drm_map_flags_t flags;	 /* Flags				    */
+	void		*handle; /* User-space: "Handle" to pass to mmap    */
+				 /* Kernel-space: kernel-virtual address    */
+	int		mtrr;	 /* MTRR slot used			    */
+				 /* Private data			    */
+} drm_map_t;
+
+typedef enum drm_lock_flags {
+	_DRM_LOCK_READY	     = 0x01, /* Wait until hardware is ready for DMA */
+	_DRM_LOCK_QUIESCENT  = 0x02, /* Wait until hardware quiescent	     */
+	_DRM_LOCK_FLUSH	     = 0x04, /* Flush this context's DMA queue first */
+	_DRM_LOCK_FLUSH_ALL  = 0x08, /* Flush all DMA queues first	     */
+				/* These *HALT* flags aren't supported yet
+				   -- they will be used to support the
+				   full-screen DGA-like mode. */
+	_DRM_HALT_ALL_QUEUES = 0x10, /* Halt all current and future queues   */
+	_DRM_HALT_CUR_QUEUES = 0x20  /* Halt all current queues		     */
+} drm_lock_flags_t;
+
+typedef struct drm_lock {
+	int		 context;
+	drm_lock_flags_t flags;
+} drm_lock_t;
+
+typedef enum drm_dma_flags {	      /* These values *MUST* match xf86drm.h */
+				      /* Flags for DMA buffer dispatch	     */
+	_DRM_DMA_BLOCK	      = 0x01, /* Block until buffer dispatched.
+					 Note, the buffer may not yet have
+					 been processed by the hardware --
+					 getting a hardware lock with the
+					 hardware quiescent will ensure
+					 that the buffer has been
+					 processed.			     */
+	_DRM_DMA_WHILE_LOCKED = 0x02, /* Dispatch while lock held	     */
+	_DRM_DMA_PRIORITY     = 0x04, /* High priority dispatch		     */
+
+				      /* Flags for DMA buffer request	     */
+	_DRM_DMA_WAIT	      = 0x10, /* Wait for free buffers		     */
+	_DRM_DMA_SMALLER_OK   = 0x20, /* Smaller-than-requested buffers ok   */
+	_DRM_DMA_LARGER_OK    = 0x40  /* Larger-than-requested buffers ok    */
+} drm_dma_flags_t;
+
+typedef struct drm_buf_desc {
+	int	      count;	 /* Number of buffers of this size	     */
+	int	      size;	 /* Size in bytes			     */
+	int	      low_mark;	 /* Low water mark			     */
+	int	      high_mark; /* High water mark			     */
+	enum {
+		_DRM_PAGE_ALIGN = 0x01, /* Align on page boundaries for DMA  */
+		_DRM_AGP_BUFFER = 0x02  /* Buffer is in agp space            */
+	}	      flags;
+	unsigned long agp_start; /* Start address of where the agp buffers
+				  * are in the agp aperture */
+} drm_buf_desc_t;
+
+typedef struct drm_buf_info {
+	int	       count;	/* Entries in list			     */
+	drm_buf_desc_t *list;
+} drm_buf_info_t;
+
+typedef struct drm_buf_free {
+	int	       count;
+	int	       *list;
+} drm_buf_free_t;
+
+typedef struct drm_buf_pub {
+	int		  idx;	       /* Index into master buflist	     */
+	int		  total;       /* Buffer size			     */
+	int		  used;	       /* Amount of buffer in use (for DMA)  */
+	void		  *address;    /* Address of buffer		     */
+} drm_buf_pub_t;
+
+typedef struct drm_buf_map {
+	int	      count;	/* Length of buflist			    */
+	void	      *virtual;	/* Mmaped area in user-virtual		    */
+	drm_buf_pub_t *list;	/* Buffer information			    */
+} drm_buf_map_t;
+
+typedef struct drm_dma {
+				/* Indices here refer to the offset into
+				   buflist in drm_buf_get_t.  */
+	int		context;	  /* Context handle		    */
+	int		send_count;	  /* Number of buffers to send	    */
+	int		*send_indices;	  /* List of handles to buffers	    */
+	int		*send_sizes;	  /* Lengths of data to send	    */
+	drm_dma_flags_t flags;		  /* Flags			    */
+	int		request_count;	  /* Number of buffers requested    */
+	int		request_size;	  /* Desired size for buffers	    */
+	int		*request_indices; /* Buffer information		    */
+	int		*request_sizes;
+	int		granted_count;	  /* Number of buffers granted	    */
+} drm_dma_t;
+
+typedef enum {
+	_DRM_CONTEXT_PRESERVED = 0x01,
+	_DRM_CONTEXT_2DONLY    = 0x02
+} drm_ctx_flags_t;
+
+typedef struct drm_ctx {
+	drm_context_t	handle;
+	drm_ctx_flags_t flags;
+} drm_ctx_t;
+
+typedef struct drm_ctx_res {
+	int		count;
+	drm_ctx_t	*contexts;
+} drm_ctx_res_t;
+
+typedef struct drm_draw {
+	drm_drawable_t	handle;
+} drm_draw_t;
+
+typedef struct drm_auth {
+	drm_magic_t	magic;
+} drm_auth_t;
+
+typedef struct drm_irq_busid {
+	int irq;
+	int busnum;
+	int devnum;
+	int funcnum;
+} drm_irq_busid_t;
+
+typedef struct drm_agp_mode {
+	unsigned long mode;
+} drm_agp_mode_t;
+
+				/* For drm_agp_alloc -- allocated a buffer */
+typedef struct drm_agp_buffer {
+	unsigned long size;	/* In bytes -- will round to page boundary */
+	unsigned long handle;	/* Used for BIND/UNBIND ioctls */
+	unsigned long type;     /* Type of memory to allocate  */
+        unsigned long physical; /* Physical used by i810       */
+} drm_agp_buffer_t;
+
+				/* For drm_agp_bind */
+typedef struct drm_agp_binding {
+	unsigned long handle;   /* From drm_agp_buffer */
+	unsigned long offset;	/* In bytes -- will round to page boundary */
+} drm_agp_binding_t;
+
+typedef struct drm_agp_info {
+	int            agp_version_major;
+	int            agp_version_minor;
+	unsigned long  mode;
+	unsigned long  aperture_base;  /* physical address */
+	unsigned long  aperture_size;  /* bytes */
+	unsigned long  memory_allowed; /* bytes */
+	unsigned long  memory_used;
+
+				/* PCI information */
+	unsigned short id_vendor;
+	unsigned short id_device;
+} drm_agp_info_t;
+
+#define DRM_IOCTL_BASE			'd'
+#define DRM_IO(nr)			_IO(DRM_IOCTL_BASE,nr)
+#define DRM_IOR(nr,size)		_IOR(DRM_IOCTL_BASE,nr,size)
+#define DRM_IOW(nr,size)		_IOW(DRM_IOCTL_BASE,nr,size)
+#define DRM_IOWR(nr,size)		_IOWR(DRM_IOCTL_BASE,nr,size)
+
+
+#define DRM_IOCTL_VERSION		DRM_IOWR(0x00, drm_version_t)
+#define DRM_IOCTL_GET_UNIQUE		DRM_IOWR(0x01, drm_unique_t)
+#define DRM_IOCTL_GET_MAGIC		DRM_IOR( 0x02, drm_auth_t)
+#define DRM_IOCTL_IRQ_BUSID		DRM_IOWR(0x03, drm_irq_busid_t)
+
+#define DRM_IOCTL_SET_UNIQUE		DRM_IOW( 0x10, drm_unique_t)
+#define DRM_IOCTL_AUTH_MAGIC		DRM_IOW( 0x11, drm_auth_t)
+#define DRM_IOCTL_BLOCK			DRM_IOWR(0x12, drm_block_t)
+#define DRM_IOCTL_UNBLOCK		DRM_IOWR(0x13, drm_block_t)
+#define DRM_IOCTL_CONTROL		DRM_IOW( 0x14, drm_control_t)
+#define DRM_IOCTL_ADD_MAP		DRM_IOWR(0x15, drm_map_t)
+#define DRM_IOCTL_ADD_BUFS		DRM_IOWR(0x16, drm_buf_desc_t)
+#define DRM_IOCTL_MARK_BUFS		DRM_IOW( 0x17, drm_buf_desc_t)
+#define DRM_IOCTL_INFO_BUFS		DRM_IOWR(0x18, drm_buf_info_t)
+#define DRM_IOCTL_MAP_BUFS		DRM_IOWR(0x19, drm_buf_map_t)
+#define DRM_IOCTL_FREE_BUFS		DRM_IOW( 0x1a, drm_buf_free_t)
+
+#define DRM_IOCTL_ADD_CTX		DRM_IOWR(0x20, drm_ctx_t)
+#define DRM_IOCTL_RM_CTX		DRM_IOWR(0x21, drm_ctx_t)
+#define DRM_IOCTL_MOD_CTX		DRM_IOW( 0x22, drm_ctx_t)
+#define DRM_IOCTL_GET_CTX		DRM_IOWR(0x23, drm_ctx_t)
+#define DRM_IOCTL_SWITCH_CTX		DRM_IOW( 0x24, drm_ctx_t)
+#define DRM_IOCTL_NEW_CTX		DRM_IOW( 0x25, drm_ctx_t)
+#define DRM_IOCTL_RES_CTX		DRM_IOWR(0x26, drm_ctx_res_t)
+#define DRM_IOCTL_ADD_DRAW		DRM_IOWR(0x27, drm_draw_t)
+#define DRM_IOCTL_RM_DRAW		DRM_IOWR(0x28, drm_draw_t)
+#define DRM_IOCTL_DMA			DRM_IOWR(0x29, drm_dma_t)
+#define DRM_IOCTL_LOCK			DRM_IOW( 0x2a, drm_lock_t)
+#define DRM_IOCTL_UNLOCK		DRM_IOW( 0x2b, drm_lock_t)
+#define DRM_IOCTL_FINISH		DRM_IOW( 0x2c, drm_lock_t)
+
+#define DRM_IOCTL_AGP_ACQUIRE		DRM_IO(  0x30)
+#define DRM_IOCTL_AGP_RELEASE		DRM_IO(  0x31)
+#define DRM_IOCTL_AGP_ENABLE		DRM_IOW( 0x32, drm_agp_mode_t)
+#define DRM_IOCTL_AGP_INFO		DRM_IOR( 0x33, drm_agp_info_t)
+#define DRM_IOCTL_AGP_ALLOC		DRM_IOWR(0x34, drm_agp_buffer_t)
+#define DRM_IOCTL_AGP_FREE		DRM_IOW( 0x35, drm_agp_buffer_t)
+#define DRM_IOCTL_AGP_BIND		DRM_IOW( 0x36, drm_agp_binding_t)
+#define DRM_IOCTL_AGP_UNBIND		DRM_IOW( 0x37, drm_agp_binding_t)
+
+/* Mga specific ioctls */
+#define DRM_IOCTL_MGA_INIT		DRM_IOW( 0x40, drm_mga_init_t)
+#define DRM_IOCTL_MGA_SWAP		DRM_IOW( 0x41, drm_mga_swap_t)
+#define DRM_IOCTL_MGA_CLEAR		DRM_IOW( 0x42, drm_mga_clear_t)
+#define DRM_IOCTL_MGA_ILOAD		DRM_IOW( 0x43, drm_mga_iload_t)
+#define DRM_IOCTL_MGA_VERTEX		DRM_IOW( 0x44, drm_mga_vertex_t)
+#define DRM_IOCTL_MGA_FLUSH		DRM_IOW( 0x45, drm_lock_t )
+#define DRM_IOCTL_MGA_INDICES		DRM_IOW( 0x46, drm_mga_indices_t)
+#define DRM_IOCTL_MGA_BLIT		DRM_IOW( 0x47, drm_mga_blit_t)
+
+/* I810 specific ioctls */
+#define DRM_IOCTL_I810_INIT		DRM_IOW( 0x40, drm_i810_init_t)
+#define DRM_IOCTL_I810_VERTEX		DRM_IOW( 0x41, drm_i810_vertex_t)
+#define DRM_IOCTL_I810_CLEAR		DRM_IOW( 0x42, drm_i810_clear_t)
+#define DRM_IOCTL_I810_FLUSH		DRM_IO(  0x43)
+#define DRM_IOCTL_I810_GETAGE		DRM_IO(  0x44)
+#define DRM_IOCTL_I810_GETBUF		DRM_IOWR(0x45, drm_i810_dma_t)
+#define DRM_IOCTL_I810_SWAP		DRM_IO(  0x46)
+#define DRM_IOCTL_I810_COPY		DRM_IOW( 0x47, drm_i810_copy_t)
+#define DRM_IOCTL_I810_DOCOPY		DRM_IO(  0x48)
+
+/* Rage 128 specific ioctls */
+#define DRM_IOCTL_R128_INIT		DRM_IOW( 0x40, drm_r128_init_t)
+#define DRM_IOCTL_R128_CCE_START	DRM_IO(  0x41)
+#define DRM_IOCTL_R128_CCE_STOP		DRM_IOW( 0x42, drm_r128_cce_stop_t)
+#define DRM_IOCTL_R128_CCE_RESET	DRM_IO(  0x43)
+#define DRM_IOCTL_R128_CCE_IDLE		DRM_IO(  0x44)
+#define DRM_IOCTL_R128_RESET		DRM_IO(  0x46)
+#define DRM_IOCTL_R128_SWAP		DRM_IO(  0x47)
+#define DRM_IOCTL_R128_CLEAR		DRM_IOW( 0x48, drm_r128_clear_t)
+#define DRM_IOCTL_R128_VERTEX		DRM_IOW( 0x49, drm_r128_vertex_t)
+#define DRM_IOCTL_R128_INDICES		DRM_IOW( 0x4a, drm_r128_indices_t)
+#define DRM_IOCTL_R128_BLIT		DRM_IOW( 0x4b, drm_r128_blit_t)
+#define DRM_IOCTL_R128_DEPTH		DRM_IOW( 0x4c, drm_r128_depth_t)
+#define DRM_IOCTL_R128_STIPPLE		DRM_IOW( 0x4d, drm_r128_stipple_t)
+#define DRM_IOCTL_R128_PACKET		DRM_IOWR(0x4e, drm_r128_packet_t)
+
+/* Radeon specific ioctls */
+#define DRM_IOCTL_RADEON_CP_INIT	DRM_IOW( 0x40, drm_radeon_init_t)
+#define DRM_IOCTL_RADEON_CP_START	DRM_IO(  0x41)
+#define DRM_IOCTL_RADEON_CP_STOP	DRM_IOW( 0x42, drm_radeon_cp_stop_t)
+#define DRM_IOCTL_RADEON_CP_RESET	DRM_IO(  0x43)
+#define DRM_IOCTL_RADEON_CP_IDLE	DRM_IO(  0x44)
+#define DRM_IOCTL_RADEON_RESET		DRM_IO(  0x45)
+#define DRM_IOCTL_RADEON_FULLSCREEN	DRM_IOW( 0x46, drm_radeon_fullscreen_t)
+#define DRM_IOCTL_RADEON_SWAP		DRM_IO(  0x47)
+#define DRM_IOCTL_RADEON_CLEAR		DRM_IOW( 0x48, drm_radeon_clear_t)
+#define DRM_IOCTL_RADEON_VERTEX		DRM_IOW( 0x49, drm_radeon_vertex_t)
+#define DRM_IOCTL_RADEON_INDICES	DRM_IOW( 0x4a, drm_radeon_indices_t)
+#define DRM_IOCTL_RADEON_BLIT		DRM_IOW( 0x4b, drm_radeon_blit_t)
+#define DRM_IOCTL_RADEON_STIPPLE	DRM_IOW( 0x4c, drm_radeon_stipple_t)
+#define DRM_IOCTL_RADEON_INDIRECT	DRM_IOWR(0x4d, drm_radeon_indirect_t)
+
+#ifdef CONFIG_DRM40_SIS
+/* SiS specific ioctls */
+#define SIS_IOCTL_FB_ALLOC		DRM_IOWR(0x44, drm_sis_mem_t)
+#define SIS_IOCTL_FB_FREE		DRM_IOW( 0x45, drm_sis_mem_t)
+#define SIS_IOCTL_AGP_INIT		DRM_IOWR(0x53, drm_sis_agp_t)
+#define SIS_IOCTL_AGP_ALLOC		DRM_IOWR(0x54, drm_sis_mem_t)
+#define SIS_IOCTL_AGP_FREE		DRM_IOW( 0x55, drm_sis_mem_t)
+#define SIS_IOCTL_FLIP			DRM_IOW( 0x48, drm_sis_flip_t)
+#define SIS_IOCTL_FLIP_INIT		DRM_IO(  0x49)
+#define SIS_IOCTL_FLIP_FINAL		DRM_IO(  0x50)
+#endif
+
+#endif
diff -urN linux-2.4.13/drivers/char/drm-4.0/drmP.h linux-2.4.13-lia/drivers/char/drm-4.0/drmP.h
--- linux-2.4.13/drivers/char/drm-4.0/drmP.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/drmP.h	Wed Oct 24 18:34:24 2001
@@ -0,0 +1,839 @@
+/* drmP.h -- Private header for Direct Rendering Manager -*- linux-c -*-
+ * Created: Mon Jan  4 10:05:05 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#ifndef _DRM_P_H_
+#define _DRM_P_H_
+
+#ifdef __KERNEL__
+#ifdef __alpha__
+/* add include of current.h so that "current" is defined
+ * before static inline funcs in wait.h. Doing this so we
+ * can build the DRM (part of PI DRI). 4/21/2000 S + B */
+#include <asm/current.h>
+#endif /* __alpha__ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/file.h>
+#include <linux/pci.h>
+#include <linux/wrapper.h>
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>	/* For (un)lock_kernel */
+#include <linux/mm.h>
+#ifdef __alpha__
+#include <asm/pgtable.h> /* For pte_wrprotect */
+#endif
+#include <asm/io.h>
+#include <asm/mman.h>
+#include <asm/uaccess.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+#include <linux/types.h>
+#include <linux/agp_backend.h>
+#endif
+#if LINUX_VERSION_CODE >= 0x020100 /* KERNEL_VERSION(2,1,0) */
+#include <linux/tqueue.h>
+#include <linux/poll.h>
+#endif
+#if LINUX_VERSION_CODE < 0x020400
+#include "compat-pre24.h"
+#endif
+#include "drm.h"
+
+#define DRM_DEBUG_CODE 2	  /* Include debugging code (if > 1, then
+				     also include looping detection. */
+#define DRM_DMA_HISTOGRAM 1	  /* Make histogram of DMA latency. */
+
+#define DRM_HASH_SIZE	      16 /* Size of key hash table		  */
+#define DRM_KERNEL_CONTEXT    0	 /* Change drm_resctx if changed	  */
+#define DRM_RESERVED_CONTEXTS 1	 /* Change drm_resctx if changed	  */
+#define DRM_LOOPING_LIMIT     5000000
+#define DRM_BSZ		      1024 /* Buffer size for /dev/drm? output	  */
+#define DRM_TIME_SLICE	      (HZ/20)  /* Time slice for GLXContexts	  */
+#define DRM_LOCK_SLICE	      1	/* Time slice for lock, in jiffies	  */
+
+#define DRM_FLAG_DEBUG	  0x01
+#define DRM_FLAG_NOCTX	  0x02
+
+#define DRM_MEM_DMA	   0
+#define DRM_MEM_SAREA	   1
+#define DRM_MEM_DRIVER	   2
+#define DRM_MEM_MAGIC	   3
+#define DRM_MEM_IOCTLS	   4
+#define DRM_MEM_MAPS	   5
+#define DRM_MEM_VMAS	   6
+#define DRM_MEM_BUFS	   7
+#define DRM_MEM_SEGS	   8
+#define DRM_MEM_PAGES	   9
+#define DRM_MEM_FILES	  10
+#define DRM_MEM_QUEUES	  11
+#define DRM_MEM_CMDS	  12
+#define DRM_MEM_MAPPINGS  13
+#define DRM_MEM_BUFLISTS  14
+#define DRM_MEM_AGPLISTS  15
+#define DRM_MEM_TOTALAGP  16
+#define DRM_MEM_BOUNDAGP  17
+#define DRM_MEM_CTXBITMAP 18
+
+#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
+
+				/* Backward compatibility section */
+				/* _PAGE_WT changed to _PAGE_PWT in 2.2.6 */
+#ifndef _PAGE_PWT
+#define _PAGE_PWT _PAGE_WT
+#endif
+				/* Wait queue declarations changed in 2.3.1 */
+#ifndef DECLARE_WAITQUEUE
+#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = { c, NULL }
+typedef struct wait_queue *wait_queue_head_t;
+#define init_waitqueue_head(q) *q = NULL;
+#endif
+
+				/* _PAGE_4M changed to _PAGE_PSE in 2.3.23 */
+#ifndef _PAGE_PSE
+#define _PAGE_PSE _PAGE_4M
+#endif
+
+				/* vm_offset changed to vm_pgoff in 2.3.25 */
+#if LINUX_VERSION_CODE < 0x020319
+#define VM_OFFSET(vma) ((vma)->vm_offset)
+#else
+#define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT)
+#endif
+
+				/* *_nopage return values defined in 2.3.26 */
+#ifndef NOPAGE_SIGBUS
+#define NOPAGE_SIGBUS 0
+#endif
+#ifndef NOPAGE_OOM
+#define NOPAGE_OOM 0
+#endif
+
+				/* module_init/module_exit added in 2.3.13 */
+#ifndef module_init
+#define module_init(x)  int init_module(void) { return x(); }
+#endif
+#ifndef module_exit
+#define module_exit(x)  void cleanup_module(void) { x(); }
+#endif
+
+				/* Generic cmpxchg added in 2.3.x */
+#ifndef __HAVE_ARCH_CMPXCHG
+				/* Include this here so that driver can be
+                                   used with older kernels. */
+#if defined(__alpha__)
+static __inline__ unsigned long
+__cmpxchg_u32(volatile int *m, int old, int new)
+{
+	unsigned long prev, cmp;
+
+	__asm__ __volatile__(
+	"1:	ldl_l %0,%2\n"
+	"	cmpeq %0,%3,%1\n"
+	"	beq %1,2f\n"
+	"	mov %4,%1\n"
+	"	stl_c %1,%2\n"
+	"	beq %1,3f\n"
+	"2:	mb\n"
+	".subsection 2\n"
+	"3:	br 1b\n"
+	".previous"
+	: "=&r"(prev), "=&r"(cmp), "=m"(*m)
+	: "r"((long) old), "r"(new), "m"(*m));
+
+	return prev;
+}
+
+static __inline__ unsigned long
+__cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new)
+{
+	unsigned long prev, cmp;
+
+	__asm__ __volatile__(
+	"1:	ldq_l %0,%2\n"
+	"	cmpeq %0,%3,%1\n"
+	"	beq %1,2f\n"
+	"	mov %4,%1\n"
+	"	stq_c %1,%2\n"
+	"	beq %1,3f\n"
+	"2:	mb\n"
+	".subsection 2\n"
+	"3:	br 1b\n"
+	".previous"
+	: "=&r"(prev), "=&r"(cmp), "=m"(*m)
+	: "r"((long) old), "r"(new), "m"(*m));
+
+	return prev;
+}
+
+static __inline__ unsigned long
+__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
+{
+	switch (size) {
+		case 4:
+			return __cmpxchg_u32(ptr, old, new);
+		case 8:
+			return __cmpxchg_u64(ptr, old, new);
+	}
+	return old;
+}
+#define cmpxchg(ptr,o,n)						 \
+  ({									 \
+     __typeof__(*(ptr)) _o_ = (o);					 \
+     __typeof__(*(ptr)) _n_ = (n);					 \
+     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,		 \
+				    (unsigned long)_n_, sizeof(*(ptr))); \
+  })
+
+#elif __i386__
+static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+				      unsigned long new, int size)
+{
+	unsigned long prev;
+	switch (size) {
+	case 1:
+		__asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
+				     : "=a"(prev)
+				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	case 2:
+		__asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
+				     : "=a"(prev)
+				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	case 4:
+		__asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
+				     : "=a"(prev)
+				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	}
+	return old;
+}
+
+#define cmpxchg(ptr,o,n)						\
+  ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),		\
+				 (unsigned long)(n),sizeof(*(ptr))))
+#endif /* i386 & alpha */
+#endif
+
+				/* Macros to make printk easier */
+#define DRM_ERROR(fmt, arg...) \
+	printk(KERN_ERR "[" DRM_NAME ":" __FUNCTION__ "] *ERROR* " fmt , ##arg)
+#define DRM_MEM_ERROR(area, fmt, arg...) \
+	printk(KERN_ERR "[" DRM_NAME ":" __FUNCTION__ ":%s] *ERROR* " fmt , \
+	       drm_mem_stats[area].name , ##arg)
+#define DRM_INFO(fmt, arg...)  printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg)
+
+#if DRM_DEBUG_CODE
+#define DRM_DEBUG(fmt, arg...)						  \
+	do {								  \
+		if (drm_flags&DRM_FLAG_DEBUG)				  \
+			printk(KERN_DEBUG				  \
+			       "[" DRM_NAME ":" __FUNCTION__ "] " fmt ,	  \
+			       ##arg);					  \
+	} while (0)
+#else
+#define DRM_DEBUG(fmt, arg...)		 do { } while (0)
+#endif
+
+#define DRM_PROC_LIMIT (PAGE_SIZE-80)
+
+#define DRM_PROC_PRINT(fmt, arg...)	   \
+   len += sprintf(&buf[len], fmt , ##arg); \
+   if (len > DRM_PROC_LIMIT) return len;
+
+#define DRM_PROC_PRINT_RET(ret, fmt, arg...)	    \
+   len += sprintf(&buf[len], fmt , ##arg);	    \
+   if (len > DRM_PROC_LIMIT) { ret; return len; }
+
+				/* Internal types and structures */
+#define DRM_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+#define DRM_MIN(a,b) ((a)<(b)?(a):(b))
+#define DRM_MAX(a,b) ((a)>(b)?(a):(b))
+
+#define DRM_LEFTCOUNT(x) (((x)->rp + (x)->count - (x)->wp) % ((x)->count + 1))
+#define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x))
+#define DRM_WAITCOUNT(dev,idx) DRM_BUFCOUNT(&dev->queuelist[idx]->waitlist)
+
+typedef int drm_ioctl_t(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+
+typedef struct drm_ioctl_desc {
+	drm_ioctl_t	     *func;
+	int		     auth_needed;
+	int		     root_only;
+} drm_ioctl_desc_t;
+
+typedef struct drm_devstate {
+	pid_t		  owner;	/* X server pid holding x_lock */
+	
+} drm_devstate_t;
+
+typedef struct drm_magic_entry {
+	drm_magic_t	       magic;
+	struct drm_file	       *priv;
+	struct drm_magic_entry *next;
+} drm_magic_entry_t;
+
+typedef struct drm_magic_head {
+	struct drm_magic_entry *head;
+	struct drm_magic_entry *tail;
+} drm_magic_head_t;
+
+typedef struct drm_vma_entry {
+	struct vm_area_struct *vma;
+	struct drm_vma_entry  *next;
+	pid_t		      pid;
+} drm_vma_entry_t;
+
+typedef struct drm_buf {
+	int		  idx;	       /* Index into master buflist	     */
+	int		  total;       /* Buffer size			     */
+	int		  order;       /* log-base-2(total)		     */
+	int		  used;	       /* Amount of buffer in use (for DMA)  */
+	unsigned long	  offset;      /* Byte offset (used internally)	     */
+	void		  *address;    /* Address of buffer		     */
+	unsigned long	  bus_address; /* Bus address of buffer		     */
+	struct drm_buf	  *next;       /* Kernel-only: used for free list    */
+	__volatile__ int  waiting;     /* On kernel DMA queue		     */
+	__volatile__ int  pending;     /* On hardware DMA queue		     */
+	wait_queue_head_t dma_wait;    /* Processes waiting		     */
+	pid_t		  pid;	       /* PID of holding process	     */
+	int		  context;     /* Kernel queue for this buffer	     */
+	int		  while_locked;/* Dispatch this buffer while locked  */
+	enum {
+		DRM_LIST_NONE	 = 0,
+		DRM_LIST_FREE	 = 1,
+		DRM_LIST_WAIT	 = 2,
+		DRM_LIST_PEND	 = 3,
+		DRM_LIST_PRIO	 = 4,
+		DRM_LIST_RECLAIM = 5
+	}		  list;	       /* Which list we're on		     */
+
+#if DRM_DMA_HISTOGRAM
+	cycles_t	  time_queued;	   /* Queued to kernel DMA queue     */
+	cycles_t	  time_dispatched; /* Dispatched to hardware	     */
+	cycles_t	  time_completed;  /* Completed by hardware	     */
+	cycles_t	  time_freed;	   /* Back on freelist		     */
+#endif
+
+	int		  dev_priv_size; /* Size of buffer private stoarge   */
+	void		  *dev_private;  /* Per-buffer private storage       */
+} drm_buf_t;
+
+#if DRM_DMA_HISTOGRAM
+#define DRM_DMA_HISTOGRAM_SLOTS		  9
+#define DRM_DMA_HISTOGRAM_INITIAL	 10
+#define DRM_DMA_HISTOGRAM_NEXT(current)	 ((current)*10)
+typedef struct drm_histogram {
+	atomic_t	  total;
+
+	atomic_t	  queued_to_dispatched[DRM_DMA_HISTOGRAM_SLOTS];
+	atomic_t	  dispatched_to_completed[DRM_DMA_HISTOGRAM_SLOTS];
+	atomic_t	  completed_to_freed[DRM_DMA_HISTOGRAM_SLOTS];
+
+	atomic_t	  queued_to_completed[DRM_DMA_HISTOGRAM_SLOTS];
+	atomic_t	  queued_to_freed[DRM_DMA_HISTOGRAM_SLOTS];
+
+	atomic_t	  dma[DRM_DMA_HISTOGRAM_SLOTS];
+	atomic_t	  schedule[DRM_DMA_HISTOGRAM_SLOTS];
+	atomic_t	  ctx[DRM_DMA_HISTOGRAM_SLOTS];
+	atomic_t	  lacq[DRM_DMA_HISTOGRAM_SLOTS];
+	atomic_t	  lhld[DRM_DMA_HISTOGRAM_SLOTS];
+} drm_histogram_t;
+#endif
+
+				/* bufs is one longer than it has to be */
+typedef struct drm_waitlist {
+	int		  count;	/* Number of possible buffers	   */
+	drm_buf_t	  **bufs;	/* List of pointers to buffers	   */
+	drm_buf_t	  **rp;		/* Read pointer			   */
+	drm_buf_t	  **wp;		/* Write pointer		   */
+	drm_buf_t	  **end;	/* End pointer			   */
+	spinlock_t	  read_lock;
+	spinlock_t	  write_lock;
+} drm_waitlist_t;
+
+typedef struct drm_freelist {
+	int		  initialized; /* Freelist in use		   */
+	atomic_t	  count;       /* Number of free buffers	   */
+	drm_buf_t	  *next;       /* End pointer			   */
+
+	wait_queue_head_t waiting;     /* Processes waiting on free bufs   */
+	int		  low_mark;    /* Low water mark		   */
+	int		  high_mark;   /* High water mark		   */
+	atomic_t	  wfh;	       /* If waiting for high mark	   */
+	spinlock_t        lock;
+} drm_freelist_t;
+
+typedef struct drm_buf_entry {
+	int		  buf_size;
+	int		  buf_count;
+	drm_buf_t	  *buflist;
+	int		  seg_count;
+	int		  page_order;
+	unsigned long	  *seglist;
+
+	drm_freelist_t	  freelist;
+} drm_buf_entry_t;
+
+typedef struct drm_hw_lock {
+	__volatile__ unsigned int lock;
+	char			  padding[60]; /* Pad to cache line */
+} drm_hw_lock_t;
+
+typedef struct drm_file {
+	int		  authenticated;
+	int		  minor;
+	pid_t		  pid;
+	uid_t		  uid;
+	drm_magic_t	  magic;
+	unsigned long	  ioctl_count;
+	struct drm_file	  *next;
+	struct drm_file	  *prev;
+	struct drm_device *dev;
+	int 		  remove_auth_on_close;
+} drm_file_t;
+
+
+typedef struct drm_queue {
+	atomic_t	  use_count;	/* Outstanding uses (+1)	    */
+	atomic_t	  finalization;	/* Finalization in progress	    */
+	atomic_t	  block_count;	/* Count of processes waiting	    */
+	atomic_t	  block_read;	/* Queue blocked for reads	    */
+	wait_queue_head_t read_queue;	/* Processes waiting on block_read  */
+	atomic_t	  block_write;	/* Queue blocked for writes	    */
+	wait_queue_head_t write_queue;	/* Processes waiting on block_write */
+	atomic_t	  total_queued;	/* Total queued statistic	    */
+	atomic_t	  total_flushed;/* Total flushes statistic	    */
+	atomic_t	  total_locks;	/* Total locks statistics	    */
+	drm_ctx_flags_t	  flags;	/* Context preserving and 2D-only   */
+	drm_waitlist_t	  waitlist;	/* Pending buffers		    */
+	wait_queue_head_t flush_queue;	/* Processes waiting until flush    */
+} drm_queue_t;
+
+typedef struct drm_lock_data {
+	drm_hw_lock_t	  *hw_lock;	/* Hardware lock		   */
+	pid_t		  pid;		/* PID of lock holder (0=kernel)   */
+	wait_queue_head_t lock_queue;	/* Queue of blocked processes	   */
+	unsigned long	  lock_time;	/* Time of last lock in jiffies	   */
+} drm_lock_data_t;
+
+typedef struct drm_device_dma {
+				/* Performance Counters */
+	atomic_t	  total_prio;	/* Total DRM_DMA_PRIORITY	   */
+	atomic_t	  total_bytes;	/* Total bytes DMA'd		   */
+	atomic_t	  total_dmas;	/* Total DMA buffers dispatched	   */
+
+	atomic_t	  total_missed_dma;  /* Missed drm_do_dma	    */
+	atomic_t	  total_missed_lock; /* Missed lock in drm_do_dma   */
+	atomic_t	  total_missed_free; /* Missed drm_free_this_buffer */
+	atomic_t	  total_missed_sched;/* Missed drm_dma_schedule	    */
+
+	atomic_t	  total_tried;	/* Tried next_buffer		    */
+	atomic_t	  total_hit;	/* Sent next_buffer		    */
+	atomic_t	  total_lost;	/* Lost interrupt		    */
+
+	drm_buf_entry_t	  bufs[DRM_MAX_ORDER+1];
+	int		  buf_count;
+	drm_buf_t	  **buflist;	/* Vector of pointers info bufs	   */
+	int		  seg_count;
+	int		  page_count;
+	unsigned long	  *pagelist;
+	unsigned long	  byte_count;
+	enum {
+	   _DRM_DMA_USE_AGP = 0x01
+	} flags;
+
+				/* DMA support */
+	drm_buf_t	  *this_buffer;	/* Buffer being sent		   */
+	drm_buf_t	  *next_buffer; /* Selected buffer to send	   */
+	drm_queue_t	  *next_queue;	/* Queue from which buffer selected*/
+	wait_queue_head_t waiting;	/* Processes waiting on free bufs  */
+} drm_device_dma_t;
+
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+typedef struct drm_agp_mem {
+	unsigned long      handle;
+	agp_memory         *memory;
+	unsigned long      bound; /* address */
+	int                pages;
+	struct drm_agp_mem *prev;
+	struct drm_agp_mem *next;
+} drm_agp_mem_t;
+
+typedef struct drm_agp_head {
+	agp_kern_info      agp_info;
+	const char         *chipset;
+	drm_agp_mem_t      *memory;
+	unsigned long      mode;
+	int                enabled;
+	int                acquired;
+	unsigned long      base;
+   	int 		   agp_mtrr;
+	int		   cant_use_aperture;
+	unsigned long	   page_mask;
+} drm_agp_head_t;
+#endif
+
+typedef struct drm_sigdata {
+	int           context;
+	drm_hw_lock_t *lock;
+} drm_sigdata_t;
+
+typedef struct drm_device {
+	const char	  *name;	/* Simple driver name		   */
+	char		  *unique;	/* Unique identifier: e.g., busid  */
+	int		  unique_len;	/* Length of unique field	   */
+	dev_t		  device;	/* Device number for mknod	   */
+	char		  *devname;	/* For /proc/interrupts		   */
+
+	int		  blocked;	/* Blocked due to VC switch?	   */
+	struct proc_dir_entry *root;	/* Root for this device's entries  */
+
+				/* Locks */
+	spinlock_t	  count_lock;	/* For inuse, open_count, buf_use  */
+	struct semaphore  struct_sem;	/* For others			   */
+
+				/* Usage Counters */
+	int		  open_count;	/* Outstanding files open	   */
+	atomic_t	  ioctl_count;	/* Outstanding IOCTLs pending	   */
+	atomic_t	  vma_count;	/* Outstanding vma areas open	   */
+	int		  buf_use;	/* Buffers in use -- cannot alloc  */
+	atomic_t	  buf_alloc;	/* Buffer allocation in progress   */
+
+				/* Performance Counters */
+	atomic_t	  total_open;
+	atomic_t	  total_close;
+	atomic_t	  total_ioctl;
+	atomic_t	  total_irq;	/* Total interruptions		   */
+	atomic_t	  total_ctx;	/* Total context switches	   */
+
+	atomic_t	  total_locks;
+	atomic_t	  total_unlocks;
+	atomic_t	  total_contends;
+	atomic_t	  total_sleeps;
+
+				/* Authentication */
+	drm_file_t	  *file_first;
+	drm_file_t	  *file_last;
+	drm_magic_head_t  magiclist[DRM_HASH_SIZE];
+
+				/* Memory management */
+	drm_map_t	  **maplist;	/* Vector of pointers to regions   */
+	int		  map_count;	/* Number of mappable regions	   */
+
+	drm_vma_entry_t	  *vmalist;	/* List of vmas (for debugging)	   */
+	drm_lock_data_t	  lock;		/* Information on hardware lock	   */
+
+				/* DMA queues (contexts) */
+	int		  queue_count;	/* Number of active DMA queues	   */
+	int		  queue_reserved; /* Number of reserved DMA queues */
+	int		  queue_slots;	/* Actual length of queuelist	   */
+	drm_queue_t	  **queuelist;	/* Vector of pointers to DMA queues */
+	drm_device_dma_t  *dma;		/* Optional pointer for DMA support */
+
+				/* Context support */
+	int		  irq;		/* Interrupt used by board	   */
+	__volatile__ long context_flag;	/* Context swapping flag	   */
+	__volatile__ long interrupt_flag; /* Interruption handler flag	   */
+	__volatile__ long dma_flag;	/* DMA dispatch flag		   */
+	struct timer_list timer;	/* Timer for delaying ctx switch   */
+	wait_queue_head_t context_wait; /* Processes waiting on ctx switch */
+	int		  last_checked;	/* Last context checked for DMA	   */
+	int		  last_context;	/* Last current context		   */
+	unsigned long	  last_switch;	/* jiffies at last context switch  */
+	struct tq_struct  tq;
+	cycles_t	  ctx_start;
+	cycles_t	  lck_start;
+#if DRM_DMA_HISTOGRAM
+	drm_histogram_t	  histo;
+#endif
+
+				/* Callback to X server for context switch
+				   and for heavy-handed reset. */
+	char		  buf[DRM_BSZ]; /* Output buffer		   */
+	char		  *buf_rp;	/* Read pointer			   */
+	char		  *buf_wp;	/* Write pointer		   */
+	char		  *buf_end;	/* End pointer			   */
+	struct fasync_struct *buf_async;/* Processes waiting for SIGIO	   */
+	wait_queue_head_t buf_readers;	/* Processes waiting to read	   */
+	wait_queue_head_t buf_writers;	/* Processes waiting to ctx switch */
+
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+	drm_agp_head_t    *agp;
+#endif
+	unsigned long     *ctx_bitmap;
+	void		  *dev_private;
+	drm_sigdata_t     sigdata; /* For block_all_signals */
+	sigset_t          sigmask;
+} drm_device_t;
+
+				/* Internal function definitions */
+
+				/* Misc. support (init.c) */
+extern int	     drm_flags;
+extern void	     drm_parse_options(char *s);
+extern int           drm_cpu_valid(void);
+
+
+				/* Device support (fops.c) */
+extern int	     drm_open_helper(struct inode *inode, struct file *filp,
+				     drm_device_t *dev);
+extern int	     drm_flush(struct file *filp);
+extern int	     drm_release(struct inode *inode, struct file *filp);
+extern int	     drm_fasync(int fd, struct file *filp, int on);
+extern ssize_t	     drm_read(struct file *filp, char *buf, size_t count,
+			      loff_t *off);
+extern int	     drm_write_string(drm_device_t *dev, const char *s);
+extern unsigned int  drm_poll(struct file *filp, struct poll_table_struct *wait);
+
+				/* Mapping support (vm.c) */
+#if LINUX_VERSION_CODE < 0x020317
+extern unsigned long drm_vm_nopage(struct vm_area_struct *vma,
+				   unsigned long address,
+				   int write_access);
+extern unsigned long drm_vm_shm_nopage(struct vm_area_struct *vma,
+				       unsigned long address,
+				       int write_access);
+extern unsigned long drm_vm_shm_nopage_lock(struct vm_area_struct *vma,
+					    unsigned long address,
+					    int write_access);
+extern unsigned long drm_vm_dma_nopage(struct vm_area_struct *vma,
+				       unsigned long address,
+				       int write_access);
+#else
+				/* Return type changed in 2.3.23 */
+extern struct page *drm_vm_nopage(struct vm_area_struct *vma,
+				  unsigned long address,
+				  int write_access);
+extern struct page *drm_vm_shm_nopage(struct vm_area_struct *vma,
+				      unsigned long address,
+				      int write_access);
+extern struct page *drm_vm_shm_nopage_lock(struct vm_area_struct *vma,
+					   unsigned long address,
+					   int write_access);
+extern struct page *drm_vm_dma_nopage(struct vm_area_struct *vma,
+				      unsigned long address,
+				      int write_access);
+#endif
+extern void	     drm_vm_open(struct vm_area_struct *vma);
+extern void	     drm_vm_close(struct vm_area_struct *vma);
+extern int	     drm_mmap_dma(struct file *filp,
+				  struct vm_area_struct *vma);
+extern int	     drm_mmap(struct file *filp, struct vm_area_struct *vma);
+
+
+				/* Proc support (proc.c) */
+extern int	     drm_proc_init(drm_device_t *dev);
+extern int	     drm_proc_cleanup(void);
+
+				/* Memory management support (memory.c) */
+extern void	     drm_mem_init(void);
+extern int	     drm_mem_info(char *buf, char **start, off_t offset,
+				  int len, int *eof, void *data);
+extern void	     *drm_alloc(size_t size, int area);
+extern void	     *drm_realloc(void *oldpt, size_t oldsize, size_t size,
+				  int area);
+extern char	     *drm_strdup(const char *s, int area);
+extern void	     drm_strfree(const char *s, int area);
+extern void	     drm_free(void *pt, size_t size, int area);
+extern unsigned long drm_alloc_pages(int order, int area);
+extern void	     drm_free_pages(unsigned long address, int order,
+				    int area);
+extern void	     *drm_ioremap(unsigned long offset, unsigned long size,
+							drm_device_t *dev);
+extern void	     drm_ioremapfree(void *pt, unsigned long size,
+							drm_device_t *dev);
+
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+extern agp_memory    *drm_alloc_agp(int pages, u32 type);
+extern int           drm_free_agp(agp_memory *handle, int pages);
+extern int           drm_bind_agp(agp_memory *handle, unsigned int start);
+extern int           drm_unbind_agp(agp_memory *handle);
+#endif
+
+
+				/* Buffer management support (bufs.c) */
+extern int	     drm_order(unsigned long size);
+extern int	     drm_addmap(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+extern int	     drm_addbufs(struct inode *inode, struct file *filp,
+				 unsigned int cmd, unsigned long arg);
+extern int	     drm_infobufs(struct inode *inode, struct file *filp,
+				  unsigned int cmd, unsigned long arg);
+extern int	     drm_markbufs(struct inode *inode, struct file *filp,
+				  unsigned int cmd, unsigned long arg);
+extern int	     drm_freebufs(struct inode *inode, struct file *filp,
+				  unsigned int cmd, unsigned long arg);
+extern int	     drm_mapbufs(struct inode *inode, struct file *filp,
+				 unsigned int cmd, unsigned long arg);
+
+
+				/* Buffer list management support (lists.c) */
+extern int	     drm_waitlist_create(drm_waitlist_t *bl, int count);
+extern int	     drm_waitlist_destroy(drm_waitlist_t *bl);
+extern int	     drm_waitlist_put(drm_waitlist_t *bl, drm_buf_t *buf);
+extern drm_buf_t     *drm_waitlist_get(drm_waitlist_t *bl);
+
+extern int	     drm_freelist_create(drm_freelist_t *bl, int count);
+extern int	     drm_freelist_destroy(drm_freelist_t *bl);
+extern int	     drm_freelist_put(drm_device_t *dev, drm_freelist_t *bl,
+				      drm_buf_t *buf);
+extern drm_buf_t     *drm_freelist_get(drm_freelist_t *bl, int block);
+
+				/* DMA support (gen_dma.c) */
+extern void	     drm_dma_setup(drm_device_t *dev);
+extern void	     drm_dma_takedown(drm_device_t *dev);
+extern void	     drm_free_buffer(drm_device_t *dev, drm_buf_t *buf);
+extern void	     drm_reclaim_buffers(drm_device_t *dev, pid_t pid);
+extern int	     drm_context_switch(drm_device_t *dev, int old, int new);
+extern int	     drm_context_switch_complete(drm_device_t *dev, int new);
+extern void	     drm_clear_next_buffer(drm_device_t *dev);
+extern int	     drm_select_queue(drm_device_t *dev,
+				      void (*wrapper)(unsigned long));
+extern int	     drm_dma_enqueue(drm_device_t *dev, drm_dma_t *dma);
+extern int	     drm_dma_get_buffers(drm_device_t *dev, drm_dma_t *dma);
+#if DRM_DMA_HISTOGRAM
+extern int	     drm_histogram_slot(unsigned long count);
+extern void	     drm_histogram_compute(drm_device_t *dev, drm_buf_t *buf);
+#endif
+
+
+				/* Misc. IOCTL support (ioctl.c) */
+extern int	     drm_irq_busid(struct inode *inode, struct file *filp,
+				   unsigned int cmd, unsigned long arg);
+extern int	     drm_getunique(struct inode *inode, struct file *filp,
+				   unsigned int cmd, unsigned long arg);
+extern int	     drm_setunique(struct inode *inode, struct file *filp,
+				   unsigned int cmd, unsigned long arg);
+
+
+				/* Context IOCTL support (context.c) */
+extern int	     drm_resctx(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+extern int	     drm_addctx(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+extern int	     drm_modctx(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+extern int	     drm_getctx(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+extern int	     drm_switchctx(struct inode *inode, struct file *filp,
+				   unsigned int cmd, unsigned long arg);
+extern int	     drm_newctx(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+extern int	     drm_rmctx(struct inode *inode, struct file *filp,
+			       unsigned int cmd, unsigned long arg);
+
+
+				/* Drawable IOCTL support (drawable.c) */
+extern int	     drm_adddraw(struct inode *inode, struct file *filp,
+				 unsigned int cmd, unsigned long arg);
+extern int	     drm_rmdraw(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+
+
+				/* Authentication IOCTL support (auth.c) */
+extern int	     drm_add_magic(drm_device_t *dev, drm_file_t *priv,
+				   drm_magic_t magic);
+extern int	     drm_remove_magic(drm_device_t *dev, drm_magic_t magic);
+extern int	     drm_getmagic(struct inode *inode, struct file *filp,
+				  unsigned int cmd, unsigned long arg);
+extern int	     drm_authmagic(struct inode *inode, struct file *filp,
+				   unsigned int cmd, unsigned long arg);
+
+
+				/* Locking IOCTL support (lock.c) */
+extern int	     drm_block(struct inode *inode, struct file *filp,
+			       unsigned int cmd, unsigned long arg);
+extern int	     drm_unblock(struct inode *inode, struct file *filp,
+				 unsigned int cmd, unsigned long arg);
+extern int	     drm_lock_take(__volatile__ unsigned int *lock,
+				   unsigned int context);
+extern int	     drm_lock_transfer(drm_device_t *dev,
+				       __volatile__ unsigned int *lock,
+				       unsigned int context);
+extern int	     drm_lock_free(drm_device_t *dev,
+				   __volatile__ unsigned int *lock,
+				   unsigned int context);
+extern int	     drm_finish(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+extern int	     drm_flush_unblock(drm_device_t *dev, int context,
+				       drm_lock_flags_t flags);
+extern int	     drm_flush_block_and_flush(drm_device_t *dev, int context,
+					       drm_lock_flags_t flags);
+extern int           drm_notifier(void *priv);
+
+				/* Context Bitmap support (ctxbitmap.c) */
+extern int	     drm_ctxbitmap_init(drm_device_t *dev);
+extern void	     drm_ctxbitmap_cleanup(drm_device_t *dev);
+extern int	     drm_ctxbitmap_next(drm_device_t *dev);
+extern void	     drm_ctxbitmap_free(drm_device_t *dev, int ctx_handle);
+
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+				/* AGP/GART support (agpsupport.c) */
+extern drm_agp_head_t *drm_agp_init(void);
+extern void           drm_agp_uninit(void);
+extern int            drm_agp_acquire(struct inode *inode, struct file *filp,
+				      unsigned int cmd, unsigned long arg);
+extern void           _drm_agp_release(void);
+extern int            drm_agp_release(struct inode *inode, struct file *filp,
+				      unsigned int cmd, unsigned long arg);
+extern int            drm_agp_enable(struct inode *inode, struct file *filp,
+				     unsigned int cmd, unsigned long arg);
+extern int            drm_agp_info(struct inode *inode, struct file *filp,
+				   unsigned int cmd, unsigned long arg);
+extern int            drm_agp_alloc(struct inode *inode, struct file *filp,
+				    unsigned int cmd, unsigned long arg);
+extern int            drm_agp_free(struct inode *inode, struct file *filp,
+				   unsigned int cmd, unsigned long arg);
+extern int            drm_agp_unbind(struct inode *inode, struct file *filp,
+				     unsigned int cmd, unsigned long arg);
+extern int            drm_agp_bind(struct inode *inode, struct file *filp,
+				   unsigned int cmd, unsigned long arg);
+extern agp_memory     *drm_agp_allocate_memory(size_t pages, u32 type);
+extern int            drm_agp_free_memory(agp_memory *handle);
+extern int            drm_agp_bind_memory(agp_memory *handle, off_t start);
+extern int            drm_agp_unbind_memory(agp_memory *handle);
+#endif
+#endif
+#endif
diff -urN linux-2.4.13/drivers/char/drm-4.0/ffb_context.c linux-2.4.13-lia/drivers/char/drm-4.0/ffb_context.c
--- linux-2.4.13/drivers/char/drm-4.0/ffb_context.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/ffb_context.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,540 @@
+/* $Id: ffb_context.c,v 1.4 2000/08/29 07:01:55 davem Exp $
+ * ffb_context.c: Creator/Creator3D DRI/DRM context switching.
+ *
+ * Copyright (C) 2000 David S. Miller (davem@redhat.com)
+ *
+ * Almost entirely stolen from tdfx_context.c, see there
+ * for authors.
+ */
+
+#include <linux/sched.h>
+#include <asm/upa.h>
+
+#include "drmP.h"
+
+#include "ffb_drv.h"
+
+static int ffb_alloc_queue(drm_device_t *dev, int is_2d_only)
+{
+	ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1);
+	int i;
+
+	for (i = 0; i < FFB_MAX_CTXS; i++) {
+		if (fpriv->hw_state[i] = NULL)
+			break;
+	}
+	if (i = FFB_MAX_CTXS)
+		return -1;
+
+	fpriv->hw_state[i] = kmalloc(sizeof(struct ffb_hw_context), GFP_KERNEL);
+	if (fpriv->hw_state[i] = NULL)
+		return -1;
+
+	fpriv->hw_state[i]->is_2d_only = is_2d_only;
+
+	/* Plus one because 0 is the special DRM_KERNEL_CONTEXT. */
+	return i + 1;
+}
+
+static void ffb_save_context(ffb_dev_priv_t *fpriv, int idx)
+{
+	ffb_fbcPtr ffb = fpriv->regs;
+	struct ffb_hw_context *ctx;
+	int i;
+
+	ctx = fpriv->hw_state[idx - 1];
+	if (idx = 0 || ctx = NULL)
+		return;
+
+	if (ctx->is_2d_only) {
+		/* 2D applications only care about certain pieces
+		 * of state.
+		 */
+		ctx->drawop = upa_readl(&ffb->drawop);
+		ctx->ppc = upa_readl(&ffb->ppc);
+		ctx->wid = upa_readl(&ffb->wid);
+		ctx->fg = upa_readl(&ffb->fg);
+		ctx->bg = upa_readl(&ffb->bg);
+		ctx->xclip = upa_readl(&ffb->xclip);
+		ctx->fbc = upa_readl(&ffb->fbc);
+		ctx->rop = upa_readl(&ffb->rop);
+		ctx->cmp = upa_readl(&ffb->cmp);
+		ctx->matchab = upa_readl(&ffb->matchab);
+		ctx->magnab = upa_readl(&ffb->magnab);
+		ctx->pmask = upa_readl(&ffb->pmask);
+		ctx->xpmask = upa_readl(&ffb->xpmask);
+		ctx->lpat = upa_readl(&ffb->lpat);
+		ctx->fontxy = upa_readl(&ffb->fontxy);
+		ctx->fontw = upa_readl(&ffb->fontw);
+		ctx->fontinc = upa_readl(&ffb->fontinc);
+
+		/* stencil/stencilctl only exists on FFB2+ and later
+		 * due to the introduction of 3DRAM-III.
+		 */
+		if (fpriv->ffb_type = ffb2_vertical_plus ||
+		    fpriv->ffb_type = ffb2_horizontal_plus) {
+			ctx->stencil = upa_readl(&ffb->stencil);
+			ctx->stencilctl = upa_readl(&ffb->stencilctl);
+		}
+
+		for (i = 0; i < 32; i++)
+			ctx->area_pattern[i] = upa_readl(&ffb->pattern[i]);
+		ctx->ucsr = upa_readl(&ffb->ucsr);
+		return;
+	}
+
+	/* Fetch drawop. */
+	ctx->drawop = upa_readl(&ffb->drawop);
+
+	/* If we were saving the vertex registers, this is where
+	 * we would do it.  We would save 32 32-bit words starting
+	 * at ffb->suvtx.
+	 */
+
+	/* Capture rendering attributes. */
+
+	ctx->ppc = upa_readl(&ffb->ppc);		/* Pixel Processor Control */
+	ctx->wid = upa_readl(&ffb->wid);		/* Current WID */
+	ctx->fg = upa_readl(&ffb->fg);			/* Constant FG color */
+	ctx->bg = upa_readl(&ffb->bg);			/* Constant BG color */
+	ctx->consty = upa_readl(&ffb->consty);		/* Constant Y */
+	ctx->constz = upa_readl(&ffb->constz);		/* Constant Z */
+	ctx->xclip = upa_readl(&ffb->xclip);		/* X plane clip */
+	ctx->dcss = upa_readl(&ffb->dcss);		/* Depth Cue Scale Slope */
+	ctx->vclipmin = upa_readl(&ffb->vclipmin);	/* Primary XY clip, minimum */
+	ctx->vclipmax = upa_readl(&ffb->vclipmax);	/* Primary XY clip, maximum */
+	ctx->vclipzmin = upa_readl(&ffb->vclipzmin);	/* Primary Z clip, minimum */
+	ctx->vclipzmax = upa_readl(&ffb->vclipzmax);	/* Primary Z clip, maximum */
+	ctx->dcsf = upa_readl(&ffb->dcsf);		/* Depth Cue Scale Front Bound */
+	ctx->dcsb = upa_readl(&ffb->dcsb);		/* Depth Cue Scale Back Bound */
+	ctx->dczf = upa_readl(&ffb->dczf);		/* Depth Cue Scale Z Front */
+	ctx->dczb = upa_readl(&ffb->dczb);		/* Depth Cue Scale Z Back */
+	ctx->blendc = upa_readl(&ffb->blendc);		/* Alpha Blend Control */
+	ctx->blendc1 = upa_readl(&ffb->blendc1);	/* Alpha Blend Color 1 */
+	ctx->blendc2 = upa_readl(&ffb->blendc2);	/* Alpha Blend Color 2 */
+	ctx->fbc = upa_readl(&ffb->fbc);		/* Frame Buffer Control */
+	ctx->rop = upa_readl(&ffb->rop);		/* Raster Operation */
+	ctx->cmp = upa_readl(&ffb->cmp);		/* Compare Controls */
+	ctx->matchab = upa_readl(&ffb->matchab);	/* Buffer A/B Match Ops */
+	ctx->matchc = upa_readl(&ffb->matchc);		/* Buffer C Match Ops */
+	ctx->magnab = upa_readl(&ffb->magnab);		/* Buffer A/B Magnitude Ops */
+	ctx->magnc = upa_readl(&ffb->magnc);		/* Buffer C Magnitude Ops */
+	ctx->pmask = upa_readl(&ffb->pmask);		/* RGB Plane Mask */
+	ctx->xpmask = upa_readl(&ffb->xpmask);		/* X Plane Mask */
+	ctx->ypmask = upa_readl(&ffb->ypmask);		/* Y Plane Mask */
+	ctx->zpmask = upa_readl(&ffb->zpmask);		/* Z Plane Mask */
+
+	/* Auxiliary Clips. */
+	ctx->auxclip0min = upa_readl(&ffb->auxclip[0].min);
+	ctx->auxclip0max = upa_readl(&ffb->auxclip[0].max);
+	ctx->auxclip1min = upa_readl(&ffb->auxclip[1].min);
+	ctx->auxclip1max = upa_readl(&ffb->auxclip[1].max);
+	ctx->auxclip2min = upa_readl(&ffb->auxclip[2].min);
+	ctx->auxclip2max = upa_readl(&ffb->auxclip[2].max);
+	ctx->auxclip3min = upa_readl(&ffb->auxclip[3].min);
+	ctx->auxclip3max = upa_readl(&ffb->auxclip[3].max);
+
+	ctx->lpat = upa_readl(&ffb->lpat);		/* Line Pattern */
+	ctx->fontxy = upa_readl(&ffb->fontxy);		/* XY Font Coordinate */
+	ctx->fontw = upa_readl(&ffb->fontw);		/* Font Width */
+	ctx->fontinc = upa_readl(&ffb->fontinc);	/* Font X/Y Increment */
+
+	/* These registers/features only exist on FFB2 and later chips. */
+	if (fpriv->ffb_type >= ffb2_prototype) {
+		ctx->dcss1 = upa_readl(&ffb->dcss1);	/* Depth Cue Scale Slope 1 */
+		ctx->dcss2 = upa_readl(&ffb->dcss2);	/* Depth Cue Scale Slope 2 */
+		ctx->dcss2 = upa_readl(&ffb->dcss3);	/* Depth Cue Scale Slope 3 */
+		ctx->dcs2  = upa_readl(&ffb->dcs2);	/* Depth Cue Scale 2 */
+		ctx->dcs3  = upa_readl(&ffb->dcs3);	/* Depth Cue Scale 3 */
+		ctx->dcs4  = upa_readl(&ffb->dcs4);	/* Depth Cue Scale 4 */
+		ctx->dcd2  = upa_readl(&ffb->dcd2);	/* Depth Cue Depth 2 */
+		ctx->dcd3  = upa_readl(&ffb->dcd3);	/* Depth Cue Depth 3 */
+		ctx->dcd4  = upa_readl(&ffb->dcd4);	/* Depth Cue Depth 4 */
+
+		/* And stencil/stencilctl only exists on FFB2+ and later
+		 * due to the introduction of 3DRAM-III.
+		 */
+		if (fpriv->ffb_type = ffb2_vertical_plus ||
+		    fpriv->ffb_type = ffb2_horizontal_plus) {
+			ctx->stencil = upa_readl(&ffb->stencil);
+			ctx->stencilctl = upa_readl(&ffb->stencilctl);
+		}
+	}
+
+	/* Save the 32x32 area pattern. */
+	for (i = 0; i < 32; i++)
+		ctx->area_pattern[i] = upa_readl(&ffb->pattern[i]);
+
+	/* Finally, stash away the User Constol/Status Register. */
+	ctx->ucsr = upa_readl(&ffb->ucsr);
+}
+
+static void ffb_restore_context(ffb_dev_priv_t *fpriv, int old, int idx)
+{
+	ffb_fbcPtr ffb = fpriv->regs;
+	struct ffb_hw_context *ctx;
+	int i;
+
+	ctx = fpriv->hw_state[idx - 1];
+	if (idx = 0 || ctx = NULL)
+		return;
+
+	if (ctx->is_2d_only) {
+		/* 2D applications only care about certain pieces
+		 * of state.
+		 */
+		upa_writel(ctx->drawop, &ffb->drawop);
+
+		/* If we were restoring the vertex registers, this is where
+		 * we would do it.  We would restore 32 32-bit words starting
+		 * at ffb->suvtx.
+		 */
+
+		upa_writel(ctx->ppc, &ffb->ppc);
+		upa_writel(ctx->wid, &ffb->wid);
+		upa_writel(ctx->fg,  &ffb->fg);
+		upa_writel(ctx->bg, &ffb->bg);
+		upa_writel(ctx->xclip, &ffb->xclip);
+		upa_writel(ctx->fbc, &ffb->fbc);
+		upa_writel(ctx->rop, &ffb->rop);
+		upa_writel(ctx->cmp, &ffb->cmp);
+		upa_writel(ctx->matchab, &ffb->matchab);
+		upa_writel(ctx->magnab, &ffb->magnab);
+		upa_writel(ctx->pmask, &ffb->pmask);
+		upa_writel(ctx->xpmask, &ffb->xpmask);
+		upa_writel(ctx->lpat, &ffb->lpat);
+		upa_writel(ctx->fontxy, &ffb->fontxy);
+		upa_writel(ctx->fontw, &ffb->fontw);
+		upa_writel(ctx->fontinc, &ffb->fontinc);
+
+		/* stencil/stencilctl only exists on FFB2+ and later
+		 * due to the introduction of 3DRAM-III.
+		 */
+		if (fpriv->ffb_type = ffb2_vertical_plus ||
+		    fpriv->ffb_type = ffb2_horizontal_plus) {
+			upa_writel(ctx->stencil, &ffb->stencil);
+			upa_writel(ctx->stencilctl, &ffb->stencilctl);
+			upa_writel(0x80000000, &ffb->fbc);
+			upa_writel((ctx->stencilctl | 0x80000),
+				   &ffb->rawstencilctl);
+			upa_writel(ctx->fbc, &ffb->fbc);
+		}
+
+		for (i = 0; i < 32; i++)
+			upa_writel(ctx->area_pattern[i], &ffb->pattern[i]);
+		upa_writel((ctx->ucsr & 0xf0000), &ffb->ucsr);
+		return;
+	}
+
+	/* Restore drawop. */
+	upa_writel(ctx->drawop, &ffb->drawop);
+
+	/* If we were restoring the vertex registers, this is where
+	 * we would do it.  We would restore 32 32-bit words starting
+	 * at ffb->suvtx.
+	 */
+
+	/* Restore rendering attributes. */
+
+	upa_writel(ctx->ppc, &ffb->ppc);		/* Pixel Processor Control */
+	upa_writel(ctx->wid, &ffb->wid);		/* Current WID */
+	upa_writel(ctx->fg, &ffb->fg);			/* Constant FG color */
+	upa_writel(ctx->bg, &ffb->bg);			/* Constant BG color */
+	upa_writel(ctx->consty, &ffb->consty);		/* Constant Y */
+	upa_writel(ctx->constz, &ffb->constz);		/* Constant Z */
+	upa_writel(ctx->xclip, &ffb->xclip);		/* X plane clip */
+	upa_writel(ctx->dcss, &ffb->dcss);		/* Depth Cue Scale Slope */
+	upa_writel(ctx->vclipmin, &ffb->vclipmin);	/* Primary XY clip, minimum */
+	upa_writel(ctx->vclipmax, &ffb->vclipmax);	/* Primary XY clip, maximum */
+	upa_writel(ctx->vclipzmin, &ffb->vclipzmin);	/* Primary Z clip, minimum */
+	upa_writel(ctx->vclipzmax, &ffb->vclipzmax);	/* Primary Z clip, maximum */
+	upa_writel(ctx->dcsf, &ffb->dcsf);		/* Depth Cue Scale Front Bound */
+	upa_writel(ctx->dcsb, &ffb->dcsb);		/* Depth Cue Scale Back Bound */
+	upa_writel(ctx->dczf, &ffb->dczf);		/* Depth Cue Scale Z Front */
+	upa_writel(ctx->dczb, &ffb->dczb);		/* Depth Cue Scale Z Back */
+	upa_writel(ctx->blendc, &ffb->blendc);		/* Alpha Blend Control */
+	upa_writel(ctx->blendc1, &ffb->blendc1);	/* Alpha Blend Color 1 */
+	upa_writel(ctx->blendc2, &ffb->blendc2);	/* Alpha Blend Color 2 */
+	upa_writel(ctx->fbc, &ffb->fbc);		/* Frame Buffer Control */
+	upa_writel(ctx->rop, &ffb->rop);		/* Raster Operation */
+	upa_writel(ctx->cmp, &ffb->cmp);		/* Compare Controls */
+	upa_writel(ctx->matchab, &ffb->matchab);	/* Buffer A/B Match Ops */
+	upa_writel(ctx->matchc, &ffb->matchc);		/* Buffer C Match Ops */
+	upa_writel(ctx->magnab, &ffb->magnab);		/* Buffer A/B Magnitude Ops */
+	upa_writel(ctx->magnc, &ffb->magnc);		/* Buffer C Magnitude Ops */
+	upa_writel(ctx->pmask, &ffb->pmask);		/* RGB Plane Mask */
+	upa_writel(ctx->xpmask, &ffb->xpmask);		/* X Plane Mask */
+	upa_writel(ctx->ypmask, &ffb->ypmask);		/* Y Plane Mask */
+	upa_writel(ctx->zpmask, &ffb->zpmask);		/* Z Plane Mask */
+
+	/* Auxiliary Clips. */
+	upa_writel(ctx->auxclip0min, &ffb->auxclip[0].min);
+	upa_writel(ctx->auxclip0max, &ffb->auxclip[0].max);
+	upa_writel(ctx->auxclip1min, &ffb->auxclip[1].min);
+	upa_writel(ctx->auxclip1max, &ffb->auxclip[1].max);
+	upa_writel(ctx->auxclip2min, &ffb->auxclip[2].min);
+	upa_writel(ctx->auxclip2max, &ffb->auxclip[2].max);
+	upa_writel(ctx->auxclip3min, &ffb->auxclip[3].min);
+	upa_writel(ctx->auxclip3max, &ffb->auxclip[3].max);
+
+	upa_writel(ctx->lpat, &ffb->lpat);		/* Line Pattern */
+	upa_writel(ctx->fontxy, &ffb->fontxy);		/* XY Font Coordinate */
+	upa_writel(ctx->fontw, &ffb->fontw);		/* Font Width */
+	upa_writel(ctx->fontinc, &ffb->fontinc);	/* Font X/Y Increment */
+
+	/* These registers/features only exist on FFB2 and later chips. */
+	if (fpriv->ffb_type >= ffb2_prototype) {
+		upa_writel(ctx->dcss1, &ffb->dcss1);	/* Depth Cue Scale Slope 1 */
+		upa_writel(ctx->dcss2, &ffb->dcss2);	/* Depth Cue Scale Slope 2 */
+		upa_writel(ctx->dcss3, &ffb->dcss2);	/* Depth Cue Scale Slope 3 */
+		upa_writel(ctx->dcs2, &ffb->dcs2);	/* Depth Cue Scale 2 */
+		upa_writel(ctx->dcs3, &ffb->dcs3);	/* Depth Cue Scale 3 */
+		upa_writel(ctx->dcs4, &ffb->dcs4);	/* Depth Cue Scale 4 */
+		upa_writel(ctx->dcd2, &ffb->dcd2);	/* Depth Cue Depth 2 */
+		upa_writel(ctx->dcd3, &ffb->dcd3);	/* Depth Cue Depth 3 */
+		upa_writel(ctx->dcd4, &ffb->dcd4);	/* Depth Cue Depth 4 */
+
+		/* And stencil/stencilctl only exists on FFB2+ and later
+		 * due to the introduction of 3DRAM-III.
+		 */
+		if (fpriv->ffb_type = ffb2_vertical_plus ||
+		    fpriv->ffb_type = ffb2_horizontal_plus) {
+			/* Unfortunately, there is a hardware bug on
+			 * the FFB2+ chips which prevents a normal write
+			 * to the stencil control register from working
+			 * as it should.
+			 *
+			 * The state controlled by the FFB stencilctl register
+			 * really gets transferred to the per-buffer instances
+			 * of the stencilctl register in the 3DRAM chips.
+			 *
+			 * The bug is that FFB does not update buffer C correctly,
+			 * so we have to do it by hand for them.
+			 */
+
+			/* This will update buffers A and B. */
+			upa_writel(ctx->stencil, &ffb->stencil);
+			upa_writel(ctx->stencilctl, &ffb->stencilctl);
+
+			/* Force FFB to use buffer C 3dram regs. */
+			upa_writel(0x80000000, &ffb->fbc);
+			upa_writel((ctx->stencilctl | 0x80000),
+				   &ffb->rawstencilctl);
+
+			/* Now restore the correct FBC controls. */
+			upa_writel(ctx->fbc, &ffb->fbc);
+		}
+	}
+
+	/* Restore the 32x32 area pattern. */
+	for (i = 0; i < 32; i++)
+		upa_writel(ctx->area_pattern[i], &ffb->pattern[i]);
+
+	/* Finally, stash away the User Constol/Status Register.
+	 * The only state we really preserve here is the picking
+	 * control.
+	 */
+	upa_writel((ctx->ucsr & 0xf0000), &ffb->ucsr);
+}
+
+#define FFB_UCSR_FB_BUSY       0x01000000
+#define FFB_UCSR_RP_BUSY       0x02000000
+#define FFB_UCSR_ALL_BUSY      (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY)
+
+static void FFBWait(ffb_fbcPtr ffb)
+{
+	int limit = 100000;
+
+	do {
+		u32 regval = upa_readl(&ffb->ucsr);
+
+		if ((regval & FFB_UCSR_ALL_BUSY) = 0)
+			break;
+	} while (--limit);
+}
+
+int ffb_context_switch(drm_device_t *dev, int old, int new)
+{
+	ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1);
+
+        atomic_inc(&dev->total_ctx);
+
+#if DRM_DMA_HISTOGRAM
+        dev->ctx_start = get_cycles();
+#endif
+        
+        DRM_DEBUG("Context switch from %d to %d\n", old, new);
+
+        if (new = dev->last_context ||
+	    dev->last_context = 0) {
+		dev->last_context = new;
+                return 0;
+	}
+        
+	FFBWait(fpriv->regs);
+	ffb_save_context(fpriv, old);
+	ffb_restore_context(fpriv, old, new);
+	FFBWait(fpriv->regs);
+        
+	dev->last_context = new;
+
+        return 0;
+}
+
+int ffb_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_ctx_res_t	res;
+	drm_ctx_t	ctx;
+	int		i;
+
+	DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
+	if (copy_from_user(&res, (drm_ctx_res_t *)arg, sizeof(res)))
+		return -EFAULT;
+	if (res.count >= DRM_RESERVED_CONTEXTS) {
+		memset(&ctx, 0, sizeof(ctx));
+		for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+			ctx.handle = i;
+			if (copy_to_user(&res.contexts[i],
+					 &i,
+					 sizeof(i)))
+				return -EFAULT;
+		}
+	}
+	res.count = DRM_RESERVED_CONTEXTS;
+	if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res)))
+		return -EFAULT;
+	return 0;
+}
+
+
+int ffb_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+	int idx;
+
+	if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+		return -EFAULT;
+	idx = ffb_alloc_queue(dev, (ctx.flags & _DRM_CONTEXT_2DONLY));
+	if (idx < 0)
+		return -ENFILE;
+
+	DRM_DEBUG("%d\n", ctx.handle);
+	ctx.handle = idx;
+	if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx)))
+		return -EFAULT;
+	return 0;
+}
+
+int ffb_modctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	ffb_dev_priv_t	*fpriv	= (ffb_dev_priv_t *) (dev + 1);
+	struct ffb_hw_context *hwctx;
+	drm_ctx_t ctx;
+	int idx;
+
+	if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx)))
+		return -EFAULT;
+
+	idx = ctx.handle;
+	if (idx <= 0 || idx >= FFB_MAX_CTXS)
+		return -EINVAL;
+
+	hwctx = fpriv->hw_state[idx - 1];
+	if (hwctx = NULL)
+		return -EINVAL;
+
+	if ((ctx.flags & _DRM_CONTEXT_2DONLY) = 0)
+		hwctx->is_2d_only = 0;
+	else
+		hwctx->is_2d_only = 1;
+
+	return 0;
+}
+
+int ffb_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	ffb_dev_priv_t	*fpriv	= (ffb_dev_priv_t *) (dev + 1);
+	struct ffb_hw_context *hwctx;
+	drm_ctx_t ctx;
+	int idx;
+
+	if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx)))
+		return -EFAULT;
+
+	idx = ctx.handle;
+	if (idx <= 0 || idx >= FFB_MAX_CTXS)
+		return -EINVAL;
+
+	hwctx = fpriv->hw_state[idx - 1];
+	if (hwctx = NULL)
+		return -EINVAL;
+
+	if (hwctx->is_2d_only != 0)
+		ctx.flags = _DRM_CONTEXT_2DONLY;
+	else
+		ctx.flags = 0;
+
+	if (copy_to_user((drm_ctx_t*)arg, &ctx, sizeof(ctx)))
+		return -EFAULT;
+
+	return 0;
+}
+
+int ffb_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+		return -EFAULT;
+	DRM_DEBUG("%d\n", ctx.handle);
+	return ffb_context_switch(dev, dev->last_context, ctx.handle);
+}
+
+int ffb_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_ctx_t	ctx;
+
+	if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+		return -EFAULT;
+	DRM_DEBUG("%d\n", ctx.handle);
+
+	return 0;
+}
+
+int ffb_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_ctx_t	ctx;
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	ffb_dev_priv_t	*fpriv	= (ffb_dev_priv_t *) (dev + 1);
+	int idx;
+
+	if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+		return -EFAULT;
+	DRM_DEBUG("%d\n", ctx.handle);
+
+	idx = ctx.handle - 1;
+	if (idx < 0 || idx >= FFB_MAX_CTXS)
+		return -EINVAL;
+
+	if (fpriv->hw_state[idx] != NULL) {
+		kfree(fpriv->hw_state[idx]);
+		fpriv->hw_state[idx] = NULL;
+	}
+	return 0;
+}
diff -urN linux-2.4.13/drivers/char/drm-4.0/ffb_drv.c linux-2.4.13-lia/drivers/char/drm-4.0/ffb_drv.c
--- linux-2.4.13/drivers/char/drm-4.0/ffb_drv.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/ffb_drv.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,951 @@
+/* $Id: ffb_drv.c,v 1.14 2001/05/24 12:01:47 davem Exp $
+ * ffb_drv.c: Creator/Creator3D direct rendering driver.
+ *
+ * Copyright (C) 2000 David S. Miller (davem@redhat.com)
+ */
+
+#include "drmP.h"
+
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <asm/shmparam.h>
+#include <asm/oplib.h>
+#include <asm/upa.h>
+
+#include "ffb_drv.h"
+
+#define FFB_NAME	"ffb"
+#define FFB_DESC	"Creator/Creator3D"
+#define FFB_DATE	"20000517"
+#define FFB_MAJOR	0
+#define FFB_MINOR	0
+#define FFB_PATCHLEVEL	1
+
+/* Forward declarations. */
+int  ffb_init(void);
+void ffb_cleanup(void);
+static int  ffb_version(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+static int  ffb_open(struct inode *inode, struct file *filp);
+static int  ffb_release(struct inode *inode, struct file *filp);
+static int  ffb_ioctl(struct inode *inode, struct file *filp,
+		      unsigned int cmd, unsigned long arg);
+static int  ffb_lock(struct inode *inode, struct file *filp,
+		     unsigned int cmd, unsigned long arg);
+static int  ffb_unlock(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+static int ffb_mmap(struct file *filp, struct vm_area_struct *vma);
+static unsigned long ffb_get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+
+/* From ffb_context.c */
+extern int ffb_resctx(struct inode *, struct file *, unsigned int, unsigned long);
+extern int ffb_addctx(struct inode *, struct file *, unsigned int, unsigned long);
+extern int ffb_modctx(struct inode *, struct file *, unsigned int, unsigned long);
+extern int ffb_getctx(struct inode *, struct file *, unsigned int, unsigned long);
+extern int ffb_switchctx(struct inode *, struct file *, unsigned int, unsigned long);
+extern int ffb_newctx(struct inode *, struct file *, unsigned int, unsigned long);
+extern int ffb_rmctx(struct inode *, struct file *, unsigned int, unsigned long);
+extern int ffb_context_switch(drm_device_t *, int, int);
+
+static struct file_operations ffb_fops = {
+	owner:			THIS_MODULE,
+	open:			ffb_open,
+	flush:			drm_flush,
+	release:		ffb_release,
+	ioctl:			ffb_ioctl,
+	mmap:			ffb_mmap,
+	read:			drm_read,
+	fasync:			drm_fasync,
+	poll:			drm_poll,
+	get_unmapped_area:	ffb_get_unmapped_area,
+};
+
+/* This is just a template, we make a new copy for each FFB
+ * we discover at init time so that each one gets a unique
+ * misc device minor number.
+ */
+static struct miscdevice ffb_misc = {
+	minor:	MISC_DYNAMIC_MINOR,
+	name:	FFB_NAME,
+	fops:	&ffb_fops,
+};
+
+static drm_ioctl_desc_t ffb_ioctls[] = {
+	[DRM_IOCTL_NR(DRM_IOCTL_VERSION)]    = { ffb_version,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)]  = { drm_getmagic,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)]  = { drm_irq_busid,	  0, 1 }, /* XXX */
+
+	[DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { drm_setunique,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_BLOCK)]	     = { drm_block,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)]    = { drm_unblock,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)]    = { drm_addmap,	  1, 1 },
+	
+	/* The implementation is currently a nop just like on tdfx.
+	 * Later we can do something more clever. -DaveM
+	 */
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)]    = { ffb_addctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)]     = { ffb_rmctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)]    = { ffb_modctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)]    = { ffb_getctx,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { ffb_switchctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)]    = { ffb_newctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)]    = { ffb_resctx,	  1, 0 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)]   = { drm_adddraw,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)]    = { drm_rmdraw,	  1, 1 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_LOCK)]	     = { ffb_lock,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)]     = { ffb_unlock,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_FINISH)]     = { drm_finish,	  1, 0 },
+};
+#define FFB_IOCTL_COUNT DRM_ARRAY_SIZE(ffb_ioctls)
+
+#ifdef MODULE
+static char *ffb = NULL;
+#endif
+
+MODULE_AUTHOR("David S. Miller (davem@redhat.com)");
+MODULE_DESCRIPTION("Sun Creator/Creator3D DRI");
+
+static int ffb_takedown(drm_device_t *dev)
+{
+	int		  i;
+	drm_magic_entry_t *pt, *next;
+	drm_map_t	  *map;
+	drm_vma_entry_t	  *vma, *vma_next;
+
+	DRM_DEBUG("\n");
+
+	down(&dev->struct_sem);
+	del_timer(&dev->timer);
+	
+	if (dev->devname) {
+		drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER);
+		dev->devname = NULL;
+	}
+	
+	if (dev->unique) {
+		drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER);
+		dev->unique = NULL;
+		dev->unique_len = 0;
+	}
+
+	/* Clear pid list */
+	for (i = 0; i < DRM_HASH_SIZE; i++) {
+		for (pt = dev->magiclist[i].head; pt; pt = next) {
+			next = pt->next;
+			drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+		}
+		dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
+	}
+	
+	/* Clear vma list (only built for debugging) */
+	if (dev->vmalist) {
+		for (vma = dev->vmalist; vma; vma = vma_next) {
+			vma_next = vma->next;
+			drm_free(vma, sizeof(*vma), DRM_MEM_VMAS);
+		}
+		dev->vmalist = NULL;
+	}
+	
+	/* Clear map area information */
+	if (dev->maplist) {
+		for (i = 0; i < dev->map_count; i++) {
+			map = dev->maplist[i];
+			switch (map->type) {
+			case _DRM_REGISTERS:
+			case _DRM_FRAME_BUFFER:
+				drm_ioremapfree(map->handle, map->size, dev);
+				break;
+
+			case _DRM_SHM:
+				drm_free_pages((unsigned long)map->handle,
+					       drm_order(map->size)
+					       - PAGE_SHIFT,
+					       DRM_MEM_SAREA);
+				break;
+
+			default:
+				break;
+			};
+
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		}
+
+		drm_free(dev->maplist,
+			 dev->map_count * sizeof(*dev->maplist),
+			 DRM_MEM_MAPS);
+		dev->maplist   = NULL;
+		dev->map_count = 0;
+	}
+	
+	if (dev->lock.hw_lock) {
+		dev->lock.hw_lock    = NULL; /* SHM removed */
+		dev->lock.pid	     = 0;
+		wake_up_interruptible(&dev->lock.lock_queue);
+	}
+	up(&dev->struct_sem);
+	
+	return 0;
+}
+
+drm_device_t **ffb_dev_table;
+static int ffb_dev_table_size;
+
+static void get_ffb_type(ffb_dev_priv_t *ffb_priv, int instance)
+{
+	volatile unsigned char *strap_bits;
+	unsigned char val;
+
+	strap_bits = (volatile unsigned char *)
+		(ffb_priv->card_phys_base + 0x00200000UL);
+
+	/* Don't ask, you have to read the value twice for whatever
+	 * reason to get correct contents.
+	 */
+	val = upa_readb(strap_bits);
+	val = upa_readb(strap_bits);
+	switch (val & 0x78) {
+	case (0x0 << 5) | (0x0 << 3):
+		ffb_priv->ffb_type = ffb1_prototype;
+		printk("ffb%d: Detected FFB1 pre-FCS prototype\n", instance);
+		break;
+	case (0x0 << 5) | (0x1 << 3):
+		ffb_priv->ffb_type = ffb1_standard;
+		printk("ffb%d: Detected FFB1\n", instance);
+		break;
+	case (0x0 << 5) | (0x3 << 3):
+		ffb_priv->ffb_type = ffb1_speedsort;
+		printk("ffb%d: Detected FFB1-SpeedSort\n", instance);
+		break;
+	case (0x1 << 5) | (0x0 << 3):
+		ffb_priv->ffb_type = ffb2_prototype;
+		printk("ffb%d: Detected FFB2/vertical pre-FCS prototype\n", instance);
+		break;
+	case (0x1 << 5) | (0x1 << 3):
+		ffb_priv->ffb_type = ffb2_vertical;
+		printk("ffb%d: Detected FFB2/vertical\n", instance);
+		break;
+	case (0x1 << 5) | (0x2 << 3):
+		ffb_priv->ffb_type = ffb2_vertical_plus;
+		printk("ffb%d: Detected FFB2+/vertical\n", instance);
+		break;
+	case (0x2 << 5) | (0x0 << 3):
+		ffb_priv->ffb_type = ffb2_horizontal;
+		printk("ffb%d: Detected FFB2/horizontal\n", instance);
+		break;
+	case (0x2 << 5) | (0x2 << 3):
+		ffb_priv->ffb_type = ffb2_horizontal;
+		printk("ffb%d: Detected FFB2+/horizontal\n", instance);
+		break;
+	default:
+		ffb_priv->ffb_type = ffb2_vertical;
+		printk("ffb%d: Unknown boardID[%08x], assuming FFB2\n", instance, val);
+		break;
+	};
+}
+
+static void __init ffb_apply_upa_parent_ranges(int parent, struct linux_prom64_registers *regs)
+{
+	struct linux_prom64_ranges ranges[PROMREG_MAX];
+	char name[128];
+	int len, i;
+
+	prom_getproperty(parent, "name", name, sizeof(name));
+	if (strcmp(name, "upa") != 0)
+		return;
+
+	len = prom_getproperty(parent, "ranges", (void *) ranges, sizeof(ranges));
+	if (len <= 0)
+		return;
+
+	len /= sizeof(struct linux_prom64_ranges);
+	for (i = 0; i < len; i++) {
+		struct linux_prom64_ranges *rng = &ranges[i];
+		u64 phys_addr = regs->phys_addr;
+
+		if (phys_addr >= rng->ot_child_base &&
+		    phys_addr < (rng->ot_child_base + rng->or_size)) {
+			regs->phys_addr -= rng->ot_child_base;
+			regs->phys_addr += rng->ot_parent_base;
+			return;
+		}
+	}
+
+	return;
+}
+
+static int __init ffb_init_one(int prom_node, int parent_node, int instance)
+{
+	struct linux_prom64_registers regs[2*PROMREG_MAX];
+	drm_device_t *dev;
+	ffb_dev_priv_t *ffb_priv;
+	int ret, i;
+
+	dev = kmalloc(sizeof(drm_device_t) + sizeof(ffb_dev_priv_t), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	memset(dev, 0, sizeof(*dev));
+	spin_lock_init(&dev->count_lock);
+	sema_init(&dev->struct_sem, 1);
+
+	ffb_priv = (ffb_dev_priv_t *) (dev + 1);
+	ffb_priv->prom_node = prom_node;
+	if (prom_getproperty(ffb_priv->prom_node, "reg",
+			     (void *)regs, sizeof(regs)) <= 0) {
+		kfree(dev);
+		return -EINVAL;
+	}
+	ffb_apply_upa_parent_ranges(parent_node, &regs[0]);
+	ffb_priv->card_phys_base = regs[0].phys_addr;
+	ffb_priv->regs = (ffb_fbcPtr)
+		(regs[0].phys_addr + 0x00600000UL);
+	get_ffb_type(ffb_priv, instance);
+	for (i = 0; i < FFB_MAX_CTXS; i++)
+		ffb_priv->hw_state[i] = NULL;
+
+	ffb_dev_table[instance] = dev;
+
+#ifdef MODULE
+	drm_parse_options(ffb);
+#endif
+
+	memcpy(&ffb_priv->miscdev, &ffb_misc, sizeof(ffb_misc));
+	ret = misc_register(&ffb_priv->miscdev);
+	if (ret) {
+		ffb_dev_table[instance] = NULL;
+		kfree(dev);
+		return ret;
+	}
+
+	dev->device = MKDEV(MISC_MAJOR, ffb_priv->miscdev.minor);
+	dev->name = FFB_NAME;
+
+	drm_mem_init();
+	drm_proc_init(dev);
+
+	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d at %016lx\n",
+		 FFB_NAME,
+		 FFB_MAJOR,
+		 FFB_MINOR,
+		 FFB_PATCHLEVEL,
+		 FFB_DATE,
+		 ffb_priv->miscdev.minor,
+		 ffb_priv->card_phys_base);
+	
+	return 0;
+}
+
+static int __init ffb_count_siblings(int root)
+{
+	int node, child, count = 0;
+
+	child = prom_getchild(root);
+	for (node = prom_searchsiblings(child, "SUNW,ffb"); node;
+	     node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb"))
+		count++;
+
+	return count;
+}
+
+static int __init ffb_init_dev_table(void)
+{
+	int root, total;
+
+	total = ffb_count_siblings(prom_root_node);
+	root = prom_getchild(prom_root_node);
+	for (root = prom_searchsiblings(root, "upa"); root;
+	     root = prom_searchsiblings(prom_getsibling(root), "upa"))
+		total += ffb_count_siblings(root);
+
+	if (!total)
+		return -ENODEV;
+
+	ffb_dev_table = kmalloc(sizeof(drm_device_t *) * total, GFP_KERNEL);
+	if (!ffb_dev_table)
+		return -ENOMEM;
+
+	ffb_dev_table_size = total;
+
+	return 0;
+}
+
+static int __init ffb_scan_siblings(int root, int instance)
+{
+	int node, child;
+
+	child = prom_getchild(root);
+	for (node = prom_searchsiblings(child, "SUNW,ffb"); node;
+	     node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) {
+		ffb_init_one(node, root, instance);
+		instance++;
+	}
+
+	return instance;
+}
+
+int __init ffb_init(void)
+{
+	int root, instance, ret;
+
+	ret = ffb_init_dev_table();
+	if (ret)
+		return ret;
+
+	instance = ffb_scan_siblings(prom_root_node, 0);
+
+	root = prom_getchild(prom_root_node);
+	for (root = prom_searchsiblings(root, "upa"); root;
+	     root = prom_searchsiblings(prom_getsibling(root), "upa"))
+		instance = ffb_scan_siblings(root, instance);
+
+	return 0;
+}
+
+void __exit ffb_cleanup(void)
+{
+	int instance;
+
+	DRM_DEBUG("\n");
+	
+	drm_proc_cleanup();
+	for (instance = 0; instance < ffb_dev_table_size; instance++) {
+		drm_device_t *dev = ffb_dev_table[instance];
+		ffb_dev_priv_t *ffb_priv;
+
+		if (!dev)
+			continue;
+
+		ffb_priv = (ffb_dev_priv_t *) (dev + 1);
+		if (misc_deregister(&ffb_priv->miscdev)) {
+			DRM_ERROR("Cannot unload module\n");
+		} else {
+			DRM_INFO("Module unloaded\n");
+		}
+		ffb_takedown(dev);
+		kfree(dev);
+		ffb_dev_table[instance] = NULL;
+	}
+	kfree(ffb_dev_table);
+	ffb_dev_table = NULL;
+	ffb_dev_table_size = 0;
+}
+
+static int ffb_version(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	drm_version_t version;
+	int len, ret;
+
+	ret = copy_from_user(&version, (drm_version_t *)arg, sizeof(version));
+	if (ret)
+		return -EFAULT;
+
+	version.version_major		= FFB_MAJOR;
+	version.version_minor		= FFB_MINOR;
+	version.version_patchlevel	= FFB_PATCHLEVEL;
+
+	len = strlen(FFB_NAME);
+	if (len > version.name_len)
+		len = version.name_len;
+	version.name_len = len;
+	if (len && version.name) {
+		ret = copy_to_user(version.name, FFB_NAME, len);
+		if (ret)
+			return -EFAULT;
+	}
+
+	len = strlen(FFB_DATE);
+	if (len > version.date_len)
+		len = version.date_len;
+	version.date_len = len;
+	if (len && version.date) {
+		ret = copy_to_user(version.date, FFB_DATE, len);
+		if (ret)
+			return -EFAULT;
+	}
+
+	len = strlen(FFB_DESC);
+	if (len > version.desc_len)
+		len = version.desc_len;
+	version.desc_len = len;
+	if (len && version.desc) {
+		ret = copy_to_user(version.desc, FFB_DESC, len);
+		if (ret)
+			return -EFAULT;
+	}
+
+	ret = copy_to_user((drm_version_t *) arg, &version, sizeof(version));
+	if (ret)
+		ret = -EFAULT;
+
+	return ret;
+}
+
+static int ffb_setup(drm_device_t *dev)
+{
+	int i;
+
+	atomic_set(&dev->ioctl_count, 0);
+	atomic_set(&dev->vma_count, 0);
+	dev->buf_use = 0;
+	atomic_set(&dev->buf_alloc, 0);
+
+	atomic_set(&dev->total_open, 0);
+	atomic_set(&dev->total_close, 0);
+	atomic_set(&dev->total_ioctl, 0);
+	atomic_set(&dev->total_irq, 0);
+	atomic_set(&dev->total_ctx, 0);
+	atomic_set(&dev->total_locks, 0);
+	atomic_set(&dev->total_unlocks, 0);
+	atomic_set(&dev->total_contends, 0);
+	atomic_set(&dev->total_sleeps, 0);
+
+	for (i = 0; i < DRM_HASH_SIZE; i++) {
+		dev->magiclist[i].head = NULL;
+		dev->magiclist[i].tail = NULL;
+	}
+
+	dev->maplist	    = NULL;
+	dev->map_count	    = 0;
+	dev->vmalist	    = NULL;
+	dev->lock.hw_lock   = NULL;
+	init_waitqueue_head(&dev->lock.lock_queue);
+	dev->queue_count    = 0;
+	dev->queue_reserved = 0;
+	dev->queue_slots    = 0;
+	dev->queuelist	    = NULL;
+	dev->irq	    = 0;
+	dev->context_flag   = 0;
+	dev->interrupt_flag = 0;
+	dev->dma            = 0;
+	dev->dma_flag	    = 0;
+	dev->last_context   = 0;
+	dev->last_switch    = 0;
+	dev->last_checked   = 0;
+	init_timer(&dev->timer);
+	init_waitqueue_head(&dev->context_wait);
+
+	dev->ctx_start	    = 0;
+	dev->lck_start	    = 0;
+	
+	dev->buf_rp	  = dev->buf;
+	dev->buf_wp	  = dev->buf;
+	dev->buf_end	  = dev->buf + DRM_BSZ;
+	dev->buf_async	  = NULL;
+	init_waitqueue_head(&dev->buf_readers);
+	init_waitqueue_head(&dev->buf_writers);
+
+	return 0;
+}
+
+static int ffb_open(struct inode *inode, struct file *filp)
+{
+	drm_device_t *dev;
+	int minor, i;
+	int ret = 0;
+
+	minor = MINOR(inode->i_rdev);
+	for (i = 0; i < ffb_dev_table_size; i++) {
+		ffb_dev_priv_t *ffb_priv;
+
+		ffb_priv = (ffb_dev_priv_t *) (ffb_dev_table[i] + 1);
+
+		if (ffb_priv->miscdev.minor = minor)
+			break;
+	}
+
+	if (i >= ffb_dev_table_size)
+		return -EINVAL;
+
+	dev = ffb_dev_table[i];
+	if (!dev)
+		return -EINVAL;
+
+	DRM_DEBUG("open_count = %d\n", dev->open_count);
+	ret = drm_open_helper(inode, filp, dev);
+	if (!ret) {
+		atomic_inc(&dev->total_open);
+		spin_lock(&dev->count_lock);
+		if (!dev->open_count++) {
+			spin_unlock(&dev->count_lock);
+			return ffb_setup(dev);
+		}
+		spin_unlock(&dev->count_lock);
+	}
+
+	return ret;
+}
+
+static int ffb_release(struct inode *inode, struct file *filp)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev;
+	int ret = 0;
+
+	lock_kernel();
+	dev = priv->dev;
+	DRM_DEBUG("open_count = %d\n", dev->open_count);
+	if (dev->lock.hw_lock != NULL
+	    && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
+	    && dev->lock.pid = current->pid) {
+		ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1);
+		int context = _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock);
+		int idx;
+
+		/* We have to free up the rogue hw context state
+		 * holding error or else we will leak it.
+		 */
+		idx = context - 1;
+		if (fpriv->hw_state[idx] != NULL) {
+			kfree(fpriv->hw_state[idx]);
+			fpriv->hw_state[idx] = NULL;
+		}
+	}
+
+	ret = drm_release(inode, filp);
+
+	if (!ret) {
+		atomic_inc(&dev->total_close);
+		spin_lock(&dev->count_lock);
+		if (!--dev->open_count) {
+			if (atomic_read(&dev->ioctl_count) || dev->blocked) {
+				DRM_ERROR("Device busy: %d %d\n",
+					  atomic_read(&dev->ioctl_count),
+					  dev->blocked);
+				spin_unlock(&dev->count_lock);
+				unlock_kernel();
+				return -EBUSY;
+			}
+			spin_unlock(&dev->count_lock);
+			ret = ffb_takedown(dev);
+			unlock_kernel();
+			return ret;
+		}
+		spin_unlock(&dev->count_lock);
+	}
+
+	unlock_kernel();
+	return ret;
+}
+
+static int ffb_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	int		 nr	 = DRM_IOCTL_NR(cmd);
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_ioctl_desc_t *ioctl;
+	drm_ioctl_t	 *func;
+	int		 ret;
+
+	atomic_inc(&dev->ioctl_count);
+	atomic_inc(&dev->total_ioctl);
+	++priv->ioctl_count;
+	
+	DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n",
+		  current->pid, cmd, nr, dev->device, priv->authenticated);
+
+	if (nr >= FFB_IOCTL_COUNT) {
+		ret = -EINVAL;
+	} else {
+		ioctl	  = &ffb_ioctls[nr];
+		func	  = ioctl->func;
+
+		if (!func) {
+			DRM_DEBUG("no function\n");
+			ret = -EINVAL;
+		} else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN))
+			    || (ioctl->auth_needed && !priv->authenticated)) {
+			ret = -EACCES;
+		} else {
+			ret = (func)(inode, filp, cmd, arg);
+		}
+	}
+	
+	atomic_dec(&dev->ioctl_count);
+
+	return ret;
+}
+
+static int ffb_lock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+        drm_file_t        *priv	= filp->private_data;
+        drm_device_t      *dev	= priv->dev;
+        DECLARE_WAITQUEUE(entry, current);
+        int               ret	= 0;
+        drm_lock_t        lock;
+
+	ret = copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock));
+	if (ret)
+		return -EFAULT;
+
+        if (lock.context = DRM_KERNEL_CONTEXT) {
+                DRM_ERROR("Process %d using kernel context %d\n",
+                          current->pid, lock.context);
+                return -EINVAL;
+        }
+
+        DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
+                  lock.context, current->pid, dev->lock.hw_lock->lock,
+                  lock.flags);
+
+	add_wait_queue(&dev->lock.lock_queue, &entry);
+	for (;;) {
+		if (!dev->lock.hw_lock) {
+			/* Device has been unregistered */
+			ret = -EINTR;
+			break;
+		}
+		if (drm_lock_take(&dev->lock.hw_lock->lock,
+				  lock.context)) {
+			dev->lock.pid       = current->pid;
+			dev->lock.lock_time = jiffies;
+			atomic_inc(&dev->total_locks);
+			break;  /* Got lock */
+		}
+                        
+		/* Contention */
+		atomic_inc(&dev->total_sleeps);
+		current->state = TASK_INTERRUPTIBLE;
+		current->policy |= SCHED_YIELD;
+		schedule();
+		if (signal_pending(current)) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&dev->lock.lock_queue, &entry);
+
+        if (!ret) {
+		sigemptyset(&dev->sigmask);
+		sigaddset(&dev->sigmask, SIGSTOP);
+		sigaddset(&dev->sigmask, SIGTSTP);
+		sigaddset(&dev->sigmask, SIGTTIN);
+		sigaddset(&dev->sigmask, SIGTTOU);
+		dev->sigdata.context = lock.context;
+		dev->sigdata.lock = dev->lock.hw_lock;
+		block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
+
+		if (dev->last_context != lock.context)
+			ffb_context_switch(dev, dev->last_context, lock.context);
+	}
+
+        DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
+
+        return ret;
+}
+
+int ffb_unlock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+	drm_lock_t	  lock;
+	unsigned int old, new, prev, ctx;
+	int ret;
+
+	ret = copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock));
+	if (ret)
+		return -EFAULT;
+	
+	if ((ctx = lock.context) = DRM_KERNEL_CONTEXT) {
+		DRM_ERROR("Process %d using kernel context %d\n",
+			  current->pid, lock.context);
+		return -EINVAL;
+	}
+
+	DRM_DEBUG("%d frees lock (%d holds)\n",
+		  lock.context,
+		  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+	atomic_inc(&dev->total_unlocks);
+	if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock))
+		atomic_inc(&dev->total_contends);
+
+	/* We no longer really hold it, but if we are the next
+	 * agent to request it then we should just be able to
+	 * take it immediately and not eat the ioctl.
+	 */
+	dev->lock.pid = 0;
+	{
+		__volatile__ unsigned int *plock = &dev->lock.hw_lock->lock;
+
+		do {
+			old  = *plock;
+			new  = ctx;
+			prev = cmpxchg(plock, old, new);
+		} while (prev != old);
+	}
+
+	wake_up_interruptible(&dev->lock.lock_queue);
+	
+	unblock_all_signals();
+	return 0;
+}
+
+extern struct vm_operations_struct drm_vm_ops;
+extern struct vm_operations_struct drm_vm_shm_ops;
+extern struct vm_operations_struct drm_vm_shm_lock_ops;
+
+static int ffb_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_map_t	*map	= NULL;
+	ffb_dev_priv_t	*ffb_priv;
+	int		i, minor;
+	
+	DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
+		  vma->vm_start, vma->vm_end, VM_OFFSET(vma));
+
+	minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+	ffb_priv = NULL;
+	for (i = 0; i < ffb_dev_table_size; i++) {
+		ffb_priv = (ffb_dev_priv_t *) (ffb_dev_table[i] + 1);
+		if (ffb_priv->miscdev.minor = minor)
+			break;
+	}
+	if (i >= ffb_dev_table_size)
+		return -EINVAL;
+
+	/* We don't support/need dma mappings, so... */
+	if (!VM_OFFSET(vma))
+		return -EINVAL;
+
+	for (i = 0; i < dev->map_count; i++) {
+		unsigned long off;
+
+		map = dev->maplist[i];
+
+		/* Ok, a little hack to make 32-bit apps work. */
+		off = (map->offset & 0xffffffff);
+		if (off = VM_OFFSET(vma))
+			break;
+	}
+
+	if (i >= dev->map_count)
+		return -EINVAL;
+
+	if (!map ||
+	    ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN)))
+		return -EPERM;
+
+	if (map->size != (vma->vm_end - vma->vm_start))
+		return -EINVAL;
+
+	/* Set read-only attribute before mappings are created
+	 * so it works for fb/reg maps too.
+	 */
+	if (map->flags & _DRM_READ_ONLY)
+		vma->vm_page_prot = __pgprot(pte_val(pte_wrprotect(
+			__pte(pgprot_val(vma->vm_page_prot)))));
+
+	switch (map->type) {
+	case _DRM_FRAME_BUFFER:
+		/* FALLTHROUGH */
+
+	case _DRM_REGISTERS:
+		/* In order to handle 32-bit drm apps/xserver we
+		 * play a trick.  The mappings only really specify
+		 * the 32-bit offset from the cards 64-bit base
+		 * address, and we just add in the base here.
+		 */
+		vma->vm_flags |= VM_IO;
+		if (io_remap_page_range(vma->vm_start,
+					ffb_priv->card_phys_base + VM_OFFSET(vma),
+					vma->vm_end - vma->vm_start,
+					vma->vm_page_prot, 0))
+			return -EAGAIN;
+
+		vma->vm_ops = &drm_vm_ops;
+		break;
+	case _DRM_SHM:
+		if (map->flags & _DRM_CONTAINS_LOCK)
+			vma->vm_ops = &drm_vm_shm_lock_ops;
+		else {
+			vma->vm_ops = &drm_vm_shm_ops;
+			vma->vm_private_data = (void *) map;
+		}
+
+		/* Don't let this area swap.  Change when
+		 * DRM_KERNEL advisory is supported.
+		 */
+		vma->vm_flags |= VM_LOCKED;
+		break;
+	default:
+		return -EINVAL;	/* This should never happen. */
+	};
+
+	vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
+
+	vma->vm_file = filp; /* Needed for drm_vm_open() */
+	drm_vm_open(vma);
+	return 0;
+}
+
+static drm_map_t *ffb_find_map(struct file *filp, unsigned long off)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev;
+	drm_map_t	*map;
+	int		i;
+
+	if (!priv || (dev = priv->dev) = NULL)
+		return NULL;
+
+	for (i = 0; i < dev->map_count; i++) {
+		unsigned long uoff;
+
+		map = dev->maplist[i];
+
+		/* Ok, a little hack to make 32-bit apps work. */
+		uoff = (map->offset & 0xffffffff);
+		if (uoff = off)
+			return map;
+	}
+	return NULL;
+}
+
+static unsigned long ffb_get_unmapped_area(struct file *filp, unsigned long hint, unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+	drm_map_t *map = ffb_find_map(filp, pgoff << PAGE_SHIFT);
+	unsigned long addr = -ENOMEM;
+
+	if (!map)
+		return get_unmapped_area(NULL, hint, len, pgoff, flags);
+
+	if (map->type = _DRM_FRAME_BUFFER ||
+	    map->type = _DRM_REGISTERS) {
+#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
+		addr = get_fb_unmapped_area(filp, hint, len, pgoff, flags);
+#else
+		addr = get_unmapped_area(NULL, hint, len, pgoff, flags);
+#endif
+	} else if (map->type = _DRM_SHM && SHMLBA > PAGE_SIZE) {
+		unsigned long slack = SHMLBA - PAGE_SIZE;
+
+		addr = get_unmapped_area(NULL, hint, len + slack, pgoff, flags);
+		if (!(addr & ~PAGE_MASK)) {
+			unsigned long kvirt = (unsigned long) map->handle;
+
+			if ((kvirt & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) {
+				unsigned long koff, aoff;
+
+				koff = kvirt & (SHMLBA - 1);
+				aoff = addr & (SHMLBA - 1);
+				if (koff < aoff)
+					koff += SHMLBA;
+
+				addr += (koff - aoff);
+			}
+		}
+	} else {
+		addr = get_unmapped_area(NULL, hint, len, pgoff, flags);
+	}
+
+	return addr;
+}
+
+module_init(ffb_init);
+module_exit(ffb_cleanup);
diff -urN linux-2.4.13/drivers/char/drm-4.0/ffb_drv.h linux-2.4.13-lia/drivers/char/drm-4.0/ffb_drv.h
--- linux-2.4.13/drivers/char/drm-4.0/ffb_drv.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/ffb_drv.h	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,276 @@
+/* $Id: ffb_drv.h,v 1.1 2000/06/01 04:24:39 davem Exp $
+ * ffb_drv.h: Creator/Creator3D direct rendering driver.
+ *
+ * Copyright (C) 2000 David S. Miller (davem@redhat.com)
+ */
+
+/* Auxilliary clips. */
+typedef struct  {
+	volatile unsigned int min;
+	volatile unsigned int max;
+} ffb_auxclip, *ffb_auxclipPtr;
+
+/* FFB register set. */
+typedef struct _ffb_fbc {
+	/* Next vertex registers, on the right we list which drawops
+	 * use said register and the logical name the register has in
+	 * that context.
+	 */					/* DESCRIPTION		DRAWOP(NAME)	*/
+/*0x00*/unsigned int		pad1[3];	/* Reserved				*/
+/*0x0c*/volatile unsigned int	alpha;		/* ALPHA Transparency			*/
+/*0x10*/volatile unsigned int	red;		/* RED					*/
+/*0x14*/volatile unsigned int	green;		/* GREEN				*/
+/*0x18*/volatile unsigned int	blue;		/* BLUE					*/
+/*0x1c*/volatile unsigned int	z;		/* DEPTH				*/
+/*0x20*/volatile unsigned int	y;		/* Y			triangle(DOYF)	*/
+						/*                      aadot(DYF)	*/
+						/*                      ddline(DYF)	*/
+						/*                      aaline(DYF)	*/
+/*0x24*/volatile unsigned int	x;		/* X			triangle(DOXF)	*/
+						/*                      aadot(DXF)	*/
+						/*                      ddline(DXF)	*/
+						/*                      aaline(DXF)	*/
+/*0x28*/unsigned int		pad2[2];	/* Reserved				*/
+/*0x30*/volatile unsigned int	ryf;		/* Y (alias to DOYF)	ddline(RYF)	*/
+						/*			aaline(RYF)	*/
+						/*			triangle(RYF)	*/
+/*0x34*/volatile unsigned int	rxf;		/* X			ddline(RXF)	*/
+						/*			aaline(RXF)	*/
+						/*			triangle(RXF)	*/
+/*0x38*/unsigned int		pad3[2];	/* Reserved				*/
+/*0x40*/volatile unsigned int	dmyf;		/* Y (alias to DOYF)	triangle(DMYF)	*/
+/*0x44*/volatile unsigned int	dmxf;		/* X			triangle(DMXF)	*/
+/*0x48*/unsigned int		pad4[2];	/* Reserved				*/
+/*0x50*/volatile unsigned int	ebyi;		/* Y (alias to RYI)	polygon(EBYI)	*/
+/*0x54*/volatile unsigned int	ebxi;		/* X			polygon(EBXI)	*/
+/*0x58*/unsigned int		pad5[2];	/* Reserved				*/
+/*0x60*/volatile unsigned int	by;		/* Y			brline(RYI)	*/
+						/*			fastfill(OP)	*/
+						/*			polygon(YI)	*/
+						/*			rectangle(YI)	*/
+						/*			bcopy(SRCY)	*/
+						/*			vscroll(SRCY)	*/
+/*0x64*/volatile unsigned int	bx;		/* X			brline(RXI)	*/
+						/*			polygon(XI)	*/
+						/*			rectangle(XI)	*/
+						/*			bcopy(SRCX)	*/
+						/*			vscroll(SRCX)	*/
+						/*			fastfill(GO)	*/
+/*0x68*/volatile unsigned int	dy;		/* destination Y	fastfill(DSTY)	*/
+						/*			bcopy(DSRY)	*/
+						/*			vscroll(DSRY)	*/
+/*0x6c*/volatile unsigned int	dx;		/* destination X	fastfill(DSTX)	*/
+						/*			bcopy(DSTX)	*/
+						/*			vscroll(DSTX)	*/
+/*0x70*/volatile unsigned int	bh;		/* Y (alias to RYI)	brline(DYI)	*/
+						/*			dot(DYI)	*/
+						/*			polygon(ETYI)	*/
+						/* Height		fastfill(H)	*/
+						/*			bcopy(H)	*/
+						/*			vscroll(H)	*/
+						/* Y count		fastfill(NY)	*/
+/*0x74*/volatile unsigned int	bw;		/* X			dot(DXI)	*/
+						/*			brline(DXI)	*/
+						/*			polygon(ETXI)	*/
+						/*			fastfill(W)	*/
+						/*			bcopy(W)	*/
+						/*			vscroll(W)	*/
+						/*			fastfill(NX)	*/
+/*0x78*/unsigned int		pad6[2];	/* Reserved				*/
+/*0x80*/unsigned int		pad7[32];	/* Reserved				*/
+	
+	/* Setup Unit's vertex state register */
+/*100*/	volatile unsigned int	suvtx;
+/*104*/	unsigned int		pad8[63];	/* Reserved				*/
+	
+	/* Frame Buffer Control Registers */
+/*200*/	volatile unsigned int	ppc;		/* Pixel Processor Control		*/
+/*204*/	volatile unsigned int	wid;		/* Current WID				*/
+/*208*/	volatile unsigned int	fg;		/* FG data				*/
+/*20c*/	volatile unsigned int	bg;		/* BG data				*/
+/*210*/	volatile unsigned int	consty;		/* Constant Y				*/
+/*214*/	volatile unsigned int	constz;		/* Constant Z				*/
+/*218*/	volatile unsigned int	xclip;		/* X Clip				*/
+/*21c*/	volatile unsigned int	dcss;		/* Depth Cue Scale Slope		*/
+/*220*/	volatile unsigned int	vclipmin;	/* Viewclip XY Min Bounds		*/
+/*224*/	volatile unsigned int	vclipmax;	/* Viewclip XY Max Bounds		*/
+/*228*/	volatile unsigned int	vclipzmin;	/* Viewclip Z Min Bounds		*/
+/*22c*/	volatile unsigned int	vclipzmax;	/* Viewclip Z Max Bounds		*/
+/*230*/	volatile unsigned int	dcsf;		/* Depth Cue Scale Front Bound		*/
+/*234*/	volatile unsigned int	dcsb;		/* Depth Cue Scale Back Bound		*/
+/*238*/	volatile unsigned int	dczf;		/* Depth Cue Z Front			*/
+/*23c*/	volatile unsigned int	dczb;		/* Depth Cue Z Back			*/
+/*240*/	unsigned int		pad9;		/* Reserved				*/
+/*244*/	volatile unsigned int	blendc;		/* Alpha Blend Control			*/
+/*248*/	volatile unsigned int	blendc1;	/* Alpha Blend Color 1			*/
+/*24c*/	volatile unsigned int	blendc2;	/* Alpha Blend Color 2			*/
+/*250*/	volatile unsigned int	fbramitc;	/* FB RAM Interleave Test Control	*/
+/*254*/	volatile unsigned int	fbc;		/* Frame Buffer Control			*/
+/*258*/	volatile unsigned int	rop;		/* Raster OPeration			*/
+/*25c*/	volatile unsigned int	cmp;		/* Frame Buffer Compare			*/
+/*260*/	volatile unsigned int	matchab;	/* Buffer AB Match Mask			*/
+/*264*/	volatile unsigned int	matchc;		/* Buffer C(YZ) Match Mask		*/
+/*268*/	volatile unsigned int	magnab;		/* Buffer AB Magnitude Mask		*/
+/*26c*/	volatile unsigned int	magnc;		/* Buffer C(YZ) Magnitude Mask		*/
+/*270*/	volatile unsigned int	fbcfg0;		/* Frame Buffer Config 0		*/
+/*274*/	volatile unsigned int	fbcfg1;		/* Frame Buffer Config 1		*/
+/*278*/	volatile unsigned int	fbcfg2;		/* Frame Buffer Config 2		*/
+/*27c*/	volatile unsigned int	fbcfg3;		/* Frame Buffer Config 3		*/
+/*280*/	volatile unsigned int	ppcfg;		/* Pixel Processor Config		*/
+/*284*/	volatile unsigned int	pick;		/* Picking Control			*/
+/*288*/	volatile unsigned int	fillmode;	/* FillMode				*/
+/*28c*/	volatile unsigned int	fbramwac;	/* FB RAM Write Address Control		*/
+/*290*/	volatile unsigned int	pmask;		/* RGB PlaneMask			*/
+/*294*/	volatile unsigned int	xpmask;		/* X PlaneMask				*/
+/*298*/	volatile unsigned int	ypmask;		/* Y PlaneMask				*/
+/*29c*/	volatile unsigned int	zpmask;		/* Z PlaneMask				*/
+/*2a0*/	ffb_auxclip		auxclip[4]; 	/* Auxilliary Viewport Clip		*/
+	
+	/* New 3dRAM III support regs */
+/*2c0*/	volatile unsigned int	rawblend2;
+/*2c4*/	volatile unsigned int	rawpreblend;
+/*2c8*/	volatile unsigned int	rawstencil;
+/*2cc*/	volatile unsigned int	rawstencilctl;
+/*2d0*/	volatile unsigned int	threedram1;
+/*2d4*/	volatile unsigned int	threedram2;
+/*2d8*/	volatile unsigned int	passin;
+/*2dc*/	volatile unsigned int	rawclrdepth;
+/*2e0*/	volatile unsigned int	rawpmask;
+/*2e4*/	volatile unsigned int	rawcsrc;
+/*2e8*/	volatile unsigned int	rawmatch;
+/*2ec*/	volatile unsigned int	rawmagn;
+/*2f0*/	volatile unsigned int	rawropblend;
+/*2f4*/	volatile unsigned int	rawcmp;
+/*2f8*/	volatile unsigned int	rawwac;
+/*2fc*/	volatile unsigned int	fbramid;
+	
+/*300*/	volatile unsigned int	drawop;		/* Draw OPeration			*/
+/*304*/	unsigned int		pad10[2];	/* Reserved				*/
+/*30c*/	volatile unsigned int	lpat;		/* Line Pattern control			*/
+/*310*/	unsigned int		pad11;		/* Reserved				*/
+/*314*/	volatile unsigned int	fontxy;		/* XY Font coordinate			*/
+/*318*/	volatile unsigned int	fontw;		/* Font Width				*/
+/*31c*/	volatile unsigned int	fontinc;	/* Font Increment			*/
+/*320*/	volatile unsigned int	font;		/* Font bits				*/
+/*324*/	unsigned int		pad12[3];	/* Reserved				*/
+/*330*/	volatile unsigned int	blend2;
+/*334*/	volatile unsigned int	preblend;
+/*338*/	volatile unsigned int	stencil;
+/*33c*/	volatile unsigned int	stencilctl;
+
+/*340*/	unsigned int		pad13[4];	/* Reserved				*/
+/*350*/	volatile unsigned int	dcss1;		/* Depth Cue Scale Slope 1		*/
+/*354*/	volatile unsigned int	dcss2;		/* Depth Cue Scale Slope 2		*/
+/*358*/	volatile unsigned int	dcss3;		/* Depth Cue Scale Slope 3		*/
+/*35c*/	volatile unsigned int	widpmask;
+/*360*/	volatile unsigned int	dcs2;
+/*364*/	volatile unsigned int	dcs3;
+/*368*/	volatile unsigned int	dcs4;
+/*36c*/	unsigned int		pad14;		/* Reserved				*/
+/*370*/	volatile unsigned int	dcd2;
+/*374*/	volatile unsigned int	dcd3;
+/*378*/	volatile unsigned int	dcd4;
+/*37c*/	unsigned int		pad15;		/* Reserved				*/
+/*380*/	volatile unsigned int	pattern[32];	/* area Pattern				*/
+/*400*/	unsigned int		pad16[8];	/* Reserved				*/
+/*420*/	volatile unsigned int	reset;		/* chip RESET				*/
+/*424*/	unsigned int		pad17[247];	/* Reserved				*/
+/*800*/	volatile unsigned int	devid;		/* Device ID				*/
+/*804*/	unsigned int		pad18[63];	/* Reserved				*/
+/*900*/	volatile unsigned int	ucsr;		/* User Control & Status Register	*/
+/*904*/	unsigned int		pad19[31];	/* Reserved				*/
+/*980*/	volatile unsigned int	mer;		/* Mode Enable Register			*/
+/*984*/	unsigned int		pad20[1439];	/* Reserved				*/
+} ffb_fbc, *ffb_fbcPtr;
+
+struct ffb_hw_context {
+	int is_2d_only;
+
+	unsigned int ppc;
+	unsigned int wid;
+	unsigned int fg;
+	unsigned int bg;
+	unsigned int consty;
+	unsigned int constz;
+	unsigned int xclip;
+	unsigned int dcss;
+	unsigned int vclipmin;
+	unsigned int vclipmax;
+	unsigned int vclipzmin;
+	unsigned int vclipzmax;
+	unsigned int dcsf;
+	unsigned int dcsb;
+	unsigned int dczf;
+	unsigned int dczb;
+	unsigned int blendc;
+	unsigned int blendc1;
+	unsigned int blendc2;
+	unsigned int fbc;
+	unsigned int rop;
+	unsigned int cmp;
+	unsigned int matchab;
+	unsigned int matchc;
+	unsigned int magnab;
+	unsigned int magnc;
+	unsigned int pmask;
+	unsigned int xpmask;
+	unsigned int ypmask;
+	unsigned int zpmask;
+	unsigned int auxclip0min;
+	unsigned int auxclip0max;
+	unsigned int auxclip1min;
+	unsigned int auxclip1max;
+	unsigned int auxclip2min;
+	unsigned int auxclip2max;
+	unsigned int auxclip3min;
+	unsigned int auxclip3max;
+	unsigned int drawop;
+	unsigned int lpat;
+	unsigned int fontxy;
+	unsigned int fontw;
+	unsigned int fontinc;
+	unsigned int area_pattern[32];
+	unsigned int ucsr;
+	unsigned int stencil;
+	unsigned int stencilctl;
+	unsigned int dcss1;
+	unsigned int dcss2;
+	unsigned int dcss3;
+	unsigned int dcs2;
+	unsigned int dcs3;
+	unsigned int dcs4;
+	unsigned int dcd2;
+	unsigned int dcd3;
+	unsigned int dcd4;
+	unsigned int mer;
+};
+
+#define FFB_MAX_CTXS	32
+
+enum ffb_chip_type {
+	ffb1_prototype = 0,	/* Early pre-FCS FFB */
+	ffb1_standard,		/* First FCS FFB, 100Mhz UPA, 66MHz gclk */
+	ffb1_speedsort,		/* Second FCS FFB, 100Mhz UPA, 75MHz gclk */
+	ffb2_prototype,		/* Early pre-FCS vertical FFB2 */
+	ffb2_vertical,		/* First FCS FFB2/vertical, 100Mhz UPA, 100MHZ gclk,
+				   75(SingleBuffer)/83(DoubleBuffer) MHz fclk */
+	ffb2_vertical_plus,	/* Second FCS FFB2/vertical, same timings */
+	ffb2_horizontal,	/* First FCS FFB2/horizontal, same timings as FFB2/vert */
+	ffb2_horizontal_plus,	/* Second FCS FFB2/horizontal, same timings */
+	afb_m3,			/* FCS Elite3D, 3 float chips */
+	afb_m6			/* FCS Elite3D, 6 float chips */
+};
+
+typedef struct ffb_dev_priv {
+	/* Misc software state. */
+	int			prom_node;
+	enum ffb_chip_type	ffb_type;
+	u64			card_phys_base;
+	struct miscdevice 	miscdev;
+
+	/* Controller registers. */
+	ffb_fbcPtr		regs;
+
+	/* Context table. */
+	struct ffb_hw_context	*hw_state[FFB_MAX_CTXS];
+} ffb_dev_priv_t;
diff -urN linux-2.4.13/drivers/char/drm-4.0/fops.c linux-2.4.13-lia/drivers/char/drm-4.0/fops.c
--- linux-2.4.13/drivers/char/drm-4.0/fops.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/fops.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,253 @@
+/* fops.c -- File operations for DRM -*- linux-c -*-
+ * Created: Mon Jan  4 08:58:31 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *    Daryll Strauss <daryll@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include <linux/poll.h>
+
+/* drm_open is called whenever a process opens /dev/drm. */
+
+int drm_open_helper(struct inode *inode, struct file *filp, drm_device_t *dev)
+{
+	kdev_t	     minor = MINOR(inode->i_rdev);
+	drm_file_t   *priv;
+
+	if (filp->f_flags & O_EXCL)   return -EBUSY; /* No exclusive opens */
+	if (!drm_cpu_valid())         return -EINVAL;
+
+	DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor);
+
+	priv		    = drm_alloc(sizeof(*priv), DRM_MEM_FILES);
+	if(priv = NULL)
+		return -ENOMEM;
+	memset(priv, 0, sizeof(*priv));
+
+	filp->private_data  = priv;
+	priv->uid	    = current->euid;
+	priv->pid	    = current->pid;
+	priv->minor	    = minor;
+	priv->dev	    = dev;
+	priv->ioctl_count   = 0;
+	priv->authenticated = capable(CAP_SYS_ADMIN);
+
+	down(&dev->struct_sem);
+	if (!dev->file_last) {
+		priv->next	= NULL;
+		priv->prev	= NULL;
+		dev->file_first = priv;
+		dev->file_last	= priv;
+	} else {
+		priv->next	     = NULL;
+		priv->prev	     = dev->file_last;
+		dev->file_last->next = priv;
+		dev->file_last	     = priv;
+	}
+	up(&dev->struct_sem);
+	
+	return 0;
+}
+
+int drm_flush(struct file *filp)
+{
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev    = priv->dev;
+
+	DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
+		  current->pid, dev->device, dev->open_count);
+	return 0;
+}
+
+/* drm_release is called whenever a process closes /dev/drm*.  Linux calls
+   this only if any mappings have been closed. */
+
+int drm_release(struct inode *inode, struct file *filp)
+{
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev    = priv->dev;
+
+	DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
+		  current->pid, dev->device, dev->open_count);
+
+	if (dev->lock.hw_lock
+	    && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
+	    && dev->lock.pid = current->pid) {
+		DRM_ERROR("Process %d dead, freeing lock for context %d\n",
+			  current->pid,
+			  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+		drm_lock_free(dev,
+			      &dev->lock.hw_lock->lock,
+			      _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+		
+				/* FIXME: may require heavy-handed reset of
+                                   hardware at this point, possibly
+                                   processed via a callback to the X
+                                   server. */
+	}
+	drm_reclaim_buffers(dev, priv->pid);
+
+	drm_fasync(-1, filp, 0);
+
+	down(&dev->struct_sem);
+	if (priv->prev) priv->prev->next = priv->next;
+	else		dev->file_first	 = priv->next;
+	if (priv->next) priv->next->prev = priv->prev;
+	else		dev->file_last	 = priv->prev;
+	up(&dev->struct_sem);
+	
+	drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
+	
+	return 0;
+}
+
+int drm_fasync(int fd, struct file *filp, int on)
+{
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev    = priv->dev;
+	int	      retcode;
+	
+	DRM_DEBUG("fd = %d, device = 0x%x\n", fd, dev->device);
+	retcode = fasync_helper(fd, filp, on, &dev->buf_async);
+	if (retcode < 0) return retcode;
+	return 0;
+}
+
+
+/* The drm_read and drm_write_string code (especially that which manages
+   the circular buffer), is based on Alessandro Rubini's LINUX DEVICE
+   DRIVERS (Cambridge: O'Reilly, 1998), pages 111-113. */
+
+ssize_t drm_read(struct file *filp, char *buf, size_t count, loff_t *off)
+{
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev    = priv->dev;
+	int	      left;
+	int	      avail;
+	int	      send;
+	int	      cur;
+
+	DRM_DEBUG("%p, %p\n", dev->buf_rp, dev->buf_wp);
+	
+	while (dev->buf_rp = dev->buf_wp) {
+		DRM_DEBUG("  sleeping\n");
+		if (filp->f_flags & O_NONBLOCK) {
+			return -EAGAIN;
+		}
+		interruptible_sleep_on(&dev->buf_readers);
+		if (signal_pending(current)) {
+			DRM_DEBUG("  interrupted\n");
+			return -ERESTARTSYS;
+		}
+		DRM_DEBUG("  awake\n");
+	}
+
+	left  = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
+	avail = DRM_BSZ - left;
+	send  = DRM_MIN(avail, count);
+
+	while (send) {
+		if (dev->buf_wp > dev->buf_rp) {
+			cur = DRM_MIN(send, dev->buf_wp - dev->buf_rp);
+		} else {
+			cur = DRM_MIN(send, dev->buf_end - dev->buf_rp);
+		}
+		if (copy_to_user(buf, dev->buf_rp, cur))
+			return -EFAULT;
+		dev->buf_rp += cur;
+		if (dev->buf_rp = dev->buf_end) dev->buf_rp = dev->buf;
+		send -= cur;
+	}
+	
+	wake_up_interruptible(&dev->buf_writers);
+	return DRM_MIN(avail, count);;
+}
+
+int drm_write_string(drm_device_t *dev, const char *s)
+{
+	int left   = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
+	int send   = strlen(s);
+	int count;
+
+	DRM_DEBUG("%d left, %d to send (%p, %p)\n",
+		  left, send, dev->buf_rp, dev->buf_wp);
+	
+	if (left = 1 || dev->buf_wp != dev->buf_rp) {
+		DRM_ERROR("Buffer not empty (%d left, wp = %p, rp = %p)\n",
+			  left,
+			  dev->buf_wp,
+			  dev->buf_rp);
+	}
+
+	while (send) {
+		if (dev->buf_wp >= dev->buf_rp) {
+			count = DRM_MIN(send, dev->buf_end - dev->buf_wp);
+			if (count = left) --count; /* Leave a hole */
+		} else {
+			count = DRM_MIN(send, dev->buf_rp - dev->buf_wp - 1);
+		}
+		strncpy(dev->buf_wp, s, count);
+		dev->buf_wp += count;
+		if (dev->buf_wp = dev->buf_end) dev->buf_wp = dev->buf;
+		send -= count;
+	}
+
+#if LINUX_VERSION_CODE < 0x020315 && !defined(KILLFASYNCHASTHREEPARAMETERS)
+	/* The extra parameter to kill_fasync was added in 2.3.21, and is
+           _not_ present in _stock_ 2.2.14 and 2.2.15.  However, some
+           distributions patch 2.2.x kernels to add this parameter.  The
+           Makefile.linux attempts to detect this addition and defines
+           KILLFASYNCHASTHREEPARAMETERS if three parameters are found. */
+	if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO);
+#else
+
+				/* Parameter added in 2.3.21. */
+#if LINUX_VERSION_CODE < 0x020400
+	if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO, POLL_IN);
+#else
+				/* Type of first parameter changed in
+                                   Linux 2.4.0-test2... */
+	if (dev->buf_async) kill_fasync(&dev->buf_async, SIGIO, POLL_IN);
+#endif
+#endif
+	DRM_DEBUG("waking\n");
+	wake_up_interruptible(&dev->buf_readers);
+	return 0;
+}
+
+unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait)
+{
+	drm_file_t   *priv = filp->private_data;
+	drm_device_t *dev  = priv->dev;
+
+	poll_wait(filp, &dev->buf_readers, wait);
+	if (dev->buf_wp != dev->buf_rp) return POLLIN | POLLRDNORM;
+	return 0;
+}
diff -urN linux-2.4.13/drivers/char/drm-4.0/gamma_dma.c linux-2.4.13-lia/drivers/char/drm-4.0/gamma_dma.c
--- linux-2.4.13/drivers/char/drm-4.0/gamma_dma.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/gamma_dma.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,836 @@
+/* gamma_dma.c -- DMA support for GMX 2000 -*- linux-c -*-
+ * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "gamma_drv.h"
+
+#include <linux/interrupt.h>	/* For task queue support */
+
+
+/* WARNING!!! MAGIC NUMBER!!!  The number of regions already added to the
+   kernel must be specified here.  Currently, the number is 2.	This must
+   match the order the X server uses for instantiating register regions ,
+   or must be passed in a new ioctl. */
+#define GAMMA_REG(reg)						   \
+	(2							   \
+	 + ((reg < 0x1000)					   \
+	    ? 0							   \
+	    : ((reg < 0x10000) ? 1 : ((reg < 0x11000) ? 2 : 3))))
+
+#define GAMMA_OFF(reg)						   \
+	((reg < 0x1000)						   \
+	 ? reg							   \
+	 : ((reg < 0x10000)					   \
+	    ? (reg - 0x1000)					   \
+	    : ((reg < 0x11000)					   \
+	       ? (reg - 0x10000)				   \
+	       : (reg - 0x11000))))
+
+#define GAMMA_BASE(reg)	 ((unsigned long)dev->maplist[GAMMA_REG(reg)]->handle)
+#define GAMMA_ADDR(reg)	 (GAMMA_BASE(reg) + GAMMA_OFF(reg))
+#define GAMMA_DEREF(reg) *(__volatile__ int *)GAMMA_ADDR(reg)
+#define GAMMA_READ(reg)	 GAMMA_DEREF(reg)
+#define GAMMA_WRITE(reg,val) do { GAMMA_DEREF(reg) = val; } while (0)
+
+#define GAMMA_BROADCASTMASK    0x9378
+#define GAMMA_COMMANDINTENABLE 0x0c48
+#define GAMMA_DMAADDRESS       0x0028
+#define GAMMA_DMACOUNT	       0x0030
+#define GAMMA_FILTERMODE       0x8c00
+#define GAMMA_GCOMMANDINTFLAGS 0x0c50
+#define GAMMA_GCOMMANDMODE     0x0c40
+#define GAMMA_GCOMMANDSTATUS   0x0c60
+#define GAMMA_GDELAYTIMER      0x0c38
+#define GAMMA_GDMACONTROL      0x0060
+#define GAMMA_GINTENABLE       0x0808
+#define GAMMA_GINTFLAGS	       0x0810
+#define GAMMA_INFIFOSPACE      0x0018
+#define GAMMA_OUTFIFOWORDS     0x0020
+#define GAMMA_OUTPUTFIFO       0x2000
+#define GAMMA_SYNC	       0x8c40
+#define GAMMA_SYNC_TAG	       0x0188
+
+static inline void gamma_dma_dispatch(drm_device_t *dev, unsigned long address,
+				      unsigned long length)
+{
+	GAMMA_WRITE(GAMMA_DMAADDRESS, virt_to_phys((void *)address));
+	while (GAMMA_READ(GAMMA_GCOMMANDSTATUS) != 4)
+		;
+	GAMMA_WRITE(GAMMA_DMACOUNT, length / 4);
+}
+
+static inline void gamma_dma_quiescent_single(drm_device_t *dev)
+{
+	while (GAMMA_READ(GAMMA_DMACOUNT))
+		;
+	while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3)
+		;
+
+	GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10);
+	GAMMA_WRITE(GAMMA_SYNC, 0);
+	
+	do {
+		while (!GAMMA_READ(GAMMA_OUTFIFOWORDS))
+			;
+	} while (GAMMA_READ(GAMMA_OUTPUTFIFO) != GAMMA_SYNC_TAG);
+}
+
+static inline void gamma_dma_quiescent_dual(drm_device_t *dev)
+{
+	while (GAMMA_READ(GAMMA_DMACOUNT))
+		;
+	while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3)
+		;
+
+	GAMMA_WRITE(GAMMA_BROADCASTMASK, 3);
+
+	GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10);
+	GAMMA_WRITE(GAMMA_SYNC, 0);
+	
+				/* Read from first MX */
+	do {
+		while (!GAMMA_READ(GAMMA_OUTFIFOWORDS))
+			;
+	} while (GAMMA_READ(GAMMA_OUTPUTFIFO) != GAMMA_SYNC_TAG);
+	
+				/* Read from second MX */
+	do {
+		while (!GAMMA_READ(GAMMA_OUTFIFOWORDS + 0x10000))
+			;
+	} while (GAMMA_READ(GAMMA_OUTPUTFIFO + 0x10000) != GAMMA_SYNC_TAG);
+}
+
+static inline void gamma_dma_ready(drm_device_t *dev)
+{
+	while (GAMMA_READ(GAMMA_DMACOUNT))
+		;
+}
+
+static inline int gamma_dma_is_ready(drm_device_t *dev)
+{
+	return !GAMMA_READ(GAMMA_DMACOUNT);
+}
+
+static void gamma_dma_service(int irq, void *device, struct pt_regs *regs)
+{
+	drm_device_t	 *dev = (drm_device_t *)device;
+	drm_device_dma_t *dma = dev->dma;
+	
+	atomic_inc(&dev->total_irq);
+	GAMMA_WRITE(GAMMA_GDELAYTIMER, 0xc350/2); /* 0x05S */
+	GAMMA_WRITE(GAMMA_GCOMMANDINTFLAGS, 8);
+	GAMMA_WRITE(GAMMA_GINTFLAGS, 0x2001);
+	if (gamma_dma_is_ready(dev)) {
+				/* Free previous buffer */
+		if (test_and_set_bit(0, &dev->dma_flag)) {
+			atomic_inc(&dma->total_missed_free);
+			return;
+		}
+		if (dma->this_buffer) {
+			drm_free_buffer(dev, dma->this_buffer);
+			dma->this_buffer = NULL;
+		}
+		clear_bit(0, &dev->dma_flag);
+
+				/* Dispatch new buffer */
+		queue_task(&dev->tq, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+	}
+}
+
+/* Only called by gamma_dma_schedule. */
+static int gamma_do_dma(drm_device_t *dev, int locked)
+{
+	unsigned long	 address;
+	unsigned long	 length;
+	drm_buf_t	 *buf;
+	int		 retcode = 0;
+	drm_device_dma_t *dma = dev->dma;
+#if DRM_DMA_HISTOGRAM
+	cycles_t	 dma_start, dma_stop;
+#endif
+
+	if (test_and_set_bit(0, &dev->dma_flag)) {
+		atomic_inc(&dma->total_missed_dma);
+		return -EBUSY;
+	}
+	
+#if DRM_DMA_HISTOGRAM
+	dma_start = get_cycles();
+#endif
+
+	if (!dma->next_buffer) {
+		DRM_ERROR("No next_buffer\n");
+		clear_bit(0, &dev->dma_flag);
+		return -EINVAL;
+	}
+
+	buf	= dma->next_buffer;
+	address = (unsigned long)buf->address;
+	length	= buf->used;
+
+	DRM_DEBUG("context %d, buffer %d (%ld bytes)\n",
+		  buf->context, buf->idx, length);
+
+	if (buf->list = DRM_LIST_RECLAIM) {
+		drm_clear_next_buffer(dev);
+		drm_free_buffer(dev, buf);
+		clear_bit(0, &dev->dma_flag);
+		return -EINVAL;
+	}
+
+	if (!length) {
+		DRM_ERROR("0 length buffer\n");
+		drm_clear_next_buffer(dev);
+		drm_free_buffer(dev, buf);
+		clear_bit(0, &dev->dma_flag);
+		return 0;
+	}
+	
+	if (!gamma_dma_is_ready(dev)) {
+		clear_bit(0, &dev->dma_flag);
+		return -EBUSY;
+	}
+
+	if (buf->while_locked) {
+		if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+			DRM_ERROR("Dispatching buffer %d from pid %d"
+				  " \"while locked\", but no lock held\n",
+				  buf->idx, buf->pid);
+		}
+	} else {
+		if (!locked && !drm_lock_take(&dev->lock.hw_lock->lock,
+					      DRM_KERNEL_CONTEXT)) {
+			atomic_inc(&dma->total_missed_lock);
+			clear_bit(0, &dev->dma_flag);
+			return -EBUSY;
+		}
+	}
+
+	if (dev->last_context != buf->context
+	    && !(dev->queuelist[buf->context]->flags
+		 & _DRM_CONTEXT_PRESERVED)) {
+				/* PRE: dev->last_context != buf->context */
+		if (drm_context_switch(dev, dev->last_context, buf->context)) {
+			drm_clear_next_buffer(dev);
+			drm_free_buffer(dev, buf);
+		}
+		retcode = -EBUSY;
+		goto cleanup;
+			
+				/* POST: we will wait for the context
+				   switch and will dispatch on a later call
+				   when dev->last_context = buf->context.
+				   NOTE WE HOLD THE LOCK THROUGHOUT THIS
+				   TIME! */
+	}
+
+	drm_clear_next_buffer(dev);
+	buf->pending	 = 1;
+	buf->waiting	 = 0;
+	buf->list	 = DRM_LIST_PEND;
+#if DRM_DMA_HISTOGRAM
+	buf->time_dispatched = get_cycles();
+#endif
+
+	gamma_dma_dispatch(dev, address, length);
+	drm_free_buffer(dev, dma->this_buffer);
+	dma->this_buffer = buf;
+
+	atomic_add(length, &dma->total_bytes);
+	atomic_inc(&dma->total_dmas);
+
+	if (!buf->while_locked && !dev->context_flag && !locked) {
+		if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+				  DRM_KERNEL_CONTEXT)) {
+			DRM_ERROR("\n");
+		}
+	}
+cleanup:
+
+	clear_bit(0, &dev->dma_flag);
+
+#if DRM_DMA_HISTOGRAM
+	dma_stop = get_cycles();
+	atomic_inc(&dev->histo.dma[drm_histogram_slot(dma_stop - dma_start)]);
+#endif
+
+	return retcode;
+}
+
+static void gamma_dma_schedule_timer_wrapper(unsigned long dev)
+{
+	gamma_dma_schedule((drm_device_t *)dev, 0);
+}
+
+static void gamma_dma_schedule_tq_wrapper(void *dev)
+{
+	gamma_dma_schedule(dev, 0);
+}
+
+int gamma_dma_schedule(drm_device_t *dev, int locked)
+{
+	int		 next;
+	drm_queue_t	 *q;
+	drm_buf_t	 *buf;
+	int		 retcode   = 0;
+	int		 processed = 0;
+	int		 missed;
+	int		 expire	   = 20;
+	drm_device_dma_t *dma	   = dev->dma;
+#if DRM_DMA_HISTOGRAM
+	cycles_t	 schedule_start;
+#endif
+
+	if (test_and_set_bit(0, &dev->interrupt_flag)) {
+				/* Not reentrant */
+		atomic_inc(&dma->total_missed_sched);
+		return -EBUSY;
+	}
+	missed = atomic_read(&dma->total_missed_sched);
+
+#if DRM_DMA_HISTOGRAM
+	schedule_start = get_cycles();
+#endif
+
+again:
+	if (dev->context_flag) {
+		clear_bit(0, &dev->interrupt_flag);
+		return -EBUSY;
+	}
+	if (dma->next_buffer) {
+				/* Unsent buffer that was previously
+				   selected, but that couldn't be sent
+				   because the lock could not be obtained
+				   or the DMA engine wasn't ready.  Try
+				   again. */
+		atomic_inc(&dma->total_tried);
+		if (!(retcode = gamma_do_dma(dev, locked))) {
+			atomic_inc(&dma->total_hit);
+			++processed;
+		}
+	} else {
+		do {
+			next = drm_select_queue(dev,
+					     gamma_dma_schedule_timer_wrapper);
+			if (next >= 0) {
+				q   = dev->queuelist[next];
+				buf = drm_waitlist_get(&q->waitlist);
+				dma->next_buffer = buf;
+				dma->next_queue	 = q;
+				if (buf && buf->list = DRM_LIST_RECLAIM) {
+					drm_clear_next_buffer(dev);
+					drm_free_buffer(dev, buf);
+				}
+			}
+		} while (next >= 0 && !dma->next_buffer);
+		if (dma->next_buffer) {
+			if (!(retcode = gamma_do_dma(dev, locked))) {
+				++processed;
+			}
+		}
+	}
+
+	if (--expire) {
+		if (missed != atomic_read(&dma->total_missed_sched)) {
+			atomic_inc(&dma->total_lost);
+			if (gamma_dma_is_ready(dev)) goto again;
+		}
+		if (processed && gamma_dma_is_ready(dev)) {
+			atomic_inc(&dma->total_lost);
+			processed = 0;
+			goto again;
+		}
+	}
+	
+	clear_bit(0, &dev->interrupt_flag);
+	
+#if DRM_DMA_HISTOGRAM
+	atomic_inc(&dev->histo.schedule[drm_histogram_slot(get_cycles()
+							   - schedule_start)]);
+#endif
+	return retcode;
+}
+
+static int gamma_dma_priority(drm_device_t *dev, drm_dma_t *d)
+{
+	unsigned long	  address;
+	unsigned long	  length;
+	int		  must_free = 0;
+	int		  retcode   = 0;
+	int		  i;
+	int		  idx;
+	drm_buf_t	  *buf;
+	drm_buf_t	  *last_buf = NULL;
+	drm_device_dma_t  *dma	    = dev->dma;
+	DECLARE_WAITQUEUE(entry, current);
+
+				/* Turn off interrupt handling */
+	while (test_and_set_bit(0, &dev->interrupt_flag)) {
+		schedule();
+		if (signal_pending(current)) return -EINTR;
+	}
+	if (!(d->flags & _DRM_DMA_WHILE_LOCKED)) {
+		while (!drm_lock_take(&dev->lock.hw_lock->lock,
+				      DRM_KERNEL_CONTEXT)) {
+			schedule();
+			if (signal_pending(current)) {
+				clear_bit(0, &dev->interrupt_flag);
+				return -EINTR;
+			}
+		}
+		++must_free;
+	}
+	atomic_inc(&dma->total_prio);
+
+	for (i = 0; i < d->send_count; i++) {
+		idx = d->send_indices[i];
+		if (idx < 0 || idx >= dma->buf_count) {
+			DRM_ERROR("Index %d (of %d max)\n",
+				  d->send_indices[i], dma->buf_count - 1);
+			continue;
+		}
+		buf = dma->buflist[ idx ];
+		if (buf->pid != current->pid) {
+			DRM_ERROR("Process %d using buffer owned by %d\n",
+				  current->pid, buf->pid);
+			retcode = -EINVAL;
+			goto cleanup;
+		}
+		if (buf->list != DRM_LIST_NONE) {
+			DRM_ERROR("Process %d using %d's buffer on list %d\n",
+				  current->pid, buf->pid, buf->list);
+			retcode = -EINVAL;
+			goto cleanup;
+		}
+				/* This isn't a race condition on
+				   buf->list, since our concern is the
+				   buffer reclaim during the time the
+				   process closes the /dev/drm? handle, so
+				   it can't also be doing DMA. */
+		buf->list	  = DRM_LIST_PRIO;
+		buf->used	  = d->send_sizes[i];
+		buf->context	  = d->context;
+		buf->while_locked = d->flags & _DRM_DMA_WHILE_LOCKED;
+		address		  = (unsigned long)buf->address;
+		length		  = buf->used;
+		if (!length) {
+			DRM_ERROR("0 length buffer\n");
+		}
+		if (buf->pending) {
+			DRM_ERROR("Sending pending buffer:"
+				  " buffer %d, offset %d\n",
+				  d->send_indices[i], i);
+			retcode = -EINVAL;
+			goto cleanup;
+		}
+		if (buf->waiting) {
+			DRM_ERROR("Sending waiting buffer:"
+				  " buffer %d, offset %d\n",
+				  d->send_indices[i], i);
+			retcode = -EINVAL;
+			goto cleanup;
+		}
+		buf->pending = 1;
+		
+		if (dev->last_context != buf->context
+		    && !(dev->queuelist[buf->context]->flags
+			 & _DRM_CONTEXT_PRESERVED)) {
+			add_wait_queue(&dev->context_wait, &entry);
+			current->state = TASK_INTERRUPTIBLE;
+				/* PRE: dev->last_context != buf->context */
+			drm_context_switch(dev, dev->last_context,
+					   buf->context);
+				/* POST: we will wait for the context
+				   switch and will dispatch on a later call
+				   when dev->last_context = buf->context.
+				   NOTE WE HOLD THE LOCK THROUGHOUT THIS
+				   TIME! */
+			schedule();
+			current->state = TASK_RUNNING;
+			remove_wait_queue(&dev->context_wait, &entry);
+			if (signal_pending(current)) {
+				retcode = -EINTR;
+				goto cleanup;
+			}
+			if (dev->last_context != buf->context) {
+				DRM_ERROR("Context mismatch: %d %d\n",
+					  dev->last_context,
+					  buf->context);
+			}
+		}
+
+#if DRM_DMA_HISTOGRAM
+		buf->time_queued     = get_cycles();
+		buf->time_dispatched = buf->time_queued;
+#endif
+		gamma_dma_dispatch(dev, address, length);
+		atomic_add(length, &dma->total_bytes);
+		atomic_inc(&dma->total_dmas);
+		
+		if (last_buf) {
+			drm_free_buffer(dev, last_buf);
+		}
+		last_buf = buf;
+	}
+
+
+cleanup:
+	if (last_buf) {
+		gamma_dma_ready(dev);
+		drm_free_buffer(dev, last_buf);
+	}
+	
+	if (must_free && !dev->context_flag) {
+		if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+				  DRM_KERNEL_CONTEXT)) {
+			DRM_ERROR("\n");
+		}
+	}
+	clear_bit(0, &dev->interrupt_flag);
+	return retcode;
+}
+
+static int gamma_dma_send_buffers(drm_device_t *dev, drm_dma_t *d)
+{
+	DECLARE_WAITQUEUE(entry, current);
+	drm_buf_t	  *last_buf = NULL;
+	int		  retcode   = 0;
+	drm_device_dma_t  *dma	    = dev->dma;
+
+	if (d->flags & _DRM_DMA_BLOCK) {
+		last_buf = dma->buflist[d->send_indices[d->send_count-1]];
+		add_wait_queue(&last_buf->dma_wait, &entry);
+	}
+	
+	if ((retcode = drm_dma_enqueue(dev, d))) {
+		if (d->flags & _DRM_DMA_BLOCK)
+			remove_wait_queue(&last_buf->dma_wait, &entry);
+		return retcode;
+	}
+	
+	gamma_dma_schedule(dev, 0);
+	
+	if (d->flags & _DRM_DMA_BLOCK) {
+		DRM_DEBUG("%d waiting\n", current->pid);
+		for (;;) {
+			current->state = TASK_INTERRUPTIBLE;
+			if (!last_buf->waiting && !last_buf->pending)
+				break; /* finished */
+			schedule();
+			if (signal_pending(current)) {
+				retcode = -EINTR; /* Can't restart */
+				break;
+			}
+		}
+		current->state = TASK_RUNNING;
+		DRM_DEBUG("%d running\n", current->pid);
+		remove_wait_queue(&last_buf->dma_wait, &entry);
+		if (!retcode
+		    || (last_buf->list=DRM_LIST_PEND && !last_buf->pending)) {
+			if (!waitqueue_active(&last_buf->dma_wait)) {
+				drm_free_buffer(dev, last_buf);
+			}
+		}
+		if (retcode) {
+			DRM_ERROR("ctx%d w%d p%d c%d i%d l%d %d/%d\n",
+				  d->context,
+				  last_buf->waiting,
+				  last_buf->pending,
+				  DRM_WAITCOUNT(dev, d->context),
+				  last_buf->idx,
+				  last_buf->list,
+				  last_buf->pid,
+				  current->pid);
+		}
+	}
+	return retcode;
+}
+
+int gamma_dma(struct inode *inode, struct file *filp, unsigned int cmd,
+	      unsigned long arg)
+{
+	drm_file_t	  *priv	    = filp->private_data;
+	drm_device_t	  *dev	    = priv->dev;
+	drm_device_dma_t  *dma	    = dev->dma;
+	int		  retcode   = 0;
+	drm_dma_t	  d;
+
+	if (copy_from_user(&d, (drm_dma_t *)arg, sizeof(d)))
+		return -EFAULT;
+	DRM_DEBUG("%d %d: %d send, %d req\n",
+		  current->pid, d.context, d.send_count, d.request_count);
+
+	if (d.context = DRM_KERNEL_CONTEXT || d.context >= dev->queue_slots) {
+		DRM_ERROR("Process %d using context %d\n",
+			  current->pid, d.context);
+		return -EINVAL;
+	}
+	if (d.send_count < 0 || d.send_count > dma->buf_count) {
+		DRM_ERROR("Process %d trying to send %d buffers (of %d max)\n",
+			  current->pid, d.send_count, dma->buf_count);
+		return -EINVAL;
+	}
+	if (d.request_count < 0 || d.request_count > dma->buf_count) {
+		DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
+			  current->pid, d.request_count, dma->buf_count);
+		return -EINVAL;
+	}
+
+	if (d.send_count) {
+		if (d.flags & _DRM_DMA_PRIORITY)
+			retcode = gamma_dma_priority(dev, &d);
+		else 
+			retcode = gamma_dma_send_buffers(dev, &d);
+	}
+
+	d.granted_count = 0;
+
+	if (!retcode && d.request_count) {
+		retcode = drm_dma_get_buffers(dev, &d);
+	}
+
+	DRM_DEBUG("%d returning, granted = %d\n",
+		  current->pid, d.granted_count);
+	if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d)))
+		return -EFAULT;
+
+	return retcode;
+}
+
+int gamma_irq_install(drm_device_t *dev, int irq)
+{
+	int retcode;
+
+	if (!irq)     return -EINVAL;
+	
+	down(&dev->struct_sem);
+	if (dev->irq) {
+		up(&dev->struct_sem);
+		return -EBUSY;
+	}
+	dev->irq = irq;
+	up(&dev->struct_sem);
+	
+	DRM_DEBUG("%d\n", irq);
+
+	dev->context_flag     = 0;
+	dev->interrupt_flag   = 0;
+	dev->dma_flag	      = 0;
+	
+	dev->dma->next_buffer = NULL;
+	dev->dma->next_queue  = NULL;
+	dev->dma->this_buffer = NULL;
+
+	INIT_LIST_HEAD(&dev->tq.list);
+	dev->tq.sync	      = 0;
+	dev->tq.routine	      = gamma_dma_schedule_tq_wrapper;
+	dev->tq.data	      = dev;
+
+
+				/* Before installing handler */
+	GAMMA_WRITE(GAMMA_GCOMMANDMODE, 0);
+	GAMMA_WRITE(GAMMA_GDMACONTROL, 0);
+	
+				/* Install handler */
+	if ((retcode = request_irq(dev->irq,
+				   gamma_dma_service,
+				   0,
+				   dev->devname,
+				   dev))) {
+		down(&dev->struct_sem);
+		dev->irq = 0;
+		up(&dev->struct_sem);
+		return retcode;
+	}
+
+				/* After installing handler */
+	GAMMA_WRITE(GAMMA_GINTENABLE,	    0x2001);
+	GAMMA_WRITE(GAMMA_COMMANDINTENABLE, 0x0008);
+	GAMMA_WRITE(GAMMA_GDELAYTIMER,	   0x39090);
+	
+	return 0;
+}
+
+int gamma_irq_uninstall(drm_device_t *dev)
+{
+	int irq;
+
+	down(&dev->struct_sem);
+	irq	 = dev->irq;
+	dev->irq = 0;
+	up(&dev->struct_sem);
+	
+	if (!irq) return -EINVAL;
+	
+	DRM_DEBUG("%d\n", irq);
+	
+	GAMMA_WRITE(GAMMA_GDELAYTIMER,	    0);
+	GAMMA_WRITE(GAMMA_COMMANDINTENABLE, 0);
+	GAMMA_WRITE(GAMMA_GINTENABLE,	    0);
+	free_irq(irq, dev);
+
+	return 0;
+}
+
+
+int gamma_control(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_control_t	ctl;
+	int		retcode;
+	
+	if (copy_from_user(&ctl, (drm_control_t *)arg, sizeof(ctl)))
+		return -EFAULT;
+	
+	switch (ctl.func) {
+	case DRM_INST_HANDLER:
+		if ((retcode = gamma_irq_install(dev, ctl.irq)))
+			return retcode;
+		break;
+	case DRM_UNINST_HANDLER:
+		if ((retcode = gamma_irq_uninstall(dev)))
+			return retcode;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int gamma_lock(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+	DECLARE_WAITQUEUE(entry, current);
+	int		  ret	= 0;
+	drm_lock_t	  lock;
+	drm_queue_t	  *q;
+#if DRM_DMA_HISTOGRAM
+	cycles_t	  start;
+
+	dev->lck_start = start = get_cycles();
+#endif
+
+	if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
+		return -EFAULT;
+
+	if (lock.context = DRM_KERNEL_CONTEXT) {
+		DRM_ERROR("Process %d using kernel context %d\n",
+			  current->pid, lock.context);
+		return -EINVAL;
+	}
+
+	DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
+		  lock.context, current->pid, dev->lock.hw_lock->lock,
+		  lock.flags);
+
+	if (lock.context < 0 || lock.context >= dev->queue_count)
+		return -EINVAL;
+	q = dev->queuelist[lock.context];
+	
+	ret = drm_flush_block_and_flush(dev, lock.context, lock.flags);
+
+	if (!ret) {
+		if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)
+		    != lock.context) {
+			long j = jiffies - dev->lock.lock_time;
+
+			if (j > 0 && j <= DRM_LOCK_SLICE) {
+				/* Can't take lock if we just had it and
+				   there is contention. */
+				current->state = TASK_INTERRUPTIBLE;
+				schedule_timeout(j);
+			}
+		}
+		add_wait_queue(&dev->lock.lock_queue, &entry);
+		for (;;) {
+			current->state = TASK_INTERRUPTIBLE;
+			if (!dev->lock.hw_lock) {
+				/* Device has been unregistered */
+				ret = -EINTR;
+				break;
+			}
+			if (drm_lock_take(&dev->lock.hw_lock->lock,
+					  lock.context)) {
+				dev->lock.pid	    = current->pid;
+				dev->lock.lock_time = jiffies;
+				atomic_inc(&dev->total_locks);
+				atomic_inc(&q->total_locks);
+				break;	/* Got lock */
+			}
+			
+				/* Contention */
+			atomic_inc(&dev->total_sleeps);
+			schedule();
+			if (signal_pending(current)) {
+				ret = -ERESTARTSYS;
+				break;
+			}
+		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&dev->lock.lock_queue, &entry);
+	}
+
+	drm_flush_unblock(dev, lock.context, lock.flags); /* cleanup phase */
+	
+	if (!ret) {
+		sigemptyset(&dev->sigmask);
+		sigaddset(&dev->sigmask, SIGSTOP);
+		sigaddset(&dev->sigmask, SIGTSTP);
+		sigaddset(&dev->sigmask, SIGTTIN);
+		sigaddset(&dev->sigmask, SIGTTOU);
+		dev->sigdata.context = lock.context;
+		dev->sigdata.lock    = dev->lock.hw_lock;
+		block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
+
+		if (lock.flags & _DRM_LOCK_READY)
+			gamma_dma_ready(dev);
+		if (lock.flags & _DRM_LOCK_QUIESCENT) {
+			if (gamma_found() = 1) {
+				gamma_dma_quiescent_single(dev);
+			} else {
+				gamma_dma_quiescent_dual(dev);
+			}
+		}
+	}
+	DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
+
+#if DRM_DMA_HISTOGRAM
+	atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]);
+#endif
+	
+	return ret;
+}
diff -urN linux-2.4.13/drivers/char/drm-4.0/gamma_drv.c linux-2.4.13-lia/drivers/char/drm-4.0/gamma_drv.c
--- linux-2.4.13/drivers/char/drm-4.0/gamma_drv.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/gamma_drv.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,571 @@
+/* gamma.c -- 3dlabs GMX 2000 driver -*- linux-c -*-
+ * Created: Mon Jan  4 08:58:31 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#include <linux/config.h>
+#include "drmP.h"
+#include "gamma_drv.h"
+
+#ifndef PCI_DEVICE_ID_3DLABS_GAMMA
+#define PCI_DEVICE_ID_3DLABS_GAMMA 0x0008
+#endif
+#ifndef PCI_DEVICE_ID_3DLABS_MX
+#define PCI_DEVICE_ID_3DLABS_MX 0x0006
+#endif
+
+#define GAMMA_NAME	 "gamma"
+#define GAMMA_DESC	 "3dlabs GMX 2000"
+#define GAMMA_DATE	 "20000910"
+#define GAMMA_MAJOR	 1
+#define GAMMA_MINOR	 0
+#define GAMMA_PATCHLEVEL 0
+
+static drm_device_t	      gamma_device;
+
+static struct file_operations gamma_fops = {
+#if LINUX_VERSION_CODE >= 0x020400
+				/* This started being used during 2.4.0-test */
+	owner:   THIS_MODULE,
+#endif
+	open:	 gamma_open,
+	flush:	 drm_flush,
+	release: gamma_release,
+	ioctl:	 gamma_ioctl,
+	mmap:	 drm_mmap,
+	read:	 drm_read,
+	fasync:	 drm_fasync,
+	poll:	 drm_poll,
+};
+
+static struct miscdevice      gamma_misc = {
+	minor: MISC_DYNAMIC_MINOR,
+	name:  GAMMA_NAME,
+	fops:  &gamma_fops,
+};
+
+static drm_ioctl_desc_t	      gamma_ioctls[] = {
+	[DRM_IOCTL_NR(DRM_IOCTL_VERSION)]    = { gamma_version,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)]  = { drm_getmagic,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)]  = { drm_irq_busid,	  0, 1 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { drm_setunique,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_BLOCK)]	     = { drm_block,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)]    = { drm_unblock,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_CONTROL)]    = { gamma_control,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)]    = { drm_addmap,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)]   = { drm_addbufs,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)]  = { drm_markbufs,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)]  = { drm_infobufs,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)]   = { drm_mapbufs,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)]  = { drm_freebufs,	  1, 0 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)]    = { drm_addctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)]     = { drm_rmctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)]    = { drm_modctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)]    = { drm_getctx,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { drm_switchctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)]    = { drm_newctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)]    = { drm_resctx,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)]   = { drm_adddraw,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)]    = { drm_rmdraw,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_DMA)]	     = { gamma_dma,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_LOCK)]	     = { gamma_lock,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)]     = { gamma_unlock,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_FINISH)]     = { drm_finish,	  1, 0 },
+};
+#define GAMMA_IOCTL_COUNT DRM_ARRAY_SIZE(gamma_ioctls)
+
+#ifdef MODULE
+static char		      *gamma = NULL;
+#endif
+static int 		      devices = 0;
+
+MODULE_AUTHOR("VA Linux Systems, Inc.");
+MODULE_DESCRIPTION("3dlabs GMX 2000");
+MODULE_PARM(gamma, "s");
+MODULE_PARM(devices, "i");
+MODULE_PARM_DESC(devices,
+		 "devices=x, where x is the number of MX chips on card\n");
+#ifndef MODULE
+/* gamma_options is called by the kernel to parse command-line options
+ * passed via the boot-loader (e.g., LILO).  It calls the insmod option
+ * routine, drm_parse_options.
+ */
+
+
+static int __init gamma_options(char *str)
+{
+	drm_parse_options(str);
+	return 1;
+}
+
+__setup("gamma=", gamma_options);
+#endif
+
+static int gamma_setup(drm_device_t *dev)
+{
+	int i;
+
+	atomic_set(&dev->ioctl_count, 0);
+	atomic_set(&dev->vma_count, 0);
+	dev->buf_use	  = 0;
+	atomic_set(&dev->buf_alloc, 0);
+
+	drm_dma_setup(dev);
+
+	atomic_set(&dev->total_open, 0);
+	atomic_set(&dev->total_close, 0);
+	atomic_set(&dev->total_ioctl, 0);
+	atomic_set(&dev->total_irq, 0);
+	atomic_set(&dev->total_ctx, 0);
+	atomic_set(&dev->total_locks, 0);
+	atomic_set(&dev->total_unlocks, 0);
+	atomic_set(&dev->total_contends, 0);
+	atomic_set(&dev->total_sleeps, 0);
+
+	for (i = 0; i < DRM_HASH_SIZE; i++) {
+		dev->magiclist[i].head = NULL;
+		dev->magiclist[i].tail = NULL;
+	}
+	dev->maplist	    = NULL;
+	dev->map_count	    = 0;
+	dev->vmalist	    = NULL;
+	dev->lock.hw_lock   = NULL;
+	init_waitqueue_head(&dev->lock.lock_queue);
+	dev->queue_count    = 0;
+	dev->queue_reserved = 0;
+	dev->queue_slots    = 0;
+	dev->queuelist	    = NULL;
+	dev->irq	    = 0;
+	dev->context_flag   = 0;
+	dev->interrupt_flag = 0;
+	dev->dma_flag	    = 0;
+	dev->last_context   = 0;
+	dev->last_switch    = 0;
+	dev->last_checked   = 0;
+	init_timer(&dev->timer);
+	init_waitqueue_head(&dev->context_wait);
+#if DRM_DMA_HISTO
+	memset(&dev->histo, 0, sizeof(dev->histo));
+#endif
+	dev->ctx_start	    = 0;
+	dev->lck_start	    = 0;
+
+	dev->buf_rp	  = dev->buf;
+	dev->buf_wp	  = dev->buf;
+	dev->buf_end	  = dev->buf + DRM_BSZ;
+	dev->buf_async	  = NULL;
+	init_waitqueue_head(&dev->buf_readers);
+	init_waitqueue_head(&dev->buf_writers);
+
+	DRM_DEBUG("\n");
+
+	/* The kernel's context could be created here, but is now created
+	   in drm_dma_enqueue.	This is more resource-efficient for
+	   hardware that does not do DMA, but may mean that
+	   drm_select_queue fails between the time the interrupt is
+	   initialized and the time the queues are initialized. */
+
+	return 0;
+}
+
+
+static int gamma_takedown(drm_device_t *dev)
+{
+	int		  i;
+	drm_magic_entry_t *pt, *next;
+	drm_map_t	  *map;
+	drm_vma_entry_t	  *vma, *vma_next;
+
+	DRM_DEBUG("\n");
+
+	if (dev->irq) gamma_irq_uninstall(dev);
+
+	down(&dev->struct_sem);
+	del_timer(&dev->timer);
+
+	if (dev->devname) {
+		drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER);
+		dev->devname = NULL;
+	}
+
+	if (dev->unique) {
+		drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER);
+		dev->unique = NULL;
+		dev->unique_len = 0;
+	}
+				/* Clear pid list */
+	for (i = 0; i < DRM_HASH_SIZE; i++) {
+		for (pt = dev->magiclist[i].head; pt; pt = next) {
+			next = pt->next;
+			drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+		}
+		dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
+	}
+
+				/* Clear vma list (only built for debugging) */
+	if (dev->vmalist) {
+		for (vma = dev->vmalist; vma; vma = vma_next) {
+			vma_next = vma->next;
+			drm_free(vma, sizeof(*vma), DRM_MEM_VMAS);
+		}
+		dev->vmalist = NULL;
+	}
+
+				/* Clear map area and mtrr information */
+	if (dev->maplist) {
+		for (i = 0; i < dev->map_count; i++) {
+			map = dev->maplist[i];
+			switch (map->type) {
+			case _DRM_REGISTERS:
+			case _DRM_FRAME_BUFFER:
+#ifdef CONFIG_MTRR
+				if (map->mtrr >= 0) {
+					int retcode;
+					retcode = mtrr_del(map->mtrr,
+							   map->offset,
+							   map->size);
+					DRM_DEBUG("mtrr_del = %d\n", retcode);
+				}
+#endif
+				drm_ioremapfree(map->handle, map->size, dev);
+				break;
+			case _DRM_SHM:
+				drm_free_pages((unsigned long)map->handle,
+					       drm_order(map->size)
+					       - PAGE_SHIFT,
+					       DRM_MEM_SAREA);
+				break;
+			case _DRM_AGP:
+				/* Do nothing here, because this is all
+                                   handled in the AGP/GART driver. */
+				break;
+			}
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		}
+		drm_free(dev->maplist,
+			 dev->map_count * sizeof(*dev->maplist),
+			 DRM_MEM_MAPS);
+		dev->maplist   = NULL;
+		dev->map_count = 0;
+	}
+
+	if (dev->queuelist) {
+		for (i = 0; i < dev->queue_count; i++) {
+			drm_waitlist_destroy(&dev->queuelist[i]->waitlist);
+			if (dev->queuelist[i]) {
+				drm_free(dev->queuelist[i],
+					 sizeof(*dev->queuelist[0]),
+					 DRM_MEM_QUEUES);
+				dev->queuelist[i] = NULL;
+			}
+		}
+		drm_free(dev->queuelist,
+			 dev->queue_slots * sizeof(*dev->queuelist),
+			 DRM_MEM_QUEUES);
+		dev->queuelist	 = NULL;
+	}
+
+	drm_dma_takedown(dev);
+
+	dev->queue_count     = 0;
+	if (dev->lock.hw_lock) {
+		dev->lock.hw_lock    = NULL; /* SHM removed */
+		dev->lock.pid	     = 0;
+		wake_up_interruptible(&dev->lock.lock_queue);
+	}
+	up(&dev->struct_sem);
+
+	return 0;
+}
+
+int gamma_found(void)
+{
+	return devices;
+}
+
+int gamma_find_devices(void)
+{
+	struct pci_dev *d = NULL, *one = NULL, *two = NULL;
+
+	d = pci_find_device(PCI_VENDOR_ID_3DLABS,PCI_DEVICE_ID_3DLABS_GAMMA,d);
+	if (!d) return 0;
+
+	one = pci_find_device(PCI_VENDOR_ID_3DLABS,PCI_DEVICE_ID_3DLABS_MX,d);
+	if (!one) return 0;
+
+	/* Make sure it's on the same card, if not - no MX's found */
+	if (PCI_SLOT(d->devfn) != PCI_SLOT(one->devfn)) return 0;
+
+	two = pci_find_device(PCI_VENDOR_ID_3DLABS,PCI_DEVICE_ID_3DLABS_MX,one);
+	if (!two) return 1;
+
+	/* Make sure it's on the same card, if not - only 1 MX found */
+	if (PCI_SLOT(d->devfn) != PCI_SLOT(two->devfn)) return 1;
+
+	/* Two MX's found - we don't currently support more than 2 */
+	return 2;
+}
+
+/* gamma_init is called via init_module at module load time, or via
+ * linux/init/main.c (this is not currently supported). */
+
+static int __init gamma_init(void)
+{
+	int		      retcode;
+	drm_device_t	      *dev = &gamma_device;
+
+	DRM_DEBUG("\n");
+
+	memset((void *)dev, 0, sizeof(*dev));
+	dev->count_lock	  = SPIN_LOCK_UNLOCKED;
+	sema_init(&dev->struct_sem, 1);
+
+#ifdef MODULE
+	drm_parse_options(gamma);
+#endif
+	devices = gamma_find_devices();
+	if (devices = 0) return -1;
+
+	if ((retcode = misc_register(&gamma_misc))) {
+		DRM_ERROR("Cannot register \"%s\"\n", GAMMA_NAME);
+		return retcode;
+	}
+	dev->device = MKDEV(MISC_MAJOR, gamma_misc.minor);
+	dev->name   = GAMMA_NAME;
+
+	drm_mem_init();
+	drm_proc_init(dev);
+
+	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d with %d MX devices\n",
+		 GAMMA_NAME,
+		 GAMMA_MAJOR,
+		 GAMMA_MINOR,
+		 GAMMA_PATCHLEVEL,
+		 GAMMA_DATE,
+		 gamma_misc.minor,
+		 devices);
+
+	return 0;
+}
+
+/* gamma_cleanup is called via cleanup_module at module unload time. */
+
+static void __exit gamma_cleanup(void)
+{
+	drm_device_t	      *dev = &gamma_device;
+
+	DRM_DEBUG("\n");
+
+	drm_proc_cleanup();
+	if (misc_deregister(&gamma_misc)) {
+		DRM_ERROR("Cannot unload module\n");
+	} else {
+		DRM_INFO("Module unloaded\n");
+	}
+	gamma_takedown(dev);
+}
+
+module_init(gamma_init);
+module_exit(gamma_cleanup);
+
+
+int gamma_version(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_version_t version;
+	int	      len;
+
+	if (copy_from_user(&version,
+			   (drm_version_t *)arg,
+			   sizeof(version)))
+		return -EFAULT;
+
+#define DRM_COPY(name,value)				     \
+	len = strlen(value);				     \
+	if (len > name##_len) len = name##_len;		     \
+	name##_len = strlen(value);			     \
+	if (len && name) {				     \
+		if (copy_to_user(name, value, len))	     \
+			return -EFAULT;			     \
+	}
+
+	version.version_major	   = GAMMA_MAJOR;
+	version.version_minor	   = GAMMA_MINOR;
+	version.version_patchlevel = GAMMA_PATCHLEVEL;
+
+	DRM_COPY(version.name, GAMMA_NAME);
+	DRM_COPY(version.date, GAMMA_DATE);
+	DRM_COPY(version.desc, GAMMA_DESC);
+
+	if (copy_to_user((drm_version_t *)arg,
+			 &version,
+			 sizeof(version)))
+		return -EFAULT;
+	return 0;
+}
+
+int gamma_open(struct inode *inode, struct file *filp)
+{
+	drm_device_t  *dev    = &gamma_device;
+	int	      retcode = 0;
+
+	DRM_DEBUG("open_count = %d\n", dev->open_count);
+	if (!(retcode = drm_open_helper(inode, filp, dev))) {
+#if LINUX_VERSION_CODE < 0x020333
+		MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
+		atomic_inc(&dev->total_open);
+		spin_lock(&dev->count_lock);
+		if (!dev->open_count++) {
+			spin_unlock(&dev->count_lock);
+			return gamma_setup(dev);
+		}
+		spin_unlock(&dev->count_lock);
+	}
+	return retcode;
+}
+
+int gamma_release(struct inode *inode, struct file *filp)
+{
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev;
+	int	      retcode = 0;
+
+	lock_kernel();
+	dev = priv->dev;
+
+	DRM_DEBUG("open_count = %d\n", dev->open_count);
+	if (!(retcode = drm_release(inode, filp))) {
+#if LINUX_VERSION_CODE < 0x020333
+		MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
+		atomic_inc(&dev->total_close);
+		spin_lock(&dev->count_lock);
+		if (!--dev->open_count) {
+			if (atomic_read(&dev->ioctl_count) || dev->blocked) {
+				DRM_ERROR("Device busy: %d %d\n",
+					  atomic_read(&dev->ioctl_count),
+					  dev->blocked);
+				spin_unlock(&dev->count_lock);
+				unlock_kernel();
+				return -EBUSY;
+			}
+			spin_unlock(&dev->count_lock);
+			unlock_kernel();
+			return gamma_takedown(dev);
+		}
+		spin_unlock(&dev->count_lock);
+	}
+	unlock_kernel();
+	return retcode;
+}
+
+/* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. */
+
+int gamma_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	int		 nr	 = DRM_IOCTL_NR(cmd);
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	int		 retcode = 0;
+	drm_ioctl_desc_t *ioctl;
+	drm_ioctl_t	 *func;
+
+	atomic_inc(&dev->ioctl_count);
+	atomic_inc(&dev->total_ioctl);
+	++priv->ioctl_count;
+
+	DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n",
+		  current->pid, cmd, nr, dev->device, priv->authenticated);
+
+	if (nr >= GAMMA_IOCTL_COUNT) {
+		retcode = -EINVAL;
+	} else {
+		ioctl	  = &gamma_ioctls[nr];
+		func	  = ioctl->func;
+
+		if (!func) {
+			DRM_DEBUG("no function\n");
+			retcode = -EINVAL;
+		} else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN))
+			    || (ioctl->auth_needed && !priv->authenticated)) {
+			retcode = -EACCES;
+		} else {
+			retcode = (func)(inode, filp, cmd, arg);
+		}
+	}
+
+	atomic_dec(&dev->ioctl_count);
+	return retcode;
+}
+
+
+int gamma_unlock(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+	drm_lock_t	  lock;
+
+	if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
+		return -EFAULT;
+
+	if (lock.context = DRM_KERNEL_CONTEXT) {
+		DRM_ERROR("Process %d using kernel context %d\n",
+			  current->pid, lock.context);
+		return -EINVAL;
+	}
+
+	DRM_DEBUG("%d frees lock (%d holds)\n",
+		  lock.context,
+		  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+	atomic_inc(&dev->total_unlocks);
+	if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock))
+		atomic_inc(&dev->total_contends);
+	drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT);
+	gamma_dma_schedule(dev, 1);
+	if (!dev->context_flag) {
+		if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+				  DRM_KERNEL_CONTEXT)) {
+			DRM_ERROR("\n");
+		}
+	}
+#if DRM_DMA_HISTOGRAM
+	atomic_inc(&dev->histo.lhld[drm_histogram_slot(get_cycles()
+						       - dev->lck_start)]);
+#endif
+
+	unblock_all_signals();
+	return 0;
+}
diff -urN linux-2.4.13/drivers/char/drm-4.0/gamma_drv.h linux-2.4.13-lia/drivers/char/drm-4.0/gamma_drv.h
--- linux-2.4.13/drivers/char/drm-4.0/gamma_drv.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/gamma_drv.h	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,58 @@
+/* gamma_drv.h -- Private header for 3dlabs GMX 2000 driver -*- linux-c -*-
+ * Created: Mon Jan  4 10:05:05 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ * 
+ */
+
+#ifndef _GAMMA_DRV_H_
+#define _GAMMA_DRV_H_
+
+				/* gamma_drv.c */
+extern int  gamma_version(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int  gamma_open(struct inode *inode, struct file *filp);
+extern int  gamma_release(struct inode *inode, struct file *filp);
+extern int  gamma_ioctl(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int  gamma_lock(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  gamma_unlock(struct inode *inode, struct file *filp,
+			 unsigned int cmd, unsigned long arg);
+
+				/* gamma_dma.c */
+extern int  gamma_dma_schedule(drm_device_t *dev, int locked);
+extern int  gamma_dma(struct inode *inode, struct file *filp,
+		      unsigned int cmd, unsigned long arg);
+extern int  gamma_irq_install(drm_device_t *dev, int irq);
+extern int  gamma_irq_uninstall(drm_device_t *dev);
+extern int  gamma_control(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int  gamma_find_devices(void);
+extern int  gamma_found(void);
+
+#endif
diff -urN linux-2.4.13/drivers/char/drm-4.0/i810_bufs.c linux-2.4.13-lia/drivers/char/drm-4.0/i810_bufs.c
--- linux-2.4.13/drivers/char/drm-4.0/i810_bufs.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/i810_bufs.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,339 @@
+/* i810_bufs.c -- IOCTLs to manage buffers -*- linux-c -*-
+ * Created: Thu Jan 6 01:47:26 2000 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ *	    Jeff Hartmann <jhartmann@valinux.com>
+ * 
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "i810_drv.h"
+#include "linux/un.h"
+
+int i810_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
+		    unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_device_dma_t *dma = dev->dma;
+	drm_buf_desc_t request;
+	drm_buf_entry_t *entry;
+	drm_buf_t *buf;
+	unsigned long offset;
+	unsigned long agp_offset;
+	int count;
+	int order;
+	int size;
+	int alignment;
+	int page_order;
+	int total;
+	int byte_count;
+	int i;
+
+	if (!dma) return -EINVAL;
+
+	if (copy_from_user(&request,
+			   (drm_buf_desc_t *)arg,
+			   sizeof(request)))
+		return -EFAULT;
+
+	count = request.count;
+	order = drm_order(request.size);
+	size	= 1 << order;
+	agp_offset = request.agp_start;
+	alignment  = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size) :size;
+	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
+	total = PAGE_SIZE << page_order;
+	byte_count = 0;
+   
+	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
+	if (dev->queue_count) return -EBUSY; /* Not while in use */
+	spin_lock(&dev->count_lock);
+	if (dev->buf_use) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	atomic_inc(&dev->buf_alloc);
+	spin_unlock(&dev->count_lock);
+   
+	down(&dev->struct_sem);
+	entry = &dma->bufs[order];
+	if (entry->buf_count) {
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM; /* May only call once for each order */
+	}
+
+	if(count < 0 || count > 4096)
+	{
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -EINVAL;
+	}
+	   
+	entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
+				   DRM_MEM_BUFS);
+	if (!entry->buflist) {
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM;
+	}
+	memset(entry->buflist, 0, count * sizeof(*entry->buflist));
+   
+	entry->buf_size   = size;
+	entry->page_order = page_order;
+	offset = 0;
+   
+	while(entry->buf_count < count) {
+		buf = &entry->buflist[entry->buf_count];
+		buf->idx = dma->buf_count + entry->buf_count;
+		buf->total = alignment;
+		buf->order = order;
+		buf->used = 0;
+		buf->offset = offset;
+		buf->bus_address = dev->agp->base + agp_offset + offset;
+		buf->address = (void *)(agp_offset + offset + dev->agp->base);
+		buf->next = NULL;
+		buf->waiting = 0;
+		buf->pending = 0;
+		init_waitqueue_head(&buf->dma_wait);
+		buf->pid = 0;
+
+		buf->dev_private = drm_alloc(sizeof(drm_i810_buf_priv_t), 
+					     DRM_MEM_BUFS);
+		buf->dev_priv_size = sizeof(drm_i810_buf_priv_t);
+	   	memset(buf->dev_private, 0, sizeof(drm_i810_buf_priv_t));
+
+#if DRM_DMA_HISTOGRAM
+		buf->time_queued = 0;
+		buf->time_dispatched = 0;
+		buf->time_completed = 0;
+		buf->time_freed = 0;
+#endif
+		offset = offset + alignment;
+		entry->buf_count++;
+		byte_count += PAGE_SIZE << page_order;
+      
+		DRM_DEBUG("buffer %d @ %p\n",
+			  entry->buf_count, buf->address);
+	}
+   
+	dma->buflist = drm_realloc(dma->buflist,
+				   dma->buf_count * sizeof(*dma->buflist),
+				   (dma->buf_count + entry->buf_count)
+				   * sizeof(*dma->buflist),
+				   DRM_MEM_BUFS);
+	for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++)
+		dma->buflist[i] = &entry->buflist[i - dma->buf_count];
+   
+	dma->buf_count  += entry->buf_count;
+	dma->byte_count += byte_count;
+	drm_freelist_create(&entry->freelist, entry->buf_count);
+	for (i = 0; i < entry->buf_count; i++) {
+		drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]);
+	}
+   
+	up(&dev->struct_sem);
+   
+	request.count = entry->buf_count;
+	request.size  = size;
+   
+	if (copy_to_user((drm_buf_desc_t *)arg,
+			 &request,
+			 sizeof(request)))
+		return -EFAULT;
+   
+	atomic_dec(&dev->buf_alloc);
+	dma->flags = _DRM_DMA_USE_AGP;
+	return 0;
+}
+
+int i810_addbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_buf_desc_t	 request;
+
+	if (copy_from_user(&request,
+			   (drm_buf_desc_t *)arg,
+			   sizeof(request)))
+		return -EFAULT;
+
+	if(request.flags & _DRM_AGP_BUFFER)
+		return i810_addbufs_agp(inode, filp, cmd, arg);
+	else
+		return -EINVAL;
+}
+
+int i810_infobufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_info_t	 request;
+	int		 i;
+	int		 count;
+
+	if (!dma) return -EINVAL;
+
+	spin_lock(&dev->count_lock);
+	if (atomic_read(&dev->buf_alloc)) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	++dev->buf_use;		/* Can't allocate more after this call */
+	spin_unlock(&dev->count_lock);
+
+	if (copy_from_user(&request,
+			   (drm_buf_info_t *)arg,
+			   sizeof(request)))
+		return -EFAULT;
+
+	for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
+		if (dma->bufs[i].buf_count) ++count;
+	}
+	
+	DRM_DEBUG("count = %d\n", count);
+	
+	if (request.count >= count) {
+		for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
+			if (dma->bufs[i].buf_count) {
+				if (copy_to_user(&request.list[count].count,
+						 &dma->bufs[i].buf_count,
+						 sizeof(dma->bufs[0]
+							.buf_count)) ||
+				    copy_to_user(&request.list[count].size,
+						 &dma->bufs[i].buf_size,
+						 sizeof(dma->bufs[0].buf_size)) ||
+				    copy_to_user(&request.list[count].low_mark,
+						 &dma->bufs[i]
+						 .freelist.low_mark,
+						 sizeof(dma->bufs[0]
+							.freelist.low_mark)) ||
+				    copy_to_user(&request.list[count]
+						 .high_mark,
+						 &dma->bufs[i]
+						 .freelist.high_mark,
+						 sizeof(dma->bufs[0]
+							.freelist.high_mark)))
+					return -EFAULT;
+
+				DRM_DEBUG("%d %d %d %d %d\n",
+					  i,
+					  dma->bufs[i].buf_count,
+					  dma->bufs[i].buf_size,
+					  dma->bufs[i].freelist.low_mark,
+					  dma->bufs[i].freelist.high_mark);
+				++count;
+			}
+		}
+	}
+	request.count = count;
+
+	if (copy_to_user((drm_buf_info_t *)arg,
+			 &request,
+			 sizeof(request)))
+		return -EFAULT;
+	
+	return 0;
+}
+
+int i810_markbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_desc_t	 request;
+	int		 order;
+	drm_buf_entry_t	 *entry;
+
+	if (!dma) return -EINVAL;
+
+	if (copy_from_user(&request,
+			   (drm_buf_desc_t *)arg,
+			   sizeof(request)))
+		return -EFAULT;
+
+	DRM_DEBUG("%d, %d, %d\n",
+		  request.size, request.low_mark, request.high_mark);
+	order = drm_order(request.size);
+	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
+	entry = &dma->bufs[order];
+
+	if (request.low_mark < 0 || request.low_mark > entry->buf_count)
+		return -EINVAL;
+	if (request.high_mark < 0 || request.high_mark > entry->buf_count)
+		return -EINVAL;
+
+	entry->freelist.low_mark  = request.low_mark;
+	entry->freelist.high_mark = request.high_mark;
+	
+	return 0;
+}
+
+int i810_freebufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_free_t	 request;
+	int		 i;
+	int		 idx;
+	drm_buf_t	 *buf;
+
+	if (!dma) return -EINVAL;
+
+	if (copy_from_user(&request,
+			   (drm_buf_free_t *)arg,
+			   sizeof(request)))
+		return -EFAULT;
+
+	DRM_DEBUG("%d\n", request.count);
+	for (i = 0; i < request.count; i++) {
+		if (copy_from_user(&idx,
+				   &request.list[i],
+				   sizeof(idx)))
+			return -EFAULT;
+		if (idx < 0 || idx >= dma->buf_count) {
+			DRM_ERROR("Index %d (of %d max)\n",
+				  idx, dma->buf_count - 1);
+			return -EINVAL;
+		}
+		buf = dma->buflist[idx];
+		if (buf->pid != current->pid) {
+			DRM_ERROR("Process %d freeing buffer owned by %d\n",
+				  current->pid, buf->pid);
+			return -EINVAL;
+		}
+		drm_free_buffer(dev, buf);
+	}
+	
+	return 0;
+}
+
diff -urN linux-2.4.13/drivers/char/drm-4.0/i810_context.c linux-2.4.13-lia/drivers/char/drm-4.0/i810_context.c
--- linux-2.4.13/drivers/char/drm-4.0/i810_context.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/i810_context.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,212 @@
+/* i810_context.c -- IOCTLs for i810 contexts -*- linux-c -*-
+ * Created: Mon Dec 13 09:51:35 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ *	    Jeff Hartmann <jhartmann@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "i810_drv.h"
+
+static int i810_alloc_queue(drm_device_t *dev)
+{
+   	int temp = drm_ctxbitmap_next(dev);
+   	DRM_DEBUG("i810_alloc_queue: %d\n", temp);
+	return temp;
+}
+
+int i810_context_switch(drm_device_t *dev, int old, int new)
+{
+        char        buf[64];
+
+        atomic_inc(&dev->total_ctx);
+
+        if (test_and_set_bit(0, &dev->context_flag)) {
+                DRM_ERROR("Reentering -- FIXME\n");
+                return -EBUSY;
+        }
+
+#if DRM_DMA_HISTOGRAM
+        dev->ctx_start = get_cycles();
+#endif
+        
+        DRM_DEBUG("Context switch from %d to %d\n", old, new);
+
+        if (new = dev->last_context) {
+                clear_bit(0, &dev->context_flag);
+                return 0;
+        }
+        
+        if (drm_flags & DRM_FLAG_NOCTX) {
+                i810_context_switch_complete(dev, new);
+        } else {
+                sprintf(buf, "C %d %d\n", old, new);
+                drm_write_string(dev, buf);
+        }
+        
+        return 0;
+}
+
+int i810_context_switch_complete(drm_device_t *dev, int new)
+{
+        dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */
+        dev->last_switch  = jiffies;
+        
+        if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+                DRM_ERROR("Lock isn't held after context switch\n");
+        }
+
+				/* If a context switch is ever initiated
+                                   when the kernel holds the lock, release
+                                   that lock here. */
+#if DRM_DMA_HISTOGRAM
+        atomic_inc(&dev->histo.ctx[drm_histogram_slot(get_cycles()
+                                                      - dev->ctx_start)]);
+                   
+#endif
+        clear_bit(0, &dev->context_flag);
+        wake_up(&dev->context_wait);
+        
+        return 0;
+}
+
+int i810_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_ctx_res_t	res;
+	drm_ctx_t	ctx;
+	int		i;
+
+	DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
+	if (copy_from_user(&res, (drm_ctx_res_t *)arg, sizeof(res)))
+		return -EFAULT;
+	if (res.count >= DRM_RESERVED_CONTEXTS) {
+		memset(&ctx, 0, sizeof(ctx));
+		for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+			ctx.handle = i;
+			if (copy_to_user(&res.contexts[i],
+					 &i,
+					 sizeof(i)))
+				return -EFAULT;
+		}
+	}
+	res.count = DRM_RESERVED_CONTEXTS;
+	if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res)))
+		return -EFAULT;
+	return 0;
+}
+
+int i810_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+		return -EFAULT;
+	if ((ctx.handle = i810_alloc_queue(dev)) = DRM_KERNEL_CONTEXT) {
+				/* Skip kernel's context and get a new one. */
+		ctx.handle = i810_alloc_queue(dev);
+	}
+        if (ctx.handle = -1) {
+		DRM_DEBUG("Not enough free contexts.\n");
+				/* Should this return -EBUSY instead? */
+		return -ENOMEM;
+	}
+	DRM_DEBUG("%d\n", ctx.handle);
+	if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx)))
+		return -EFAULT;
+	return 0;
+}
+
+int i810_modctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	unsigned long arg)
+{
+   	/* This does nothing for the i810 */
+	return 0;
+}
+
+int i810_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	unsigned long arg)
+{
+	drm_ctx_t ctx;
+
+	if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx)))
+		return -EFAULT;
+	/* This is 0, because we don't hanlde any context flags */
+	ctx.flags = 0;
+	if (copy_to_user((drm_ctx_t*)arg, &ctx, sizeof(ctx)))
+		return -EFAULT;
+	return 0;
+}
+
+int i810_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
+		   unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+		return -EFAULT;
+	DRM_DEBUG("%d\n", ctx.handle);
+	return i810_context_switch(dev, dev->last_context, ctx.handle);
+}
+
+int i810_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+		return -EFAULT;
+	DRM_DEBUG("%d\n", ctx.handle);
+	i810_context_switch_complete(dev, ctx.handle);
+
+	return 0;
+}
+
+int i810_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	      unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+		return -EFAULT;
+	DRM_DEBUG("%d\n", ctx.handle);
+   	if(ctx.handle != DRM_KERNEL_CONTEXT) {
+	   	drm_ctxbitmap_free(dev, ctx.handle);
+	}
+	
+	return 0;
+}
diff -urN linux-2.4.13/drivers/char/drm-4.0/i810_dma.c linux-2.4.13-lia/drivers/char/drm-4.0/i810_dma.c
--- linux-2.4.13/drivers/char/drm-4.0/i810_dma.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/i810_dma.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,1438 @@
+/* i810_dma.c -- DMA support for the i810 -*- linux-c -*-
+ * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ *	    Jeff Hartmann <jhartmann@valinux.com>
+ *          Keith Whitwell <keithw@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "i810_drv.h"
+#include <linux/interrupt.h>	/* For task queue support */
+
+/* in case we don't have a 2.3.99-pre6 kernel or later: */
+#ifndef VM_DONTCOPY
+#define VM_DONTCOPY 0
+#endif
+
+#define I810_BUF_FREE		2
+#define I810_BUF_CLIENT		1
+#define I810_BUF_HARDWARE      	0
+
+#define I810_BUF_UNMAPPED 0
+#define I810_BUF_MAPPED   1
+
+#define I810_REG(reg)		2
+#define I810_BASE(reg)		((unsigned long) \
+				dev->maplist[I810_REG(reg)]->handle)
+#define I810_ADDR(reg)		(I810_BASE(reg) + reg)
+#define I810_DEREF(reg)		*(__volatile__ int *)I810_ADDR(reg)
+#define I810_READ(reg)		I810_DEREF(reg)
+#define I810_WRITE(reg,val) 	do { I810_DEREF(reg) = val; } while (0)
+#define I810_DEREF16(reg)	*(__volatile__ u16 *)I810_ADDR(reg)
+#define I810_READ16(reg)	I810_DEREF16(reg)
+#define I810_WRITE16(reg,val)	do { I810_DEREF16(reg) = val; } while (0)
+
+#define RING_LOCALS	unsigned int outring, ringmask; volatile char *virt;
+
+#define BEGIN_LP_RING(n) do {				\
+	if (I810_VERBOSE)				\
+		DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n",	\
+			  n, __FUNCTION__);		\
+	if (dev_priv->ring.space < n*4) 		\
+		i810_wait_ring(dev, n*4);		\
+	dev_priv->ring.space -= n*4;			\
+	outring = dev_priv->ring.tail;			\
+	ringmask = dev_priv->ring.tail_mask;		\
+	virt = dev_priv->ring.virtual_start;		\
+} while (0)
+
+#define ADVANCE_LP_RING() do {					\
+	if (I810_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n");	\
+	dev_priv->ring.tail = outring;				\
+	I810_WRITE(LP_RING + RING_TAIL, outring);		\
+} while(0)
+
+#define OUT_RING(n) do {						\
+	if (I810_VERBOSE) DRM_DEBUG("   OUT_RING %x\n", (int)(n));	\
+	*(volatile unsigned int *)(virt + outring) = n;			\
+	outring += 4;							\
+	outring &= ringmask;						\
+} while (0);
+
+static inline void i810_print_status_page(drm_device_t *dev)
+{
+   	drm_device_dma_t *dma = dev->dma;
+      	drm_i810_private_t *dev_priv = dev->dev_private;
+	u32 *temp = (u32 *)dev_priv->hw_status_page;
+   	int i;
+
+   	DRM_DEBUG(  "hw_status: Interrupt Status : %x\n", temp[0]);
+   	DRM_DEBUG(  "hw_status: LpRing Head ptr : %x\n", temp[1]);
+   	DRM_DEBUG(  "hw_status: IRing Head ptr : %x\n", temp[2]);
+      	DRM_DEBUG(  "hw_status: Reserved : %x\n", temp[3]);
+   	DRM_DEBUG(  "hw_status: Driver Counter : %d\n", temp[5]);
+   	for(i = 6; i < dma->buf_count + 6; i++) {
+	   	DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 6, temp[i]);
+	}
+}
+
+static drm_buf_t *i810_freelist_get(drm_device_t *dev)
+{
+   	drm_device_dma_t *dma = dev->dma;
+	int		 i;
+   	int 		 used;
+   
+	/* Linear search might not be the best solution */
+
+   	for (i = 0; i < dma->buf_count; i++) {
+	   	drm_buf_t *buf = dma->buflist[ i ];
+	   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+		/* In use is already a pointer */
+	   	used = cmpxchg(buf_priv->in_use, I810_BUF_FREE, 
+			       I810_BUF_CLIENT);
+	   	if(used = I810_BUF_FREE) {
+			return buf;
+		}
+	}
+   	return NULL;
+}
+
+/* This should only be called if the buffer is not sent to the hardware
+ * yet, the hardware updates in use for us once its on the ring buffer.
+ */
+
+static int i810_freelist_put(drm_device_t *dev, drm_buf_t *buf)
+{
+   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+   	int used;
+   
+   	/* In use is already a pointer */
+   	used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_FREE);
+   	if(used != I810_BUF_CLIENT) {
+	   	DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx);
+	   	return -EINVAL;
+	}
+   
+   	return 0;
+}
+
+static struct file_operations i810_buffer_fops = {
+	open:	 i810_open,
+	flush:	 drm_flush,
+	release: i810_release,
+	ioctl:	 i810_ioctl,
+	mmap:	 i810_mmap_buffers,
+	read:	 drm_read,
+	fasync:	 drm_fasync,
+      	poll:	 drm_poll,
+};
+
+int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
+{
+	drm_file_t	    *priv	  = filp->private_data;
+	drm_device_t	    *dev;
+	drm_i810_private_t  *dev_priv;
+	drm_buf_t           *buf;
+	drm_i810_buf_priv_t *buf_priv;
+
+	lock_kernel();
+	dev	 = priv->dev;
+	dev_priv = dev->dev_private;
+	buf      = dev_priv->mmap_buffer;
+	buf_priv = buf->dev_private;
+   
+	vma->vm_flags |= (VM_IO | VM_DONTCOPY);
+	vma->vm_file = filp;
+   
+   	buf_priv->currently_mapped = I810_BUF_MAPPED;
+	unlock_kernel();
+
+	if (remap_page_range(vma->vm_start,
+			     VM_OFFSET(vma),
+			     vma->vm_end - vma->vm_start,
+			     vma->vm_page_prot)) return -EAGAIN;
+	return 0;
+}
+
+static int i810_map_buffer(drm_buf_t *buf, struct file *filp)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+      	drm_i810_private_t *dev_priv = dev->dev_private;
+   	struct file_operations *old_fops;
+	int retcode = 0;
+
+	if(buf_priv->currently_mapped = I810_BUF_MAPPED) return -EINVAL;
+
+	if(VM_DONTCOPY != 0) {
+		down_write(&current->mm->mmap_sem);
+		old_fops = filp->f_op;
+		filp->f_op = &i810_buffer_fops;
+		dev_priv->mmap_buffer = buf;
+		buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total, 
+						    PROT_READ|PROT_WRITE,
+						    MAP_SHARED, 
+						    buf->bus_address);
+		dev_priv->mmap_buffer = NULL;
+   		filp->f_op = old_fops;
+		if ((unsigned long)buf_priv->virtual > -1024UL) {
+			/* Real error */
+			DRM_DEBUG("mmap error\n");
+			retcode = (signed int)buf_priv->virtual;
+			buf_priv->virtual = 0;
+		}
+   		up_write(&current->mm->mmap_sem);
+	} else {
+		buf_priv->virtual = buf_priv->kernel_virtual;
+   		buf_priv->currently_mapped = I810_BUF_MAPPED;
+	}
+	return retcode;
+}
+
+static int i810_unmap_buffer(drm_buf_t *buf)
+{
+	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+	int retcode = 0;
+
+	if(VM_DONTCOPY != 0) {
+		if(buf_priv->currently_mapped != I810_BUF_MAPPED) 
+			return -EINVAL;
+		down_write(&current->mm->mmap_sem);
+#if LINUX_VERSION_CODE < 0x020399
+        	retcode = do_munmap((unsigned long)buf_priv->virtual, 
+				    (size_t) buf->total);
+#else
+        	retcode = do_munmap(current->mm, 
+				    (unsigned long)buf_priv->virtual, 
+				    (size_t) buf->total);
+#endif
+   		up_write(&current->mm->mmap_sem);
+	}
+   	buf_priv->currently_mapped = I810_BUF_UNMAPPED;
+   	buf_priv->virtual = 0;
+
+	return retcode;
+}
+
+static int i810_dma_get_buffer(drm_device_t *dev, drm_i810_dma_t *d, 
+			       struct file *filp)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_buf_t	  *buf;
+	drm_i810_buf_priv_t *buf_priv;
+	int retcode = 0;
+
+	buf = i810_freelist_get(dev);
+	if (!buf) {
+		retcode = -ENOMEM;
+	   	DRM_DEBUG("retcode=%d\n", retcode);
+		return retcode;
+	}
+   
+	retcode = i810_map_buffer(buf, filp);
+	if(retcode) {
+		i810_freelist_put(dev, buf);
+	   	DRM_DEBUG("mapbuf failed, retcode %d\n", retcode);
+		return retcode;
+	}
+	buf->pid     = priv->pid;
+	buf_priv = buf->dev_private;	
+	d->granted = 1;
+   	d->request_idx = buf->idx;
+   	d->request_size = buf->total;
+   	d->virtual = buf_priv->virtual;
+
+	return retcode;
+}
+
+static unsigned long i810_alloc_page(drm_device_t *dev)
+{
+	unsigned long address;
+   
+	address = __get_free_page(GFP_KERNEL);
+	if(address = 0UL) 
+		return 0;
+	
+	atomic_inc(&virt_to_page(address)->count);
+	set_bit(PG_locked, &virt_to_page(address)->flags);
+   
+	return address;
+}
+
+static void i810_free_page(drm_device_t *dev, unsigned long page)
+{
+	if(page = 0UL) 
+		return;
+	
+	atomic_dec(&virt_to_page(page)->count);
+	clear_bit(PG_locked, &virt_to_page(page)->flags);
+	wake_up(&virt_to_page(page)->wait);
+	free_page(page);
+	return;
+}
+
+static int i810_dma_cleanup(drm_device_t *dev)
+{
+	drm_device_dma_t *dma = dev->dma;
+
+	if(dev->dev_private) {
+		int i;
+	   	drm_i810_private_t *dev_priv = 
+	     		(drm_i810_private_t *) dev->dev_private;
+	   
+	   	if(dev_priv->ring.virtual_start) {
+		   	drm_ioremapfree((void *) dev_priv->ring.virtual_start,
+					dev_priv->ring.Size, dev);
+		}
+	   	if(dev_priv->hw_status_page != 0UL) {
+		   	i810_free_page(dev, dev_priv->hw_status_page);
+		   	/* Need to rewrite hardware status page */
+		   	I810_WRITE(0x02080, 0x1ffff000);
+		}
+	   	drm_free(dev->dev_private, sizeof(drm_i810_private_t), 
+			 DRM_MEM_DRIVER);
+	   	dev->dev_private = NULL;
+
+		for (i = 0; i < dma->buf_count; i++) {
+			drm_buf_t *buf = dma->buflist[ i ];
+			drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+			drm_ioremapfree(buf_priv->kernel_virtual,
+							buf->total, dev);
+		}
+	}
+   	return 0;
+}
+
+static int i810_wait_ring(drm_device_t *dev, int n)
+{
+   	drm_i810_private_t *dev_priv = dev->dev_private;
+   	drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
+   	int iters = 0;
+   	unsigned long end;
+	unsigned int last_head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+
+	end = jiffies + (HZ*3);
+   	while (ring->space < n) {
+	   	int i;
+	
+	   	ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+	   	ring->space = ring->head - (ring->tail+8);
+		if (ring->space < 0) ring->space += ring->Size;
+	   
+		if (ring->head != last_head)
+		   end = jiffies + (HZ*3);
+	  
+	   	iters++;
+		if((signed)(end - jiffies) <= 0) {
+		   	DRM_ERROR("space: %d wanted %d\n", ring->space, n);
+		   	DRM_ERROR("lockup\n");
+		   	goto out_wait_ring;
+		}
+
+	   	for (i = 0 ; i < 2000 ; i++) ;
+	}
+
+out_wait_ring:   
+   	return iters;
+}
+
+static void i810_kernel_lost_context(drm_device_t *dev)
+{
+      	drm_i810_private_t *dev_priv = dev->dev_private;
+   	drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
+      
+   	ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+     	ring->tail = I810_READ(LP_RING + RING_TAIL);
+     	ring->space = ring->head - (ring->tail+8);
+     	if (ring->space < 0) ring->space += ring->Size;
+}
+
+static int i810_freelist_init(drm_device_t *dev)
+{
+      	drm_device_dma_t *dma = dev->dma;
+   	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+   	int my_idx = 24;
+   	u32 *hw_status = (u32 *)(dev_priv->hw_status_page + my_idx);
+   	int i;
+   
+   	if(dma->buf_count > 1019) {
+	   	/* Not enough space in the status page for the freelist */
+	   	return -EINVAL;
+	}
+
+   	for (i = 0; i < dma->buf_count; i++) {
+	   	drm_buf_t *buf = dma->buflist[ i ];
+	   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+	   
+	   	buf_priv->in_use = hw_status++;
+	   	buf_priv->my_use_idx = my_idx;
+	   	my_idx += 4;
+
+	   	*buf_priv->in_use = I810_BUF_FREE;
+
+		buf_priv->kernel_virtual = drm_ioremap(buf->bus_address, 
+						       buf->total, dev);
+	}
+	return 0;
+}
+
+static int i810_dma_initialize(drm_device_t *dev, 
+			       drm_i810_private_t *dev_priv,
+			       drm_i810_init_t *init)
+{
+	drm_map_t *sarea_map;
+
+   	dev->dev_private = (void *) dev_priv;
+   	memset(dev_priv, 0, sizeof(drm_i810_private_t));
+
+   	if (init->ring_map_idx >= dev->map_count ||
+	    init->buffer_map_idx >= dev->map_count) {
+	   	i810_dma_cleanup(dev);
+	   	DRM_ERROR("ring_map or buffer_map are invalid\n");
+	   	return -EINVAL;
+	}
+   
+   	dev_priv->ring_map_idx = init->ring_map_idx;
+   	dev_priv->buffer_map_idx = init->buffer_map_idx;
+	sarea_map = dev->maplist[0];
+	dev_priv->sarea_priv = (drm_i810_sarea_t *) 
+		((u8 *)sarea_map->handle + 
+		 init->sarea_priv_offset);
+
+   	atomic_set(&dev_priv->flush_done, 0);
+	init_waitqueue_head(&dev_priv->flush_queue);
+   	
+   	dev_priv->ring.Start = init->ring_start;
+   	dev_priv->ring.End = init->ring_end;
+   	dev_priv->ring.Size = init->ring_size;
+
+   	dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base + 
+						   init->ring_start, 
+						   init->ring_size, dev);
+
+   	dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
+   
+   	if (dev_priv->ring.virtual_start = NULL) {
+	   	i810_dma_cleanup(dev);
+	   	DRM_ERROR("can not ioremap virtual address for"
+			  " ring buffer\n");
+	   	return -ENOMEM;
+	}
+
+	dev_priv->w = init->w;
+	dev_priv->h = init->h;
+	dev_priv->pitch = init->pitch;
+	dev_priv->back_offset = init->back_offset;
+	dev_priv->depth_offset = init->depth_offset;
+
+	dev_priv->front_di1 = init->front_offset | init->pitch_bits;
+	dev_priv->back_di1 = init->back_offset | init->pitch_bits;
+	dev_priv->zi1 = init->depth_offset | init->pitch_bits;
+	
+   
+   	/* Program Hardware Status Page */
+   	dev_priv->hw_status_page = i810_alloc_page(dev);
+   	memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE);
+   	if(dev_priv->hw_status_page = 0UL) {
+		i810_dma_cleanup(dev);
+		DRM_ERROR("Can not allocate hardware status page\n");
+		return -ENOMEM;
+	}
+   	DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page);
+   
+   	I810_WRITE(0x02080, virt_to_bus((void *)dev_priv->hw_status_page));
+   	DRM_DEBUG("Enabled hardware status page\n");
+   
+   	/* Now we need to init our freelist */
+   	if(i810_freelist_init(dev) != 0) {
+	   	i810_dma_cleanup(dev);
+	   	DRM_ERROR("Not enough space in the status page for"
+			  " the freelist\n");
+	   	return -ENOMEM;
+	}
+   	return 0;
+}
+
+int i810_dma_init(struct inode *inode, struct file *filp,
+		  unsigned int cmd, unsigned long arg)
+{
+   	drm_file_t *priv = filp->private_data;
+   	drm_device_t *dev = priv->dev;
+   	drm_i810_private_t *dev_priv;
+   	drm_i810_init_t init;
+   	int retcode = 0;
+	
+  	if (copy_from_user(&init, (drm_i810_init_t *)arg, sizeof(init)))
+		return -EFAULT;
+	
+   	switch(init.func) {
+	 	case I810_INIT_DMA:
+	   		dev_priv = drm_alloc(sizeof(drm_i810_private_t), 
+					     DRM_MEM_DRIVER);
+	   		if(dev_priv = NULL) return -ENOMEM;
+	   		retcode = i810_dma_initialize(dev, dev_priv, &init);
+	   	break;
+	 	case I810_CLEANUP_DMA:
+	   		retcode = i810_dma_cleanup(dev);
+	   	break;
+	 	default:
+	   		retcode = -EINVAL;
+	   	break;
+	}
+   
+   	return retcode;
+}
+
+
+
+/* Most efficient way to verify state for the i810 is as it is
+ * emitted.  Non-conformant state is silently dropped.
+ *
+ * Use 'volatile' & local var tmp to force the emitted values to be
+ * identical to the verified ones.
+ */
+static void i810EmitContextVerified( drm_device_t *dev, 
+				     volatile unsigned int *code ) 
+{	
+   	drm_i810_private_t *dev_priv = dev->dev_private;
+	int i, j = 0;
+	unsigned int tmp;
+	RING_LOCALS;
+
+	BEGIN_LP_RING( I810_CTX_SETUP_SIZE );
+
+	OUT_RING( GFX_OP_COLOR_FACTOR );
+	OUT_RING( code[I810_CTXREG_CF1] );
+
+	OUT_RING( GFX_OP_STIPPLE );
+	OUT_RING( code[I810_CTXREG_ST1] );
+
+	for ( i = 4 ; i < I810_CTX_SETUP_SIZE ; i++ ) {
+		tmp = code[i];
+
+		if ((tmp & (7<<29)) = (3<<29) &&
+		    (tmp & (0x1f<<24)) < (0x1d<<24)) 
+		{
+			OUT_RING( tmp ); 
+			j++;
+		} 
+	}
+
+	if (j & 1) 
+		OUT_RING( 0 ); 
+
+	ADVANCE_LP_RING();
+}
+
+static void i810EmitTexVerified( drm_device_t *dev, 
+				 volatile unsigned int *code ) 
+{	
+   	drm_i810_private_t *dev_priv = dev->dev_private;
+	int i, j = 0;
+	unsigned int tmp;
+	RING_LOCALS;
+
+	BEGIN_LP_RING( I810_TEX_SETUP_SIZE );
+
+	OUT_RING( GFX_OP_MAP_INFO );
+	OUT_RING( code[I810_TEXREG_MI1] );
+	OUT_RING( code[I810_TEXREG_MI2] );
+	OUT_RING( code[I810_TEXREG_MI3] );
+
+	for ( i = 4 ; i < I810_TEX_SETUP_SIZE ; i++ ) {
+		tmp = code[i];
+
+		if ((tmp & (7<<29)) = (3<<29) &&
+		    (tmp & (0x1f<<24)) < (0x1d<<24)) 
+		{
+			OUT_RING( tmp ); 
+			j++;
+		}
+	} 
+		
+	if (j & 1) 
+		OUT_RING( 0 ); 
+
+	ADVANCE_LP_RING();
+}
+
+
+/* Need to do some additional checking when setting the dest buffer.
+ */
+static void i810EmitDestVerified( drm_device_t *dev, 
+				  volatile unsigned int *code ) 
+{	
+   	drm_i810_private_t *dev_priv = dev->dev_private;
+	unsigned int tmp;
+	RING_LOCALS;
+
+	BEGIN_LP_RING( I810_DEST_SETUP_SIZE + 2 );
+
+	tmp = code[I810_DESTREG_DI1];
+	if (tmp = dev_priv->front_di1 || tmp = dev_priv->back_di1) {
+		OUT_RING( CMD_OP_DESTBUFFER_INFO );
+		OUT_RING( tmp );
+	} else
+	   DRM_DEBUG("bad di1 %x (allow %x or %x)\n",
+		     tmp, dev_priv->front_di1, dev_priv->back_di1);
+
+	/* invarient:
+	 */
+	OUT_RING( CMD_OP_Z_BUFFER_INFO );
+	OUT_RING( dev_priv->zi1 );
+
+	OUT_RING( GFX_OP_DESTBUFFER_VARS );
+	OUT_RING( code[I810_DESTREG_DV1] );
+
+	OUT_RING( GFX_OP_DRAWRECT_INFO );
+	OUT_RING( code[I810_DESTREG_DR1] );
+	OUT_RING( code[I810_DESTREG_DR2] );
+	OUT_RING( code[I810_DESTREG_DR3] );
+	OUT_RING( code[I810_DESTREG_DR4] );
+	OUT_RING( 0 );
+
+	ADVANCE_LP_RING();
+}
+
+
+
+static void i810EmitState( drm_device_t *dev )
+{
+   	drm_i810_private_t *dev_priv = dev->dev_private;
+      	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	unsigned int dirty = sarea_priv->dirty;
+
+	if (dirty & I810_UPLOAD_BUFFERS) {
+		i810EmitDestVerified( dev, sarea_priv->BufferState );
+		sarea_priv->dirty &= ~I810_UPLOAD_BUFFERS;
+	}
+
+	if (dirty & I810_UPLOAD_CTX) {
+		i810EmitContextVerified( dev, sarea_priv->ContextState );
+		sarea_priv->dirty &= ~I810_UPLOAD_CTX;
+	}
+
+	if (dirty & I810_UPLOAD_TEX0) {
+		i810EmitTexVerified( dev, sarea_priv->TexState[0] );
+		sarea_priv->dirty &= ~I810_UPLOAD_TEX0;
+	}
+
+	if (dirty & I810_UPLOAD_TEX1) {
+		i810EmitTexVerified( dev, sarea_priv->TexState[1] );
+		sarea_priv->dirty &= ~I810_UPLOAD_TEX1;
+	}
+}
+
+
+
+/* need to verify 
+ */
+static void i810_dma_dispatch_clear( drm_device_t *dev, int flags, 
+				     unsigned int clear_color,
+				     unsigned int clear_zval )
+{
+   	drm_i810_private_t *dev_priv = dev->dev_private;
+      	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	int nbox = sarea_priv->nbox;
+	drm_clip_rect_t *pbox = sarea_priv->boxes;
+	int pitch = dev_priv->pitch;
+	int cpp = 2;
+	int i;
+	RING_LOCALS;
+
+  	i810_kernel_lost_context(dev);
+
+      	if (nbox > I810_NR_SAREA_CLIPRECTS)
+     		nbox = I810_NR_SAREA_CLIPRECTS;
+
+	for (i = 0 ; i < nbox ; i++, pbox++) {
+		unsigned int x = pbox->x1;
+		unsigned int y = pbox->y1;
+		unsigned int width = (pbox->x2 - x) * cpp;
+		unsigned int height = pbox->y2 - y;
+		unsigned int start = y * pitch + x * cpp;
+
+		if (pbox->x1 > pbox->x2 ||
+		    pbox->y1 > pbox->y2 ||
+		    pbox->x2 > dev_priv->w ||
+		    pbox->y2 > dev_priv->h)
+			continue;
+
+	   	if ( flags & I810_FRONT ) {	    
+		   	DRM_DEBUG("clear front\n");
+			BEGIN_LP_RING( 6 );	    
+			OUT_RING( BR00_BITBLT_CLIENT | 
+				  BR00_OP_COLOR_BLT | 0x3 );
+			OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch );
+			OUT_RING( (height << 16) | width );
+			OUT_RING( start );
+			OUT_RING( clear_color );
+			OUT_RING( 0 );
+			ADVANCE_LP_RING();
+		}
+
+		if ( flags & I810_BACK ) {
+			DRM_DEBUG("clear back\n");
+			BEGIN_LP_RING( 6 );	    
+			OUT_RING( BR00_BITBLT_CLIENT | 
+				  BR00_OP_COLOR_BLT | 0x3 );
+			OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch );
+			OUT_RING( (height << 16) | width );
+			OUT_RING( dev_priv->back_offset + start );
+			OUT_RING( clear_color );
+			OUT_RING( 0 );
+			ADVANCE_LP_RING();
+		}
+
+		if ( flags & I810_DEPTH ) {
+			DRM_DEBUG("clear depth\n");
+			BEGIN_LP_RING( 6 );	    
+			OUT_RING( BR00_BITBLT_CLIENT | 
+				  BR00_OP_COLOR_BLT | 0x3 );
+			OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch );
+			OUT_RING( (height << 16) | width );
+			OUT_RING( dev_priv->depth_offset + start );
+			OUT_RING( clear_zval );
+			OUT_RING( 0 );
+			ADVANCE_LP_RING();
+		}
+	}
+}
+
+static void i810_dma_dispatch_swap( drm_device_t *dev )
+{
+   	drm_i810_private_t *dev_priv = dev->dev_private;
+      	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	int nbox = sarea_priv->nbox;
+	drm_clip_rect_t *pbox = sarea_priv->boxes;
+	int pitch = dev_priv->pitch;
+	int cpp = 2;
+	int ofs = dev_priv->back_offset;
+	int i;
+	RING_LOCALS;
+
+	DRM_DEBUG("swapbuffers\n");
+
+  	i810_kernel_lost_context(dev);
+
+      	if (nbox > I810_NR_SAREA_CLIPRECTS)
+     		nbox = I810_NR_SAREA_CLIPRECTS;
+
+	for (i = 0 ; i < nbox; i++, pbox++) 
+	{
+		unsigned int w = pbox->x2 - pbox->x1;
+		unsigned int h = pbox->y2 - pbox->y1;
+		unsigned int dst = pbox->x1*cpp + pbox->y1*pitch;
+		unsigned int start = ofs + dst;
+
+		if (pbox->x1 > pbox->x2 ||
+		    pbox->y1 > pbox->y2 ||
+		    pbox->x2 > dev_priv->w ||
+		    pbox->y2 > dev_priv->h)
+			continue;
+ 
+	   	DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n",
+			  pbox[i].x1, pbox[i].y1,
+			  pbox[i].x2, pbox[i].y2);
+
+		BEGIN_LP_RING( 6 );
+		OUT_RING( BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4 );
+		OUT_RING( pitch | (0xCC << 16));
+		OUT_RING( (h << 16) | (w * cpp));
+		OUT_RING( dst );
+		OUT_RING( pitch );	
+		OUT_RING( start );
+		ADVANCE_LP_RING();
+	}
+}
+
+
+static void i810_dma_dispatch_vertex(drm_device_t *dev, 
+				     drm_buf_t *buf,
+				     int discard,
+				     int used)
+{
+   	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+   	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+   	drm_clip_rect_t *box = sarea_priv->boxes;
+   	int nbox = sarea_priv->nbox;
+	unsigned long address = (unsigned long)buf->bus_address;
+	unsigned long start = address - dev->agp->base;     
+	int i = 0, u;
+   	RING_LOCALS;
+
+   	i810_kernel_lost_context(dev);
+
+   	if (nbox > I810_NR_SAREA_CLIPRECTS) 
+		nbox = I810_NR_SAREA_CLIPRECTS;
+
+	if (discard) {
+		u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, 
+			    I810_BUF_HARDWARE);
+		if(u != I810_BUF_CLIENT) {
+			DRM_DEBUG("xxxx 2\n");
+		}
+	}
+
+	if (used > 4*1024) 
+		used = 0;
+
+	if (sarea_priv->dirty)
+	   i810EmitState( dev );
+
+  	DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n", 
+		  address, used, nbox);
+
+   	dev_priv->counter++;
+   	DRM_DEBUG(  "dispatch counter : %ld\n", dev_priv->counter);
+   	DRM_DEBUG(  "i810_dma_dispatch\n");
+   	DRM_DEBUG(  "start : %lx\n", start);
+	DRM_DEBUG(  "used : %d\n", used);
+   	DRM_DEBUG(  "start + used - 4 : %ld\n", start + used - 4);
+
+	if (buf_priv->currently_mapped = I810_BUF_MAPPED) {
+		*(u32 *)buf_priv->virtual = (GFX_OP_PRIMITIVE |
+					     sarea_priv->vertex_prim |
+					     ((used/4)-2));
+		
+		if (used & 4) {
+			*(u32 *)((u32)buf_priv->virtual + used) = 0;
+			used += 4;
+		}
+
+		i810_unmap_buffer(buf);
+	}
+		   
+	if (used) {
+		do {
+			if (i < nbox) {
+				BEGIN_LP_RING(4);
+				OUT_RING( GFX_OP_SCISSOR | SC_UPDATE_SCISSOR | 
+					  SC_ENABLE );
+				OUT_RING( GFX_OP_SCISSOR_INFO );
+				OUT_RING( box[i].x1 | (box[i].y1<<16) );
+				OUT_RING( (box[i].x2-1) | ((box[i].y2-1)<<16) );
+				ADVANCE_LP_RING();
+			}
+			
+			BEGIN_LP_RING(4);
+			OUT_RING( CMD_OP_BATCH_BUFFER );
+			OUT_RING( start | BB1_PROTECTED );
+			OUT_RING( start + used - 4 );
+			OUT_RING( 0 );
+			ADVANCE_LP_RING();
+			
+		} while (++i < nbox);
+	}
+
+	BEGIN_LP_RING(10);
+	OUT_RING( CMD_STORE_DWORD_IDX );
+	OUT_RING( 20 );
+	OUT_RING( dev_priv->counter );
+	OUT_RING( 0 );
+
+	if (discard) {
+		OUT_RING( CMD_STORE_DWORD_IDX );
+		OUT_RING( buf_priv->my_use_idx );
+		OUT_RING( I810_BUF_FREE );
+		OUT_RING( 0 );
+	}
+
+      	OUT_RING( CMD_REPORT_HEAD );
+	OUT_RING( 0 );
+   	ADVANCE_LP_RING();
+}
+
+
+/* Interrupts are only for flushing */
+static void i810_dma_service(int irq, void *device, struct pt_regs *regs)
+{
+	drm_device_t	 *dev = (drm_device_t *)device;
+   	u16 temp;
+   
+	atomic_inc(&dev->total_irq);
+      	temp = I810_READ16(I810REG_INT_IDENTITY_R);
+   	temp = temp & ~(0x6000);
+   	if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R, 
+				   temp); /* Clear all interrupts */
+	else
+	   return;
+ 
+   	queue_task(&dev->tq, &tq_immediate);
+   	mark_bh(IMMEDIATE_BH);
+}
+
+static void i810_dma_task_queue(void *device)
+{
+	drm_device_t *dev = (drm_device_t *) device;
+      	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+
+   	atomic_set(&dev_priv->flush_done, 1);
+   	wake_up_interruptible(&dev_priv->flush_queue);
+}
+
+int i810_irq_install(drm_device_t *dev, int irq)
+{
+	int retcode;
+	u16 temp;
+   
+	if (!irq)     return -EINVAL;
+	
+	down(&dev->struct_sem);
+	if (dev->irq) {
+		up(&dev->struct_sem);
+		return -EBUSY;
+	}
+	dev->irq = irq;
+	up(&dev->struct_sem);
+	
+   	DRM_DEBUG(  "Interrupt Install : %d\n", irq);
+	DRM_DEBUG("%d\n", irq);
+
+	dev->context_flag     = 0;
+	dev->interrupt_flag   = 0;
+	dev->dma_flag	      = 0;
+	
+	dev->dma->next_buffer = NULL;
+	dev->dma->next_queue  = NULL;
+	dev->dma->this_buffer = NULL;
+
+	INIT_LIST_HEAD(&dev->tq.list);
+	dev->tq.sync	      = 0;
+	dev->tq.routine	      = i810_dma_task_queue;
+	dev->tq.data	      = dev;
+
+				/* Before installing handler */
+   	temp = I810_READ16(I810REG_HWSTAM);
+   	temp = temp & 0x6000;
+   	I810_WRITE16(I810REG_HWSTAM, temp);
+   	
+      	temp = I810_READ16(I810REG_INT_MASK_R);
+   	temp = temp & 0x6000;
+   	I810_WRITE16(I810REG_INT_MASK_R, temp); /* Unmask interrupts */
+   	temp = I810_READ16(I810REG_INT_ENABLE_R);
+   	temp = temp & 0x6000;
+      	I810_WRITE16(I810REG_INT_ENABLE_R, temp); /* Disable all interrupts */
+
+				/* Install handler */
+	if ((retcode = request_irq(dev->irq,
+				   i810_dma_service,
+				   SA_SHIRQ,
+				   dev->devname,
+				   dev))) {
+		down(&dev->struct_sem);
+		dev->irq = 0;
+		up(&dev->struct_sem);
+		return retcode;
+	}
+   	temp = I810_READ16(I810REG_INT_ENABLE_R);
+   	temp = temp & 0x6000;
+   	temp = temp | 0x0003;
+   	I810_WRITE16(I810REG_INT_ENABLE_R, 
+		     temp); /* Enable bp & user interrupts */
+	return 0;
+}
+
+int i810_irq_uninstall(drm_device_t *dev)
+{
+	int irq;
+   	u16 temp;
+
+
+/*  	return 0; */
+
+	down(&dev->struct_sem);
+	irq	 = dev->irq;
+	dev->irq = 0;
+	up(&dev->struct_sem);
+	
+	if (!irq) return -EINVAL;
+
+   	DRM_DEBUG(  "Interrupt UnInstall: %d\n", irq);	
+	DRM_DEBUG("%d\n", irq);
+   
+   	temp = I810_READ16(I810REG_INT_IDENTITY_R);
+   	temp = temp & ~(0x6000);
+   	if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R, 
+				   temp); /* Clear all interrupts */
+   
+   	temp = I810_READ16(I810REG_INT_ENABLE_R);
+   	temp = temp & 0x6000;
+   	I810_WRITE16(I810REG_INT_ENABLE_R, 
+		     temp);                     /* Disable all interrupts */
+
+   	free_irq(irq, dev);
+
+	return 0;
+}
+
+int i810_control(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_control_t	ctl;
+	int		retcode;
+   
+   	DRM_DEBUG(  "i810_control\n");
+
+	if (copy_from_user(&ctl, (drm_control_t *)arg, sizeof(ctl)))
+		return -EFAULT;
+	
+	switch (ctl.func) {
+	case DRM_INST_HANDLER:
+		if ((retcode = i810_irq_install(dev, ctl.irq)))
+			return retcode;
+		break;
+	case DRM_UNINST_HANDLER:
+		if ((retcode = i810_irq_uninstall(dev)))
+			return retcode;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static inline void i810_dma_emit_flush(drm_device_t *dev)
+{
+   	drm_i810_private_t *dev_priv = dev->dev_private;
+   	RING_LOCALS;
+
+   	i810_kernel_lost_context(dev);
+
+   	BEGIN_LP_RING(2);
+      	OUT_RING( CMD_REPORT_HEAD );
+      	OUT_RING( GFX_OP_USER_INTERRUPT );
+      	ADVANCE_LP_RING();
+
+/*  	i810_wait_ring( dev, dev_priv->ring.Size - 8 ); */
+/*     	atomic_set(&dev_priv->flush_done, 1); */
+/*     	wake_up_interruptible(&dev_priv->flush_queue); */
+}
+
+static inline void i810_dma_quiescent_emit(drm_device_t *dev)
+{
+      	drm_i810_private_t *dev_priv = dev->dev_private;
+   	RING_LOCALS;
+
+  	i810_kernel_lost_context(dev);
+
+   	BEGIN_LP_RING(4);
+   	OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE );
+   	OUT_RING( CMD_REPORT_HEAD );
+      	OUT_RING( 0 );
+      	OUT_RING( GFX_OP_USER_INTERRUPT );
+   	ADVANCE_LP_RING();
+
+/*  	i810_wait_ring( dev, dev_priv->ring.Size - 8 ); */
+/*     	atomic_set(&dev_priv->flush_done, 1); */
+/*     	wake_up_interruptible(&dev_priv->flush_queue); */
+}
+
+static void i810_dma_quiescent(drm_device_t *dev)
+{
+      	DECLARE_WAITQUEUE(entry, current);
+  	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+	unsigned long end;      
+
+   	if(dev_priv = NULL) {
+	   	return;
+	}
+      	atomic_set(&dev_priv->flush_done, 0);
+   	add_wait_queue(&dev_priv->flush_queue, &entry);
+   	end = jiffies + (HZ*3);
+   
+   	for (;;) {
+		current->state = TASK_INTERRUPTIBLE;
+	      	i810_dma_quiescent_emit(dev);
+	   	if (atomic_read(&dev_priv->flush_done) = 1) break;
+		if((signed)(end - jiffies) <= 0) {
+		   	DRM_ERROR("lockup\n");
+		   	break;
+		}	   
+	      	schedule_timeout(HZ*3);
+	      	if (signal_pending(current)) {
+		   	break;
+		}
+	}
+   
+   	current->state = TASK_RUNNING;
+   	remove_wait_queue(&dev_priv->flush_queue, &entry);
+   
+   	return;
+}
+
+static int i810_flush_queue(drm_device_t *dev)
+{
+   	DECLARE_WAITQUEUE(entry, current);
+  	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+	drm_device_dma_t *dma = dev->dma;
+	unsigned long end;
+   	int i, ret = 0;      
+
+   	if(dev_priv = NULL) {
+	   	return 0;
+	}
+      	atomic_set(&dev_priv->flush_done, 0);
+   	add_wait_queue(&dev_priv->flush_queue, &entry);
+   	end = jiffies + (HZ*3);
+   	for (;;) {
+		current->state = TASK_INTERRUPTIBLE;
+	      	i810_dma_emit_flush(dev);
+	   	if (atomic_read(&dev_priv->flush_done) = 1) break;
+		if((signed)(end - jiffies) <= 0) {
+		   	DRM_ERROR("lockup\n");
+		   	break;
+		}	   
+	      	schedule_timeout(HZ*3);
+	      	if (signal_pending(current)) {
+		   	ret = -EINTR; /* Can't restart */
+		   	break;
+		}
+	}
+   
+   	current->state = TASK_RUNNING;
+   	remove_wait_queue(&dev_priv->flush_queue, &entry);
+
+
+   	for (i = 0; i < dma->buf_count; i++) {
+	   	drm_buf_t *buf = dma->buflist[ i ];
+	   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+	   
+		int used = cmpxchg(buf_priv->in_use, I810_BUF_HARDWARE, 
+				   I810_BUF_FREE);
+
+		if (used = I810_BUF_HARDWARE)
+			DRM_DEBUG("reclaimed from HARDWARE\n");
+		if (used = I810_BUF_CLIENT)
+			DRM_DEBUG("still on client HARDWARE\n");
+	}
+
+   	return ret;
+}
+
+/* Must be called with the lock held */
+void i810_reclaim_buffers(drm_device_t *dev, pid_t pid)
+{
+	drm_device_dma_t *dma = dev->dma;
+	int		 i;
+
+	if (!dma) return;
+      	if (!dev->dev_private) return;
+	if (!dma->buflist) return;
+
+        i810_flush_queue(dev);
+
+	for (i = 0; i < dma->buf_count; i++) {
+	   	drm_buf_t *buf = dma->buflist[ i ];
+	   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+	   
+		if (buf->pid = pid && buf_priv) {
+			int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, 
+					   I810_BUF_FREE);
+
+			if (used = I810_BUF_CLIENT)
+				DRM_DEBUG("reclaimed from client\n");
+		   	if(buf_priv->currently_mapped = I810_BUF_MAPPED)
+		     		buf_priv->currently_mapped = I810_BUF_UNMAPPED;
+		}
+	}
+}
+
+int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+
+	DECLARE_WAITQUEUE(entry, current);
+	int		  ret	= 0;
+	drm_lock_t	  lock;
+
+	if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
+		return -EFAULT;
+
+	if (lock.context = DRM_KERNEL_CONTEXT) {
+		DRM_ERROR("Process %d using kernel context %d\n",
+			  current->pid, lock.context);
+		return -EINVAL;
+	}
+   
+   	DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
+		  lock.context, current->pid, dev->lock.hw_lock->lock,
+		  lock.flags);
+
+	if (lock.context < 0) {
+		return -EINVAL;
+	}
+	/* Only one queue:
+	 */
+
+	if (!ret) {
+		add_wait_queue(&dev->lock.lock_queue, &entry);
+		for (;;) {
+			current->state = TASK_INTERRUPTIBLE;
+			if (!dev->lock.hw_lock) {
+				/* Device has been unregistered */
+				ret = -EINTR;
+				break;
+			}
+			if (drm_lock_take(&dev->lock.hw_lock->lock,
+					  lock.context)) {
+				dev->lock.pid	    = current->pid;
+				dev->lock.lock_time = jiffies;
+				atomic_inc(&dev->total_locks);
+				break;	/* Got lock */
+			}
+			
+				/* Contention */
+			atomic_inc(&dev->total_sleeps);
+		   	DRM_DEBUG("Calling lock schedule\n");
+			schedule();
+			if (signal_pending(current)) {
+				ret = -ERESTARTSYS;
+				break;
+			}
+		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&dev->lock.lock_queue, &entry);
+	}
+	
+	if (!ret) {
+		sigemptyset(&dev->sigmask);
+		sigaddset(&dev->sigmask, SIGSTOP);
+		sigaddset(&dev->sigmask, SIGTSTP);
+		sigaddset(&dev->sigmask, SIGTTIN);
+		sigaddset(&dev->sigmask, SIGTTOU);
+		dev->sigdata.context = lock.context;
+		dev->sigdata.lock    = dev->lock.hw_lock;
+		block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
+
+		if (lock.flags & _DRM_LOCK_QUIESCENT) {
+		   DRM_DEBUG("_DRM_LOCK_QUIESCENT\n");
+		   DRM_DEBUG("fred\n");
+		   i810_dma_quiescent(dev);
+		}
+	}
+	DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
+	return ret;
+}
+
+int i810_flush_ioctl(struct inode *inode, struct file *filp, 
+		     unsigned int cmd, unsigned long arg)
+{
+   	drm_file_t	  *priv	  = filp->private_data;
+   	drm_device_t	  *dev	  = priv->dev;
+   
+   	DRM_DEBUG("i810_flush_ioctl\n");
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i810_flush_ioctl called without lock held\n");
+		return -EINVAL;
+	}
+
+   	i810_flush_queue(dev);
+   	return 0;
+}
+
+
+int i810_dma_vertex(struct inode *inode, struct file *filp,
+	       unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_device_dma_t *dma = dev->dma;
+   	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+      	u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) 
+     					dev_priv->sarea_priv; 
+	drm_i810_vertex_t vertex;
+
+	if (copy_from_user(&vertex, (drm_i810_vertex_t *)arg, sizeof(vertex)))
+		return -EFAULT;
+
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i810_dma_vertex called without lock held\n");
+		return -EINVAL;
+	}
+
+	DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n",
+		  vertex.idx, vertex.used, vertex.discard);
+
+	if(vertex.idx < 0 || vertex.idx > dma->buf_count) return -EINVAL;
+
+	i810_dma_dispatch_vertex( dev, 
+				  dma->buflist[ vertex.idx ], 
+				  vertex.discard, vertex.used );
+
+   	atomic_add(vertex.used, &dma->total_bytes);
+	atomic_inc(&dma->total_dmas);
+	sarea_priv->last_enqueue = dev_priv->counter-1;
+   	sarea_priv->last_dispatch = (int) hw_status[5];
+   
+	return 0;
+}
+
+
+
+int i810_clear_bufs(struct inode *inode, struct file *filp,
+		   unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_i810_clear_t clear;
+
+   	if (copy_from_user(&clear, (drm_i810_clear_t *)arg, sizeof(clear)))
+		return -EFAULT;
+   
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i810_clear_bufs called without lock held\n");
+		return -EINVAL;
+	}
+
+	i810_dma_dispatch_clear( dev, clear.flags, 
+				 clear.clear_color, 
+				 clear.clear_depth );
+   	return 0;
+}
+
+int i810_swap_bufs(struct inode *inode, struct file *filp,
+		  unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+   
+	DRM_DEBUG("i810_swap_bufs\n");
+
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i810_swap_buf called without lock held\n");
+		return -EINVAL;
+	}
+
+	i810_dma_dispatch_swap( dev );
+   	return 0;
+}
+
+int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+   	drm_file_t	  *priv	    = filp->private_data;
+	drm_device_t	  *dev	    = priv->dev;
+   	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+      	u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) 
+     					dev_priv->sarea_priv; 
+
+      	sarea_priv->last_dispatch = (int) hw_status[5];
+	return 0;
+}
+
+int i810_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	  *priv	    = filp->private_data;
+	drm_device_t	  *dev	    = priv->dev;
+	int		  retcode   = 0;
+	drm_i810_dma_t	  d;
+   	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+   	u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) 
+     					dev_priv->sarea_priv; 
+
+	DRM_DEBUG("getbuf\n");
+   	if (copy_from_user(&d, (drm_i810_dma_t *)arg, sizeof(d)))
+		return -EFAULT;
+   
+	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i810_dma called without lock held\n");
+		return -EINVAL;
+	}
+	
+	d.granted = 0;
+
+	retcode = i810_dma_get_buffer(dev, &d, filp);
+
+	DRM_DEBUG("i810_dma: %d returning %d, granted = %d\n",
+		  current->pid, retcode, d.granted);
+
+	if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d)))
+		return -EFAULT;
+   	sarea_priv->last_dispatch = (int) hw_status[5];
+
+	return retcode;
+}
+
+int i810_copybuf(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	  *priv	    = filp->private_data;
+	drm_device_t	  *dev	    = priv->dev;
+	drm_i810_copy_t	  d;
+   	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+   	u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) 
+     					dev_priv->sarea_priv; 
+	drm_buf_t *buf;
+	drm_i810_buf_priv_t *buf_priv;
+	drm_device_dma_t *dma = dev->dma;
+
+	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i810_dma called without lock held\n");
+		return -EINVAL;
+	}
+   
+   	if (copy_from_user(&d, (drm_i810_copy_t *)arg, sizeof(d)))
+		return -EFAULT;
+
+	if(d.idx < 0 || d.idx > dma->buf_count) return -EINVAL;
+	buf = dma->buflist[ d.idx ];
+   	buf_priv = buf->dev_private;
+	if (buf_priv->currently_mapped != I810_BUF_MAPPED) return -EPERM;
+
+	/* Stopping end users copying their data to the entire kernel
+	   is good.. */
+	if (d.used < 0 || d.used > buf->total)
+		return -EINVAL;
+		
+   	if (copy_from_user(buf_priv->virtual, d.address, d.used))
+		return -EFAULT;
+
+   	sarea_priv->last_dispatch = (int) hw_status[5];
+
+	return 0;
+}
+
+int i810_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	if(VM_DONTCOPY = 0) return 1;
+	return 0;
+}
diff -urN linux-2.4.13/drivers/char/drm-4.0/i810_drm.h linux-2.4.13-lia/drivers/char/drm-4.0/i810_drm.h
--- linux-2.4.13/drivers/char/drm-4.0/i810_drm.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/i810_drm.h	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,194 @@
+#ifndef _I810_DRM_H_
+#define _I810_DRM_H_
+
+/* WARNING: These defines must be the same as what the Xserver uses.
+ * if you change them, you must change the defines in the Xserver.
+ */
+
+#ifndef _I810_DEFINES_
+#define _I810_DEFINES_
+
+#define I810_DMA_BUF_ORDER		12
+#define I810_DMA_BUF_SZ 		(1<<I810_DMA_BUF_ORDER)
+#define I810_DMA_BUF_NR 		256
+#define I810_NR_SAREA_CLIPRECTS 	8
+
+/* Each region is a minimum of 64k, and there are at most 64 of them.
+ */
+#define I810_NR_TEX_REGIONS 64
+#define I810_LOG_MIN_TEX_REGION_SIZE 16
+#endif
+
+#define I810_UPLOAD_TEX0IMAGE  0x1 /* handled clientside */
+#define I810_UPLOAD_TEX1IMAGE  0x2 /* handled clientside */
+#define I810_UPLOAD_CTX        0x4
+#define I810_UPLOAD_BUFFERS    0x8
+#define I810_UPLOAD_TEX0       0x10
+#define I810_UPLOAD_TEX1       0x20
+#define I810_UPLOAD_CLIPRECTS  0x40
+
+
+/* Indices into buf.Setup where various bits of state are mirrored per
+ * context and per buffer.  These can be fired at the card as a unit,
+ * or in a piecewise fashion as required.
+ */
+
+/* Destbuffer state 
+ *    - backbuffer linear offset and pitch -- invarient in the current dri
+ *    - zbuffer linear offset and pitch -- also invarient
+ *    - drawing origin in back and depth buffers.
+ *
+ * Keep the depth/back buffer state here to acommodate private buffers
+ * in the future.
+ */
+#define I810_DESTREG_DI0  0	/* CMD_OP_DESTBUFFER_INFO (2 dwords) */
+#define I810_DESTREG_DI1  1
+#define I810_DESTREG_DV0  2	/* GFX_OP_DESTBUFFER_VARS (2 dwords) */
+#define I810_DESTREG_DV1  3
+#define I810_DESTREG_DR0  4	/* GFX_OP_DRAWRECT_INFO (4 dwords) */
+#define I810_DESTREG_DR1  5
+#define I810_DESTREG_DR2  6
+#define I810_DESTREG_DR3  7
+#define I810_DESTREG_DR4  8
+#define I810_DEST_SETUP_SIZE 10
+
+/* Context state
+ */
+#define I810_CTXREG_CF0   0	/* GFX_OP_COLOR_FACTOR */
+#define I810_CTXREG_CF1   1	
+#define I810_CTXREG_ST0   2     /* GFX_OP_STIPPLE */
+#define I810_CTXREG_ST1   3
+#define I810_CTXREG_VF    4	/* GFX_OP_VERTEX_FMT */
+#define I810_CTXREG_MT    5	/* GFX_OP_MAP_TEXELS */
+#define I810_CTXREG_MC0   6	/* GFX_OP_MAP_COLOR_STAGES - stage 0 */
+#define I810_CTXREG_MC1   7     /* GFX_OP_MAP_COLOR_STAGES - stage 1 */
+#define I810_CTXREG_MC2   8	/* GFX_OP_MAP_COLOR_STAGES - stage 2 */
+#define I810_CTXREG_MA0   9	/* GFX_OP_MAP_ALPHA_STAGES - stage 0 */
+#define I810_CTXREG_MA1   10	/* GFX_OP_MAP_ALPHA_STAGES - stage 1 */
+#define I810_CTXREG_MA2   11	/* GFX_OP_MAP_ALPHA_STAGES - stage 2 */
+#define I810_CTXREG_SDM   12	/* GFX_OP_SRC_DEST_MONO */
+#define I810_CTXREG_FOG   13	/* GFX_OP_FOG_COLOR */
+#define I810_CTXREG_B1    14	/* GFX_OP_BOOL_1 */
+#define I810_CTXREG_B2    15	/* GFX_OP_BOOL_2 */
+#define I810_CTXREG_LCS   16	/* GFX_OP_LINEWIDTH_CULL_SHADE_MODE */
+#define I810_CTXREG_PV    17	/* GFX_OP_PV_RULE -- Invarient! */
+#define I810_CTXREG_ZA    18	/* GFX_OP_ZBIAS_ALPHAFUNC */
+#define I810_CTXREG_AA    19	/* GFX_OP_ANTIALIAS */
+#define I810_CTX_SETUP_SIZE 20 
+
+/* Texture state (per tex unit)
+ */
+#define I810_TEXREG_MI0  0	/* GFX_OP_MAP_INFO (4 dwords) */
+#define I810_TEXREG_MI1  1	
+#define I810_TEXREG_MI2  2	
+#define I810_TEXREG_MI3  3	
+#define I810_TEXREG_MF   4	/* GFX_OP_MAP_FILTER */
+#define I810_TEXREG_MLC  5	/* GFX_OP_MAP_LOD_CTL */
+#define I810_TEXREG_MLL  6	/* GFX_OP_MAP_LOD_LIMITS */
+#define I810_TEXREG_MCS  7	/* GFX_OP_MAP_COORD_SETS ??? */
+#define I810_TEX_SETUP_SIZE 8
+
+#define I810_FRONT   0x1
+#define I810_BACK    0x2
+#define I810_DEPTH   0x4
+
+
+typedef struct _drm_i810_init {
+	enum {
+		I810_INIT_DMA = 0x01,
+		I810_CLEANUP_DMA = 0x02
+	} func;
+	int ring_map_idx;
+	int buffer_map_idx;
+	int sarea_priv_offset;
+	unsigned int ring_start;
+	unsigned int ring_end;
+	unsigned int ring_size;
+	unsigned int front_offset;
+	unsigned int back_offset;
+	unsigned int depth_offset;
+	unsigned int w;
+	unsigned int h;
+	unsigned int pitch;
+	unsigned int pitch_bits; 
+} drm_i810_init_t;
+
+/* Warning: If you change the SAREA structure you must change the Xserver
+ * structure as well */
+
+typedef struct _drm_i810_tex_region {
+	unsigned char next, prev; /* indices to form a circular LRU  */
+	unsigned char in_use;	/* owned by a client, or free? */
+	int age;		/* tracked by clients to update local LRU's */
+} drm_i810_tex_region_t;
+
+typedef struct _drm_i810_sarea {
+   	unsigned int ContextState[I810_CTX_SETUP_SIZE];
+   	unsigned int BufferState[I810_DEST_SETUP_SIZE];
+   	unsigned int TexState[2][I810_TEX_SETUP_SIZE];
+   	unsigned int dirty;
+
+	unsigned int nbox;
+	drm_clip_rect_t boxes[I810_NR_SAREA_CLIPRECTS];
+
+	/* Maintain an LRU of contiguous regions of texture space.  If
+	 * you think you own a region of texture memory, and it has an
+	 * age different to the one you set, then you are mistaken and
+	 * it has been stolen by another client.  If global texAge
+	 * hasn't changed, there is no need to walk the list.
+	 *
+	 * These regions can be used as a proxy for the fine-grained
+	 * texture information of other clients - by maintaining them
+	 * in the same lru which is used to age their own textures,
+	 * clients have an approximate lru for the whole of global
+	 * texture space, and can make informed decisions as to which
+	 * areas to kick out.  There is no need to choose whether to
+	 * kick out your own texture or someone else's - simply eject
+	 * them all in LRU order.  
+	 */
+   
+	drm_i810_tex_region_t texList[I810_NR_TEX_REGIONS+1]; 
+				/* Last elt is sentinal */
+        int texAge;		/* last time texture was uploaded */
+        int last_enqueue;	/* last time a buffer was enqueued */
+	int last_dispatch;	/* age of the most recently dispatched buffer */
+	int last_quiescent;     /*  */
+	int ctxOwner;		/* last context to upload state */
+
+	int vertex_prim;
+
+} drm_i810_sarea_t;
+
+typedef struct _drm_i810_clear {
+	int clear_color;
+	int clear_depth;
+	int flags;
+} drm_i810_clear_t;
+
+
+
+/* These may be placeholders if we have more cliprects than
+ * I810_NR_SAREA_CLIPRECTS.  In that case, the client sets discard to
+ * false, indicating that the buffer will be dispatched again with a
+ * new set of cliprects.
+ */
+typedef struct _drm_i810_vertex {
+   	int idx;		/* buffer index */
+	int used;		/* nr bytes in use */
+	int discard;		/* client is finished with the buffer? */
+} drm_i810_vertex_t;
+
+typedef struct _drm_i810_copy_t {
+   	int idx;		/* buffer index */
+	int used;		/* nr bytes in use */
+	void *address;		/* Address to copy from */
+} drm_i810_copy_t;
+
+typedef struct drm_i810_dma {
+	void *virtual;
+	int request_idx;
+	int request_size;
+	int granted;
+} drm_i810_dma_t;
+
+#endif /* _I810_DRM_H_ */
diff -urN linux-2.4.13/drivers/char/drm-4.0/i810_drv.c linux-2.4.13-lia/drivers/char/drm-4.0/i810_drv.c
--- linux-2.4.13/drivers/char/drm-4.0/i810_drv.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/i810_drv.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,648 @@
+/* i810_drv.c -- I810 driver -*- linux-c -*-
+ * Created: Mon Dec 13 01:56:22 1999 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ *	    Jeff Hartmann <jhartmann@valinux.com>
+ *
+ */
+
+#include <linux/config.h>
+#include "drmP.h"
+#include "i810_drv.h"
+
+#define I810_NAME	 "i810"
+#define I810_DESC	 "Intel I810"
+#define I810_DATE	 "20000928"
+#define I810_MAJOR	 1
+#define I810_MINOR	 1
+#define I810_PATCHLEVEL	 0
+
+static drm_device_t	      i810_device;
+drm_ctx_t		      i810_res_ctx;
+
+static struct file_operations i810_fops = {
+#if LINUX_VERSION_CODE >= 0x020400
+				/* This started being used during 2.4.0-test */
+	owner:   THIS_MODULE,
+#endif
+	open:	 i810_open,
+	flush:	 drm_flush,
+	release: i810_release,
+	ioctl:	 i810_ioctl,
+	mmap:	 drm_mmap,
+	read:	 drm_read,
+	fasync:	 drm_fasync,
+      	poll:	 drm_poll,
+};
+
+static struct miscdevice      i810_misc = {
+	minor: MISC_DYNAMIC_MINOR,
+	name:  I810_NAME,
+	fops:  &i810_fops,
+};
+
+static drm_ioctl_desc_t	      i810_ioctls[] = {
+	[DRM_IOCTL_NR(DRM_IOCTL_VERSION)]     = { i810_version,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)]  = { drm_getunique,  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)]   = { drm_getmagic,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)]   = { drm_irq_busid,  0, 1 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)]  = { drm_setunique,  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_BLOCK)]	      = { drm_block,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)]     = { drm_unblock,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_CONTROL)]     = { i810_control,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)]  = { drm_authmagic,  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)]     = { drm_addmap,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)]    = { i810_addbufs,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)]   = { i810_markbufs,  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)]   = { i810_infobufs,  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)]   = { i810_freebufs,  1, 0 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)]     = { i810_addctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)]      = { i810_rmctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)]     = { i810_modctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)]     = { i810_getctx,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)]  = { i810_switchctx,  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)]     = { i810_newctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)]     = { i810_resctx,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)]    = { drm_adddraw,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)]     = { drm_rmdraw,	  1, 1 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_LOCK)]	      = { i810_lock,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)]      = { i810_unlock,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_FINISH)]      = { drm_finish,	  1, 0 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { drm_agp_acquire, 1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { drm_agp_release, 1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)]  = { drm_agp_enable,  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)]    = { drm_agp_info,    1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)]   = { drm_agp_alloc,   1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)]    = { drm_agp_free,    1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)]    = { drm_agp_bind,    1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)]  = { drm_agp_unbind,  1, 1 },
+
+   	[DRM_IOCTL_NR(DRM_IOCTL_I810_INIT)]   = { i810_dma_init,   1, 1 },
+   	[DRM_IOCTL_NR(DRM_IOCTL_I810_VERTEX)] = { i810_dma_vertex, 1, 0 },
+   	[DRM_IOCTL_NR(DRM_IOCTL_I810_CLEAR)]  = { i810_clear_bufs, 1, 0 },
+      	[DRM_IOCTL_NR(DRM_IOCTL_I810_FLUSH)]  = { i810_flush_ioctl,1, 0 },
+   	[DRM_IOCTL_NR(DRM_IOCTL_I810_GETAGE)] = { i810_getage,     1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_I810_GETBUF)] = { i810_getbuf,     1, 0 },
+   	[DRM_IOCTL_NR(DRM_IOCTL_I810_SWAP)]   = { i810_swap_bufs,  1, 0 },
+   	[DRM_IOCTL_NR(DRM_IOCTL_I810_COPY)]   = { i810_copybuf,    1, 0 },
+   	[DRM_IOCTL_NR(DRM_IOCTL_I810_DOCOPY)] = { i810_docopy,     1, 0 },
+};
+
+#define I810_IOCTL_COUNT DRM_ARRAY_SIZE(i810_ioctls)
+
+#ifdef MODULE
+static char		      *i810 = NULL;
+#endif
+
+MODULE_AUTHOR("VA Linux Systems, Inc.");
+MODULE_DESCRIPTION("Intel I810");
+MODULE_PARM(i810, "s");
+
+#ifndef MODULE
+/* i810_options is called by the kernel to parse command-line options
+ * passed via the boot-loader (e.g., LILO).  It calls the insmod option
+ * routine, drm_parse_drm.
+ */
+
+static int __init i810_options(char *str)
+{
+	drm_parse_options(str);
+	return 1;
+}
+
+__setup("i810=", i810_options);
+#endif
+
+static int i810_setup(drm_device_t *dev)
+{
+	int i;
+
+	atomic_set(&dev->ioctl_count, 0);
+	atomic_set(&dev->vma_count, 0);
+	dev->buf_use	  = 0;
+	atomic_set(&dev->buf_alloc, 0);
+
+	drm_dma_setup(dev);
+
+	atomic_set(&dev->total_open, 0);
+	atomic_set(&dev->total_close, 0);
+	atomic_set(&dev->total_ioctl, 0);
+	atomic_set(&dev->total_irq, 0);
+	atomic_set(&dev->total_ctx, 0);
+	atomic_set(&dev->total_locks, 0);
+	atomic_set(&dev->total_unlocks, 0);
+	atomic_set(&dev->total_contends, 0);
+	atomic_set(&dev->total_sleeps, 0);
+
+	for (i = 0; i < DRM_HASH_SIZE; i++) {
+		dev->magiclist[i].head = NULL;
+		dev->magiclist[i].tail = NULL;
+	}
+	dev->maplist	    = NULL;
+	dev->map_count	    = 0;
+	dev->vmalist	    = NULL;
+	dev->lock.hw_lock   = NULL;
+	init_waitqueue_head(&dev->lock.lock_queue);
+	dev->queue_count    = 0;
+	dev->queue_reserved = 0;
+	dev->queue_slots    = 0;
+	dev->queuelist	    = NULL;
+	dev->irq	    = 0;
+	dev->context_flag   = 0;
+	dev->interrupt_flag = 0;
+	dev->dma_flag	    = 0;
+	dev->last_context   = 0;
+	dev->last_switch    = 0;
+	dev->last_checked   = 0;
+	init_timer(&dev->timer);
+	init_waitqueue_head(&dev->context_wait);
+#if DRM_DMA_HISTO
+	memset(&dev->histo, 0, sizeof(dev->histo));
+#endif
+	dev->ctx_start	    = 0;
+	dev->lck_start	    = 0;
+
+	dev->buf_rp	  = dev->buf;
+	dev->buf_wp	  = dev->buf;
+	dev->buf_end	  = dev->buf + DRM_BSZ;
+	dev->buf_async	  = NULL;
+	init_waitqueue_head(&dev->buf_readers);
+	init_waitqueue_head(&dev->buf_writers);
+
+	DRM_DEBUG("\n");
+
+	/* The kernel's context could be created here, but is now created
+	   in drm_dma_enqueue.	This is more resource-efficient for
+	   hardware that does not do DMA, but may mean that
+	   drm_select_queue fails between the time the interrupt is
+	   initialized and the time the queues are initialized. */
+
+	return 0;
+}
+
+
+static int i810_takedown(drm_device_t *dev)
+{
+	int		  i;
+	drm_magic_entry_t *pt, *next;
+	drm_map_t	  *map;
+	drm_vma_entry_t	  *vma, *vma_next;
+
+	DRM_DEBUG("\n");
+
+	if (dev->irq) i810_irq_uninstall(dev);
+
+	down(&dev->struct_sem);
+	del_timer(&dev->timer);
+
+	if (dev->devname) {
+		drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER);
+		dev->devname = NULL;
+	}
+
+	if (dev->unique) {
+		drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER);
+		dev->unique = NULL;
+		dev->unique_len = 0;
+	}
+				/* Clear pid list */
+	for (i = 0; i < DRM_HASH_SIZE; i++) {
+		for (pt = dev->magiclist[i].head; pt; pt = next) {
+			next = pt->next;
+			drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+		}
+		dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
+	}
+   				/* Clear AGP information */
+	if (dev->agp) {
+		drm_agp_mem_t *entry;
+		drm_agp_mem_t *nexte;
+
+				/* Remove AGP resources, but leave dev->agp
+                                   intact until r128_cleanup is called. */
+		for (entry = dev->agp->memory; entry; entry = nexte) {
+			nexte = entry->next;
+			if (entry->bound) drm_unbind_agp(entry->memory);
+			drm_free_agp(entry->memory, entry->pages);
+			drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+		}
+		dev->agp->memory = NULL;
+
+		if (dev->agp->acquired) _drm_agp_release();
+
+		dev->agp->acquired = 0;
+		dev->agp->enabled  = 0;
+	}
+				/* Clear vma list (only built for debugging) */
+	if (dev->vmalist) {
+		for (vma = dev->vmalist; vma; vma = vma_next) {
+			vma_next = vma->next;
+			drm_free(vma, sizeof(*vma), DRM_MEM_VMAS);
+		}
+		dev->vmalist = NULL;
+	}
+
+				/* Clear map area and mtrr information */
+	if (dev->maplist) {
+		for (i = 0; i < dev->map_count; i++) {
+			map = dev->maplist[i];
+			switch (map->type) {
+			case _DRM_REGISTERS:
+			case _DRM_FRAME_BUFFER:
+#ifdef CONFIG_MTRR
+				if (map->mtrr >= 0) {
+					int retcode;
+					retcode = mtrr_del(map->mtrr,
+							   map->offset,
+							   map->size);
+					DRM_DEBUG("mtrr_del = %d\n", retcode);
+				}
+#endif
+				drm_ioremapfree(map->handle, map->size, dev);
+				break;
+			case _DRM_SHM:
+				drm_free_pages((unsigned long)map->handle,
+					       drm_order(map->size)
+					       - PAGE_SHIFT,
+					       DRM_MEM_SAREA);
+				break;
+			case _DRM_AGP:
+				break;
+			}
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		}
+		drm_free(dev->maplist,
+			 dev->map_count * sizeof(*dev->maplist),
+			 DRM_MEM_MAPS);
+		dev->maplist   = NULL;
+		dev->map_count = 0;
+	}
+
+	if (dev->queuelist) {
+		for (i = 0; i < dev->queue_count; i++) {
+			drm_waitlist_destroy(&dev->queuelist[i]->waitlist);
+			if (dev->queuelist[i]) {
+				drm_free(dev->queuelist[i],
+					 sizeof(*dev->queuelist[0]),
+					 DRM_MEM_QUEUES);
+				dev->queuelist[i] = NULL;
+			}
+		}
+		drm_free(dev->queuelist,
+			 dev->queue_slots * sizeof(*dev->queuelist),
+			 DRM_MEM_QUEUES);
+		dev->queuelist	 = NULL;
+	}
+
+	drm_dma_takedown(dev);
+
+	dev->queue_count     = 0;
+	if (dev->lock.hw_lock) {
+		dev->lock.hw_lock    = NULL; /* SHM removed */
+		dev->lock.pid	     = 0;
+		wake_up_interruptible(&dev->lock.lock_queue);
+	}
+	up(&dev->struct_sem);
+
+	return 0;
+}
+
+/* i810_init is called via init_module at module load time, or via
+ * linux/init/main.c (this is not currently supported). */
+
+static int __init i810_init(void)
+{
+	int		      retcode;
+	drm_device_t	      *dev = &i810_device;
+
+	DRM_DEBUG("\n");
+
+	memset((void *)dev, 0, sizeof(*dev));
+	dev->count_lock	  = SPIN_LOCK_UNLOCKED;
+	sema_init(&dev->struct_sem, 1);
+
+#ifdef MODULE
+	drm_parse_options(i810);
+#endif
+	DRM_DEBUG("doing misc_register\n");
+	if ((retcode = misc_register(&i810_misc))) {
+		DRM_ERROR("Cannot register \"%s\"\n", I810_NAME);
+		return retcode;
+	}
+	dev->device = MKDEV(MISC_MAJOR, i810_misc.minor);
+	dev->name   = I810_NAME;
+
+   	DRM_DEBUG("doing mem init\n");
+	drm_mem_init();
+	DRM_DEBUG("doing proc init\n");
+	drm_proc_init(dev);
+	DRM_DEBUG("doing agp init\n");
+	dev->agp    = drm_agp_init();
+   	if(dev->agp = NULL) {
+	   	DRM_INFO("The i810 drm module requires the agpgart module"
+			 " to function correctly\nPlease load the agpgart"
+			 " module before you load the i810 module\n");
+	   	drm_proc_cleanup();
+	   	misc_deregister(&i810_misc);
+	   	i810_takedown(dev);
+	   	return -ENOMEM;
+	}
+	DRM_DEBUG("doing ctxbitmap init\n");
+	if((retcode = drm_ctxbitmap_init(dev))) {
+		DRM_ERROR("Cannot allocate memory for context bitmap.\n");
+		drm_proc_cleanup();
+		misc_deregister(&i810_misc);
+		i810_takedown(dev);
+		return retcode;
+	}
+
+	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
+		 I810_NAME,
+		 I810_MAJOR,
+		 I810_MINOR,
+		 I810_PATCHLEVEL,
+		 I810_DATE,
+		 i810_misc.minor);
+
+	return 0;
+}
+
+/* i810_cleanup is called via cleanup_module at module unload time. */
+
+static void __exit i810_cleanup(void)
+{
+	drm_device_t	      *dev = &i810_device;
+
+	DRM_DEBUG("\n");
+
+	drm_proc_cleanup();
+	if (misc_deregister(&i810_misc)) {
+		DRM_ERROR("Cannot unload module\n");
+	} else {
+		DRM_INFO("Module unloaded\n");
+	}
+	drm_ctxbitmap_cleanup(dev);
+	i810_takedown(dev);
+	if (dev->agp) {
+		drm_agp_uninit();
+		drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
+		dev->agp = NULL;
+	}
+}
+
+module_init(i810_init);
+module_exit(i810_cleanup);
+
+
+int i810_version(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_version_t version;
+	int	      len;
+
+	if (copy_from_user(&version,
+			   (drm_version_t *)arg,
+			   sizeof(version)))
+		return -EFAULT;
+
+#define DRM_COPY(name,value)				     \
+	len = strlen(value);				     \
+	if (len > name##_len) len = name##_len;		     \
+	name##_len = strlen(value);			     \
+	if (len && name) {				     \
+		if (copy_to_user(name, value, len))          \
+			return -EFAULT;			     \
+	}
+
+	version.version_major	   = I810_MAJOR;
+	version.version_minor	   = I810_MINOR;
+	version.version_patchlevel = I810_PATCHLEVEL;
+
+	DRM_COPY(version.name, I810_NAME);
+	DRM_COPY(version.date, I810_DATE);
+	DRM_COPY(version.desc, I810_DESC);
+
+	if (copy_to_user((drm_version_t *)arg,
+			 &version,
+			 sizeof(version)))
+		return -EFAULT;
+	return 0;
+}
+
+int i810_open(struct inode *inode, struct file *filp)
+{
+	drm_device_t  *dev    = &i810_device;
+	int	      retcode = 0;
+
+	DRM_DEBUG("open_count = %d\n", dev->open_count);
+	if (!(retcode = drm_open_helper(inode, filp, dev))) {
+#if LINUX_VERSION_CODE < 0x020333
+		MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
+		atomic_inc(&dev->total_open);
+		spin_lock(&dev->count_lock);
+		if (!dev->open_count++) {
+			spin_unlock(&dev->count_lock);
+			return i810_setup(dev);
+		}
+		spin_unlock(&dev->count_lock);
+	}
+	return retcode;
+}
+
+int i810_release(struct inode *inode, struct file *filp)
+{
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev;
+	int	      retcode = 0;
+
+	lock_kernel();
+	dev    = priv->dev;
+	DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
+		  current->pid, dev->device, dev->open_count);
+
+	if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
+	    && dev->lock.pid = current->pid) {
+	      	i810_reclaim_buffers(dev, priv->pid);
+		DRM_ERROR("Process %d dead, freeing lock for context %d\n",
+			  current->pid,
+			  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+		drm_lock_free(dev,
+			      &dev->lock.hw_lock->lock,
+			      _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+
+				/* FIXME: may require heavy-handed reset of
+                                   hardware at this point, possibly
+                                   processed via a callback to the X
+                                   server. */
+	} else if (dev->lock.hw_lock) {
+	   	/* The lock is required to reclaim buffers */
+	   	DECLARE_WAITQUEUE(entry, current);
+	   	add_wait_queue(&dev->lock.lock_queue, &entry);
+		for (;;) {
+			current->state = TASK_INTERRUPTIBLE;
+			if (!dev->lock.hw_lock) {
+				/* Device has been unregistered */
+				retcode = -EINTR;
+				break;
+			}
+			if (drm_lock_take(&dev->lock.hw_lock->lock,
+					  DRM_KERNEL_CONTEXT)) {
+				dev->lock.pid	    = priv->pid;
+				dev->lock.lock_time = jiffies;
+				atomic_inc(&dev->total_locks);
+				break;	/* Got lock */
+			}
+				/* Contention */
+			atomic_inc(&dev->total_sleeps);
+			schedule();
+			if (signal_pending(current)) {
+				retcode = -ERESTARTSYS;
+				break;
+			}
+		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&dev->lock.lock_queue, &entry);
+	   	if(!retcode) {
+		   	i810_reclaim_buffers(dev, priv->pid);
+		   	drm_lock_free(dev, &dev->lock.hw_lock->lock,
+				      DRM_KERNEL_CONTEXT);
+		}
+	}
+	drm_fasync(-1, filp, 0);
+
+	down(&dev->struct_sem);
+	if (priv->prev) priv->prev->next = priv->next;
+	else		dev->file_first	 = priv->next;
+	if (priv->next) priv->next->prev = priv->prev;
+	else		dev->file_last	 = priv->prev;
+	up(&dev->struct_sem);
+
+	drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
+#if LINUX_VERSION_CODE < 0x020333
+	MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
+   	atomic_inc(&dev->total_close);
+   	spin_lock(&dev->count_lock);
+   	if (!--dev->open_count) {
+	   	if (atomic_read(&dev->ioctl_count) || dev->blocked) {
+		   	DRM_ERROR("Device busy: %d %d\n",
+				  atomic_read(&dev->ioctl_count),
+				  dev->blocked);
+		   	spin_unlock(&dev->count_lock);
+			unlock_kernel();
+		   	return -EBUSY;
+		}
+	   	spin_unlock(&dev->count_lock);
+		unlock_kernel();
+		return i810_takedown(dev);
+	}
+	spin_unlock(&dev->count_lock);
+	unlock_kernel();
+	return retcode;
+}
+
+/* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. */
+
+int i810_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	int		 nr	 = DRM_IOCTL_NR(cmd);
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	int		 retcode = 0;
+	drm_ioctl_desc_t *ioctl;
+	drm_ioctl_t	 *func;
+
+	atomic_inc(&dev->ioctl_count);
+	atomic_inc(&dev->total_ioctl);
+	++priv->ioctl_count;
+
+	DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n",
+		  current->pid, cmd, nr, dev->device, priv->authenticated);
+
+	if (nr >= I810_IOCTL_COUNT) {
+		retcode = -EINVAL;
+	} else {
+		ioctl	  = &i810_ioctls[nr];
+		func	  = ioctl->func;
+
+		if (!func) {
+			DRM_DEBUG("no function\n");
+			retcode = -EINVAL;
+		} else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN))
+			    || (ioctl->auth_needed && !priv->authenticated)) {
+			retcode = -EACCES;
+		} else {
+			retcode = (func)(inode, filp, cmd, arg);
+		}
+	}
+
+	atomic_dec(&dev->ioctl_count);
+	return retcode;
+}
+
+int i810_unlock(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+	drm_lock_t	  lock;
+
+	if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
+		return -EFAULT;
+
+	if (lock.context = DRM_KERNEL_CONTEXT) {
+		DRM_ERROR("Process %d using kernel context %d\n",
+			  current->pid, lock.context);
+		return -EINVAL;
+	}
+
+	DRM_DEBUG("%d frees lock (%d holds)\n",
+		  lock.context,
+		  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+	atomic_inc(&dev->total_unlocks);
+	if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock))
+		atomic_inc(&dev->total_contends);
+   	drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT);
+	if (!dev->context_flag) {
+		if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+				  DRM_KERNEL_CONTEXT)) {
+			DRM_ERROR("\n");
+		}
+	}
+#if DRM_DMA_HISTOGRAM
+	atomic_inc(&dev->histo.lhld[drm_histogram_slot(get_cycles()
+						       - dev->lck_start)]);
+#endif
+
+	unblock_all_signals();
+	return 0;
+}
diff -urN linux-2.4.13/drivers/char/drm-4.0/i810_drv.h linux-2.4.13-lia/drivers/char/drm-4.0/i810_drv.h
--- linux-2.4.13/drivers/char/drm-4.0/i810_drv.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/i810_drv.h	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,225 @@
+/* i810_drv.h -- Private header for the Matrox g200/g400 driver -*- linux-c -*-
+ * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ * 	    Jeff Hartmann <jhartmann@valinux.com>
+ *
+ */
+
+#ifndef _I810_DRV_H_
+#define _I810_DRV_H_
+
+typedef struct drm_i810_buf_priv {
+   	u32 *in_use;
+   	int my_use_idx;
+	int currently_mapped;
+	void *virtual;
+	void *kernel_virtual;
+	int map_count;
+   	struct vm_area_struct *vma;
+} drm_i810_buf_priv_t;
+
+typedef struct _drm_i810_ring_buffer{
+	int tail_mask;
+	unsigned long Start;
+	unsigned long End;
+	unsigned long Size;
+	u8 *virtual_start;
+	int head;
+	int tail;
+	int space;
+} drm_i810_ring_buffer_t;
+
+typedef struct drm_i810_private {
+   	int ring_map_idx;
+   	int buffer_map_idx;
+
+   	drm_i810_ring_buffer_t ring;
+	drm_i810_sarea_t *sarea_priv;
+
+      	unsigned long hw_status_page;
+   	unsigned long counter;
+
+   	atomic_t flush_done;
+   	wait_queue_head_t flush_queue;	/* Processes waiting until flush    */
+	drm_buf_t *mmap_buffer;
+
+	
+	u32 front_di1, back_di1, zi1;
+	
+	int back_offset;
+	int depth_offset;
+	int w, h;
+	int pitch;
+} drm_i810_private_t;
+
+				/* i810_drv.c */
+extern int  i810_version(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int  i810_open(struct inode *inode, struct file *filp);
+extern int  i810_release(struct inode *inode, struct file *filp);
+extern int  i810_ioctl(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int  i810_unlock(struct inode *inode, struct file *filp,
+			 unsigned int cmd, unsigned long arg);
+
+				/* i810_dma.c */
+extern int  i810_dma_schedule(drm_device_t *dev, int locked);
+extern int  i810_getbuf(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int  i810_irq_install(drm_device_t *dev, int irq);
+extern int  i810_irq_uninstall(drm_device_t *dev);
+extern int  i810_control(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int  i810_lock(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  i810_dma_init(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int  i810_flush_ioctl(struct inode *inode, struct file *filp,
+			     unsigned int cmd, unsigned long arg);
+extern void i810_reclaim_buffers(drm_device_t *dev, pid_t pid);
+extern int  i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
+			unsigned long arg);
+extern int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma);
+extern int i810_copybuf(struct inode *inode, struct file *filp, 
+			unsigned int cmd, unsigned long arg);
+extern int i810_docopy(struct inode *inode, struct file *filp, 
+		       unsigned int cmd, unsigned long arg);
+
+				/* i810_bufs.c */
+extern int  i810_addbufs(struct inode *inode, struct file *filp, 
+			unsigned int cmd, unsigned long arg);
+extern int  i810_infobufs(struct inode *inode, struct file *filp, 
+			 unsigned int cmd, unsigned long arg);
+extern int  i810_markbufs(struct inode *inode, struct file *filp,
+			 unsigned int cmd, unsigned long arg);
+extern int  i810_freebufs(struct inode *inode, struct file *filp,
+			 unsigned int cmd, unsigned long arg);
+extern int  i810_addmap(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+
+				/* i810_context.c */
+extern int  i810_resctx(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  i810_addctx(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  i810_modctx(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  i810_getctx(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  i810_switchctx(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int  i810_newctx(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  i810_rmctx(struct inode *inode, struct file *filp,
+		      unsigned int cmd, unsigned long arg);
+
+extern int  i810_context_switch(drm_device_t *dev, int old, int new);
+extern int  i810_context_switch_complete(drm_device_t *dev, int new);
+
+#define I810_VERBOSE 0
+
+
+int i810_dma_vertex(struct inode *inode, struct file *filp,
+		    unsigned int cmd, unsigned long arg);
+
+int i810_swap_bufs(struct inode *inode, struct file *filp,
+		   unsigned int cmd, unsigned long arg);
+
+int i810_clear_bufs(struct inode *inode, struct file *filp,
+		    unsigned int cmd, unsigned long arg);
+
+#define GFX_OP_USER_INTERRUPT 		((0<<29)|(2<<23))
+#define GFX_OP_BREAKPOINT_INTERRUPT	((0<<29)|(1<<23))
+#define CMD_REPORT_HEAD			(7<<23)
+#define CMD_STORE_DWORD_IDX		((0x21<<23) | 0x1)
+#define CMD_OP_BATCH_BUFFER  ((0x0<<29)|(0x30<<23)|0x1)
+
+#define INST_PARSER_CLIENT   0x00000000
+#define INST_OP_FLUSH        0x02000000
+#define INST_FLUSH_MAP_CACHE 0x00000001
+
+
+#define BB1_START_ADDR_MASK   (~0x7)
+#define BB1_PROTECTED         (1<<0)
+#define BB1_UNPROTECTED       (0<<0)
+#define BB2_END_ADDR_MASK     (~0x7)
+
+#define I810REG_HWSTAM		0x02098
+#define I810REG_INT_IDENTITY_R	0x020a4
+#define I810REG_INT_MASK_R 	0x020a8
+#define I810REG_INT_ENABLE_R	0x020a0
+
+#define LP_RING     		0x2030
+#define HP_RING     		0x2040
+#define RING_TAIL      		0x00
+#define TAIL_ADDR		0x000FFFF8
+#define RING_HEAD      		0x04
+#define HEAD_WRAP_COUNT     	0xFFE00000
+#define HEAD_WRAP_ONE       	0x00200000
+#define HEAD_ADDR           	0x001FFFFC
+#define RING_START     		0x08
+#define START_ADDR          	0x00FFFFF8
+#define RING_LEN       		0x0C
+#define RING_NR_PAGES       	0x000FF000 
+#define RING_REPORT_MASK    	0x00000006
+#define RING_REPORT_64K     	0x00000002
+#define RING_REPORT_128K    	0x00000004
+#define RING_NO_REPORT      	0x00000000
+#define RING_VALID_MASK     	0x00000001
+#define RING_VALID          	0x00000001
+#define RING_INVALID        	0x00000000
+
+#define GFX_OP_SCISSOR         ((0x3<<29)|(0x1c<<24)|(0x10<<19))
+#define SC_UPDATE_SCISSOR       (0x1<<1)
+#define SC_ENABLE_MASK          (0x1<<0)
+#define SC_ENABLE               (0x1<<0)
+
+#define GFX_OP_SCISSOR_INFO    ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1))
+#define SCI_YMIN_MASK      (0xffff<<16)
+#define SCI_XMIN_MASK      (0xffff<<0)
+#define SCI_YMAX_MASK      (0xffff<<16)
+#define SCI_XMAX_MASK      (0xffff<<0)
+
+#define GFX_OP_COLOR_FACTOR      ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0)
+#define GFX_OP_STIPPLE           ((0x3<<29)|(0x1d<<24)|(0x83<<16))
+#define GFX_OP_MAP_INFO          ((0x3<<29)|(0x1d<<24)|0x2)
+#define GFX_OP_DESTBUFFER_VARS   ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0)
+#define GFX_OP_DRAWRECT_INFO     ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3))
+#define GFX_OP_PRIMITIVE         ((0x3<<29)|(0x1f<<24))
+
+#define CMD_OP_Z_BUFFER_INFO     ((0x0<<29)|(0x16<<23))
+#define CMD_OP_DESTBUFFER_INFO   ((0x0<<29)|(0x15<<23))
+
+#define BR00_BITBLT_CLIENT   0x40000000
+#define BR00_OP_COLOR_BLT    0x10000000
+#define BR00_OP_SRC_COPY_BLT 0x10C00000
+#define BR13_SOLID_PATTERN   0x80000000
+
+
+
+#endif
+
diff -urN linux-2.4.13/drivers/char/drm-4.0/init.c linux-2.4.13-lia/drivers/char/drm-4.0/init.c
--- linux-2.4.13/drivers/char/drm-4.0/init.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/init.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,113 @@
+/* init.c -- Setup/Cleanup for DRM -*- linux-c -*-
+ * Created: Mon Jan  4 08:58:31 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int			      drm_flags		= 0;
+
+/* drm_parse_option parses a single option.  See description for
+   drm_parse_options for details. */
+
+static void drm_parse_option(char *s)
+{
+	char *c, *r;
+	
+	DRM_DEBUG("\"%s\"\n", s);
+	if (!s || !*s) return;
+	for (c = s; *c && *c != ':'; c++); /* find : or \0 */
+	if (*c) r = c + 1; else r = NULL;  /* remember remainder */
+	*c = '\0';			   /* terminate */
+	if (!strcmp(s, "noctx")) {
+		drm_flags |= DRM_FLAG_NOCTX;
+		DRM_INFO("Server-mediated context switching OFF\n");
+		return;
+	}
+	if (!strcmp(s, "debug")) {
+		drm_flags |= DRM_FLAG_DEBUG;
+		DRM_INFO("Debug messages ON\n");
+		return;
+	}
+	DRM_ERROR("\"%s\" is not a valid option\n", s);
+	return;
+}
+
+/* drm_parse_options parse the insmod "drm=" options, or the command-line
+ * options passed to the kernel via LILO.  The grammar of the format is as
+ * follows:
+ *
+ * drm		::= 'drm=' option_list
+ * option_list	::= option [ ';' option_list ]
+ * option	::= 'device:' major
+ *		|   'debug' 
+ *		|   'noctx'
+ * major	::= INTEGER
+ *
+ * Note that 's' contains option_list without the 'drm=' part.
+ *
+ * device=major,minor specifies the device number used for /dev/drm
+ *	  if major = 0 then the misc device is used
+ *	  if major = 0 and minor = 0 then dynamic misc allocation is used
+ * debug=on specifies that debugging messages will be printk'd
+ * debug=trace specifies that each function call will be logged via printk
+ * debug=off turns off all debugging options
+ *
+ */
+
+void drm_parse_options(char *s)
+{
+	char *h, *t, *n;
+	
+	DRM_DEBUG("\"%s\"\n", s ?: "");
+	if (!s || !*s) return;
+
+	for (h = t = n = s; h && *h; h = n) {
+		for (; *t && *t != ';'; t++);	       /* find ; or \0 */
+		if (*t) n = t + 1; else n = NULL;      /* remember next */
+		*t = '\0';			       /* terminate */
+		drm_parse_option(h);		       /* parse */
+	}
+}
+
+/* drm_cpu_valid returns non-zero if the DRI will run on this CPU, and 0
+ * otherwise. */
+
+int drm_cpu_valid(void)
+{
+#if defined(__i386__)
+	if (boot_cpu_data.x86 = 3) return 0; /* No cmpxchg on a 386 */
+#endif
+#if defined(__sparc__) && !defined(__sparc_v9__)
+	if (1)
+		return 0; /* No cmpxchg before v9 sparc. */
+#endif
+	return 1;
+}
diff -urN linux-2.4.13/drivers/char/drm-4.0/ioctl.c linux-2.4.13-lia/drivers/char/drm-4.0/ioctl.c
--- linux-2.4.13/drivers/char/drm-4.0/ioctl.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/ioctl.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,99 @@
+/* ioctl.c -- IOCTL processing for DRM -*- linux-c -*-
+ * Created: Fri Jan  8 09:01:26 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int drm_irq_busid(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_irq_busid_t p;
+	struct pci_dev	*dev;
+
+	if (copy_from_user(&p, (drm_irq_busid_t *)arg, sizeof(p)))
+		return -EFAULT;
+	dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum));
+	if (dev) p.irq = dev->irq;
+	else	 p.irq = 0;
+	DRM_DEBUG("%d:%d:%d => IRQ %d\n",
+		  p.busnum, p.devnum, p.funcnum, p.irq);
+	if (copy_to_user((drm_irq_busid_t *)arg, &p, sizeof(p)))
+		return -EFAULT;
+	return 0;
+}
+
+int drm_getunique(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_unique_t	 u;
+
+	if (copy_from_user(&u, (drm_unique_t *)arg, sizeof(u)))
+		return -EFAULT;
+	if (u.unique_len >= dev->unique_len) {
+		if (copy_to_user(u.unique, dev->unique, dev->unique_len))
+			return -EFAULT;
+	}
+	u.unique_len = dev->unique_len;
+	if (copy_to_user((drm_unique_t *)arg, &u, sizeof(u)))
+		return -EFAULT;
+	return 0;
+}
+
+int drm_setunique(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_unique_t	 u;
+
+	if (dev->unique_len || dev->unique)
+		return -EBUSY;
+
+	if (copy_from_user(&u, (drm_unique_t *)arg, sizeof(u)))
+		return -EFAULT;
+
+	if (!u.unique_len || u.unique_len > 1024)
+		return -EINVAL;
+	
+	dev->unique_len = u.unique_len;
+	dev->unique	= drm_alloc(u.unique_len + 1, DRM_MEM_DRIVER);
+	if (copy_from_user(dev->unique, u.unique, dev->unique_len))
+		return -EFAULT;
+	dev->unique[dev->unique_len] = '\0';
+
+	dev->devname = drm_alloc(strlen(dev->name) + strlen(dev->unique) + 2,
+				 DRM_MEM_DRIVER);
+	sprintf(dev->devname, "%s@%s", dev->name, dev->unique);
+
+	return 0;
+}
diff -urN linux-2.4.13/drivers/char/drm-4.0/lists.c linux-2.4.13-lia/drivers/char/drm-4.0/lists.c
--- linux-2.4.13/drivers/char/drm-4.0/lists.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/lists.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,218 @@
+/* lists.c -- Buffer list handling routines -*- linux-c -*-
+ * Created: Mon Apr 19 20:54:22 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int drm_waitlist_create(drm_waitlist_t *bl, int count)
+{
+	if (bl->count) return -EINVAL;
+	
+	bl->count      = count;
+	bl->bufs       = drm_alloc((bl->count + 2) * sizeof(*bl->bufs),
+				   DRM_MEM_BUFLISTS);
+	bl->rp	       = bl->bufs;
+	bl->wp	       = bl->bufs;
+	bl->end	       = &bl->bufs[bl->count+1];
+	bl->write_lock = SPIN_LOCK_UNLOCKED;
+	bl->read_lock  = SPIN_LOCK_UNLOCKED;
+	return 0;
+}
+
+int drm_waitlist_destroy(drm_waitlist_t *bl)
+{
+	if (bl->rp != bl->wp) return -EINVAL;
+	if (bl->bufs) drm_free(bl->bufs,
+			       (bl->count + 2) * sizeof(*bl->bufs),
+			       DRM_MEM_BUFLISTS);
+	bl->count = 0;
+	bl->bufs  = NULL;
+	bl->rp	  = NULL;
+	bl->wp	  = NULL;
+	bl->end	  = NULL;
+	return 0;
+}
+
+int drm_waitlist_put(drm_waitlist_t *bl, drm_buf_t *buf)
+{							
+	int	      left;
+	unsigned long flags;
+
+	left = DRM_LEFTCOUNT(bl);
+	if (!left) {
+		DRM_ERROR("Overflow while adding buffer %d from pid %d\n",
+			  buf->idx, buf->pid);
+		return -EINVAL;
+	}
+#if DRM_DMA_HISTOGRAM
+	buf->time_queued = get_cycles();
+#endif
+	buf->list	 = DRM_LIST_WAIT;
+	
+	spin_lock_irqsave(&bl->write_lock, flags);
+	*bl->wp = buf;
+	if (++bl->wp >= bl->end) bl->wp = bl->bufs;
+	spin_unlock_irqrestore(&bl->write_lock, flags);
+	
+	return 0;
+}
+
+drm_buf_t *drm_waitlist_get(drm_waitlist_t *bl)
+{
+	drm_buf_t     *buf;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bl->read_lock, flags);
+	buf = *bl->rp;
+	if (bl->rp = bl->wp) {
+		spin_unlock_irqrestore(&bl->read_lock, flags);
+		return NULL;
+	}				     
+	if (++bl->rp >= bl->end) bl->rp = bl->bufs;
+	spin_unlock_irqrestore(&bl->read_lock, flags);
+	
+	return buf;
+}
+
+int drm_freelist_create(drm_freelist_t *bl, int count)
+{
+	atomic_set(&bl->count, 0);
+	bl->next      = NULL;
+	init_waitqueue_head(&bl->waiting);
+	bl->low_mark  = 0;
+	bl->high_mark = 0;
+	atomic_set(&bl->wfh,   0);
+	bl->lock      = SPIN_LOCK_UNLOCKED;
+	++bl->initialized;
+	return 0;
+}
+
+int drm_freelist_destroy(drm_freelist_t *bl)
+{
+	atomic_set(&bl->count, 0);
+	bl->next = NULL;
+	return 0;
+}
+
+int drm_freelist_put(drm_device_t *dev, drm_freelist_t *bl, drm_buf_t *buf)
+{
+	drm_device_dma_t *dma  = dev->dma;
+
+	if (!dma) {
+		DRM_ERROR("No DMA support\n");
+		return 1;
+	}
+
+	if (buf->waiting || buf->pending || buf->list = DRM_LIST_FREE) {
+		DRM_ERROR("Freed buffer %d: w%d, p%d, l%d\n",
+			  buf->idx, buf->waiting, buf->pending, buf->list);
+	}
+	if (!bl) return 1;
+#if DRM_DMA_HISTOGRAM
+	buf->time_freed = get_cycles();
+	drm_histogram_compute(dev, buf);
+#endif
+	buf->list	= DRM_LIST_FREE;
+	
+	spin_lock(&bl->lock);
+	buf->next	= bl->next;
+	bl->next	= buf;
+	spin_unlock(&bl->lock);
+	
+	atomic_inc(&bl->count);
+	if (atomic_read(&bl->count) > dma->buf_count) {
+		DRM_ERROR("%d of %d buffers free after addition of %d\n",
+			  atomic_read(&bl->count), dma->buf_count, buf->idx);
+		return 1;
+	}
+				/* Check for high water mark */
+	if (atomic_read(&bl->wfh) && atomic_read(&bl->count)>=bl->high_mark) {
+		atomic_set(&bl->wfh, 0);
+		wake_up_interruptible(&bl->waiting);
+	}
+	return 0;
+}
+
+static drm_buf_t *drm_freelist_try(drm_freelist_t *bl)
+{
+	drm_buf_t	  *buf;
+
+	if (!bl) return NULL;
+	
+				/* Get buffer */
+	spin_lock(&bl->lock);
+	if (!bl->next) {
+		spin_unlock(&bl->lock);
+		return NULL;
+	}
+	buf	  = bl->next;
+	bl->next  = bl->next->next;
+	spin_unlock(&bl->lock);
+	
+	atomic_dec(&bl->count);
+	buf->next = NULL;
+	buf->list = DRM_LIST_NONE;
+	if (buf->waiting || buf->pending) {
+		DRM_ERROR("Free buffer %d: w%d, p%d, l%d\n",
+			  buf->idx, buf->waiting, buf->pending, buf->list);
+	}
+	
+	return buf;
+}
+
+drm_buf_t *drm_freelist_get(drm_freelist_t *bl, int block)
+{
+	drm_buf_t	  *buf	= NULL;
+	DECLARE_WAITQUEUE(entry, current);
+
+	if (!bl || !bl->initialized) return NULL;
+	
+				/* Check for low water mark */
+	if (atomic_read(&bl->count) <= bl->low_mark) /* Became low */
+		atomic_set(&bl->wfh, 1);
+	if (atomic_read(&bl->wfh)) {
+		if (block) {
+			add_wait_queue(&bl->waiting, &entry);
+			for (;;) {
+				current->state = TASK_INTERRUPTIBLE;
+				if (!atomic_read(&bl->wfh)
+				    && (buf = drm_freelist_try(bl))) break;
+				schedule();
+				if (signal_pending(current)) break;
+			}
+			current->state = TASK_RUNNING;
+			remove_wait_queue(&bl->waiting, &entry);
+		}
+		return buf;
+	}
+		
+	return drm_freelist_try(bl);
+}
diff -urN linux-2.4.13/drivers/char/drm-4.0/lock.c linux-2.4.13-lia/drivers/char/drm-4.0/lock.c
--- linux-2.4.13/drivers/char/drm-4.0/lock.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/lock.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,252 @@
+/* lock.c -- IOCTLs for locking -*- linux-c -*-
+ * Created: Tue Feb  2 08:37:54 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int drm_block(struct inode *inode, struct file *filp, unsigned int cmd,
+	      unsigned long arg)
+{
+	DRM_DEBUG("\n");
+	return 0;
+}
+
+int drm_unblock(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	DRM_DEBUG("\n");
+	return 0;
+}
+
+int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
+{
+	unsigned int old, new, prev;
+
+	do {
+		old = *lock;
+		if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT;
+		else			  new = context | _DRM_LOCK_HELD;
+		prev = cmpxchg(lock, old, new);
+	} while (prev != old);
+	if (_DRM_LOCKING_CONTEXT(old) = context) {
+		if (old & _DRM_LOCK_HELD) {
+			if (context != DRM_KERNEL_CONTEXT) {
+				DRM_ERROR("%d holds heavyweight lock\n",
+					  context);
+			}
+			return 0;
+		}
+	}
+	if (new = (context | _DRM_LOCK_HELD)) {
+				/* Have lock */
+		return 1;
+	}
+	return 0;
+}
+
+/* This takes a lock forcibly and hands it to context.	Should ONLY be used
+   inside *_unlock to give lock to kernel before calling *_dma_schedule. */
+int drm_lock_transfer(drm_device_t *dev,
+		      __volatile__ unsigned int *lock, unsigned int context)
+{
+	unsigned int old, new, prev;
+
+	dev->lock.pid = 0;
+	do {
+		old  = *lock;
+		new  = context | _DRM_LOCK_HELD;
+		prev = cmpxchg(lock, old, new);
+	} while (prev != old);
+	return 1;
+}
+
+int drm_lock_free(drm_device_t *dev,
+		  __volatile__ unsigned int *lock, unsigned int context)
+{
+	unsigned int old, new, prev;
+	pid_t        pid = dev->lock.pid;
+
+	dev->lock.pid = 0;
+	do {
+		old  = *lock;
+		new  = 0;
+		prev = cmpxchg(lock, old, new);
+	} while (prev != old);
+	if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
+		DRM_ERROR("%d freed heavyweight lock held by %d (pid %d)\n",
+			  context,
+			  _DRM_LOCKING_CONTEXT(old),
+			  pid);
+		return 1;
+	}
+	wake_up_interruptible(&dev->lock.lock_queue);
+	return 0;
+}
+
+static int drm_flush_queue(drm_device_t *dev, int context)
+{
+	DECLARE_WAITQUEUE(entry, current);
+	int		  ret	= 0;
+	drm_queue_t	  *q	= dev->queuelist[context];
+	
+	DRM_DEBUG("\n");
+	
+	atomic_inc(&q->use_count);
+	if (atomic_read(&q->use_count) > 1) {
+		atomic_inc(&q->block_write);
+		add_wait_queue(&q->flush_queue, &entry);
+		atomic_inc(&q->block_count);
+		for (;;) {
+			current->state = TASK_INTERRUPTIBLE;
+			if (!DRM_BUFCOUNT(&q->waitlist)) break;
+			schedule();
+			if (signal_pending(current)) {
+				ret = -EINTR; /* Can't restart */
+				break;
+			}
+		}
+		atomic_dec(&q->block_count);
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&q->flush_queue, &entry);
+	}
+	atomic_dec(&q->use_count);
+	atomic_inc(&q->total_flushed);
+		
+				/* NOTE: block_write is still incremented!
+				   Use drm_flush_unlock_queue to decrement. */
+	return ret;
+}
+
+static int drm_flush_unblock_queue(drm_device_t *dev, int context)
+{
+	drm_queue_t	  *q	= dev->queuelist[context];
+	
+	DRM_DEBUG("\n");
+	
+	atomic_inc(&q->use_count);
+	if (atomic_read(&q->use_count) > 1) {
+		if (atomic_read(&q->block_write)) {
+			atomic_dec(&q->block_write);
+			wake_up_interruptible(&q->write_queue);
+		}
+	}
+	atomic_dec(&q->use_count);
+	return 0;
+}
+
+int drm_flush_block_and_flush(drm_device_t *dev, int context,
+			      drm_lock_flags_t flags)
+{
+	int ret = 0;
+	int i;
+	
+	DRM_DEBUG("\n");
+	
+	if (flags & _DRM_LOCK_FLUSH) {
+		ret = drm_flush_queue(dev, DRM_KERNEL_CONTEXT);
+		if (!ret) ret = drm_flush_queue(dev, context);
+	}
+	if (flags & _DRM_LOCK_FLUSH_ALL) {
+		for (i = 0; !ret && i < dev->queue_count; i++) {
+			ret = drm_flush_queue(dev, i);
+		}
+	}
+	return ret;
+}
+
+int drm_flush_unblock(drm_device_t *dev, int context, drm_lock_flags_t flags)
+{
+	int ret = 0;
+	int i;
+	
+	DRM_DEBUG("\n");
+	
+	if (flags & _DRM_LOCK_FLUSH) {
+		ret = drm_flush_unblock_queue(dev, DRM_KERNEL_CONTEXT);
+		if (!ret) ret = drm_flush_unblock_queue(dev, context);
+	}
+	if (flags & _DRM_LOCK_FLUSH_ALL) {
+		for (i = 0; !ret && i < dev->queue_count; i++) {
+			ret = drm_flush_unblock_queue(dev, i);
+		}
+	}
+		
+	return ret;
+}
+
+int drm_finish(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+	int		  ret	  = 0;
+	drm_lock_t	  lock;
+
+	DRM_DEBUG("\n");
+
+	if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
+		return -EFAULT;
+	ret = drm_flush_block_and_flush(dev, lock.context, lock.flags);
+	drm_flush_unblock(dev, lock.context, lock.flags);
+	return ret;
+}
+
+/* If we get here, it means that the process has called DRM_IOCTL_LOCK
+   without calling DRM_IOCTL_UNLOCK.
+   
+   If the lock is not held, then let the signal proceed as usual.
+   
+   If the lock is held, then set the contended flag and keep the signal
+   blocked.
+   
+
+   Return 1 if the signal should be delivered normally.
+   Return 0 if the signal should be blocked.  */
+
+int drm_notifier(void *priv)
+{
+	drm_sigdata_t *s = (drm_sigdata_t *)priv;
+	unsigned int  old, new, prev;
+
+
+				/* Allow signal delivery if lock isn't held */
+	if (!_DRM_LOCK_IS_HELD(s->lock->lock)
+	    || _DRM_LOCKING_CONTEXT(s->lock->lock) != s->context) return 1;
+	
+				/* Otherwise, set flag to force call to
+                                   drmUnlock */
+	do {
+		old  = s->lock->lock;
+		new  = old | _DRM_LOCK_CONT;
+		prev = cmpxchg(&s->lock->lock, old, new);
+	} while (prev != old);
+	return 0;
+}
diff -urN linux-2.4.13/drivers/char/drm-4.0/memory.c linux-2.4.13-lia/drivers/char/drm-4.0/memory.c
--- linux-2.4.13/drivers/char/drm-4.0/memory.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/memory.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,486 @@
+/* memory.c -- Memory management wrappers for DRM -*- linux-c -*-
+ * Created: Thu Feb  4 14:00:34 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include "drmP.h"
+#include <linux/wrapper.h>
+
+typedef struct drm_mem_stats {
+	const char	  *name;
+	int		  succeed_count;
+	int		  free_count;
+	int		  fail_count;
+	unsigned long	  bytes_allocated;
+	unsigned long	  bytes_freed;
+} drm_mem_stats_t;
+
+static spinlock_t	  drm_mem_lock	    = SPIN_LOCK_UNLOCKED;
+static unsigned long	  drm_ram_available = 0; /* In pages */
+static unsigned long	  drm_ram_used	    = 0;
+static drm_mem_stats_t	  drm_mem_stats[]   = {
+	[DRM_MEM_DMA]	    = { "dmabufs"  },
+	[DRM_MEM_SAREA]	    = { "sareas"   },
+	[DRM_MEM_DRIVER]    = { "driver"   },
+	[DRM_MEM_MAGIC]	    = { "magic"	   },
+	[DRM_MEM_IOCTLS]    = { "ioctltab" },
+	[DRM_MEM_MAPS]	    = { "maplist"  },
+	[DRM_MEM_VMAS]	    = { "vmalist"  },
+	[DRM_MEM_BUFS]	    = { "buflist"  },
+	[DRM_MEM_SEGS]	    = { "seglist"  },
+	[DRM_MEM_PAGES]	    = { "pagelist" },
+	[DRM_MEM_FILES]	    = { "files"	   },
+	[DRM_MEM_QUEUES]    = { "queues"   },
+	[DRM_MEM_CMDS]	    = { "commands" },
+	[DRM_MEM_MAPPINGS]  = { "mappings" },
+	[DRM_MEM_BUFLISTS]  = { "buflists" },
+	[DRM_MEM_AGPLISTS]  = { "agplist"  },
+	[DRM_MEM_TOTALAGP]  = { "totalagp" },
+	[DRM_MEM_BOUNDAGP]  = { "boundagp" },
+	[DRM_MEM_CTXBITMAP] = { "ctxbitmap"},
+	{ NULL, 0, }		/* Last entry must be null */
+};
+
+void drm_mem_init(void)
+{
+	drm_mem_stats_t *mem;
+	struct sysinfo	si;
+	
+	for (mem = drm_mem_stats; mem->name; ++mem) {
+		mem->succeed_count   = 0;
+		mem->free_count	     = 0;
+		mem->fail_count	     = 0;
+		mem->bytes_allocated = 0;
+		mem->bytes_freed     = 0;
+	}
+	
+	si_meminfo(&si);
+#if LINUX_VERSION_CODE < 0x020317
+				/* Changed to page count in 2.3.23 */
+	drm_ram_available = si.totalram >> PAGE_SHIFT;
+#else
+	drm_ram_available = si.totalram;
+#endif
+	drm_ram_used	  = 0;
+}
+
+/* drm_mem_info is called whenever a process reads /dev/drm/mem. */
+
+static int _drm_mem_info(char *buf, char **start, off_t offset, int len,
+			 int *eof, void *data)
+{
+	drm_mem_stats_t *pt;
+
+	if (offset > 0) return 0; /* no partial requests */
+	len  = 0;
+	*eof = 1;
+	DRM_PROC_PRINT("		  total counts			"
+		       " |    outstanding  \n");
+	DRM_PROC_PRINT("type	   alloc freed fail	bytes	   freed"
+		       " | allocs      bytes\n\n");
+	DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB         |\n",
+		       "system", 0, 0, 0,
+		       drm_ram_available << (PAGE_SHIFT - 10));
+	DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB         |\n",
+		       "locked", 0, 0, 0, drm_ram_used >> 10);
+	DRM_PROC_PRINT("\n");
+	for (pt = drm_mem_stats; pt->name; pt++) {
+		DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu %10lu | %6d %10ld\n",
+			       pt->name,
+			       pt->succeed_count,
+			       pt->free_count,
+			       pt->fail_count,
+			       pt->bytes_allocated,
+			       pt->bytes_freed,
+			       pt->succeed_count - pt->free_count,
+			       (long)pt->bytes_allocated
+			       - (long)pt->bytes_freed);
+	}
+	
+	return len;
+}
+
+int drm_mem_info(char *buf, char **start, off_t offset, int len,
+		 int *eof, void *data)
+{
+	int ret;
+	
+	spin_lock(&drm_mem_lock);
+	ret = _drm_mem_info(buf, start, offset, len, eof, data);
+	spin_unlock(&drm_mem_lock);
+	return ret;
+}
+
+void *drm_alloc(size_t size, int area)
+{
+	void *pt;
+	
+	if (!size) {
+		DRM_MEM_ERROR(area, "Allocating 0 bytes\n");
+		return NULL;
+	}
+	
+	if (!(pt = kmalloc(size, GFP_KERNEL))) {
+		spin_lock(&drm_mem_lock);
+		++drm_mem_stats[area].fail_count;
+		spin_unlock(&drm_mem_lock);
+		return NULL;
+	}
+	spin_lock(&drm_mem_lock);
+	++drm_mem_stats[area].succeed_count;
+	drm_mem_stats[area].bytes_allocated += size;
+	spin_unlock(&drm_mem_lock);
+	return pt;
+}
+
+void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area)
+{
+	void *pt;
+	
+	if (!(pt = drm_alloc(size, area))) return NULL;
+	if (oldpt && oldsize) {
+		memcpy(pt, oldpt, oldsize);
+		drm_free(oldpt, oldsize, area);
+	}
+	return pt;
+}
+
+char *drm_strdup(const char *s, int area)
+{
+	char *pt;
+	int	 length = s ? strlen(s) : 0;
+	
+	if (!(pt = drm_alloc(length+1, area))) return NULL;
+	strcpy(pt, s);
+	return pt;
+}
+
+void drm_strfree(const char *s, int area)
+{
+	unsigned int size;
+	
+	if (!s) return;
+	
+	size = 1 + (s ? strlen(s) : 0);
+	drm_free((void *)s, size, area);
+}
+
+void drm_free(void *pt, size_t size, int area)
+{
+	int alloc_count;
+	int free_count;
+	
+	if (!pt) DRM_MEM_ERROR(area, "Attempt to free NULL pointer\n");
+	else	 kfree(pt);
+	spin_lock(&drm_mem_lock);
+	drm_mem_stats[area].bytes_freed += size;
+	free_count  = ++drm_mem_stats[area].free_count;
+	alloc_count =	drm_mem_stats[area].succeed_count;
+	spin_unlock(&drm_mem_lock);
+	if (free_count > alloc_count) {
+		DRM_MEM_ERROR(area, "Excess frees: %d frees, %d allocs\n",
+			      free_count, alloc_count);
+	}
+}
+
+unsigned long drm_alloc_pages(int order, int area)
+{
+	unsigned long address;
+	unsigned long bytes	  = PAGE_SIZE << order;
+	unsigned long addr;
+	unsigned int  sz;
+	
+	spin_lock(&drm_mem_lock);
+	if ((drm_ram_used >> PAGE_SHIFT)
+	    > (DRM_RAM_PERCENT * drm_ram_available) / 100) {
+		spin_unlock(&drm_mem_lock);
+		return 0;
+	}
+	spin_unlock(&drm_mem_lock);
+	
+	address = __get_free_pages(GFP_KERNEL, order);
+	if (!address) {
+		spin_lock(&drm_mem_lock);
+		++drm_mem_stats[area].fail_count;
+		spin_unlock(&drm_mem_lock);
+		return 0;
+	}
+	spin_lock(&drm_mem_lock);
+	++drm_mem_stats[area].succeed_count;
+	drm_mem_stats[area].bytes_allocated += bytes;
+	drm_ram_used		            += bytes;
+	spin_unlock(&drm_mem_lock);
+	
+	
+				/* Zero outside the lock */
+	memset((void *)address, 0, bytes);
+	
+				/* Reserve */
+	for (addr = address, sz = bytes;
+	     sz > 0;
+	     addr += PAGE_SIZE, sz -= PAGE_SIZE) {
+#if LINUX_VERSION_CODE >= 0x020400
+				/* Argument type changed in 2.4.0-test6/pre8 */
+		mem_map_reserve(virt_to_page(addr));
+#else
+		mem_map_reserve(MAP_NR(addr));
+#endif
+	}
+	
+	return address;
+}
+
+void drm_free_pages(unsigned long address, int order, int area)
+{
+	unsigned long bytes = PAGE_SIZE << order;
+	int		  alloc_count;
+	int		  free_count;
+	unsigned long addr;
+	unsigned int  sz;
+	
+	if (!address) {
+		DRM_MEM_ERROR(area, "Attempt to free address 0\n");
+	} else {
+				/* Unreserve */
+		for (addr = address, sz = bytes;
+		     sz > 0;
+		     addr += PAGE_SIZE, sz -= PAGE_SIZE) {
+#if LINUX_VERSION_CODE >= 0x020400
+				/* Argument type changed in 2.4.0-test6/pre8 */
+			mem_map_unreserve(virt_to_page(addr));
+#else
+			mem_map_unreserve(MAP_NR(addr));
+#endif
+		}
+		free_pages(address, order);
+	}
+	
+	spin_lock(&drm_mem_lock);
+	free_count  = ++drm_mem_stats[area].free_count;
+	alloc_count =	drm_mem_stats[area].succeed_count;
+	drm_mem_stats[area].bytes_freed += bytes;
+	drm_ram_used			-= bytes;
+	spin_unlock(&drm_mem_lock);
+	if (free_count > alloc_count) {
+		DRM_MEM_ERROR(area,
+			      "Excess frees: %d frees, %d allocs\n",
+			      free_count, alloc_count);
+	}
+}
+
+void *drm_ioremap(unsigned long offset, unsigned long size, drm_device_t *dev)
+{
+	void *pt;
+	
+	if (!size) {
+		DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+			      "Mapping 0 bytes at 0x%08lx\n", offset);
+		return NULL;
+	}
+	
+	if(dev->agp->cant_use_aperture = 0) {
+		goto standard_ioremap;
+	} else {
+		drm_map_t *map    = NULL;
+		int i;
+
+		for(i = 0; i < dev->map_count; i++) {
+			map = dev->maplist[i];
+			if (!map) continue;
+			if (map->offset <= offset &&
+				(map->offset + map->size) >= (offset + size))
+				break;
+		}
+		
+		if(map && map->type = _DRM_AGP) {
+			struct drm_agp_mem *agpmem;
+
+			for(agpmem = dev->agp->memory; agpmem;
+						agpmem = agpmem->next) {
+				if(agpmem->bound <= offset &&
+				   (agpmem->bound + (agpmem->pages
+					<< PAGE_SHIFT)) >= (offset + size))
+					break;
+			}
+
+			if(agpmem = NULL)
+				goto standard_ioremap;
+
+			pt = agpmem->memory->vmptr + (offset - agpmem->bound);
+			goto ioremap_success;
+		} else {
+			goto standard_ioremap;
+		}
+	}
+
+standard_ioremap:
+	if (!(pt = ioremap(offset, size))) {
+		spin_lock(&drm_mem_lock);
+		++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
+		spin_unlock(&drm_mem_lock);
+		return NULL;
+	}
+
+ioremap_success:
+	spin_lock(&drm_mem_lock);
+	++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
+	drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
+	spin_unlock(&drm_mem_lock);
+	return pt;
+}
+
+void drm_ioremapfree(void *pt, unsigned long size, drm_device_t *dev)
+{
+	int alloc_count;
+	int free_count;
+	
+	if (!pt)
+		DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+			      "Attempt to free NULL pointer\n");
+	else if(dev->agp->cant_use_aperture = 0)
+		iounmap(pt);
+	
+	spin_lock(&drm_mem_lock);
+	drm_mem_stats[DRM_MEM_MAPPINGS].bytes_freed += size;
+	free_count  = ++drm_mem_stats[DRM_MEM_MAPPINGS].free_count;
+	alloc_count =	drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
+	spin_unlock(&drm_mem_lock);
+	if (free_count > alloc_count) {
+		DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+			      "Excess frees: %d frees, %d allocs\n",
+			      free_count, alloc_count);
+	}
+}
+
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+agp_memory *drm_alloc_agp(int pages, u32 type)
+{
+	agp_memory *handle;
+
+	if (!pages) {
+		DRM_MEM_ERROR(DRM_MEM_TOTALAGP, "Allocating 0 pages\n");
+		return NULL;
+	}
+	
+	if ((handle = drm_agp_allocate_memory(pages, type))) {
+		spin_lock(&drm_mem_lock);
+		++drm_mem_stats[DRM_MEM_TOTALAGP].succeed_count;
+		drm_mem_stats[DRM_MEM_TOTALAGP].bytes_allocated
+			+= pages << PAGE_SHIFT;
+		spin_unlock(&drm_mem_lock);
+		return handle;
+	}
+	spin_lock(&drm_mem_lock);
+	++drm_mem_stats[DRM_MEM_TOTALAGP].fail_count;
+	spin_unlock(&drm_mem_lock);
+	return NULL;
+}
+
+int drm_free_agp(agp_memory *handle, int pages)
+{
+	int           alloc_count;
+	int           free_count;
+	int           retval = -EINVAL;
+
+	if (!handle) {
+		DRM_MEM_ERROR(DRM_MEM_TOTALAGP,
+			      "Attempt to free NULL AGP handle\n");
+		return retval;;
+	}
+	
+	if (drm_agp_free_memory(handle)) {
+		spin_lock(&drm_mem_lock);
+		free_count  = ++drm_mem_stats[DRM_MEM_TOTALAGP].free_count;
+		alloc_count =   drm_mem_stats[DRM_MEM_TOTALAGP].succeed_count;
+		drm_mem_stats[DRM_MEM_TOTALAGP].bytes_freed
+			+= pages << PAGE_SHIFT;
+		spin_unlock(&drm_mem_lock);
+		if (free_count > alloc_count) {
+			DRM_MEM_ERROR(DRM_MEM_TOTALAGP,
+				      "Excess frees: %d frees, %d allocs\n",
+				      free_count, alloc_count);
+		}
+		return 0;
+	}
+	return retval;
+}
+
+int drm_bind_agp(agp_memory *handle, unsigned int start)
+{
+	int retcode = -EINVAL;
+
+	if (!handle) {
+		DRM_MEM_ERROR(DRM_MEM_BOUNDAGP,
+			      "Attempt to bind NULL AGP handle\n");
+		return retcode;
+	}
+
+	if (!(retcode = drm_agp_bind_memory(handle, start))) {
+		spin_lock(&drm_mem_lock);
+		++drm_mem_stats[DRM_MEM_BOUNDAGP].succeed_count;
+		drm_mem_stats[DRM_MEM_BOUNDAGP].bytes_allocated
+			+= handle->page_count << PAGE_SHIFT;
+		spin_unlock(&drm_mem_lock);
+		return retcode;
+	}
+	spin_lock(&drm_mem_lock);
+	++drm_mem_stats[DRM_MEM_BOUNDAGP].fail_count;
+	spin_unlock(&drm_mem_lock);
+	return retcode;
+}
+
+int drm_unbind_agp(agp_memory *handle)
+{
+	int alloc_count;
+	int free_count;
+	int retcode = -EINVAL;
+	
+	if (!handle) {
+		DRM_MEM_ERROR(DRM_MEM_BOUNDAGP,
+			      "Attempt to unbind NULL AGP handle\n");
+		return retcode;
+	}
+
+	if ((retcode = drm_agp_unbind_memory(handle))) return retcode;
+	spin_lock(&drm_mem_lock);
+	free_count  = ++drm_mem_stats[DRM_MEM_BOUNDAGP].free_count;
+	alloc_count = drm_mem_stats[DRM_MEM_BOUNDAGP].succeed_count;
+	drm_mem_stats[DRM_MEM_BOUNDAGP].bytes_freed
+		+= handle->page_count << PAGE_SHIFT;
+	spin_unlock(&drm_mem_lock);
+	if (free_count > alloc_count) {
+		DRM_MEM_ERROR(DRM_MEM_BOUNDAGP,
+			      "Excess frees: %d frees, %d allocs\n",
+			      free_count, alloc_count);
+	}
+	return retcode;
+}
+#endif
diff -urN linux-2.4.13/drivers/char/drm-4.0/mga_bufs.c linux-2.4.13-lia/drivers/char/drm-4.0/mga_bufs.c
--- linux-2.4.13/drivers/char/drm-4.0/mga_bufs.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/mga_bufs.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,629 @@
+/* mga_bufs.c -- IOCTLs to manage buffers -*- linux-c -*-
+ * Created: Thu Jan 6 01:47:26 2000 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ *	    Jeff Hartmann <jhartmann@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "mga_drv.h"
+#include "linux/un.h"
+
+
+int mga_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
+		    unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_device_dma_t *dma = dev->dma;
+	drm_buf_desc_t request;
+	drm_buf_entry_t *entry;
+	drm_buf_t *buf;
+	unsigned long offset;
+	unsigned long agp_offset;
+	int count;
+	int order;
+	int size;
+	int alignment;
+	int page_order;
+	int total;
+	int byte_count;
+	int i;
+
+	if (!dma) return -EINVAL;
+
+	if (copy_from_user(&request,
+			   (drm_buf_desc_t *)arg,
+			   sizeof(request)))
+		return -EFAULT;
+
+	count = request.count;
+	order = drm_order(request.size);
+	size	= 1 << order;
+	agp_offset = request.agp_start;
+	alignment  = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size):size;
+	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
+	total = PAGE_SIZE << page_order;
+	byte_count = 0;
+
+	DRM_DEBUG("count: %d\n", count);
+	DRM_DEBUG("order: %d\n", order);
+	DRM_DEBUG("size: %d\n", size);
+	DRM_DEBUG("agp_offset: %ld\n", agp_offset);
+	DRM_DEBUG("alignment: %d\n", alignment);
+	DRM_DEBUG("page_order: %d\n", page_order);
+	DRM_DEBUG("total: %d\n", total);
+	DRM_DEBUG("byte_count: %d\n", byte_count);
+
+	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
+	if (dev->queue_count) return -EBUSY; /* Not while in use */
+	spin_lock(&dev->count_lock);
+	if (dev->buf_use) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	atomic_inc(&dev->buf_alloc);
+	spin_unlock(&dev->count_lock);
+   
+	down(&dev->struct_sem);
+	entry = &dma->bufs[order];
+	if (entry->buf_count) {
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM; /* May only call once for each order */
+	}
+
+	/* This isnt neccessarily a good limit, but we have to stop a dumb
+	   32 bit overflow problem below */
+	   
+	if ( count < 0 || count > 4096)
+	{
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -EINVAL;
+	}
+		   
+	entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
+				   DRM_MEM_BUFS);
+	if (!entry->buflist) {
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM;
+	}
+	memset(entry->buflist, 0, count * sizeof(*entry->buflist));
+   
+	entry->buf_size   = size;
+	entry->page_order = page_order;
+	offset = 0;
+
+   
+	while(entry->buf_count < count) {
+		buf = &entry->buflist[entry->buf_count];
+		buf->idx = dma->buf_count + entry->buf_count;
+		buf->total = alignment;
+		buf->order = order;
+		buf->used = 0;
+
+		buf->offset = offset; /* Hrm */
+		buf->bus_address = dev->agp->base + agp_offset + offset;
+		buf->address = (void *)(agp_offset + offset + dev->agp->base);
+		buf->next = NULL;
+		buf->waiting = 0;
+		buf->pending = 0;
+		init_waitqueue_head(&buf->dma_wait);
+		buf->pid = 0;
+
+		buf->dev_private = drm_alloc(sizeof(drm_mga_buf_priv_t),
+					     DRM_MEM_BUFS);
+		buf->dev_priv_size = sizeof(drm_mga_buf_priv_t);
+
+#if DRM_DMA_HISTOGRAM
+		buf->time_queued = 0;
+		buf->time_dispatched = 0;
+		buf->time_completed = 0;
+		buf->time_freed = 0;
+#endif
+		offset = offset + alignment;
+		entry->buf_count++;
+		byte_count += PAGE_SIZE << page_order;
+	}
+   
+	dma->buflist = drm_realloc(dma->buflist,
+				   dma->buf_count * sizeof(*dma->buflist),
+				   (dma->buf_count + entry->buf_count)
+				   * sizeof(*dma->buflist),
+				   DRM_MEM_BUFS);
+	for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++)
+		dma->buflist[i] = &entry->buflist[i - dma->buf_count];
+   
+	dma->buf_count  += entry->buf_count;
+
+	DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count);
+
+	dma->byte_count += byte_count;
+
+	DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count);
+
+	drm_freelist_create(&entry->freelist, entry->buf_count);
+	for (i = 0; i < entry->buf_count; i++) {
+		drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]);
+	}
+   
+	up(&dev->struct_sem);
+   
+	request.count = entry->buf_count;
+	request.size  = size;
+   
+	if (copy_to_user((drm_buf_desc_t *)arg,
+			 &request,
+			 sizeof(request)))
+		return -EFAULT;
+   
+	atomic_dec(&dev->buf_alloc);
+
+	DRM_DEBUG("count: %d\n", count);
+	DRM_DEBUG("order: %d\n", order);
+	DRM_DEBUG("size: %d\n", size);
+	DRM_DEBUG("agp_offset: %ld\n", agp_offset);
+	DRM_DEBUG("alignment: %d\n", alignment);
+	DRM_DEBUG("page_order: %d\n", page_order);
+	DRM_DEBUG("total: %d\n", total);
+	DRM_DEBUG("byte_count: %d\n", byte_count);
+
+	dma->flags = _DRM_DMA_USE_AGP;
+
+	DRM_DEBUG("dma->flags : %x\n", dma->flags);
+
+	return 0;
+}
+
+int mga_addbufs_pci(struct inode *inode, struct file *filp, unsigned int cmd,
+		    unsigned long arg)
+{
+   	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_desc_t	 request;
+	int		 count;
+	int		 order;
+	int		 size;
+	int		 total;
+	int		 page_order;
+	drm_buf_entry_t	 *entry;
+	unsigned long	 page;
+	drm_buf_t	 *buf;
+	int		 alignment;
+	unsigned long	 offset;
+	int		 i;
+	int		 byte_count;
+	int		 page_count;
+
+	if (!dma) return -EINVAL;
+
+	if (copy_from_user(&request,
+			   (drm_buf_desc_t *)arg,
+			   sizeof(request)))
+		return -EFAULT;
+
+	count	   = request.count;
+	order	   = drm_order(request.size);
+	size	   = 1 << order;
+	
+	DRM_DEBUG("count = %d, size = %d (%d), order = %d, queue_count = %d\n",
+		  request.count, request.size, size, order, dev->queue_count);
+
+	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
+	if (dev->queue_count) return -EBUSY; /* Not while in use */
+
+	alignment  = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size):size;
+	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
+	total	   = PAGE_SIZE << page_order;
+
+	spin_lock(&dev->count_lock);
+	if (dev->buf_use) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	atomic_inc(&dev->buf_alloc);
+	spin_unlock(&dev->count_lock);
+	
+	down(&dev->struct_sem);
+	entry = &dma->bufs[order];
+	if (entry->buf_count) {
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM;	/* May only call once for each order */
+	}
+	
+	if(count < 0 || count > 4096)
+	{
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -EINVAL;
+	}
+	
+	entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
+				   DRM_MEM_BUFS);
+	if (!entry->buflist) {
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM;
+	}
+	memset(entry->buflist, 0, count * sizeof(*entry->buflist));
+
+	entry->seglist = drm_alloc(count * sizeof(*entry->seglist),
+				   DRM_MEM_SEGS);
+	if (!entry->seglist) {
+		drm_free(entry->buflist,
+			 count * sizeof(*entry->buflist),
+			 DRM_MEM_BUFS);
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM;
+	}
+	memset(entry->seglist, 0, count * sizeof(*entry->seglist));
+
+	dma->pagelist = drm_realloc(dma->pagelist,
+				    dma->page_count * sizeof(*dma->pagelist),
+				    (dma->page_count + (count << page_order))
+				    * sizeof(*dma->pagelist),
+				    DRM_MEM_PAGES);
+	DRM_DEBUG("pagelist: %d entries\n",
+		  dma->page_count + (count << page_order));
+
+
+	entry->buf_size	  = size;
+	entry->page_order = page_order;
+	byte_count	  = 0;
+	page_count	  = 0;
+	while (entry->buf_count < count) {
+		if (!(page = drm_alloc_pages(page_order, DRM_MEM_DMA))) break;
+		entry->seglist[entry->seg_count++] = page;
+		for (i = 0; i < (1 << page_order); i++) {
+			DRM_DEBUG("page %d @ 0x%08lx\n",
+				  dma->page_count + page_count,
+				  page + PAGE_SIZE * i);
+			dma->pagelist[dma->page_count + page_count++]
+				= page + PAGE_SIZE * i;
+		}
+		for (offset = 0;
+		     offset + size <= total && entry->buf_count < count;
+		     offset += alignment, ++entry->buf_count) {
+			buf	     = &entry->buflist[entry->buf_count];
+			buf->idx     = dma->buf_count + entry->buf_count;
+			buf->total   = alignment;
+			buf->order   = order;
+			buf->used    = 0;
+			buf->offset  = (dma->byte_count + byte_count + offset);
+			buf->address = (void *)(page + offset);
+			buf->next    = NULL;
+			buf->waiting = 0;
+			buf->pending = 0;
+			init_waitqueue_head(&buf->dma_wait);
+			buf->pid     = 0;
+#if DRM_DMA_HISTOGRAM
+			buf->time_queued     = 0;
+			buf->time_dispatched = 0;
+			buf->time_completed  = 0;
+			buf->time_freed	     = 0;
+#endif
+			DRM_DEBUG("buffer %d @ %p\n",
+				  entry->buf_count, buf->address);
+		}
+		byte_count += PAGE_SIZE << page_order;
+	}
+
+	dma->buflist = drm_realloc(dma->buflist,
+				   dma->buf_count * sizeof(*dma->buflist),
+				   (dma->buf_count + entry->buf_count)
+				   * sizeof(*dma->buflist),
+				   DRM_MEM_BUFS);
+	for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++)
+		dma->buflist[i] = &entry->buflist[i - dma->buf_count];
+
+	dma->buf_count	+= entry->buf_count;
+	dma->seg_count	+= entry->seg_count;
+	dma->page_count += entry->seg_count << page_order;
+	dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order);
+	
+	drm_freelist_create(&entry->freelist, entry->buf_count);
+	for (i = 0; i < entry->buf_count; i++) {
+		drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]);
+	}
+	
+	up(&dev->struct_sem);
+
+	request.count = entry->buf_count;
+	request.size  = size;
+
+	if (copy_to_user((drm_buf_desc_t *)arg,
+			 &request,
+			 sizeof(request)))
+		return -EFAULT;
+	
+	atomic_dec(&dev->buf_alloc);
+	return 0;
+}
+
+int mga_addbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_buf_desc_t	 request;
+
+	if (copy_from_user(&request,
+			   (drm_buf_desc_t *)arg,
+			   sizeof(request)))
+		return -EFAULT;
+
+	if(request.flags & _DRM_AGP_BUFFER)
+		return mga_addbufs_agp(inode, filp, cmd, arg);
+	else
+		return mga_addbufs_pci(inode, filp, cmd, arg);
+}
+
+int mga_infobufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_info_t	 request;
+	int		 i;
+	int		 count;
+
+	if (!dma) return -EINVAL;
+
+	spin_lock(&dev->count_lock);
+	if (atomic_read(&dev->buf_alloc)) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	++dev->buf_use;		/* Can't allocate more after this call */
+	spin_unlock(&dev->count_lock);
+
+	if (copy_from_user(&request,
+			   (drm_buf_info_t *)arg,
+			   sizeof(request)))
+		return -EFAULT;
+
+	for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
+		if (dma->bufs[i].buf_count) ++count;
+	}
+	
+	if (request.count >= count) {
+		for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
+			if (dma->bufs[i].buf_count) {
+				if (copy_to_user(&request.list[count].count,
+						 &dma->bufs[i].buf_count,
+						 sizeof(dma->bufs[0]
+							.buf_count)) ||
+				    copy_to_user(&request.list[count].size,
+						 &dma->bufs[i].buf_size,
+						 sizeof(dma->bufs[0].buf_size)) ||
+				    copy_to_user(&request.list[count].low_mark,
+						 &dma->bufs[i]
+						 .freelist.low_mark,
+						 sizeof(dma->bufs[0]
+							.freelist.low_mark)) ||
+				    copy_to_user(&request.list[count]
+						 .high_mark,
+						 &dma->bufs[i]
+						 .freelist.high_mark,
+						 sizeof(dma->bufs[0]
+							.freelist.high_mark)))
+					return -EFAULT;
+				++count;
+			}
+		}
+	}
+	request.count = count;
+
+	if (copy_to_user((drm_buf_info_t *)arg,
+			 &request,
+			 sizeof(request)))
+		return -EFAULT;
+	
+	return 0;
+}
+
+int mga_markbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_desc_t	 request;
+	int		 order;
+	drm_buf_entry_t	 *entry;
+
+	if (!dma) return -EINVAL;
+
+	if (copy_from_user(&request, (drm_buf_desc_t *)arg, sizeof(request)))
+		return -EFAULT;
+
+	order = drm_order(request.size);
+	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
+	entry = &dma->bufs[order];
+
+	if (request.low_mark < 0 || request.low_mark > entry->buf_count)
+		return -EINVAL;
+	if (request.high_mark < 0 || request.high_mark > entry->buf_count)
+		return -EINVAL;
+
+	entry->freelist.low_mark  = request.low_mark;
+	entry->freelist.high_mark = request.high_mark;
+	
+	return 0;
+}
+
+int mga_freebufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_free_t	 request;
+	int		 i;
+	int		 idx;
+	drm_buf_t	 *buf;
+
+	if (!dma) return -EINVAL;
+
+	if (copy_from_user(&request,
+			   (drm_buf_free_t *)arg,
+			   sizeof(request)))
+		return -EFAULT;
+
+	for (i = 0; i < request.count; i++) {
+		if (copy_from_user(&idx,
+				   &request.list[i],
+				   sizeof(idx)))
+			return -EFAULT;
+		if (idx < 0 || idx >= dma->buf_count) {
+			DRM_ERROR("Index %d (of %d max)\n",
+				  idx, dma->buf_count - 1);
+			return -EINVAL;
+		}
+		buf = dma->buflist[idx];
+		if (buf->pid != current->pid) {
+			DRM_ERROR("Process %d freeing buffer owned by %d\n",
+				  current->pid, buf->pid);
+			return -EINVAL;
+		}
+		drm_free_buffer(dev, buf);
+	}
+	
+	return 0;
+}
+
+int mga_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	int		 retcode = 0;
+	const int	 zero	 = 0;
+	unsigned long	 virtual;
+	unsigned long	 address;
+	drm_buf_map_t	 request;
+	int		 i;
+
+	if (!dma) return -EINVAL;
+	
+	spin_lock(&dev->count_lock);
+	if (atomic_read(&dev->buf_alloc)) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	++dev->buf_use;		/* Can't allocate more after this call */
+	spin_unlock(&dev->count_lock);
+
+	if (copy_from_user(&request,
+			   (drm_buf_map_t *)arg,
+			   sizeof(request)))
+		return -EFAULT;
+
+	if (request.count >= dma->buf_count) {
+		if(dma->flags & _DRM_DMA_USE_AGP) {
+			drm_mga_private_t *dev_priv = dev->dev_private;
+			drm_map_t *map = NULL;
+	 
+			map = dev->maplist[dev_priv->buffer_map_idx];
+			if (!map) {
+				retcode = -EINVAL;
+				goto done;
+			}
+
+			DRM_DEBUG("map->offset : %lx\n", map->offset);
+			DRM_DEBUG("map->size : %lx\n", map->size);
+			DRM_DEBUG("map->type : %d\n", map->type);
+			DRM_DEBUG("map->flags : %x\n", map->flags);
+			DRM_DEBUG("map->handle : %p\n", map->handle);
+			DRM_DEBUG("map->mtrr : %d\n", map->mtrr);
+			down_write(&current->mm->mmap_sem);
+			virtual = do_mmap(filp, 0, map->size, 
+					  PROT_READ|PROT_WRITE,
+					  MAP_SHARED, 
+					  (unsigned long)map->offset);
+			up_write(&current->mm->mmap_sem);
+		} else {
+			down_write(&current->mm->mmap_sem);
+			virtual = do_mmap(filp, 0, dma->byte_count,
+					  PROT_READ|PROT_WRITE, MAP_SHARED, 0);
+			up_write(&current->mm->mmap_sem);
+		}
+		if (virtual > -1024UL) {
+			/* Real error */
+			DRM_DEBUG("mmap error\n");
+			retcode = (signed long)virtual;
+			goto done;
+		}
+		request.virtual = (void *)virtual;
+      
+		for (i = 0; i < dma->buf_count; i++) {
+			if (copy_to_user(&request.list[i].idx,
+					 &dma->buflist[i]->idx,
+					 sizeof(request.list[0].idx))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+			if (copy_to_user(&request.list[i].total,
+					 &dma->buflist[i]->total,
+					 sizeof(request.list[0].total))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+			if (copy_to_user(&request.list[i].used,
+					 &zero,
+					 sizeof(zero))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+			address = virtual + dma->buflist[i]->offset;
+			if (copy_to_user(&request.list[i].address,
+					 &address,
+					 sizeof(address))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+		}
+	}
+ done:
+	request.count = dma->buf_count;
+	DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode);
+   
+	if (copy_to_user((drm_buf_map_t *)arg,
+			 &request,
+			 sizeof(request)))
+		return -EFAULT;
+
+	DRM_DEBUG("retcode : %d\n", retcode);
+
+	return retcode;
+}
diff -urN linux-2.4.13/drivers/char/drm-4.0/mga_context.c linux-2.4.13-lia/drivers/char/drm-4.0/mga_context.c
--- linux-2.4.13/drivers/char/drm-4.0/mga_context.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/mga_context.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,209 @@
+/* mga_context.c -- IOCTLs for mga contexts -*- linux-c -*-
+ * Created: Mon Dec 13 09:51:35 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Author: Rickard E. (Rik) Faith <faith@valinux.com>
+ *	   Jeff Hartmann <jhartmann@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "mga_drv.h"
+
+static int mga_alloc_queue(drm_device_t *dev)
+{
+   	return drm_ctxbitmap_next(dev);
+}
+
+int mga_context_switch(drm_device_t *dev, int old, int new)
+{
+        char        buf[64];
+
+        atomic_inc(&dev->total_ctx);
+
+        if (test_and_set_bit(0, &dev->context_flag)) {
+                DRM_ERROR("Reentering -- FIXME\n");
+                return -EBUSY;
+        }
+
+#if DRM_DMA_HISTOGRAM
+        dev->ctx_start = get_cycles();
+#endif
+        
+        DRM_DEBUG("Context switch from %d to %d\n", old, new);
+
+        if (new = dev->last_context) {
+                clear_bit(0, &dev->context_flag);
+                return 0;
+        }
+        
+        if (drm_flags & DRM_FLAG_NOCTX) {
+                mga_context_switch_complete(dev, new);
+        } else {
+                sprintf(buf, "C %d %d\n", old, new);
+                drm_write_string(dev, buf);
+        }
+        
+        return 0;
+}
+
+int mga_context_switch_complete(drm_device_t *dev, int new)
+{
+        dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */
+        dev->last_switch  = jiffies;
+        
+        if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+                DRM_ERROR("Lock isn't held after context switch\n");
+        }
+
+				/* If a context switch is ever initiated
+                                   when the kernel holds the lock, release
+                                   that lock here. */
+#if DRM_DMA_HISTOGRAM
+        atomic_inc(&dev->histo.ctx[drm_histogram_slot(get_cycles()
+                                                      - dev->ctx_start)]);
+                   
+#endif
+        clear_bit(0, &dev->context_flag);
+        wake_up(&dev->context_wait);
+        
+        return 0;
+}
+
+int mga_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_ctx_res_t	res;
+	drm_ctx_t	ctx;
+	int		i;
+
+	if (copy_from_user(&res, (drm_ctx_res_t *)arg, sizeof(res)))
+		return -EFAULT;
+	if (res.count >= DRM_RESERVED_CONTEXTS) {
+		memset(&ctx, 0, sizeof(ctx));
+		for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+			ctx.handle = i;
+			if (copy_to_user(&res.contexts[i],
+					 &i,
+					 sizeof(i)))
+				return -EFAULT;
+		}
+	}
+	res.count = DRM_RESERVED_CONTEXTS;
+	if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res)))
+		return -EFAULT;
+	return 0;
+}
+
+int mga_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+		return -EFAULT;
+	if ((ctx.handle = mga_alloc_queue(dev)) = DRM_KERNEL_CONTEXT) {
+				/* Skip kernel's context and get a new one. */
+		ctx.handle = mga_alloc_queue(dev);
+	}
+        if (ctx.handle = -1) {
+		return -ENOMEM;
+	}
+	DRM_DEBUG("%d\n", ctx.handle);
+	if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx)))
+		return -EFAULT;
+	return 0;
+}
+
+int mga_modctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	unsigned long arg)
+{
+   	/* This does nothing for the mga */
+	return 0;
+}
+
+int mga_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	unsigned long arg)
+{
+	drm_ctx_t ctx;
+
+	if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx)))
+		return -EFAULT;
+	/* This is 0, because we don't hanlde any context flags */
+	ctx.flags = 0;
+	if (copy_to_user((drm_ctx_t*)arg, &ctx, sizeof(ctx)))
+		return -EFAULT;
+	return 0;
+}
+
+int mga_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
+		   unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+		return -EFAULT;
+	DRM_DEBUG("%d\n", ctx.handle);
+	return mga_context_switch(dev, dev->last_context, ctx.handle);
+}
+
+int mga_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+		return -EFAULT;
+	DRM_DEBUG("%d\n", ctx.handle);
+	mga_context_switch_complete(dev, ctx.handle);
+
+	return 0;
+}
+
+int mga_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	      unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+		return -EFAULT;
+	DRM_DEBUG("%d\n", ctx.handle);
+	if(ctx.handle = DRM_KERNEL_CONTEXT+1) priv->remove_auth_on_close = 1;
+
+      	if(ctx.handle != DRM_KERNEL_CONTEXT) {
+	   	drm_ctxbitmap_free(dev, ctx.handle);
+	}
+	
+	return 0;
+}
diff -urN linux-2.4.13/drivers/char/drm-4.0/mga_dma.c linux-2.4.13-lia/drivers/char/drm-4.0/mga_dma.c
--- linux-2.4.13/drivers/char/drm-4.0/mga_dma.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.13-lia/drivers/char/drm-4.0/mga_dma.c	Thu Oct  4 00:21:40 2001
@@ -0,0 +1,1059 @@
+/* mga_dma.c -- DMA support for mga g200/g400 -*- linux-c -*-
+ * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ *	    Jeff Hartmann <jhartmann@valinux.com>
+ *	    Keith Whitwell <keithw@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "mga_drv.h"
+
+#include <linux/interrupt.h>	/* For task queue support */
+
+#define MGA_REG(reg)		2
+#define MGA_BASE(reg)		((unsigned long) \
+				((drm_device_t *)dev)->maplist[MGA_REG(reg)]->handle)
+#define MGA_ADDR(reg)		(MGA_BASE(reg) + reg)
+#define MGA_DEREF(reg)		*(__volatile__ int *)MGA_ADDR(reg)
+#define MGA_READ(reg)		MGA_DEREF(reg)
+#define MGA_WRITE(reg,val) 	do { MGA_DEREF(reg) = val; } while (0)
+
+#define PDEA_pagpxfer_enable 	     0x2
+
+static int mga_flush_queue(drm_device_t *dev);
+
+static unsigned long mga_alloc_page(drm_device_t *dev)
+{
+	unsigned long address;
+
+	address = __get_free_page(GFP_KERNEL);
+	if(address = 0UL) {
+		return 0;
+	}
+	atomic_inc(&virt_to_page(address)->count);
+	set_bit(PG_reserved, &virt_to_page(address)->flags);
+
+	return address;
+}
+
+static void mga_free_page(drm_device_t *dev, unsigned long page)
+{
+	if(!page) return;
+	atomic_dec(&virt_to_page(page)->count);
+	clear_bit(PG_reserved, &virt_to_page(page)->flags);
+	free_page(page);
+	return;
+}
+
+static void mga_delay(void)
+{
+	return;
+}
+
+/* These are two age tags that will never be sent to
+ * the hardware */
+#define MGA_BUF_USED 	0xffffffff
+#define MGA_BUF_FREE	0
+
+static int mga_freelist_init(drm_device_t *dev)
+{
+      	drm_device_dma_t *dma = dev->dma;
+   	drm_buf_t *buf;
+   	drm_mga_buf_priv_t *buf_priv;
+      	drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
+   	drm_mga_freelist_t *item;
+   	int i;
+
+   	dev_priv->head = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER);
+	if(dev_priv->head = NULL) return -ENOMEM;
+   	memset(dev_priv->head, 0, sizeof(drm_mga_freelist_t));
+   	dev_priv->head->age = MGA_BUF_USED;
+
+   	for (i = 0; i < dma->buf_count; i++) {
+	   	buf = dma->buflist[ i ];
+	        buf_priv = buf->dev_private;
+		item = drm_alloc(sizeof(drm_mga_freelist_t),
+				 DRM_MEM_DRIVER);
+	   	if(item = NULL) return -ENOMEM;
+	   	memset(item, 0, sizeof(drm_mga_freelist_t));
+	  	item->age = MGA_BUF_FREE;
+	   	item->prev = dev_priv->head;
+	   	item->next = dev_priv->head->next;
+	   	if(dev_priv->head->next != NULL)
+			dev_priv->head->next->prev = item;
+	   	if(item->next = NULL) dev_priv->tail = item;
+	   	item->buf = buf;
+	   	buf_priv->my_freelist = item;
+		buf_priv->discard = 0;
+		buf_priv->dispatched = 0;
+	   	dev_priv->head->next = item;
+	}
+
+   	return 0;
+}
+
+static void mga_freelist_cleanup(drm_device_t *dev)
+{
+      	drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
+   	drm_mga_freelist_t *item;
+   	drm_mga_freelist_t *prev;
+
+   	item = dev_priv->head;
+   	while(item) {
+	   	prev = item;
+	   	item = item->next;
+	   	drm_free(prev, sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER);
+	}
+
+   	dev_priv->head = dev_priv->tail = NULL;
+}
+
+/* Frees dispatch lock */
+static inline void mga_dma_quiescent(drm_device_t *dev)
+{
+	drm_device_dma_t  *dma      = dev->dma;
+	drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
+	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
+   	unsigned long end;
+	int i;
+
+	DRM_DEBUG("dispatch_status = 0x%02lx\n", dev_priv->dispatch_status);
+	end = jiffies + (HZ*3);
+    	while(1) {
+		if(!test_and_set_bit(MGA_IN_DISPATCH,
+				     &dev_priv->dispatch_status)) {
+			break;
+		}
+	   	if((signed)(end - jiffies) <= 0) {
+			DRM_ERROR("irqs: %d wanted %d\n",
+				  atomic_read(&dev->total_irq),
+				  atomic_read(&dma->total_lost));
+			DRM_ERROR("lockup: dispatch_status = 0x%02lx,"
+				  " jiffies = %lu, end = %lu\n",
+				  dev_priv->dispatch_status, jiffies, end);
+			return;
+		}
+		for (i = 0 ; i < 2000 ; i++) mga_delay();
+	}
+	end = jiffies + (HZ*3);
+    	DRM_DEBUG("quiescent status : %x\n", MGA_READ(MGAREG_STATUS));
+    	while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) {
+		if((signed)(end - jiffies) <= 0) {
+			DRM_ERROR("irqs: %d wanted

  parent reply	other threads:[~2001-10-25  4:27 UTC|newest]

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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=marc-linux-ia64-105590698805620@msgid-missing \
    --to=davidm@hpl.hp.com \
    --cc=linux-ia64@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.