## Automatically generated incremental diff
## From:   linux-2.5.66-bk4
## To:     linux-2.5.66-bk5
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $

diff -urN linux-2.5.66-bk4/Documentation/kernel-parameters.txt linux-2.5.66-bk5/Documentation/kernel-parameters.txt
--- linux-2.5.66-bk4/Documentation/kernel-parameters.txt	Mon Mar 24 14:01:53 2003
+++ linux-2.5.66-bk5/Documentation/kernel-parameters.txt	Mon Mar 31 12:50:20 2003
@@ -207,6 +207,12 @@
 
 	chandev=	[HW,NET] Generic channel device initialisation
  
+ 	clock=		[BUGS=IA-32, HW] gettimeofday timesource override. 
+			Forces specified timesource (if avaliable) to be used
+			when calculating gettimeofday(). If specicified timesource
+			is not avalible, it defaults to PIT. 
+			Format: { pit | tsc | cyclone | ... }
+			
 	cm206=		[HW,CD]
 			Format: { auto | [<io>,][<irq>] }
 
@@ -390,6 +396,10 @@
 			Run specified binary instead of /sbin/init as init
 			process.
 
+	initcall_debug	[KNL] Trace initcalls as they are executed.  Useful
+			for working out where the kernel is dying during
+			startup.
+
 	initrd=		[BOOT] Specify the location of the initial ramdisk
 
 	inport_irq=	[HW] Inport (ATI XL and Microsoft) busmouse driver
diff -urN linux-2.5.66-bk4/Documentation/networking/bonding.txt linux-2.5.66-bk5/Documentation/networking/bonding.txt
--- linux-2.5.66-bk4/Documentation/networking/bonding.txt	Mon Mar 24 14:00:11 2003
+++ linux-2.5.66-bk5/Documentation/networking/bonding.txt	Mon Mar 31 12:50:20 2003
@@ -7,6 +7,7 @@
   - Constantine Gavrilov <const-g at xpert.com>
   - Chad N. Tindel <ctindel at ieee dot org>
   - Janice Girouard <girouard at us dot ibm dot com>
+  - Jay Vosburgh <fubar at us dot ibm dot com>
 
 Note :
 ------
@@ -199,28 +200,42 @@
 parameters be specified, otherwise serious network degradation will occur
 during link failures.
 
+max_bonds
+
+	Specifies the number of bonding devices to create for this
+	instance of the bonding driver.  E.g., if max_bonds is 3, and
+	the bonding driver is not already loaded, then bond0, bond1
+	and bond2 will be created.  The default value is 1.
+
 mode
-        Specifies one of four bonding policies. The default is round-robin.
-        Possible values are:
- 
-        0       Round-robin policy: Transmit in a sequential order from the
-                first available slave through the last. This mode provides
-                load balancing and fault tolerance.
-
-        1       Active-backup policy: Only one slave in the bond is active. A 
-                different slave becomes active if, and only if, the active slave
-                fails. The bond's MAC address is externally visible on only 
-                one port (network adapter) to avoid confusing the switch.
-                This mode provides fault tolerance.
- 
- 
-        2       XOR policy: Transmit based on [(source MAC address XOR'd with 
-                destination MAC address) modula slave count]. This selects the 
-                same slave for each destination MAC address. This mode provides
-                load balancing and fault tolerance.
 
-        3       Broadcast policy: transmits everything on all slave interfaces.
-                This mode provides fault tolerance.
+	Specifies one of four bonding policies. The default is
+round-robin (balance-rr).  Possible values are (you can use either the
+text or numeric option):
+ 
+	balance-rr or 0
+		Round-robin policy: Transmit in a sequential order
+		from the first available slave through the last. This
+		mode provides load balancing and fault tolerance.
+
+	active-backup or 1
+		Active-backup policy: Only one slave in the bond is
+		active. A different slave becomes active if, and only
+		if, the active slave fails. The bond's MAC address is
+		externally visible on only one port (network adapter)
+		to avoid confusing the switch.  This mode provides
+		fault tolerance.
+ 
+        balance-xor or 2
+		XOR policy: Transmit based on [(source MAC address
+		XOR'd with destination MAC address) modula slave
+		count]. This selects the same slave for each
+		destination MAC address. This mode provides load
+		balancing and fault tolerance.
+
+	broadcast or 3
+		Broadcast policy: transmits everything on all slave
+		interfaces. This mode provides fault tolerance.
 
 miimon
  
@@ -229,6 +244,27 @@
         100 is a good starting point. See High Availability section for 
         additional information. The default value is 0.
 
+use_carrier
+
+        Specifies whether or not miimon should use MII or ETHTOOL
+        ioctls vs. netif_carrier_ok() to determine the link status.
+        The MII or ETHTOOL ioctls are less efficient and utilize a
+        deprecated calling sequence within the kernel.  The
+        netif_carrier_ok() relies on the device driver to maintain its
+        state with netif_carrier_on/off; at this writing, most, but
+        not all, device drivers support this facility.
+
+        If bonding insists that the link is up when it should not be,
+        it may be that your network device driver does not support
+        netif_carrier_on/off.  This is because the default state for
+        netif_carrier is "carrier on." In this case, disabling
+        use_carrier will cause bonding to revert to the MII / ETHTOOL
+        ioctl method to determine the link state.
+
+        A value of 1 enables the use of netif_carrier_ok(), a value of
+        0 will use the deprecated MII / ETHTOOL ioctls.  The default
+        value is 1.
+
 downdelay
  
         Specifies the delay time in milli-seconds to disable a link after a 
@@ -277,14 +313,17 @@
 
 multicast
 
-        Integer value for the mode of operation for multicast support.
+        Option specifying the mode of operation for multicast support.
         Possible values are:
 
-        0       Disabled (no multicast support)
+	disabled or 0
+		Disabled (no multicast support)
 
-        1       Enabled on active slave only, useful in active-backup mode
+        active or 1
+		Enabled on active slave only, useful in active-backup mode
 
-        2       Enabled on all slaves, this is the default
+	all or 2
+		Enabled on all slaves, this is the default
 
 
 Configuring Multiple Bonds
@@ -321,7 +360,52 @@
 alias bond0 bonding
 options bond0 arp_interval=60 arp_ip_target=192.168.0.100
 
+Potential Problems When Using ARP Monitor
+=========================================
+
+1. Driver support
 
+The ARP monitor relies on the network device driver to maintain two
+statistics: the last receive time (dev->last_rx), and the last
+transmit time (dev->trans_start).  If the network device driver does
+not update one or both of these, then the typical result will be that,
+upon startup, all links in the bond will immediately be declared down,
+and remain that way.  A network monitoring tool (tcpdump, e.g.) will
+show ARP requests and replies being sent and received on the bonding
+device.
+
+The possible resolutions for this are to (a) fix the device driver, or
+(b) discontinue the ARP monitor (using miimon as an alternative, for
+example).
+
+2. Adventures in Routing
+
+When bonding is set up with the ARP monitor, it is important that the
+slave devices not have routes that supercede routes of the master (or,
+generally, not have routes at all).  For example, suppose the bonding
+device bond0 has two slaves, eth0 and eth1, and the routing table is
+as follows:
+
+Kernel IP routing table
+Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
+10.0.0.0        0.0.0.0         255.255.0.0     U        40 0          0 eth0
+10.0.0.0        0.0.0.0         255.255.0.0     U        40 0          0 eth1
+10.0.0.0        0.0.0.0         255.255.0.0     U        40 0          0 bond0
+127.0.0.0       0.0.0.0         255.0.0.0       U        40 0          0 lo
+
+In this case, the ARP monitor (and ARP itself) may become confused,
+because ARP requests will be sent on one interface (bond0), but the
+corresponding reply will arrive on a different interface (eth0).  This
+reply looks to ARP as an unsolicited ARP reply (because ARP matches
+replies on an interface basis), and is discarded.  This will likely
+still update the receive/transmit times in the driver, but will lose
+packets.
+
+The resolution here is simply to insure that slaves do not have routes
+of their own, and if for some reason they must, those routes do not
+supercede routes of their master.  This should generally be the case,
+but unusual configurations or errant manual or automatic static route
+additions may cause trouble.
 
 Switch Configuration
 ====================
@@ -462,7 +546,7 @@
 	If not explicitly configured with ifconfig, the MAC address of the
 	bonding device is taken from its first slave device. This MAC address
 	is then passed to all following slaves and remains persistent (even if
-	the first slave is removed) until the bonding device is brought
+	the the first slave is removed) until the bonding device is brought
 	down or reconfigured.
 	
 	If you wish to change the MAC address, you can set it with ifconfig:
@@ -606,12 +690,16 @@
 
 To use this mode, pass "mode=1" to the module at load time :
 
+    # modprobe bonding miimon=100 mode=active-backup
+
+	or:
+
     # modprobe bonding miimon=100 mode=1
 
 Or, put in your /etc/modules.conf :
 
     alias bond0 bonding
-    options bond0 miimon=100 mode=1
+    options bond0 miimon=100 mode=active-backup
 
 Example 1: Using multiple host and multiple switches to build a "no single
 point of failure" solution.
@@ -698,7 +786,7 @@
 Examples :
 
     # modprobe bonding miimon=100 mode=1 downdelay=2000 updelay=5000
-    # modprobe bonding miimon=100 mode=0 downdelay=0 updelay=5000
+    # modprobe bonding miimon=100 mode=balance-rr downdelay=0 updelay=5000
 
 
 Promiscuous Sniffing notes
diff -urN linux-2.5.66-bk4/Makefile linux-2.5.66-bk5/Makefile
--- linux-2.5.66-bk4/Makefile	Mon Mar 31 12:50:18 2003
+++ linux-2.5.66-bk5/Makefile	Mon Mar 31 12:50:20 2003
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 66
-EXTRAVERSION = -bk4
+EXTRAVERSION = -bk5
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
diff -urN linux-2.5.66-bk4/arch/i386/kernel/smpboot.c linux-2.5.66-bk5/arch/i386/kernel/smpboot.c
--- linux-2.5.66-bk4/arch/i386/kernel/smpboot.c	Mon Mar 24 14:00:35 2003
+++ linux-2.5.66-bk5/arch/i386/kernel/smpboot.c	Mon Mar 31 12:50:20 2003
@@ -422,7 +422,7 @@
 	/*
 	 *      Synchronize the TSC with the BP
 	 */
-	if (cpu_has_tsc)
+	if (cpu_has_tsc && cpu_khz)
 		synchronize_tsc_ap();
 }
 
@@ -1114,7 +1114,7 @@
 	/*
 	 * Synchronize the TSC with the AP
 	 */
-	if (cpu_has_tsc && cpucount)
+	if (cpu_has_tsc && cpucount && cpu_khz)
 		synchronize_tsc_bp();
 }
 
diff -urN linux-2.5.66-bk4/arch/i386/kernel/timers/timer.c linux-2.5.66-bk5/arch/i386/kernel/timers/timer.c
--- linux-2.5.66-bk4/arch/i386/kernel/timers/timer.c	Mon Mar 24 14:01:44 2003
+++ linux-2.5.66-bk5/arch/i386/kernel/timers/timer.c	Mon Mar 31 12:50:20 2003
@@ -1,4 +1,6 @@
+#include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/string.h>
 #include <asm/timer.h>
 
 /* list of externed timers */
@@ -17,6 +19,17 @@
 	NULL,
 };
 
+static char clock_override[10] __initdata;
+
+static int __init clock_setup(char* str)
+{
+	if (str) {
+		strncpy(clock_override, str,10);
+		clock_override[9] = '\0';
+	}
+	return 1;
+}
+__setup("clock=", clock_setup);
 
 /* iterates through the list of timers, returning the first 
  * one that initializes successfully.
@@ -28,7 +41,7 @@
 	/* find most preferred working timer */
 	while (timers[i]) {
 		if (timers[i]->init)
-			if (timers[i]->init() == 0)
+			if (timers[i]->init(clock_override) == 0)
 				return timers[i];
 		++i;
 	}
diff -urN linux-2.5.66-bk4/arch/i386/kernel/timers/timer_cyclone.c linux-2.5.66-bk5/arch/i386/kernel/timers/timer_cyclone.c
--- linux-2.5.66-bk4/arch/i386/kernel/timers/timer_cyclone.c	Mon Mar 24 14:00:56 2003
+++ linux-2.5.66-bk5/arch/i386/kernel/timers/timer_cyclone.c	Mon Mar 31 12:50:20 2003
@@ -10,6 +10,7 @@
 #include <linux/init.h>
 #include <linux/timex.h>
 #include <linux/errno.h>
+#include <linux/string.h>
 
 #include <asm/timer.h>
 #include <asm/io.h>
@@ -73,7 +74,7 @@
 	return delay_at_last_interrupt + offset;
 }
 
-static int init_cyclone(void)
+static int __init init_cyclone(char* override)
 {
 	u32* reg;	
 	u32 base;		/* saved cyclone base address */
@@ -81,8 +82,11 @@
 	u32 offset;		/* offset from pageaddr to cyclone_timer register */
 	int i;
 	
+	/* check clock override */
+	if (override[0] && strncmp(override,"cyclone",7))
+			return -ENODEV;
+
 	/*make sure we're on a summit box*/
-	/*XXX need to use proper summit hooks! such as xapic -john*/
 	if(!use_cyclone) return -ENODEV; 
 	
 	printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n");
diff -urN linux-2.5.66-bk4/arch/i386/kernel/timers/timer_none.c linux-2.5.66-bk5/arch/i386/kernel/timers/timer_none.c
--- linux-2.5.66-bk4/arch/i386/kernel/timers/timer_none.c	Mon Mar 24 14:00:41 2003
+++ linux-2.5.66-bk5/arch/i386/kernel/timers/timer_none.c	Mon Mar 31 12:50:20 2003
@@ -1,6 +1,7 @@
+#include <linux/init.h>
 #include <asm/timer.h>
 
-static int init_none(void)
+static int __init init_none(char* override)
 {
 	return 0;
 }
diff -urN linux-2.5.66-bk4/arch/i386/kernel/timers/timer_pit.c linux-2.5.66-bk5/arch/i386/kernel/timers/timer_pit.c
--- linux-2.5.66-bk4/arch/i386/kernel/timers/timer_pit.c	Mon Mar 24 14:01:23 2003
+++ linux-2.5.66-bk5/arch/i386/kernel/timers/timer_pit.c	Mon Mar 31 12:50:20 2003
@@ -17,8 +17,12 @@
 extern spinlock_t i8253_lock;
 #include "do_timer.h"
 
-static int init_pit(void)
+static int __init init_pit(char* override)
 {
+	/* check clock override */
+	if (override[0] && strncmp(override,"pit",3))
+		printk(KERN_ERR "Warning: clock= override failed. Defaulting to PIT\n");
+
 	return 0;
 }
 
diff -urN linux-2.5.66-bk4/arch/i386/kernel/timers/timer_tsc.c linux-2.5.66-bk5/arch/i386/kernel/timers/timer_tsc.c
--- linux-2.5.66-bk4/arch/i386/kernel/timers/timer_tsc.c	Mon Mar 24 14:00:55 2003
+++ linux-2.5.66-bk5/arch/i386/kernel/timers/timer_tsc.c	Mon Mar 31 12:50:20 2003
@@ -8,6 +8,7 @@
 #include <linux/timex.h>
 #include <linux/errno.h>
 #include <linux/cpufreq.h>
+#include <linux/string.h>
 
 #include <asm/timer.h>
 #include <asm/io.h>
@@ -244,8 +245,13 @@
 #endif
 
 
-static int init_tsc(void)
+static int __init init_tsc(char* override)
 {
+
+	/* check clock override */
+	if (override[0] && strncmp(override,"tsc",3))
+			return -ENODEV;
+
 	/*
 	 * If we have APM enabled or the CPU clock speed is variable
 	 * (CPU stops clock on HLT or slows clock to save power)
diff -urN linux-2.5.66-bk4/arch/i386/mm/boot_ioremap.c linux-2.5.66-bk5/arch/i386/mm/boot_ioremap.c
--- linux-2.5.66-bk4/arch/i386/mm/boot_ioremap.c	Mon Mar 24 14:01:53 2003
+++ linux-2.5.66-bk5/arch/i386/mm/boot_ioremap.c	Mon Mar 31 12:50:20 2003
@@ -19,6 +19,7 @@
 #undef CONFIG_X86_PAE
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/tlbflush.h>
 #include <linux/init.h>
 #include <linux/stddef.h>
 
@@ -48,10 +49,12 @@
 {
 	boot_pte_t* pte;
 	int i;
+	char *vaddr = virtual_source;
 
 	pte = boot_vaddr_to_pte(virtual_source);
 	for (i=0; i < nrpages; i++, phys_addr += PAGE_SIZE, pte++) {
 		set_pte(pte, pfn_pte(phys_addr>>PAGE_SHIFT, PAGE_KERNEL));
+		__flush_tlb_one(&vaddr[i*PAGE_SIZE]);
 	}
 }
 
diff -urN linux-2.5.66-bk4/arch/i386/mm/highmem.c linux-2.5.66-bk5/arch/i386/mm/highmem.c
--- linux-2.5.66-bk4/arch/i386/mm/highmem.c	Mon Mar 24 14:00:41 2003
+++ linux-2.5.66-bk5/arch/i386/mm/highmem.c	Mon Mar 31 12:50:20 2003
@@ -2,8 +2,7 @@
 
 void *kmap(struct page *page)
 {
-	if (in_interrupt())
-		BUG();
+	might_sleep();
 	if (page < highmem_start_page)
 		return page_address(page);
 	return kmap_high(page);
diff -urN linux-2.5.66-bk4/drivers/base/base.h linux-2.5.66-bk5/drivers/base/base.h
--- linux-2.5.66-bk4/drivers/base/base.h	Mon Mar 24 14:00:18 2003
+++ linux-2.5.66-bk5/drivers/base/base.h	Mon Mar 31 12:50:20 2003
@@ -1,5 +1,3 @@
-#undef DEBUG
-
 extern struct semaphore device_sem;
 extern struct semaphore devclass_sem;
 
diff -urN linux-2.5.66-bk4/drivers/base/cpu.c linux-2.5.66-bk5/drivers/base/cpu.c
--- linux-2.5.66-bk4/drivers/base/cpu.c	Mon Mar 24 14:00:14 2003
+++ linux-2.5.66-bk5/drivers/base/cpu.c	Mon Mar 31 12:50:20 2003
@@ -48,6 +48,9 @@
 
 int __init cpu_dev_init(void)
 {
-	devclass_register(&cpu_devclass);
-	return driver_register(&cpu_driver);
+	int error;
+	if (!(error = devclass_register(&cpu_devclass)))
+		if ((error = driver_register(&cpu_driver)))
+			devclass_unregister(&cpu_devclass);
+	return error;
 }
diff -urN linux-2.5.66-bk4/drivers/base/driver.c linux-2.5.66-bk5/drivers/base/driver.c
--- linux-2.5.66-bk4/drivers/base/driver.c	Mon Mar 24 14:01:24 2003
+++ linux-2.5.66-bk5/drivers/base/driver.c	Mon Mar 31 12:50:20 2003
@@ -82,6 +82,7 @@
 int driver_register(struct device_driver * drv)
 {
 	INIT_LIST_HEAD(&drv->devices);
+	INIT_LIST_HEAD(&drv->class_list);
 	init_MUTEX_LOCKED(&drv->unload_sem);
 	return bus_add_driver(drv);
 }
diff -urN linux-2.5.66-bk4/drivers/base/memblk.c linux-2.5.66-bk5/drivers/base/memblk.c
--- linux-2.5.66-bk4/drivers/base/memblk.c	Mon Mar 24 14:01:48 2003
+++ linux-2.5.66-bk5/drivers/base/memblk.c	Mon Mar 31 12:50:20 2003
@@ -47,9 +47,12 @@
 }
 
 
-static int __init register_memblk_type(void)
+int __init register_memblk_type(void)
 {
-	int error = devclass_register(&memblk_devclass);
-	return error ? error : driver_register(&memblk_driver);
+	int error;
+	if (!(error = devclass_register(&memblk_devclass)))
+		if (error = driver_register(&memblk_driver))
+			devclass_unregister(&memblk_devclass);
+	return error;
 }
 postcore_initcall(register_memblk_type);
diff -urN linux-2.5.66-bk4/drivers/base/node.c linux-2.5.66-bk5/drivers/base/node.c
--- linux-2.5.66-bk4/drivers/base/node.c	Mon Mar 24 14:00:08 2003
+++ linux-2.5.66-bk5/drivers/base/node.c	Mon Mar 31 12:50:20 2003
@@ -89,9 +89,12 @@
 }
 
 
-static int __init register_node_type(void)
+int __init register_node_type(void)
 {
-	int error = devclass_register(&node_devclass);
-	return error ? error : driver_register(&node_driver);
+	int error;
+	if (!(error = devclass_register(&node_devclass)))
+		if (error = driver_register(&node_driver))
+			devclass_unregister(&node_devclass);
+	return error;
 }
 postcore_initcall(register_node_type);
diff -urN linux-2.5.66-bk4/drivers/char/drm/Kconfig linux-2.5.66-bk5/drivers/char/drm/Kconfig
--- linux-2.5.66-bk4/drivers/char/drm/Kconfig	Mon Mar 24 14:01:23 2003
+++ linux-2.5.66-bk5/drivers/char/drm/Kconfig	Mon Mar 31 12:50:20 2003
@@ -22,7 +22,13 @@
 	  Choose this option if you have a 3dfx Banshee or Voodoo3 (or later),
 	  graphics card.  If M is selected, the module will be called tdfx.
 
-#    tristate '  3dlabs GMX 2000' CONFIG_DRM_GAMMA
+config DRM_GAMMA
+	tristate "3dlabs GMX 2000"
+	depends on DRM && n
+	help
+	  This is the old gamma driver, disabled for now unless somebody
+	  tells me it actually might work.
+
 config DRM_R128
 	tristate "ATI Rage 128"
 	depends on DRM
@@ -60,4 +66,3 @@
 	  Choose this option if you have a Matrox G200, G400 or G450 graphics
 	  card.  If M is selected, the module will be called mga.  AGP
 	  support is required for this driver to work.
-
diff -urN linux-2.5.66-bk4/drivers/char/drm/Makefile linux-2.5.66-bk5/drivers/char/drm/Makefile
--- linux-2.5.66-bk4/drivers/char/drm/Makefile	Mon Mar 24 14:01:43 2003
+++ linux-2.5.66-bk5/drivers/char/drm/Makefile	Mon Mar 31 12:50:20 2003
@@ -7,7 +7,7 @@
 r128-objs   := r128_drv.o r128_cce.o r128_state.o r128_irq.o
 mga-objs    := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o
 i810-objs   := i810_drv.o i810_dma.o
-i830-objs   := i830_drv.o i830_dma.o
+i830-objs   := i830_drv.o i830_dma.o i830_irq.o
 radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o
 ffb-objs    := ffb_drv.o ffb_context.o
 
diff -urN linux-2.5.66-bk4/drivers/char/drm/drmP.h linux-2.5.66-bk5/drivers/char/drm/drmP.h
--- linux-2.5.66-bk4/drivers/char/drm/drmP.h	Mon Mar 24 14:01:13 2003
+++ linux-2.5.66-bk5/drivers/char/drm/drmP.h	Mon Mar 31 12:50:21 2003
@@ -254,6 +254,7 @@
  		}							\
 	}								\
 } while(0)
+#define DRM_DROP_MAP(_map)
 
 				/* Internal types and structures */
 #define DRM_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
@@ -268,6 +269,17 @@
 	(_map) = (_dev)->context_sareas[_ctx];		\
 } while(0)
 
+#define LOCK_TEST_WITH_RETURN( dev, filp )				\
+do {									\
+	if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) ||		\
+	     dev->lock.filp != filp ) {				\
+		DRM_ERROR( "%s called without lock held\n",		\
+			   __FUNCTION__ );				\
+		return -EINVAL;						\
+	}								\
+} while (0)
+
+
 typedef int drm_ioctl_t( struct inode *inode, struct file *filp,
 			 unsigned int cmd, unsigned long arg );
 
@@ -316,7 +328,7 @@
 	__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	     */
+	struct file       *filp;       /* Pointer to holding file descr	     */
 	int		  context;     /* Kernel queue for this buffer	     */
 	int		  while_locked;/* Dispatch this buffer while locked  */
 	enum {
@@ -434,7 +446,7 @@
 
 typedef struct drm_lock_data {
 	drm_hw_lock_t	  *hw_lock;	/* Hardware lock		   */
-	pid_t		  pid;		/* PID of lock holder (0=kernel)   */
+	struct file       *filp;	/* File descr 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;
@@ -516,6 +528,8 @@
 	drm_map_t		*map;
 } drm_map_list_t;
 
+typedef drm_map_t drm_local_map_t;
+
 #if __HAVE_VBL_IRQ
 
 typedef struct drm_vbl_sig {
@@ -591,6 +605,7 @@
    	atomic_t          vbl_received;
 	spinlock_t        vbl_lock;
 	drm_vbl_sig_t     vbl_sigs;
+	unsigned int      vbl_pending;
 #endif
 	cycles_t	  ctx_start;
 	cycles_t	  lck_start;
@@ -807,15 +822,15 @@
 extern int	     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 void	     DRM(reclaim_buffers)( struct file *filp );
 #if __HAVE_OLD_DMA
 /* GH: This is a dirty hack for now...
  */
 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);
+extern int	     DRM(dma_enqueue)(struct file *filp, drm_dma_t *dma);
+extern int	     DRM(dma_get_buffers)(struct file *filp, drm_dma_t *dma);
 #endif
 #if __HAVE_DMA_IRQ
 extern int           DRM(control)( struct inode *inode, struct file *filp,
diff -urN linux-2.5.66-bk4/drivers/char/drm/drm_agpsupport.h linux-2.5.66-bk5/drivers/char/drm/drm_agpsupport.h
--- linux-2.5.66-bk4/drivers/char/drm/drm_agpsupport.h	Mon Mar 24 13:59:46 2003
+++ linux-2.5.66-bk5/drivers/char/drm/drm_agpsupport.h	Mon Mar 31 12:50:21 2003
@@ -266,12 +266,12 @@
 		head->cant_use_aperture = head->agp_info.cant_use_aperture;
 		head->page_mask = head->agp_info.page_mask;
 #endif
-		
-		DRM_DEBUG("AGP %d.%d, aperture @ 0x%08lx %ZuMB\n",
-			  head->agp_info.version.major,
-			  head->agp_info.version.minor,
-			  head->agp_info.aper_base,
-			  head->agp_info.aper_size);
+
+		DRM_INFO("AGP %d.%d aperture @ 0x%08lx %ZuMB\n",
+			 head->agp_info.version.major,
+			 head->agp_info.version.minor,
+			 head->agp_info.aper_base,
+			 head->agp_info.aper_size);
 	}
 	return head;
 }
diff -urN linux-2.5.66-bk4/drivers/char/drm/drm_bufs.h linux-2.5.66-bk5/drivers/char/drm/drm_bufs.h
--- linux-2.5.66-bk4/drivers/char/drm/drm_bufs.h	Mon Mar 24 14:00:09 2003
+++ linux-2.5.66-bk5/drivers/char/drm/drm_bufs.h	Mon Mar 31 12:50:21 2003
@@ -403,7 +403,7 @@
 		buf->waiting = 0;
 		buf->pending = 0;
 		init_waitqueue_head( &buf->dma_wait );
-		buf->pid     = 0;
+		buf->filp    = 0;
 
 		buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T);
 		buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T),
@@ -616,7 +616,7 @@
 			buf->waiting = 0;
 			buf->pending = 0;
 			init_waitqueue_head( &buf->dma_wait );
-			buf->pid     = 0;
+			buf->filp    = 0;
 #if __HAVE_DMA_HISTOGRAM
 			buf->time_queued     = 0;
 			buf->time_dispatched = 0;
@@ -773,7 +773,7 @@
 		buf->waiting = 0;
 		buf->pending = 0;
 		init_waitqueue_head( &buf->dma_wait );
-		buf->pid     = 0;
+		buf->filp    = 0;
 
 		buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T);
 		buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T),
@@ -1011,9 +1011,9 @@
 			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 );
+		if ( buf->filp != filp ) {
+			DRM_ERROR( "Process %d freeing buffer not owned\n",
+				   current->pid );
 			return -EINVAL;
 		}
 		DRM(free_buffer)( dev, buf );
diff -urN linux-2.5.66-bk4/drivers/char/drm/drm_dma.h linux-2.5.66-bk5/drivers/char/drm/drm_dma.h
--- linux-2.5.66-bk4/drivers/char/drm/drm_dma.h	Mon Mar 24 14:00:52 2003
+++ linux-2.5.66-bk5/drivers/char/drm/drm_dma.h	Mon Mar 31 12:50:21 2003
@@ -188,7 +188,7 @@
 
 	buf->waiting  = 0;
 	buf->pending  = 0;
-	buf->pid      = 0;
+	buf->filp     = 0;
 	buf->used     = 0;
 #if __HAVE_DMA_HISTOGRAM
 	buf->time_completed = get_cycles();
@@ -210,14 +210,16 @@
 }
 
 #if !__HAVE_DMA_RECLAIM
-void DRM(reclaim_buffers)(drm_device_t *dev, pid_t pid)
+void DRM(reclaim_buffers)( struct file *filp )
 {
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev    = priv->dev;
 	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) {
+		if (dma->buflist[i]->filp == filp) {
 			switch (dma->buflist[i]->list) {
 			case DRM_LIST_NONE:
 				DRM(free_buffer)(dev, dma->buflist[i]);
@@ -318,8 +320,10 @@
 }
 
 
-int DRM(dma_enqueue)(drm_device_t *dev, drm_dma_t *d)
+int DRM(dma_enqueue)(struct file *filp, drm_dma_t *d)
 {
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev    = priv->dev;
 	int		  i;
 	drm_queue_t	  *q;
 	drm_buf_t	  *buf;
@@ -381,10 +385,10 @@
 			return -EINVAL;
 		}
 		buf = dma->buflist[ idx ];
-		if (buf->pid != current->pid) {
+		if (buf->filp != filp) {
 			atomic_dec(&q->use_count);
-			DRM_ERROR("Process %d using buffer owned by %d\n",
-				  current->pid, buf->pid);
+			DRM_ERROR("Process %d using buffer not owned\n",
+				  current->pid);
 			return -EINVAL;
 		}
 		if (buf->list != DRM_LIST_NONE) {
@@ -426,9 +430,11 @@
 	return 0;
 }
 
-static int DRM(dma_get_buffers_of_order)(drm_device_t *dev, drm_dma_t *d,
+static int DRM(dma_get_buffers_of_order)(struct file *filp, drm_dma_t *d,
 					 int order)
 {
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev    = priv->dev;
 	int		  i;
 	drm_buf_t	  *buf;
 	drm_device_dma_t  *dma = dev->dma;
@@ -438,13 +444,13 @@
 					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",
+			DRM_ERROR("Free buffer %d in use by %x (w%d, p%d)\n",
 				  buf->idx,
-				  buf->pid,
+				  buf->filp,
 				  buf->waiting,
 				  buf->pending);
 		}
-		buf->pid     = current->pid;
+		buf->filp     = filp;
 		if (copy_to_user(&d->request_indices[i],
 				 &buf->idx,
 				 sizeof(buf->idx)))
@@ -461,7 +467,7 @@
 }
 
 
-int DRM(dma_get_buffers)(drm_device_t *dev, drm_dma_t *dma)
+int DRM(dma_get_buffers)(struct file *filp, drm_dma_t *dma)
 {
 	int		  order;
 	int		  retcode = 0;
@@ -470,7 +476,7 @@
 	order = DRM(order)(dma->request_size);
 
 	dma->granted_count = 0;
-	retcode		   = DRM(dma_get_buffers_of_order)(dev, dma, order);
+	retcode		   = DRM(dma_get_buffers_of_order)(filp, dma, order);
 
 	if (dma->granted_count < dma->request_count
 	    && (dma->flags & _DRM_DMA_SMALLER_OK)) {
@@ -480,7 +486,7 @@
 			     && tmp_order >= DRM_MIN_ORDER;
 		     --tmp_order) {
 
-			retcode = DRM(dma_get_buffers_of_order)(dev, dma,
+			retcode = DRM(dma_get_buffers_of_order)(filp, dma,
 								tmp_order);
 		}
 	}
@@ -493,7 +499,7 @@
 			     && tmp_order <= DRM_MAX_ORDER;
 		     ++tmp_order) {
 
-			retcode = DRM(dma_get_buffers_of_order)(dev, dma,
+			retcode = DRM(dma_get_buffers_of_order)(filp, dma,
 								tmp_order);
 		}
 	}
@@ -540,6 +546,8 @@
 	spin_lock_init( &dev->vbl_lock );
 
 	INIT_LIST_HEAD( &dev->vbl_sigs.head );
+
+	dev->vbl_pending = 0;
 #endif
 
 				/* Before installing handler */
@@ -622,6 +630,7 @@
 	switch ( vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK ) {
 	case _DRM_VBLANK_RELATIVE:
 		vblwait.request.sequence += atomic_read( &dev->vbl_received );
+		vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
 	case _DRM_VBLANK_ABSOLUTE:
 		break;
 	default:
@@ -632,10 +641,38 @@
 	
 	if ( flags & _DRM_VBLANK_SIGNAL ) {
 		unsigned long irqflags;
-		drm_vbl_sig_t *vbl_sig = DRM_MALLOC( sizeof( drm_vbl_sig_t ) );
+		drm_vbl_sig_t *vbl_sig;
+		
+		vblwait.reply.sequence = atomic_read( &dev->vbl_received );
+
+		spin_lock_irqsave( &dev->vbl_lock, irqflags );
+
+		/* Check if this task has already scheduled the same signal
+		 * for the same vblank sequence number; nothing to be done in
+		 * that case
+		 */
+		list_for_each( ( (struct list_head *) vbl_sig ), &dev->vbl_sigs.head ) {
+			if (vbl_sig->sequence == vblwait.request.sequence
+			    && vbl_sig->info.si_signo == vblwait.request.signal
+			    && vbl_sig->task == current)
+			{
+				spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
+				goto done;
+			}
+		}
+
+		if ( dev->vbl_pending >= 100 ) {
+			spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
+			return -EBUSY;
+		}
+
+		dev->vbl_pending++;
 
-		if ( !vbl_sig )
+		spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
+
+		if ( !( vbl_sig = DRM_MALLOC( sizeof( drm_vbl_sig_t ) ) ) ) {
 			return -ENOMEM;
+		}
 
 		memset( (void *)vbl_sig, 0, sizeof(*vbl_sig) );
 
@@ -643,9 +680,6 @@
 		vbl_sig->info.si_signo = vblwait.request.signal;
 		vbl_sig->task = current;
 
-		vblwait.reply.sequence = atomic_read( &dev->vbl_received );
-
-		/* Hook signal entry into list */
 		spin_lock_irqsave( &dev->vbl_lock, irqflags );
 
 		list_add_tail( (struct list_head *) vbl_sig, &dev->vbl_sigs.head );
@@ -659,6 +693,7 @@
 		vblwait.reply.tval_usec = now.tv_usec;
 	}
 
+done:
 	DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait,
 				sizeof(vblwait) );
 
@@ -667,25 +702,23 @@
 
 void DRM(vbl_send_signals)( drm_device_t *dev )
 {
-	struct list_head *entry, *tmp;
+	struct list_head *tmp;
 	drm_vbl_sig_t *vbl_sig;
 	unsigned int vbl_seq = atomic_read( &dev->vbl_received );
 	unsigned long flags;
 
 	spin_lock_irqsave( &dev->vbl_lock, flags );
 
-	list_for_each_safe( entry, tmp, &dev->vbl_sigs.head ) {
-
-		vbl_sig = (drm_vbl_sig_t *) entry;
-
+	list_for_each_safe( ( (struct list_head *) vbl_sig ), tmp, &dev->vbl_sigs.head ) {
 		if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) {
-
-			vbl_sig->info.si_code = atomic_read( &dev->vbl_received );
+			vbl_sig->info.si_code = vbl_seq;
 			send_sig_info( vbl_sig->info.si_signo, &vbl_sig->info, vbl_sig->task );
 
-			list_del( entry );
+			list_del( (struct list_head *) vbl_sig );
+
+			DRM_FREE( vbl_sig, sizeof(*vbl_sig) );
 
-			DRM_FREE( entry );
+			dev->vbl_pending--;
 		}
 	}
 
diff -urN linux-2.5.66-bk4/drivers/char/drm/drm_drv.h linux-2.5.66-bk5/drivers/char/drm/drm_drv.h
--- linux-2.5.66-bk4/drivers/char/drm/drm_drv.h	Mon Mar 31 12:50:18 2003
+++ linux-2.5.66-bk5/drivers/char/drm/drm_drv.h	Mon Mar 31 12:50:21 2003
@@ -323,6 +323,8 @@
 	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;
@@ -494,7 +496,7 @@
 #endif
 	if ( dev->lock.hw_lock ) {
 		dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */
-		dev->lock.pid = 0;
+		dev->lock.filp = 0;
 		wake_up_interruptible( &dev->lock.lock_queue );
 	}
 	up( &dev->struct_sem );
@@ -576,13 +578,9 @@
 		memset( (void *)dev, 0, sizeof(*dev) );
 		dev->count_lock = SPIN_LOCK_UNLOCKED;
 		sema_init( &dev->struct_sem, 1 );
-		init_timer( &dev->timer );
-		init_waitqueue_head( &dev->context_wait );
 
-		if ((DRM(minor)[i] = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0) {
-			retcode = -EPERM;
-			goto fail_reg;
-		}
+		if ((DRM(minor)[i] = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0)
+			return -EPERM;
 		dev->device = MKDEV(DRM_MAJOR, DRM(minor)[i] );
 		dev->name   = DRIVER_NAME;
 
@@ -591,8 +589,9 @@
 #if __MUST_HAVE_AGP
 		if ( dev->agp == NULL ) {
 			DRM_ERROR( "Cannot initialize the agpgart module.\n" );
-			retcode = -ENOMEM;
-			goto fail;
+			DRM(stub_unregister)(DRM(minor)[i]);
+			DRM(takedown)( dev );
+			return -ENOMEM;
 		}
 #endif
 #if __REALLY_HAVE_MTRR
@@ -608,7 +607,9 @@
 		retcode = DRM(ctxbitmap_init)( dev );
 		if( retcode ) {
 			DRM_ERROR( "Cannot allocate memory for context bitmap.\n" );
-			goto fail;
+			DRM(stub_unregister)(DRM(minor)[i]);
+			DRM(takedown)( dev );
+			return retcode;
 		}
 #endif
 		DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d\n",
@@ -623,17 +624,6 @@
 	DRIVER_POSTINIT();
 
 	return 0;
-
-#if (__REALLY_HAVE_AGP && __MUST_HAVE_AGP) || __HAVE_CTX_BITMAP
-fail:
-	DRM(stub_unregister)(DRM(minor)[i]);
-	DRM(takedown)( dev );
-#endif
-
-fail_reg:
-	kfree (DRM(device));
-	kfree (DRM(minor));
-	return retcode;
 }
 
 /* drm_cleanup is called via cleanup_module at module unload time.
@@ -740,8 +730,6 @@
 		return -ENODEV;
 	}
 
-	DRM_DEBUG( "open_count = %d\n", dev->open_count );
-
 	retcode = DRM(open_helper)( inode, filp, dev );
 	if ( !retcode ) {
 		atomic_inc( &dev->counts[_DRM_STAT_OPENS] );
@@ -773,15 +761,15 @@
 	 * Begin inline drm_release
 	 */
 
-	DRM_DEBUG( "pid = %d, device = 0x%x, open_count = %d\n",
-		   current->pid, dev->device, dev->open_count );
+	DRM_DEBUG( "pid = %d, device = 0x%lx, open_count = %d\n",
+		   current->pid, (long)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_DEBUG( "Process %d dead, freeing lock for context %d\n",
-			   current->pid,
-			   _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) );
+	     dev->lock.filp == filp ) {
+		DRM_DEBUG( "File %p released, freeing lock for context %d\n",
+			filp,
+			_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) );
 #if __HAVE_RELEASE
 		DRIVER_RELEASE();
 #endif
@@ -797,6 +785,7 @@
 	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;
@@ -807,7 +796,7 @@
 			}
 			if ( DRM(lock_take)( &dev->lock.hw_lock->lock,
 					     DRM_KERNEL_CONTEXT ) ) {
-				dev->lock.pid	    = priv->pid;
+				dev->lock.filp	    = filp;
 				dev->lock.lock_time = jiffies;
                                 atomic_inc( &dev->counts[_DRM_STAT_LOCKS] );
 				break;	/* Got lock */
@@ -831,7 +820,7 @@
 		}
 	}
 #elif __HAVE_DMA
-	DRM(reclaim_buffers)( dev, priv->pid );
+	DRM(reclaim_buffers)( filp );
 #endif
 
 	DRM(fasync)( -1, filp, 0 );
@@ -855,7 +844,7 @@
 		dev->file_last	 = priv->prev;
 	}
 	up( &dev->struct_sem );
-
+	
 	DRM(free)( priv, sizeof(*priv), DRM_MEM_FILES );
 
 	/* ========================================================
@@ -880,6 +869,7 @@
 	spin_unlock( &dev->count_lock );
 
 	unlock_kernel();
+
 	return retcode;
 }
 
@@ -899,8 +889,9 @@
 	atomic_inc( &dev->counts[_DRM_STAT_IOCTLS] );
 	++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 );
+	DRM_DEBUG( "pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%lx, auth=%d\n",
+		   current->pid, cmd, nr, (long)dev->device, 
+		   priv->authenticated );
 
 	if ( nr >= DRIVER_IOCTL_COUNT ) {
 		retcode = -EINVAL;
@@ -976,7 +967,7 @@
                         }
                         if ( DRM(lock_take)( &dev->lock.hw_lock->lock,
 					     lock.context ) ) {
-                                dev->lock.pid       = current->pid;
+                                dev->lock.filp      = filp;
                                 dev->lock.lock_time = jiffies;
                                 atomic_inc( &dev->counts[_DRM_STAT_LOCKS] );
                                 break;  /* Got lock */
@@ -1058,7 +1049,7 @@
 	 * agent to request it then we should just be able to
 	 * take it immediately and not eat the ioctl.
 	 */
-	dev->lock.pid = 0;
+	dev->lock.filp = 0;
 	{
 		__volatile__ unsigned int *plock = &dev->lock.hw_lock->lock;
 		unsigned int old, new, prev, ctx;
diff -urN linux-2.5.66-bk4/drivers/char/drm/drm_fops.h linux-2.5.66-bk5/drivers/char/drm/drm_fops.h
--- linux-2.5.66-bk4/drivers/char/drm/drm_fops.h	Mon Mar 24 14:00:45 2003
+++ linux-2.5.66-bk5/drivers/char/drm/drm_fops.h	Mon Mar 31 12:50:21 2003
@@ -94,8 +94,8 @@
 	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);
+	DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
+		  current->pid, (long)dev->device, dev->open_count);
 	return 0;
 }
 
@@ -105,7 +105,7 @@
 	drm_device_t  *dev    = priv->dev;
 	int	      retcode;
 
-	DRM_DEBUG("fd = %d, device = 0x%x\n", fd, dev->device);
+	DRM_DEBUG("fd = %d, device = 0x%lx\n", fd, (long)dev->device);
 	retcode = fasync_helper(fd, filp, on, &dev->buf_async);
 	if (retcode < 0) return retcode;
 	return 0;
diff -urN linux-2.5.66-bk4/drivers/char/drm/drm_ioctl.h linux-2.5.66-bk5/drivers/char/drm/drm_ioctl.h
--- linux-2.5.66-bk4/drivers/char/drm/drm_ioctl.h	Mon Mar 24 14:00:10 2003
+++ linux-2.5.66-bk5/drivers/char/drm/drm_ioctl.h	Mon Mar 31 12:50:21 2003
@@ -40,6 +40,28 @@
 
 	if (copy_from_user(&p, (drm_irq_busid_t *)arg, sizeof(p)))
 		return -EFAULT;
+#ifdef __alpha__
+	{
+		int domain = p.busnum >> 8;
+		p.busnum &= 0xff;
+
+		/*
+		 * Find the hose the device is on (the domain number is the
+		 * hose index) and offset the bus by the root bus of that
+		 * hose.
+		 */
+                for(dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,NULL);
+                    dev;
+                    dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,dev)) {
+			struct pci_controller *hose = dev->sysdata;
+			
+			if (hose->index == domain) {
+				p.busnum += hose->bus->number;
+				break;
+			}
+		}
+	}
+#endif
 	dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum));
 	if (!dev) {
 		DRM_ERROR("pci_find_slot failed for %d:%d:%d\n",
@@ -112,7 +134,7 @@
 
 	do {
 		struct pci_dev *pci_dev;
-                int b, d, f;
+                int domain, b, d, f;
                 char *p;
  
                 for(p = dev->unique; p && *p && *p != ':'; p++);
@@ -124,6 +146,27 @@
                 f = (int)simple_strtoul(p+1, &p, 10);
                 if (*p) break;
  
+		domain = b >> 8;
+		b &= 0xff;
+
+#ifdef __alpha__
+		/*
+		 * Find the hose the device is on (the domain number is the
+		 * hose index) and offset the bus by the root bus of that
+		 * hose.
+		 */
+                for(pci_dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,NULL);
+                    pci_dev;
+                    pci_dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,pci_dev)) {
+			struct pci_controller *hose = pci_dev->sysdata;
+			
+			if (hose->index == domain) {
+				b += hose->bus->number;
+				break;
+			}
+		}
+#endif
+
                 pci_dev = pci_find_slot(b, PCI_DEVFN(d,f));
                 if (pci_dev) {
 			dev->pdev = pci_dev;
diff -urN linux-2.5.66-bk4/drivers/char/drm/drm_lists.h linux-2.5.66-bk5/drivers/char/drm/drm_lists.h
--- linux-2.5.66-bk4/drivers/char/drm/drm_lists.h	Mon Mar 24 14:01:18 2003
+++ linux-2.5.66-bk5/drivers/char/drm/drm_lists.h	Mon Mar 31 12:50:21 2003
@@ -72,8 +72,8 @@
 
 	left = DRM_LEFTCOUNT(bl);
 	if (!left) {
-		DRM_ERROR("Overflow while adding buffer %d from pid %d\n",
-			  buf->idx, buf->pid);
+		DRM_ERROR("Overflow while adding buffer %d from filp %p\n",
+			  buf->idx, buf->filp);
 		return -EINVAL;
 	}
 #if __HAVE_DMA_HISTOGRAM
diff -urN linux-2.5.66-bk4/drivers/char/drm/drm_lock.h linux-2.5.66-bk5/drivers/char/drm/drm_lock.h
--- linux-2.5.66-bk4/drivers/char/drm/drm_lock.h	Mon Mar 24 14:00:54 2003
+++ linux-2.5.66-bk5/drivers/char/drm/drm_lock.h	Mon Mar 31 12:50:21 2003
@@ -78,7 +78,7 @@
 {
 	unsigned int old, new, prev;
 
-	dev->lock.pid = 0;
+	dev->lock.filp = 0;
 	do {
 		old  = *lock;
 		new  = context | _DRM_LOCK_HELD;
@@ -91,19 +91,17 @@
 		   __volatile__ unsigned int *lock, unsigned int context)
 {
 	unsigned int old, new, prev;
-	pid_t        pid = dev->lock.pid;
 
-	dev->lock.pid = 0;
+	dev->lock.filp = 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",
+		DRM_ERROR("%d freed heavyweight lock held by %d\n",
 			  context,
-			  _DRM_LOCKING_CONTEXT(old),
-			  pid);
+			  _DRM_LOCKING_CONTEXT(old));
 		return 1;
 	}
 	wake_up_interruptible(&dev->lock.lock_queue);
diff -urN linux-2.5.66-bk4/drivers/char/drm/drm_os_linux.h linux-2.5.66-bk5/drivers/char/drm/drm_os_linux.h
--- linux-2.5.66-bk4/drivers/char/drm/drm_os_linux.h	Mon Mar 24 14:01:25 2003
+++ linux-2.5.66-bk5/drivers/char/drm/drm_os_linux.h	Mon Mar 31 12:50:21 2003
@@ -2,16 +2,17 @@
 #include <linux/interrupt.h>	/* For task queue support */
 #include <linux/delay.h>
 
+#define DRMFILE                         struct file *
 #define DRM_IOCTL_ARGS			struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data
 #define DRM_ERR(d)			-(d)
 #define DRM_CURRENTPID			current->pid
 #define DRM_UDELAY(d)			udelay(d)
-#define DRM_READ8(addr)			readb(addr)
-#define DRM_READ32(addr)		readl(addr)
-#define DRM_WRITE8(addr, val)		writeb(val, addr)
-#define DRM_WRITE32(addr, val)		writel(val, addr)
-#define DRM_READMEMORYBARRIER()		mb()
-#define DRM_WRITEMEMORYBARRIER()	wmb()
+#define DRM_READ8(map, offset)		readb(((unsigned long)(map)->handle) + (offset))
+#define DRM_READ32(map, offset)		readl(((unsigned long)(map)->handle) + (offset))
+#define DRM_WRITE8(map, offset, val)	writeb(val, ((unsigned long)(map)->handle) + (offset))
+#define DRM_WRITE32(map, offset, val)	writel(val, ((unsigned long)(map)->handle) + (offset))
+#define DRM_READMEMORYBARRIER(map)	mb()
+#define DRM_WRITEMEMORYBARRIER(map)	wmb()
 #define DRM_DEVICE	drm_file_t	*priv	= filp->private_data; \
 			drm_device_t	*dev	= priv->dev
 
@@ -41,7 +42,7 @@
 
 /* malloc/free without the overhead of DRM(alloc) */
 #define DRM_MALLOC(x) kmalloc(x, GFP_KERNEL)
-#define DRM_FREE(x) kfree(x)
+#define DRM_FREE(x,size) kfree(x)
 
 #define DRM_GETSAREA()							 \
 do { 									 \
diff -urN linux-2.5.66-bk4/drivers/char/drm/drm_proc.h linux-2.5.66-bk5/drivers/char/drm/drm_proc.h
--- linux-2.5.66-bk4/drivers/char/drm/drm_proc.h	Mon Mar 24 14:00:00 2003
+++ linux-2.5.66-bk5/drivers/char/drm/drm_proc.h	Mon Mar 31 12:50:21 2003
@@ -147,10 +147,10 @@
 	*eof   = 0;
 
 	if (dev->unique) {
-		DRM_PROC_PRINT("%s 0x%x %s\n",
-			       dev->name, dev->device, dev->unique);
+		DRM_PROC_PRINT("%s 0x%lx %s\n",
+			       dev->name, (long)dev->device, dev->unique);
 	} else {
-		DRM_PROC_PRINT("%s 0x%x\n", dev->name, dev->device);
+		DRM_PROC_PRINT("%s 0x%lx\n", dev->name, (long)dev->device);
 	}
 
 	if (len > request + offset) return request;
diff -urN linux-2.5.66-bk4/drivers/char/drm/gamma_dma.c linux-2.5.66-bk5/drivers/char/drm/gamma_dma.c
--- linux-2.5.66-bk4/drivers/char/drm/gamma_dma.c	Mon Mar 24 14:01:25 2003
+++ linux-2.5.66-bk5/drivers/char/drm/gamma_dma.c	Mon Mar 31 12:50:21 2003
@@ -188,7 +188,7 @@
 		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);
+				  buf->idx, current->pid);
 		}
 	} else {
 		if (!locked && !gamma_lock_take(&dev->lock.hw_lock->lock,
@@ -340,7 +340,8 @@
 	return retcode;
 }
 
-static int gamma_dma_priority(drm_device_t *dev, drm_dma_t *d)
+static int gamma_dma_priority(struct file *filp, 
+			      drm_device_t *dev, drm_dma_t *d)
 {
 	unsigned long	  address;
 	unsigned long	  length;
@@ -378,15 +379,15 @@
 			continue;
 		}
 		buf = dma->buflist[ idx ];
-		if (buf->pid != current->pid) {
-			DRM_ERROR("Process %d using buffer owned by %d\n",
-				  current->pid, buf->pid);
+		if (buf->filp != filp) {
+			DRM_ERROR("Process %d using buffer not owned\n",
+				  current->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);
+			DRM_ERROR("Process %d using buffer on list %d\n",
+				  current->pid, buf->list);
 			retcode = -EINVAL;
 			goto cleanup;
 		}
@@ -478,7 +479,8 @@
 	return retcode;
 }
 
-static int gamma_dma_send_buffers(drm_device_t *dev, drm_dma_t *d)
+static int gamma_dma_send_buffers(struct file *filp,
+				  drm_device_t *dev, drm_dma_t *d)
 {
 	DECLARE_WAITQUEUE(entry, current);
 	drm_buf_t	  *last_buf = NULL;
@@ -490,7 +492,7 @@
 		add_wait_queue(&last_buf->dma_wait, &entry);
 	}
 
-	if ((retcode = gamma_dma_enqueue(dev, d))) {
+	if ((retcode = gamma_dma_enqueue(filp, d))) {
 		if (d->flags & _DRM_DMA_BLOCK)
 			remove_wait_queue(&last_buf->dma_wait, &entry);
 		return retcode;
@@ -520,14 +522,13 @@
 			}
 		}
 		if (retcode) {
-			DRM_ERROR("ctx%d w%d p%d c%d i%d l%d %d/%d\n",
+			DRM_ERROR("ctx%d w%d p%d c%ld i%d l%d pid:%d\n",
 				  d->context,
 				  last_buf->waiting,
 				  last_buf->pending,
-				  DRM_WAITCOUNT(dev, d->context),
+				  (long)DRM_WAITCOUNT(dev, d->context),
 				  last_buf->idx,
 				  last_buf->list,
-				  last_buf->pid,
 				  current->pid);
 		}
 	}
@@ -560,15 +561,15 @@
 
 	if (d.send_count) {
 		if (d.flags & _DRM_DMA_PRIORITY)
-			retcode = gamma_dma_priority(dev, &d);
+			retcode = gamma_dma_priority(filp, dev, &d);
 		else
-			retcode = gamma_dma_send_buffers(dev, &d);
+			retcode = gamma_dma_send_buffers(filp, dev, &d);
 	}
 
 	d.granted_count = 0;
 
 	if (!retcode && d.request_count) {
-		retcode = gamma_dma_get_buffers(dev, &d);
+		retcode = gamma_dma_get_buffers(filp, &d);
 	}
 
 	DRM_DEBUG("%d returning, granted = %d\n",
@@ -590,7 +591,7 @@
 	drm_buf_t	    *buf;
 	int i;
 	struct list_head    *list;
-	unsigned int	    *pgt;
+	unsigned long	    *pgt;
 
 	DRM_DEBUG( "%s\n", __FUNCTION__ );
 
@@ -643,7 +644,7 @@
 
  		for (i = 0; i < GLINT_DRI_BUF_COUNT; i++) {
 			buf = dma->buflist[i];
-			*pgt = (unsigned int)buf->address + 0x07;
+			*pgt = (unsigned long)buf->address + 0x07;
 			pgt++;
 		}
 
diff -urN linux-2.5.66-bk4/drivers/char/drm/gamma_drv.h linux-2.5.66-bk5/drivers/char/drm/gamma_drv.h
--- linux-2.5.66-bk4/drivers/char/drm/gamma_drv.h	Mon Mar 24 14:00:20 2003
+++ linux-2.5.66-bk5/drivers/char/drm/gamma_drv.h	Mon Mar 31 12:50:21 2003
@@ -42,16 +42,6 @@
 	drm_map_t *mmio3;
 } drm_gamma_private_t;
 
-#define LOCK_TEST_WITH_RETURN( dev )					\
-do {									\
-	if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) ||		\
-	     dev->lock.pid != current->pid ) {				\
-		DRM_ERROR( "%s called without lock held\n",		\
-			   __FUNCTION__ );				\
-		return -EINVAL;						\
-	}								\
-} while (0)
-
 				/* gamma_dma.c */
 extern int gamma_dma_init( struct inode *inode, struct file *filp,
 			 unsigned int cmd, unsigned long arg );
diff -urN linux-2.5.66-bk4/drivers/char/drm/i810.h linux-2.5.66-bk5/drivers/char/drm/i810.h
--- linux-2.5.66-bk4/drivers/char/drm/i810.h	Mon Mar 24 14:00:15 2003
+++ linux-2.5.66-bk5/drivers/char/drm/i810.h	Mon Mar 31 12:50:21 2003
@@ -86,7 +86,7 @@
  */
 #define __HAVE_RELEASE		1
 #define DRIVER_RELEASE() do {						\
-	i810_reclaim_buffers( dev, priv->pid );				\
+	i810_reclaim_buffers( filp );				\
 } while (0)
 
 /* DMA customization:
diff -urN linux-2.5.66-bk4/drivers/char/drm/i810_dma.c linux-2.5.66-bk5/drivers/char/drm/i810_dma.c
--- linux-2.5.66-bk4/drivers/char/drm/i810_dma.c	Mon Mar 24 14:00:15 2003
+++ linux-2.5.66-bk5/drivers/char/drm/i810_dma.c	Mon Mar 31 12:50:21 2003
@@ -46,30 +46,10 @@
 #define I810_BUF_UNMAPPED 0
 #define I810_BUF_MAPPED   1
 
-#define RING_LOCALS	unsigned int outring, ringmask; volatile char *virt;
-
-#define BEGIN_LP_RING(n) do {						\
-	if (0) 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 (0) 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 (0) DRM_DEBUG("   OUT_RING %x\n", (int)(n));	\
-	*(volatile unsigned int *)(virt + outring) = n;	\
-	outring += 4;					\
-	outring &= ringmask;				\
-} while (0)
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,2)
+#define down_write down
+#define up_write up
+#endif
 
 static inline void i810_print_status_page(drm_device_t *dev)
 {
@@ -178,11 +158,7 @@
 
 	if(buf_priv->currently_mapped == I810_BUF_MAPPED) return -EINVAL;
 
-#if LINUX_VERSION_CODE <= 0x020402
-	down( &current->mm->mmap_sem );
-#else
 	down_write( &current->mm->mmap_sem );
-#endif
 	old_fops = filp->f_op;
 	filp->f_op = &i810_buffer_fops;
 	dev_priv->mmap_buffer = buf;
@@ -194,15 +170,12 @@
 	filp->f_op = old_fops;
 	if ((unsigned long)buf_priv->virtual > -1024UL) {
 		/* Real error */
-		DRM_DEBUG("mmap error\n");
+		DRM_ERROR("mmap error\n");
 		retcode = (signed int)buf_priv->virtual;
 		buf_priv->virtual = 0;
 	}
-#if LINUX_VERSION_CODE <= 0x020402
-	up( &current->mm->mmap_sem );
-#else
 	up_write( &current->mm->mmap_sem );
-#endif
+
 	return retcode;
 }
 
@@ -213,19 +186,13 @@
 
 	if(buf_priv->currently_mapped != I810_BUF_MAPPED)
 		return -EINVAL;
-#if LINUX_VERSION_CODE <= 0x020402
-	down( &current->mm->mmap_sem );
-#else
-	down_write( &current->mm->mmap_sem );
-#endif
+
+	down_write(&current->mm->mmap_sem);
 	retcode = do_munmap(current->mm,
 			    (unsigned long)buf_priv->virtual,
 			    (size_t) buf->total);
-#if LINUX_VERSION_CODE <= 0x020402
-	up( &current->mm->mmap_sem );
-#else
-	up_write( &current->mm->mmap_sem );
-#endif
+	up_write(&current->mm->mmap_sem);
+
    	buf_priv->currently_mapped = I810_BUF_UNMAPPED;
    	buf_priv->virtual = 0;
 
@@ -235,7 +202,6 @@
 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;
@@ -250,10 +216,10 @@
 	retcode = i810_map_buffer(buf, filp);
 	if(retcode) {
 		i810_freelist_put(dev, buf);
-	   	DRM_DEBUG("mapbuf failed, retcode %d\n", retcode);
+	   	DRM_ERROR("mapbuf failed, retcode %d\n", retcode);
 		return retcode;
 	}
-	buf->pid     = priv->pid;
+	buf->filp = filp;
 	buf_priv = buf->dev_private;
 	d->granted = 1;
    	d->request_idx = buf->idx;
@@ -314,7 +280,7 @@
 		   end = jiffies + (HZ*3);
 
 	   	iters++;
-		if((signed)(end - jiffies) <= 0) {
+		if(time_before(end, jiffies)) {
 		   	DRM_ERROR("space: %d wanted %d\n", ring->space, n);
 		   	DRM_ERROR("lockup\n");
 		   	goto out_wait_ring;
@@ -882,8 +848,10 @@
 }
 
 /* Must be called with the lock held */
-void i810_reclaim_buffers(drm_device_t *dev, pid_t pid)
+void i810_reclaim_buffers(struct file *filp)
 {
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev    = priv->dev;
 	drm_device_dma_t *dma = dev->dma;
 	int		 i;
 
@@ -897,7 +865,7 @@
 	   	drm_buf_t *buf = dma->buflist[ i ];
 	   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
 
-		if (buf->pid == pid && buf_priv) {
+		if (buf->filp == filp && buf_priv) {
 			int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
 					   I810_BUF_FREE);
 
diff -urN linux-2.5.66-bk4/drivers/char/drm/i810_drv.h linux-2.5.66-bk5/drivers/char/drm/i810_drv.h
--- linux-2.5.66-bk4/drivers/char/drm/i810_drv.h	Mon Mar 24 14:01:43 2003
+++ linux-2.5.66-bk5/drivers/char/drm/i810_drv.h	Mon Mar 31 12:50:21 2003
@@ -88,7 +88,7 @@
 			  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 void i810_reclaim_buffers(struct file *filp);
 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);
@@ -136,6 +136,33 @@
 #define I810_READ16(reg)	I810_DEREF16(reg)
 #define I810_WRITE16(reg,val)	do { I810_DEREF16(reg) = val; } while (0)
 
+#define I810_VERBOSE 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)
 
 #define GFX_OP_USER_INTERRUPT 		((0<<29)|(2<<23))
 #define GFX_OP_BREAKPOINT_INTERRUPT	((0<<29)|(1<<23))
@@ -198,6 +225,7 @@
 
 #define CMD_OP_Z_BUFFER_INFO     ((0x0<<29)|(0x16<<23))
 #define CMD_OP_DESTBUFFER_INFO   ((0x0<<29)|(0x15<<23))
+#define CMD_OP_FRONTBUFFER_INFO  ((0x0<<29)|(0x14<<23))
 
 #define BR00_BITBLT_CLIENT   0x40000000
 #define BR00_OP_COLOR_BLT    0x10000000
diff -urN linux-2.5.66-bk4/drivers/char/drm/i830.h linux-2.5.66-bk5/drivers/char/drm/i830.h
--- linux-2.5.66-bk4/drivers/char/drm/i830.h	Mon Mar 24 14:00:14 2003
+++ linux-2.5.66-bk5/drivers/char/drm/i830.h	Mon Mar 31 12:50:21 2003
@@ -45,22 +45,37 @@
 
 #define DRIVER_NAME		"i830"
 #define DRIVER_DESC		"Intel 830M"
-#define DRIVER_DATE		"20020828"
+#define DRIVER_DATE		"20021108"
 
+/* Interface history:
+ *
+ * 1.1: Original.
+ * 1.2: ?
+ * 1.3: New irq emit/wait ioctls.
+ *      New pageflip ioctl.
+ *      New getparam ioctl.
+ *      State for texunits 3&4 in sarea.
+ *      New (alternative) layout for texture state.
+ */
 #define DRIVER_MAJOR		1
-#define DRIVER_MINOR		2
-#define DRIVER_PATCHLEVEL	1
+#define DRIVER_MINOR		3
+#define DRIVER_PATCHLEVEL	2
 
 #define DRIVER_IOCTLS							    \
 	[DRM_IOCTL_NR(DRM_IOCTL_I830_INIT)]   = { i830_dma_init,    1, 1 }, \
-   	[DRM_IOCTL_NR(DRM_IOCTL_I830_VERTEX)] = { i830_dma_vertex,  1, 0 }, \
-   	[DRM_IOCTL_NR(DRM_IOCTL_I830_CLEAR)]  = { i830_clear_bufs,  1, 0 }, \
-      	[DRM_IOCTL_NR(DRM_IOCTL_I830_FLUSH)]  = { i830_flush_ioctl, 1, 0 }, \
-   	[DRM_IOCTL_NR(DRM_IOCTL_I830_GETAGE)] = { i830_getage,      1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I830_VERTEX)] = { i830_dma_vertex,  1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I830_CLEAR)]  = { i830_clear_bufs,  1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I830_FLUSH)]  = { i830_flush_ioctl, 1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I830_GETAGE)] = { i830_getage,      1, 0 }, \
 	[DRM_IOCTL_NR(DRM_IOCTL_I830_GETBUF)] = { i830_getbuf,      1, 0 }, \
-   	[DRM_IOCTL_NR(DRM_IOCTL_I830_SWAP)]   = { i830_swap_bufs,   1, 0 }, \
-   	[DRM_IOCTL_NR(DRM_IOCTL_I830_COPY)]   = { i830_copybuf,     1, 0 }, \
-   	[DRM_IOCTL_NR(DRM_IOCTL_I830_DOCOPY)] = { i830_docopy,      1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_I830_SWAP)]   = { i830_swap_bufs,   1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I830_COPY)]   = { i830_copybuf,     1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I830_DOCOPY)] = { i830_docopy,      1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I830_FLIP)]   = { i830_flip_bufs,   1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I830_IRQ_EMIT)] = { i830_irq_emit,  1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I830_IRQ_WAIT)] = { i830_irq_wait,  1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I830_GETPARAM)] = { i830_getparam,  1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I830_SETPARAM)] = { i830_setparam,  1, 0 } 
 
 #define __HAVE_COUNTERS         4
 #define __HAVE_COUNTER6         _DRM_STAT_IRQ
@@ -72,7 +87,7 @@
  */
 #define __HAVE_RELEASE		1
 #define DRIVER_RELEASE() do {						\
-	i830_reclaim_buffers( dev, priv->pid );				\
+	i830_reclaim_buffers( filp );				\
 } while (0)
 
 /* DMA customization:
@@ -87,10 +102,49 @@
 	i830_dma_quiescent( dev );					\
 } while (0)
 
-/* Don't need an irq any more.  The template code will make sure that
- * a noop stub is generated for compatibility.
+
+/* Driver will work either way: IRQ's save cpu time when waiting for
+ * the card, but are subject to subtle interactions between bios,
+ * hardware and the driver.
  */
-#define __HAVE_DMA_IRQ		0
+#define USE_IRQS 0
+
+
+#if USE_IRQS
+#define __HAVE_DMA_IRQ		1
+#define __HAVE_SHARED_IRQ	1
+
+#define DRIVER_PREINSTALL() do {			\
+	drm_i830_private_t *dev_priv =			\
+		(drm_i830_private_t *)dev->dev_private;	\
+							\
+   	I830_WRITE16( I830REG_HWSTAM, 0xffff );	\
+        I830_WRITE16( I830REG_INT_MASK_R, 0x0 );	\
+      	I830_WRITE16( I830REG_INT_ENABLE_R, 0x0 );	\
+} while (0)
+
+
+#define DRIVER_POSTINSTALL() do {				\
+	drm_i830_private_t *dev_priv =				\
+		(drm_i830_private_t *)dev->dev_private;		\
+   	I830_WRITE16( I830REG_INT_ENABLE_R, 0x2 );		\
+   	atomic_set(&dev_priv->irq_received, 0);			\
+   	atomic_set(&dev_priv->irq_emitted, 0);			\
+	init_waitqueue_head(&dev_priv->irq_queue);		\
+} while (0)
+
+
+/* This gets called too late to be useful: dev_priv has already been
+ * freed.
+ */
+#define DRIVER_UNINSTALL() do {					\
+} while (0)
+
+#else
+#define __HAVE_DMA_IRQ          0
+#endif
+
+
 
 /* Buffer customization:
  */
diff -urN linux-2.5.66-bk4/drivers/char/drm/i830_dma.c linux-2.5.66-bk5/drivers/char/drm/i830_dma.c
--- linux-2.5.66-bk4/drivers/char/drm/i830_dma.c	Mon Mar 24 14:00:00 2003
+++ linux-2.5.66-bk5/drivers/char/drm/i830_dma.c	Mon Mar 31 12:50:21 2003
@@ -37,6 +37,7 @@
 #include "i830_drm.h"
 #include "i830_drv.h"
 #include <linux/interrupt.h>	/* For task queue support */
+#include <linux/pagemap.h>	/* For FASTCALL on unlock_page() */
 #include <linux/delay.h>
 
 #define I830_BUF_FREE		2
@@ -46,8 +47,6 @@
 #define I830_BUF_UNMAPPED 0
 #define I830_BUF_MAPPED   1
 
-#define RING_LOCALS	unsigned int outring, ringmask; volatile char *virt;
-
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,2)
 #define down_write down
 #define up_write up
@@ -60,32 +59,6 @@
 #define UnlockPage(page)	unlock_page(page)
 #endif
 
-#define I830_VERBOSE 0
-
-#define BEGIN_LP_RING(n) do {				\
-	if (I830_VERBOSE)				\
-		printk("BEGIN_LP_RING(%d) in %s\n",	\
-			  n, __FUNCTION__);		\
-	if (dev_priv->ring.space < n*4) 		\
-		i830_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 (I830_VERBOSE) printk("ADVANCE_LP_RING %x\n", outring);	\
-	dev_priv->ring.tail = outring;				\
-	I830_WRITE(LP_RING + RING_TAIL, outring);		\
-} while(0)
-
-#define OUT_RING(n) do {						\
-	if (I830_VERBOSE) printk("   OUT_RING %x\n", (int)(n));	\
-	*(volatile unsigned int *)(virt + outring) = n;			\
-	outring += 4;							\
-	outring &= ringmask;						\
-} while (0)
 
 static inline void i830_print_status_page(drm_device_t *dev)
 {
@@ -237,7 +210,6 @@
 static int i830_dma_get_buffer(drm_device_t *dev, drm_i830_dma_t *d, 
 			       struct file *filp)
 {
-	drm_file_t	  *priv	  = filp->private_data;
 	drm_buf_t	  *buf;
 	drm_i830_buf_priv_t *buf_priv;
 	int retcode = 0;
@@ -245,7 +217,7 @@
 	buf = i830_freelist_get(dev);
 	if (!buf) {
 		retcode = -ENOMEM;
-	   	DRM_ERROR("retcode=%d\n", retcode);
+	   	DRM_DEBUG("retcode=%d\n", retcode);
 		return retcode;
 	}
    
@@ -255,7 +227,7 @@
 	   	DRM_ERROR("mapbuf failed, retcode %d\n", retcode);
 		return retcode;
 	}
-	buf->pid     = priv->pid;
+	buf->filp = filp;
 	buf_priv = buf->dev_private;	
 	d->granted = 1;
    	d->request_idx = buf->idx;
@@ -279,12 +251,21 @@
 					 dev_priv->ring.Size);
 		}
 	   	if(dev_priv->hw_status_page != 0UL) {
-		   	pci_free_consistent(dev->pdev, PAGE_SIZE,
+			pci_free_consistent(dev->pdev, PAGE_SIZE,
 					    (void *)dev_priv->hw_status_page,
 					    dev_priv->dma_status_page);
 		   	/* Need to rewrite hardware status page */
 		   	I830_WRITE(0x02080, 0x1ffff000);
 		}
+
+		/* Disable interrupts here because after dev_private
+		 * is freed, it's too late.
+		 */
+		if (dev->irq) {
+			I830_WRITE16( I830REG_INT_MASK_R, 0xffff );
+			I830_WRITE16( I830REG_INT_ENABLE_R, 0x0 );
+		}
+
 	   	DRM(free)(dev->dev_private, sizeof(drm_i830_private_t), 
 			 DRM_MEM_DRIVER);
 	   	dev->dev_private = NULL;
@@ -298,7 +279,7 @@
    	return 0;
 }
 
-static int i830_wait_ring(drm_device_t *dev, int n)
+int i830_wait_ring(drm_device_t *dev, int n, const char *caller)
 {
    	drm_i830_private_t *dev_priv = dev->dev_private;
    	drm_i830_ring_buffer_t *ring = &(dev_priv->ring);
@@ -324,6 +305,7 @@
 		   	goto out_wait_ring;
 		}
 		udelay(1);
+		dev_priv->sarea_priv->perf_boxes |= I830_BOX_WAIT;
 	}
 
 out_wait_ring:   
@@ -339,6 +321,9 @@
      	ring->tail = I830_READ(LP_RING + RING_TAIL) & TAIL_ADDR;
      	ring->space = ring->head - (ring->tail+8);
      	if (ring->space < 0) ring->space += ring->Size;
+
+	if (ring->head == ring->tail)
+		dev_priv->sarea_priv->perf_boxes |= I830_BOX_RING_EMPTY;
 }
 
 static int i830_freelist_init(drm_device_t *dev, drm_i830_private_t *dev_priv)
@@ -453,6 +438,8 @@
 
 	dev_priv->back_pitch = init->back_pitch;
 	dev_priv->depth_pitch = init->depth_pitch;
+	dev_priv->do_boxes = 0;
+	dev_priv->use_mi_batchbuffer_start = 0;
 
    	/* Program Hardware Status Page */
    	dev_priv->hw_status_page =
@@ -467,7 +454,7 @@
    	memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE);
 	DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page);
    
-	I830_WRITE(0x02080, dev_priv->dma_status_page);
+   	I830_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 */
@@ -528,11 +515,7 @@
 	unsigned int tmp;
 	RING_LOCALS;
 
-	BEGIN_LP_RING( I830_CTX_SETUP_SIZE + 2 );
-
-	OUT_RING( GFX_OP_STIPPLE );
-	OUT_RING( 0 );
-
+	BEGIN_LP_RING( I830_CTX_SETUP_SIZE + 4 );
 
 	for ( i = 0 ; i < I830_CTXREG_BLENDCOLR0 ; i++ ) {
 		tmp = code[i];
@@ -570,38 +553,44 @@
 	ADVANCE_LP_RING();
 }
 
-static void i830EmitTexVerified( drm_device_t *dev, 
-				 volatile unsigned int *code ) 
+static void i830EmitTexVerified( drm_device_t *dev, unsigned int *code ) 
 {
    	drm_i830_private_t *dev_priv = dev->dev_private;
 	int i, j = 0;
 	unsigned int tmp;
 	RING_LOCALS;
 
-	BEGIN_LP_RING( I830_TEX_SETUP_SIZE );
-
-	OUT_RING( GFX_OP_MAP_INFO );
-	OUT_RING( code[I830_TEXREG_MI1] );
-	OUT_RING( code[I830_TEXREG_MI2] );
-	OUT_RING( code[I830_TEXREG_MI3] );
-	OUT_RING( code[I830_TEXREG_MI4] );
-	OUT_RING( code[I830_TEXREG_MI5] );
-
-	for ( i = 6 ; i < I830_TEX_SETUP_SIZE ; i++ ) {
-		tmp = code[i];
-		OUT_RING( tmp ); 
-		j++;
-	} 
+	if (code[I830_TEXREG_MI0] == GFX_OP_MAP_INFO ||
+	    (code[I830_TEXREG_MI0] & ~(0xf*LOAD_TEXTURE_MAP0)) == 
+	    (STATE3D_LOAD_STATE_IMMEDIATE_2|4)) {
+
+		BEGIN_LP_RING( I830_TEX_SETUP_SIZE );
+
+		OUT_RING( code[I830_TEXREG_MI0] ); /* TM0LI */
+		OUT_RING( code[I830_TEXREG_MI1] ); /* TM0S0 */
+		OUT_RING( code[I830_TEXREG_MI2] ); /* TM0S1 */
+		OUT_RING( code[I830_TEXREG_MI3] ); /* TM0S2 */
+		OUT_RING( code[I830_TEXREG_MI4] ); /* TM0S3 */
+		OUT_RING( code[I830_TEXREG_MI5] ); /* TM0S4 */
+		
+		for ( i = 6 ; i < I830_TEX_SETUP_SIZE ; i++ ) {
+			tmp = code[i];
+			OUT_RING( tmp ); 
+			j++;
+		} 
 
-	if (j & 1) 
-		OUT_RING( 0 ); 
+		if (j & 1) 
+			OUT_RING( 0 ); 
 
-	ADVANCE_LP_RING();
+		ADVANCE_LP_RING();
+	}
+	else
+		printk("rejected packet %x\n", code[0]);
 }
 
 static void i830EmitTexBlendVerified( drm_device_t *dev, 
-				     volatile unsigned int *code,
-				     volatile unsigned int num)
+				      unsigned int *code,
+				      unsigned int num)
 {
    	drm_i830_private_t *dev_priv = dev->dev_private;
 	int i, j = 0;
@@ -611,7 +600,7 @@
 	if (!num)
 		return;
 
-	BEGIN_LP_RING( num );
+	BEGIN_LP_RING( num + 1 );
 
 	for ( i = 0 ; i < num ; i++ ) {
 		tmp = code[i];
@@ -634,6 +623,8 @@
 	int i;
 	RING_LOCALS;
 
+	return;
+
 	BEGIN_LP_RING( 258 );
 
 	if(is_shared == 1) {
@@ -647,42 +638,41 @@
 		OUT_RING(palette[i]);
 	}
 	OUT_RING(0);
+	/* KW:  WHERE IS THE ADVANCE_LP_RING?  This is effectively a noop! 
+	 */
 }
 
 /* Need to do some additional checking when setting the dest buffer.
  */
 static void i830EmitDestVerified( drm_device_t *dev, 
-				  volatile unsigned int *code ) 
+				  unsigned int *code ) 
 {	
    	drm_i830_private_t *dev_priv = dev->dev_private;
 	unsigned int tmp;
 	RING_LOCALS;
 
-	BEGIN_LP_RING( I830_DEST_SETUP_SIZE + 6 );
+	BEGIN_LP_RING( I830_DEST_SETUP_SIZE + 10 );
+
 
 	tmp = code[I830_DESTREG_CBUFADDR];
-	if (tmp == dev_priv->front_di1) {
-		/* Don't use fence when front buffer rendering */
-		OUT_RING( CMD_OP_DESTBUFFER_INFO );
-		OUT_RING( BUF_3D_ID_COLOR_BACK | 
-			  BUF_3D_PITCH(dev_priv->back_pitch * dev_priv->cpp) );
-		OUT_RING( tmp );
+	if (tmp == dev_priv->front_di1 || tmp == dev_priv->back_di1) {
+		if (((int)outring) & 8) {
+			OUT_RING(0);
+			OUT_RING(0);
+		}
 
 		OUT_RING( CMD_OP_DESTBUFFER_INFO );
-		OUT_RING( BUF_3D_ID_DEPTH |
-			  BUF_3D_PITCH(dev_priv->depth_pitch * dev_priv->cpp));
-		OUT_RING( dev_priv->zi1 );
-	} else if(tmp == dev_priv->back_di1) {
-		OUT_RING( CMD_OP_DESTBUFFER_INFO );
 		OUT_RING( BUF_3D_ID_COLOR_BACK | 
 			  BUF_3D_PITCH(dev_priv->back_pitch * dev_priv->cpp) |
 			  BUF_3D_USE_FENCE);
 		OUT_RING( tmp );
+		OUT_RING( 0 );
 
 		OUT_RING( CMD_OP_DESTBUFFER_INFO );
 		OUT_RING( BUF_3D_ID_DEPTH | BUF_3D_USE_FENCE | 
 			  BUF_3D_PITCH(dev_priv->depth_pitch * dev_priv->cpp));
 		OUT_RING( dev_priv->zi1 );
+		OUT_RING( 0 );
 	} else {
 		DRM_ERROR("bad di1 %x (allow %x or %x)\n",
 			  tmp, dev_priv->front_di1, dev_priv->back_di1);
@@ -710,21 +700,35 @@
 		OUT_RING( 0 );
 	}
 
-	OUT_RING( code[I830_DESTREG_SENABLE] );
-
 	OUT_RING( GFX_OP_SCISSOR_RECT );
 	OUT_RING( code[I830_DESTREG_SR1] );
 	OUT_RING( code[I830_DESTREG_SR2] );
+	OUT_RING( 0 );
 
 	ADVANCE_LP_RING();
 }
 
+static void i830EmitStippleVerified( drm_device_t *dev, 
+				     unsigned int *code ) 
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+	RING_LOCALS;
+
+	BEGIN_LP_RING( 2 );
+	OUT_RING( GFX_OP_STIPPLE );
+	OUT_RING( code[1] );
+	ADVANCE_LP_RING();	
+}
+
+
 static void i830EmitState( drm_device_t *dev )
 {
    	drm_i830_private_t *dev_priv = dev->dev_private;
       	drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	unsigned int dirty = sarea_priv->dirty;
 
+	DRM_DEBUG("%s %x\n", __FUNCTION__, dirty);
+
 	if (dirty & I830_UPLOAD_BUFFERS) {
 		i830EmitDestVerified( dev, sarea_priv->BufferState );
 		sarea_priv->dirty &= ~I830_UPLOAD_BUFFERS;
@@ -758,17 +762,154 @@
 	}
 
 	if (dirty & I830_UPLOAD_TEX_PALETTE_SHARED) {
-	   i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 1);
+		i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 1);
+	} else {
+		if (dirty & I830_UPLOAD_TEX_PALETTE_N(0)) {
+			i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 0);
+			sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(0);
+		}
+		if (dirty & I830_UPLOAD_TEX_PALETTE_N(1)) {
+			i830EmitTexPalette(dev, sarea_priv->Palette[1], 1, 0);
+			sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(1);
+		}
+
+		/* 1.3:
+		 */
+#if 0
+		if (dirty & I830_UPLOAD_TEX_PALETTE_N(2)) {
+			i830EmitTexPalette(dev, sarea_priv->Palette2[0], 0, 0);
+			sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(2);
+		}
+		if (dirty & I830_UPLOAD_TEX_PALETTE_N(3)) {
+			i830EmitTexPalette(dev, sarea_priv->Palette2[1], 1, 0);
+			sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(2);
+		}
+#endif
+	}
+
+	/* 1.3:
+	 */
+	if (dirty & I830_UPLOAD_STIPPLE) {
+		i830EmitStippleVerified( dev, 
+					 sarea_priv->StippleState);
+		sarea_priv->dirty &= ~I830_UPLOAD_STIPPLE;
+	}
+
+	if (dirty & I830_UPLOAD_TEX2) {
+		i830EmitTexVerified( dev, sarea_priv->TexState2 );
+		sarea_priv->dirty &= ~I830_UPLOAD_TEX2;
+	}
+
+	if (dirty & I830_UPLOAD_TEX3) {
+		i830EmitTexVerified( dev, sarea_priv->TexState3 );
+		sarea_priv->dirty &= ~I830_UPLOAD_TEX3;
+	}
+
+
+	if (dirty & I830_UPLOAD_TEXBLEND2) {
+		i830EmitTexBlendVerified( 
+			dev, 
+			sarea_priv->TexBlendState2,
+			sarea_priv->TexBlendStateWordsUsed2);
+
+		sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND2;
+	}
+
+	if (dirty & I830_UPLOAD_TEXBLEND3) {
+		i830EmitTexBlendVerified( 
+			dev, 
+			sarea_priv->TexBlendState3,
+			sarea_priv->TexBlendStateWordsUsed3);
+		sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND3;
+	}
+}
+
+/* ================================================================
+ * Performance monitoring functions
+ */
+
+static void i830_fill_box( drm_device_t *dev,
+			   int x, int y, int w, int h,
+			   int r, int g, int b )
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+	u32 color;
+	unsigned int BR13, CMD;
+	RING_LOCALS;
+
+	BR13 = (0xF0 << 16) | (dev_priv->pitch * dev_priv->cpp) | (1<<24);
+	CMD = XY_COLOR_BLT_CMD;
+	x += dev_priv->sarea_priv->boxes[0].x1;
+	y += dev_priv->sarea_priv->boxes[0].y1;
+
+	if (dev_priv->cpp == 4) {
+		BR13 |= (1<<25);
+		CMD |= (XY_COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB);
+		color = (((0xff) << 24) | (r << 16) | (g <<  8) | b);	
 	} else {
-	   if (dirty & I830_UPLOAD_TEX_PALETTE_N(0)) {
-	      i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 0);
-	      sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(0);
-	   }
-	   if (dirty & I830_UPLOAD_TEX_PALETTE_N(1)) {
-	      i830EmitTexPalette(dev, sarea_priv->Palette[1], 1, 0);
-	      sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(1);
-	   }
+		color = (((r & 0xf8) << 8) |
+			 ((g & 0xfc) << 3) |
+			 ((b & 0xf8) >> 3));
 	}
+
+	BEGIN_LP_RING( 6 );	    
+	OUT_RING( CMD );
+	OUT_RING( BR13 );
+	OUT_RING( (y << 16) | x );
+	OUT_RING( ((y+h) << 16) | (x+w) );
+
+ 	if ( dev_priv->current_page == 1 ) { 
+		OUT_RING( dev_priv->front_offset );
+ 	} else {	 
+		OUT_RING( dev_priv->back_offset );
+ 	} 
+
+	OUT_RING( color );
+	ADVANCE_LP_RING();
+}
+
+static void i830_cp_performance_boxes( drm_device_t *dev )
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+
+	/* Purple box for page flipping
+	 */
+	if ( dev_priv->sarea_priv->perf_boxes & I830_BOX_FLIP ) 
+		i830_fill_box( dev, 4, 4, 8, 8, 255, 0, 255 );
+
+	/* Red box if we have to wait for idle at any point
+	 */
+	if ( dev_priv->sarea_priv->perf_boxes & I830_BOX_WAIT ) 
+		i830_fill_box( dev, 16, 4, 8, 8, 255, 0, 0 );
+
+	/* Blue box: lost context?
+	 */
+	if ( dev_priv->sarea_priv->perf_boxes & I830_BOX_LOST_CONTEXT ) 
+		i830_fill_box( dev, 28, 4, 8, 8, 0, 0, 255 );
+
+	/* Yellow box for texture swaps
+	 */
+	if ( dev_priv->sarea_priv->perf_boxes & I830_BOX_TEXTURE_LOAD ) 
+		i830_fill_box( dev, 40, 4, 8, 8, 255, 255, 0 );
+
+	/* Green box if hardware never idles (as far as we can tell)
+	 */
+	if ( !(dev_priv->sarea_priv->perf_boxes & I830_BOX_RING_EMPTY) ) 
+		i830_fill_box( dev, 64, 4, 8, 8, 0, 255, 0 );
+
+
+	/* Draw bars indicating number of buffers allocated 
+	 * (not a great measure, easily confused)
+	 */
+	if (dev_priv->dma_used) {
+		int bar = dev_priv->dma_used / 10240;
+		if (bar > 100) bar = 100;
+		if (bar < 1) bar = 1;
+		i830_fill_box( dev, 4, 16, bar, 4, 196, 128, 128 );
+		dev_priv->dma_used = 0;
+	}
+
+	dev_priv->sarea_priv->perf_boxes = 0;
 }
 
 static void i830_dma_dispatch_clear( drm_device_t *dev, int flags, 
@@ -786,6 +927,15 @@
 	unsigned int BR13, CMD, D_CMD;
 	RING_LOCALS;
 
+
+	if ( dev_priv->current_page == 1 ) {
+		unsigned int tmp = flags;
+
+		flags &= ~(I830_FRONT | I830_BACK);
+		if ( tmp & I830_FRONT ) flags |= I830_BACK;
+		if ( tmp & I830_BACK )  flags |= I830_FRONT;
+	}
+
   	i830_kernel_lost_context(dev);
 
 	switch(cpp) {
@@ -865,13 +1015,17 @@
 	drm_clip_rect_t *pbox = sarea_priv->boxes;
 	int pitch = dev_priv->pitch;
 	int cpp = dev_priv->cpp;
-	int ofs = dev_priv->back_offset;
 	int i;
 	unsigned int CMD, BR13;
 	RING_LOCALS;
 
 	DRM_DEBUG("swapbuffers\n");
 
+  	i830_kernel_lost_context(dev);
+
+	if (dev_priv->do_boxes)
+		i830_cp_performance_boxes( dev );
+
 	switch(cpp) {
 	case 2: 
 		BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24);
@@ -888,7 +1042,6 @@
 		break;
 	}
 
-  	i830_kernel_lost_context(dev);
 
       	if (nbox > I830_NR_SAREA_CLIPRECTS)
      		nbox = I830_NR_SAREA_CLIPRECTS;
@@ -908,23 +1061,72 @@
 		BEGIN_LP_RING( 8 );
 		OUT_RING( CMD );
 		OUT_RING( BR13 );
+		OUT_RING( (pbox->y1 << 16) | pbox->x1 );
+		OUT_RING( (pbox->y2 << 16) | pbox->x2 );
 
-		OUT_RING( (pbox->y1 << 16) |
-			  pbox->x1 );
-		OUT_RING( (pbox->y2 << 16) |
-			  pbox->x2 );
-
-		OUT_RING( dev_priv->front_offset );
-		OUT_RING( (pbox->y1 << 16) |
-			  pbox->x1 );
+		if (dev_priv->current_page == 0) 
+			OUT_RING( dev_priv->front_offset );
+		else
+			OUT_RING( dev_priv->back_offset );			
 
+		OUT_RING( (pbox->y1 << 16) | pbox->x1 );
 		OUT_RING( BR13 & 0xffff );
-		OUT_RING( ofs );
+
+		if (dev_priv->current_page == 0) 
+			OUT_RING( dev_priv->back_offset );			
+		else
+			OUT_RING( dev_priv->front_offset );
 
 		ADVANCE_LP_RING();
 	}
 }
 
+static void i830_dma_dispatch_flip( drm_device_t *dev )
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+	RING_LOCALS;
+
+	DRM_DEBUG( "%s: page=%d pfCurrentPage=%d\n", 
+		   __FUNCTION__, 
+		   dev_priv->current_page,
+		   dev_priv->sarea_priv->pf_current_page);
+
+  	i830_kernel_lost_context(dev);
+
+	if (dev_priv->do_boxes) {
+		dev_priv->sarea_priv->perf_boxes |= I830_BOX_FLIP;
+		i830_cp_performance_boxes( dev );
+	}
+
+
+	BEGIN_LP_RING( 2 );
+    	OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); 
+	OUT_RING( 0 );
+	ADVANCE_LP_RING();
+
+	BEGIN_LP_RING( 6 );
+	OUT_RING( CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP );	
+	OUT_RING( 0 );
+	if ( dev_priv->current_page == 0 ) {
+		OUT_RING( dev_priv->back_offset );
+		dev_priv->current_page = 1;
+	} else {
+		OUT_RING( dev_priv->front_offset );
+		dev_priv->current_page = 0;
+	}
+	OUT_RING(0);
+	ADVANCE_LP_RING();
+
+
+	BEGIN_LP_RING( 2 );
+	OUT_RING( MI_WAIT_FOR_EVENT |
+		  MI_WAIT_FOR_PLANE_A_FLIP );
+	OUT_RING( 0 );
+	ADVANCE_LP_RING();
+	
+
+	dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
+}
 
 static void i830_dma_dispatch_vertex(drm_device_t *dev, 
 				     drm_buf_t *buf,
@@ -977,8 +1179,10 @@
 			 sarea_priv->vertex_prim |
 			 ((used/4)-2));
 
-		vp[used/4] = MI_BATCH_BUFFER_END;
-		used += 4;
+		if (dev_priv->use_mi_batchbuffer_start) {
+			vp[used/4] = MI_BATCH_BUFFER_END; 
+			used += 4; 
+		}
 		
 		if (used & 4) {
 			vp[used/4] = 0;
@@ -1001,11 +1205,21 @@
 				ADVANCE_LP_RING();
 			}
 
-			BEGIN_LP_RING(2);
-			OUT_RING( MI_BATCH_BUFFER_START | (2<<6) );
-			OUT_RING( start | MI_BATCH_NON_SECURE );
-			ADVANCE_LP_RING();
-			
+			if (dev_priv->use_mi_batchbuffer_start) {
+				BEGIN_LP_RING(2);
+				OUT_RING( MI_BATCH_BUFFER_START | (2<<6) );
+				OUT_RING( start | MI_BATCH_NON_SECURE );
+				ADVANCE_LP_RING();
+			} 
+			else {
+				BEGIN_LP_RING(4);
+				OUT_RING( MI_BATCH_BUFFER );
+				OUT_RING( start | MI_BATCH_NON_SECURE );
+				OUT_RING( start + used - 4 );
+				OUT_RING( 0 );
+				ADVANCE_LP_RING();
+			}
+
 		} while (++i < nbox);
 	}
 
@@ -1043,7 +1257,7 @@
       	OUT_RING( 0 );
    	ADVANCE_LP_RING();
 
-	i830_wait_ring( dev, dev_priv->ring.Size - 8 );
+	i830_wait_ring( dev, dev_priv->ring.Size - 8, __FUNCTION__ );
 }
 
 static int i830_flush_queue(drm_device_t *dev)
@@ -1060,7 +1274,7 @@
       	OUT_RING( 0 );
       	ADVANCE_LP_RING();
 
-	i830_wait_ring( dev, dev_priv->ring.Size - 8 );
+	i830_wait_ring( dev, dev_priv->ring.Size - 8, __FUNCTION__ );
 
    	for (i = 0; i < dma->buf_count; i++) {
 	   	drm_buf_t *buf = dma->buflist[ i ];
@@ -1079,8 +1293,10 @@
 }
 
 /* Must be called with the lock held */
-void i830_reclaim_buffers(drm_device_t *dev, pid_t pid)
+void i830_reclaim_buffers( struct file *filp )
 {
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev    = priv->dev;
 	drm_device_dma_t *dma = dev->dma;
 	int		 i;
 
@@ -1094,7 +1310,7 @@
 	   	drm_buf_t *buf = dma->buflist[ i ];
 	   	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
 	   
-		if (buf->pid == pid && buf_priv) {
+		if (buf->filp == filp && buf_priv) {
 			int used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, 
 					   I830_BUF_FREE);
 
@@ -1200,6 +1416,53 @@
    	return 0;
 }
 
+
+
+/* Not sure why this isn't set all the time:
+ */ 
+static void i830_do_init_pageflip( drm_device_t *dev )
+{
+	drm_i830_private_t *dev_priv = dev->dev_private;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+	dev_priv->page_flipping = 1;
+	dev_priv->current_page = 0;
+	dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
+}
+
+int i830_do_cleanup_pageflip( drm_device_t *dev )
+{
+	drm_i830_private_t *dev_priv = dev->dev_private;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+	if (dev_priv->current_page != 0)
+		i830_dma_dispatch_flip( dev );
+
+	dev_priv->page_flipping = 0;
+	return 0;
+}
+
+int i830_flip_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_i830_private_t *dev_priv = dev->dev_private;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i830_flip_buf called without lock held\n");
+		return -EINVAL;
+	}
+
+	if (!dev_priv->page_flipping) 
+		i830_do_init_pageflip( dev );
+
+	i830_dma_dispatch_flip( dev );
+   	return 0;
+}
+
 int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd,
 		unsigned long arg)
 {
@@ -1263,3 +1526,66 @@
 {
 	return 0;
 }
+
+
+
+int i830_getparam( 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_i830_private_t *dev_priv = dev->dev_private;
+	drm_i830_getparam_t param;
+	int value;
+
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&param, (drm_i830_getparam_t *)arg, sizeof(param) ))
+		return -EFAULT;
+
+	switch( param.param ) {
+	case I830_PARAM_IRQ_ACTIVE:
+		value = dev->irq ? 1 : 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if ( copy_to_user( param.value, &value, sizeof(int) ) ) {
+		DRM_ERROR( "copy_to_user\n" );
+		return -EFAULT;
+	}
+	
+	return 0;
+}
+
+
+int i830_setparam( 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_i830_private_t *dev_priv = dev->dev_private;
+	drm_i830_setparam_t param;
+
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&param, (drm_i830_setparam_t *)arg, sizeof(param) ))
+		return -EFAULT;
+
+	switch( param.param ) {
+	case I830_SETPARAM_USE_MI_BATCHBUFFER_START:
+		dev_priv->use_mi_batchbuffer_start = param.value;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
diff -urN linux-2.5.66-bk4/drivers/char/drm/i830_drm.h linux-2.5.66-bk5/drivers/char/drm/i830_drm.h
--- linux-2.5.66-bk4/drivers/char/drm/i830_drm.h	Mon Mar 24 14:00:18 2003
+++ linux-2.5.66-bk5/drivers/char/drm/i830_drm.h	Mon Mar 31 12:50:21 2003
@@ -3,6 +3,9 @@
 
 /* WARNING: These defines must be the same as what the Xserver uses.
  * if you change them, you must change the defines in the Xserver.
+ *
+ * KW: Actually, you can't ever change them because doing so would
+ * break backwards compatibility.
  */
 
 #ifndef _I830_DEFINES_
@@ -18,14 +21,12 @@
 #define I830_NR_TEX_REGIONS 64
 #define I830_LOG_MIN_TEX_REGION_SIZE 16
 
-/* if defining I830_ENABLE_4_TEXTURES, do it in i830_3d_reg.h, too */
-#if !defined(I830_ENABLE_4_TEXTURES)
+/* KW: These aren't correct but someone set them to two and then
+ * released the module.  Now we can't change them as doing so would
+ * break backwards compatibility.
+ */
 #define I830_TEXTURE_COUNT	2
-#define I830_TEXBLEND_COUNT	2	/* always same as TEXTURE_COUNT? */
-#else /* defined(I830_ENABLE_4_TEXTURES) */
-#define I830_TEXTURE_COUNT	4
-#define I830_TEXBLEND_COUNT	4	/* always same as TEXTURE_COUNT? */
-#endif /* I830_ENABLE_4_TEXTURES */
+#define I830_TEXBLEND_COUNT	I830_TEXTURE_COUNT
 
 #define I830_TEXBLEND_SIZE	12	/* (4 args + op) * 2 + COLOR_FACTOR */
 
@@ -57,6 +58,7 @@
 #define I830_UPLOAD_TEXBLEND_MASK	0xf00000
 #define I830_UPLOAD_TEX_PALETTE_N(n)    (0x1000000 << (n))
 #define I830_UPLOAD_TEX_PALETTE_SHARED	0x4000000
+#define I830_UPLOAD_STIPPLE         	0x8000000
 
 /* 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,
@@ -73,7 +75,6 @@
  */
 
 #define I830_DESTREG_CBUFADDR 0
-/* Invarient */
 #define I830_DESTREG_DBUFADDR 1
 #define I830_DESTREG_DV0 2
 #define I830_DESTREG_DV1 3
@@ -109,6 +110,13 @@
 #define I830_CTXREG_MCSB1		16
 #define I830_CTX_SETUP_SIZE		17
 
+/* 1.3: Stipple state
+ */ 
+#define I830_STPREG_ST0 0
+#define I830_STPREG_ST1 1
+#define I830_STP_SETUP_SIZE 2
+
+
 /* Texture state (per tex unit)
  */
 
@@ -124,6 +132,18 @@
 #define I830_TEXREG_MCS	9	/* GFX_OP_MAP_COORD_SETS */
 #define I830_TEX_SETUP_SIZE 10
 
+#define I830_TEXREG_TM0LI      0 /* load immediate 2 texture map n */
+#define I830_TEXREG_TM0S0      1
+#define I830_TEXREG_TM0S1      2
+#define I830_TEXREG_TM0S2      3
+#define I830_TEXREG_TM0S3      4
+#define I830_TEXREG_TM0S4      5
+#define I830_TEXREG_NOP0       6       /* noop */
+#define I830_TEXREG_NOP1       7       /* noop */
+#define I830_TEXREG_NOP2       8       /* noop */
+#define __I830_TEXREG_MCS      9       /* GFX_OP_MAP_COORD_SETS -- shared */
+#define __I830_TEX_SETUP_SIZE   10
+
 #define I830_FRONT   0x1
 #define I830_BACK    0x2
 #define I830_DEPTH   0x4
@@ -199,8 +219,35 @@
 	int ctxOwner;		/* last context to upload state */
 
 	int vertex_prim;
+
+        int pf_enabled;               /* is pageflipping allowed? */
+        int pf_active;               
+        int pf_current_page;	    /* which buffer is being displayed? */
+
+        int perf_boxes;             /* performance boxes to be displayed */
+   
+        /* Here's the state for texunits 2,3:
+	 */
+	unsigned int TexState2[I830_TEX_SETUP_SIZE];
+	unsigned int TexBlendState2[I830_TEXBLEND_SIZE];
+	unsigned int TexBlendStateWordsUsed2;
+
+	unsigned int TexState3[I830_TEX_SETUP_SIZE];
+	unsigned int TexBlendState3[I830_TEXBLEND_SIZE];
+	unsigned int TexBlendStateWordsUsed3;
+
+	unsigned int StippleState[I830_STP_SETUP_SIZE];
 } drm_i830_sarea_t;
 
+/* Flags for perf_boxes
+ */
+#define I830_BOX_RING_EMPTY    0x1 /* populated by kernel */
+#define I830_BOX_FLIP          0x2 /* populated by kernel */
+#define I830_BOX_WAIT          0x4 /* populated by kernel & client */
+#define I830_BOX_TEXTURE_LOAD  0x8 /* populated by kernel */
+#define I830_BOX_LOST_CONTEXT  0x10 /* populated by client */
+
+
 /* I830 specific ioctls
  * The device specific ioctl range is 0x40 to 0x79.
  */
@@ -213,6 +260,11 @@
 #define DRM_IOCTL_I830_SWAP		DRM_IO ( 0x46)
 #define DRM_IOCTL_I830_COPY		DRM_IOW( 0x47, drm_i830_copy_t)
 #define DRM_IOCTL_I830_DOCOPY		DRM_IO ( 0x48)
+#define DRM_IOCTL_I830_FLIP		DRM_IO ( 0x49)
+#define DRM_IOCTL_I830_IRQ_EMIT         DRM_IOWR(0x4a, drm_i830_irq_emit_t)
+#define DRM_IOCTL_I830_IRQ_WAIT         DRM_IOW( 0x4b, drm_i830_irq_wait_t)
+#define DRM_IOCTL_I830_GETPARAM         DRM_IOWR(0x4c, drm_i830_getparam_t)
+#define DRM_IOCTL_I830_SETPARAM         DRM_IOWR(0x4d, drm_i830_setparam_t)
 
 typedef struct _drm_i830_clear {
 	int clear_color;
@@ -248,4 +300,36 @@
 	int granted;
 } drm_i830_dma_t;
 
+
+/* 1.3: Userspace can request & wait on irq's:
+ */
+typedef struct drm_i830_irq_emit {
+	int *irq_seq;
+} drm_i830_irq_emit_t;
+
+typedef struct drm_i830_irq_wait {
+	int irq_seq;
+} drm_i830_irq_wait_t;
+
+
+/* 1.3: New ioctl to query kernel params:
+ */
+#define I830_PARAM_IRQ_ACTIVE            1
+
+typedef struct drm_i830_getparam {
+	int param;
+	int *value;
+} drm_i830_getparam_t;
+
+
+/* 1.3: New ioctl to set kernel params:
+ */
+#define I830_SETPARAM_USE_MI_BATCHBUFFER_START            1
+
+typedef struct drm_i830_setparam {
+	int param;
+	int value;
+} drm_i830_setparam_t;
+
+
 #endif /* _I830_DRM_H_ */
diff -urN linux-2.5.66-bk4/drivers/char/drm/i830_drv.h linux-2.5.66-bk5/drivers/char/drm/i830_drv.h
--- linux-2.5.66-bk4/drivers/char/drm/i830_drv.h	Mon Mar 24 14:00:55 2003
+++ linux-2.5.66-bk5/drivers/char/drm/i830_drv.h	Mon Mar 31 12:50:21 2003
@@ -78,6 +78,19 @@
 	int back_pitch;
 	int depth_pitch;
 	unsigned int cpp;
+
+	int do_boxes;
+	int dma_used;
+
+	int current_page;
+	int page_flipping;
+
+	wait_queue_head_t irq_queue;
+   	atomic_t irq_received;
+   	atomic_t irq_emitted;
+
+	int use_mi_batchbuffer_start;
+
 } drm_i830_private_t;
 
 				/* i830_dma.c */
@@ -88,7 +101,7 @@
 			  unsigned int cmd, unsigned long arg);
 extern int  i830_flush_ioctl(struct inode *inode, struct file *filp,
 			     unsigned int cmd, unsigned long arg);
-extern void i830_reclaim_buffers(drm_device_t *dev, pid_t pid);
+extern void i830_reclaim_buffers(struct file *filp);
 extern int  i830_getage(struct inode *inode, struct file *filp, unsigned int cmd,
 			unsigned long arg);
 extern int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma);
@@ -108,6 +121,23 @@
 extern int i830_clear_bufs(struct inode *inode, struct file *filp,
 			  unsigned int cmd, unsigned long arg);
 
+extern int i830_flip_bufs(struct inode *inode, struct file *filp,
+			 unsigned int cmd, unsigned long arg);
+
+extern int i830_getparam( struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg );
+
+extern int i830_setparam( struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg );
+
+/* i830_irq.c */
+extern int i830_irq_emit( struct inode *inode, struct file *filp, 
+			  unsigned int cmd, unsigned long arg );
+extern int i830_irq_wait( struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg );
+extern int i830_wait_irq(drm_device_t *dev, int irq_nr);
+extern int i830_emit_irq(drm_device_t *dev);
+
 
 #define I830_BASE(reg)		((unsigned long) \
 				dev_priv->mmio_map->handle)
@@ -119,12 +149,53 @@
 #define I830_READ16(reg) 	I830_DEREF16(reg)
 #define I830_WRITE16(reg,val)	do { I830_DEREF16(reg) = val; } while (0)
 
+
+
+#define I830_VERBOSE 0
+
+#define RING_LOCALS	unsigned int outring, ringmask, outcount; \
+                        volatile char *virt;
+
+#define BEGIN_LP_RING(n) do {				\
+	if (I830_VERBOSE)				\
+		printk("BEGIN_LP_RING(%d) in %s\n",	\
+			  n, __FUNCTION__);		\
+	if (dev_priv->ring.space < n*4)			\
+		i830_wait_ring(dev, n*4, __FUNCTION__);		\
+	outcount = 0;					\
+	outring = dev_priv->ring.tail;			\
+	ringmask = dev_priv->ring.tail_mask;		\
+	virt = dev_priv->ring.virtual_start;		\
+} while (0)
+
+
+#define OUT_RING(n) do {					\
+	if (I830_VERBOSE) printk("   OUT_RING %x\n", (int)(n));	\
+	*(volatile unsigned int *)(virt + outring) = n;		\
+        outcount++;						\
+	outring += 4;						\
+	outring &= ringmask;					\
+} while (0)
+
+#define ADVANCE_LP_RING() do {						\
+	if (I830_VERBOSE) printk("ADVANCE_LP_RING %x\n", outring);	\
+	dev_priv->ring.tail = outring;					\
+	dev_priv->ring.space -= outcount * 4;				\
+	I830_WRITE(LP_RING + RING_TAIL, outring);			\
+} while(0)
+
+extern int i830_wait_ring(drm_device_t *dev, int n, const char *caller);
+
+
 #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 STATE3D_LOAD_STATE_IMMEDIATE_2      ((0x3<<29)|(0x1d<<24)|(0x03<<16))
+#define LOAD_TEXTURE_MAP0                   (1<<11)
+
 #define INST_PARSER_CLIENT   0x00000000
 #define INST_OP_FLUSH        0x02000000
 #define INST_FLUSH_MAP_CACHE 0x00000001
@@ -140,6 +211,9 @@
 #define I830REG_INT_MASK_R 	0x020a8
 #define I830REG_INT_ENABLE_R	0x020a0
 
+#define I830_IRQ_RESERVED ((1<<13)|(3<<2))
+
+
 #define LP_RING     		0x2030
 #define HP_RING     		0x2040
 #define RING_TAIL      		0x00
@@ -182,6 +256,9 @@
 
 #define CMD_OP_DESTBUFFER_INFO	 ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1)
 
+#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2)
+#define ASYNC_FLIP                (1<<22)
+
 #define CMD_3D                          (0x3<<29)
 #define STATE3D_CONST_BLEND_COLOR_CMD   (CMD_3D|(0x1d<<24)|(0x88<<16))
 #define STATE3D_MAP_COORD_SETBIND_CMD   (CMD_3D|(0x1d<<24)|(0x02<<16))
@@ -213,6 +290,11 @@
 #define MI_BATCH_BUFFER_END 	(0xA<<23)
 #define MI_BATCH_NON_SECURE	(1)
 
+#define MI_WAIT_FOR_EVENT       ((0x3<<23))
+#define MI_WAIT_FOR_PLANE_A_FLIP      (1<<2) 
+#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1) 
+
+#define MI_LOAD_SCAN_LINES_INCL  ((0x12<<23))
 
 #endif
 
diff -urN linux-2.5.66-bk4/drivers/char/drm/i830_irq.c linux-2.5.66-bk5/drivers/char/drm/i830_irq.c
--- linux-2.5.66-bk4/drivers/char/drm/i830_irq.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk5/drivers/char/drm/i830_irq.c	Mon Mar 31 12:50:21 2003
@@ -0,0 +1,177 @@
+/* i830_dma.c -- DMA support for the I830 -*- linux-c -*-
+ *
+ * Copyright 2002 Tungsten Graphics, Inc.
+ * 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
+ * TUNGSTEN GRAPHICS 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: Keith Whitwell <keith@tungstengraphics.com>
+ *
+ */
+
+#include "i830.h"
+#include "drmP.h"
+#include "drm.h"
+#include "i830_drm.h"
+#include "i830_drv.h"
+#include <linux/interrupt.h>	/* For task queue support */
+#include <linux/delay.h>
+
+
+void DRM(dma_service)(int irq, void *device, struct pt_regs *regs)
+{
+	drm_device_t	 *dev = (drm_device_t *)device;
+      	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+   	u16 temp;
+   
+      	temp = I830_READ16(I830REG_INT_IDENTITY_R);
+	printk("%s: %x\n", __FUNCTION__, temp);
+	
+   	if(temp == 0) 
+	   return;
+
+	I830_WRITE16(I830REG_INT_IDENTITY_R, temp); 
+
+	if (temp & 2) {
+		atomic_inc(&dev_priv->irq_received);
+		wake_up_interruptible(&dev_priv->irq_queue); 
+	}
+}
+
+
+int i830_emit_irq(drm_device_t *dev)
+{
+	drm_i830_private_t *dev_priv = dev->dev_private;
+	RING_LOCALS;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	atomic_inc(&dev_priv->irq_emitted);
+
+   	BEGIN_LP_RING(2);
+      	OUT_RING( 0 );
+      	OUT_RING( GFX_OP_USER_INTERRUPT );
+      	ADVANCE_LP_RING();
+
+	return atomic_read(&dev_priv->irq_emitted);
+}
+
+
+int i830_wait_irq(drm_device_t *dev, int irq_nr)
+{
+  	drm_i830_private_t *dev_priv = 
+	   (drm_i830_private_t *)dev->dev_private;
+	DECLARE_WAITQUEUE(entry, current);
+	unsigned long end = jiffies + HZ*3;
+	int ret = 0;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+ 	if (atomic_read(&dev_priv->irq_received) >= irq_nr)  
+ 		return 0; 
+
+	dev_priv->sarea_priv->perf_boxes |= I830_BOX_WAIT;
+
+	add_wait_queue(&dev_priv->irq_queue, &entry);
+
+	for (;;) {
+		current->state = TASK_INTERRUPTIBLE;
+	   	if (atomic_read(&dev_priv->irq_received) >= irq_nr) 
+		   break;
+		if((signed)(end - jiffies) <= 0) {
+			DRM_ERROR("timeout iir %x imr %x ier %x hwstam %x\n",
+				  I830_READ16( I830REG_INT_IDENTITY_R ),
+				  I830_READ16( I830REG_INT_MASK_R ),
+				  I830_READ16( I830REG_INT_ENABLE_R ),
+				  I830_READ16( I830REG_HWSTAM ));
+
+		   	ret = -EBUSY;	/* Lockup?  Missed irq? */
+			break;
+		}
+	      	schedule_timeout(HZ*3);
+	      	if (signal_pending(current)) {
+		   	ret = -EINTR;
+			break;
+		}
+	}
+
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&dev_priv->irq_queue, &entry);
+	return ret;
+}
+
+
+/* Needs the lock as it touches the ring.
+ */
+int i830_irq_emit( 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_i830_private_t *dev_priv = dev->dev_private;
+	drm_i830_irq_emit_t emit;
+	int result;
+
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i830_irq_emit called without lock held\n");
+		return -EINVAL;
+	}
+
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+		return -EINVAL;
+	}
+
+	if (copy_from_user( &emit, (drm_i830_irq_emit_t *)arg, sizeof(emit) ))
+		return -EFAULT;
+
+	result = i830_emit_irq( dev );
+
+	if ( copy_to_user( emit.irq_seq, &result, sizeof(int) ) ) {
+		DRM_ERROR( "copy_to_user\n" );
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+
+/* Doesn't need the hardware lock.
+ */
+int i830_irq_wait( 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_i830_private_t *dev_priv = dev->dev_private;
+	drm_i830_irq_wait_t irqwait;
+
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+		return -EINVAL;
+	}
+
+	if (copy_from_user( &irqwait, (drm_i830_irq_wait_t *)arg, 
+			    sizeof(irqwait) ))
+		return -EFAULT;
+
+	return i830_wait_irq( dev, irqwait.irq_seq );
+}
+
diff -urN linux-2.5.66-bk4/drivers/char/drm/mga_dma.c linux-2.5.66-bk5/drivers/char/drm/mga_dma.c
--- linux-2.5.66-bk4/drivers/char/drm/mga_dma.c	Mon Mar 24 14:01:24 2003
+++ linux-2.5.66-bk5/drivers/char/drm/mga_dma.c	Mon Mar 31 12:50:21 2003
@@ -686,7 +686,7 @@
 	drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
 	drm_lock_t lock;
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	DRM_COPY_FROM_USER_IOCTL( lock, (drm_lock_t *)data, sizeof(lock) );
 
@@ -720,7 +720,7 @@
 	DRM_DEVICE;
 	drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	return mga_do_dma_reset( dev_priv );
 }
@@ -730,7 +730,8 @@
  * DMA buffer management
  */
 
-static int mga_dma_get_buffers( drm_device_t *dev, drm_dma_t *d )
+static int mga_dma_get_buffers( DRMFILE filp,
+				drm_device_t *dev, drm_dma_t *d )
 {
 	drm_buf_t *buf;
 	int i;
@@ -739,7 +740,7 @@
 		buf = mga_freelist_get( dev );
 		if ( !buf ) return DRM_ERR(EAGAIN);
 
-		buf->pid = DRM_CURRENTPID;
+		buf->filp = filp;
 
 		if ( DRM_COPY_TO_USER( &d->request_indices[i],
 				   &buf->idx, sizeof(buf->idx) ) )
@@ -761,7 +762,7 @@
 	drm_dma_t d;
 	int ret = 0;
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	DRM_COPY_FROM_USER_IOCTL( d, (drm_dma_t *)data, sizeof(d) );
 
@@ -786,7 +787,7 @@
 	d.granted_count = 0;
 
 	if ( d.request_count ) {
-		ret = mga_dma_get_buffers( dev, &d );
+		ret = mga_dma_get_buffers( filp, dev, &d );
 	}
 
 	DRM_COPY_TO_USER_IOCTL( (drm_dma_t *)data, d, sizeof(d) );
diff -urN linux-2.5.66-bk4/drivers/char/drm/mga_drv.h linux-2.5.66-bk5/drivers/char/drm/mga_drv.h
--- linux-2.5.66-bk4/drivers/char/drm/mga_drv.h	Mon Mar 24 14:01:24 2003
+++ linux-2.5.66-bk5/drivers/char/drm/mga_drv.h	Mon Mar 31 12:50:21 2003
@@ -90,14 +90,14 @@
 	unsigned int texture_offset;
 	unsigned int texture_size;
 
-	drm_map_t *sarea;
-	drm_map_t *fb;
-	drm_map_t *mmio;
-	drm_map_t *status;
-	drm_map_t *warp;
-	drm_map_t *primary;
-	drm_map_t *buffers;
-	drm_map_t *agp_textures;
+	drm_local_map_t *sarea;
+	drm_local_map_t *fb;
+	drm_local_map_t *mmio;
+	drm_local_map_t *status;
+	drm_local_map_t *warp;
+	drm_local_map_t *primary;
+	drm_local_map_t *buffers;
+	drm_local_map_t *agp_textures;
 } drm_mga_private_t;
 
 				/* mga_dma.c */
@@ -131,32 +131,30 @@
 extern int mga_warp_install_microcode( drm_mga_private_t *dev_priv );
 extern int mga_warp_init( drm_mga_private_t *dev_priv );
 
-#define mga_flush_write_combine()	DRM_WRITEMEMORYBARRIER()
-
+#define mga_flush_write_combine()	DRM_WRITEMEMORYBARRIER(dev_priv->primary)
 
+#if defined(__linux__) && defined(__alpha__)
 #define MGA_BASE( reg )		((unsigned long)(dev_priv->mmio->handle))
 #define MGA_ADDR( reg )		(MGA_BASE(reg) + reg)
 
 #define MGA_DEREF( reg )	*(volatile u32 *)MGA_ADDR( reg )
 #define MGA_DEREF8( reg )	*(volatile u8 *)MGA_ADDR( reg )
 
-#ifdef __alpha__
 #define MGA_READ( reg )		(_MGA_READ((u32 *)MGA_ADDR(reg)))
 #define MGA_READ8( reg )	(_MGA_READ((u8 *)MGA_ADDR(reg)))
-#define MGA_WRITE( reg, val )	do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF( reg ) = val; } while (0)
-#define MGA_WRITE8( reg, val )  do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF8( reg ) = val; } while (0)
+#define MGA_WRITE( reg, val )	do { DRM_WRITEMEMORYBARRIER(dev_priv->mmio); MGA_DEREF( reg ) = val; } while (0)
+#define MGA_WRITE8( reg, val )  do { DRM_WRITEMEMORYBARRIER(dev_priv->mmio); MGA_DEREF8( reg ) = val; } while (0)
 
 static inline u32 _MGA_READ(u32 *addr)
 {
-	DRM_READMEMORYBARRIER();
+	DRM_READMEMORYBARRIER(dev_priv->mmio);
 	return *(volatile u32 *)addr;
 }
-
 #else
-#define MGA_READ( reg )		MGA_DEREF( reg )
-#define MGA_READ8( reg )	MGA_DEREF8( reg )
-#define MGA_WRITE( reg, val )	do { MGA_DEREF( reg ) = val; } while (0)
-#define MGA_WRITE8( reg, val )  do { MGA_DEREF8( reg ) = val; } while (0)
+#define MGA_READ8( reg )	DRM_READ8(dev_priv->mmio, (reg))
+#define MGA_READ( reg )		DRM_READ32(dev_priv->mmio, (reg))
+#define MGA_WRITE8( reg, val )  DRM_WRITE8(dev_priv->mmio, (reg), (val))
+#define MGA_WRITE( reg, val )	DRM_WRITE32(dev_priv->mmio, (reg), (val))
 #endif
 
 #define DWGREG0 	0x1c00
@@ -186,16 +184,6 @@
 	}								\
 } while (0)
 
-#define LOCK_TEST_WITH_RETURN( dev )					\
-do {									\
-	if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) ||		\
-	     dev->lock.pid != DRM_CURRENTPID ) {				\
-		DRM_ERROR( "%s called without lock held\n",		\
-			   __FUNCTION__ );					\
-		return DRM_ERR(EINVAL);				\
-	}								\
-} while (0)
-
 #define WRAP_TEST_WITH_RETURN( dev_priv )				\
 do {									\
 	if ( test_bit( 0, &dev_priv->prim.wrapped ) ) {			\
diff -urN linux-2.5.66-bk4/drivers/char/drm/mga_state.c linux-2.5.66-bk5/drivers/char/drm/mga_state.c
--- linux-2.5.66-bk4/drivers/char/drm/mga_state.c	Mon Mar 24 14:00:19 2003
+++ linux-2.5.66-bk5/drivers/char/drm/mga_state.c	Mon Mar 31 12:50:21 2003
@@ -887,7 +887,7 @@
 	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	drm_mga_clear_t clear;
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	DRM_COPY_FROM_USER_IOCTL( clear, (drm_mga_clear_t *)data, sizeof(clear) );
 
@@ -911,7 +911,7 @@
 	drm_mga_private_t *dev_priv = dev->dev_private;
 	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	if ( sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS )
 		sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
@@ -936,7 +936,7 @@
 	drm_mga_buf_priv_t *buf_priv;
 	drm_mga_vertex_t vertex;
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	DRM_COPY_FROM_USER_IOCTL( vertex,
 			     (drm_mga_vertex_t *)data,
@@ -975,7 +975,7 @@
 	drm_mga_buf_priv_t *buf_priv;
 	drm_mga_indices_t indices;
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	DRM_COPY_FROM_USER_IOCTL( indices,
 			     (drm_mga_indices_t *)data,
@@ -1015,7 +1015,7 @@
 	drm_mga_iload_t iload;
 	DRM_DEBUG( "\n" );
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	DRM_COPY_FROM_USER_IOCTL( iload, (drm_mga_iload_t *)data, sizeof(iload) );
 
@@ -1055,7 +1055,7 @@
 	drm_mga_blit_t blit;
 	DRM_DEBUG( "\n" );
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	DRM_COPY_FROM_USER_IOCTL( blit, (drm_mga_blit_t *)data, sizeof(blit) );
 
diff -urN linux-2.5.66-bk4/drivers/char/drm/r128_cce.c linux-2.5.66-bk5/drivers/char/drm/r128_cce.c
--- linux-2.5.66-bk4/drivers/char/drm/r128_cce.c	Mon Mar 24 14:00:07 2003
+++ linux-2.5.66-bk5/drivers/char/drm/r128_cce.c	Mon Mar 31 12:50:21 2003
@@ -579,6 +579,7 @@
 		(dev_priv->ring.size / sizeof(u32)) - 1;
 
 	dev_priv->ring.high_mark = 128;
+	dev_priv->ring.ring_rptr = dev_priv->ring_rptr;
 
 	dev_priv->sarea_priv->last_frame = 0;
 	R128_WRITE( R128_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame );
@@ -663,7 +664,7 @@
 	drm_r128_private_t *dev_priv = dev->dev_private;
 	DRM_DEBUG( "\n" );
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	if ( dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4 ) {
 		DRM_DEBUG( "%s while CCE running\n", __FUNCTION__ );
@@ -686,7 +687,7 @@
 	int ret;
 	DRM_DEBUG( "\n" );
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	DRM_COPY_FROM_USER_IOCTL(stop, (drm_r128_cce_stop_t *)data, sizeof(stop) );
 
@@ -725,7 +726,7 @@
 	drm_r128_private_t *dev_priv = dev->dev_private;
 	DRM_DEBUG( "\n" );
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	if ( !dev_priv ) {
 		DRM_DEBUG( "%s called before init done\n", __FUNCTION__ );
@@ -746,7 +747,7 @@
 	drm_r128_private_t *dev_priv = dev->dev_private;
 	DRM_DEBUG( "\n" );
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	if ( dev_priv->cce_running ) {
 		r128_do_cce_flush( dev_priv );
@@ -760,7 +761,7 @@
 	DRM_DEVICE;
 	DRM_DEBUG( "\n" );
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	return r128_do_engine_reset( dev );
 }
@@ -807,7 +808,7 @@
 	DRM_DEVICE;
 	drm_r128_fullscreen_t fs;
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	DRM_COPY_FROM_USER_IOCTL( fs, (drm_r128_fullscreen_t *)data, sizeof(fs) );
 
@@ -889,7 +890,7 @@
 	for ( i = 0 ; i < dma->buf_count ; i++ ) {
 		buf = dma->buflist[i];
 		buf_priv = buf->dev_private;
-		if ( buf->pid == 0 )
+		if ( buf->filp == 0 )
 			return buf;
 	}
 
@@ -948,7 +949,7 @@
 	return DRM_ERR(EBUSY);
 }
 
-static int r128_cce_get_buffers( drm_device_t *dev, drm_dma_t *d )
+static int r128_cce_get_buffers( DRMFILE filp, drm_device_t *dev, drm_dma_t *d )
 {
 	int i;
 	drm_buf_t *buf;
@@ -957,7 +958,7 @@
 		buf = r128_freelist_get( dev );
 		if ( !buf ) return DRM_ERR(EAGAIN);
 
-		buf->pid = DRM_CURRENTPID;
+		buf->filp = filp;
 
 		if ( DRM_COPY_TO_USER( &d->request_indices[i], &buf->idx,
 				   sizeof(buf->idx) ) )
@@ -978,7 +979,7 @@
 	int ret = 0;
 	drm_dma_t d;
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	DRM_COPY_FROM_USER_IOCTL( d, (drm_dma_t *) data, sizeof(d) );
 
@@ -1001,7 +1002,7 @@
 	d.granted_count = 0;
 
 	if ( d.request_count ) {
-		ret = r128_cce_get_buffers( dev, &d );
+		ret = r128_cce_get_buffers( filp, dev, &d );
 	}
 
 	DRM_COPY_TO_USER_IOCTL((drm_dma_t *) data, d, sizeof(d) );
diff -urN linux-2.5.66-bk4/drivers/char/drm/r128_drv.h linux-2.5.66-bk5/drivers/char/drm/r128_drv.h
--- linux-2.5.66-bk4/drivers/char/drm/r128_drv.h	Mon Mar 24 14:01:52 2003
+++ linux-2.5.66-bk5/drivers/char/drm/r128_drv.h	Mon Mar 31 12:50:21 2003
@@ -34,8 +34,8 @@
 #ifndef __R128_DRV_H__
 #define __R128_DRV_H__
 
-#define GET_RING_HEAD(ring)		DRM_READ32(  (volatile u32 *) (ring)->head )
-#define SET_RING_HEAD(ring,val)		DRM_WRITE32( (volatile u32 *) (ring)->head, (val) )
+#define GET_RING_HEAD(ring)		DRM_READ32(  (ring)->ring_rptr, 0 ) /* (ring)->head */
+#define SET_RING_HEAD(ring,val)		DRM_WRITE32( (ring)->ring_rptr, 0, (val) ) /* (ring)->head */
 
 typedef struct drm_r128_freelist {
    	unsigned int age;
@@ -56,6 +56,7 @@
 	int space;
 
 	int high_mark;
+	drm_local_map_t *ring_rptr;
 } drm_r128_ring_buffer_t;
 
 typedef struct drm_r128_private {
@@ -98,13 +99,13 @@
 	u32 depth_pitch_offset_c;
 	u32 span_pitch_offset_c;
 
-	drm_map_t *sarea;
-	drm_map_t *fb;
-	drm_map_t *mmio;
-	drm_map_t *cce_ring;
-	drm_map_t *ring_rptr;
-	drm_map_t *buffers;
-	drm_map_t *agp_textures;
+	drm_local_map_t *sarea;
+	drm_local_map_t *fb;
+	drm_local_map_t *mmio;
+	drm_local_map_t *cce_ring;
+	drm_local_map_t *ring_rptr;
+	drm_local_map_t *buffers;
+	drm_local_map_t *agp_textures;
 } drm_r128_private_t;
 
 typedef struct drm_r128_buf_priv {
@@ -370,15 +371,10 @@
 
 #define R128_PERFORMANCE_BOXES		0
 
-
-#define R128_BASE(reg)		((unsigned long)(dev_priv->mmio->handle))
-#define R128_ADDR(reg)		(R128_BASE( reg ) + reg)
-
-#define R128_READ(reg)		DRM_READ32(  (volatile u32 *) R128_ADDR(reg) )
-#define R128_WRITE(reg,val)	DRM_WRITE32( (volatile u32 *) R128_ADDR(reg), (val) )
-
-#define R128_READ8(reg)		DRM_READ8(  (volatile u8 *) R128_ADDR(reg) )
-#define R128_WRITE8(reg,val)	DRM_WRITE8( (volatile u8 *) R128_ADDR(reg), (val) )
+#define R128_READ(reg)		DRM_READ32(  dev_priv->mmio, (reg) )
+#define R128_WRITE(reg,val)	DRM_WRITE32( dev_priv->mmio, (reg), (val) )
+#define R128_READ8(reg)		DRM_READ8(   dev_priv->mmio, (reg) )
+#define R128_WRITE8(reg,val)	DRM_WRITE8(  dev_priv->mmio, (reg), (val) )
 
 #define R128_WRITE_PLL(addr,val)					\
 do {									\
@@ -403,15 +399,6 @@
  * Misc helper macros
  */
 
-#define LOCK_TEST_WITH_RETURN( dev )					\
-do {									\
-	if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) ||		\
-	     dev->lock.pid != DRM_CURRENTPID ) {			\
-		DRM_ERROR( "%s called without lock held\n", __FUNCTION__ );	\
-		return DRM_ERR(EINVAL);				\
-	}								\
-} while (0)
-
 #define RING_SPACE_TEST_WITH_RETURN( dev_priv )				\
 do {									\
 	drm_r128_ring_buffer_t *ring = &dev_priv->ring; int i;		\
@@ -453,7 +440,7 @@
 #if defined(__powerpc__)
 #define r128_flush_write_combine()	(void) GET_RING_HEAD( &dev_priv->ring )
 #else
-#define r128_flush_write_combine()	DRM_WRITEMEMORYBARRIER()
+#define r128_flush_write_combine()	DRM_WRITEMEMORYBARRIER(dev_priv->ring_rptr)
 #endif
 
 
diff -urN linux-2.5.66-bk4/drivers/char/drm/r128_state.c linux-2.5.66-bk5/drivers/char/drm/r128_state.c
--- linux-2.5.66-bk4/drivers/char/drm/r128_state.c	Mon Mar 24 14:00:08 2003
+++ linux-2.5.66-bk5/drivers/char/drm/r128_state.c	Mon Mar 31 12:50:21 2003
@@ -778,7 +778,8 @@
 	sarea_priv->nbox = 0;
 }
 
-static int r128_cce_dispatch_blit( drm_device_t *dev,
+static int r128_cce_dispatch_blit( DRMFILE filp,
+				   drm_device_t *dev,
 				   drm_r128_blit_t *blit )
 {
 	drm_r128_private_t *dev_priv = dev->dev_private;
@@ -829,9 +830,9 @@
 	buf = dma->buflist[blit->idx];
 	buf_priv = buf->dev_private;
 
-	if ( buf->pid != DRM_CURRENTPID ) {
-		DRM_ERROR( "process %d using buffer owned by %d\n",
-			   DRM_CURRENTPID, buf->pid );
+	if ( buf->filp != filp ) {
+		DRM_ERROR( "process %d using buffer owned by %p\n",
+			   DRM_CURRENTPID, buf->filp );
 		return DRM_ERR(EINVAL);
 	}
 	if ( buf->pending ) {
@@ -896,7 +897,7 @@
 	int count, x, y;
 	u32 *buffer;
 	u8 *mask;
-	int i;
+	int i, buffer_size, mask_size;
 	RING_LOCALS;
 	DRM_DEBUG( "\n" );
 
@@ -908,25 +909,25 @@
 		return DRM_ERR(EFAULT);
 	}
 
-	buffer = DRM_MALLOC( depth->n * sizeof(u32) );
+	buffer_size = depth->n * sizeof(u32);
+	buffer = DRM_MALLOC( buffer_size );
 	if ( buffer == NULL )
 		return DRM_ERR(ENOMEM);
-	if ( DRM_COPY_FROM_USER( buffer, depth->buffer,
-			     depth->n * sizeof(u32) ) ) {
-		DRM_FREE( buffer );
+	if ( DRM_COPY_FROM_USER( buffer, depth->buffer, buffer_size ) ) {
+		DRM_FREE( buffer, buffer_size);
 		return DRM_ERR(EFAULT);
 	}
 
+	mask_size = depth->n * sizeof(u8);
 	if ( depth->mask ) {
-		mask = DRM_MALLOC( depth->n * sizeof(u8) );
+		mask = DRM_MALLOC( mask_size );
 		if ( mask == NULL ) {
-			DRM_FREE( buffer );
+			DRM_FREE( buffer, buffer_size );
 			return DRM_ERR(ENOMEM);
 		}
-		if ( DRM_COPY_FROM_USER( mask, depth->mask,
-				     depth->n * sizeof(u8) ) ) {
-			DRM_FREE( buffer );
-			DRM_FREE( mask );
+		if ( DRM_COPY_FROM_USER( mask, depth->mask, mask_size ) ) {
+			DRM_FREE( buffer, buffer_size );
+			DRM_FREE( mask, mask_size );
 			return DRM_ERR(EFAULT);
 		}
 
@@ -953,7 +954,7 @@
 			}
 		}
 
-		DRM_FREE( mask );
+		DRM_FREE( mask, mask_size );
 	} else {
 		for ( i = 0 ; i < count ; i++, x++ ) {
 			BEGIN_RING( 6 );
@@ -977,7 +978,7 @@
 		}
 	}
 
-	DRM_FREE( buffer );
+	DRM_FREE( buffer, buffer_size );
 
 	return 0;
 }
@@ -989,60 +990,62 @@
 	int count, *x, *y;
 	u32 *buffer;
 	u8 *mask;
-	int i;
+	int i, xbuf_size, ybuf_size, buffer_size, mask_size;
 	RING_LOCALS;
 	DRM_DEBUG( "\n" );
 
 	count = depth->n;
 
-	x = DRM_MALLOC( count * sizeof(*x) );
+	xbuf_size = count * sizeof(*x);
+	ybuf_size = count * sizeof(*y);
+	x = DRM_MALLOC( xbuf_size );
 	if ( x == NULL ) {
 		return DRM_ERR(ENOMEM);
 	}
-	y = DRM_MALLOC( count * sizeof(*y) );
+	y = DRM_MALLOC( ybuf_size );
 	if ( y == NULL ) {
-		DRM_FREE( x );
+		DRM_FREE( x, xbuf_size );
 		return DRM_ERR(ENOMEM);
 	}
-	if ( DRM_COPY_FROM_USER( x, depth->x, count * sizeof(int) ) ) {
-		DRM_FREE( x );
-		DRM_FREE( y );
+	if ( DRM_COPY_FROM_USER( x, depth->x, xbuf_size ) ) {
+		DRM_FREE( x, xbuf_size );
+		DRM_FREE( y, ybuf_size );
 		return DRM_ERR(EFAULT);
 	}
-	if ( DRM_COPY_FROM_USER( y, depth->y, count * sizeof(int) ) ) {
-		DRM_FREE( x );
-		DRM_FREE( y );
+	if ( DRM_COPY_FROM_USER( y, depth->y, xbuf_size ) ) {
+		DRM_FREE( x, xbuf_size );
+		DRM_FREE( y, ybuf_size );
 		return DRM_ERR(EFAULT);
 	}
 
-	buffer = DRM_MALLOC( depth->n * sizeof(u32) );
+	buffer_size = depth->n * sizeof(u32);
+	buffer = DRM_MALLOC( buffer_size );
 	if ( buffer == NULL ) {
-		DRM_FREE( x );
-		DRM_FREE( y );
+		DRM_FREE( x, xbuf_size );
+		DRM_FREE( y, ybuf_size );
 		return DRM_ERR(ENOMEM);
 	}
-	if ( DRM_COPY_FROM_USER( buffer, depth->buffer,
-			     depth->n * sizeof(u32) ) ) {
-		DRM_FREE( x );
-		DRM_FREE( y );
-		DRM_FREE( buffer );
+	if ( DRM_COPY_FROM_USER( buffer, depth->buffer, buffer_size ) ) {
+		DRM_FREE( x, xbuf_size );
+		DRM_FREE( y, ybuf_size );
+		DRM_FREE( buffer, buffer_size );
 		return DRM_ERR(EFAULT);
 	}
 
 	if ( depth->mask ) {
-		mask = DRM_MALLOC( depth->n * sizeof(u8) );
+		mask_size = depth->n * sizeof(u8);
+		mask = DRM_MALLOC( mask_size );
 		if ( mask == NULL ) {
-			DRM_FREE( x );
-			DRM_FREE( y );
-			DRM_FREE( buffer );
+			DRM_FREE( x, xbuf_size );
+			DRM_FREE( y, ybuf_size );
+			DRM_FREE( buffer, buffer_size );
 			return DRM_ERR(ENOMEM);
 		}
-		if ( DRM_COPY_FROM_USER( mask, depth->mask,
-				     depth->n * sizeof(u8) ) ) {
-			DRM_FREE( x );
-			DRM_FREE( y );
-			DRM_FREE( buffer );
-			DRM_FREE( mask );
+		if ( DRM_COPY_FROM_USER( mask, depth->mask, mask_size ) ) {
+			DRM_FREE( x, xbuf_size );
+			DRM_FREE( y, ybuf_size );
+			DRM_FREE( buffer, buffer_size );
+			DRM_FREE( mask, mask_size );
 			return DRM_ERR(EFAULT);
 		}
 
@@ -1069,7 +1072,7 @@
 			}
 		}
 
-		DRM_FREE( mask );
+		DRM_FREE( mask, mask_size );
 	} else {
 		for ( i = 0 ; i < count ; i++ ) {
 			BEGIN_RING( 6 );
@@ -1093,9 +1096,9 @@
 		}
 	}
 
-	DRM_FREE( x );
-	DRM_FREE( y );
-	DRM_FREE( buffer );
+	DRM_FREE( x, xbuf_size );
+	DRM_FREE( y, ybuf_size );
+	DRM_FREE( buffer, buffer_size );
 
 	return 0;
 }
@@ -1146,7 +1149,7 @@
 {
 	drm_r128_private_t *dev_priv = dev->dev_private;
 	int count, *x, *y;
-	int i;
+	int i, xbuf_size, ybuf_size;
 	RING_LOCALS;
 	DRM_DEBUG( "%s\n", __FUNCTION__ );
 
@@ -1155,23 +1158,25 @@
 		count = dev_priv->depth_pitch;
 	}
 
-	x = DRM_MALLOC( count * sizeof(*x) );
+	xbuf_size = count * sizeof(*x);
+	ybuf_size = count * sizeof(*y);
+	x = DRM_MALLOC( xbuf_size );
 	if ( x == NULL ) {
 		return DRM_ERR(ENOMEM);
 	}
-	y = DRM_MALLOC( count * sizeof(*y) );
+	y = DRM_MALLOC( ybuf_size );
 	if ( y == NULL ) {
-		DRM_FREE( x );
+		DRM_FREE( x, xbuf_size );
 		return DRM_ERR(ENOMEM);
 	}
-	if ( DRM_COPY_FROM_USER( x, depth->x, count * sizeof(int) ) ) {
-		DRM_FREE( x );
-		DRM_FREE( y );
+	if ( DRM_COPY_FROM_USER( x, depth->x, xbuf_size ) ) {
+		DRM_FREE( x, xbuf_size );
+		DRM_FREE( y, ybuf_size );
 		return DRM_ERR(EFAULT);
 	}
-	if ( DRM_COPY_FROM_USER( y, depth->y, count * sizeof(int) ) ) {
-		DRM_FREE( x );
-		DRM_FREE( y );
+	if ( DRM_COPY_FROM_USER( y, depth->y, ybuf_size ) ) {
+		DRM_FREE( x, xbuf_size );
+		DRM_FREE( y, ybuf_size );
 		return DRM_ERR(EFAULT);
 	}
 
@@ -1199,8 +1204,8 @@
 		ADVANCE_RING();
 	}
 
-	DRM_FREE( x );
-	DRM_FREE( y );
+	DRM_FREE( x, xbuf_size );
+	DRM_FREE( y, ybuf_size );
 
 	return 0;
 }
@@ -1240,7 +1245,7 @@
 	drm_r128_clear_t clear;
 	DRM_DEBUG( "\n" );
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	DRM_COPY_FROM_USER_IOCTL( clear, (drm_r128_clear_t *) data,
 			     sizeof(clear) );
@@ -1266,7 +1271,7 @@
 	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	DRM_DEBUG( "%s\n", __FUNCTION__ );
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	RING_SPACE_TEST_WITH_RETURN( dev_priv );
 
@@ -1293,7 +1298,7 @@
 	drm_r128_buf_priv_t *buf_priv;
 	drm_r128_vertex_t vertex;
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	if ( !dev_priv ) {
 		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
@@ -1324,9 +1329,9 @@
 	buf = dma->buflist[vertex.idx];
 	buf_priv = buf->dev_private;
 
-	if ( buf->pid != DRM_CURRENTPID ) {
-		DRM_ERROR( "process %d using buffer owned by %d\n",
-			   DRM_CURRENTPID, buf->pid );
+	if ( buf->filp != filp ) {
+		DRM_ERROR( "process %d using buffer owned by %p\n",
+			   DRM_CURRENTPID, buf->filp );
 		return DRM_ERR(EINVAL);
 	}
 	if ( buf->pending ) {
@@ -1353,7 +1358,7 @@
 	drm_r128_indices_t elts;
 	int count;
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	if ( !dev_priv ) {
 		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
@@ -1383,9 +1388,9 @@
 	buf = dma->buflist[elts.idx];
 	buf_priv = buf->dev_private;
 
-	if ( buf->pid != DRM_CURRENTPID ) {
-		DRM_ERROR( "process %d using buffer owned by %d\n",
-			   DRM_CURRENTPID, buf->pid );
+	if ( buf->filp != filp ) {
+		DRM_ERROR( "process %d using buffer owned by %p\n",
+			   DRM_CURRENTPID, buf->filp );
 		return DRM_ERR(EINVAL);
 	}
 	if ( buf->pending ) {
@@ -1421,7 +1426,7 @@
 	drm_r128_private_t *dev_priv = dev->dev_private;
 	drm_r128_blit_t blit;
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	DRM_COPY_FROM_USER_IOCTL( blit, (drm_r128_blit_t *) data,
 			     sizeof(blit) );
@@ -1437,7 +1442,7 @@
 	RING_SPACE_TEST_WITH_RETURN( dev_priv );
 	VB_AGE_TEST_WITH_RETURN( dev_priv );
 
-	return r128_cce_dispatch_blit( dev, &blit );
+	return r128_cce_dispatch_blit( filp, dev, &blit );
 }
 
 int r128_cce_depth( DRM_IOCTL_ARGS )
@@ -1446,7 +1451,7 @@
 	drm_r128_private_t *dev_priv = dev->dev_private;
 	drm_r128_depth_t depth;
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	DRM_COPY_FROM_USER_IOCTL( depth, (drm_r128_depth_t *) data,
 			     sizeof(depth) );
@@ -1474,7 +1479,7 @@
 	drm_r128_stipple_t stipple;
 	u32 mask[32];
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	DRM_COPY_FROM_USER_IOCTL( stipple, (drm_r128_stipple_t *) data,
 			     sizeof(stipple) );
@@ -1502,7 +1507,7 @@
 	RING_LOCALS;
 #endif
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	if ( !dev_priv ) {
 		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
@@ -1525,9 +1530,9 @@
 	buf = dma->buflist[indirect.idx];
 	buf_priv = buf->dev_private;
 
-	if ( buf->pid != DRM_CURRENTPID ) {
-		DRM_ERROR( "process %d using buffer owned by %d\n",
-			   DRM_CURRENTPID, buf->pid );
+	if ( buf->filp != filp ) {
+		DRM_ERROR( "process %d using buffer owned by %p\n",
+			   DRM_CURRENTPID, buf->filp );
 		return DRM_ERR(EINVAL);
 	}
 	if ( buf->pending ) {
diff -urN linux-2.5.66-bk4/drivers/char/drm/radeon.h linux-2.5.66-bk5/drivers/char/drm/radeon.h
--- linux-2.5.66-bk4/drivers/char/drm/radeon.h	Mon Mar 24 14:01:24 2003
+++ linux-2.5.66-bk5/drivers/char/drm/radeon.h	Mon Mar 31 12:50:21 2003
@@ -51,7 +51,7 @@
 #define DRIVER_DATE		"20020828"
 
 #define DRIVER_MAJOR		1
-#define DRIVER_MINOR		7
+#define DRIVER_MINOR		8
 #define DRIVER_PATCHLEVEL	0
 
 /* Interface history:
@@ -77,6 +77,7 @@
  *       and R200_PP_CUBIC_OFFSET_F1_[0..5].
  *       Added packets R200_EMIT_PP_CUBIC_FACES_[0..5] and
  *       R200_EMIT_PP_CUBIC_OFFSETS_[0..5].  (brian)
+ * 1.8 - Remove need to call cleanup ioctls on last client exit (keith)
  */
 #define DRIVER_IOCTLS							     \
  [DRM_IOCTL_NR(DRM_IOCTL_DMA)]               = { radeon_cp_buffers,  1, 0 }, \
@@ -105,11 +106,6 @@
  [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_WAIT)]   = { radeon_irq_wait, 1, 0 },
 
 
-#define USE_IRQS 1
-#if USE_IRQS
-#define __HAVE_DMA_IRQ		1
-#define __HAVE_VBL_IRQ		1
-#define __HAVE_SHARED_IRQ       1
 
 /* When a client dies:
  *    - Check for and clean up flipped page state
@@ -117,35 +113,34 @@
  *
  * DRM infrastructure takes care of reclaiming dma buffers.
  */
-#define DRIVER_PRERELEASE() do {					\
+#define DRIVER_PRERELEASE() 						\
+do {									\
 	if ( dev->dev_private ) {					\
 		drm_radeon_private_t *dev_priv = dev->dev_private;	\
 		if ( dev_priv->page_flipping ) {			\
 			radeon_do_cleanup_pageflip( dev );		\
 		}							\
-		radeon_mem_release( dev_priv->agp_heap );		\
+                radeon_mem_release( filp, dev_priv->agp_heap );		\
+                radeon_mem_release( filp, dev_priv->fb_heap );		\
 	}								\
 } while (0)
 
-/* On unloading the module:
- *    - Free memory heap structure
- *    - Remove mappings made at startup and free dev_private.
+/* When the last client dies, shut down the CP and free dev->dev_priv.
  */
-#define DRIVER_PRETAKEDOWN() do {					\
-	if ( dev->dev_private ) {					\
-		drm_radeon_private_t *dev_priv = dev->dev_private;	\
-		radeon_mem_takedown( &(dev_priv->agp_heap) );		\
-		radeon_do_cleanup_cp( dev );				\
-	}								\
+/* #define __HAVE_RELEASE 1 */
+#define DRIVER_PRETAKEDOWN()			\
+do {						\
+    radeon_do_release( dev );			\
 } while (0)
 
-#else
-#define __HAVE_DMA_IRQ 0
-#endif
+
 
 /* DMA customization:
  */
 #define __HAVE_DMA		1
+#define __HAVE_DMA_IRQ		1
+#define __HAVE_VBL_IRQ		1
+#define __HAVE_SHARED_IRQ       1
 
 
 /* Buffer customization:
diff -urN linux-2.5.66-bk4/drivers/char/drm/radeon_cp.c linux-2.5.66-bk5/drivers/char/drm/radeon_cp.c
--- linux-2.5.66-bk4/drivers/char/drm/radeon_cp.c	Mon Mar 24 14:00:08 2003
+++ linux-2.5.66-bk5/drivers/char/drm/radeon_cp.c	Mon Mar 31 12:50:21 2003
@@ -926,11 +926,11 @@
 	RADEON_WRITE( RADEON_SCRATCH_UMSK, 0x7 );
 
 	/* Writeback doesn't seem to work everywhere, test it first */
-	DRM_WRITE32( &dev_priv->scratch[1], 0 );
+	DRM_WRITE32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(1), 0 );
 	RADEON_WRITE( RADEON_SCRATCH_REG1, 0xdeadbeef );
 
 	for ( tmp = 0 ; tmp < dev_priv->usec_timeout ; tmp++ ) {
-		if ( DRM_READ32( &dev_priv->scratch[1] ) == 0xdeadbeef )
+		if ( DRM_READ32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(1) ) == 0xdeadbeef )
 			break;
 		DRM_UDELAY( 1 );
 	}
@@ -1217,6 +1217,7 @@
 		(dev_priv->ring.size / sizeof(u32)) - 1;
 
 	dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK;
+	dev_priv->ring.ring_rptr = dev_priv->ring_rptr;
 
 #if __REALLY_HAVE_SG
 	if ( dev_priv->is_pci ) {
@@ -1322,7 +1323,7 @@
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	DRM_DEBUG( "\n" );
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	if ( dev_priv->cp_running ) {
 		DRM_DEBUG( "%s while CP running\n", __FUNCTION__ );
@@ -1350,10 +1351,13 @@
 	int ret;
 	DRM_DEBUG( "\n" );
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	DRM_COPY_FROM_USER_IOCTL( stop, (drm_radeon_cp_stop_t *)data, sizeof(stop) );
 
+	if (!dev_priv->cp_running)
+		return 0;
+
 	/* Flush any pending CP commands.  This ensures any outstanding
 	 * commands are exectuted by the engine before we turn it off.
 	 */
@@ -1381,6 +1385,39 @@
 	return 0;
 }
 
+
+void radeon_do_release( drm_device_t *dev )
+{
+	drm_radeon_private_t *dev_priv = dev->dev_private;
+	int ret;
+
+	if (dev_priv) {
+		if (dev_priv->cp_running) {
+			/* Stop the cp */
+			while ((ret = radeon_do_cp_idle( dev_priv )) != 0) {
+				DRM_DEBUG("radeon_do_cp_idle %d\n", ret);
+#ifdef __linux__
+				schedule();
+#else
+				tsleep(&ret, PZERO, "rdnrel", 1);
+#endif
+			}
+			radeon_do_cp_stop( dev_priv );
+			radeon_do_engine_reset( dev );
+		}
+
+		/* Disable *all* interrupts */
+		RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 );
+
+		/* Free memory heap structures */
+		radeon_mem_takedown( &(dev_priv->agp_heap) );
+		radeon_mem_takedown( &(dev_priv->fb_heap) );
+
+		/* deallocate kernel resources */
+		radeon_do_cleanup_cp( dev );
+	}
+}
+
 /* Just reset the CP ring.  Called as part of an X Server engine reset.
  */
 int radeon_cp_reset( DRM_IOCTL_ARGS )
@@ -1389,7 +1426,7 @@
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	DRM_DEBUG( "\n" );
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	if ( !dev_priv ) {
 		DRM_DEBUG( "%s called before init done\n", __FUNCTION__ );
@@ -1410,10 +1447,7 @@
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	DRM_DEBUG( "\n" );
 
-	LOCK_TEST_WITH_RETURN( dev );
-
-/* 	if (dev->irq)  */
-/* 		radeon_emit_and_wait_irq( dev ); */
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	return radeon_do_cp_idle( dev_priv );
 }
@@ -1423,7 +1457,7 @@
 	DRM_DEVICE;
 	DRM_DEBUG( "\n" );
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	return radeon_do_engine_reset( dev );
 }
@@ -1482,7 +1516,7 @@
 		for ( i = start ; i < dma->buf_count ; i++ ) {
 			buf = dma->buflist[i];
 			buf_priv = buf->dev_private;
-			if ( buf->pid == 0 || (buf->pending && 
+			if ( buf->filp == 0 || (buf->pending && 
 					       buf_priv->age <= done_age) ) {
 				dev_priv->stats.requested_bufs++;
 				buf->pending = 0;
@@ -1509,7 +1543,7 @@
 	drm_buf_t *buf;
 	int i, t;
 	int start;
-	u32 done_age = DRM_READ32(&dev_priv->scratch[1]);
+	u32 done_age = DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1));
 
 	if ( ++dev_priv->last_buf >= dma->buf_count )
 		dev_priv->last_buf = 0;
@@ -1521,7 +1555,7 @@
 		for ( i = start ; i < dma->buf_count ; i++ ) {
 			buf = dma->buflist[i];
 			buf_priv = buf->dev_private;
-			if ( buf->pid == 0 || (buf->pending && 
+			if ( buf->filp == 0 || (buf->pending && 
 					       buf_priv->age <= done_age) ) {
 				dev_priv->stats.requested_bufs++;
 				buf->pending = 0;
@@ -1586,7 +1620,7 @@
 	return DRM_ERR(EBUSY);
 }
 
-static int radeon_cp_get_buffers( drm_device_t *dev, drm_dma_t *d )
+static int radeon_cp_get_buffers( DRMFILE filp, drm_device_t *dev, drm_dma_t *d )
 {
 	int i;
 	drm_buf_t *buf;
@@ -1595,7 +1629,7 @@
 		buf = radeon_freelist_get( dev );
 		if ( !buf ) return DRM_ERR(EBUSY); /* NOTE: broken client */
 
-		buf->pid = DRM_CURRENTPID;
+		buf->filp = filp;
 
 		if ( DRM_COPY_TO_USER( &d->request_indices[i], &buf->idx,
 				   sizeof(buf->idx) ) )
@@ -1616,7 +1650,7 @@
 	int ret = 0;
 	drm_dma_t d;
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	DRM_COPY_FROM_USER_IOCTL( d, (drm_dma_t *)data, sizeof(d) );
 
@@ -1639,7 +1673,7 @@
 	d.granted_count = 0;
 
 	if ( d.request_count ) {
-		ret = radeon_cp_get_buffers( dev, &d );
+		ret = radeon_cp_get_buffers( filp, dev, &d );
 	}
 
 	DRM_COPY_TO_USER_IOCTL( (drm_dma_t *)data, d, sizeof(d) );
diff -urN linux-2.5.66-bk4/drivers/char/drm/radeon_drm.h linux-2.5.66-bk5/drivers/char/drm/radeon_drm.h
--- linux-2.5.66-bk4/drivers/char/drm/radeon_drm.h	Mon Mar 24 14:00:54 2003
+++ linux-2.5.66-bk5/drivers/char/drm/radeon_drm.h	Mon Mar 31 12:50:21 2003
@@ -382,7 +382,7 @@
 #define DRM_IOCTL_RADEON_STIPPLE    DRM_IOW( 0x4c, drm_radeon_stipple_t)
 #define DRM_IOCTL_RADEON_INDIRECT   DRM_IOWR(0x4d, drm_radeon_indirect_t)
 #define DRM_IOCTL_RADEON_TEXTURE    DRM_IOWR(0x4e, drm_radeon_texture_t)
-#define DRM_IOCTL_RADEON_VERTEX2    DRM_IOW( 0x4f, drm_radeon_vertex_t)
+#define DRM_IOCTL_RADEON_VERTEX2    DRM_IOW( 0x4f, drm_radeon_vertex2_t)
 #define DRM_IOCTL_RADEON_CMDBUF     DRM_IOW( 0x50, drm_radeon_cmd_buffer_t)
 #define DRM_IOCTL_RADEON_GETPARAM   DRM_IOWR(0x51, drm_radeon_getparam_t)
 #define DRM_IOCTL_RADEON_FLIP	    DRM_IO(  0x52)
@@ -396,7 +396,7 @@
 	enum {
 		RADEON_INIT_CP    = 0x01,
 		RADEON_CLEANUP_CP = 0x02,
-		RADEON_INIT_R200_CP = 0x03,	
+		RADEON_INIT_R200_CP = 0x03
 	} func;
 	unsigned long sarea_priv_offset;
 	int is_pci;
diff -urN linux-2.5.66-bk4/drivers/char/drm/radeon_drv.h linux-2.5.66-bk5/drivers/char/drm/radeon_drv.h
--- linux-2.5.66-bk4/drivers/char/drm/radeon_drv.h	Mon Mar 24 14:00:39 2003
+++ linux-2.5.66-bk5/drivers/char/drm/radeon_drv.h	Mon Mar 31 12:50:21 2003
@@ -31,8 +31,8 @@
 #ifndef __RADEON_DRV_H__
 #define __RADEON_DRV_H__
 
-#define GET_RING_HEAD(ring)		DRM_READ32(  (volatile u32 *) (ring)->head )
-#define SET_RING_HEAD(ring,val)		DRM_WRITE32( (volatile u32 *) (ring)->head , (val))
+#define GET_RING_HEAD(ring)		DRM_READ32(  (ring)->ring_rptr, 0 ) /* (ring)->head */
+#define SET_RING_HEAD(ring,val)		DRM_WRITE32( (ring)->ring_rptr, 0, (val) ) /* (ring)->head */
 
 typedef struct drm_radeon_freelist {
    	unsigned int age;
@@ -53,6 +53,7 @@
 	int space;
 
 	int high_mark;
+	drm_local_map_t *ring_rptr;
 } drm_radeon_ring_buffer_t;
 
 typedef struct drm_radeon_depth_clear_t {
@@ -67,7 +68,7 @@
 	struct mem_block *prev;
 	int start;
 	int size;
-	int pid;		/* 0: free, -1: heap, other: real pids */
+	DRMFILE filp;		/* 0: free, -1: heap, other: real files */
 };
 
 typedef struct drm_radeon_private {
@@ -126,13 +127,13 @@
 
 	drm_radeon_depth_clear_t depth_clear;
 
-	drm_map_t *sarea;
-	drm_map_t *fb;
-	drm_map_t *mmio;
-	drm_map_t *cp_ring;
-	drm_map_t *ring_rptr;
-	drm_map_t *buffers;
-	drm_map_t *agp_textures;
+	drm_local_map_t *sarea;
+	drm_local_map_t *fb;
+	drm_local_map_t *mmio;
+	drm_local_map_t *cp_ring;
+	drm_local_map_t *ring_rptr;
+	drm_local_map_t *buffers;
+	drm_local_map_t *agp_textures;
 
 	struct mem_block *agp_heap;
 	struct mem_block *fb_heap;
@@ -183,7 +184,7 @@
 extern int radeon_mem_free( DRM_IOCTL_ARGS );
 extern int radeon_mem_init_heap( DRM_IOCTL_ARGS );
 extern void radeon_mem_takedown( struct mem_block **heap );
-extern void radeon_mem_release( struct mem_block *heap );
+extern void radeon_mem_release( DRMFILE filp, struct mem_block *heap );
 
 				/* radeon_irq.c */
 extern int radeon_irq_emit( DRM_IOCTL_ARGS );
@@ -193,6 +194,7 @@
 extern int radeon_wait_irq(drm_device_t *dev, int swi_nr);
 extern int radeon_emit_irq(drm_device_t *dev);
 
+extern void radeon_do_release(drm_device_t *dev);
 
 /* Flags for stats.boxes
  */
@@ -266,8 +268,10 @@
 #define RADEON_SCRATCH_UMSK		0x0770
 #define RADEON_SCRATCH_ADDR		0x0774
 
+#define RADEON_SCRATCHOFF( x )		(RADEON_SCRATCH_REG_OFFSET + 4*(x))
+
 #define GET_SCRATCH( x )	(dev_priv->writeback_works			\
-				? DRM_READ32( &dev_priv->scratch[(x)] )		\
+				? DRM_READ32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(x) ) \
 				: RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x) ) )
 
 
@@ -686,15 +690,10 @@
 
 #define RADEON_RING_HIGH_MARK		128
 
-
-#define RADEON_BASE(reg)	((unsigned long)(dev_priv->mmio->handle))
-#define RADEON_ADDR(reg)	(RADEON_BASE( reg ) + reg)
-
-#define RADEON_READ(reg)	DRM_READ32(  (volatile u32 *) RADEON_ADDR(reg) )
-#define RADEON_WRITE(reg,val)	DRM_WRITE32( (volatile u32 *) RADEON_ADDR(reg), (val) )
-
-#define RADEON_READ8(reg)	DRM_READ8(  (volatile u8 *) RADEON_ADDR(reg) )
-#define RADEON_WRITE8(reg,val)	DRM_WRITE8( (volatile u8 *) RADEON_ADDR(reg), (val) )
+#define RADEON_READ(reg)	DRM_READ32(  dev_priv->mmio, (reg) )
+#define RADEON_WRITE(reg,val)	DRM_WRITE32( dev_priv->mmio, (reg), (val) )
+#define RADEON_READ8(reg)	DRM_READ8(  dev_priv->mmio, (reg) )
+#define RADEON_WRITE8(reg,val)	DRM_WRITE8( dev_priv->mmio, (reg), (val) )
 
 #define RADEON_WRITE_PLL( addr, val )					\
 do {									\
@@ -771,16 +770,6 @@
  * Misc helper macros
  */
 
-#define LOCK_TEST_WITH_RETURN( dev )					\
-do {									\
-	if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) ||		\
-	     dev->lock.pid != DRM_CURRENTPID ) {			\
-		DRM_ERROR( "%s called without lock held\n", __FUNCTION__ );	\
-		return DRM_ERR(EINVAL);				\
-	}								\
-} while (0)
-
-
 /* Perfbox functionality only.  
  */
 #define RING_SPACE_TEST_WITH_RETURN( dev_priv )				\
@@ -823,13 +812,6 @@
  * Ring control
  */
 
-#if defined(__powerpc__)
-#define radeon_flush_write_combine()	(void) GET_RING_HEAD( &dev_priv->ring )
-#else
-#define radeon_flush_write_combine()	DRM_WRITEMEMORYBARRIER()
-#endif
-
-
 #define RADEON_VERBOSE	0
 
 #define RING_LOCALS	int write, _nr; unsigned int mask; u32 *ring;
@@ -863,8 +845,13 @@
 		dev_priv->ring.tail = write;				\
 } while (0)
 
-#define COMMIT_RING() do {					    \
-	RADEON_WRITE( RADEON_CP_RB_WPTR, dev_priv->ring.tail );		    \
+#define COMMIT_RING() do {						\
+	/* Flush writes to ring */					\
+	DRM_READMEMORYBARRIER(dev_priv->mmio);					\
+	GET_RING_HEAD( &dev_priv->ring );				\
+	RADEON_WRITE( RADEON_CP_RB_WPTR, dev_priv->ring.tail );		\
+	/* read from PCI bus to ensure correct posting */		\
+	RADEON_READ( RADEON_CP_RB_RPTR );				\
 } while (0)
 
 #define OUT_RING( x ) do {						\
diff -urN linux-2.5.66-bk4/drivers/char/drm/radeon_irq.c linux-2.5.66-bk5/drivers/char/drm/radeon_irq.c
--- linux-2.5.66-bk4/drivers/char/drm/radeon_irq.c	Mon Mar 24 14:01:43 2003
+++ linux-2.5.66-bk5/drivers/char/drm/radeon_irq.c	Mon Mar 31 12:50:21 2003
@@ -61,7 +61,11 @@
 	   (drm_radeon_private_t *)dev->dev_private;
    	u32 stat;
 
-	stat = RADEON_READ(RADEON_GEN_INT_STATUS);
+	/* Only consider the bits we're interested in - others could be used
+	 * outside the DRM
+	 */
+	stat = RADEON_READ(RADEON_GEN_INT_STATUS)
+	     & (RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT);
 	if (!stat)
 		return;
 
@@ -77,15 +81,14 @@
 		DRM(vbl_send_signals)( dev );
 	}
 
-	/* Acknowledge all the bits in GEN_INT_STATUS -- seem to get
-	 * more than we asked for...
-	 */
+	/* Acknowledge interrupts we handle */
 	RADEON_WRITE(RADEON_GEN_INT_STATUS, stat);
 }
 
 static __inline__ void radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv)
 {
-	u32 tmp = RADEON_READ( RADEON_GEN_INT_STATUS );
+	u32 tmp = RADEON_READ( RADEON_GEN_INT_STATUS )
+		& (RADEON_SW_INT_TEST_ACK | RADEON_CRTC_VBLANK_STAT);
 	if (tmp)
 		RADEON_WRITE( RADEON_GEN_INT_STATUS, tmp );
 }
@@ -176,7 +179,7 @@
 	drm_radeon_irq_emit_t emit;
 	int result;
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	if ( !dev_priv ) {
 		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
diff -urN linux-2.5.66-bk4/drivers/char/drm/radeon_mem.c linux-2.5.66-bk5/drivers/char/drm/radeon_mem.c
--- linux-2.5.66-bk4/drivers/char/drm/radeon_mem.c	Mon Mar 24 14:01:23 2003
+++ linux-2.5.66-bk5/drivers/char/drm/radeon_mem.c	Mon Mar 31 12:50:21 2003
@@ -40,7 +40,7 @@
  */
 
 static struct mem_block *split_block(struct mem_block *p, int start, int size,
-				     int pid )
+				     DRMFILE filp )
 {
 	/* Maybe cut off the start of an existing block */
 	if (start > p->start) {
@@ -49,7 +49,7 @@
 			goto out;
 		newblock->start = start;
 		newblock->size = p->size - (start - p->start);
-		newblock->pid = 0;
+		newblock->filp = 0;
 		newblock->next = p->next;
 		newblock->prev = p;
 		p->next->prev = newblock;
@@ -65,7 +65,7 @@
 			goto out;
 		newblock->start = start + size;
 		newblock->size = p->size - size;
-		newblock->pid = 0;
+		newblock->filp = 0;
 		newblock->next = p->next;
 		newblock->prev = p;
 		p->next->prev = newblock;
@@ -75,20 +75,20 @@
 
  out:
 	/* Our block is in the middle */
-	p->pid = pid;
+	p->filp = filp;
 	return p;
 }
 
 static struct mem_block *alloc_block( struct mem_block *heap, int size, 
-				      int align2, int pid )
+				      int align2, DRMFILE filp )
 {
 	struct mem_block *p;
 	int mask = (1 << align2)-1;
 
 	for (p = heap->next ; p != heap ; p = p->next) {
 		int start = (p->start + mask) & ~mask;
-		if (p->pid == 0 && start + size <= p->start + p->size)
-			return split_block( p, start, size, pid );
+		if (p->filp == 0 && start + size <= p->start + p->size)
+			return split_block( p, start, size, filp );
 	}
 
 	return NULL;
@@ -108,25 +108,25 @@
 
 static void free_block( struct mem_block *p )
 {
-	p->pid = 0;
+	p->filp = 0;
 
-	/* Assumes a single contiguous range.  Needs a special pid in
+	/* Assumes a single contiguous range.  Needs a special filp in
 	 * 'heap' to stop it being subsumed.
 	 */
-	if (p->next->pid == 0) {
+	if (p->next->filp == 0) {
 		struct mem_block *q = p->next;
 		p->size += q->size;
 		p->next = q->next;
 		p->next->prev = p;
-		DRM_FREE(q);
+		DRM_FREE(q, sizeof(*q));
 	}
 
-	if (p->prev->pid == 0) {
+	if (p->prev->filp == 0) {
 		struct mem_block *q = p->prev;
 		q->size += p->size;
 		q->next = p->next;
 		q->next->prev = q;
-		DRM_FREE(p);
+		DRM_FREE(p, sizeof(*q));
 	}
 }
 
@@ -141,47 +141,46 @@
 	
 	*heap = DRM_MALLOC(sizeof(**heap));
 	if (!*heap) {
-		DRM_FREE( blocks );
+		DRM_FREE( blocks, sizeof(*blocks) );
 		return -ENOMEM;
 	}
 
 	blocks->start = start;
 	blocks->size = size;
-	blocks->pid = 0;
+	blocks->filp = 0;
 	blocks->next = blocks->prev = *heap;
 
 	memset( *heap, 0, sizeof(**heap) );
-	(*heap)->pid = -1;
+	(*heap)->filp = (DRMFILE) -1;
 	(*heap)->next = (*heap)->prev = blocks;
 	return 0;
 }
 
 
-/* Free all blocks associated with the releasing pid.
+/* Free all blocks associated with the releasing file.
  */
-void radeon_mem_release( struct mem_block *heap )
+void radeon_mem_release( DRMFILE filp, struct mem_block *heap )
 {
-	int pid = DRM_CURRENTPID;
 	struct mem_block *p;
 
 	if (!heap || !heap->next)
 		return;
 
 	for (p = heap->next ; p != heap ; p = p->next) {
-		if (p->pid == pid) 
-			p->pid = 0;
+		if (p->filp == filp) 
+			p->filp = 0;
 	}
 
-	/* Assumes a single contiguous range.  Needs a special pid in
+	/* Assumes a single contiguous range.  Needs a special filp in
 	 * 'heap' to stop it being subsumed.
 	 */
 	for (p = heap->next ; p != heap ; p = p->next) {
-		while (p->pid == 0 && p->next->pid == 0) {
+		while (p->filp == 0 && p->next->filp == 0) {
 			struct mem_block *q = p->next;
 			p->size += q->size;
 			p->next = q->next;
 			p->next->prev = p;
-			DRM_FREE(q);
+			DRM_FREE(q, sizeof(*q));
 		}
 	}
 }
@@ -198,10 +197,10 @@
 	for (p = (*heap)->next ; p != *heap ; ) {
 		struct mem_block *q = p;
 		p = p->next;
-		DRM_FREE(q);
+		DRM_FREE(q, sizeof(*q));
 	}
 
-	DRM_FREE( *heap );
+	DRM_FREE( *heap, sizeof(**heap) );
 	*heap = 0;
 }
 
@@ -248,7 +247,7 @@
 		alloc.alignment = 12;
 
 	block = alloc_block( *heap, alloc.size, alloc.alignment,
-			     DRM_CURRENTPID );
+			     filp );
 
 	if (!block) 
 		return DRM_ERR(ENOMEM);
@@ -287,7 +286,7 @@
 	if (!block)
 		return DRM_ERR(EFAULT);
 
-	if (block->pid != DRM_CURRENTPID)
+	if (block->filp != filp)
 		return DRM_ERR(EPERM);
 
 	free_block( block );	
diff -urN linux-2.5.66-bk4/drivers/char/drm/radeon_state.c linux-2.5.66-bk5/drivers/char/drm/radeon_state.c
--- linux-2.5.66-bk4/drivers/char/drm/radeon_state.c	Mon Mar 24 14:01:22 2003
+++ linux-2.5.66-bk5/drivers/char/drm/radeon_state.c	Mon Mar 31 12:50:21 2003
@@ -1063,7 +1063,8 @@
 
 #define RADEON_MAX_TEXTURE_SIZE (RADEON_BUFFER_SIZE - 8 * sizeof(u32))
 
-static int radeon_cp_dispatch_texture( drm_device_t *dev,
+static int radeon_cp_dispatch_texture( DRMFILE filp,
+				       drm_device_t *dev,
 				       drm_radeon_texture_t *tex,
 				       drm_radeon_tex_image_t *image )
 {
@@ -1073,7 +1074,7 @@
 	u32 *buffer;
 	const u8 *data;
 	int size, dwords, tex_width, blit_width;
-	u32 y, height;
+	u32 height;
 	int i;
 	RING_LOCALS;
 
@@ -1138,10 +1139,9 @@
 			   tex->offset >> 10, tex->pitch, tex->format,
 			   image->x, image->y, image->width, image->height );
 
-		/* Make a copy of the parameters in case we have to
+		/* Make a copy of some parameters in case we have to
 		 * update them for a multi-pass texture blit.
 		 */
-		y = image->y;
 		height = image->height;
 		data = (const u8 *)image->data;
 		
@@ -1156,11 +1156,6 @@
 			return 0;
 		}
 
-		/* Update the input parameters for next time */
-		image->y += height;
-		image->height -= height;
-		image->data += size;
-
 		buf = radeon_freelist_get( dev );
 		if ( 0 && !buf ) {
 			radeon_do_cp_idle( dev_priv );
@@ -1190,7 +1185,7 @@
 		buffer[2] = (tex->pitch << 22) | (tex->offset >> 10);
 		buffer[3] = 0xffffffff;
 		buffer[4] = 0xffffffff;
-		buffer[5] = (y << 16) | image->x;
+		buffer[5] = (image->y << 16) | image->x;
 		buffer[6] = (height << 16) | image->width;
 		buffer[7] = dwords;
 		buffer += 8;
@@ -1222,11 +1217,15 @@
 			}
 		}
 
-		buf->pid = DRM_CURRENTPID;
+		buf->filp = filp;
 		buf->used = (dwords + 8) * sizeof(u32);
 		radeon_cp_dispatch_indirect( dev, buf, 0, buf->used );
 		radeon_cp_discard_buffer( dev, buf );
 
+		/* Update the input parameters for next time */
+		image->y += height;
+		image->height -= height;
+		(const u8 *)image->data += size;
 	} while (image->height > 0);
 
 	/* Flush the pixel cache after the blit completes.  This ensures
@@ -1275,7 +1274,7 @@
 	drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
 	DRM_DEBUG( "\n" );
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	DRM_COPY_FROM_USER_IOCTL( clear, (drm_radeon_clear_t *)data,
 			     sizeof(clear) );
@@ -1344,7 +1343,7 @@
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	DRM_DEBUG( "\n" );
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	RING_SPACE_TEST_WITH_RETURN( dev_priv );
 
@@ -1364,7 +1363,7 @@
 	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	DRM_DEBUG( "\n" );
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	RING_SPACE_TEST_WITH_RETURN( dev_priv );
 
@@ -1388,7 +1387,7 @@
 	drm_radeon_vertex_t vertex;
 	drm_radeon_tcl_prim_t prim;
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	if ( !dev_priv ) {
 		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
@@ -1418,9 +1417,9 @@
 
 	buf = dma->buflist[vertex.idx];
 
-	if ( buf->pid != DRM_CURRENTPID ) {
-		DRM_ERROR( "process %d using buffer owned by %d\n",
-			   DRM_CURRENTPID, buf->pid );
+	if ( buf->filp != filp ) {
+		DRM_ERROR( "process %d using buffer owned by %p\n",
+			   DRM_CURRENTPID, buf->filp );
 		return DRM_ERR(EINVAL);
 	}
 	if ( buf->pending ) {
@@ -1475,7 +1474,7 @@
 	drm_radeon_tcl_prim_t prim;
 	int count;
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	if ( !dev_priv ) {
 		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
@@ -1505,9 +1504,9 @@
 
 	buf = dma->buflist[elts.idx];
 
-	if ( buf->pid != DRM_CURRENTPID ) {
-		DRM_ERROR( "process %d using buffer owned by %d\n",
-			   DRM_CURRENTPID, buf->pid );
+	if ( buf->filp != filp ) {
+		DRM_ERROR( "process %d using buffer owned by %p\n",
+			   DRM_CURRENTPID, buf->filp );
 		return DRM_ERR(EINVAL);
 	}
 	if ( buf->pending ) {
@@ -1570,7 +1569,7 @@
 	drm_radeon_tex_image_t image;
 	int ret;
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	DRM_COPY_FROM_USER_IOCTL( tex, (drm_radeon_texture_t *)data, sizeof(tex) );
 
@@ -1587,7 +1586,7 @@
 	RING_SPACE_TEST_WITH_RETURN( dev_priv );
 	VB_AGE_TEST_WITH_RETURN( dev_priv );
 
-	ret = radeon_cp_dispatch_texture( dev, &tex, &image );
+	ret = radeon_cp_dispatch_texture( filp, dev, &tex, &image );
 
 	COMMIT_RING();
 	return ret;
@@ -1600,7 +1599,7 @@
 	drm_radeon_stipple_t stipple;
 	u32 mask[32];
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	DRM_COPY_FROM_USER_IOCTL( stipple, (drm_radeon_stipple_t *)data,
 			     sizeof(stipple) );
@@ -1625,7 +1624,7 @@
 	drm_radeon_indirect_t indirect;
 	RING_LOCALS;
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	if ( !dev_priv ) {
 		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
@@ -1647,9 +1646,9 @@
 
 	buf = dma->buflist[indirect.idx];
 
-	if ( buf->pid != DRM_CURRENTPID ) {
-		DRM_ERROR( "process %d using buffer owned by %d\n",
-			   DRM_CURRENTPID, buf->pid );
+	if ( buf->filp != filp ) {
+		DRM_ERROR( "process %d using buffer owned by %p\n",
+			   DRM_CURRENTPID, buf->filp );
 		return DRM_ERR(EINVAL);
 	}
 	if ( buf->pending ) {
@@ -1702,7 +1701,7 @@
 	int i;
 	unsigned char laststate;
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	if ( !dev_priv ) {
 		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
@@ -1727,9 +1726,9 @@
 
 	buf = dma->buflist[vertex.idx];
 
-	if ( buf->pid != DRM_CURRENTPID ) {
-		DRM_ERROR( "process %d using buffer owned by %d\n",
-			   DRM_CURRENTPID, buf->pid );
+	if ( buf->filp != filp ) {
+		DRM_ERROR( "process %d using buffer owned by %p\n",
+			   DRM_CURRENTPID, buf->filp );
 		return DRM_ERR(EINVAL);
 	}
 
@@ -2029,7 +2028,7 @@
 	drm_radeon_cmd_header_t header;
 	int orig_nbox;
 
-	LOCK_TEST_WITH_RETURN( dev );
+	LOCK_TEST_WITH_RETURN( dev, filp );
 
 	if ( !dev_priv ) {
 		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
@@ -2098,8 +2097,9 @@
 			}
 
 			buf = dma->buflist[idx];
-			if ( buf->pid != DRM_CURRENTPID || buf->pending ) {
-				DRM_ERROR( "bad buffer\n" );
+			if ( buf->filp != filp || buf->pending ) {
+				DRM_ERROR( "bad buffer %p %p %d\n",
+					   buf->filp, filp, buf->pending);
 				return DRM_ERR(EINVAL);
 			}
 
diff -urN linux-2.5.66-bk4/drivers/char/drm/sis.h linux-2.5.66-bk5/drivers/char/drm/sis.h
--- linux-2.5.66-bk4/drivers/char/drm/sis.h	Mon Mar 24 14:01:46 2003
+++ linux-2.5.66-bk5/drivers/char/drm/sis.h	Mon Mar 31 12:50:21 2003
@@ -24,7 +24,7 @@
  * DEALINGS IN THE SOFTWARE.
  * 
  */
-/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/sis.h,v 1.2 2001/12/19 21:25:59 dawes Exp $ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/sis.h,v 1.3 2002/10/30 12:52:38 alanh Exp $ */
 
 #ifndef __SIS_H__
 #define __SIS_H__
diff -urN linux-2.5.66-bk4/drivers/char/drm/sis_mm.c linux-2.5.66-bk5/drivers/char/drm/sis_mm.c
--- linux-2.5.66-bk4/drivers/char/drm/sis_mm.c	Mon Mar 24 14:00:55 2003
+++ linux-2.5.66-bk5/drivers/char/drm/sis_mm.c	Mon Mar 31 12:50:21 2003
@@ -182,10 +182,10 @@
   if(block){
     /* TODO */
     agp.offset = block->ofs;
-    agp.free = (unsigned int)block;
+    agp.free = (unsigned long)block;
     if(!add_alloc_set(agp.context, AGP_TYPE, agp.free)){
       DRM_DEBUG("adding to allocation set fails\n");
-      mmFreeMem((PMemBlock)agp.free);
+      mmFreeMem((PMemBlock)(unsigned long)agp.free);
       retval = -1;
     }
   }
@@ -218,7 +218,7 @@
     return -1;
   }
 
-  mmFreeMem((PMemBlock)agp.free);
+  mmFreeMem((PMemBlock)(unsigned long)agp.free);
   if(!del_alloc_set(agp.context, AGP_TYPE, agp.free))
     retval = -1;
 
@@ -288,7 +288,7 @@
 	  retval = setFirst(set, &item);
 	  while(retval){
    	    DRM_DEBUG("free agp memory 0x%x\n", item);
-	    mmFreeMem((PMemBlock)item);
+	    mmFreeMem((PMemBlock)(unsigned long)item);
 	    retval = setNext(set, &item);
 	  }
 	  setDestroy(set);
diff -urN linux-2.5.66-bk4/drivers/char/hw_random.c linux-2.5.66-bk5/drivers/char/hw_random.c
--- linux-2.5.66-bk4/drivers/char/hw_random.c	Mon Mar 24 14:00:18 2003
+++ linux-2.5.66-bk5/drivers/char/hw_random.c	Mon Mar 31 12:50:21 2003
@@ -151,6 +151,7 @@
  */
 static struct pci_device_id rng_pci_tbl[] __initdata = {
 	{ 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd },
+	{ 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd },
 
 	{ 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
 	{ 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
diff -urN linux-2.5.66-bk4/drivers/char/tty_io.c linux-2.5.66-bk5/drivers/char/tty_io.c
--- linux-2.5.66-bk4/drivers/char/tty_io.c	Mon Mar 24 14:00:49 2003
+++ linux-2.5.66-bk5/drivers/char/tty_io.c	Mon Mar 31 12:50:21 2003
@@ -2143,31 +2143,16 @@
  */
 int tty_unregister_driver(struct tty_driver *driver)
 {
-	int	retval;
-	struct tty_driver *p;
-	int	i, found = 0;
+	int retval, i;
 	struct termios *tp;
-	const char *othername = NULL;
-	
+
 	if (*driver->refcount)
 		return -EBUSY;
 
-	list_for_each_entry(p, &tty_drivers, tty_drivers) {
-		if (p == driver)
-			found++;
-		else if (p->major == driver->major)
-			othername = p->name;
-	}
-	
-	if (!found)
-		return -ENOENT;
-
-	if (othername == NULL) {
-		retval = unregister_chrdev(driver->major, driver->name);
-		if (retval)
-			return retval;
-	} else
-		register_chrdev(driver->major, othername, &tty_fops);
+	retval = unregister_chrdev_region(driver->major, driver->minor_start,
+					  driver->num, driver->name);
+	if (retval)
+		return retval;
 
 	list_del(&driver->tty_drivers);
 
diff -urN linux-2.5.66-bk4/drivers/net/3c509.c linux-2.5.66-bk5/drivers/net/3c509.c
--- linux-2.5.66-bk4/drivers/net/3c509.c	Mon Mar 24 13:59:55 2003
+++ linux-2.5.66-bk5/drivers/net/3c509.c	Mon Mar 31 12:50:22 2003
@@ -208,7 +208,9 @@
 static int el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data);
 #endif
 /* generic device remove for all device types */
+#if defined(CONFIG_EISA) || defined(CONFIG_MCA)
 static int el3_device_remove (struct device *device);
+#endif
 
 #ifdef CONFIG_EISA
 struct eisa_device_id el3_eisa_ids[] = {
diff -urN linux-2.5.66-bk4/drivers/net/bonding.c linux-2.5.66-bk5/drivers/net/bonding.c
--- linux-2.5.66-bk4/drivers/net/bonding.c	Mon Mar 24 14:01:27 2003
+++ linux-2.5.66-bk5/drivers/net/bonding.c	Mon Mar 31 12:50:22 2003
@@ -258,10 +258,47 @@
  *     - correct ifr_data reference.  Update ifr_data reference
  *       to mii_ioctl_data struct values to avoid confusion.
  *
- *
  *  2002/11/22 - Bert Barbe <bert.barbe at oracle dot com>
  *      - Add support for multiple arp_ip_target
  *
+ *  2002/12/13 - Jay Vosburgh <fubar at us dot ibm dot com>
+ *	- Changed to allow text strings for mode and multicast, e.g.,
+ *	  insmod bonding mode=active-backup.  The numbers still work.
+ *	  One change: an invalid choice will cause module load failure,
+ *	  rather than the previous behavior of just picking one.
+ *	- Minor cleanups; got rid of dup ctype stuff, atoi function
+ * 
+ * 2003/02/07 - Jay Vosburgh <fubar at us dot ibm dot com>
+ *	- Added use_carrier module parameter that causes miimon to
+ *	  use netif_carrier_ok() test instead of MII/ETHTOOL ioctls.
+ *	- Minor cleanups; consolidated ioctl calls to one function.
+ *
+ * 2003/02/07 - Tony Cureington <tony.cureington * hp_com>
+ *	- Fix bond_mii_monitor() logic error that could result in
+ *	  bonding round-robin mode ignoring links after failover/recovery
+ *
+ * 2003/03/17 - Jay Vosburgh <fubar at us dot ibm dot com>
+ *	- kmalloc fix (GFP_KERNEL to GFP_ATOMIC) reported by
+ *	  Shmulik dot Hen at intel.com.
+ *	- Based on discussion on mailing list, changed use of
+ *	  update_slave_cnt(), created wrapper functions for adding/removing
+ *	  slaves, changed bond_xmit_xor() to check slave_cnt instead of
+ *	  checking slave and slave->dev (which only worked by accident).
+ *	- Misc code cleanup: get arp_send() prototype from header file,
+ *	  add max_bonds to bonding.txt.
+ *
+ * 2003/03/18 - Tsippy Mendelson <tsippy.mendelson at intel dot com> and
+ *		Shmulik Hen <shmulik.hen at intel dot com>
+ *	- Make sure only bond_attach_slave() and bond_detach_slave() can
+ *	  manipulate the slave list, including slave_cnt, even when in
+ *	  bond_release_all().
+ *	- Fixed hang in bond_release() while traffic is running.
+ *	  netdev_set_master() must not be called from within the bond lock.
+ *
+ * 2003/03/18 - Tsippy Mendelson <tsippy.mendelson at intel dot com> and
+ *		Shmulik Hen <shmulik.hen at intel dot com>
+ *	- Fixed hang in bond_enslave(): netdev_set_master() must not be
+ *	  called from within the bond lock while traffic is running.
  */
 
 #include <linux/config.h>
@@ -278,6 +315,7 @@
 #include <linux/init.h>
 #include <linux/timer.h>
 #include <linux/socket.h>
+#include <linux/ctype.h>
 #include <linux/errno.h>
 #include <linux/netdevice.h>
 #include <linux/inetdevice.h>
@@ -288,7 +326,7 @@
 #include <linux/if_bonding.h>
 #include <linux/smp.h>
 #include <linux/if_ether.h>
-#include <linux/if_arp.h>
+#include <net/arp.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
 
@@ -298,8 +336,8 @@
 #include <asm/dma.h>
 #include <asm/uaccess.h>
 
-#define DRV_VERSION		"2.4.20-20021210"
-#define DRV_RELDATE		"December 10, 2002"
+#define DRV_VERSION		"2.5.65-20030320"
+#define DRV_RELDATE		"March 20, 2003"
 #define DRV_NAME		"bonding"
 #define DRV_DESCRIPTION		"Ethernet Channel Bonding Driver"
 
@@ -330,14 +368,30 @@
 
 static int max_bonds	= BOND_DEFAULT_MAX_BONDS;
 static int miimon	= BOND_LINK_MON_INTERV;
-static int mode		= BOND_MODE_ROUNDROBIN;
+static int use_carrier	= 1;
+static int bond_mode	= BOND_MODE_ROUNDROBIN;
 static int updelay	= 0;
 static int downdelay	= 0;
 
-#define BOND_MULTICAST_DISABLED 0
-#define BOND_MULTICAST_ACTIVE   1
-#define BOND_MULTICAST_ALL      2
-static int multicast    = BOND_MULTICAST_ALL;
+static char *mode	= NULL;
+
+static struct bond_parm_tbl bond_mode_tbl[] = {
+{	"balance-rr",		BOND_MODE_ROUNDROBIN},
+{	"active-backup",	BOND_MODE_ACTIVEBACKUP},
+{	"balance-xor",		BOND_MODE_XOR},
+{	"broadcast",		BOND_MODE_BROADCAST},
+{	NULL,			-1},
+};
+
+static int multicast_mode	= BOND_MULTICAST_ALL;
+static char *multicast		= NULL;
+
+static struct bond_parm_tbl bond_mc_tbl[] = {
+{	"disabled",		BOND_MULTICAST_DISABLED},
+{	"active",		BOND_MULTICAST_ACTIVE},
+{	"all",			BOND_MULTICAST_ALL},
+{	NULL,			-1},
+};
 
 static int first_pass	= 1;
 static struct bonding *these_bonds =  NULL;
@@ -347,25 +401,23 @@
 MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");
 MODULE_PARM(miimon, "i");
 MODULE_PARM_DESC(miimon, "Link check interval in milliseconds");
-MODULE_PARM(mode, "i");
+MODULE_PARM(use_carrier, "i");
+MODULE_PARM_DESC(use_carrier, "Use netif_carrier_ok (vs MII ioctls) in miimon; 09 for off, 1 for on (default)");
+MODULE_PARM(mode, "s");
+MODULE_PARM_DESC(mode, "Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor");
 MODULE_PARM(arp_interval, "i");
 MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds");
 MODULE_PARM(arp_ip_target, "1-" __MODULE_STRING(MAX_ARP_IP_TARGETS) "s");
 MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form");
-MODULE_PARM_DESC(mode, "Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor");
 MODULE_PARM(updelay, "i");
 MODULE_PARM_DESC(updelay, "Delay before considering link up, in milliseconds");
 MODULE_PARM(downdelay, "i");
 MODULE_PARM_DESC(downdelay, "Delay before considering link down, in milliseconds");
 MODULE_PARM(primary, "s");
 MODULE_PARM_DESC(primary, "Primary network device to use");
-MODULE_PARM(multicast, "i");
+MODULE_PARM(multicast, "s");
 MODULE_PARM_DESC(multicast, "Mode for multicast support : 0 for none, 1 for active slave, 2 for all slaves (default)");
 
-extern void arp_send( int type, int ptype, u32 dest_ip, struct net_device *dev,
-	u32 src_ip, unsigned char *dest_hw, unsigned char *src_hw, 
-	unsigned char *target_hw);
-
 static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *dev);
 static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev);
 static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *dev);
@@ -408,18 +460,20 @@
   
 static void arp_send_all(slave_t *slave)
 {	
-  int i; 
-  for ( i=0; (i<MAX_ARP_IP_TARGETS) && arp_target[i]; i++) { 
-    arp_send(ARPOP_REQUEST, ETH_P_ARP, arp_target[i], slave->dev, 
-	     my_ip, arp_target_hw_addr, slave->dev->dev_addr,
-	     arp_target_hw_addr); 
-  } 
+	int i; 
+
+	for (i = 0; (i<MAX_ARP_IP_TARGETS) && arp_target[i]; i++) { 
+		arp_send(ARPOP_REQUEST, ETH_P_ARP, arp_target[i], slave->dev, 
+			 my_ip, arp_target_hw_addr, slave->dev->dev_addr,
+			 arp_target_hw_addr); 
+	} 
 }
  
 
-static const char *bond_mode(void)
+static const char *
+bond_mode_name(void)
 {
-	switch (mode) {
+	switch (bond_mode) {
 	case BOND_MODE_ROUNDROBIN :
 		return "load balancing (round-robin)";
 	case BOND_MODE_ACTIVEBACKUP :
@@ -433,9 +487,10 @@
 	}
 }
 
-static const char *multicast_mode(void)
+static const char *
+multicast_mode_name(void)
 {
-	switch(multicast) {
+	switch(multicast_mode) {
 	case BOND_MULTICAST_DISABLED :
 		return "disabled";
 	case BOND_MULTICAST_ACTIVE :
@@ -464,6 +519,29 @@
 	slave->dev->flags &= ~IFF_NOARP;
 }
 
+/*
+ * This function counts and verifies the the number of attached
+ * slaves, checking the count against the expected value (given that incr
+ * is either 1 or -1, for add or removal of a slave).  Only
+ * bond_xmit_xor() uses the slave_cnt value, but this is still a good
+ * consistency check.
+ */
+static inline void
+update_slave_cnt(bonding_t *bond, int incr)
+{
+	slave_t *slave = NULL;
+	int expect = bond->slave_cnt + incr;
+
+	bond->slave_cnt = 0;
+	for (slave = bond->prev; slave != (slave_t*)bond;
+	     slave = slave->prev) {
+		bond->slave_cnt++;
+	}
+
+	if (expect != bond->slave_cnt)
+		BUG();
+}
+
 /* 
  * This function detaches the slave <slave> from the list <bond>.
  * WARNING: no check is made to verify if the slave effectively
@@ -471,8 +549,11 @@
  * Nothing is freed on return, structures are just unchained.
  * If the bond->current_slave pointer was pointing to <slave>,
  * it's replaced with slave->next, or <bond> if not applicable.
+ *
+ * bond->lock held by caller.
  */
-static slave_t *bond_detach_slave(bonding_t *bond, slave_t *slave)
+static slave_t *
+bond_detach_slave(bonding_t *bond, slave_t *slave)
 {
 	if ((bond == NULL) || (slave == NULL) ||
 	   ((void *)bond == (void *)slave)) {
@@ -499,8 +580,7 @@
 			}
 			write_unlock(&bond->ptrlock);
 		}
-	}
-	else {
+	} else {
 		slave->prev->next = slave->next;
 		if (bond->prev == slave) {  /* is this slave the last one ? */
 			bond->prev = slave->prev;
@@ -515,9 +595,44 @@
 		write_unlock(&bond->ptrlock);
 	}
 
+	update_slave_cnt(bond, -1);
+
 	return slave;
 }
 
+static void
+bond_attach_slave(struct bonding *bond, struct slave *new_slave)
+{
+	/* 
+	 * queue to the end of the slaves list, make the first element its
+	 * successor, the last one its predecessor, and make it the bond's
+	 * predecessor. 
+	 *
+	 * Just to clarify, so future bonding driver hackers don't go through
+	 * the same confusion stage I did trying to figure this out, the
+	 * slaves are stored in a double linked circular list, sortof.
+	 * In the ->next direction, the last slave points to the first slave,
+	 * bypassing bond; only the slaves are in the ->next direction.
+	 * In the ->prev direction, however, the first slave points to bond
+	 * and bond points to the last slave.
+	 *
+	 * It looks like a circle with a little bubble hanging off one side
+	 * in the ->prev direction only.
+	 *
+	 * When going through the list once, its best to start at bond->prev
+	 * and go in the ->prev direction, testing for bond.  Doing this
+	 * in the ->next direction doesn't work.  Trust me, I know this now.
+	 * :)  -mts 2002.03.14
+	 */
+	new_slave->prev       = bond->prev;
+	new_slave->prev->next = new_slave;
+	bond->prev            = new_slave;
+	new_slave->next       = bond->next;
+
+	update_slave_cnt(bond, 1);
+}
+
+
 /*
  * Less bad way to call ioctl from within the kernel; this needs to be
  * done some other way to get the call out of interrupt context.
@@ -534,17 +649,31 @@
 /* 
  * if <dev> supports MII link status reporting, check its link status.
  *
+ * We either do MII/ETHTOOL ioctls, or check netif_carrier_ok(),
+ * depening upon the setting of the use_carrier parameter.
+ *
  * Return either BMSR_LSTATUS, meaning that the link is up (or we
  * can't tell and just pretend it is), or 0, meaning that the link is
  * down.
+ *
+ * If reporting is non-zero, instead of faking link up, return -1 if
+ * both ETHTOOL and MII ioctls fail (meaning the device does not
+ * support them).  If use_carrier is set, return whatever it says.
+ * It'd be nice if there was a good way to tell if a driver supports
+ * netif_carrier, but there really isn't.
  */
-static u16 bond_check_dev_link(struct net_device *dev)
+static int
+bond_check_dev_link(struct net_device *dev, int reporting)
 {
 	static int (* ioctl)(struct net_device *, struct ifreq *, int);
 	struct ifreq ifr;
 	struct mii_ioctl_data *mii;
 	struct ethtool_value etool;
 
+	if (use_carrier) {
+		return netif_carrier_ok(dev) ? BMSR_LSTATUS : 0;
+	}
+
 	ioctl = dev->do_ioctl;
 	if (ioctl) {
 		/* TODO: set pointer to correct ioctl on a per team member */
@@ -576,18 +705,24 @@
 		if (IOCTL(dev, &ifr, SIOCETHTOOL) == 0) {
 			if (etool.data == 1) {
 				return BMSR_LSTATUS;
-			} 
-			else { 
+			} else { 
 #ifdef BONDING_DEBUG
 				printk(KERN_INFO 
-					":: SIOCETHTOOL shows failure \n");
+					":: SIOCETHTOOL shows link down \n");
 #endif
-				return(0);
+				return 0;
 			} 
 		}
 
 	}
-	return BMSR_LSTATUS;  /* spoof link up ( we can't check it) */
+ 
+	/*
+	 * If reporting, report that either there's no dev->do_ioctl,
+	 * or both SIOCGMIIREG and SIOCETHTOOL failed (meaning that we
+	 * cannot report link status).  If not reporting, pretend
+	 * we're ok.
+	 */
+	return reporting ? -1 : BMSR_LSTATUS;
 }
 
 static u16 bond_check_mii_link(bonding_t *bond)
@@ -622,7 +757,7 @@
 		init_timer(arp_timer);
 		arp_timer->expires  = jiffies + (arp_interval * HZ / 1000);
 		arp_timer->data     = (unsigned long)dev;
-		if (mode == BOND_MODE_ACTIVEBACKUP) {
+		if (bond_mode == BOND_MODE_ACTIVEBACKUP) {
 			arp_timer->function = (void *)&activebackup_arp_monitor;
 		} else {
 			arp_timer->function = (void *)&loadbalance_arp_monitor;
@@ -692,7 +827,7 @@
 static void bond_mc_add(bonding_t *bond, void *addr, int alen)
 { 
 	slave_t *slave;
-	switch (multicast) {
+	switch (multicast_mode) {
 	case BOND_MULTICAST_ACTIVE :
 		/* write lock already acquired */
 		if (bond->current_slave != NULL)
@@ -713,7 +848,7 @@
 static void bond_mc_delete(bonding_t *bond, void *addr, int alen)
 { 
 	slave_t *slave; 
-	switch (multicast) {
+	switch (multicast_mode) {
 	case BOND_MULTICAST_ACTIVE :
 		/* write lock already acquired */
 		if (bond->current_slave != NULL)
@@ -769,7 +904,7 @@
 static void bond_set_promiscuity(bonding_t *bond, int inc)
 { 
 	slave_t *slave; 
-	switch (multicast) {
+	switch (multicast_mode) {
 	case BOND_MULTICAST_ACTIVE :
 		/* write lock already acquired */
 		if (bond->current_slave != NULL)
@@ -790,7 +925,7 @@
 static void bond_set_allmulti(bonding_t *bond, int inc)
 { 
 	slave_t *slave; 
-	switch (multicast) {
+	switch (multicast_mode) {
 	case BOND_MULTICAST_ACTIVE : 
 		/* write lock already acquired */
 		if (bond->current_slave != NULL)
@@ -827,7 +962,7 @@
 	struct dev_mc_list *dmi;
 	unsigned long flags = 0;
 
-	if (multicast == BOND_MULTICAST_DISABLED)
+	if (multicast_mode == BOND_MULTICAST_DISABLED)
 		return;
 	/*
 	 * Lock the private data for the master
@@ -865,7 +1000,7 @@
 
 	/* save master's multicast list */ 
 	bond_mc_list_destroy (bond);
-	bond_mc_list_copy (master->mc_list, bond, GFP_KERNEL);
+	bond_mc_list_copy (master->mc_list, bond, GFP_ATOMIC);
 
 	write_unlock_irqrestore(&bond->lock, flags);
 }
@@ -878,7 +1013,7 @@
 {
 	struct dev_mc_list *dmi;
 
-	switch(multicast) {
+	switch(multicast_mode) {
 	case BOND_MULTICAST_ACTIVE :		
 		if (bond->device->flags & IFF_PROMISC) {
 			if (old != NULL && new != old)
@@ -907,20 +1042,6 @@
 	}
 }
 
-/*
- * This function counts the number of attached 
- * slaves for use by bond_xmit_xor.
- */
-static void update_slave_cnt(bonding_t *bond)
-{
-	slave_t *slave = NULL;
-
-	bond->slave_cnt = 0;
-	for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev) {
-		bond->slave_cnt++;
-	}
-}
-
 /* enslave device <slave> to bond device <master> */
 static int bond_enslave(struct net_device *master_dev, 
                         struct net_device *slave_dev)
@@ -934,10 +1055,7 @@
 	struct dev_mc_list *dmi;
 	struct in_ifaddr **ifap;
 	struct in_ifaddr *ifa;
-	static int (* ioctl)(struct net_device *, struct ifreq *, int);
-	struct ifreq ifr;
-	struct ethtool_value etool; 
-	int link_reporting = 0;
+	int link_reporting;
 
 	if (master_dev == NULL || slave_dev == NULL) {
 		return -ENODEV;
@@ -949,14 +1067,12 @@
 			"Warning : no link monitoring support for %s\n",
 			slave_dev->name);
 	}
-	write_lock_irqsave(&bond->lock, flags);
 
 	/* not running. */
 	if ((slave_dev->flags & IFF_UP) != IFF_UP) {
 #ifdef BONDING_DEBUG
 		printk(KERN_CRIT "Error, slave_dev is not running\n");
 #endif
-		write_unlock_irqrestore(&bond->lock, flags);
 		return -EINVAL;
 	}
 
@@ -965,12 +1081,10 @@
 #ifdef BONDING_DEBUG
 		printk(KERN_CRIT "Error, Device was already enslaved\n");
 #endif
-		write_unlock_irqrestore(&bond->lock, flags);
 		return -EBUSY;
 	}
 		   
-	if ((new_slave = kmalloc(sizeof(slave_t), GFP_KERNEL)) == NULL) {
-		write_unlock_irqrestore(&bond->lock, flags);
+	if ((new_slave = kmalloc(sizeof(slave_t), GFP_ATOMIC)) == NULL) {
 		return -ENOMEM;
 	}
 	memset(new_slave, 0, sizeof(slave_t));
@@ -983,14 +1097,12 @@
 #ifdef BONDING_DEBUG
 		printk(KERN_CRIT "Error %d calling netdev_set_master\n", err);
 #endif
-		kfree(new_slave);
-		write_unlock_irqrestore(&bond->lock, flags);
-		return err;      
+		goto err_free;
 	}
 
 	new_slave->dev = slave_dev;
 
-	if (multicast == BOND_MULTICAST_ALL) {
+	if (multicast_mode == BOND_MULTICAST_ALL) {
 		/* set promiscuity level to new slave */ 
 		if (master_dev->flags & IFF_PROMISC)
 			dev_set_promiscuity(slave_dev, 1); 
@@ -1004,64 +1116,24 @@
 			dev_mc_add (slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
 	}
 
-	/* 
-	 * queue to the end of the slaves list, make the first element its
-	 * successor, the last one its predecessor, and make it the bond's
-	 * predecessor. 
-	 *
-	 * Just to clarify, so future bonding driver hackers don't go through
-	 * the same confusion stage I did trying to figure this out, the
-	 * slaves are stored in a double linked circular list, sortof.
-	 * In the ->next direction, the last slave points to the first slave,
-	 * bypassing bond; only the slaves are in the ->next direction.
-	 * In the ->prev direction, however, the first slave points to bond
-	 * and bond points to the last slave.
-	 *
-	 * It looks like a circle with a little bubble hanging off one side
-	 * in the ->prev direction only.
-	 *
-	 * When going through the list once, its best to start at bond->prev
-	 * and go in the ->prev direction, testing for bond.  Doing this
-	 * in the ->next direction doesn't work.  Trust me, I know this now.
-	 * :)  -mts 2002.03.14
-	 */
-	new_slave->prev       = bond->prev;
-	new_slave->prev->next = new_slave;
-	bond->prev            = new_slave;
-	new_slave->next       = bond->next;
-
+	write_lock_irqsave(&bond->lock, flags);
+	
+	bond_attach_slave(bond, new_slave);
 	new_slave->delay = 0;
 	new_slave->link_failure_count = 0;
 
-	if (miimon > 0) {
-		/* if the network driver for the slave does not support
-		 * ETHTOOL/MII link status reporting, warn the user of this
-		 */
-		if ((ioctl = slave_dev->do_ioctl) != NULL) {
-			etool.cmd = ETHTOOL_GLINK;
-	        	ifr.ifr_data = (char*)&etool;
-			if (IOCTL(slave_dev, &ifr, SIOCETHTOOL) == 0) {
-				link_reporting = 1;
-			}
-			else {
-				if (IOCTL(slave_dev, &ifr, SIOCGMIIPHY) == 0) {
-		                        /* Yes, the mii is overlaid on the
-					 * ifreq.ifr_ifru
-					 */
-					((struct mii_ioctl_data*)
-					 (&ifr.ifr_data))->reg_num = 1;
-					if (IOCTL(slave_dev, &ifr, SIOCGMIIREG)
-						       			== 0) {
-	                                	link_reporting = 1;
-					}
-				}
-			}
-		}
+	if (miimon > 0 && !use_carrier) {
+		link_reporting = bond_check_dev_link(slave_dev, 1);
 
-		if ((link_reporting == 0) && (arp_interval == 0)) {
-			/* miimon is set but a bonded network driver does
-			 * not support ETHTOOL/MII and arp_interval is
-			 * not set
+		if ((link_reporting == -1) && (arp_interval == 0)) {
+			/*
+			 * miimon is set but a bonded network driver
+			 * does not support ETHTOOL/MII and
+			 * arp_interval is not set.  Note: if
+			 * use_carrier is enabled, we will never go
+			 * here (because netif_carrier is always
+			 * supported); thus, we don't need to change
+			 * the messages for netif_carrier.
 			 */ 
 			printk(KERN_ERR
 				"bond_enslave(): MII and ETHTOOL support not "
@@ -1070,8 +1142,7 @@
 		       		"not specified, thus bonding will not detect "
 				"link failures! see bonding.txt for details.\n",
 		       		slave_dev->name);
-		}
-		else if (link_reporting == 0) {
+		} else if (link_reporting == -1) {
 			/* unable  get link status using mii/ethtool */
 			printk(KERN_WARNING 
 			       "bond_enslave: can't get link status from "
@@ -1085,7 +1156,7 @@
 
 	/* check for initial state */
 	if ((miimon <= 0) ||
-	    (bond_check_dev_link(slave_dev) == BMSR_LSTATUS)) {
+	    (bond_check_dev_link(slave_dev, 0) == BMSR_LSTATUS)) {
 #ifdef BONDING_DEBUG
 		printk(KERN_CRIT "Initial state of slave_dev is BOND_LINK_UP\n");
 #endif
@@ -1106,7 +1177,7 @@
 	 * since we guarantee that current_slave always point to the last
 	 * usable interface, we just have to verify this interface's flag.
 	 */
-	if (mode == BOND_MODE_ACTIVEBACKUP) {
+	if (bond_mode == BOND_MODE_ACTIVEBACKUP) {
 		if (((bond->current_slave == NULL)
 			|| (bond->current_slave->dev->flags & IFF_NOARP))
 			&& (new_slave->link == BOND_LINK_UP)) {
@@ -1145,8 +1216,6 @@
 			bond->current_slave = new_slave;
 	}
 
-	update_slave_cnt(bond);
-
 	write_unlock_irqrestore(&bond->lock, flags);
 
 	/*
@@ -1187,7 +1256,11 @@
 		new_slave->state == BOND_STATE_ACTIVE ? "n active" : " backup",
 		new_slave->link == BOND_LINK_UP ? "n up" : " down");
 
+	/* enslave is successful */
 	return 0;
+err_free:
+	kfree(new_slave);
+	return err;
 }
 
 /* 
@@ -1276,13 +1349,13 @@
 		} else {
 
 			printk (" but could not find any %s interface.\n",
-				(mode == BOND_MODE_ACTIVEBACKUP) ? "backup":"other");
+				(bond_mode == BOND_MODE_ACTIVEBACKUP) ? "backup":"other");
 			write_lock(&bond->ptrlock);
 			bond->current_slave = (slave_t *)NULL;
 			write_unlock(&bond->ptrlock);
 			return NULL; /* still no slave, return NULL */
 		}
-	} else if (mode == BOND_MODE_ACTIVEBACKUP) {
+	} else if (bond_mode == BOND_MODE_ACTIVEBACKUP) {
 		/* make sure oldslave doesn't send arps - this could
 		 * cause a ping-pong effect between interfaces since they
 		 * would be able to tx arps - in active backup only one
@@ -1311,7 +1384,7 @@
 		if (IS_UP(newslave->dev)) {
 			if (newslave->link == BOND_LINK_UP) {
 				/* this one is immediately usable */
-				if (mode == BOND_MODE_ACTIVEBACKUP) {
+				if (bond_mode == BOND_MODE_ACTIVEBACKUP) {
 					bond_set_slave_active_flags(newslave);
 					bond_mc_update(bond, newslave, oldslave);
 					printk (" and making interface %s the active one.\n",
@@ -1358,8 +1431,8 @@
 		return bestslave;
 	}
 
-	if ((mode == BOND_MODE_ACTIVEBACKUP) &&
-	    (multicast == BOND_MULTICAST_ACTIVE) &&
+	if ((bond_mode == BOND_MODE_ACTIVEBACKUP) &&
+	    (multicast_mode == BOND_MULTICAST_ACTIVE) &&
 	    (oldslave != NULL)) {
 		/* flush bonds (master's) mc_list from oldslave since it wasn't
 		 * updated (and deleted) above
@@ -1374,7 +1447,7 @@
 	}
 
 	printk (" but could not find any %s interface.\n",
-		(mode == BOND_MODE_ACTIVEBACKUP) ? "backup":"other");
+		(bond_mode == BOND_MODE_ACTIVEBACKUP) ? "backup":"other");
 	
 	/* absolutely nothing found. let's return NULL */
 	write_lock(&bond->ptrlock);
@@ -1406,16 +1479,14 @@
 
 	bond = (struct bonding *) master->priv;
 
-	write_lock_irqsave(&bond->lock, flags);
-
 	/* master already enslaved, or slave not enslaved,
 	   or no slave for this master */
 	if ((master->flags & IFF_SLAVE) || !(slave->flags & IFF_SLAVE)) {
 		printk (KERN_DEBUG "%s: cannot release %s.\n", master->name, slave->name);
-		write_unlock_irqrestore(&bond->lock, flags);
 		return -EINVAL;
 	}
 
+	write_lock_irqsave(&bond->lock, flags);
 	bond->current_arp_slave = NULL;
 	our_slave = (slave_t *)bond;
 	old_current = bond->current_slave;
@@ -1434,60 +1505,62 @@
 			} else {
 				printk(".\n");
 			}
-
-			/* release the slave from its bond */
-
-			if (multicast == BOND_MULTICAST_ALL) {
-				/* flush master's mc_list from slave */ 
-				bond_mc_list_flush (slave, master); 
-				
-				/* unset promiscuity level from slave */
-				if (master->flags & IFF_PROMISC) 
-					dev_set_promiscuity(slave, -1); 
-       
-				/* unset allmulti level from slave */ 
-				if (master->flags & IFF_ALLMULTI)
-					dev_set_allmulti(slave, -1); 
-			}
-
-			netdev_set_master(slave, NULL);
-
-			/* only restore its RUNNING flag if monitoring set it down */
-			if (slave->flags & IFF_UP) {
-				slave->flags |= IFF_RUNNING;
-			}
-
-			if (slave->flags & IFF_NOARP || 
-				bond->current_slave != NULL) {
-					dev_close(slave);
-					our_slave->original_flags &= ~IFF_UP;
-			}
-
-			bond_restore_slave_flags(our_slave);
-			kfree(our_slave);
-
+			
 			if (bond->current_slave == NULL) {
 				printk(KERN_INFO
 					"%s: now running without any active interface !\n",
 					master->name);
 			}
 
-			update_slave_cnt(bond);
-
 			if (bond->primary_slave == our_slave) {
 				bond->primary_slave = NULL;
 			}
 
-			write_unlock_irqrestore(&bond->lock, flags);
-			return 0;  /* deletion OK */
+			break;
 		}
-	}
 
-	/* if we get here, it's because the device was not found */
+	}
 	write_unlock_irqrestore(&bond->lock, flags);
+	
+	if (our_slave == (slave_t *)bond) {
+		/* if we get here, it's because the device was not found */
+		printk (KERN_INFO "%s: %s not enslaved\n", master->name, slave->name);
+		return -EINVAL;
+	}
 
-	printk (KERN_INFO "%s: %s not enslaved\n", master->name, slave->name);
-	return -EINVAL;
+	/* undo settings and restore original values */
+	
+	if (multicast_mode == BOND_MULTICAST_ALL) {
+		/* flush master's mc_list from slave */ 
+		bond_mc_list_flush (slave, master); 
+
+		/* unset promiscuity level from slave */
+		if (master->flags & IFF_PROMISC) 
+			dev_set_promiscuity(slave, -1); 
+
+		/* unset allmulti level from slave */ 
+		if (master->flags & IFF_ALLMULTI)
+			dev_set_allmulti(slave, -1); 
+	}
+
+	netdev_set_master(slave, NULL);
+
+	/* only restore its RUNNING flag if monitoring set it down */
+	if (slave->flags & IFF_UP) {
+		slave->flags |= IFF_RUNNING;
+	}
+
+	if (slave->flags & IFF_NOARP || 
+		bond->current_slave != NULL) {
+			dev_close(slave);
+			our_slave->original_flags &= ~IFF_UP;
+	}
+
+	bond_restore_slave_flags(our_slave);
+	
+	kfree(our_slave);
+
+	return 0;  /* deletion OK */
 }
 
 /* 
@@ -1510,13 +1583,15 @@
 
 	bond = (struct bonding *) master->priv;
 	bond->current_arp_slave = NULL;
+	bond->current_slave = NULL;
+	bond->primary_slave = NULL;
 
 	while ((our_slave = bond->prev) != (slave_t *)bond) {
 		slave_dev = our_slave->dev;
-		bond->prev = our_slave->prev;
+		bond_detach_slave(bond, our_slave);
 
-		if (multicast == BOND_MULTICAST_ALL 
-		    || (multicast == BOND_MULTICAST_ACTIVE 
+		if (multicast_mode == BOND_MULTICAST_ALL 
+		    || (multicast_mode == BOND_MULTICAST_ACTIVE 
 			&& bond->current_slave == our_slave)) {
 
 			/* flush master's mc_list from slave */ 
@@ -1533,6 +1608,10 @@
 
 		kfree(our_slave);
 
+		/*
+		 * Can be safely called from inside the bond lock
+		 * since traffic and timers have already stopped
+		 */
 		netdev_set_master(slave_dev, NULL);
 
 		/* only restore its RUNNING flag if monitoring set it down */
@@ -1543,10 +1622,6 @@
 			dev_close(slave_dev);
 	}
 
-	bond->current_slave = NULL;
-	bond->next = (slave_t *)bond;
-	bond->slave_cnt = 0;
-	bond->primary_slave = NULL;
 	printk (KERN_INFO "%s: released all slaves\n", master->name);
 
 	return 0;
@@ -1579,9 +1654,9 @@
 		/* use updelay+1 to match an UP slave even when updelay is 0 */
 		int mindelay = updelay + 1;
 		struct net_device *dev = slave->dev;
-		u16 link_state;
+		int link_state;
 		
-		link_state = bond_check_dev_link(dev);
+		link_state = bond_check_dev_link(dev, 0);
 
 		switch (slave->link) {
 		case BOND_LINK_UP:	/* the link was up */
@@ -1608,7 +1683,7 @@
 						"%s, disabling it in %d ms.\n",
 						master->name,
 						IS_UP(dev)
-						? ((mode == BOND_MODE_ACTIVEBACKUP)
+						? ((bond_mode == BOND_MODE_ACTIVEBACKUP)
 						   ? ((slave == oldcurrent)
 						      ? "active " : "backup ")
 						   : "")
@@ -1628,7 +1703,7 @@
 					slave->link = BOND_LINK_DOWN;
 					/* in active/backup mode, we must
 					   completely disable this interface */
-					if (mode == BOND_MODE_ACTIVEBACKUP) {
+					if (bond_mode == BOND_MODE_ACTIVEBACKUP) {
 						bond_set_slave_inactive_flags(slave);
 					}
 					printk(KERN_INFO
@@ -1708,14 +1783,12 @@
 					slave->link = BOND_LINK_UP;
 					slave->jiffies = jiffies;
 
-					if ( (mode == BOND_MODE_ACTIVEBACKUP) 
-					 || (slave != bond->primary_slave) ) {
-						/* prevent it from being the active one */
-						slave->state = BOND_STATE_BACKUP;
-					}
-					else {
+					if (bond_mode != BOND_MODE_ACTIVEBACKUP) {
 						/* make it immediately active */
 						slave->state = BOND_STATE_ACTIVE;
+					} else if (slave != bond->primary_slave) {
+						/* prevent it from being the active one */
+						slave->state = BOND_STATE_BACKUP;
 					}
 
 					printk(KERN_INFO
@@ -1775,7 +1848,7 @@
 				bestslave->jiffies = jiffies;
 			}
 
-			if (mode == BOND_MODE_ACTIVEBACKUP) {
+			if (bond_mode == BOND_MODE_ACTIVEBACKUP) {
 				bond_set_slave_active_flags(bestslave);
 				bond_mc_update(bond, bestslave, NULL);
 			} else {
@@ -2171,19 +2244,6 @@
 	read_unlock_irqrestore(&bond->lock, flags);
 }
 
-
-#define isdigit(c) (c >= '0' && c <= '9')
-__inline static int atoi( char **s) 
-{
-int i = 0;
-while (isdigit(**s))
-  i = i*20 + *((*s)++) - '0';
-return i;
-}
-
-#define isascii(c) (((unsigned char)(c))<=0x7f)
-#define LF 0xA
-#define isspace(c) (c==' ' || c=='	'|| c==LF)   
 typedef uint32_t in_addr_t;
 
 int
@@ -2279,7 +2339,7 @@
 	slave_t *slave;
 	unsigned long flags;
 
-	info->bond_mode = mode;
+	info->bond_mode = bond_mode;
 	info->num_slaves = 0;
 	info->miimon = miimon;
 
@@ -2416,7 +2476,7 @@
 			break;
 		case BOND_CHANGE_ACTIVE_OLD:
 		case SIOCBONDCHANGEACTIVE:
-			if (mode == BOND_MODE_ACTIVEBACKUP) {
+			if (bond_mode == BOND_MODE_ACTIVEBACKUP) {
 				ret = bond_change_active(master_dev, slave_dev);
 			}
 			else {
@@ -2567,20 +2627,13 @@
 	slave = bond->prev;
 
 	/* we're at the root, get the first slave */
-	if ((slave == NULL) || (slave->dev == NULL)) { 
+	if (bond->slave_cnt == 0) {
 		/* no suitable interface, frame not sent */
 		dev_kfree_skb(skb);
 		read_unlock_irqrestore(&bond->lock, flags);
 		return 0;
 	}
 
-	if (bond->slave_cnt == 0) {
-		/* no slaves in the bond, frame not sent */
-		dev_kfree_skb(skb);
-		read_unlock_irqrestore(&bond->lock, flags);
-		return 0;
-	}
-	
 	slave_no = (data->h_dest[5]^slave->dev->dev_addr[5]) % bond->slave_cnt;
 
 	while ( (slave_no > 0) && (slave != (slave_t *)bond) ) {
@@ -2642,7 +2695,7 @@
 	 * receive packets to stay up, and the only ones they receive are 
 	 * broadcasts. 
 	 */
-	if ( (mode != BOND_MODE_ACTIVEBACKUP) && 
+	if ( (bond_mode != BOND_MODE_ACTIVEBACKUP) && 
              (arp_ip_count == 1) &&
 	     (arp_interval > 0) && (arp_target_hw_addr == NULL) &&
 	     (skb->protocol == __constant_htons(ETH_P_IP) ) ) {
@@ -2743,9 +2796,10 @@
 		 */
 		link = bond_check_mii_link(bond);
 
-		len += sprintf(buf + len, "Bonding Mode: %s\n", bond_mode());
+		len += sprintf(buf + len, "Bonding Mode: %s\n",
+			       bond_mode_name());
 
-		if (mode == BOND_MODE_ACTIVEBACKUP) {
+		if (bond_mode == BOND_MODE_ACTIVEBACKUP) {
 			read_lock_irqsave(&bond->lock, flags);
 			read_lock(&bond->ptrlock);
 			if (bond->current_slave != NULL) {
@@ -2766,7 +2820,8 @@
 				updelay * miimon);
 		len += sprintf(buf + len, "Down Delay (ms): %d\n", 
 				downdelay * miimon);
-		len += sprintf(buf + len, "Multicast Mode: %s\n", multicast_mode());
+		len += sprintf(buf + len, "Multicast Mode: %s\n",
+			       multicast_mode_name());
 
 		read_lock_irqsave(&bond->lock, flags);
 		for (slave = bond->prev; slave != (slave_t *)bond; 
@@ -2884,16 +2939,21 @@
 	dev->priv = bond;
 
 	/* Initialize the device structure. */
-	if (mode == BOND_MODE_ACTIVEBACKUP) {
+	switch (bond_mode) {
+	case BOND_MODE_ACTIVEBACKUP:
 		dev->hard_start_xmit = bond_xmit_activebackup;
-	} else if (mode == BOND_MODE_ROUNDROBIN) {
+		break;
+	case BOND_MODE_ROUNDROBIN:
 		dev->hard_start_xmit = bond_xmit_roundrobin;
-	} else if (mode == BOND_MODE_XOR) {
+		break;
+	case BOND_MODE_XOR:
 		dev->hard_start_xmit = bond_xmit_xor;
-	} else if (mode == BOND_MODE_BROADCAST) {
+		break;
+	case BOND_MODE_BROADCAST:
 		dev->hard_start_xmit = bond_xmit_broadcast;
-	} else {
-		printk(KERN_ERR "Unknown bonding mode %d\n", mode);
+		break;
+	default:
+		printk(KERN_ERR "Unknown bonding mode %d\n", bond_mode);
 		kfree(bond->stats);
 		kfree(bond);
 		return -EINVAL;
@@ -2926,7 +2986,7 @@
 	} else {
 		printk("out MII link monitoring");
 	}
-	printk(", in %s mode.\n", bond_mode());
+	printk(", in %s mode.\n", bond_mode_name());
 
 	printk(KERN_INFO "%s registered with", dev->name);
 	if (arp_interval > 0) {
@@ -2986,6 +3046,28 @@
 }
  */
 
+/*
+ * Convert string input module parms.  Accept either the
+ * number of the mode or its string name.
+ */
+static inline int
+bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl)
+{
+	int i;
+
+	for (i = 0; tbl[i].modename != NULL; i++) {
+		if ((isdigit(*mode_arg) &&
+		    tbl[i].mode == simple_strtol(mode_arg, NULL, 0)) ||
+		    (0 == strncmp(mode_arg, tbl[i].modename,
+				  strlen(tbl[i].modename)))) {
+			return tbl[i].mode;
+		}
+	}
+
+	return -1;
+}
+
+
 static int __init bonding_init(void)
 {
 	int no;
@@ -2996,6 +3078,29 @@
 
 	printk(KERN_INFO "%s", version);
 
+	/*
+	 * Convert string parameters.
+	 */
+	if (mode) {
+		bond_mode = bond_parse_parm(mode, bond_mode_tbl);
+		if (bond_mode == -1) {
+			printk(KERN_WARNING
+			       "bonding_init(): Invalid bonding mode \"%s\"\n",
+			       mode == NULL ? "NULL" : mode);
+			return -EINVAL;
+		}
+	}
+
+	if (multicast) {
+		multicast_mode = bond_parse_parm(multicast, bond_mc_tbl);
+		if (multicast_mode == -1) {
+			printk(KERN_WARNING 
+		       "bonding_init(): Invalid multicast mode \"%s\"\n",
+			       multicast == NULL ? "NULL" : multicast);
+			return -EINVAL;
+		}
+	}
+
 	if (max_bonds < 1 || max_bonds > INT_MAX) {
 		printk(KERN_WARNING 
 		       "bonding_init(): max_bonds (%d) not in range %d-%d, "
@@ -3125,28 +3230,18 @@
 		       "link failures! see bonding.txt for details.\n");
 	}
 
-	if ((primary != NULL) && (mode != BOND_MODE_ACTIVEBACKUP)){
+	if ((primary != NULL) && (bond_mode != BOND_MODE_ACTIVEBACKUP)){
 		/* currently, using a primary only makes sence 
 		 * in active backup mode 
 		 */
 		printk(KERN_WARNING 
 		       "bonding_init(): %s primary device specified but has "
 		       " no effect in %s mode\n",
-		       primary, bond_mode());
+		       primary, bond_mode_name());
 		primary = NULL;
 	}
 
 
-        if (multicast != BOND_MULTICAST_DISABLED &&
-	    multicast != BOND_MULTICAST_ACTIVE &&
-	    multicast != BOND_MULTICAST_ALL) {
-		printk(KERN_WARNING 
-		       "bonding_init(): unknown multicast module "
-		       "parameter (%d), multicast reset to %d\n", 
-		       multicast, BOND_MULTICAST_ALL);
-		multicast = BOND_MULTICAST_ALL;
-	}
-
 	for (no = 0; no < max_bonds; no++) {
 		dev_bond->init = bond_init;
 	
diff -urN linux-2.5.66-bk4/drivers/net/gt96100eth.c linux-2.5.66-bk5/drivers/net/gt96100eth.c
--- linux-2.5.66-bk4/drivers/net/gt96100eth.c	Mon Mar 24 14:01:15 2003
+++ linux-2.5.66-bk5/drivers/net/gt96100eth.c	Mon Mar 31 12:50:22 2003
@@ -758,19 +758,6 @@
 		goto free_region;
 	}
 
-	/* Initialize our private structure. */
-	if (dev->priv == NULL) {
-
-		gp = (struct gt96100_private *)kmalloc(sizeof(*gp),
-						       GFP_KERNEL);
-		if (gp == NULL) {
-			retval = -ENOMEM;
-			goto free_region;
-		}
-	
-		dev->priv = gp;
-	}
-
 	gp = dev->priv;
 
 	memset(gp, 0, sizeof(*gp)); // clear it
@@ -854,8 +841,6 @@
  free_region:
 	release_region(gtif->iobase, GT96100_ETH_IO_SIZE);
 	unregister_netdev(dev);
-	if (dev->priv != NULL)
-		kfree (dev->priv);
 	kfree (dev);
 	err("%s failed.  Returns %d\n", __FUNCTION__, retval);
 	return retval;
@@ -1601,8 +1586,6 @@
 				(struct gt96100_private *)gtif->dev->priv;
 			release_region(gtif->iobase, gp->io_size);
 			unregister_netdev(gtif->dev);
-			if (gtif->dev->priv != NULL)
-				kfree (gtif->dev->priv);
 			kfree (gtif->dev);
 		}
 	}
diff -urN linux-2.5.66-bk4/drivers/net/irda/irda-usb.c linux-2.5.66-bk5/drivers/net/irda/irda-usb.c
--- linux-2.5.66-bk4/drivers/net/irda/irda-usb.c	Mon Mar 24 14:00:39 2003
+++ linux-2.5.66-bk5/drivers/net/irda/irda-usb.c	Mon Mar 31 12:50:22 2003
@@ -402,7 +402,7 @@
 
         usb_fill_bulk_urb(urb, self->usbdev, 
 		      usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
-                      skb->data, IRDA_USB_MAX_MTU,
+                      skb->data, IRDA_SKB_MAX_MTU,
                       write_bulk_callback, skb);
 	urb->transfer_buffer_length = skb->len;
 	/* Note : unlink *must* be Asynchronous because of the code in 
@@ -442,6 +442,9 @@
 			 * would be lost in the noise - Jean II */
 			diff += IU_USB_MIN_RTT;
 #endif /* IU_USB_MIN_RTT */
+			/* If the usec counter did wraparound, the diff will
+			 * go negative (tv_usec is a long), so we need to
+			 * correct it by one second. Jean II */
 			if (diff < 0)
 				diff += 1000000;
 
@@ -701,30 +704,11 @@
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
-	/* Check that we have an urb */
-	if (!urb) {
-		WARNING("%s(), Bug : urb == NULL\n", __FUNCTION__);
-		return;
-	}
-
-	/* Allocate new skb if it has not been recycled */
-	if (!skb) {
-		skb = dev_alloc_skb(IRDA_USB_MAX_MTU + 1);
-		if (!skb) {
-			/* If this ever happen, we are in deep s***.
-			 * Basically, the Rx path will stop... */
-			WARNING("%s(), Failed to allocate Rx skb\n", __FUNCTION__);
-			return;
-		}
-	} else  {
-		/* Reset recycled skb */
-		skb->data = skb->tail = skb->head;
-		skb->len = 0;
-	}
-	/* Make sure IP header get aligned (IrDA header is 5 bytes ) */
-	skb_reserve(skb, 1);
+	/* This should never happen */
+	ASSERT(skb != NULL, return;);
+	ASSERT(urb != NULL, return;);
 
-	/* Save ourselves */
+	/* Save ourselves in the skb */
 	cb = (struct irda_skb_cb *) skb->cb;
 	cb->context = self;
 
@@ -758,8 +742,10 @@
 	struct sk_buff *skb = (struct sk_buff *) urb->context;
 	struct irda_usb_cb *self; 
 	struct irda_skb_cb *cb;
-	struct sk_buff *new;
-	
+	struct sk_buff *newskb;
+	struct sk_buff *dataskb;
+	int		docopy;
+
 	IRDA_DEBUG(2, "%s(), len=%d\n", __FUNCTION__, urb->actual_length);
 	
 	/* Find ourselves */
@@ -808,39 +794,56 @@
 	 */
         do_gettimeofday(&self->stamp);
 
-	/* Fix skb, and remove USB-IrDA header */
-	skb_put(skb, urb->actual_length);
-	skb_pull(skb, USB_IRDA_HEADER);
-
-	/* Don't waste a lot of memory on small IrDA frames */
-	if (skb->len < RX_COPY_THRESHOLD) {
-		new = dev_alloc_skb(skb->len+1);
-		if (!new) {
-			self->stats.rx_dropped++;
-			goto done;  
-		}
+	/* Check if we need to copy the data to a new skb or not.
+	 * For most frames, we use ZeroCopy and pass the already
+	 * allocated skb up the stack.
+	 * If the frame is small, it is more efficient to copy it
+	 * to save memory (copy will be fast anyway - that's
+	 * called Rx-copy-break). Jean II */
+	docopy = (urb->actual_length < IRDA_RX_COPY_THRESHOLD);
+
+	/* Allocate a new skb */
+	newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU);
+	if (!newskb)  {
+		self->stats.rx_dropped++;
+		/* We could deliver the current skb, but this would stall
+		 * the Rx path. Better drop the packet... Jean II */
+		goto done;  
+	}
+
+	/* Make sure IP header get aligned (IrDA header is 5 bytes) */
+	/* But IrDA-USB header is 1 byte. Jean II */
+	//skb_reserve(newskb, USB_IRDA_HEADER - 1);
 
-		/* Make sure IP header get aligned (IrDA header is 5 bytes) */
-		skb_reserve(new, 1);
-		
+	if(docopy) {
 		/* Copy packet, so we can recycle the original */
-		memcpy(skb_put(new, skb->len), skb->data, skb->len);
-		/* We will cleanup the skb in irda_usb_submit() */
+		memcpy(newskb->data, skb->data, urb->actual_length);
+		/* Deliver this new skb */
+		dataskb = newskb;
+		/* And hook the old skb to the URB
+		 * Note : we don't need to "clean up" the old skb,
+		 * as we never touched it. Jean II */
 	} else {
-		/* Deliver the original skb */
-		new = skb;
-		skb = NULL;
+		/* We are using ZeroCopy. Deliver old skb */
+		dataskb = skb;
+		/* And hook the new skb to the URB */
+		skb = newskb;
 	}
-	
-	self->stats.rx_bytes += new->len;
-	self->stats.rx_packets++;
+
+	/* Set proper length on skb & remove USB-IrDA header */
+	skb_put(dataskb, urb->actual_length);
+	skb_pull(dataskb, USB_IRDA_HEADER);
 
 	/* Ask the networking layer to queue the packet for the IrDA stack */
-        new->dev = self->netdev;
-        new->mac.raw  = new->data;
-        new->protocol = htons(ETH_P_IRDA);
-        netif_rx(new);
-        self->netdev->last_rx = jiffies;
+	dataskb->dev = self->netdev;
+	dataskb->mac.raw  = dataskb->data;
+	dataskb->protocol = htons(ETH_P_IRDA);
+	netif_rx(dataskb);
+
+	/* Keep stats up to date */
+	self->stats.rx_bytes += dataskb->len;
+	self->stats.rx_packets++;
+	self->netdev->last_rx = jiffies;
 
 done:
 	/* Note : at this point, the URB we've just received (urb)
@@ -973,8 +976,17 @@
 
 	/* Now that we can pass data to IrLAP, allow the USB layer
 	 * to send us some data... */
-	for (i = 0; i < IU_MAX_ACTIVE_RX_URBS; i++)
-		irda_usb_submit(self, NULL, self->rx_urb[i]);
+	for (i = 0; i < IU_MAX_ACTIVE_RX_URBS; i++) {
+		struct sk_buff *skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
+		if (!skb) {
+			/* If this ever happen, we are in deep s***.
+			 * Basically, we can't start the Rx path... */
+			WARNING("%s(), Failed to allocate Rx skb\n", __FUNCTION__);
+			return -1;
+		}
+		//skb_reserve(newskb, USB_IRDA_HEADER - 1);
+		irda_usb_submit(self, skb, self->rx_urb[i]);
+	}
 
 	/* Ready to play !!! */
 	return 0;
@@ -1167,9 +1179,6 @@
 	spin_lock_init(&self->lock);
 
 	irda_usb_init_qos(self);
-	
-	/* Initialise list of skb beeing curently transmitted */
-	self->tx_list = hashbin_new(HB_NOLOCK);	/* unused */
 
 	/* Allocate the buffer for speed changes */
 	/* Don't change this buffer size and allocation without doing
@@ -1228,8 +1237,6 @@
 		self->netdev = NULL;
 		rtnl_unlock();
 	}
-	/* Delete all pending skbs */
-	hashbin_delete(self->tx_list, (FREE_FUNC) &dev_kfree_skb_any);
 	/* Remove the speed buffer */
 	if (self->speed_buff != NULL) {
 		kfree(self->speed_buff);
@@ -1492,8 +1499,10 @@
 		case 0:
 			break;
 		case -EPIPE:		/* -EPIPE = -32 */
-			usb_clear_halt(dev, usb_sndctrlpipe(dev, 0));
-			IRDA_DEBUG(0, "%s(), Clearing stall on control interface\n", __FUNCTION__);
+			/* Martin Diehl says if we get a -EPIPE we should
+			 * be fine and we don't need to do a usb_clear_halt().
+			 * - Jean II */
+			IRDA_DEBUG(0, "%s(), Received -EPIPE, ignoring...\n", __FUNCTION__);
 			break;
 		default:
 			IRDA_DEBUG(0, "%s(), Unknown error %d\n", __FUNCTION__, ret);
diff -urN linux-2.5.66-bk4/drivers/net/irda/sir_dev.c linux-2.5.66-bk5/drivers/net/irda/sir_dev.c
--- linux-2.5.66-bk4/drivers/net/irda/sir_dev.c	Mon Mar 24 14:00:51 2003
+++ linux-2.5.66-bk5/drivers/net/irda/sir_dev.c	Mon Mar 31 12:50:22 2003
@@ -223,25 +223,24 @@
 	}
 
 	/* Read the characters into the buffer */
- 	while (count--) {
-		if (likely(atomic_read(&dev->enable_rx))) {
+	if (likely(atomic_read(&dev->enable_rx))) {
+		while (count--)
 			/* Unwrap and destuff one byte */
 			async_unwrap_char(dev->netdev, &dev->stats, 
-				  &dev->rx_buff, *cp++);
-		}
-		else {
+					  &dev->rx_buff, *cp++);
+	} else {
+		while (count--) {
 			/* rx not enabled: save the raw bytes and never
 			 * trigger any netif_rx. The received bytes are flushed
 			 * later when we re-enable rx but might be read meanwhile
 			 * by the dongle driver.
 			 */
 			dev->rx_buff.data[dev->rx_buff.len++] = *cp++;
-		}
 
-		/* What should we do when the buffer is full? */
-		if (unlikely(dev->rx_buff.len == dev->rx_buff.truesize))
-			dev->rx_buff.len = 0;
-			
+			/* What should we do when the buffer is full? */
+			if (unlikely(dev->rx_buff.len == dev->rx_buff.truesize))
+				dev->rx_buff.len = 0;
+		}
 	}
 
 	return 0;
@@ -423,19 +422,24 @@
 
 static int sirdev_alloc_buffers(struct sir_dev *dev)
 {
-	dev->rx_buff.truesize = SIRBUF_ALLOCSIZE; 
 	dev->tx_buff.truesize = SIRBUF_ALLOCSIZE;
+	dev->rx_buff.truesize = IRDA_SKB_MAX_MTU; 
 
-	dev->rx_buff.head = kmalloc(dev->rx_buff.truesize, GFP_KERNEL);
-	if (dev->rx_buff.head == NULL)
+	/* Bootstrap ZeroCopy Rx */
+	dev->rx_buff.skb = __dev_alloc_skb(dev->rx_buff.truesize, GFP_KERNEL);
+	if (dev->rx_buff.skb == NULL)
 		return -ENOMEM;
-	memset(dev->rx_buff.head, 0, dev->rx_buff.truesize);
+	skb_reserve(dev->rx_buff.skb, 1);
+	dev->rx_buff.head = dev->rx_buff.skb->data;
+	/* No need to memset the buffer, unless you are really pedantic */
 
 	dev->tx_buff.head = kmalloc(dev->tx_buff.truesize, GFP_KERNEL);
 	if (dev->tx_buff.head == NULL) {
-		kfree(dev->rx_buff.head);
+		kfree_skb(dev->rx_buff.skb);
+		dev->rx_buff.skb = NULL;
 		dev->rx_buff.head = NULL;
 		return -ENOMEM;
+		/* Hu ??? This should not be here, Martin ? */
 		memset(dev->tx_buff.head, 0, dev->tx_buff.truesize);
 	}
 
@@ -451,11 +455,12 @@
 
 static void sirdev_free_buffers(struct sir_dev *dev)
 {
-	if (dev->rx_buff.head)
-		kfree(dev->rx_buff.head);
+	if (dev->rx_buff.skb)
+		kfree_skb(dev->rx_buff.skb);
 	if (dev->tx_buff.head)
 		kfree(dev->tx_buff.head);
 	dev->rx_buff.head = dev->tx_buff.head = NULL;
+	dev->rx_buff.skb = NULL;
 }
 
 static int sirdev_open(struct net_device *ndev)
diff -urN linux-2.5.66-bk4/drivers/net/mace.c linux-2.5.66-bk5/drivers/net/mace.c
--- linux-2.5.66-bk4/drivers/net/mace.c	Mon Mar 24 14:00:13 2003
+++ linux-2.5.66-bk5/drivers/net/mace.c	Mon Mar 31 12:50:22 2003
@@ -16,6 +16,7 @@
 #include <linux/timer.h>
 #include <linux/init.h>
 #include <linux/crc32.h>
+#include <linux/spinlock.h>
 #include <asm/prom.h>
 #include <asm/dbdma.h>
 #include <asm/io.h>
@@ -63,6 +64,7 @@
     int chipid;
     struct device_node* of_node;
     struct net_device *next_mace;
+    spinlock_t lock;
 };
 
 /*
@@ -203,6 +205,7 @@
 	memset((char *) mp->tx_cmds, 0,
 	       (NCMDS_TX*N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd));
 	init_timer(&mp->tx_timeout);
+	spin_lock_init(&mp->lock);
 	mp->timeout_active = 0;
 
 	if (port_aaui >= 0)
@@ -351,14 +354,14 @@
     volatile struct mace *mb = mp->mace;
     unsigned long flags;
 
-    save_flags(flags); cli();
+    spin_lock_irqsave(&mp->lock, flags);
 
     __mace_set_address(dev, addr);
 
     /* note: setting ADDRCHG clears ENRCV */
     out_8(&mb->maccc, mp->maccc);
 
-    restore_flags(flags);
+    spin_unlock_irqrestore(&mp->lock, flags);
     return 0;
 }
 
@@ -473,10 +476,7 @@
 static inline void mace_set_timeout(struct net_device *dev)
 {
     struct mace_data *mp = (struct mace_data *) dev->priv;
-    unsigned long flags;
 
-    save_flags(flags);
-    cli();
     if (mp->timeout_active)
 	del_timer(&mp->tx_timeout);
     mp->tx_timeout.expires = jiffies + TX_TIMEOUT;
@@ -484,7 +484,6 @@
     mp->tx_timeout.data = (unsigned long) dev;
     add_timer(&mp->tx_timeout);
     mp->timeout_active = 1;
-    restore_flags(flags);
 }
 
 static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
@@ -496,7 +495,7 @@
     int fill, next, len;
 
     /* see if there's a free slot in the tx ring */
-    save_flags(flags); cli();
+    spin_lock_irqsave(&mp->lock, flags);
     fill = mp->tx_fill;
     next = fill + 1;
     if (next >= N_TX_RING)
@@ -504,10 +503,10 @@
     if (next == mp->tx_empty) {
 	netif_stop_queue(dev);
 	mp->tx_fullup = 1;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&mp->lock, flags);
 	return 1;		/* can't take it at the moment */
     }
-    restore_flags(flags);
+    spin_unlock_irqrestore(&mp->lock, flags);
 
     /* partially fill in the dma command block */
     len = skb->len;
@@ -524,8 +523,7 @@
     out_le16(&np->command, DBDMA_STOP);
 
     /* poke the tx dma channel */
-    save_flags(flags);
-    cli();
+    spin_lock_irqsave(&mp->lock, flags);
     mp->tx_fill = next;
     if (!mp->tx_bad_runt && mp->tx_active < MAX_TX_ACTIVE) {
 	out_le16(&cp->xfer_status, 0);
@@ -538,7 +536,7 @@
 	next = 0;
     if (next == mp->tx_empty)
 	netif_stop_queue(dev);
-    restore_flags(flags);
+    spin_unlock_irqrestore(&mp->lock, flags);
 
     return 0;
 }
@@ -556,7 +554,9 @@
     volatile struct mace *mb = mp->mace;
     int i, j;
     u32 crc;
+    unsigned long flags;
 
+    spin_lock_irqsave(&mp->lock, flags);
     mp->maccc &= ~PROM;
     if (dev->flags & IFF_PROMISC) {
 	mp->maccc |= PROM;
@@ -598,6 +598,7 @@
     }
     /* reset maccc */
     out_8(&mb->maccc, mp->maccc);
+    spin_unlock_irqrestore(&mp->lock, flags);
 }
 
 static void mace_handle_misc_intrs(struct mace_data *mp, int intr)
@@ -630,8 +631,10 @@
     volatile struct dbdma_cmd *cp;
     int intr, fs, i, stat, x;
     int xcount, dstat;
+    unsigned long flags;
     /* static int mace_last_fs, mace_last_xcount; */
 
+    spin_lock_irqsave(&mp->lock, flags);
     intr = in_8(&mb->ir);		/* read interrupt register */
     in_8(&mb->xmtrc);			/* get retries */
     mace_handle_misc_intrs(mp, intr);
@@ -761,6 +764,7 @@
 	out_le32(&td->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
 	mace_set_timeout(dev);
     }
+    spin_unlock_irqrestore(&mp->lock, flags);
 }
 
 static void mace_tx_timeout(unsigned long data)
@@ -774,8 +778,7 @@
     unsigned long flags;
     int i;
 
-    save_flags(flags);
-    cli();
+    spin_lock_irqsave(&mp->lock, flags);
     mp->timeout_active = 0;
     if (mp->tx_active == 0 && !mp->tx_bad_runt)
 	goto out;
@@ -827,7 +830,7 @@
     out_8(&mb->maccc, mp->maccc);
 
 out:
-    restore_flags(flags);
+    spin_unlock_irqrestore(&mp->lock, flags);
 }
 
 static void mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs)
@@ -845,7 +848,9 @@
     unsigned frame_status;
     static int mace_lost_status;
     unsigned char *data;
+    unsigned long flags;
 
+    spin_lock_irqsave(&mp->lock, flags);
     for (i = mp->rx_empty; i != mp->rx_fill; ) {
 	cp = mp->rx_cmds + i;
 	stat = ld_le16(&cp->xfer_status);
@@ -941,6 +946,7 @@
 	out_le32(&rd->control, ((RUN|WAKE) << 16) | (RUN|WAKE));
 	mp->rx_fill = i;
     }
+    spin_unlock_irqrestore(&mp->lock, flags);
 }
 
 MODULE_AUTHOR("Paul Mackerras");
diff -urN linux-2.5.66-bk4/drivers/net/r8169.c linux-2.5.66-bk5/drivers/net/r8169.c
--- linux-2.5.66-bk4/drivers/net/r8169.c	Mon Mar 24 14:00:40 2003
+++ linux-2.5.66-bk5/drivers/net/r8169.c	Mon Mar 31 12:50:22 2003
@@ -1110,7 +1110,7 @@
 	.name		= MODULENAME,
 	.id_table	= rtl8169_pci_tbl,
 	.probe		= rtl8169_init_one,
-	.remove		= rtl8169_remove_one,
+	.remove		= __devexit_p(rtl8169_remove_one),
 	.suspend	= NULL,
 	.resume		= NULL,
 };
diff -urN linux-2.5.66-bk4/drivers/net/tulip/de4x5.c linux-2.5.66-bk5/drivers/net/tulip/de4x5.c
--- linux-2.5.66-bk4/drivers/net/tulip/de4x5.c	Mon Mar 24 13:59:54 2003
+++ linux-2.5.66-bk5/drivers/net/tulip/de4x5.c	Mon Mar 31 12:50:22 2003
@@ -452,7 +452,6 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/spinlock.h>
 #include <linux/crc32.h>
 #include <linux/netdevice.h>
diff -urN linux-2.5.66-bk4/drivers/net/tulip/dmfe.c linux-2.5.66-bk5/drivers/net/tulip/dmfe.c
--- linux-2.5.66-bk4/drivers/net/tulip/dmfe.c	Mon Mar 24 14:01:24 2003
+++ linux-2.5.66-bk5/drivers/net/tulip/dmfe.c	Mon Mar 31 12:50:22 2003
@@ -49,6 +49,10 @@
     support.  Updated PCI resource allocation.  Do not
     forget to unmap PCI mapped skbs.
 
+    Alan Cox <alan@redhat.com>
+    Added new PCI identifiers provided by Clear Zhang at ALi 
+    for their 1563 ethernet device.
+
     TODO
 
     Implement pci_driver::suspend() and pci_driver::resume()
@@ -75,7 +79,6 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
@@ -1975,6 +1978,7 @@
 	{ 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9102_ID },
 	{ 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9100_ID },
 	{ 0x1282, 0x9009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9009_ID },
+	{ 0x10B9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9102_ID },
 	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci, dmfe_pci_tbl);
diff -urN linux-2.5.66-bk4/fs/block_dev.c linux-2.5.66-bk5/fs/block_dev.c
--- linux-2.5.66-bk4/fs/block_dev.c	Mon Mar 24 14:01:53 2003
+++ linux-2.5.66-bk5/fs/block_dev.c	Mon Mar 31 12:50:23 2003
@@ -653,15 +653,16 @@
 	struct gendisk *disk = bdev->bd_disk;
 
 	down(&bdev->bd_sem);
-	switch (kind) {
-	case BDEV_FILE:
-	case BDEV_FS:
-		sync_blockdev(bd_inode->i_bdev);
-		break;
-	}
 	lock_kernel();
-	if (!--bdev->bd_openers)
+	if (!--bdev->bd_openers) {
+		switch (kind) {
+		case BDEV_FILE:
+		case BDEV_FS:
+			sync_blockdev(bd_inode->i_bdev);
+			break;
+		}
 		kill_bdev(bdev);
+	}
 	if (bdev->bd_contains == bdev) {
 		if (disk->fops->release)
 			ret = disk->fops->release(bd_inode, NULL);
diff -urN linux-2.5.66-bk4/fs/buffer.c linux-2.5.66-bk5/fs/buffer.c
--- linux-2.5.66-bk4/fs/buffer.c	Mon Mar 24 14:00:48 2003
+++ linux-2.5.66-bk5/fs/buffer.c	Mon Mar 31 12:50:23 2003
@@ -123,7 +123,9 @@
 	wait_queue_head_t *wqh = bh_waitq_head(bh);
 	DEFINE_WAIT(wait);
 
-	get_bh(bh);
+	if (atomic_read(&bh->b_count) == 0)
+		buffer_error();
+
 	do {
 		prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
 		if (buffer_locked(bh)) {
@@ -131,7 +133,6 @@
 			io_schedule();
 		}
 	} while (buffer_locked(bh));
-	put_bh(bh);
 	finish_wait(wqh, &wait);
 }
 
diff -urN linux-2.5.66-bk4/fs/char_dev.c linux-2.5.66-bk5/fs/char_dev.c
--- linux-2.5.66-bk4/fs/char_dev.c	Mon Mar 24 14:00:15 2003
+++ linux-2.5.66-bk5/fs/char_dev.c	Mon Mar 31 12:50:23 2003
@@ -115,7 +115,15 @@
 }
 
 /*
- * Register a single major with a specified minor range
+ * Register a single major with a specified minor range.
+ *
+ * If major == 0 this functions will dynamically allocate a major and return
+ * its number.
+ *
+ * If major > 0 this function will attempt to reserve the passed range of
+ * minors and will return zero on success.
+ *
+ * Returns a -ve errno on failure.
  */
 int register_chrdev_region(unsigned int major, unsigned int baseminor,
 			   int minorct, const char *name,
@@ -125,23 +133,27 @@
 	int ret = 0;
 	int i;
 
+	cd = kmalloc(sizeof(struct char_device_struct), GFP_KERNEL);
+	if (cd == NULL)
+		return -ENOMEM;
+
+	write_lock_irq(&chrdevs_lock);
+
 	/* temporary */
 	if (major == 0) {
-		read_lock(&chrdevs_lock);
-		for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--)
+		for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) {
 			if (chrdevs[i] == NULL)
 				break;
-		read_unlock(&chrdevs_lock);
+		}
 
-		if (i == 0)
-			return -EBUSY;
-		ret = major = i;
+		if (i == 0) {
+			ret = -EBUSY;
+			goto out;
+		}
+		major = i;
+		ret = major;
 	}
 
-	cd = kmalloc(sizeof(struct char_device_struct), GFP_KERNEL);
-	if (cd == NULL)
-		return -ENOMEM;
-
 	cd->major = major;
 	cd->baseminor = baseminor;
 	cd->minorct = minorct;
@@ -150,7 +162,6 @@
 
 	i = major_to_index(major);
 
-	write_lock(&chrdevs_lock);
 	for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
 		if ((*cp)->major > major ||
 		    ((*cp)->major == major && (*cp)->baseminor >= baseminor))
@@ -162,8 +173,10 @@
 		cd->next = *cp;
 		*cp = cd;
 	}
-	write_unlock(&chrdevs_lock);
-
+out:
+	write_unlock_irq(&chrdevs_lock);
+	if (ret < 0)
+		kfree(cd);
 	return ret;
 }
 
@@ -174,7 +187,8 @@
 }
 
 /* todo: make void - error printk here */
-int unregister_chrdev(unsigned int major, const char * name)
+int unregister_chrdev_region(unsigned int major, unsigned int baseminor,
+			     int minorct, const char *name)
 {
 	struct char_device_struct *cd, **cp;
 	int ret = 0;
@@ -182,9 +196,11 @@
 
 	i = major_to_index(major);
 
-	write_lock(&chrdevs_lock);
+	write_lock_irq(&chrdevs_lock);
 	for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
-		if ((*cp)->major == major)
+		if ((*cp)->major == major &&
+		    (*cp)->baseminor == baseminor &&
+		    (*cp)->minorct == minorct)
 			break;
 	if (!*cp || strcmp((*cp)->name, name))
 		ret = -EINVAL;
@@ -193,11 +209,16 @@
 		*cp = cd->next;
 		kfree(cd);
 	}
-	write_unlock(&chrdevs_lock);
+	write_unlock_irq(&chrdevs_lock);
 
 	return ret;
 }
 
+int unregister_chrdev(unsigned int major, const char *name)
+{
+	return unregister_chrdev_region(major, 0, 256, name);
+}
+
 /*
  * Called every time a character special file is opened
  */
diff -urN linux-2.5.66-bk4/fs/ext3/fsync.c linux-2.5.66-bk5/fs/ext3/fsync.c
--- linux-2.5.66-bk4/fs/ext3/fsync.c	Mon Mar 24 14:01:47 2003
+++ linux-2.5.66-bk5/fs/ext3/fsync.c	Mon Mar 31 12:50:23 2003
@@ -34,7 +34,7 @@
  * akpm: A new design for ext3_sync_file().
  *
  * This is only called from sys_fsync(), sys_fdatasync() and sys_msync().
- * There cannot be a transaction open by this task. (AKPM: quotas?)
+ * There cannot be a transaction open by this task.
  * Another task could have dirtied this inode.  Its data can be in any
  * state in the journalling system.
  *
@@ -50,19 +50,28 @@
 int ext3_sync_file(struct file * file, struct dentry *dentry, int datasync)
 {
 	struct inode *inode = dentry->d_inode;
-	int ret;
 
 	J_ASSERT(ext3_journal_current_handle() == 0);
 
 	/*
-	 * fsync_inode_buffers() just walks private_list and waits
-	 * on them.  It's a no-op for full data journalling because
-	 * private_list will be empty.
-	 * Really, we only need to start I/O on the dirty buffers -
-	 * we'll end up waiting on them in commit.
+	 * data=writeback:
+	 *  The caller's filemap_fdatawrite()/wait will sync the data.
+	 *  ext3_force_commit() will sync the metadata
+	 *
+	 * data=ordered:
+	 *  The caller's filemap_fdatawrite() will write the data and
+	 *  ext3_force_commit() will wait on the buffers.  Then the caller's
+	 *  filemap_fdatawait() will wait on the pages (but all IO is complete)
+	 *  Not pretty, but it works.
+	 *
+	 * data=journal:
+	 *  filemap_fdatawrite won't do anything (the buffers are clean).
+	 *  ext3_force_commit will write the file data into the journal and
+	 *  will wait on that.
+	 *  filemap_fdatawait() will encounter a ton of newly-dirtied pages
+	 *  (they were dirtied by commit).  But that's OK - the blocks are
+	 *  safe in-journal, which is all fsync() needs to ensure.
 	 */
-	ret = sync_mapping_buffers(inode->i_mapping);
 	ext3_force_commit(inode->i_sb);
-
-	return ret;
+	return 0;
 }
diff -urN linux-2.5.66-bk4/fs/ext3/super.c linux-2.5.66-bk5/fs/ext3/super.c
--- linux-2.5.66-bk4/fs/ext3/super.c	Mon Mar 24 14:01:25 2003
+++ linux-2.5.66-bk5/fs/ext3/super.c	Mon Mar 31 12:50:23 2003
@@ -1207,8 +1207,6 @@
 		goto failed_mount;
 	}
 
-	sb->s_maxbytes = ext3_max_size(sb->s_blocksize_bits);
-
 	hblock = bdev_hardsect_size(sb->s_bdev);
 	if (sb->s_blocksize != blocksize) {
 		/*
@@ -1240,6 +1238,8 @@
 		}
 	}
 
+	sb->s_maxbytes = ext3_max_size(sb->s_blocksize_bits);
+
 	if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV) {
 		sbi->s_inode_size = EXT3_GOOD_OLD_INODE_SIZE;
 		sbi->s_first_ino = EXT3_GOOD_OLD_FIRST_INO;
diff -urN linux-2.5.66-bk4/fs/inode.c linux-2.5.66-bk5/fs/inode.c
--- linux-2.5.66-bk4/fs/inode.c	Mon Mar 24 14:01:48 2003
+++ linux-2.5.66-bk5/fs/inode.c	Mon Mar 31 12:50:23 2003
@@ -1260,7 +1260,7 @@
 		init_waitqueue_head(&i_wait_queue_heads[i].wqh);
 
 	mempages >>= (14 - PAGE_SHIFT);
-	mempages *= sizeof(struct list_head);
+	mempages *= sizeof(struct hlist_head);
 	for (order = 0; ((1UL << order) << PAGE_SHIFT) < mempages; order++)
 		;
 
diff -urN linux-2.5.66-bk4/fs/jbd/checkpoint.c linux-2.5.66-bk5/fs/jbd/checkpoint.c
--- linux-2.5.66-bk4/fs/jbd/checkpoint.c	Mon Mar 24 14:00:10 2003
+++ linux-2.5.66-bk5/fs/jbd/checkpoint.c	Mon Mar 31 12:50:23 2003
@@ -260,7 +260,6 @@
 {
 	transaction_t *transaction, *last_transaction, *next_transaction;
 	int result;
-	int target;
 	int batch_count = 0;
 	struct buffer_head *bhs[NR_BATCH];
 
@@ -284,8 +283,6 @@
 	 * AKPM: check this code.  I had a feeling a while back that it
 	 * degenerates into a busy loop at unmount time.
 	 */
-	target = (journal->j_last - journal->j_first) / 4;
-
 	spin_lock(&journal_datalist_lock);
 repeat:
 	transaction = journal->j_checkpoint_transactions;
@@ -443,11 +440,8 @@
 			struct journal_head *last_jh = jh->b_cpprev;
 			struct journal_head *next_jh = jh;
 			do {
-				struct buffer_head *bh;
-
 				jh = next_jh;
 				next_jh = jh->b_cpnext;
-				bh = jh2bh(jh);
 				ret += __try_to_free_cp_buf(jh);
 			} while (jh != last_jh);
 		}
diff -urN linux-2.5.66-bk4/fs/nfs/read.c linux-2.5.66-bk5/fs/nfs/read.c
--- linux-2.5.66-bk4/fs/nfs/read.c	Mon Mar 31 12:50:18 2003
+++ linux-2.5.66-bk5/fs/nfs/read.c	Mon Mar 31 12:50:23 2003
@@ -252,8 +252,7 @@
 void
 nfs_readpage_result(struct rpc_task *task)
 {
-	struct nfs_read_data	*data = (struct nfs_read_data *) task->tk_calldata;
-	struct nfs_fattr	*fattr = &data->fattr;
+	struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata;
 	unsigned int count = data->res.count;
 
 	dprintk("NFS: %4d nfs_readpage_result, (status %d)\n",
diff -urN linux-2.5.66-bk4/fs/sysfs/inode.c linux-2.5.66-bk5/fs/sysfs/inode.c
--- linux-2.5.66-bk4/fs/sysfs/inode.c	Mon Mar 24 14:01:21 2003
+++ linux-2.5.66-bk5/fs/sysfs/inode.c	Mon Mar 31 12:50:23 2003
@@ -97,7 +97,7 @@
 				 atomic_read(&victim->d_count));
 
 			simple_unlink(dir->d_inode,victim);
-
+			d_delete(victim);
 		}
 		/*
 		 * Drop reference from sysfs_get_dentry() above.
diff -urN linux-2.5.66-bk4/include/asm-i386/timer.h linux-2.5.66-bk5/include/asm-i386/timer.h
--- linux-2.5.66-bk4/include/asm-i386/timer.h	Mon Mar 24 14:00:11 2003
+++ linux-2.5.66-bk5/include/asm-i386/timer.h	Mon Mar 31 12:50:23 2003
@@ -4,14 +4,14 @@
 /**
  * struct timer_ops - used to define a timer source
  *
- * @init: Probes and initializes the timer.  Returns 0 on success, anything
- *	else on failure.
+ * @init: Probes and initializes the timer. Takes clock= override 
+ *  string as an argument. Returns 0 on success, anything else on failure.
  * @mark_offset: called by the timer interrupt
  * @get_offset: called by gettimeofday().  Returns the number of ms since the
  *	last timer intruupt.
  */
 struct timer_opts{
-	int (*init)(void);
+	int (*init)(char *override);
 	void (*mark_offset)(void);
 	unsigned long (*get_offset)(void);
 	void (*delay)(unsigned long);
diff -urN linux-2.5.66-bk4/include/linux/buffer_head.h linux-2.5.66-bk5/include/linux/buffer_head.h
--- linux-2.5.66-bk4/include/linux/buffer_head.h	Mon Mar 24 13:59:54 2003
+++ linux-2.5.66-bk5/include/linux/buffer_head.h	Mon Mar 31 12:50:23 2003
@@ -60,6 +60,12 @@
 	struct list_head b_assoc_buffers; /* associated with another mapping */
 };
 
+/*
+ * Debug
+ */
+
+void __buffer_error(char *file, int line);
+#define buffer_error() __buffer_error(__FILE__, __LINE__)
 
 /*
  * macro tricks to expand the set_buffer_foo(), clear_buffer_foo()
@@ -183,7 +189,8 @@
  */
 int try_to_release_page(struct page * page, int gfp_mask);
 int block_invalidatepage(struct page *page, unsigned long offset);
-int block_write_full_page(struct page *page, get_block_t *get_block, struct writeback_control *wbc);
+int block_write_full_page(struct page *page, get_block_t *get_block,
+				struct writeback_control *wbc);
 int block_read_full_page(struct page*, get_block_t*);
 int block_prepare_write(struct page*, unsigned, unsigned, get_block_t*);
 int cont_prepare_write(struct page*, unsigned, unsigned, get_block_t*,
@@ -232,12 +239,14 @@
 		__bforget(bh);
 }
 
-static inline struct buffer_head *sb_bread(struct super_block *sb, sector_t block)
+static inline struct buffer_head *
+sb_bread(struct super_block *sb, sector_t block)
 {
 	return __bread(sb->s_bdev, block, sb->s_blocksize);
 }
 
-static inline struct buffer_head *sb_getblk(struct super_block *sb, sector_t block)
+static inline struct buffer_head *
+sb_getblk(struct super_block *sb, sector_t block)
 {
 	return __getblk(sb->s_bdev, block, sb->s_blocksize);
 }
@@ -256,9 +265,14 @@
 	bh->b_blocknr = block;
 }
 
+/*
+ * Calling wait_on_buffer() for a zero-ref buffer is illegal, so we call into
+ * __wait_on_buffer() just to trip a debug check.  Because debug code in inline
+ * functions is bloaty.
+ */
 static inline void wait_on_buffer(struct buffer_head *bh)
 {
-	if (buffer_locked(bh))
+	if (buffer_locked(bh) || atomic_read(&bh->b_count) == 0)
 		__wait_on_buffer(bh);
 }
 
@@ -268,11 +282,4 @@
 		__wait_on_buffer(bh);
 }
 
-/*
- * Debug
- */
-
-void __buffer_error(char *file, int line);
-#define buffer_error() __buffer_error(__FILE__, __LINE__)
-
 #endif /* _LINUX_BUFFER_HEAD_H */
diff -urN linux-2.5.66-bk4/include/linux/device.h linux-2.5.66-bk5/include/linux/device.h
--- linux-2.5.66-bk4/include/linux/device.h	Mon Mar 24 14:01:25 2003
+++ linux-2.5.66-bk5/include/linux/device.h	Mon Mar 31 12:50:23 2003
@@ -35,7 +35,7 @@
 #define DEVICE_NAME_SIZE	50
 #define DEVICE_NAME_HALF	__stringify(20)	/* Less than half to accommodate slop */
 #define DEVICE_ID_SIZE		32
-#define BUS_ID_SIZE		16
+#define BUS_ID_SIZE		20
 
 
 enum {
diff -urN linux-2.5.66-bk4/include/linux/fs.h linux-2.5.66-bk5/include/linux/fs.h
--- linux-2.5.66-bk4/include/linux/fs.h	Mon Mar 24 14:00:10 2003
+++ linux-2.5.66-bk5/include/linux/fs.h	Mon Mar 31 12:50:23 2003
@@ -1060,6 +1060,8 @@
 extern int register_chrdev(unsigned int, const char *,
 			   struct file_operations *);
 extern int unregister_chrdev(unsigned int, const char *);
+extern int unregister_chrdev_region(unsigned int, unsigned int, int,
+				    const char *);
 extern int chrdev_open(struct inode *, struct file *);
 
 /* fs/block_dev.c */
diff -urN linux-2.5.66-bk4/include/linux/highmem.h linux-2.5.66-bk5/include/linux/highmem.h
--- linux-2.5.66-bk4/include/linux/highmem.h	Mon Mar 24 14:01:14 2003
+++ linux-2.5.66-bk5/include/linux/highmem.h	Mon Mar 31 12:50:23 2003
@@ -18,7 +18,11 @@
 
 static inline unsigned int nr_free_highpages(void) { return 0; }
 
-static inline void *kmap(struct page *page) { return page_address(page); }
+static inline void *kmap(struct page *page)
+{
+	might_sleep();
+	return page_address(page);
+}
 
 #define kunmap(page) do { (void) (page); } while (0)
 
diff -urN linux-2.5.66-bk4/include/linux/idr.h linux-2.5.66-bk5/include/linux/idr.h
--- linux-2.5.66-bk4/include/linux/idr.h	Mon Mar 24 13:59:59 2003
+++ linux-2.5.66-bk5/include/linux/idr.h	Mon Mar 31 12:50:23 2003
@@ -13,40 +13,44 @@
 
 #define RESERVED_ID_BITS 8
 
-#if     BITS_PER_LONG == 32
-#define IDR_BITS 5
-#define IDR_FULL 0xffffffff
+#if BITS_PER_LONG == 32
+# define IDR_BITS 5
+# define IDR_FULL 0xffffffff
 #elif BITS_PER_LONG == 64
-#define IDR_BITS 6
-#define IDR_FULL 0xffffffffffffffff
+# define IDR_BITS 6
+# define IDR_FULL 0xffffffffffffffff
 #else
-#error "BITS_PER_LONG is not 32 or 64"
+# error "BITS_PER_LONG is not 32 or 64"
 #endif
 
 #define IDR_MASK ((1 << IDR_BITS)-1)
 
-/* Leave the possibility of an incomplete final layer */
-#define MAX_LEVEL (BITS_PER_LONG - RESERVED_ID_BITS + IDR_BITS - 1) / IDR_BITS
-#define MAX_ID_SHIFT (BITS_PER_LONG - RESERVED_ID_BITS)
-#define MAX_ID_BIT (1L << MAX_ID_SHIFT)
+/* Define the size of the id's */
+#define BITS_PER_INT (sizeof(int)*8)
+
+#define MAX_ID_SHIFT (BITS_PER_INT - RESERVED_ID_BITS)
+#define MAX_ID_BIT (1 << MAX_ID_SHIFT)
 #define MAX_ID_MASK (MAX_ID_BIT - 1)
 
+/* Leave the possibility of an incomplete final layer */
+#define MAX_LEVEL (MAX_ID_SHIFT + IDR_BITS - 1) / IDR_BITS
+
 /* Number of id_layer structs to leave in free list */
 #define IDR_FREE_MAX MAX_LEVEL + MAX_LEVEL
 
 struct idr_layer {
-	unsigned long	        bitmap;     // A zero bit means "space here"
-	int                     count;      // When zero, we can release it
-	struct idr_layer       *ary[1<<IDR_BITS];
+	unsigned long		 bitmap;	/* A zero bit means "space here" */
+	struct idr_layer	*ary[1<<IDR_BITS];
+	int			 count;		/* When zero, we can release it */
 };
 
 struct idr {
 	struct idr_layer *top;
-	int		  layers;
-	long		  count;
 	struct idr_layer *id_free;
-	int               id_free_cnt;
-	spinlock_t        lock;
+	long		  count;
+	int		  layers;
+	int		  id_free_cnt;
+	spinlock_t	  lock;
 };
 
 /*
diff -urN linux-2.5.66-bk4/include/linux/if_bonding.h linux-2.5.66-bk5/include/linux/if_bonding.h
--- linux-2.5.66-bk4/include/linux/if_bonding.h	Mon Mar 24 14:01:17 2003
+++ linux-2.5.66-bk5/include/linux/if_bonding.h	Mon Mar 31 12:50:23 2003
@@ -54,6 +54,15 @@
 
 #define BOND_DEFAULT_MAX_BONDS  1   /* Default maximum number of devices to support */
 
+#define BOND_MULTICAST_DISABLED 0
+#define BOND_MULTICAST_ACTIVE   1
+#define BOND_MULTICAST_ALL      2
+
+struct bond_parm_tbl {
+	char *modename;
+	int mode;
+};
+
 typedef struct ifbond {
 	__s32 bond_mode;
 	__s32 num_slaves;
diff -urN linux-2.5.66-bk4/include/linux/kmalloc_sizes.h linux-2.5.66-bk5/include/linux/kmalloc_sizes.h
--- linux-2.5.66-bk4/include/linux/kmalloc_sizes.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk5/include/linux/kmalloc_sizes.h	Mon Mar 31 12:50:23 2003
@@ -0,0 +1,33 @@
+#if (PAGE_SIZE == 4096)
+	CACHE(32)
+#endif
+	CACHE(64)
+#if L1_CACHE_BYTES < 64
+	CACHE(96)
+#endif
+	CACHE(128)
+#if L1_CACHE_BYTES < 128
+	CACHE(192)
+#endif
+	CACHE(256)
+	CACHE(512)
+	CACHE(1024)
+	CACHE(2048)
+	CACHE(4096)
+	CACHE(8192)
+	CACHE(16384)
+	CACHE(32768)
+	CACHE(65536)
+	CACHE(131072)
+#ifndef CONFIG_MMU
+	CACHE(262144)
+	CACHE(524288)
+	CACHE(1048576)
+#ifdef CONFIG_LARGE_ALLOCS
+	CACHE(2097152)
+	CACHE(4194304)
+	CACHE(8388608)
+	CACHE(16777216)
+	CACHE(33554432)
+#endif /* CONFIG_LARGE_ALLOCS */
+#endif /* CONFIG_MMU */
diff -urN linux-2.5.66-bk4/include/linux/swap.h linux-2.5.66-bk5/include/linux/swap.h
--- linux-2.5.66-bk4/include/linux/swap.h	Mon Mar 24 13:59:54 2003
+++ linux-2.5.66-bk5/include/linux/swap.h	Mon Mar 31 12:50:23 2003
@@ -177,22 +177,19 @@
 					struct pte_chain *));
 void FASTCALL(page_remove_rmap(struct page *, pte_t *));
 int FASTCALL(try_to_unmap(struct page *));
-int FASTCALL(page_over_rsslimit(struct page *));
-
-/* return values of try_to_unmap */
-#define	SWAP_SUCCESS	0
-#define	SWAP_AGAIN	1
-#define	SWAP_FAIL	2
-#define	SWAP_ERROR	3
 
 /* linux/mm/shmem.c */
 extern int shmem_unuse(swp_entry_t entry, struct page *page);
-
 #else
-#define page_referenced(page) \
-	TestClearPageReferenced(page)
+#define page_referenced(page)	TestClearPageReferenced(page)
+#define try_to_unmap(page)	SWAP_FAIL
 #endif /* CONFIG_MMU */
 
+/* return values of try_to_unmap */
+#define	SWAP_SUCCESS	0
+#define	SWAP_AGAIN	1
+#define	SWAP_FAIL	2
+
 #ifdef CONFIG_SWAP
 /* linux/mm/page_io.c */
 extern int swap_readpage(struct file *, struct page *);
@@ -203,7 +200,6 @@
 extern struct address_space swapper_space;
 #define total_swapcache_pages  swapper_space.nrpages
 extern void show_swap_cache_info(void);
-extern int add_to_swap_cache(struct page *, swp_entry_t);
 extern int add_to_swap(struct page *);
 extern void __delete_from_swap_cache(struct page *);
 extern void delete_from_swap_cache(struct page *);
diff -urN linux-2.5.66-bk4/include/net/irda/af_irda.h linux-2.5.66-bk5/include/net/irda/af_irda.h
--- linux-2.5.66-bk4/include/net/irda/af_irda.h	Mon Mar 24 14:01:24 2003
+++ linux-2.5.66-bk5/include/net/irda/af_irda.h	Mon Mar 31 12:50:23 2003
@@ -52,8 +52,8 @@
 	__u8  max_header_size;
 	struct qos_info qos_tx;
 
-	__u16 mask;           /* Hint bits mask */
-	__u16 hints;          /* Hint bits */
+	__u16_host_order mask;           /* Hint bits mask */
+	__u16_host_order hints;          /* Hint bits */
 
 	void *ckey;           /* IrLMP client handle */
 	void *skey;           /* IrLMP service handle */
@@ -63,7 +63,7 @@
 	struct ias_value *ias_result; /* Result of remote IAS query */
 
 	hashbin_t *cachelog;		/* Result of discovery query */
-	struct discovery_t *cachediscovery;	/* Result of selective discovery query */
+	__u32 cachedaddr;	/* Result of selective discovery query */
 
 	int nslots;           /* Number of slots to use for discovery */
 
diff -urN linux-2.5.66-bk4/include/net/irda/discovery.h linux-2.5.66-bk5/include/net/irda/discovery.h
--- linux-2.5.66-bk4/include/net/irda/discovery.h	Mon Mar 24 14:00:55 2003
+++ linux-2.5.66-bk5/include/net/irda/discovery.h	Mon Mar 31 12:50:23 2003
@@ -46,12 +46,20 @@
  *  little endian format. A little endian machine stores MSB of word in
  *  byte[1] and LSB in byte[0]. A big endian machine stores MSB in byte[0] 
  *  and LSB in byte[1].
+ *
+ * This structure is used in the code for things that are endian neutral
+ * but that fit in a word so that we can manipulate them efficiently.
+ * By endian neutral, I mean things that are really an array of bytes,
+ * and always used as such, for example the hint bits. Jean II
  */
 typedef union {
 	__u16 word;
 	__u8  byte[2];
 } __u16_host_order;
 
+/* Same purpose, different application */
+#define u16ho(array) (* ((__u16 *) array))
+
 /* Types of discovery */
 typedef enum {
 	DISCOVERY_LOG,		/* What's in our discovery log */
@@ -62,30 +70,31 @@
 
 #define NICKNAME_MAX_LEN 21
 
+/* Basic discovery information about a peer */
+typedef struct irda_device_info		discinfo_t;	/* linux/irda.h */
+
 /*
  * The DISCOVERY structure is used for both discovery requests and responses
  */
 typedef struct discovery_t {
-	irda_queue_t q;          /* Must be first! */
+	irda_queue_t	q;		/* Must be first! */
+
+	discinfo_t	data;		/* Basic discovery information */
+	int		name_len;	/* Lenght of nickname */
 
-	__u32      saddr;        /* Which link the device was discovered */
-	__u32      daddr;        /* Remote device address */
-	LAP_REASON condition;    /* More info about the discovery */
-
-	__u16_host_order hints;  /* Discovery hint bits */
-	__u8       charset;      /* Encoding of nickname */
-	char       nickname[22]; /* The name of the device (21 bytes + \0) */
-	int        name_len;     /* Lenght of nickname */
-
-	int        gen_addr_bit; /* Need to generate a new device address? */
-	int        nslots;       /* Number of slots to use when discovering */
-	unsigned long timestamp; /* Time discovered */
-	unsigned long first_timestamp; /* First time discovered */
+	LAP_REASON	condition;	/* More info about the discovery */
+	int		gen_addr_bit;	/* Need to generate a new device
+					 * address? */
+	int		nslots;		/* Number of slots to use when
+					 * discovering */
+	unsigned long	timestamp;	/* Last time discovered */
+	unsigned long	firststamp;	/* First time discovered */
 } discovery_t;
 
 void irlmp_add_discovery(hashbin_t *cachelog, discovery_t *discovery);
 void irlmp_add_discovery_log(hashbin_t *cachelog, hashbin_t *log);
 void irlmp_expire_discoveries(hashbin_t *log, __u32 saddr, int force);
-struct irda_device_info *irlmp_copy_discoveries(hashbin_t *log, int *pn, __u16 mask);
+struct irda_device_info *irlmp_copy_discoveries(hashbin_t *log, int *pn,
+						__u16 mask, int old_entries);
 
 #endif
diff -urN linux-2.5.66-bk4/include/net/irda/irlan_client.h linux-2.5.66-bk5/include/net/irda/irlan_client.h
--- linux-2.5.66-bk4/include/net/irda/irlan_client.h	Mon Mar 24 14:01:15 2003
+++ linux-2.5.66-bk5/include/net/irda/irlan_client.h	Mon Mar 31 12:50:23 2003
@@ -34,7 +34,7 @@
 #include <net/irda/irlan_event.h>
 
 void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout);
-void irlan_client_discovery_indication(discovery_t *, DISCOVERY_MODE, void *);
+void irlan_client_discovery_indication(discinfo_t *, DISCOVERY_MODE, void *);
 void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr);
 
 void irlan_client_open_ctrl_tsap( struct irlan_cb *self);
diff -urN linux-2.5.66-bk4/include/net/irda/irlmp.h linux-2.5.66-bk5/include/net/irda/irlmp.h
--- linux-2.5.66-bk4/include/net/irda/irlmp.h	Mon Mar 24 13:59:54 2003
+++ linux-2.5.66-bk5/include/net/irda/irlmp.h	Mon Mar 31 12:50:23 2003
@@ -58,7 +58,7 @@
 #define LM_IDLE_TIMEOUT     2*HZ /* 2 seconds for now */
 
 typedef enum {
-	S_PNP,
+	S_PNP = 0,
 	S_PDA,
 	S_COMPUTER,
 	S_PRINTER,
@@ -72,22 +72,24 @@
 	S_END,
 } SERVICE;
 
-typedef void (*DISCOVERY_CALLBACK1) (discovery_t *, DISCOVERY_MODE, void *);
-typedef void (*DISCOVERY_CALLBACK2) (hashbin_t *, void *);
+/* For selective discovery */
+typedef void (*DISCOVERY_CALLBACK1) (discinfo_t *, DISCOVERY_MODE, void *);
+/* For expiry (the same) */
+typedef void (*DISCOVERY_CALLBACK2) (discinfo_t *, DISCOVERY_MODE, void *);
 
 typedef struct {
 	irda_queue_t queue; /* Must be first */
 
-	__u16 hints; /* Hint bits */
+	__u16_host_order hints; /* Hint bits */
 } irlmp_service_t;
 
 typedef struct {
 	irda_queue_t queue; /* Must be first */
 
-	__u16 hint_mask;
+	__u16_host_order hint_mask;
 
 	DISCOVERY_CALLBACK1 disco_callback;	/* Selective discovery */
-	DISCOVERY_CALLBACK1 expir_callback;	/* Selective expiration */
+	DISCOVERY_CALLBACK2 expir_callback;	/* Selective expiration */
 	void *priv;                /* Used to identify client */
 } irlmp_client_t;
 
@@ -199,11 +201,11 @@
 void *irlmp_register_service(__u16 hints);
 int irlmp_unregister_service(void *handle);
 void *irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb,
-			    DISCOVERY_CALLBACK1 expir_clb, void *priv);
+			    DISCOVERY_CALLBACK2 expir_clb, void *priv);
 int irlmp_unregister_client(void *handle);
 int irlmp_update_client(void *handle, __u16 hint_mask, 
 			DISCOVERY_CALLBACK1 disco_clb,
-			DISCOVERY_CALLBACK1 expir_clb, void *priv);
+			DISCOVERY_CALLBACK2 expir_clb, void *priv);
 
 void irlmp_register_link(struct irlap_cb *, __u32 saddr, notify_t *);
 void irlmp_unregister_link(__u32 saddr);
@@ -222,11 +224,11 @@
 
 void irlmp_discovery_confirm(hashbin_t *discovery_log, DISCOVERY_MODE mode);
 void irlmp_discovery_request(int nslots);
-struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask, int nslots);
+discinfo_t *irlmp_get_discoveries(int *pn, __u16 mask, int nslots);
 void irlmp_do_expiry(void);
 void irlmp_do_discovery(int nslots);
 discovery_t *irlmp_get_discovery_response(void);
-void irlmp_discovery_expiry(discovery_t *expiry);
+void irlmp_discovery_expiry(discinfo_t *expiry, int number);
 
 int  irlmp_data_request(struct lsap_cb *, struct sk_buff *);
 void irlmp_data_indication(struct lsap_cb *, struct sk_buff *);
diff -urN linux-2.5.66-bk4/init/main.c linux-2.5.66-bk5/init/main.c
--- linux-2.5.66-bk4/init/main.c	Mon Mar 24 14:00:08 2003
+++ linux-2.5.66-bk5/init/main.c	Mon Mar 31 12:50:23 2003
@@ -463,6 +463,15 @@
 	rest_init();
 }
 
+int __initdata initcall_debug;
+
+static int __init initcall_debug_setup(char *str)
+{
+	initcall_debug = 1;
+	return 1;
+}
+__setup("initcall_debug", initcall_debug_setup);
+
 struct task_struct *child_reaper = &init_task;
 
 extern initcall_t __initcall_start, __initcall_end;
@@ -470,12 +479,30 @@
 static void __init do_initcalls(void)
 {
 	initcall_t *call;
+	int count = preempt_count();
+
+	for (call = &__initcall_start; call < &__initcall_end; call++) {
+		char *msg;
+
+		if (initcall_debug)
+			printk("calling initcall 0x%p\n", *call);
 
-	call = &__initcall_start;
-	do {
 		(*call)();
-		call++;
-	} while (call < &__initcall_end);
+
+		msg = NULL;
+		if (preempt_count() != count) {
+			msg = "preemption imbalance";
+			preempt_count() = count;
+		}
+		if (irqs_disabled()) {
+			msg = "disabled interrupts";
+			local_irq_enable();
+		}
+		if (msg) {
+			printk("error in initcall at 0x%p: "
+				"returned with %s\n", *call, msg);
+		}
+	}
 
 	/* Make sure there is no pending stuff from the initcall sequence */
 	flush_scheduled_work();
diff -urN linux-2.5.66-bk4/kernel/posix-timers.c linux-2.5.66-bk5/kernel/posix-timers.c
--- linux-2.5.66-bk4/kernel/posix-timers.c	Mon Mar 24 14:00:40 2003
+++ linux-2.5.66-bk5/kernel/posix-timers.c	Mon Mar 31 12:50:23 2003
@@ -230,8 +230,10 @@
 		return;
 	}
 	posix_get_now(&now);
-	while (posix_time_before(&timr->it_timer, &now))
+	do {
 		posix_bump_timer(timr);
+	}while (posix_time_before(&timr->it_timer, &now));
+
 	timr->it_overrun_last = timr->it_overrun;
 	timr->it_overrun = -1;
 	timr->it_requeue_pending = 0;
@@ -587,7 +589,6 @@
 void inline
 do_timer_gettime(struct k_itimer *timr, struct itimerspec *cur_setting)
 {
-	long sub_expires;
 	unsigned long expires;
 	struct now_struct now;
 
@@ -607,7 +608,7 @@
 				posix_bump_timer(timr);
 		else
 			if (!timer_pending(&timr->it_timer))
-				sub_expires = expires = 0;
+				expires = 0;
 		if (expires)
 			expires -= now.jiffies;
 	}
diff -urN linux-2.5.66-bk4/lib/idr.c linux-2.5.66-bk5/lib/idr.c
--- linux-2.5.66-bk4/lib/idr.c	Mon Mar 24 14:00:19 2003
+++ linux-2.5.66-bk5/lib/idr.c	Mon Mar 31 12:50:23 2003
@@ -150,7 +150,7 @@
 
 static inline int sub_alloc(struct idr *idp, int shift, void *ptr)
 {
-	long n, v = 0;
+	int n, v = 0;
 	struct idr_layer *p;
 	struct idr_layer **pa[MAX_LEVEL];
 	struct idr_layer ***paa = &pa[0];
@@ -211,7 +211,7 @@
 
 int idr_get_new(struct idr *idp, void *ptr)
 {
-	long v;
+	int v;
 	
 	if (idp->id_free_cnt < idp->layers + 1) 
 		return (-1);
diff -urN linux-2.5.66-bk4/mm/fremap.c linux-2.5.66-bk5/mm/fremap.c
--- linux-2.5.66-bk4/mm/fremap.c	Mon Mar 24 13:59:54 2003
+++ linux-2.5.66-bk5/mm/fremap.c	Mon Mar 31 12:50:23 2003
@@ -17,7 +17,8 @@
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 
-static inline int zap_pte(struct mm_struct *mm, pte_t *ptep)
+static inline int zap_pte(struct mm_struct *mm, struct vm_area_struct *vma,
+			unsigned long addr, pte_t *ptep)
 {
 	pte_t pte = *ptep;
 
@@ -26,6 +27,7 @@
 	if (pte_present(pte)) {
 		unsigned long pfn = pte_pfn(pte);
 
+		flush_cache_page(vma, addr);
 		pte = ptep_get_and_clear(ptep);
 		if (pfn_valid(pfn)) {
 			struct page *page = pfn_to_page(pfn);
@@ -54,7 +56,7 @@
 		unsigned long addr, struct page *page, pgprot_t prot)
 {
 	int err = -ENOMEM, flush;
-	pte_t *pte, entry;
+	pte_t *pte;
 	pgd_t *pgd;
 	pmd_t *pmd;
 	struct pte_chain *pte_chain;
@@ -73,13 +75,12 @@
 	if (!pte)
 		goto err_unlock;
 
-	flush = zap_pte(mm, pte);
+	flush = zap_pte(mm, vma, addr, pte);
 
 	mm->rss++;
 	flush_page_to_ram(page);
 	flush_icache_page(vma, page);
-	entry = mk_pte(page, prot);
-	set_pte(pte, entry);
+	set_pte(pte, mk_pte(page, prot));
 	pte_chain = page_add_rmap(page, pte, pte_chain);
 	pte_unmap(pte);
 	if (flush)
diff -urN linux-2.5.66-bk4/mm/highmem.c linux-2.5.66-bk5/mm/highmem.c
--- linux-2.5.66-bk4/mm/highmem.c	Mon Mar 24 14:00:50 2003
+++ linux-2.5.66-bk5/mm/highmem.c	Mon Mar 31 12:50:23 2003
@@ -381,7 +381,7 @@
 		/*
 		 * is destination page below bounce pfn?
 		 */
-		if ((page - page_zone(page)->zone_mem_map) + (page_zone(page)->zone_start_pfn) < q->bounce_pfn)
+		if (page_to_pfn(page) < q->bounce_pfn)
 			continue;
 
 		/*
diff -urN linux-2.5.66-bk4/mm/mmap.c linux-2.5.66-bk5/mm/mmap.c
--- linux-2.5.66-bk4/mm/mmap.c	Mon Mar 24 14:00:50 2003
+++ linux-2.5.66-bk5/mm/mmap.c	Mon Mar 31 12:50:23 2003
@@ -82,14 +82,6 @@
 		free += nr_swap_pages;
 
 		/*
-		 * This double-counts: the nrpages are both in the
-		 * page-cache and in the swapper space. At the same time,
-		 * this compensates for the swap-space over-allocation
-		 * (ie "nr_swap_pages" being too small).
-		 */
-		free += total_swapcache_pages;
-
-		/*
 		 * The code below doesn't account for free space in the
 		 * inode and dentry slab cache, slab cache fragmentation,
 		 * inodes and dentries which will become freeable under
@@ -374,6 +366,8 @@
 can_vma_merge_before(struct vm_area_struct *vma, unsigned long vm_flags,
 	struct file *file, unsigned long vm_pgoff, unsigned long size)
 {
+	if ((vma->vm_flags & VM_DONTEXPAND) || (vm_flags & VM_DONTEXPAND))
+		return 0;
 	if (vma->vm_file == file && vma->vm_flags == vm_flags) {
 		if (!file)
 			return 1;	/* anon mapping */
@@ -391,6 +385,8 @@
 can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags,
 	struct file *file, unsigned long vm_pgoff)
 {
+	if ((vma->vm_flags & VM_DONTEXPAND) || (vm_flags & VM_DONTEXPAND))
+		return 0;
 	if (vma->vm_file == file && vma->vm_flags == vm_flags) {
 		unsigned long vma_size;
 
diff -urN linux-2.5.66-bk4/mm/page_alloc.c linux-2.5.66-bk5/mm/page_alloc.c
--- linux-2.5.66-bk4/mm/page_alloc.c	Mon Mar 24 13:59:57 2003
+++ linux-2.5.66-bk5/mm/page_alloc.c	Mon Mar 31 12:50:23 2003
@@ -106,7 +106,7 @@
  * This is only for debug at present.  This usage means that zero-order pages
  * may not be compound.
  */
-static void prep_compound_page(struct page *page, int order)
+static void prep_compound_page(struct page *page, unsigned long order)
 {
 	int i;
 	int nr_pages = 1 << order;
@@ -121,7 +121,7 @@
 	}
 }
 
-static void destroy_compound_page(struct page *page, int order)
+static void destroy_compound_page(struct page *page, unsigned long order)
 {
 	int i;
 	int nr_pages = 1 << order;
diff -urN linux-2.5.66-bk4/mm/rmap.c linux-2.5.66-bk5/mm/rmap.c
--- linux-2.5.66-bk4/mm/rmap.c	Mon Mar 24 14:01:26 2003
+++ linux-2.5.66-bk5/mm/rmap.c	Mon Mar 31 12:50:23 2003
@@ -415,7 +415,6 @@
  * SWAP_SUCCESS	- we succeeded in removing all mappings
  * SWAP_AGAIN	- we missed a trylock, try again later
  * SWAP_FAIL	- the page is unswappable
- * SWAP_ERROR	- an error occurred
  */
 int try_to_unmap(struct page * page)
 {
@@ -483,9 +482,6 @@
 			case SWAP_FAIL:
 				ret = SWAP_FAIL;
 				goto out;
-			case SWAP_ERROR:
-				ret = SWAP_ERROR;
-				goto out;
 			}
 		}
 	}
diff -urN linux-2.5.66-bk4/mm/shmem.c linux-2.5.66-bk5/mm/shmem.c
--- linux-2.5.66-bk4/mm/shmem.c	Mon Mar 24 14:00:20 2003
+++ linux-2.5.66-bk5/mm/shmem.c	Mon Mar 31 12:50:23 2003
@@ -33,6 +33,7 @@
 #include <linux/mount.h>
 #include <linux/writeback.h>
 #include <linux/vfs.h>
+#include <linux/blkdev.h>
 #include <asm/uaccess.h>
 
 /* This magic number is used in glibc for posix shared memory */
@@ -486,6 +487,16 @@
 	}
 done2:
 	BUG_ON(info->swapped > info->next_index);
+	if (inode->i_mapping->nrpages) {
+		/*
+		 * Call truncate_inode_pages again: racing shmem_unuse_inode
+		 * may have swizzled a page in from swap since vmtruncate or
+		 * generic_delete_inode did it, before we lowered next_index.
+		 */
+		spin_unlock(&info->lock);
+		truncate_inode_pages(inode->i_mapping, inode->i_size);
+		spin_lock(&info->lock);
+	}
 	shmem_recalc_inode(inode);
 	spin_unlock(&info->lock);
 }
@@ -828,8 +839,7 @@
 			SetPageUptodate(filepage);
 			set_page_dirty(filepage);
 			swap_free(swap);
-		} else if (!(error = move_from_swap_cache(
-				swappage, idx, mapping))) {
+		} else if (move_from_swap_cache(swappage, idx, mapping) == 0) {
 			shmem_swp_set(info, entry, 0);
 			shmem_swp_unmap(entry);
 			spin_unlock(&info->lock);
@@ -840,8 +850,8 @@
 			spin_unlock(&info->lock);
 			unlock_page(swappage);
 			page_cache_release(swappage);
-			if (error != -EEXIST)
-				goto failed;
+			/* let kswapd refresh zone for GFP_ATOMICs */
+			blk_congestion_wait(WRITE, HZ/50);
 			goto repeat;
 		}
 	} else if (sgp == SGP_READ && !filepage) {
@@ -887,15 +897,16 @@
 				swap = *entry;
 				shmem_swp_unmap(entry);
 			}
-			if (error || swap.val ||
-			    (error = add_to_page_cache_lru(
-					filepage, mapping, idx, GFP_ATOMIC))) {
+			if (error || swap.val || 0 != add_to_page_cache_lru(
+					filepage, mapping, idx, GFP_ATOMIC)) {
 				spin_unlock(&info->lock);
 				page_cache_release(filepage);
 				shmem_free_block(inode);
 				filepage = NULL;
-				if (error != -EEXIST)
+				if (error)
 					goto failed;
+				/* let kswapd refresh zone for GFP_ATOMICs */
+				blk_congestion_wait(WRITE, HZ / 50);
 				goto repeat;
 			}
 		}
diff -urN linux-2.5.66-bk4/mm/slab.c linux-2.5.66-bk5/mm/slab.c
--- linux-2.5.66-bk4/mm/slab.c	Mon Mar 24 14:01:15 2003
+++ linux-2.5.66-bk5/mm/slab.c	Mon Mar 31 12:50:23 2003
@@ -375,91 +375,26 @@
 #define	SET_PAGE_SLAB(pg,x)   ((pg)->list.prev = (struct list_head *)(x))
 #define	GET_PAGE_SLAB(pg)     ((struct slab *)(pg)->list.prev)
 
-/* Size description struct for general caches. */
-struct cache_sizes {
+/* These are the default caches for kmalloc. Custom caches can have other sizes. */
+static struct cache_sizes {
 	size_t		 cs_size;
 	kmem_cache_t	*cs_cachep;
 	kmem_cache_t	*cs_dmacachep;
+} malloc_sizes[] = {
+#define CACHE(x) { .cs_size = (x) },
+#include <linux/kmalloc_sizes.h>
+#undef CACHE
 };
 
-/* These are the default caches for kmalloc. Custom caches can have other sizes. */
-static struct cache_sizes malloc_sizes[] = {
-#if PAGE_SIZE == 4096
-	{    32,	NULL, NULL},
-#endif
-	{    64,	NULL, NULL},
-#if L1_CACHE_BYTES < 64
-	{    96,	NULL, NULL},
-#endif
-	{   128,	NULL, NULL},
-#if L1_CACHE_BYTES < 128
-	{   192,	NULL, NULL},
-#endif
-	{   256,	NULL, NULL},
-	{   512,	NULL, NULL},
-	{  1024,	NULL, NULL},
-	{  2048,	NULL, NULL},
-	{  4096,	NULL, NULL},
-	{  8192,	NULL, NULL},
-	{ 16384,	NULL, NULL},
-	{ 32768,	NULL, NULL},
-	{ 65536,	NULL, NULL},
-	{131072,	NULL, NULL},
-#ifndef CONFIG_MMU
-	{262144,	NULL, NULL},
-	{524288,	NULL, NULL},
-	{1048576,	NULL, NULL},
-#ifdef CONFIG_LARGE_ALLOCS
-	{2097152,	NULL, NULL},
-	{4194304,	NULL, NULL},
-	{8388608,	NULL, NULL},
-	{16777216,	NULL, NULL},
-	{33554432,	NULL, NULL},
-#endif /* CONFIG_LARGE_ALLOCS */
-#endif /* CONFIG_MMU */
-	{     0,	NULL, NULL}
-};
 /* Must match cache_sizes above. Out of line to keep cache footprint low. */
-#define CN(x) { x, x "(DMA)" }
 static struct { 
 	char *name; 
 	char *name_dma;
 } cache_names[] = { 
-#if PAGE_SIZE == 4096
-	CN("size-32"),
-#endif
-	CN("size-64"),
-#if L1_CACHE_BYTES < 64
-	CN("size-96"),
-#endif
-	CN("size-128"),
-#if L1_CACHE_BYTES < 128
-	CN("size-192"),
-#endif
-	CN("size-256"),
-	CN("size-512"),
-	CN("size-1024"),
-	CN("size-2048"),
-	CN("size-4096"),
-	CN("size-8192"),
-	CN("size-16384"),
-	CN("size-32768"),
-	CN("size-65536"),
-	CN("size-131072"),
-#ifndef CONFIG_MMU
-	CN("size-262144"),
-	CN("size-524288"),
-	CN("size-1048576"),
-#ifdef CONFIG_LARGE_ALLOCS
-	CN("size-2097152"),
-	CN("size-4194304"),
-	CN("size-8388608"),
-	CN("size-16777216"),
-	CN("size-33554432"),
-#endif /* CONFIG_LARGE_ALLOCS */
-#endif /* CONFIG_MMU */
+#define CACHE(x) { .name = "size-" #x, .name_dma = "size-" #x "(DMA)" },
+#include <linux/kmalloc_sizes.h>
+#undef CACHE
 }; 
-#undef CN
 
 struct arraycache_init initarray_cache __initdata = { { 0, BOOT_CPUCACHE_ENTRIES, 1, 0} };
 struct arraycache_init initarray_generic __initdata = { { 0, BOOT_CPUCACHE_ENTRIES, 1, 0} };
@@ -660,39 +595,39 @@
  */
 void __init kmem_cache_sizes_init(void)
 {
-	struct cache_sizes *sizes = malloc_sizes;
+	int i;
 	/*
 	 * Fragmentation resistance on low memory - only use bigger
 	 * page orders on machines with more than 32MB of memory.
 	 */
 	if (num_physpages > (32 << 20) >> PAGE_SHIFT)
 		slab_break_gfp_order = BREAK_GFP_ORDER_HI;
-	do {
+
+	for (i = 0; i < ARRAY_SIZE(malloc_sizes); i++) {
+		struct cache_sizes *sizes = malloc_sizes + i;
 		/* For performance, all the general caches are L1 aligned.
 		 * This should be particularly beneficial on SMP boxes, as it
 		 * eliminates "false sharing".
 		 * Note for systems short on memory removing the alignment will
 		 * allow tighter packing of the smaller caches. */
-		if (!(sizes->cs_cachep =
-			kmem_cache_create(cache_names[sizes-malloc_sizes].name, 
-					  sizes->cs_size,
-					0, SLAB_HWCACHE_ALIGN, NULL, NULL))) {
+		sizes->cs_cachep = kmem_cache_create(
+			cache_names[i].name, sizes->cs_size,
+			0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+		if (!sizes->cs_cachep)
 			BUG();
-		}
 
 		/* Inc off-slab bufctl limit until the ceiling is hit. */
 		if (!(OFF_SLAB(sizes->cs_cachep))) {
 			offslab_limit = sizes->cs_size-sizeof(struct slab);
 			offslab_limit /= sizeof(kmem_bufctl_t);
 		}
+
 		sizes->cs_dmacachep = kmem_cache_create(
-		    cache_names[sizes-malloc_sizes].name_dma, 
-			sizes->cs_size, 0,
-			SLAB_CACHE_DMA|SLAB_HWCACHE_ALIGN, NULL, NULL);
+			cache_names[i].name_dma, sizes->cs_size,
+			0, SLAB_CACHE_DMA|SLAB_HWCACHE_ALIGN, NULL, NULL);
 		if (!sizes->cs_dmacachep)
 			BUG();
-		sizes++;
-	} while (sizes->cs_size);
+	}
 	/*
 	 * The generic caches are running - time to kick out the
 	 * bootstrap cpucaches.
@@ -1035,7 +970,7 @@
 	if (flags & SLAB_HWCACHE_ALIGN) {
 		/* Need to adjust size so that objs are cache aligned. */
 		/* Small obj size, can get at least two per cache line. */
-		while (size < align/2)
+		while (size <= align/2)
 			align /= 2;
 		size = (size+align-1)&(~(align-1));
 	}
diff -urN linux-2.5.66-bk4/mm/swap_state.c linux-2.5.66-bk5/mm/swap_state.c
--- linux-2.5.66-bk4/mm/swap_state.c	Mon Mar 24 14:00:21 2003
+++ linux-2.5.66-bk5/mm/swap_state.c	Mon Mar 31 12:50:23 2003
@@ -68,7 +68,7 @@
 		swap_cache_info.noent_race, swap_cache_info.exist_race);
 }
 
-int add_to_swap_cache(struct page *page, swp_entry_t entry)
+static int add_to_swap_cache(struct page *page, swp_entry_t entry)
 {
 	int error;
 
@@ -78,7 +78,7 @@
 		INC_CACHE_INFO(noent_race);
 		return -ENOENT;
 	}
-	error = add_to_page_cache(page, &swapper_space, entry.val, GFP_ATOMIC);
+	error = add_to_page_cache(page, &swapper_space, entry.val, GFP_KERNEL);
 	/*
 	 * Anon pages are already on the LRU, we don't run lru_cache_add here.
 	 */
diff -urN linux-2.5.66-bk4/mm/vmscan.c linux-2.5.66-bk5/mm/vmscan.c
--- linux-2.5.66-bk4/mm/vmscan.c	Mon Mar 24 14:00:03 2003
+++ linux-2.5.66-bk5/mm/vmscan.c	Mon Mar 31 12:50:23 2003
@@ -277,6 +277,7 @@
 			pte_chain_lock(page);
 			mapping = page->mapping;
 		}
+#endif /* CONFIG_SWAP */
 
 		/*
 		 * The page is mapped into the page tables of one or more
@@ -284,7 +285,6 @@
 		 */
 		if (page_mapped(page) && mapping) {
 			switch (try_to_unmap(page)) {
-			case SWAP_ERROR:
 			case SWAP_FAIL:
 				pte_chain_unlock(page);
 				goto activate_locked;
@@ -295,7 +295,6 @@
 				; /* try to free the page below */
 			}
 		}
-#endif /* CONFIG_SWAP */
 		pte_chain_unlock(page);
 
 		/*
diff -urN linux-2.5.66-bk4/net/irda/af_irda.c linux-2.5.66-bk5/net/irda/af_irda.c
--- linux-2.5.66-bk4/net/irda/af_irda.c	Mon Mar 24 14:00:14 2003
+++ linux-2.5.66-bk5/net/irda/af_irda.c	Mon Mar 31 12:50:23 2003
@@ -401,11 +401,10 @@
  *
  *    Got a selective discovery indication from IrLMP.
  *
- * IrLMP is telling us that this node is matching our hint bit
- * filter. Check if it's a newly discovered node (or if node changed its
- * hint bits), and then wake up any process waiting for answer...
+ * IrLMP is telling us that this node is new and matching our hint bit
+ * filter. Wake up any process waiting for answer...
  */
-static void irda_selective_discovery_indication(discovery_t *discovery,
+static void irda_selective_discovery_indication(discinfo_t *discovery,
 						DISCOVERY_MODE mode,
 						void *priv)
 {
@@ -419,18 +418,8 @@
 		return;
 	}
 
-	/* Check if node is discovered is a new one or an old one.
-	 * We check when how long ago this node was discovered, with a
-	 * coarse timeout (we may miss some discovery events or be delayed).
-	 * Note : by doing this test here, we avoid waking up a process ;-)
-	 */
-	if((jiffies - discovery->first_timestamp) >
-	   (sysctl_discovery_timeout * HZ)) {
-		return;		/* Too old, not interesting -> goodbye */
-	}
-
 	/* Pass parameter to the caller */
-	self->cachediscovery = discovery;
+	self->cachedaddr = discovery->daddr;
 
 	/* Wake up process if its waiting for device to be discovered */
 	wake_up_interruptible(&self->query_wait);
@@ -455,7 +444,7 @@
 
 	/* Nothing for the caller */
 	self->cachelog = NULL;
-	self->cachediscovery = NULL;
+	self->cachedaddr = 0;
 	self->errno = -ETIME;
 
 	/* Wake up process if its still waiting... */
@@ -627,7 +616,7 @@
  */
 static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name)
 {
-	struct irda_device_info *discoveries;	/* Copy of the discovery log */
+	discinfo_t *discoveries;	/* Copy of the discovery log */
 	int	number;			/* Number of nodes in the log */
 	int	i;
 	int	err = -ENETUNREACH;
@@ -642,7 +631,8 @@
 	 * Note : we have to use irlmp_get_discoveries(), as opposed
 	 * to play with the cachelog directly, because while we are
 	 * making our ias query, le log might change... */
-	discoveries = irlmp_get_discoveries(&number, self->mask, self->nslots);
+	discoveries = irlmp_get_discoveries(&number, self->mask.word,
+					    self->nslots);
 	/* Check if the we got some results */
 	if (discoveries == NULL)
 		return -ENETUNREACH;	/* No nodes discovered */
@@ -1137,7 +1127,7 @@
 
 	/* Register as a client with IrLMP */
 	self->ckey = irlmp_register_client(0, NULL, NULL, NULL);
-	self->mask = 0xffff;
+	self->mask.word = 0xffff;
 	self->rx_flow = self->tx_flow = FLOW_START;
 	self->nslots = DISCOVERY_DEFAULT_SLOTS;
 	self->daddr = DEV_ADDR_ANY;	/* Until we get connected */
@@ -1997,6 +1987,7 @@
 		if (optlen < sizeof(int))
 			return -EINVAL;
 
+		/* The input is really a (__u8 hints[2]), easier as an int */
 		if (get_user(opt, (int *)optval))
 			return -EFAULT;
 
@@ -2015,16 +2006,17 @@
 		if (optlen < sizeof(int))
 			return -EINVAL;
 
+		/* The input is really a (__u8 hints[2]), easier as an int */
 		if (get_user(opt, (int *)optval))
 			return -EFAULT;
 
 		/* Set the new hint mask */
-		self->mask = (__u16) opt;
+		self->mask.word = (__u16) opt;
 		/* Mask out extension bits */
-		self->mask &= 0x7f7f;
+		self->mask.word &= 0x7f7f;
 		/* Check if no bits */
-		if(!self->mask)
-			self->mask = 0xFFFF;
+		if(!self->mask.word)
+			self->mask.word = 0xFFFF;
 
 		break;
 	default:
@@ -2115,7 +2107,7 @@
 	switch (optname) {
 	case IRLMP_ENUMDEVICES:
 		/* Ask lmp for the current discovery log */
-		discoveries = irlmp_get_discoveries(&list.len, self->mask,
+		discoveries = irlmp_get_discoveries(&list.len, self->mask.word,
 						    self->nslots);
 		/* Check if the we got some results */
 		if (discoveries == NULL)
@@ -2347,7 +2339,7 @@
 			return -EFAULT;
 
 		/* Tell IrLMP we want to be notified */
-		irlmp_update_client(self->ckey, self->mask,
+		irlmp_update_client(self->ckey, self->mask.word,
 				    irda_selective_discovery_indication,
 				    NULL, (void *) self);
 
@@ -2355,7 +2347,7 @@
 		irlmp_discovery_request(self->nslots);
 
 		/* Wait until a node is discovered */
-		if (!self->cachediscovery) {
+		if (!self->cachedaddr) {
 			int ret = 0;
 
 			IRDA_DEBUG(1, "%s(), nothing discovered yet, going to sleep...\n", __FUNCTION__);
@@ -2370,7 +2362,7 @@
 
 			/* Wait for IR-LMP to call us back */
 			__wait_event_interruptible(self->query_wait,
-			   (self->cachediscovery!=NULL || self->errno==-ETIME),
+			      (self->cachedaddr != 0 || self->errno == -ETIME),
 						   ret);
 
 			/* If watchdog is still activated, kill it! */
@@ -2387,19 +2379,25 @@
 				   __FUNCTION__);
 
 		/* Tell IrLMP that we have been notified */
-		irlmp_update_client(self->ckey, self->mask, NULL, NULL, NULL);
+		irlmp_update_client(self->ckey, self->mask.word,
+				    NULL, NULL, NULL);
 
 		/* Check if the we got some results */
-		if (!self->cachediscovery)
+		if (!self->cachedaddr)
 			return -EAGAIN;		/* Didn't find any devices */
+		daddr = self->cachedaddr;
 		/* Cleanup */
-		self->cachediscovery = NULL;
+		self->cachedaddr = 0;
 
-		/* Note : We don't return anything to the user.
-		 * We could return the device that triggered the wake up,
-		 * but it's probably better to force the user to query
-		 * the whole discovery log and let him pick one device...
+		/* We return the daddr of the device that trigger the
+		 * wakeup. As irlmp pass us only the new devices, we
+		 * are sure that it's not an old device.
+		 * If the user want more details, he should query
+		 * the whole discovery log and pick one device...
 		 */
+		if (put_user(daddr, (int *)optval))
+			return -EFAULT;
+
 		break;
 	default:
 		return -ENOPROTOOPT;
diff -urN linux-2.5.66-bk4/net/irda/discovery.c linux-2.5.66-bk5/net/irda/discovery.c
--- linux-2.5.66-bk4/net/irda/discovery.c	Mon Mar 24 14:00:10 2003
+++ linux-2.5.66-bk5/net/irda/discovery.c	Mon Mar 31 12:50:23 2003
@@ -59,7 +59,7 @@
 	unsigned long flags;
 
 	/* Set time of first discovery if node is new (see below) */
-	new->first_timestamp = new->timestamp;
+	new->firststamp = new->timestamp;
 
 	spin_lock_irqsave(&cachelog->hb_spinlock, flags);
 
@@ -76,24 +76,24 @@
 		/* Be sure to stay one item ahead */
 		discovery = (discovery_t *) hashbin_get_next(cachelog);
 
-		if ((node->saddr == new->saddr) &&
-		    ((node->daddr == new->daddr) || 
-		     (strcmp(node->nickname, new->nickname) == 0)))
+		if ((node->data.saddr == new->data.saddr) &&
+		    ((node->data.daddr == new->data.daddr) || 
+		     (strcmp(node->data.info, new->data.info) == 0)))
 		{
 			/* This discovery is a previous discovery 
 			 * from the same device, so just remove it
 			 */
 			hashbin_remove_this(cachelog, (irda_queue_t *) node);
-			/* Check if hints bits have changed */
-			if(node->hints.word == new->hints.word)
+			/* Check if hints bits are unchanged */
+			if(u16ho(node->data.hints) == u16ho(new->data.hints))
 				/* Set time of first discovery for this node */
-				new->first_timestamp = node->first_timestamp;
+				new->firststamp = node->firststamp;
 			kfree(node);
 		}
 	}
 
 	/* Insert the new and updated version */
-	hashbin_insert(cachelog, (irda_queue_t *) new, new->daddr, NULL);
+	hashbin_insert(cachelog, (irda_queue_t *) new, new->data.daddr, NULL);
 
 	spin_unlock_irqrestore(&cachelog->hb_spinlock, flags);
 }
@@ -147,27 +147,50 @@
  */
 void irlmp_expire_discoveries(hashbin_t *log, __u32 saddr, int force)
 {
-	discovery_t *discovery, *curr;
-	unsigned long flags;
+	discovery_t *		discovery;
+	discovery_t *		curr;
+	unsigned long		flags;
+	discinfo_t *		buffer = NULL;
+	int			n;		/* Size of the full log */
+	int			i = 0;		/* How many we expired */
 
+	ASSERT(log != NULL, return;);
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	spin_lock_irqsave(&log->hb_spinlock, flags);
 
 	discovery = (discovery_t *) hashbin_get_first(log);
 	while (discovery != NULL) {
-		curr = discovery;
-
 		/* Be sure to be one item ahead */
+		curr = discovery;
 		discovery = (discovery_t *) hashbin_get_next(log);
 
 		/* Test if it's time to expire this discovery */
-		if ((curr->saddr == saddr) &&
+		if ((curr->data.saddr == saddr) &&
 		    (force ||
 		     ((jiffies - curr->timestamp) > DISCOVERY_EXPIRE_TIMEOUT)))
 		{
-			/* Tell IrLMP and registered clients about it */
-			irlmp_discovery_expiry(curr);
+			/* Create buffer as needed.
+			 * As this function get called a lot and most time
+			 * we don't have anything to put in the log (we are
+			 * quite picky), we can save a lot of overhead
+			 * by not calling kmalloc. Jean II */
+			if(buffer == NULL) {
+				/* Create the client specific buffer */
+				n = HASHBIN_GET_SIZE(log);
+				buffer = kmalloc(n * sizeof(struct irda_device_info), GFP_ATOMIC);
+				if (buffer == NULL) {
+					spin_unlock_irqrestore(&log->hb_spinlock, flags);
+					return;
+				}
+
+			}
+
+			/* Copy discovery information */
+			memcpy(&(buffer[i]), &(curr->data),
+			       sizeof(discinfo_t));
+			i++;
+
 			/* Remove it from the log */
 			curr = hashbin_remove_this(log, (irda_queue_t *) curr);
 			if (curr)
@@ -175,9 +198,23 @@
 		}
 	}
 
+	/* Drop the spinlock before calling the higher layers, as
+	 * we can't guarantee they won't call us back and create a
+	 * deadlock. We will work on our own private data, so we
+	 * don't care to be interupted. - Jean II */
 	spin_unlock_irqrestore(&log->hb_spinlock, flags);
+
+	if(buffer == NULL)
+		return;
+
+	/* Tell IrLMP and registered clients about it */
+	irlmp_discovery_expiry(buffer, i);
+
+	/* Free up our buffer */
+	kfree(buffer);
 }
 
+#if 0
 /*
  * Function irlmp_dump_discoveries (log)
  *
@@ -193,13 +230,14 @@
 	discovery = (discovery_t *) hashbin_get_first(log);
 	while (discovery != NULL) {
 		IRDA_DEBUG(0, "Discovery:\n");
-		IRDA_DEBUG(0, "  daddr=%08x\n", discovery->daddr);
-		IRDA_DEBUG(0, "  saddr=%08x\n", discovery->saddr); 
-		IRDA_DEBUG(0, "  nickname=%s\n", discovery->nickname);
+		IRDA_DEBUG(0, "  daddr=%08x\n", discovery->data.daddr);
+		IRDA_DEBUG(0, "  saddr=%08x\n", discovery->data.saddr); 
+		IRDA_DEBUG(0, "  nickname=%s\n", discovery->data.info);
 
 		discovery = (discovery_t *) hashbin_get_next(log);
 	}
 }
+#endif
 
 /*
  * Function irlmp_copy_discoveries (log, pn, mask)
@@ -221,43 +259,49 @@
  * Note : the client must kfree himself() the log...
  * Jean II
  */
-struct irda_device_info *irlmp_copy_discoveries(hashbin_t *log, int *pn, __u16 mask)
+struct irda_device_info *irlmp_copy_discoveries(hashbin_t *log, int *pn,
+						__u16 mask, int old_entries)
 {
-	discovery_t *			discovery;
-	unsigned long			flags;
-	struct irda_device_info *	buffer;
-	int				i = 0;
-	int				n;
+	discovery_t *		discovery;
+	unsigned long		flags;
+	discinfo_t *		buffer = NULL;
+	int			j_timeout = (sysctl_discovery_timeout * HZ);
+	int			n;		/* Size of the full log */
+	int			i = 0;		/* How many we picked */
 
 	ASSERT(pn != NULL, return NULL;);
+	ASSERT(log != NULL, return NULL;);
 
-	/* Check if log is empty */
-	if(log == NULL)
-		return NULL;
-
-	/* Save spin lock - spinlock should be discovery specific */
+	/* Save spin lock */
 	spin_lock_irqsave(&log->hb_spinlock, flags);
 
-	/* Create the client specific buffer */
-	n = HASHBIN_GET_SIZE(log);
-	buffer = kmalloc(n * sizeof(struct irda_device_info), GFP_ATOMIC);
-	if (buffer == NULL) {
-		spin_unlock_irqrestore(&log->hb_spinlock, flags);
-		return NULL;
-	}
-
 	discovery = (discovery_t *) hashbin_get_first(log);
-	while ((discovery != NULL) && (i < n)) {
-		/* Mask out the ones we don't want */
-		if (discovery->hints.word & mask) {
+	while (discovery != NULL) {
+		/* Mask out the ones we don't want :
+		 * We want to match the discovery mask, and to get only
+		 * the most recent one (unless we want old ones) */
+		if ((u16ho(discovery->data.hints) & mask) &&
+		    ((old_entries) ||
+		     ((jiffies - discovery->firststamp) < j_timeout)) ) {
+			/* Create buffer as needed.
+			 * As this function get called a lot and most time
+			 * we don't have anything to put in the log (we are
+			 * quite picky), we can save a lot of overhead
+			 * by not calling kmalloc. Jean II */
+			if(buffer == NULL) {
+				/* Create the client specific buffer */
+				n = HASHBIN_GET_SIZE(log);
+				buffer = kmalloc(n * sizeof(struct irda_device_info), GFP_ATOMIC);
+				if (buffer == NULL) {
+					spin_unlock_irqrestore(&log->hb_spinlock, flags);
+					return NULL;
+				}
+
+			}
+
 			/* Copy discovery information */
-			buffer[i].saddr = discovery->saddr;
-			buffer[i].daddr = discovery->daddr;
-			buffer[i].charset = discovery->charset;
-			buffer[i].hints[0] = discovery->hints.byte[0];
-			buffer[i].hints[1] = discovery->hints.byte[1];
-			strncpy(buffer[i].info, discovery->nickname,
-				NICKNAME_MAX_LEN);
+			memcpy(&(buffer[i]), &(discovery->data),
+			       sizeof(discinfo_t));
 			i++;
 		}
 		discovery = (discovery_t *) hashbin_get_next(log);
@@ -288,14 +332,14 @@
 	d = (discovery_t *) hashbin_get_first(cachelog);
 	while (d != NULL) {
 		IRDA_DEBUG(1, "Discovery:\n");
-		IRDA_DEBUG(1, "  daddr=%08x\n", d->daddr);
-		IRDA_DEBUG(1, "  nickname=%s\n", d->nickname);
-		
-		if (strcmp(name, d->nickname) == 0) {
-			*saddr = d->saddr;
+		IRDA_DEBUG(1, "  daddr=%08x\n", d->data.daddr);
+		IRDA_DEBUG(1, "  nickname=%s\n", d->data.info);
+
+		if (strcmp(name, d->data.info) == 0) {
+			*saddr = d->data.saddr;
 			
 			spin_unlock_irqrestore(&cachelog->hb_spinlock, flags);
-			return d->daddr;
+			return d->data.daddr;
 		}
 		d = (discovery_t *) hashbin_get_next(cachelog);
 	}
@@ -328,41 +372,41 @@
 
 	discovery = (discovery_t *) hashbin_get_first(cachelog);
 	while (( discovery != NULL) && (len < length)) {
-		len += sprintf(buf+len, "nickname: %s,", discovery->nickname);
+		len += sprintf(buf+len, "nickname: %s,", discovery->data.info);
 		
 		len += sprintf(buf+len, " hint: 0x%02x%02x", 
-			       discovery->hints.byte[0], 
-			       discovery->hints.byte[1]);
+			       discovery->data.hints[0], 
+			       discovery->data.hints[1]);
 #if 0
-		if ( discovery->hints.byte[0] & HINT_PNP)
+		if ( discovery->data.hints[0] & HINT_PNP)
 			len += sprintf( buf+len, "PnP Compatible ");
-		if ( discovery->hints.byte[0] & HINT_PDA)
+		if ( discovery->data.hints[0] & HINT_PDA)
 			len += sprintf( buf+len, "PDA/Palmtop ");
-		if ( discovery->hints.byte[0] & HINT_COMPUTER)
+		if ( discovery->data.hints[0] & HINT_COMPUTER)
 			len += sprintf( buf+len, "Computer ");
-		if ( discovery->hints.byte[0] & HINT_PRINTER)
+		if ( discovery->data.hints[0] & HINT_PRINTER)
 			len += sprintf( buf+len, "Printer ");
-		if ( discovery->hints.byte[0] & HINT_MODEM)
+		if ( discovery->data.hints[0] & HINT_MODEM)
 			len += sprintf( buf+len, "Modem ");
-		if ( discovery->hints.byte[0] & HINT_FAX)
+		if ( discovery->data.hints[0] & HINT_FAX)
 			len += sprintf( buf+len, "Fax ");
-		if ( discovery->hints.byte[0] & HINT_LAN)
+		if ( discovery->data.hints[0] & HINT_LAN)
 			len += sprintf( buf+len, "LAN Access ");
 		
-		if ( discovery->hints.byte[1] & HINT_TELEPHONY)
+		if ( discovery->data.hints[1] & HINT_TELEPHONY)
 			len += sprintf( buf+len, "Telephony ");
-		if ( discovery->hints.byte[1] & HINT_FILE_SERVER)
+		if ( discovery->data.hints[1] & HINT_FILE_SERVER)
 			len += sprintf( buf+len, "File Server ");       
-		if ( discovery->hints.byte[1] & HINT_COMM)
+		if ( discovery->data.hints[1] & HINT_COMM)
 			len += sprintf( buf+len, "IrCOMM ");
-		if ( discovery->hints.byte[1] & HINT_OBEX)
+		if ( discovery->data.hints[1] & HINT_OBEX)
 			len += sprintf( buf+len, "IrOBEX ");
 #endif		
 		len += sprintf(buf+len, ", saddr: 0x%08x", 
-			       discovery->saddr);
+			       discovery->data.saddr);
 
 		len += sprintf(buf+len, ", daddr: 0x%08x\n", 
-			       discovery->daddr);
+			       discovery->data.daddr);
 		
 		len += sprintf(buf+len, "\n");
 		
diff -urN linux-2.5.66-bk4/net/irda/ircomm/ircomm_tty_attach.c linux-2.5.66-bk5/net/irda/ircomm/ircomm_tty_attach.c
--- linux-2.5.66-bk4/net/irda/ircomm/ircomm_tty_attach.c	Mon Mar 24 14:01:25 2003
+++ linux-2.5.66-bk5/net/irda/ircomm/ircomm_tty_attach.c	Mon Mar 31 12:50:23 2003
@@ -46,7 +46,7 @@
 #include <net/irda/ircomm_tty_attach.h>
 
 static void ircomm_tty_ias_register(struct ircomm_tty_cb *self);
-static void ircomm_tty_discovery_indication(discovery_t *discovery,
+static void ircomm_tty_discovery_indication(discinfo_t *discovery,
 					    DISCOVERY_MODE mode,
 					    void *priv);
 static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id, 
@@ -305,7 +305,7 @@
  *    device it is, and which services it has.
  *
  */
-static void ircomm_tty_discovery_indication(discovery_t *discovery,
+static void ircomm_tty_discovery_indication(discinfo_t *discovery,
 					    DISCOVERY_MODE mode,
 					    void *priv)
 {
diff -urN linux-2.5.66-bk4/net/irda/irlan/irlan_client.c linux-2.5.66-bk5/net/irda/irlan/irlan_client.c
--- linux-2.5.66-bk4/net/irda/irlan/irlan_client.c	Mon Mar 24 14:00:44 2003
+++ linux-2.5.66-bk5/net/irda/irlan/irlan_client.c	Mon Mar 31 12:50:23 2003
@@ -145,7 +145,7 @@
  *    Remote device with IrLAN server support discovered
  *
  */
-void irlan_client_discovery_indication(discovery_t *discovery,
+void irlan_client_discovery_indication(discinfo_t *discovery,
 				       DISCOVERY_MODE mode,
 				       void *priv) 
 {
diff -urN linux-2.5.66-bk4/net/irda/irlap_event.c linux-2.5.66-bk5/net/irda/irlap_event.c
--- linux-2.5.66-bk4/net/irda/irlap_event.c	Mon Mar 24 14:00:50 2003
+++ linux-2.5.66-bk5/net/irda/irlap_event.c	Mon Mar 31 12:50:23 2003
@@ -419,7 +419,7 @@
 								   info->s);
 			if (self->slot == info->s) {
 				discovery_rsp = irlmp_get_discovery_response();
-				discovery_rsp->daddr = info->daddr;
+				discovery_rsp->data.daddr = info->daddr;
 
 				irlap_send_discovery_xid_frame(self, info->S,
 							       self->slot,
@@ -576,7 +576,7 @@
 		ASSERT(info->discovery != NULL, return -1;);
 
 		IRDA_DEBUG(4, "%s(), daddr=%08x\n", __FUNCTION__,
-			   info->discovery->daddr);
+			   info->discovery->data.daddr);
 
 		if (!self->discovery_log) {
 			WARNING("%s: discovery log is gone! "
@@ -586,7 +586,7 @@
 		}
 		hashbin_insert(self->discovery_log,
 			       (irda_queue_t *) info->discovery,
-			       info->discovery->daddr, NULL);
+			       info->discovery->data.daddr, NULL);
 
 		/* Keep state */
 		/* irlap_next_state(self, LAP_QUERY);  */
@@ -704,7 +704,7 @@
 			irlap_discovery_indication(self, info->discovery);
 		} else if ((info->s >= self->slot) && (!self->frame_sent)) {
 			discovery_rsp = irlmp_get_discovery_response();
-			discovery_rsp->daddr = info->daddr;
+			discovery_rsp->data.daddr = info->daddr;
 
 			irlap_send_discovery_xid_frame(self, info->S,
 						       self->slot, FALSE,
@@ -982,15 +982,48 @@
 		 *  Only send frame if send-window > 0.
 		 */
 		if ((self->window > 0) && (!self->remote_busy)) {
+			int nextfit;
 #ifdef CONFIG_IRDA_DYNAMIC_WINDOW
+			struct sk_buff *skb_next;
+
+			/* With DYNAMIC_WINDOW, we keep the window size
+			 * maximum, and adapt on the packets we are sending.
+			 * At 115k, we can send only 2 packets of 2048 bytes
+			 * in a 500 ms turnaround. Without this option, we
+			 * would always limit the window to 2. With this
+			 * option, if we send smaller packets, we can send
+			 * up to 7 of them (always depending on QoS).
+			 * Jean II */
+
+			/* Look at the next skb. This is safe, as we are
+			 * the only consumer of the Tx queue (if we are not,
+			 * we have other problems) - Jean II */
+			skb_next = skb_peek(&self->txq);
+
+			/* Check if a subsequent skb exist and would fit in
+			 * the current window (with respect to turnaround
+			 * time).
+			 * This allow us to properly mark the current packet
+			 * with the pf bit, to avoid falling back on the
+			 * second test below, and avoid waiting the
+			 * end of the window and sending a extra RR.
+			 * Note : (skb_next != NULL) <=> (skb_queue_len() > 0)
+			 * Jean II */
+			nextfit = ((skb_next != NULL) &&
+				   ((skb_next->len + skb->len) <=
+				    self->bytes_left));
+
 			/*
+			 * The current packet may not fit ! Because of test
+			 * above, this should not happen any more !!!
 			 *  Test if we have transmitted more bytes over the
 			 *  link than its possible to do with the current
 			 *  speed and turn-around-time.
 			 */
-			if (skb->len > self->bytes_left) {
-				IRDA_DEBUG(4, "%s(), Not allowed to transmit"
+			if((!nextfit) && (skb->len > self->bytes_left)) {
+				IRDA_DEBUG(0, "%s(), Not allowed to transmit"
 					   " more bytes!\n", __FUNCTION__);
+				/* Requeue the skb */
 				skb_queue_head(&self->txq, skb_get(skb));
 				/*
 				 *  We should switch state to LAP_NRM_P, but
@@ -1000,20 +1033,33 @@
 				 *  trigger anyway now, so we just wait for it
 				 *  DB
 				 */
+				/*
+				 * Sorry, but that's not totally true. If
+				 * we send 2000B packets, we may wait another
+				 * 1000B until our turnaround expire. That's
+				 * why we need to be proactive in avoiding
+				 * comming here. - Jean II
+				 */
 				return -EPROTO;
 			}
+
+			/* Substract space used by this skb */
 			self->bytes_left -= skb->len;
-#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
+#else	/* CONFIG_IRDA_DYNAMIC_WINDOW */
+			/* Window has been adjusted for the max packet
+			 * size, so much simpler... - Jean II */
+			nextfit = (skb_queue_len(&self->txq) > 0);
+#endif	/* CONFIG_IRDA_DYNAMIC_WINDOW */
 			/*
 			 *  Send data with poll bit cleared only if window > 1
 			 *  and there is more frames after this one to be sent
 			 */
-			if ((self->window > 1) &&
-			    skb_queue_len( &self->txq) > 0)
-			{
+			if ((self->window > 1) && (nextfit)) {
+				/* More packet to send in current window */
 				irlap_send_data_primary(self, skb);
 				irlap_next_state(self, LAP_XMIT_P);
 			} else {
+				/* Final packet of window */
 				irlap_send_data_primary_poll(self, skb);
 				irlap_next_state(self, LAP_NRM_P);
 
@@ -1683,16 +1729,37 @@
 	switch (event) {
 	case SEND_I_CMD:
 		/*
-		 *  Send frame only if send window > 1
+		 *  Send frame only if send window > 0
 		 */
 		if ((self->window > 0) && (!self->remote_busy)) {
+			int nextfit;
 #ifdef CONFIG_IRDA_DYNAMIC_WINDOW
+			struct sk_buff *skb_next;
+
+			/*
+			 * Same deal as in irlap_state_xmit_p(), so see
+			 * the comments at that point.
+			 * We are the secondary, so there are only subtle
+			 * differences. - Jean II
+			 */
+
+			/* Check if a subsequent skb exist and would fit in
+			 * the current window (with respect to turnaround
+			 * time). - Jean II */
+			skb_next = skb_peek(&self->txq);
+			nextfit = ((skb_next != NULL) &&
+				   ((skb_next->len + skb->len) <=
+				    self->bytes_left));
+
 			/*
 			 *  Test if we have transmitted more bytes over the
 			 *  link than its possible to do with the current
 			 *  speed and turn-around-time.
 			 */
-			if (skb->len > self->bytes_left) {
+			if((!nextfit) && (skb->len > self->bytes_left)) {
+				IRDA_DEBUG(0, "%s(), Not allowed to transmit"
+					   " more bytes!\n", __FUNCTION__);
+				/* Requeue the skb */
 				skb_queue_head(&self->txq, skb_get(skb));
 
 				/*
@@ -1706,18 +1773,24 @@
 				irlap_start_wd_timer(self, self->wd_timeout);
 
 				irlap_next_state(self, LAP_NRM_S);
+				/* Slight difference with primary :
+				 * here we would wait for the other side to
+				 * expire the turnaround. - Jean II */
 
 				return -EPROTO; /* Try again later */
 			}
+			/* Substract space used by this skb */
 			self->bytes_left -= skb->len;
+#else	/* CONFIG_IRDA_DYNAMIC_WINDOW */
+			/* Window has been adjusted for the max packet
+			 * size, so much simpler... - Jean II */
+			nextfit = (skb_queue_len(&self->txq) > 0);
 #endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
 			/*
 			 *  Send data with final bit cleared only if window > 1
 			 *  and there is more frames to be sent
 			 */
-			if ((self->window > 1) &&
-			    skb_queue_len(&self->txq) > 0)
-			{
+			if ((self->window > 1) && (nextfit)) {
 				irlap_send_data_secondary(self, skb);
 				irlap_next_state(self, LAP_XMIT_S);
 			} else {
diff -urN linux-2.5.66-bk4/net/irda/irlap_frame.c linux-2.5.66-bk5/net/irda/irlap_frame.c
--- linux-2.5.66-bk4/net/irda/irlap_frame.c	Mon Mar 24 14:00:10 2003
+++ linux-2.5.66-bk5/net/irda/irlap_frame.c	Mon Mar 31 12:50:23 2003
@@ -335,7 +335,7 @@
 	if (command)
 		frame->daddr = cpu_to_le32(bcast);
 	else
-		frame->daddr = cpu_to_le32(discovery->daddr);
+		frame->daddr = cpu_to_le32(discovery->data.daddr);
 
 	switch (S) {
 	case 1:
@@ -366,20 +366,20 @@
 	if (!command || (frame->slotnr == 0xff)) {
 		int len;
 
-		if (discovery->hints.byte[0] & HINT_EXTENSION) {
+		if (discovery->data.hints[0] & HINT_EXTENSION) {
 			info = skb_put(skb, 2);
-			info[0] = discovery->hints.byte[0];
-			info[1] = discovery->hints.byte[1];
+			info[0] = discovery->data.hints[0];
+			info[1] = discovery->data.hints[1];
 		} else {
 			info = skb_put(skb, 1);
-			info[0] = discovery->hints.byte[0];
+			info[0] = discovery->data.hints[0];
 		}
 		info = skb_put(skb, 1);
-		info[0] = discovery->charset;
+		info[0] = discovery->data.charset;
 
 		len = IRDA_MIN(discovery->name_len, skb_tailroom(skb));
 		info = skb_put(skb, len);
-		memcpy(info, discovery->nickname, len);
+		memcpy(info, discovery->data.info, len);
 	}
 	irlap_queue_xmit(self, skb);
 }
@@ -422,24 +422,25 @@
 	}
 	memset(discovery, 0, sizeof(discovery_t));
 
-	discovery->daddr = info->daddr;
-	discovery->saddr = self->saddr;
+	discovery->data.daddr = info->daddr;
+	discovery->data.saddr = self->saddr;
 	discovery->timestamp = jiffies;
 
-	IRDA_DEBUG(4, "%s(), daddr=%08x\n", __FUNCTION__, discovery->daddr);
+	IRDA_DEBUG(4, "%s(), daddr=%08x\n", __FUNCTION__,
+		   discovery->data.daddr);
 
 	discovery_info = skb_pull(skb, sizeof(struct xid_frame));
 
 	/* Get info returned from peer */
-	discovery->hints.byte[0] = discovery_info[0];
+	discovery->data.hints[0] = discovery_info[0];
 	if (discovery_info[0] & HINT_EXTENSION) {
 		IRDA_DEBUG(4, "EXTENSION\n");
-		discovery->hints.byte[1] = discovery_info[1];
-		discovery->charset = discovery_info[2];
+		discovery->data.hints[1] = discovery_info[1];
+		discovery->data.charset = discovery_info[2];
 		text = (char *) &discovery_info[3];
 	} else {
-		discovery->hints.byte[1] = 0;
-		discovery->charset = discovery_info[1];
+		discovery->data.hints[1] = 0;
+		discovery->data.charset = discovery_info[1];
 		text = (char *) &discovery_info[2];
 	}
 	/*
@@ -447,8 +448,8 @@
 	 *  FCS bytes resides.
 	 */
 	skb->data[skb->len] = '\0';
-	strncpy(discovery->nickname, text, NICKNAME_MAX_LEN);
-	discovery->name_len = strlen(discovery->nickname);
+	strncpy(discovery->data.info, text, NICKNAME_MAX_LEN);
+	discovery->name_len = strlen(discovery->data.info);
 
 	info->discovery = discovery;
 
@@ -523,18 +524,18 @@
 			return;
 		}
 
-		discovery->daddr = info->daddr;
-		discovery->saddr = self->saddr;
+		discovery->data.daddr = info->daddr;
+		discovery->data.saddr = self->saddr;
 		discovery->timestamp = jiffies;
 
-		discovery->hints.byte[0] = discovery_info[0];
+		discovery->data.hints[0] = discovery_info[0];
 		if (discovery_info[0] & HINT_EXTENSION) {
-			discovery->hints.byte[1] = discovery_info[1];
-			discovery->charset = discovery_info[2];
+			discovery->data.hints[1] = discovery_info[1];
+			discovery->data.charset = discovery_info[2];
 			text = (char *) &discovery_info[3];
 		} else {
-			discovery->hints.byte[1] = 0;
-			discovery->charset = discovery_info[1];
+			discovery->data.hints[1] = 0;
+			discovery->data.charset = discovery_info[1];
 			text = (char *) &discovery_info[2];
 		}
 		/*
@@ -542,8 +543,8 @@
 		 *  FCS bytes resides.
 		 */
 		skb->data[skb->len] = '\0';
-		strncpy(discovery->nickname, text, NICKNAME_MAX_LEN);
-		discovery->name_len = strlen(discovery->nickname);
+		strncpy(discovery->data.info, text, NICKNAME_MAX_LEN);
+		discovery->name_len = strlen(discovery->data.info);
 
 		info->discovery = discovery;
 	} else
diff -urN linux-2.5.66-bk4/net/irda/irlmp.c linux-2.5.66-bk5/net/irda/irlmp.c
--- linux-2.5.66-bk4/net/irda/irlmp.c	Mon Mar 24 14:01:25 2003
+++ linux-2.5.66-bk5/net/irda/irlmp.c	Mon Mar 31 12:50:23 2003
@@ -401,8 +401,8 @@
 		}
 
 		if (discovery) {
-			saddr = discovery->saddr;
-			daddr = discovery->daddr;
+			saddr = discovery->data.saddr;
+			daddr = discovery->data.daddr;
 		}
 		spin_unlock_irqrestore(&irlmp->cachelog->hb_spinlock, flags);
 	}
@@ -793,17 +793,17 @@
 	}
 
 	/* Construct new discovery info to be used by IrLAP, */
-	irlmp->discovery_cmd.hints.word = irlmp->hints.word;
+	u16ho(irlmp->discovery_cmd.data.hints) = irlmp->hints.word;
 
 	/*
 	 *  Set character set for device name (we use ASCII), and
 	 *  copy device name. Remember to make room for a \0 at the
 	 *  end
 	 */
-	irlmp->discovery_cmd.charset = CS_ASCII;
-	strncpy(irlmp->discovery_cmd.nickname, sysctl_devname,
+	irlmp->discovery_cmd.data.charset = CS_ASCII;
+	strncpy(irlmp->discovery_cmd.data.info, sysctl_devname,
 		NICKNAME_MAX_LEN);
-	irlmp->discovery_cmd.name_len = strlen(irlmp->discovery_cmd.nickname);
+	irlmp->discovery_cmd.name_len = strlen(irlmp->discovery_cmd.data.info);
 	irlmp->discovery_cmd.nslots = nslots;
 
 	/*
@@ -827,10 +827,13 @@
  *
  *    Do a discovery of devices in front of the computer
  *
+ * If the caller has registered a client discovery callback, this
+ * allow him to receive the full content of the discovery log through
+ * this callback (as normally he will receive only new discoveries).
  */
 void irlmp_discovery_request(int nslots)
 {
-	/* Return current cached discovery log */
+	/* Return current cached discovery log (in full) */
 	irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_LOG);
 
 	/*
@@ -854,6 +857,8 @@
  *
  *    Return the current discovery log
  *
+ * If discovery is not enabled, you should call this function again
+ * after 1 or 2 seconds (i.e. after discovery has been done).
  */
 struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask, int nslots)
 {
@@ -875,50 +880,9 @@
 	}
 
 	/* Return current cached discovery log */
-	return(irlmp_copy_discoveries(irlmp->cachelog, pn, mask));
+	return(irlmp_copy_discoveries(irlmp->cachelog, pn, mask, TRUE));
 }
 
-#if 0
-/*
- * Function irlmp_check_services (discovery)
- */
-void irlmp_check_services(discovery_t *discovery)
-{
-	struct irlmp_client *client;
-	__u8 *service_log;
-	__u8 service;
-	int i = 0;
-
-	IRDA_DEBUG(1, "IrDA Discovered: %s\n", discovery->info);
-	IRDA_DEBUG(1, "    Services: ");
-
-	service_log = irlmp_hint_to_service(discovery->hints.byte);
-	if (!service_log)
-		return;
-
-	/*
-	 *  Check all services on the device
-	 */
-	while ((service = service_log[i++]) != S_END) {
-		IRDA_DEBUG( 4, "service=%02x\n", service);
-		client = hashbin_lock_find(irlmp->registry, service, NULL);
-		if (entry && entry->discovery_callback) {
-			IRDA_DEBUG( 4, "discovery_callback!\n");
-
-			entry->discovery_callback(discovery);
-		} else {
-			/* Don't notify about the ANY service */
-			if (service == S_ANY)
-				continue;
-			/*
-			 * Found no clients for dealing with this service,
-			 */
-		}
-	}
-	kfree(service_log);
-}
-#endif
-
 /*
  * Function irlmp_notify_client (log)
  *
@@ -935,7 +899,9 @@
 irlmp_notify_client(irlmp_client_t *client,
 		    hashbin_t *log, DISCOVERY_MODE mode)
 {
-	discovery_t *discovery;
+	discinfo_t *discoveries;	/* Copy of the discovery log */
+	int	number;			/* Number of nodes in the log */
+	int	i;
 
 	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 
@@ -944,28 +910,36 @@
 		return;
 
 	/*
+	 * Locking notes :
+	 * the old code was manipulating the log directly, which was
+	 * very racy. Now, we use copy_discoveries, that protects
+	 * itself while dumping the log for us.
+	 * The overhead of the copy is compensated by the fact that
+	 * we only pass new discoveries in normal mode and don't
+	 * pass the same old entry every 3s to the caller as we used
+	 * to do (virtual function calling is expensive).
+	 * Jean II
+	 */
+
+	/*
 	 * Now, check all discovered devices (if any), and notify client
 	 * only about the services that the client is interested in
-	 * Note : most often, we will get called immediately following
-	 * a discovery, so the log is not going to expire.
-	 * On the other hand, comming here through irlmp_discovery_request()
-	 * is *very* problematic - Jean II
-	 * Can't use hashbin_find_next(), key is not unique. I'm running
-	 * out of options :-( - Jean II
+	 * We also notify only about the new devices unless the caller
+	 * explicity request a dump of the log. Jean II
 	 */
-	discovery = (discovery_t *) hashbin_get_first(log);
-	while (discovery != NULL) {
-		IRDA_DEBUG(3, "discovery->daddr = 0x%08x\n", discovery->daddr);
-
-		/*
-		 * Any common hint bits? Remember to mask away the extension
-		 * bits ;-)
-		 */
-		if (client->hint_mask & discovery->hints.word & 0x7f7f)
-			client->disco_callback(discovery, mode, client->priv);
+	discoveries = irlmp_copy_discoveries(log, &number,
+					     client->hint_mask.word,
+					     (mode == DISCOVERY_LOG));
+	/* Check if the we got some results */
+	if (discoveries == NULL)
+		return;	/* No nodes discovered */
+
+	/* Pass all entries to the listener */
+	for(i = 0; i < number; i++)
+		client->disco_callback(&(discoveries[i]), mode, client->priv);
 
-		discovery = (discovery_t *) hashbin_get_next(log);
-	}
+	/* Free up our buffer */
+	kfree(discoveries);
 }
 
 /*
@@ -987,6 +961,7 @@
 	if (!(HASHBIN_GET_SIZE(log)))
 		return;
 
+	/* For each client - notify callback may touch client list */
 	client = (irlmp_client_t *) hashbin_get_first(irlmp->clients);
 	while (NULL != hashbin_find_next(irlmp->clients, (long) client, NULL,
 					 (void *) &client_next) ) {
@@ -1005,26 +980,34 @@
  *	registered for this event...
  *
  *	Note : called exclusively from discovery.c
- *	Note : as we are currently processing the log, the clients callback
- *	should *NOT* attempt to touch the log now.
+ *	Note : this is no longer called under discovery spinlock, so the
+ *		client can do whatever he wants in the callback.
  */
-void irlmp_discovery_expiry(discovery_t *expiry)
+void irlmp_discovery_expiry(discinfo_t *expiries, int number)
 {
 	irlmp_client_t *client;
 	irlmp_client_t *client_next;
+	int		i;
 
 	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 
-	ASSERT(expiry != NULL, return;);
+	ASSERT(expiries != NULL, return;);
 
+	/* For each client - notify callback may touch client list */
 	client = (irlmp_client_t *) hashbin_get_first(irlmp->clients);
 	while (NULL != hashbin_find_next(irlmp->clients, (long) client, NULL,
 					 (void *) &client_next) ) {
-		/* Check if we should notify client */
-		if ((client->expir_callback) &&
-		    (client->hint_mask & expiry->hints.word & 0x7f7f))
-			client->expir_callback(expiry, EXPIRY_TIMEOUT,
-					       client->priv);
+
+		/* Pass all entries to the listener */
+		for(i = 0; i < number; i++) {
+			/* Check if we should notify client */
+			if ((client->expir_callback) &&
+			    (client->hint_mask.word & u16ho(expiries[i].hints)
+			     & 0x7f7f) )
+				client->expir_callback(&(expiries[i]),
+						       EXPIRY_TIMEOUT,
+						       client->priv);
+		}
 
 		/* Next client */
 		client = client_next;
@@ -1043,18 +1026,18 @@
 
 	ASSERT(irlmp != NULL, return NULL;);
 
-	irlmp->discovery_rsp.hints.word = irlmp->hints.word;
+	u16ho(irlmp->discovery_rsp.data.hints) = irlmp->hints.word;
 
 	/*
 	 *  Set character set for device name (we use ASCII), and
 	 *  copy device name. Remember to make room for a \0 at the
 	 *  end
 	 */
-	irlmp->discovery_rsp.charset = CS_ASCII;
+	irlmp->discovery_rsp.data.charset = CS_ASCII;
 
-	strncpy(irlmp->discovery_rsp.nickname, sysctl_devname,
+	strncpy(irlmp->discovery_rsp.data.info, sysctl_devname,
 		NICKNAME_MAX_LEN);
-	irlmp->discovery_rsp.name_len = strlen(irlmp->discovery_rsp.nickname);
+	irlmp->discovery_rsp.name_len = strlen(irlmp->discovery_rsp.data.info);
 
 	return &irlmp->discovery_rsp;
 }
@@ -1291,6 +1274,7 @@
 	}
 }
 
+#if 0
 /*
  * Function irlmp_hint_to_service (hint)
  *
@@ -1365,6 +1349,21 @@
 
 	return service;
 }
+#endif
+
+const __u16 service_hint_mapping[S_END][2] = {
+	{ HINT_PNP,		0 },			/* S_PNP */
+	{ HINT_PDA,		0 },			/* S_PDA */
+	{ HINT_COMPUTER,	0 },			/* S_COMPUTER */
+	{ HINT_PRINTER,		0 },			/* S_PRINTER */
+	{ HINT_MODEM,		0 },			/* S_MODEM */
+	{ HINT_FAX,		0 },			/* S_FAX */
+	{ HINT_LAN,		0 },			/* S_LAN */
+	{ HINT_EXTENSION,	HINT_TELEPHONY },	/* S_TELEPHONY */
+	{ HINT_EXTENSION,	HINT_COMM },		/* S_COMM */
+	{ HINT_EXTENSION,	HINT_OBEX },		/* S_OBEX */
+	{ 0xFF,			0xFF },			/* S_ANY */
+};
 
 /*
  * Function irlmp_service_to_hint (service)
@@ -1377,46 +1376,9 @@
 {
 	__u16_host_order hint;
 
-	hint.word = 0;
+	hint.byte[0] = service_hint_mapping[service][0];
+	hint.byte[1] = service_hint_mapping[service][1];
 
-	switch (service) {
-	case S_PNP:
-		hint.byte[0] |= HINT_PNP;
-		break;
-	case S_PDA:
-		hint.byte[0] |= HINT_PDA;
-		break;
-	case S_COMPUTER:
-		hint.byte[0] |= HINT_COMPUTER;
-		break;
-	case S_PRINTER:
-		hint.byte[0] |= HINT_PRINTER;
-		break;
-	case S_MODEM:
-		hint.byte[0] |= HINT_PRINTER;
-		break;
-	case S_LAN:
-		hint.byte[0] |= HINT_LAN;
-		break;
-	case S_COMM:
-		hint.byte[0] |= HINT_EXTENSION;
-		hint.byte[1] |= HINT_COMM;
-		break;
-	case S_OBEX:
-		hint.byte[0] |= HINT_EXTENSION;
-		hint.byte[1] |= HINT_OBEX;
-		break;
-	case S_TELEPHONY:
-		hint.byte[0] |= HINT_EXTENSION;
-		hint.byte[1] |= HINT_TELEPHONY;
-		break;
-	case S_ANY:
-		hint.word = 0xffff;
-		break;
-	default:
-		IRDA_DEBUG( 1, "%s(), Unknown service!\n", __FUNCTION__);
-		break;
-	}
 	return hint.word;
 }
 
@@ -1438,7 +1400,7 @@
 		IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __FUNCTION__);
 		return 0;
 	}
-	service->hints = hints;
+	service->hints.word = hints;
 	hashbin_insert(irlmp->services, (irda_queue_t *) service,
 		       (long) service, NULL);
 
@@ -1481,7 +1443,7 @@
 	spin_lock_irqsave(&irlmp->services->hb_spinlock, flags);
         service = (irlmp_service_t *) hashbin_get_first(irlmp->services);
         while (service) {
-		irlmp->hints.word |= service->hints;
+		irlmp->hints.word |= service->hints.word;
 
                 service = (irlmp_service_t *)hashbin_get_next(irlmp->services);
         }
@@ -1499,7 +1461,7 @@
  *    Returns: handle > 0 on success, 0 on error
  */
 void *irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb,
-			    DISCOVERY_CALLBACK1 expir_clb, void *priv)
+			    DISCOVERY_CALLBACK2 expir_clb, void *priv)
 {
 	irlmp_client_t *client;
 
@@ -1514,7 +1476,7 @@
 	}
 
 	/* Register the details */
-	client->hint_mask = hint_mask;
+	client->hint_mask.word = hint_mask;
 	client->disco_callback = disco_clb;
 	client->expir_callback = expir_clb;
 	client->priv = priv;
@@ -1535,7 +1497,7 @@
  */
 int irlmp_update_client(void *handle, __u16 hint_mask,
 			DISCOVERY_CALLBACK1 disco_clb,
-			DISCOVERY_CALLBACK1 expir_clb, void *priv)
+			DISCOVERY_CALLBACK2 expir_clb, void *priv)
 {
 	irlmp_client_t *client;
 
@@ -1548,7 +1510,7 @@
 		return -1;
 	}
 
-	client->hint_mask = hint_mask;
+	client->hint_mask.word = hint_mask;
 	client->disco_callback = disco_clb;
 	client->expir_callback = expir_clb;
 	client->priv = priv;
diff -urN linux-2.5.66-bk4/net/irda/irnet/irnet.h linux-2.5.66-bk5/net/irda/irnet/irnet.h
--- linux-2.5.66-bk4/net/irda/irnet/irnet.h	Mon Mar 24 14:00:56 2003
+++ linux-2.5.66-bk5/net/irda/irnet/irnet.h	Mon Mar 31 12:50:23 2003
@@ -225,6 +225,10 @@
  *
  * v13 - 30.5.02 - Jean II
  *	o Update module init code
+ *
+ * v14 - 20.2.03 - Jean II
+ *	o Add discovery hint bits in the control channel.
+ *	o Remove obsolete MOD_INC/DEC_USE_COUNT in favor of .owner
  */
 
 /***************************** INCLUDES *****************************/
@@ -476,6 +480,7 @@
   __u32		saddr;
   __u32		daddr;
   char		name[NICKNAME_MAX_LEN + 1];	/* 21 + 1 */
+  __u16_host_order hints;			/* Discovery hint bits */
 } irnet_log;
 
 /*
diff -urN linux-2.5.66-bk4/net/irda/irnet/irnet_irda.c linux-2.5.66-bk5/net/irda/irnet/irnet_irda.c
--- linux-2.5.66-bk4/net/irda/irnet/irnet_irda.c	Mon Mar 24 13:59:55 2003
+++ linux-2.5.66-bk5/net/irda/irnet/irnet_irda.c	Mon Mar 31 12:50:23 2003
@@ -28,7 +28,8 @@
 		 irnet_event	event,
 		 __u32		saddr,
 		 __u32		daddr,
-		 char *		name)
+		 char *		name,
+		 __u16		hints)
 {
   unsigned long		flags;		/* For spinlock */
   int			index;		/* In the log */
@@ -52,6 +53,8 @@
     strcpy(irnet_events.log[index].name, name);
   else
     irnet_events.log[index].name[0] = '\0';
+  /* Copy hints */
+  irnet_events.log[index].hints.word = hints;
   /* Try to get ppp unit number */
   if((ap != (irnet_socket *) NULL) && (ap->ppp_open))
     irnet_events.log[index].unit = ppp_unit_number(&ap->chan);
@@ -609,7 +612,7 @@
        * doesn't exist anymore when we post the event, so we need to pass
        * NULL as the first arg... */
       irnet_post_event(NULL, IRNET_DISCONNECT_TO,
-		       self->saddr, self->daddr, self->rname);
+		       self->saddr, self->daddr, self->rname, 0);
     }
 
   /* Prevent various IrDA callbacks from messing up things
@@ -862,7 +865,7 @@
 
   /* Notify the control channel */
   irnet_post_event(new, IRNET_CONNECT_FROM,
-		   new->saddr, new->daddr, server->rname);
+		   new->saddr, new->daddr, server->rname, 0);
 
   DEXIT(IRDA_SERV_TRACE, "\n");
   return 0;
@@ -893,7 +896,7 @@
 
   /* Notify the control channel (see irnet_find_socket()) */
   irnet_post_event(NULL, IRNET_REQUEST_FROM,
-		   self->saddr, self->daddr, self->rname);
+		   self->saddr, self->daddr, self->rname, 0);
 
   /* Clean up the server to keep it in listen state */
   irttp_listen(self->tsap);
@@ -1108,12 +1111,12 @@
   /* If we were active, notify the control channel */
   if(test_open)
     irnet_post_event(self, IRNET_DISCONNECT_FROM,
-		     self->saddr, self->daddr, self->rname);
+		     self->saddr, self->daddr, self->rname, 0);
   else
     /* If we were trying to connect, notify the control channel */
     if((self->tsap) && (self != &irnet_server.s))
       irnet_post_event(self, IRNET_NOANSWER_FROM,
-		       self->saddr, self->daddr, self->rname);
+		       self->saddr, self->daddr, self->rname, 0);
 
   /* Close our IrTTP connection, cleanup tsap */
   if((self->tsap) && (self != &irnet_server.s))
@@ -1213,7 +1216,7 @@
 
   /* Notify the control channel */
   irnet_post_event(self, IRNET_CONNECT_TO,
-		   self->saddr, self->daddr, self->rname);
+		   self->saddr, self->daddr, self->rname, 0);
 
   DEXIT(IRDA_TCB_TRACE, "\n");
 }
@@ -1282,7 +1285,7 @@
     {
     case STATUS_NO_ACTIVITY:
       irnet_post_event(self, IRNET_BLOCKED_LINK,
-		       self->saddr, self->daddr, self->rname);
+		       self->saddr, self->daddr, self->rname, 0);
       break;
     default:
       DEBUG(IRDA_CB_INFO, "Unknown status...\n");
@@ -1616,8 +1619,8 @@
  *
  *    Got a discovery indication from IrLMP, post an event
  *
- * Note : IrLMP take care of matching the hint mask for us, we only
- * check if it is a "new" node...
+ * Note : IrLMP take care of matching the hint mask for us, and also
+ * check if it is a "new" node for us...
  *
  * As IrLMP filter on the IrLAN hint bit, we get both IrLAN and IrNET
  * nodes, so it's only at connection time that we will know if the
@@ -1633,7 +1636,7 @@
  * is to messy, so we leave that to user space...
  */
 static void
-irnet_discovery_indication(discovery_t *	discovery,
+irnet_discovery_indication(discinfo_t *		discovery,
 			   DISCOVERY_MODE	mode,
 			   void *		priv)
 {
@@ -1643,21 +1646,13 @@
   DASSERT(priv == &irnet_server, , IRDA_OCB_ERROR,
 	  "Invalid instance (0x%X) !!!\n", (unsigned int) priv);
 
-  /* Check if node is discovered is a new one or an old one.
-   * We check when how long ago this node was discovered, with a
-   * coarse timeout (we may miss some discovery events or be delayed).
-   */
-  if((jiffies - discovery->first_timestamp) >= (sysctl_discovery_timeout * HZ))
-    {
-      return;		/* Too old, not interesting -> goodbye */
-    }
-
   DEBUG(IRDA_OCB_INFO, "Discovered new IrNET/IrLAN node %s...\n",
-	discovery->nickname);
+	discovery->info);
 
   /* Notify the control channel */
   irnet_post_event(NULL, IRNET_DISCOVER,
-		   discovery->saddr, discovery->daddr, discovery->nickname);
+		   discovery->saddr, discovery->daddr, discovery->info,
+		   u16ho(discovery->hints));
 
   DEXIT(IRDA_OCB_TRACE, "\n");
 }
@@ -1672,7 +1667,7 @@
  * check if it is a "new" node...
  */
 static void
-irnet_expiry_indication(discovery_t *	expiry,
+irnet_expiry_indication(discinfo_t *	expiry,
 			DISCOVERY_MODE	mode,
 			void *		priv)
 {
@@ -1683,11 +1678,12 @@
 	  "Invalid instance (0x%X) !!!\n", (unsigned int) priv);
 
   DEBUG(IRDA_OCB_INFO, "IrNET/IrLAN node %s expired...\n",
-	expiry->nickname);
+	expiry->info);
 
   /* Notify the control channel */
   irnet_post_event(NULL, IRNET_EXPIRE,
-		   expiry->saddr, expiry->daddr, expiry->nickname);
+		   expiry->saddr, expiry->daddr, expiry->info,
+		   u16ho(expiry->hints));
 
   DEXIT(IRDA_OCB_TRACE, "\n");
 }
diff -urN linux-2.5.66-bk4/net/irda/irnet/irnet_irda.h linux-2.5.66-bk5/net/irda/irnet/irnet_irda.h
--- linux-2.5.66-bk4/net/irda/irnet/irnet_irda.h	Mon Mar 24 14:00:02 2003
+++ linux-2.5.66-bk5/net/irda/irnet/irnet_irda.h	Mon Mar 31 12:50:23 2003
@@ -69,7 +69,8 @@
 			 irnet_event,
 			 __u32,
 			 __u32,
-			 char *);
+			 char *,
+			 __u16);
 /* ----------------------- IRDA SUBROUTINES ----------------------- */
 static inline int
 	irnet_open_tsap(irnet_socket *);
@@ -150,11 +151,11 @@
 				    void *);
 #ifdef DISCOVERY_EVENTS
 static void
-	irnet_discovery_indication(discovery_t *,
+	irnet_discovery_indication(discinfo_t *,
 				   DISCOVERY_MODE,
 				   void *);
 static void
-	irnet_expiry_indication(discovery_t *,
+	irnet_expiry_indication(discinfo_t *,
 				DISCOVERY_MODE,
 				void *);
 #endif
diff -urN linux-2.5.66-bk4/net/irda/irnet/irnet_ppp.c linux-2.5.66-bk5/net/irda/irnet/irnet_ppp.c
--- linux-2.5.66-bk4/net/irda/irnet/irnet_ppp.c	Mon Mar 24 14:01:13 2003
+++ linux-2.5.66-bk5/net/irda/irnet/irnet_ppp.c	Mon Mar 31 12:50:23 2003
@@ -213,10 +213,12 @@
   if(ap->disco_index < ap->disco_number)
     {
       /* Write an event */
-      sprintf(event, "Found %08x (%s) behind %08x\n",
+      sprintf(event, "Found %08x (%s) behind %08x {hints %02X-%02X}\n",
 	      ap->discoveries[ap->disco_index].daddr,
 	      ap->discoveries[ap->disco_index].info,
-	      ap->discoveries[ap->disco_index].saddr);
+	      ap->discoveries[ap->disco_index].saddr,
+	      ap->discoveries[ap->disco_index].hints[0],
+	      ap->discoveries[ap->disco_index].hints[1]);
       DEBUG(CTRL_INFO, "Writing discovery %d : %s\n",
 	    ap->disco_index, ap->discoveries[ap->disco_index].info);
 
@@ -313,16 +315,20 @@
   switch(irnet_events.log[ap->event_index].event)
     {
     case IRNET_DISCOVER:
-      sprintf(event, "Discovered %08x (%s) behind %08x\n",
+      sprintf(event, "Discovered %08x (%s) behind %08x {hints %02X-%02X}\n",
 	      irnet_events.log[ap->event_index].daddr,
 	      irnet_events.log[ap->event_index].name,
-	      irnet_events.log[ap->event_index].saddr);
+	      irnet_events.log[ap->event_index].saddr,
+	      irnet_events.log[ap->event_index].hints.byte[0],
+	      irnet_events.log[ap->event_index].hints.byte[1]);
       break;
     case IRNET_EXPIRE:
-      sprintf(event, "Expired %08x (%s) behind %08x\n",
+      sprintf(event, "Expired %08x (%s) behind %08x {hints %02X-%02X}\n",
 	      irnet_events.log[ap->event_index].daddr,
 	      irnet_events.log[ap->event_index].name,
-	      irnet_events.log[ap->event_index].saddr);
+	      irnet_events.log[ap->event_index].saddr,
+	      irnet_events.log[ap->event_index].hints.byte[0],
+	      irnet_events.log[ap->event_index].hints.byte[1]);
       break;
     case IRNET_CONNECT_TO:
       sprintf(event, "Connected to %08x (%s) on ppp%d\n",
@@ -445,8 +451,6 @@
   ap = kmalloc(sizeof(*ap), GFP_KERNEL);
   DABORT(ap == NULL, -ENOMEM, FS_ERROR, "Can't allocate struct irnet...\n");
 
-  MOD_INC_USE_COUNT;
-
   /* initialize the irnet structure */
   memset(ap, 0, sizeof(*ap));
   ap->file = file;
@@ -469,7 +473,6 @@
     {
       DERROR(FS_ERROR, "Can't setup IrDA link...\n");
       kfree(ap);
-      MOD_DEC_USE_COUNT;
       return err;
     }
 
@@ -514,7 +517,6 @@
     }
 
   kfree(ap);
-  MOD_DEC_USE_COUNT;
 
   DEXIT(FS_TRACE, "\n");
   return 0;
diff -urN linux-2.5.66-bk4/net/irda/irnet/irnet_ppp.h linux-2.5.66-bk5/net/irda/irnet/irnet_ppp.h
--- linux-2.5.66-bk4/net/irda/irnet/irnet_ppp.h	Mon Mar 24 14:01:13 2003
+++ linux-2.5.66-bk5/net/irda/irnet/irnet_ppp.h	Mon Mar 31 12:50:23 2003
@@ -98,6 +98,7 @@
 /* Filesystem callbacks (to call us) */
 static struct file_operations irnet_device_fops =
 {
+	.owner		= THIS_MODULE,
 	.read		= dev_irnet_read,
 	.write		= dev_irnet_write,
 	.poll		= dev_irnet_poll,
diff -urN linux-2.5.66-bk4/net/irda/timer.c linux-2.5.66-bk5/net/irda/timer.c
--- linux-2.5.66-bk4/net/irda/timer.c	Mon Mar 24 14:00:44 2003
+++ linux-2.5.66-bk5/net/irda/timer.c	Mon Mar 31 12:50:23 2003
@@ -39,8 +39,8 @@
 static void irlap_final_timer_expired(void* data);
 static void irlap_wd_timer_expired(void* data);
 static void irlap_backoff_timer_expired(void* data);
-
 static void irlap_media_busy_expired(void* data); 
+
 /*
  * Function irda_start_timer (timer, timeout)
  *
@@ -50,19 +50,18 @@
 void irda_start_timer(struct timer_list *ptimer, int timeout, void *data,
 		      TIMER_CALLBACK callback) 
 {
-	del_timer(ptimer);
- 
-	ptimer->data = (unsigned long) data;
-
 	/* 
 	 * For most architectures void * is the same as unsigned long, but
 	 * at least we try to use void * as long as possible. Since the 
 	 * timer functions use unsigned long, we cast the function here
 	 */
 	ptimer->function = (void (*)(unsigned long)) callback;
-	ptimer->expires = jiffies + timeout;
+	ptimer->data = (unsigned long) data;
 	
-	add_timer(ptimer);
+	/* Set new value for timer (update or add timer).
+	 * We use mod_timer() because it's more efficient and also
+	 * safer with respect to race conditions - Jean II */
+	mod_timer(ptimer, jiffies + timeout);
 }
 
 void irlap_start_slot_timer(struct irlap_cb *self, int timeout)
@@ -136,8 +135,7 @@
 void irlmp_stop_idle_timer(struct lap_cb *self) 
 {
 	/* If timer is activated, kill it! */
-	if(timer_pending(&self->idle_timer))
-		del_timer(&self->idle_timer);
+	del_timer(&self->idle_timer);
 }
 
 /*
